diff --git a/latest b/latest index 7ddcd34e1..d3d5a61c9 120000 --- a/latest +++ b/latest @@ -1 +1 @@ -v0.9.x \ No newline at end of file +v0.10.x \ No newline at end of file diff --git a/v0.10.x/.buildinfo b/v0.10.x/.buildinfo new file mode 100644 index 000000000..9bf7f2a1c --- /dev/null +++ b/v0.10.x/.buildinfo @@ -0,0 +1,4 @@ +# Sphinx build info version 1 +# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. +config: f947d0e99c572b4dcff0ce6cdbeab40d +tags: 645f666f9bcd5a90fca523b33c5a78b7 diff --git a/v0.10.x/.nojekyll b/v0.10.x/.nojekyll new file mode 100644 index 000000000..e69de29bb diff --git a/v0.10.x/_downloads/02506d9d0821045a7f391bb7d1e4dd02/viz_spline_interpolator.ipynb b/v0.10.x/_downloads/02506d9d0821045a7f391bb7d1e4dd02/viz_spline_interpolator.ipynb new file mode 100644 index 000000000..4cd141706 --- /dev/null +++ b/v0.10.x/_downloads/02506d9d0821045a7f391bb7d1e4dd02/viz_spline_interpolator.ipynb @@ -0,0 +1,237 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Keyframes Spline Interpolator\n\nTutorial on making keyframe-based animation in FURY using Spline interpolators.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "import numpy as np\n\nfrom fury import actor, window\nfrom fury.animation import Animation, Timeline\nfrom fury.animation.interpolator import spline_interpolator\n\nscene = window.Scene()\n\nshowm = window.ShowManager(\n scene, size=(900, 768), reset_camera=False, order_transparent=True\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Position keyframes as a dict object containing timestamps as keys and\npositions as values.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "position_keyframes = {\n 0.0: np.array([0, 0, 0]),\n 2.0: np.array([10, 3, 5]),\n 4.0: np.array([20, 14, 13]),\n 6.0: np.array([-20, 20, 0]),\n 8.0: np.array([17, -10, 15]),\n 10.0: np.array([0, -6, 0]),\n}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "creating FURY dots to visualize the position values.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "pos_dots = actor.dot(np.array(list(position_keyframes.values())))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "creating two timelines (one uses linear and the other uses' spline\ninterpolator), each timeline controls a sphere actor\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "sphere_linear = actor.sphere(np.array([[0, 0, 0]]), (1, 0.5, 0.2), 0.5)\n\nlinear_anim = Animation()\nlinear_anim.add_actor(sphere_linear)\n\nlinear_anim.set_position_keyframes(position_keyframes)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Note: linear_interpolator is used by default. So, no need to set it for this\nfirst animation that we need to linearly interpolate positional animation.\n\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "creating a second timeline that translates another larger sphere actor using\nspline interpolator.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "sphere_spline = actor.sphere(np.array([[0, 0, 0]]), (0.3, 0.9, 0.6), 1)\nspline_anim = Animation(sphere_spline)\nspline_anim.set_position_keyframes(position_keyframes)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Setting 5th degree spline interpolator for position keyframes.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "spline_anim.set_position_interpolator(spline_interpolator, degree=5)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Wrapping animations up!\n\nAdding everything to a ``Timeline`` to control the two timelines.\n\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "First we create a timeline with a playback panel:\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "timeline = Timeline(playback_panel=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Add visualization dots actor to the scene.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "scene.add(pos_dots)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Adding the animations to the timeline (so that it controls their playback).\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "timeline.add_animation([linear_anim, spline_anim])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Adding the timeline to the show manager.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "showm.add_animation(timeline)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now that these two animations are added to timeline, if the timeline\nis played, paused, ..., all these changes will reflect on the animations.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "interactive = False\n\nif interactive:\n showm.start()\n\nwindow.record(scene, out_path='viz_keyframe_animation_spline.png', size=(900, 768))" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.8" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/v0.10.x/_downloads/047960bb41f51d256e795f60be8e1969/viz_timers.py b/v0.10.x/_downloads/047960bb41f51d256e795f60be8e1969/viz_timers.py new file mode 100644 index 000000000..c529a5768 --- /dev/null +++ b/v0.10.x/_downloads/047960bb41f51d256e795f60be8e1969/viz_timers.py @@ -0,0 +1,70 @@ +""" +=============== +Using a timer +=============== + +This example shows how to create a simple animation using a timer callback. + +We will use a sphere actor that generates many spheres of different colors, +radii and opacity. Then we will animate this actor by rotating and changing +global opacity levels from inside a user defined callback. + +The timer will call this user defined callback every 200 milliseconds. The +application will exit after the callback has been called 100 times. +""" + + +import itertools + +import numpy as np + +from fury import actor, ui, window + +xyz = 10 * np.random.rand(100, 3) +colors = np.random.rand(100, 4) +radii = np.random.rand(100) + 0.5 + +scene = window.Scene() + +sphere_actor = actor.sphere(centers=xyz, colors=colors, radii=radii) + +scene.add(sphere_actor) + +showm = window.ShowManager( + scene, size=(900, 768), reset_camera=False, order_transparent=True +) + + +tb = ui.TextBlock2D(bold=True) + +# use itertools to avoid global variables +counter = itertools.count() + + +def timer_callback(_obj, _event): + global timer_id + cnt = next(counter) + tb.message = "Let's count up to 300 and exit :" + str(cnt) + showm.scene.azimuth(0.05 * cnt) + sphere_actor.GetProperty().SetOpacity(cnt / 100.0) + showm.render() + + if cnt == 10: + # destroy the first timer and replace it with another faster timer + showm.destroy_timer(timer_id) + timer_id = showm.add_timer_callback(True, 10, timer_callback) + + if cnt == 300: + # destroy the second timer and exit + showm.destroy_timer(timer_id) + showm.exit() + + +scene.add(tb) + +# Run every 200 milliseconds +timer_id = showm.add_timer_callback(True, 200, timer_callback) + +showm.start() + +window.record(showm.scene, size=(900, 768), out_path='viz_timer.png') diff --git a/v0.10.x/_downloads/0495e6a00e4c37b628df83c952f39155/viz_picking.ipynb b/v0.10.x/_downloads/0495e6a00e4c37b628df83c952f39155/viz_picking.ipynb new file mode 100644 index 000000000..044889b01 --- /dev/null +++ b/v0.10.x/_downloads/0495e6a00e4c37b628df83c952f39155/viz_picking.ipynb @@ -0,0 +1,259 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Simple picking\n\nHere we present a tutorial showing how to interact with objects in the\n3D world. All objects to be picked are part of a single actor.\nFURY likes to bundle objects in a few actors to reduce code and\nincrease speed.\n\nWhen the objects are picked they will change size and color.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "import numpy as np\n\nfrom fury import actor, pick, ui, utils, window\n\ncenters = 0.5 * np.array([[0, 0, 0], [100, 0, 0], [200, 0, 0.0]])\ncolors = np.array([[0.8, 0, 0], [0, 0.8, 0], [0, 0, 0.8]])\nradii = 0.1 * np.array([50, 100, 150.0])\n\nselected = np.zeros(3, dtype=bool)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's create a panel to show what is picked\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "panel = ui.Panel2D(size=(400, 200), color=(1, 0.5, 0.0), align='right')\npanel.center = (150, 200)\n\ntext_block = ui.TextBlock2D(text='Left click on object \\n')\npanel.add_element(text_block, (0.3, 0.3))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Build scene and add an actor with many objects.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "scene = window.Scene()\n\nlabel_actor = actor.vector_text(text='Test')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This actor is made with 3 cubes of different orientation\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "directions = np.array(\n [\n [np.sqrt(2) / 2, 0, np.sqrt(2) / 2],\n [np.sqrt(2) / 2, np.sqrt(2) / 2, 0],\n [0, np.sqrt(2) / 2, np.sqrt(2) / 2],\n ]\n)\nfury_actor = actor.cube(centers, directions, colors, scales=radii)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Access the memory of the vertices of all the cubes\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "vertices = utils.vertices_from_actor(fury_actor)\nnum_vertices = vertices.shape[0]\nnum_objects = centers.shape[0]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Access the memory of the colors of all the cubes\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "vcolors = utils.colors_from_actor(fury_actor, 'colors')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Adding an actor showing the axes of the world coordinates\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "ax = actor.axes(scale=(10, 10, 10))\n\nscene.add(fury_actor)\nscene.add(label_actor)\nscene.add(ax)\nscene.reset_camera()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Create the Picking manager\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "pickm = pick.PickingManager()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Time to make the callback which will be called when we pick an object\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def left_click_callback(obj, event):\n\n # Get the event position on display and pick\n\n event_pos = pickm.event_position(showm.iren)\n picked_info = pickm.pick(event_pos, showm.scene)\n\n vertex_index = picked_info['vertex']\n\n # Calculate the objects index\n\n object_index = int(np.floor((vertex_index / num_vertices) * num_objects))\n\n # Find how many vertices correspond to each object\n sec = int(num_vertices / num_objects)\n\n if not selected[object_index]:\n scale = 6 / 5\n color_add = np.array([30, 30, 30], dtype='uint8')\n selected[object_index] = True\n else:\n scale = 5 / 6\n color_add = np.array([-30, -30, -30], dtype='uint8')\n selected[object_index] = False\n\n # Update vertices positions\n vertices[object_index * sec : object_index * sec + sec] = (\n scale\n * (\n vertices[object_index * sec : object_index * sec + sec]\n - centers[object_index]\n )\n + centers[object_index]\n )\n\n # Update colors\n vcolors[object_index * sec : object_index * sec + sec] += color_add\n\n # Tell actor that memory is modified\n utils.update_actor(fury_actor)\n\n face_index = picked_info['face']\n\n # Show some info\n text = 'Object ' + str(object_index) + '\\n'\n text += 'Vertex ID ' + str(vertex_index) + '\\n'\n text += 'Face ID ' + str(face_index) + '\\n'\n text += 'World pos ' + str(np.round(picked_info['xyz'], 2)) + '\\n'\n text += 'Actor ID ' + str(id(picked_info['actor']))\n text_block.message = text\n showm.render()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Bind the callback to the actor\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "fury_actor.AddObserver('LeftButtonPressEvent', left_click_callback, 1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Make the window appear\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "showm = window.ShowManager(scene, size=(1024, 768), order_transparent=True)\n\nscene.add(panel)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Change interactive to True to start interacting with the scene\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "interactive = False\n\nif interactive:\n\n showm.start()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Save the current framebuffer in a PNG file\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "window.record(showm.scene, size=(1024, 768), out_path='viz_picking.png')" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.8" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/v0.10.x/_downloads/04e8eda84bdca47952939ad54850e938/viz_layout.py b/v0.10.x/_downloads/04e8eda84bdca47952939ad54850e938/viz_layout.py new file mode 100644 index 000000000..98270c66e --- /dev/null +++ b/v0.10.x/_downloads/04e8eda84bdca47952939ad54850e938/viz_layout.py @@ -0,0 +1,63 @@ +""" +======================================== +Using Layouts with different UI elements +======================================== + +This example shows how to place different UI elements in different Layouts. +The Layouts used here is GridLayout (with different cell shapes). + +First, some imports. +""" + +from fury import ui, window +from fury.layout import GridLayout + +############################################################################### +# We create some panels and then we arrange them in a grid fashion +# +# First, we create some panels with different sizes/positions + +panel_1 = ui.Panel2D(size=(200, 200), color=(0.4, 0.6, 0.3), position=(100, 100)) + +panel_2 = ui.Panel2D(size=(250, 250), color=(0.8, 0.3, 0.5), position=(150, 150)) + +############################################################################### +# Now we create two listboxes + +listbox_1 = ui.ListBox2D(size=(150, 150), values=['First', 'Second', 'Third']) + +listbox_2 = ui.ListBox2D(size=(250, 250), values=['First', 'Second', 'Third']) + +############################################################################### +# Now we create two different UI i.e. a slider and a listbox + +slider = ui.LineSlider2D(length=150) +listbox = ui.ListBox2D(size=(150, 150), values=['First', 'Second', 'Third']) + +############################################################################### +# Now, we create grids with different shapes + +rect_grid = GridLayout(position_offset=(0, 0, 0)) +square_grid = GridLayout(cell_shape='square', position_offset=(0, 300, 0)) +diagonal_grid = GridLayout(cell_shape='diagonal', position_offset=(0, 600, 0)) + + +############################################################################### +# Applying the grid to the ui elements + +rect_grid.apply([panel_1, panel_2]) +square_grid.apply([listbox_1, listbox_2]) +diagonal_grid.apply([slider, listbox]) + +current_size = (1500, 1500) +show_manager = window.ShowManager(size=current_size, title='FURY UI Layout') + +show_manager.scene.add(panel_1, panel_2, listbox_1, listbox_2, slider, listbox) + +# To interact with the UI, set interactive = True +interactive = False + +if interactive: + show_manager.start() + +window.record(show_manager.scene, out_path='ui_layout.png', size=(400, 400)) diff --git a/v0.10.x/_downloads/05fd9f63e6e71b89f69af9820567b262/viz_timeline.py b/v0.10.x/_downloads/05fd9f63e6e71b89f69af9820567b262/viz_timeline.py new file mode 100644 index 000000000..65c65e949 --- /dev/null +++ b/v0.10.x/_downloads/05fd9f63e6e71b89f69af9820567b262/viz_timeline.py @@ -0,0 +1,92 @@ +""" +============================== +Timeline and setting keyframes +============================== + +In his tutorial, you will learn how to use Fury ``Timeline`` for playing the +animations. +""" + +############################################################################### +# What is ``Timeline``? +# ===================== +# +# ``Timeline`` is responsible for handling the playback of Fury Animations. +# +# ``Timeline`` has playback methods such as ``play``, ``pause``, ``stop``, ... +# which can be used to control the animation. + + +import numpy as np + +from fury import actor, window +from fury.animation import Animation, Timeline + +############################################################################### +# We create our ``Scene`` and ``ShowManager`` as usual. +scene = window.Scene() + +showm = window.ShowManager(scene, size=(900, 768)) +showm.initialize() + +############################################################################### +# Creating a ``Timeline`` +# ======================= +# +# FURY ``Timeline`` has the option to attaches a very useful panel for +# controlling the animation by setting ``playback_panel=True``. + +############################################################################### +# Creating a ``Timeline`` with a PlaybackPanel. +timeline = Timeline(playback_panel=True) + +############################################################################### +# Creating a Fury Animation as usual +anim = Animation() +sphere = actor.sphere(np.zeros([1, 3]), np.ones([1, 3])) +anim.add_actor(sphere) +# Now that the actor is add to the ``Animation``, setting keyframes to the +# Animation will animate the actor accordingly. + + +############################################################################### +# Setting Keyframes +# ================= +# +# There are multiple ways to set keyframes: +# +# 1- To set a single keyframe, you may use ``animation.set_(t, k)``, +# where is the name of the property to be set. I.e. setting position +# to (1, 2, 3) at time 0.0 would be as following: +anim.set_position(0.0, np.array([1, 2, 3])) + +############################################################################### +# Supported properties are: **position, rotation, scale, color, and opacity**. +# +# 2- To set multiple keyframes at once, you may use +# ``animation.set__keyframes(keyframes)``. +keyframes = {1.0: np.array([0, 0, 0]), 3.0: np.array([-2, 0, 0])} + +anim.set_position_keyframes(keyframes) + +############################################################################### +# That's it! Now we are done setting keyframes. + +############################################################################### +# In order to control this animation by the timeline we created earlier, this +# animation must be added to the timeline. +timeline.add_animation(anim) + +############################################################################### +# Now we add only the ``Timeline`` to the ``ShowManager`` the same way we add +# ``Animation`` to the ``ShowManager``. +showm.add_animation(timeline) + +scene.set_camera(position=(0, 0, -10)) + +interactive = False + +if interactive: + showm.start() + +window.record(scene, out_path='viz_keyframe_animation_timeline.png', size=(900, 768)) diff --git a/v0.10.x/_downloads/06040223ef85b9fe77670040e9f10779/viz_cone.py b/v0.10.x/_downloads/06040223ef85b9fe77670040e9f10779/viz_cone.py new file mode 100644 index 000000000..188bafbfc --- /dev/null +++ b/v0.10.x/_downloads/06040223ef85b9fe77670040e9f10779/viz_cone.py @@ -0,0 +1,47 @@ +""" +====================================================================== +Fury Cone Actor +====================================================================== +This example shows how to use the cone actor. +""" + +import numpy as np + +from fury import actor, window + +############################################################################ +# First thing, you have to specify centers, directions, and colors of the cone + +centers = np.zeros([3, 3]) +dirs = np.identity(3) +colors = np.identity(3) + +############################################################################ +# The below cone actor is generated by repeating the cone primitive. + +cone_actor1 = actor.cone(centers, dirs, colors=colors, heights=1.5) + +############################################################################ +# repeating what we did but this time with random directions, and colors +# Here, we're using vtkConeSource to generate the cone actor + +cen2 = np.add(centers, np.array([3, 0, 0])) +dir2 = np.random.rand(5, 3) +cols2 = np.random.rand(5, 3) + +cone_actor2 = actor.cone(cen2, dir2, colors=cols2, heights=1.5, use_primitive=False) + +scene = window.Scene() + +############################################################################ +# Adding our cone actors to scene. + +scene.add(cone_actor1) +scene.add(cone_actor2) + +interactive = False + +if interactive: + window.show(scene, size=(600, 600)) + +window.record(scene, out_path='viz_cone.png', size=(600, 600)) diff --git a/v0.10.x/_downloads/061559c729409529da6e1dc02a16f347/viz_principled_spheres.py b/v0.10.x/_downloads/061559c729409529da6e1dc02a16f347/viz_principled_spheres.py new file mode 100644 index 000000000..6408bfa62 --- /dev/null +++ b/v0.10.x/_downloads/061559c729409529da6e1dc02a16f347/viz_principled_spheres.py @@ -0,0 +1,107 @@ +""" +=============================================================================== +Principled BRDF shader on spheres +=============================================================================== + +The Principled Bidirectional Reflectance Distribution Function ([BRDF] +(https://en.wikipedia.org/wiki/Bidirectional_reflectance_distribution_function) +) was introduced by Brent Burley as part of the [SIGGRAPH 2012 Physically Based +Shading course] +(https://blog.selfshadow.com/publications/s2012-shading-course/). Although it +is not strictly physically based, it was designed so the parameters included +could model materials in the [MERL 100](https://www.merl.com/brdf/) (Material +Exchange and Research Library) database. Moreover, each parameter was +carefully chosen and limited to be easy to use and understand, so that +blending multiple layers together would give intuitive results. + +In this demo, we showcase our implementation of the Principled BRDF in FURY. + +Let's start by importing the necessary modules: +""" + +import numpy as np + +from fury import actor, material, window + +############################################################################### +# Now set up a new scene. + +scene = window.Scene() +scene.background((0.9, 0.9, 0.9)) + +############################################################################### +# Let's define the parameters needed for our demo. In this demo we will see the +# effect of each one of the 10 parameters defined by the Principled shader. +# For interpretability and usability purposes, each parameter is limited to +# values between the range 0 to 1. + +material_params = [ + [(1, 1, 1), {'subsurface': 0}], + [[1, 1, 0], {'metallic': 0}], + [(1, 0, 0), {'specular': 0}], + [(1, 0, 0), {'specular_tint': 0, 'specular': 1}], + [(0, 0, 1), {'roughness': 0}], + [(1, 0, 1), {'anisotropic': 0, 'metallic': 0.25, 'roughness': 0.5}], + [[0, 1, 0.5], {'sheen': 0}], + [(0, 1, 0.5), {'sheen_tint': 0, 'sheen': 1}], + [(0, 1, 1), {'clearcoat': 0}], + [(0, 1, 1), {'clearcoat_gloss': 0, 'clearcoat': 1}], +] + +############################################################################### +# We can start to add our actors to the scene and see how different values of +# the parameters produce interesting effects. + +for i in range(10): + center = np.array([[0, -5 * i, 0]]) + for j in range(11): + center[0][0] = -25 + 5 * j + sphere = actor.sphere( + center, colors=material_params[i][0], radii=2, theta=32, phi=32 + ) + keys = list(material_params[i][1]) + material_params[i][1][keys[0]] = np.round(0.1 * j, decimals=1) + material.manifest_principled(sphere, **material_params[i][1]) + scene.add(sphere) + +############################################################################### +# Finally, let's add some labels to guide us through our visualization. + +labels = [ + 'Subsurface', + 'Metallic', + 'Specular', + 'Specular Tint', + 'Roughness', + 'Anisotropic', + 'Sheen', + 'Sheen Tint', + 'Clearcoat', + 'Clearcoat Gloss', +] + +for i in range(10): + pos = [-40, -5 * i, 0] + label = actor.vector_text( + labels[i], pos=pos, scale=(0.8, 0.8, 0.8), color=(0, 0, 0) + ) + scene.add(label) + +for j in range(11): + pos = [-26 + 5 * j, 5, 0] + label = actor.vector_text( + str(np.round(j * 0.1, decimals=1)), + pos=pos, + scale=(0.8, 0.8, 0.8), + color=(0, 0, 0), + ) + scene.add(label) + +############################################################################### +# And visualize our demo. + +interactive = False +if interactive: + window.show(scene) + +window.record(scene, size=(600, 600), out_path='viz_principled_spheres.png') diff --git a/v0.10.x/_downloads/07f458553007d2dd2d69d3eb0dd3bf05/viz_brick_wall.py b/v0.10.x/_downloads/07f458553007d2dd2d69d3eb0dd3bf05/viz_brick_wall.py new file mode 100644 index 000000000..b61166f18 --- /dev/null +++ b/v0.10.x/_downloads/07f458553007d2dd2d69d3eb0dd3bf05/viz_brick_wall.py @@ -0,0 +1,302 @@ +""" +===================== +Brick Wall Simulation +===================== + +This example simulation shows how to use pybullet to render physics simulations +in fury. In this example we specifically render a ball beign thrown at a brick +wall. + +First some imports. +""" +import itertools + +import numpy as np +import pybullet as p + +from fury import actor, ui, utils, window + +############################################################################### +# Next, we initialize a pybullet client to render the physics. We use `DIRECT` +# mode to initialize pybullet without a GUI. + +p.connect(p.DIRECT) + +############################################################################### +# Apply gravity to the scene. In pybullet all values are in SI units. +p.setGravity(0, 0, -10) + +############################################################################### +# We define some global parameters so that its easier for us to tweak the +# tweak the simulation. + +# Ball Parameters +ball_radius = 0.3 +ball_color = np.array([1, 0, 0]) +ball_mass = 3 +ball_position = np.array([2, 0, 1.5]) +ball_orientation = np.array([0, 0, 0, 1]) + +# Base Plane Parameters +base_size = np.array([5, 5, 0.2]) +base_color = np.array([1, 1, 1]) +base_position = np.array([0, 0, -0.1]) +base_orientation = np.array([0, 0, 0, 1]) + +# Wall Parameters +wall_height = 10 +wall_width = 10 +brick_mass = 0.5 +brick_size = np.array([0.2, 0.4, 0.2]) + +############################################################################### +# Now we define the required parameters to render the Ball. + +# Ball actor +ball_actor = actor.sphere( + centers=np.array([[0, 0, 0]]), colors=ball_color, radii=ball_radius +) + +# Collision shape for the ball. +ball_coll = p.createCollisionShape(p.GEOM_SPHERE, radius=ball_radius) + +# Creating a multi-body which will be tracked by pybullet. +ball = p.createMultiBody( + baseMass=3, + baseCollisionShapeIndex=ball_coll, + basePosition=ball_position, + baseOrientation=ball_orientation, +) + +# Change the dynamics of the ball by adding friction and restitution. +p.changeDynamics(ball, -1, lateralFriction=0.3, restitution=0.5) + +############################################################################### +# Render a base plane to support the bricks. + +base_actor = actor.box( + centers=np.array([[0, 0, 0]]), + directions=[0, 0, 0], + scales=base_size, + colors=base_color, +) + +base_coll = p.createCollisionShape(p.GEOM_BOX, halfExtents=base_size / 2) +# half of the actual size. + +base = p.createMultiBody( + baseCollisionShapeIndex=base_coll, + basePosition=base_position, + baseOrientation=base_orientation, +) + +p.changeDynamics(base, -1, lateralFriction=0.3, restitution=0.5) + +############################################################################### +# Now we render the bricks. All the bricks are rendered by a single actor for +# better performance. + +nb_bricks = wall_height * wall_width + +brick_centers = np.zeros((nb_bricks, 3)) + +brick_directions = np.zeros((nb_bricks, 3)) +brick_directions[:] = np.array([1.57, 0, 0]) + +brick_orns = np.zeros((nb_bricks, 4)) + +brick_sizes = np.zeros((nb_bricks, 3)) +brick_sizes[:] = brick_size + +brick_colors = np.random.rand(nb_bricks, 3) + +brick_coll = p.createCollisionShape(p.GEOM_BOX, halfExtents=brick_size / 2) + +# We use this array to store the reference of brick objects in pybullet world. +bricks = np.zeros(nb_bricks, dtype=np.int8) + +# Logic to position the bricks appropriately to form a wall. +i = 0 +for k in range(wall_height): + for j in range(wall_width): + center_pos = np.array([-1, (j * 0.4) - 1.8, (0.2 * k) + 0.1]) + brick_centers[i] = center_pos + brick_orns[i] = np.array([0, 0, 0, 1]) + bricks[i] = p.createMultiBody( + baseMass=brick_mass, + baseCollisionShapeIndex=brick_coll, + basePosition=center_pos, + baseOrientation=brick_orns[i], + ) + p.changeDynamics(bricks[i], -1, lateralFriction=0.1, restitution=0.1) + i += 1 + +brick_actor = actor.box( + centers=brick_centers, + directions=brick_directions, + scales=brick_sizes, + colors=brick_colors, +) + +############################################################################### +# Now, we define a scene and add actors to it. + +scene = window.Scene() +scene.add(actor.axes()) +scene.add(ball_actor) +scene.add(base_actor) +scene.add(brick_actor) + +# Create show manager. +showm = window.ShowManager( + scene, size=(900, 768), reset_camera=False, order_transparent=True +) + + +# Counter iterator for tracking simulation steps. +counter = itertools.count() + +# Variable for tracking applied force. +apply_force = True + +############################################################################### +# Now, we define methods to sync objects between fury and Pybullet. + +# Get the position of base and set it. +base_pos, _ = p.getBasePositionAndOrientation(base) +base_actor.SetPosition(*base_pos) + +# Do the same for ball. +ball_pos, _ = p.getBasePositionAndOrientation(ball) +ball_actor.SetPosition(*ball_pos) + +# Calculate the vertices of the bricks. +vertices = utils.vertices_from_actor(brick_actor) +num_vertices = vertices.shape[0] +num_objects = brick_centers.shape[0] +sec = int(num_vertices / num_objects) + + +############################################################################### +# ============== +# Syncing Bricks +# ============== +# +# Here, we perform three major steps to sync bricks accurately. +# * Get the position and orientation of the bricks from pybullet. +# * Calculate the Rotation Matrix. +# +# - Get the difference in orientations (Quaternion). +# - Generate the corresponding rotation matrix according to that difference. +# - Reshape it in a 3x3 matrix. +# +# * Perform calculations to get the required position and orientation. +# * Update the position and orientation. + + +def sync_brick(object_index, multibody): + pos, orn = p.getBasePositionAndOrientation(multibody) + + rot_mat = np.reshape( + p.getMatrixFromQuaternion( + p.getDifferenceQuaternion(orn, brick_orns[object_index]) + ), + (3, 3), + ) + + vertices[object_index * sec : object_index * sec + sec] = ( + vertices[object_index * sec : object_index * sec + sec] + - brick_centers[object_index] + ) @ rot_mat + pos + + brick_centers[object_index] = pos + brick_orns[object_index] = orn + + +############################################################################### +# A simpler but inaccurate approach is used here to update the position and +# orientation. + + +def sync_actor(actor, multibody): + pos, orn = p.getBasePositionAndOrientation(multibody) + actor.SetPosition(*pos) + orn_deg = np.degrees(p.getEulerFromQuaternion(orn)) + actor.SetOrientation(*orn_deg) + + +############################################################################### +# Here, we define a textblock to display the Avg. FPS and simulation steps. + +fpss = np.array([]) +tb = ui.TextBlock2D( + text='Avg. FPS: \nSim Steps: ', position=(0, 680), font_size=30, color=(1, 0.5, 0) +) +scene.add(tb) + +############################################################################### +# Set the camera for better visualization. + +scene.set_camera( + position=(10.46, -8.13, 6.18), + focal_point=(0.0, 0.0, 0.79), + view_up=(-0.27, 0.26, 0.90), +) + + +############################################################################### +# Timer callback is created which is responsible for calling the sync and +# simulation methods. + + +# Create timer callback which will execute at each step of simulation. +def timer_callback(_obj, _event): + global apply_force, fpss + cnt = next(counter) + showm.render() + + if cnt % 1 == 0: + fps = showm.frame_rate + fpss = np.append(fpss, fps) + tb.message = ( + 'Avg. FPS: ' + str(np.round(np.mean(fpss), 0)) + '\nSim Steps: ' + str(cnt) + ) + + # Get the position and orientation of the ball. + ball_pos, ball_orn = p.getBasePositionAndOrientation(ball) + + # Apply force for 5 times for the first step of simulation. + if apply_force: + # Apply the force. + p.applyExternalForce( + ball, -1, forceObj=[-10000, 0, 0], posObj=ball_pos, flags=p.WORLD_FRAME + ) + apply_force = False + + # Set position and orientation of the ball. + sync_actor(ball_actor, ball) + + # Updating the position and orientation of each individual brick. + for idx, brick in enumerate(bricks): + sync_brick(idx, brick) + utils.update_actor(brick_actor) + + # Simulate a step. + p.stepSimulation() + + # Exit after 2000 steps of simulation. + if cnt == 130: + showm.exit() + + +# Add the timer callback to showmanager. +# Increasing the duration value will slow down the simulation. +showm.add_timer_callback(True, 1, timer_callback) + +interactive = False + +# start simulation +if interactive: + showm.start() + +window.record(scene, out_path='viz_brick_wall.png', size=(900, 768)) diff --git a/v0.10.x/_downloads/07fcc19ba03226cd3d83d4e40ec44385/auto_examples_python.zip b/v0.10.x/_downloads/07fcc19ba03226cd3d83d4e40ec44385/auto_examples_python.zip new file mode 100644 index 000000000..22f6b695d Binary files /dev/null and b/v0.10.x/_downloads/07fcc19ba03226cd3d83d4e40ec44385/auto_examples_python.zip differ diff --git a/v0.10.x/_downloads/0815a10a49849e7a50936c253c3ffffc/viz_fractals.py b/v0.10.x/_downloads/0815a10a49849e7a50936c253c3ffffc/viz_fractals.py new file mode 100644 index 000000000..4c5c40113 --- /dev/null +++ b/v0.10.x/_downloads/0815a10a49849e7a50936c253c3ffffc/viz_fractals.py @@ -0,0 +1,292 @@ +""" +======== +Fractals +======== + +Fractals are geometric structures that are self-similar at any scale. These +structures are easy to generate using recursion. In this demo, we'll be +implementing the following fractals: + +- Sierpinski Tetrahedron or Tetrix +- Menger Sponge +- Moseley Snowflake + +Let's begin by importing some necessary modules. We need ``fury.primitive`` to +avoid having to hardcode the geometry of a tetrahedron and a cube. +``fury.utils`` also contains a ``repeat_primitive`` function which we will use +for this demo. +""" + +import math + +import numpy as np + +from fury import primitive, ui, utils, window + +############################################################################### +# Before we create our first fractal, let's set some ground rules for us to +# work with. +# +# 1. Instead of creating a new actor to represent each primitive of the +# fractal, we will compute the centers of each primitive and draw them at once +# using ``repeat_primitive()``. +# +# 2. How many primitives do we need? For each fractal, we define a depth which +# will prevent infinite recursion. Assuming we have a depth of :math:`N`, and +# at each level the shape is divided into :math:`k` smaller parts, we will need +# :math:`k^{N}` primitives to represent the fractal. +# +# 3. Ideally, we want to allocate the array of centers upfront. To achieve +# this, we can use the method of representing a binary tree in an array, and +# extend it to work with k-ary trees (formulas for the same can be found +# `here`_). In this scheme of representation, we represent every primitive as a +# node, and each sub-primitive as a child node. We can also skip storing the +# first :math:`\frac{k^{N} - 1}{k - 1} + 1` entries as we only need to render +# the leaf nodes. This allows us to create an array of exactly the required +# size at the start, without any additional overhead. +# +# .. _here: https://book.huihoo.com/data-structures-and-algorithms-with-object-oriented-design-patterns-in-c++/html/page356.html # noqa +# +# ----------------------------------------------------------------------------- + +############################################################################### +# The tetrix is a classic 3d fractal, a natural three-dimensional extension of +# the Sierpinski Triangle. At each level, we need to calculate the new centers +# for the next level. We can use the vertices of a tetrahedron as the offsets +# for the new centers, provided that the tetrahedron is centered at the origin +# (which is the case here). + + +def tetrix(N): + centers = np.zeros((4**N, 3)) + + # skipping non-leaf nodes (see above) + offset = (4**N - 1) // 3 + 1 + + # just need the vertices + U, _ = primitive.prim_tetrahedron() + + def gen_centers(depth, pos, center, dist): + if depth == N: + centers[pos - offset] = center + else: + idx = 4 * (pos - 1) + 2 + for i in range(4): + # distance gets halved at each level + gen_centers(depth + 1, idx + i, center + dist * U[i], dist / 2) + + # the division by sqrt(6) is to ensure correct scale + gen_centers(0, 1, np.zeros(3), 2 / (6**0.5)) + + vertices, faces = primitive.prim_tetrahedron() + + # primitive is scaled down depending on level + vertices /= 2 ** (N - 1) + + # compute some pretty colors + bounds_min, bounds_max = np.min(centers, axis=0), np.max(centers, axis=0) + colors = (centers - bounds_min) / (bounds_max - bounds_min) + + vertices, triangles, colors, _ = primitive.repeat_primitive( + centers=centers, colors=colors, vertices=vertices, faces=faces + ) + return utils.get_actor_from_primitive(vertices, triangles, colors) + + +############################################################################### +# For a Menger Sponge, each cube is divided into 27 smaller cubes, and we skip +# some of them (face centers, and the center of the cube). This means that on +# every level we get 20 new cubes. +# +# Here, to compute the points of each new center, we start at a corner cube's +# center and add the offsets to each smaller cube, scaled according to the +# level. + + +def sponge(N): + centers = np.zeros((20**N, 3)) + offset = (20**N - 1) // 19 + 1 + + # these are the offsets of the new centers at the next level of recursion + # each cube is divided into 20 smaller cubes for a snowflake + V = np.array( + [ + [0, 0, 0], + [0, 0, 1], + [0, 0, 2], + [0, 1, 0], + [0, 1, 2], + [0, 2, 0], + [0, 2, 1], + [0, 2, 2], + [1, 0, 0], + [1, 0, 2], + [1, 2, 0], + [1, 2, 2], + [2, 0, 0], + [2, 0, 1], + [2, 0, 2], + [2, 1, 0], + [2, 1, 2], + [2, 2, 0], + [2, 2, 1], + [2, 2, 2], + ] + ) + + def gen_centers(depth, pos, center, dist): + if depth == N: + centers[pos - offset] = center + else: + # we consider a corner cube as our starting point + start = center - np.array([1, 1, 1]) * dist**0.5 + idx = 20 * (pos - 1) + 2 + + # this moves from the corner cube to each new cube's center + for i in range(20): + # each cube is divided into 27 cubes so side gets divided by 3 + gen_centers(depth + 1, idx + i, start + V[i] * dist, dist / 3) + + gen_centers(0, 1, np.zeros(3), 1 / 3) + + vertices, faces = primitive.prim_box() + vertices /= 3**N + + bounds_min, bounds_max = np.min(centers, axis=0), np.max(centers, axis=0) + colors = (centers - bounds_min) / (bounds_max - bounds_min) + + vertices, triangles, colors, _ = primitive.repeat_primitive( + centers=centers, colors=colors, vertices=vertices, faces=faces + ) + return utils.get_actor_from_primitive(vertices, triangles, colors) + + +############################################################################### +# A snowflake is exactly the same as above, but we skip different cubes +# (corners and center). I think this looks quite interesting, and it is +# possible to see the Koch snowflake if you position the camera just right. + + +def snowflake(N): + centers = np.zeros((18**N, 3)) + offset = (18**N - 1) // 17 + 1 + V = np.array( + [ + [0, 0, 1], + [0, 1, 0], + [0, 1, 1], + [0, 1, 2], + [0, 2, 1], + [1, 0, 0], + [1, 0, 1], + [1, 0, 2], + [1, 1, 0], + [1, 1, 2], + [1, 2, 0], + [1, 2, 1], + [1, 2, 2], + [2, 0, 1], + [2, 1, 0], + [2, 1, 1], + [2, 1, 2], + [2, 2, 1], + ] + ) + + def gen_centers(depth, pos, center, side): + if depth == N: + centers[pos - offset] = center + else: + start = center - np.array([1, 1, 1]) * side**0.5 + idx = 18 * (pos - 1) + 2 + for i in range(18): + gen_centers(depth + 1, idx + i, start + V[i] * side, side / 3) + + gen_centers(0, 1, np.zeros(3), 1 / 3) + + vertices, faces = primitive.prim_box() + vertices /= 3**N + + bounds_min, bounds_max = np.min(centers, axis=0), np.max(centers, axis=0) + colors = (centers - bounds_min) / (bounds_max - bounds_min) + + vertices, triangles, colors, _ = primitive.repeat_primitive( + centers=centers, colors=colors, vertices=vertices, faces=faces + ) + return utils.get_actor_from_primitive(vertices, triangles, colors) + + +############################################################################### +# Now that we have the functions to generate fractals, we can start setting up +# the Scene and ShowManager. + +scene = window.Scene() +showmgr = window.ShowManager(scene, 'Fractals', (800, 800), reset_camera=True) + +############################################################################### +# These values are what work nicely on my machine without lagging. If you have +# a powerful machine, you could bump these up by around 2-3. + +fractals = [tetrix(6), sponge(3), snowflake(3)] + +############################################################################### +# We want to be able to switch between the three fractals. To achieve this +# we'll create a RadioButton and register a callback which will remove existing +# fractals and add the selected one. This also resets the camera. + +options = { + 'Tetrix': 0, + 'Sponge': 1, + 'Snowflake': 2, +} + +shape_chooser = ui.RadioButton( + options.keys(), + padding=10, + font_size=16, + checked_labels=['Tetrix'], + position=(10, 10), +) + + +def choose_shape(radio): + showmgr.scene.rm(*fractals) + showmgr.scene.add(fractals[options[radio.checked_labels[0]]]) + showmgr.scene.reset_camera() + + +shape_chooser.on_change = choose_shape + +# selected at start +showmgr.scene.add(fractals[0]) +showmgr.scene.add(shape_chooser) + +############################################################################### +# Let's add some basic camera movement to make it look a little interesting. +# We can use a callback here to update a counter and calculate the camera +# positions using the counter. ``sin`` and ``cos`` are used here to make smooth +# looping movements. + +counter = 0 + + +def timer_callback(_obj, _event): + global counter + counter += 1 + showmgr.scene.azimuth(math.sin(counter * 0.01)) + showmgr.scene.elevation(math.cos(counter * 0.01) / 4) + showmgr.render() + + +showmgr.add_timer_callback(True, 20, timer_callback) + +############################################################################### +# Finally, show the window if running in interactive mode or render to an image +# otherwise. This is needed for generating the documentation that you are +# reading. + +interactive = False +if interactive: + showmgr.start() +else: + window.record(showmgr.scene, out_path='fractals.png', size=(800, 800)) diff --git a/v0.10.x/_downloads/0876d276baec8afe5efd02e1c78e1d73/viz_wrecking_ball.ipynb b/v0.10.x/_downloads/0876d276baec8afe5efd02e1c78e1d73/viz_wrecking_ball.ipynb new file mode 100644 index 000000000..72f24ab16 --- /dev/null +++ b/v0.10.x/_downloads/0876d276baec8afe5efd02e1c78e1d73/viz_wrecking_ball.ipynb @@ -0,0 +1,313 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Wrecking Ball Simulation\n\nThis example simulation shows how to use pybullet to render physics simulations\nin fury. In this example we specifically render a brick wall being destroyed by\na wrecking ball.\n\nFirst some imports.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "import itertools\n\nimport numpy as np\nimport pybullet as p\n\nfrom fury import actor, ui, utils, window" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Initiate pybullet and enable gravity.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "p.connect(p.DIRECT)\np.setGravity(0, 0, -10)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Define some handy parameters to customize simulation.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Parameters\nwall_length = 5\nwall_breadth = 5\nwall_height = 5\n\nbrick_size = np.array([0.2, 0.4, 0.2])\n\nn_links = 15\n# Size of segments\ndx_link = 0.1\nlink_mass = 0.5\nbase_mass = 0.1\n# radius of the cylindrical links or the rope\nradii = 0.1\n\nball_mass = 10\n# radius of the wrecking ball\nball_radius = 0.5\nball_color = np.array([[1, 0, 0]])\n\njoint_friction = 0.0005" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Creating the base plane actor.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Base\nbase_actor = actor.box(\n centers=np.array([[0, 0, 0]]),\n directions=[0, 0, 0],\n scales=(5, 5, 0.2),\n colors=(1, 1, 1),\n)\nbase_coll = p.createCollisionShape(p.GEOM_BOX, halfExtents=[2.5, 2.5, 0.1])\nbase = p.createMultiBody(\n baseCollisionShapeIndex=base_coll,\n basePosition=[0, 0, -0.1],\n baseOrientation=[0, 0, 0, 1],\n)\np.changeDynamics(base, -1, lateralFriction=0.3, restitution=0.5)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The following definitions are made to render a NxNxN brick wall.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Generate bricks.\nnb_bricks = wall_length * wall_breadth * wall_height\nbrick_centers = np.zeros((nb_bricks, 3))\n\nbrick_directions = np.zeros((nb_bricks, 3))\nbrick_directions[:] = np.array([1.57, 0, 0])\n\nbrick_orns = np.zeros((nb_bricks, 4))\n\nbrick_sizes = np.zeros((nb_bricks, 3))\nbrick_sizes[:] = brick_size\n\nbrick_colors = np.random.rand(nb_bricks, 3)\n\nbrick_coll = p.createCollisionShape(p.GEOM_BOX, halfExtents=brick_size / 2)\n\nbricks = np.zeros(nb_bricks, dtype=np.int16)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The following is the logic to position the bricks in our desired location and\ngenerate the actor.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "idx = 0\n# Setting up wall\nfor i in range(wall_length):\n for k in range(wall_height):\n for j in range(wall_breadth):\n center_pos = np.array([(i * 0.2) - 1.8, (j * 0.4) - 0.9, (0.2 * k) + 0.1])\n brick_centers[idx] = center_pos\n brick_orns[idx] = np.array([0, 0, 0, 1])\n bricks[idx] = p.createMultiBody(\n baseMass=0.5,\n baseCollisionShapeIndex=brick_coll,\n basePosition=center_pos,\n baseOrientation=brick_orns[i],\n )\n p.changeDynamics(bricks[idx], -1, lateralFriction=0.1, restitution=0.1)\n idx += 1\n\nbrick_actor = actor.box(\n centers=brick_centers,\n directions=brick_directions,\n scales=brick_sizes,\n colors=brick_colors,\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we render the wrecking ball consisting of a fixed hinge, a ball and rope.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Generate wrecking ball\nlink_shape = p.createCollisionShape(\n p.GEOM_CYLINDER,\n radius=radii,\n height=dx_link,\n collisionFramePosition=[0, 0, -dx_link / 2],\n)\n\nbase_shape = p.createCollisionShape(p.GEOM_BOX, halfExtents=[0.01, 0.01, 0.01])\nball_shape = p.createCollisionShape(p.GEOM_SPHERE, radius=ball_radius)\n\nvisualShapeId = -1\n\nlink_Masses = np.zeros(n_links)\nlink_Masses[:] = link_mass\nlink_Masses[-1] = 5\nlinkCollisionShapeIndices = np.zeros(n_links)\nlinkCollisionShapeIndices[:] = np.array(link_shape)\nlinkCollisionShapeIndices[-1] = ball_shape\nlinkVisualShapeIndices = -1 * np.ones(n_links)\nlinkPositions = np.zeros((n_links, 3))\nlinkPositions[:] = np.array([0, 0, -dx_link])\nlinkOrientations = np.zeros((n_links, 4))\nlinkOrientations[:] = np.array([0, 0, 0, 1])\nlinkInertialFramePositions = np.zeros((n_links, 3))\nlinkInertialFrameOrns = np.zeros((n_links, 4))\nlinkInertialFrameOrns[:] = np.array([0, 0, 0, 1])\nindices = np.arange(n_links)\njointTypes = np.zeros(n_links)\njointTypes[:] = np.array(p.JOINT_SPHERICAL)\naxis = np.zeros((n_links, 3))\naxis[:] = np.array([1, 0, 0])\n\nlinkDirections = np.zeros((n_links, 3))\nlinkDirections[:] = np.array([1, 1, 1])\n\nlink_radii = np.zeros(n_links)\nlink_radii[:] = radii\n\nlink_heights = np.zeros(n_links)\nlink_heights[:] = dx_link\n\nrope_actor = actor.cylinder(\n centers=linkPositions,\n directions=linkDirections,\n colors=np.random.rand(n_links, 3),\n radius=radii,\n heights=link_heights,\n capped=True,\n)\n\nbasePosition = [0, 0, 2]\nbaseOrientation = [0, 0, 0, 1]\nrope = p.createMultiBody(\n base_mass,\n base_shape,\n visualShapeId,\n basePosition,\n baseOrientation,\n linkMasses=link_Masses,\n linkCollisionShapeIndices=linkCollisionShapeIndices.astype(int),\n linkVisualShapeIndices=linkVisualShapeIndices.astype(int),\n linkPositions=linkPositions.astype(int),\n linkOrientations=linkOrientations.astype(int),\n linkInertialFramePositions=linkInertialFramePositions.astype(int),\n linkInertialFrameOrientations=linkInertialFrameOrns.astype(int),\n linkParentIndices=indices.astype(int),\n linkJointTypes=jointTypes.astype(int),\n linkJointAxis=axis.astype(int),\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Next we define the frictional force between the joints of wrecking ball.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "friction_vec = [joint_friction] * 3 # same all axis\ncontrol_mode = p.POSITION_CONTROL # set pos control mode\nfor j in range(p.getNumJoints(rope)):\n p.setJointMotorControlMultiDof(\n rope,\n j,\n control_mode,\n targetPosition=[0, 0, 0, 1],\n targetVelocity=[0, 0, 0],\n positionGain=0,\n velocityGain=1,\n force=friction_vec,\n )" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We add the following constraint to keep the cubical hinge fixed.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "root_robe_c = p.createConstraint(\n rope, -1, -1, -1, p.JOINT_FIXED, [0, 0, 0], [0, 0, 0], [0, 0, 2]\n)\n\nbox_actor = actor.box(\n centers=np.array([[0, 0, 0]]),\n directions=np.array([[0, 0, 0]]),\n scales=(0.02, 0.02, 0.02),\n colors=np.array([[1, 0, 0]]),\n)\n\nball_actor = actor.sphere(\n centers=np.array([[0, 0, 0]]), radii=ball_radius, colors=np.array([1, 0, 1])\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we add the necessary actors to the scene and set the camera for better\nvisualization.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "scene = window.Scene()\nscene.set_camera((10.28, -7.10, 6.39), (0.0, 0.0, 0.4), (-0.35, 0.26, 1.0))\nscene.add(actor.axes(scale=(0.5, 0.5, 0.5)), base_actor, brick_actor)\nscene.add(rope_actor, box_actor, ball_actor)\n\nshowm = window.ShowManager(\n scene, size=(900, 768), reset_camera=False, order_transparent=True\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Position the base correctly.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "base_pos, base_orn = p.getBasePositionAndOrientation(base)\nbase_actor.SetPosition(*base_pos)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Calculate the vertices of the bricks.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "brick_vertices = utils.vertices_from_actor(brick_actor)\nnum_vertices = brick_vertices.shape[0]\nnum_objects = brick_centers.shape[0]\nbrick_sec = int(num_vertices / num_objects)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Calculate the vertices of the wrecking ball.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "chain_vertices = utils.vertices_from_actor(rope_actor)\nnum_vertices = chain_vertices.shape[0]\nnum_objects = brick_centers.shape[0]\nchain_sec = int(num_vertices / num_objects)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We define methods to sync bricks and wrecking ball.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Function for syncing actors with multibodies.\ndef sync_brick(object_index, multibody):\n pos, orn = p.getBasePositionAndOrientation(multibody)\n\n rot_mat = np.reshape(\n p.getMatrixFromQuaternion(\n p.getDifferenceQuaternion(orn, brick_orns[object_index])\n ),\n (3, 3),\n )\n\n sec = brick_sec\n\n brick_vertices[object_index * sec : object_index * sec + sec] = (\n brick_vertices[object_index * sec : object_index * sec + sec]\n - brick_centers[object_index]\n ) @ rot_mat + pos\n\n brick_centers[object_index] = pos\n brick_orns[object_index] = orn\n\n\ndef sync_chain(actor_list, multibody):\n for joint in range(p.getNumJoints(multibody)):\n # `p.getLinkState` offers various information about the joints\n # as a list and the values in 4th and 5th index refer to the joint's\n # position and orientation respectively.\n pos, orn = p.getLinkState(multibody, joint)[4:6]\n\n rot_mat = np.reshape(\n p.getMatrixFromQuaternion(\n p.getDifferenceQuaternion(orn, linkOrientations[joint])\n ),\n (3, 3),\n )\n\n sec = chain_sec\n\n chain_vertices[joint * sec : joint * sec + sec] = (\n chain_vertices[joint * sec : joint * sec + sec] - linkPositions[joint]\n ) @ rot_mat + pos\n\n linkPositions[joint] = pos\n linkOrientations[joint] = orn" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Some helper tools to keep track of avg. FPS and simulation steps.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "counter = itertools.count()\nfpss = np.array([])\ntb = ui.TextBlock2D(\n position=(0, 680), font_size=30, color=(1, 0.5, 0), text='Avg. FPS: \\nSim Steps: '\n)\nscene.add(tb)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Timer callback to sync objects, simulate steps and apply force.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "apply_force = True\n\n\n# Create timer callback which will execute at each step of simulation.\ndef timer_callback(_obj, _event):\n global apply_force, fpss\n cnt = next(counter)\n showm.render()\n\n if cnt % 1 == 0:\n fps = showm.frame_rate\n fpss = np.append(fpss, fps)\n tb.message = (\n 'Avg. FPS: ' + str(np.round(np.mean(fpss), 0)) + '\\nSim Steps: ' + str(cnt)\n )\n\n # Updating the position and orientation of each individual brick.\n for idx, brick in enumerate(bricks):\n sync_brick(idx, brick)\n\n pos, _ = p.getBasePositionAndOrientation(rope)\n\n if apply_force:\n p.applyExternalForce(\n rope, -1, forceObj=[-500, 0, 0], posObj=pos, flags=p.WORLD_FRAME\n )\n apply_force = False\n\n pos = p.getLinkState(rope, p.getNumJoints(rope) - 1)[4]\n ball_actor.SetPosition(*pos)\n sync_chain(rope_actor, rope)\n utils.update_actor(brick_actor)\n utils.update_actor(rope_actor)\n\n # Simulate a step.\n p.stepSimulation()\n\n if cnt == 130:\n showm.exit()\n\n\n# Add the timer callback to showmanager.\n# Increasing the duration value will slow down the simulation.\nshowm.add_timer_callback(True, 1, timer_callback)\n\ninteractive = True #False\n\n# start simulation\nif interactive:\n showm.start()\n\nwindow.record(scene, size=(900, 768), out_path='viz_wrecking_ball.png')" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.8" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/v0.10.x/_downloads/0a1e78fb4edd12691b261219a7c8130a/viz_gltf_export.py b/v0.10.x/_downloads/0a1e78fb4edd12691b261219a7c8130a/viz_gltf_export.py new file mode 100644 index 000000000..6595c91cf --- /dev/null +++ b/v0.10.x/_downloads/0a1e78fb4edd12691b261219a7c8130a/viz_gltf_export.py @@ -0,0 +1,67 @@ +""" +============================== +Exporting scene as a glTF file +============================== +In this tutorial, we will show how to create a glTF file for a scene. +""" +import numpy as np + +from fury import actor, gltf, window +from fury.data import fetch_gltf, read_viz_gltf + +############################################################################ +# Specifying centers and colors for actors. We will use these parameters +# later. + +centers = np.zeros((3, 3)) +colors = np.array([1, 1, 1]) + +############################################################################## +# Create a scene. + +scene = window.Scene() + +############################################################################## +# Creating actors and adding to scene. + +cube = actor.cube(np.add(centers, np.array([2, 0, 0])), colors=colors / 2) +scene.add(cube) + +sphere = actor.sphere(np.add(centers, np.array([0, 2, 0])), colors=colors) +scene.add(sphere) + +fetch_gltf('BoxTextured', 'glTF') +filename = read_viz_gltf('BoxTextured') +gltf_obj = gltf.glTF(filename) +box_actor = gltf_obj.actors() +scene.add(box_actor[0]) + +############################################################################## +# Setting camera to the scene. + +scene.set_camera( + position=(4.45, -21, 12), focal_point=(4.45, 0.0, 0.0), view_up=(0.0, 0.0, 1.0) +) + +############################################################################## +# Exporting scene as a glTF file + +gltf.export_scene(scene, filename='viz_gltf_export.gltf') + +############################################################################## +# Reading the newly created glTF file and get actors. + +gltf_obj = gltf.glTF('viz_gltf_export.gltf') +actors = gltf_obj.actors() + +############################################################################## +# Add all the actor from list of actors to the scene. + +scene.add(*actors) + +interactive = False + +if interactive: + window.show(scene, size=(1280, 720)) + +window.record(scene, out_path='viz_gltf_export.png', size=(1280, 720)) diff --git a/v0.10.x/_downloads/0e3f27ad64a68bb8e27f50447dcf2c40/viz_timeline.ipynb b/v0.10.x/_downloads/0e3f27ad64a68bb8e27f50447dcf2c40/viz_timeline.ipynb new file mode 100644 index 000000000..7e9b32575 --- /dev/null +++ b/v0.10.x/_downloads/0e3f27ad64a68bb8e27f50447dcf2c40/viz_timeline.ipynb @@ -0,0 +1,190 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Timeline and setting keyframes\n\nIn his tutorial, you will learn how to use Fury ``Timeline`` for playing the\nanimations.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## What is ``Timeline``?\n\n``Timeline`` is responsible for handling the playback of Fury Animations.\n\n``Timeline`` has playback methods such as ``play``, ``pause``, ``stop``, ...\nwhich can be used to control the animation.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "import numpy as np\n\nfrom fury import actor, window\nfrom fury.animation import Animation, Timeline" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We create our ``Scene`` and ``ShowManager`` as usual.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "scene = window.Scene()\n\nshowm = window.ShowManager(scene, size=(900, 768))\nshowm.initialize()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Creating a ``Timeline``\n\nFURY ``Timeline`` has the option to attaches a very useful panel for\ncontrolling the animation by setting ``playback_panel=True``.\n\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Creating a ``Timeline`` with a PlaybackPanel.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "timeline = Timeline(playback_panel=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Creating a Fury Animation as usual\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "anim = Animation()\nsphere = actor.sphere(np.zeros([1, 3]), np.ones([1, 3]))\nanim.add_actor(sphere)\n# Now that the actor is add to the ``Animation``, setting keyframes to the\n# Animation will animate the actor accordingly." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Setting Keyframes\n\nThere are multiple ways to set keyframes:\n\n1- To set a single keyframe, you may use ``animation.set_(t, k)``,\nwhere is the name of the property to be set. I.e. setting position\nto (1, 2, 3) at time 0.0 would be as following:\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "anim.set_position(0.0, np.array([1, 2, 3]))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Supported properties are: **position, rotation, scale, color, and opacity**.\n\n2- To set multiple keyframes at once, you may use\n``animation.set__keyframes(keyframes)``.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "keyframes = {1.0: np.array([0, 0, 0]), 3.0: np.array([-2, 0, 0])}\n\nanim.set_position_keyframes(keyframes)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "That's it! Now we are done setting keyframes.\n\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In order to control this animation by the timeline we created earlier, this\nanimation must be added to the timeline.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "timeline.add_animation(anim)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we add only the ``Timeline`` to the ``ShowManager`` the same way we add\n``Animation`` to the ``ShowManager``.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "showm.add_animation(timeline)\n\nscene.set_camera(position=(0, 0, -10))\n\ninteractive = False\n\nif interactive:\n showm.start()\n\nwindow.record(scene, out_path='viz_keyframe_animation_timeline.png', size=(900, 768))" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.8" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/v0.10.x/_downloads/1159dab220778ac5e3d8ffe6030f5272/viz_multithread.py b/v0.10.x/_downloads/1159dab220778ac5e3d8ffe6030f5272/viz_multithread.py new file mode 100644 index 000000000..a68e3ec37 --- /dev/null +++ b/v0.10.x/_downloads/1159dab220778ac5e3d8ffe6030f5272/viz_multithread.py @@ -0,0 +1,113 @@ +""" +======================================================= +Multithreading Example +======================================================= + +The goal of this demo is to show how to use different threads +to interact with FURY. In particular, the main thread is used +to update interactions and render the scene, while thread A +rotates the camera, thread B prints a counter, and thread C +adds and removes elements from the scene. +""" + +import time +from threading import Thread + +import numpy as np + +from fury import actor, ui, window + +# Preparing to draw some spheres +xyz = 10 * (np.random.random((100, 3)) - 0.5) +colors = np.random.random((100, 4)) +radii = np.random.random(100) + 0.5 + +scene = window.Scene() +sphere_actor = actor.sphere( + centers=xyz, colors=colors, radii=radii, use_primitive=False +) +scene.add(sphere_actor) + + +# Preparing the show manager as usual +showm = window.ShowManager( + scene, size=(900, 768), reset_camera=False, order_transparent=True +) + +# showm.initialize() + +# Creating a text block to show a message and reset the camera +tb = ui.TextBlock2D(bold=True) +scene.add(tb) +scene.ResetCamera() + + +# Create a function to print a counter to the console +def print_counter(): + print('') + for i in range(100): + print('\rCounter: %d' % i, end='') + message = "Let's count up to 100 and exit :" + str(i + 1) + tb.message = message + time.sleep(0.05) + if showm.is_done(): + break + showm.exit() + print('') + + +# Create a function to rotate the camera + + +def rotate_camera(): + for i in range(100): + if showm.lock_current(): + scene.azimuth(0.01 * i) + showm.release_current() + time.sleep(0.05) + else: + break + + +# Create a function to add or remove the axes and increase its scale + + +def add_remove_axes(): + current_axes = None + for i in range(100): + if showm.lock_current(): + if current_axes is None: + current_axes = actor.axes(scale=(0.20 * i, 0.20 * i, 0.20 * i)) + scene.add(current_axes) + pass + else: + scene.rm(current_axes) + current_axes = None + pass + showm.release_current() + time.sleep(0.1) + else: + break + + +# Start the threads +# Multiple threads can be started here +# First, one to rotate the camera +thread_a = Thread(target=rotate_camera) +thread_a.start() + +# Now let's start a thread that will print a counter +thread_b = Thread(target=print_counter) +thread_b.start() + +# Now let's start a thread that will add or remove axes +thread_c = Thread(target=add_remove_axes) +thread_c.start() + +# Let's start the show manager loop with multithreading option +showm.start(multithreaded=True) + +# Wait for the threads to finish +thread_a.join() +thread_b.join() +thread_c.join() diff --git a/v0.10.x/_downloads/158a5837a2e576427d337801d7f86d9c/viz_check_boxes.py b/v0.10.x/_downloads/158a5837a2e576427d337801d7f86d9c/viz_check_boxes.py new file mode 100644 index 000000000..99c9fada1 --- /dev/null +++ b/v0.10.x/_downloads/158a5837a2e576427d337801d7f86d9c/viz_check_boxes.py @@ -0,0 +1,164 @@ +""" +============================================================ +Figure and Color Control using Check boxes and Radio Buttons +============================================================ + +This example shows how to use the CheckBox UI API. We will demonstrate how to +create a cube, sphere, cone and arrow and control its color and visibility +using checkboxes. + +First, some imports. +""" + +import numpy as np + +from fury import actor, ui, utils, window +from fury.data import fetch_viz_icons + +############################################################################## +# First we need to fetch some icons that are included in FURY. + +fetch_viz_icons() + +############################################################################### +# We create the corresponding object actors for cube, sphere, cone and arrow. + +cube = actor.cube( + centers=np.array([[15, 0, 0]]), + colors=np.array([[0, 0, 1]]), + scales=np.array([[20, 20, 20]]), + directions=np.array([[0, 0, 1]]), +) + +sphere = actor.sphere( + centers=np.array([[50, 0, 0]]), + colors=np.array([[0, 0, 1]]), + radii=11.0, + theta=360, + phi=360, +) + +cone = actor.cone( + centers=np.array([[-20, -0.5, 0]]), + directions=np.array([[0, 1, 0]]), + colors=np.array([[0, 0, 1]]), + heights=20, + resolution=100, +) + +arrow = actor.arrow( + centers=np.array([[0, 25, 0]]), + colors=np.array([[0, 0, 1]]), + directions=np.array([[1, 0, 0]]), + heights=40, + resolution=100, +) + +############################################################################### +# We perform symmetric difference to determine the unchecked options. +# We also define methods to render visibility and color. + + +# Get difference between two lists. +def sym_diff(l1, l2): + return list(set(l1).symmetric_difference(set(l2))) + + +# Set Visibility of the figures +def set_figure_visiblity(checkboxes): + checked = checkboxes.checked_labels + unchecked = sym_diff(list(figure_dict), checked) + + for visible in checked: + figure_dict[visible].SetVisibility(True) + + for invisible in unchecked: + figure_dict[invisible].SetVisibility(False) + + +def update_colors(color_array): + for _, figure in figure_dict.items(): + vcolors = utils.colors_from_actor(figure) + vcolors[:] = color_array + utils.update_actor(figure) + + +# Toggle colors of the figures +def toggle_color(checkboxes): + colors = checkboxes.checked_labels + + color_array = np.array([0, 0, 0]) + + for col in colors: + if col == 'Red': + color_array[0] = 255 + elif col == 'Green': + color_array[1] = 255 + else: + color_array[2] = 255 + + update_colors(color_array) + + +############################################################################### +# We define a dictionary to store the actors with their names as keys. +# A checkbox is created with actor names as it's options. + +figure_dict = {'cube': cube, 'sphere': sphere, 'cone': cone, 'arrow': arrow} +check_box = ui.Checkbox( + list(figure_dict), + list(figure_dict), + padding=1, + font_size=18, + font_family='Arial', + position=(400, 85), +) + +############################################################################### +# A similar checkbox is created for changing colors. + +options = {'Blue': (0, 0, 1), 'Red': (1, 0, 0), 'Green': (0, 1, 0)} +color_toggler = ui.Checkbox( + list(options), + checked_labels=['Blue'], + padding=1, + font_size=16, + font_family='Arial', + position=(600, 120), +) + + +check_box.on_change = set_figure_visiblity +color_toggler.on_change = toggle_color + + +############################################################################### +# Show Manager +# ================================== +# +# Now that all the elements have been initialised, we add them to the show +# manager. + +current_size = (1000, 1000) +show_manager = window.ShowManager(size=current_size, title='FURY Checkbox Example') + +show_manager.scene.add(cube) +show_manager.scene.add(sphere) +show_manager.scene.add(cone) +show_manager.scene.add(arrow) +show_manager.scene.add(check_box) +show_manager.scene.add(color_toggler) + +############################################################################### +# Set camera for better visualization + +show_manager.scene.reset_camera() +show_manager.scene.set_camera(position=(0, 0, 150)) +show_manager.scene.reset_clipping_range() +show_manager.scene.azimuth(30) +interactive = False + +if interactive: + show_manager.start() + +window.record(show_manager.scene, size=current_size, out_path='viz_checkbox.png') diff --git a/v0.10.x/_downloads/15ac013b7a87b60bc067a78f156ac21f/viz_texture.ipynb b/v0.10.x/_downloads/15ac013b7a87b60bc067a78f156ac21f/viz_texture.ipynb new file mode 100644 index 000000000..d8247226b --- /dev/null +++ b/v0.10.x/_downloads/15ac013b7a87b60bc067a78f156ac21f/viz_texture.ipynb @@ -0,0 +1,115 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Sphere Texture\nIn this tutorial, we will show how to create a sphere with a texture.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "from fury import actor, io, window\nfrom fury.data import fetch_viz_textures, read_viz_textures" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Create a scene to start.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "scene = window.Scene()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Load an image (png, bmp, jpeg or jpg) using ``io.load_image``. In this\nexample, we will use ``read_viz_textures`` to access an image of the\nEarth's surface from the fury Github after using ''fetch_viz_textures()''\nto download the available textures.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "fetch_viz_textures()\nfilename = read_viz_textures('1_earth_8k.jpg')\nimage = io.load_image(filename)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Next, use ``actor.texture_on_sphere`` to add a sphere with the texture from\nyour loaded image to the already existing scene.\nTo add a texture to your scene as visualized on a plane, use\n``actor.texture`` instead.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "scene.add(actor.texture_on_sphere(image))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Lastly, record the scene, or set interactive to True if you would like to\nmanipulate your new sphere.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "interactive = False\nif interactive:\n window.show(scene, size=(600, 600), reset_camera=False)\nwindow.record(scene, size=(900, 768), out_path='viz_texture.png')" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.8" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/v0.10.x/_downloads/16be6a14d02d2f4211e44f5bd4014bc3/viz_earth_coordinates.ipynb b/v0.10.x/_downloads/16be6a14d02d2f4211e44f5bd4014bc3/viz_earth_coordinates.ipynb new file mode 100644 index 000000000..46106ec2f --- /dev/null +++ b/v0.10.x/_downloads/16be6a14d02d2f4211e44f5bd4014bc3/viz_earth_coordinates.ipynb @@ -0,0 +1,205 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Earth Coordinate Conversion\n\nIn this tutorial, we will show how to place actors on specific locations\non the surface of the Earth using a new function.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "import itertools\nimport math\n\nimport numpy as np\n\nfrom fury import actor, io, utils, window\nfrom fury.data import fetch_viz_textures, read_viz_textures" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Create a new scene, and load in the image of the Earth using\n``fetch_viz_textures`` and ``read_viz_textures``. We will use a 16k\nresolution texture for maximum detail.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "scene = window.Scene()\n\nfetch_viz_textures()\nearth_file = read_viz_textures('1_earth_16k.jpg')\nearth_image = io.load_image(earth_file)\nearth_actor = actor.texture_on_sphere(earth_image)\nscene.add(earth_actor)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Rotate the Earth to make sure the texture is correctly oriented. Change it's\nscale using ``actor.SetScale()``.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "utils.rotate(earth_actor, (-90, 1, 0, 0))\nutils.rotate(earth_actor, (180, 0, 1, 0))\nearth_actor.SetScale(2, 2, 2)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Define the function to convert geographical coordinates of a location in\nlatitude and longitude degrees to coordinates on the ``earth_actor`` surface.\nIn this function, convert to radians, then to spherical coordinates, and\nlastly, to cartesian coordinates.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def latlong_coordinates(lat, lon):\n # Convert latitude and longitude to spherical coordinates\n degrees_to_radians = math.pi / 180.0\n # phi = 90 - latitude\n phi = (90 - lat) * degrees_to_radians\n # theta = longitude\n theta = lon * degrees_to_radians * -1\n # now convert to cartesian\n x = np.sin(phi) * np.cos(theta)\n y = np.sin(phi) * np.sin(theta)\n z = np.cos(phi)\n # flipping z to y for FURY coordinates\n return (x, z, y)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Use this new function to place some sphere actors on several big cities\naround the Earth.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "locationone = latlong_coordinates(40.730610, -73.935242) # new york city, us\nlocationtwo = latlong_coordinates(39.916668, 116.383331) # beijing, china\nlocationthree = latlong_coordinates(48.864716, 2.349014) # paris, france" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Set the centers, radii, and colors of these spheres, and create a new\n``sphere_actor`` for each location to add to the scene.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "centers = np.array([[*locationone], [*locationtwo], [*locationthree]])\ncolors = np.random.rand(3, 3)\nradii = np.array([0.005, 0.005, 0.005])\nsphere_actor = actor.sphere(centers, colors, radii)\nscene.add(sphere_actor)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Create some text actors to add to the scene indicating each location and its\ngeographical coordinates.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "nyc_actor = actor.text_3d(\n 'New York City, New York\\n40.7128\u00b0 N, 74.0060\u00b0 W',\n (locationone[0] - 0.04, locationone[1], locationone[2] + 0.07),\n window.colors.white,\n 0.01,\n)\nparis_actor = actor.text_3d(\n 'Paris, France\\n48.8566\u00b0 N, 2.3522\u00b0 E',\n (locationthree[0] - 0.04, locationthree[1], locationthree[2] - 0.07),\n window.colors.white,\n 0.01,\n)\nbeijing_actor = actor.text_3d(\n 'Beijing, China\\n39.9042\u00b0 N, 116.4074\u00b0 E',\n (locationtwo[0] - 0.06, locationtwo[1], locationtwo[2] - 0.07),\n window.colors.white,\n 0.01,\n)\nutils.rotate(paris_actor, (85, 0, 1, 0))\nutils.rotate(beijing_actor, (180, 0, 1, 0))\nutils.rotate(nyc_actor, (5, 1, 0, 0))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Create a ShowManager object, which acts as the interface between the scene,\nthe window and the interactor.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "showm = window.ShowManager(\n scene, size=(900, 768), reset_camera=False, order_transparent=True\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's create a ``timer_callback`` function to add some animation to the\nEarth. Change the camera position and angle to fly over and zoom in on each\nnew location.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "counter = itertools.count()\n\n\ndef timer_callback(_obj, _event):\n cnt = next(counter)\n showm.render()\n if cnt == 0:\n scene.set_camera(position=(1.5, 3.5, 7.0))\n if cnt < 200 and cnt > 25:\n scene.zoom(1.015)\n scene.pitch(0.01)\n if cnt == 200:\n scene.add(nyc_actor)\n if cnt > 250 and cnt < 350:\n scene.zoom(0.985)\n if cnt > 350 and cnt < 425:\n scene.azimuth(1)\n if cnt > 425 and cnt < 525:\n scene.zoom(1.015)\n scene.pitch(0.011)\n if cnt == 525:\n scene.add(paris_actor)\n if cnt > 575 and cnt < 700:\n scene.zoom(0.985)\n if cnt > 700 and cnt < 820:\n scene.azimuth(1)\n if cnt > 820 and cnt < 930:\n scene.zoom(1.015)\n if cnt == 930:\n scene.add(beijing_actor)\n if cnt == 1000:\n showm.exit()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Initialize the ShowManager object, add the timer_callback, and watch the\nnew animation take place!\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "showm.add_timer_callback(True, 25, timer_callback)\nshowm.start()\n\nwindow.record(showm.scene, size=(900, 768), out_path='viz_earth_coordinates.png')" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.8" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/v0.10.x/_downloads/18abde366d53ac67affaf44a0d2cc267/viz_fiber_odf.ipynb b/v0.10.x/_downloads/18abde366d53ac67affaf44a0d2cc267/viz_fiber_odf.ipynb new file mode 100644 index 000000000..d56b5f67e --- /dev/null +++ b/v0.10.x/_downloads/18abde366d53ac67affaf44a0d2cc267/viz_fiber_odf.ipynb @@ -0,0 +1,223 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Brain Fiber ODF Visualisation\n\nThis example demonstrate how to create a simple viewer for fiber\norientation distribution functions (ODF) using fury's odf_slicer.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "import nibabel as nib\n\n# First, we import some useful modules and methods.\nimport numpy as np\nfrom dipy.data import get_sphere\nfrom dipy.reconst.shm import sh_to_sf_matrix\n\nfrom fury import actor, ui, window\nfrom fury.data import fetch_viz_dmri, fetch_viz_icons, read_viz_dmri\nfrom fury.utils import fix_winding_order" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Here, we fetch and load the fiber ODF volume to display. The ODF are\nexpressed as spherical harmonics (SH) coefficients in a 3D grid.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "fetch_viz_dmri()\nfetch_viz_icons()\n\nfodf_img = nib.load(read_viz_dmri('fodf.nii.gz'))\nsh = fodf_img.get_fdata()\naffine = fodf_img.affine\ngrid_shape = sh.shape[:-1]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We then define a low resolution sphere used to visualize SH coefficients\nas spherical functions (SF) as well as a matrix `B_low` to project SH\nonto the sphere.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "sphere_low = get_sphere('repulsion100')\nB_low = sh_to_sf_matrix(sphere_low, 8, return_inv=False)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now, we create a slicer for each orientation to display a slice in\nthe middle of the volume and we add them to a `scene`.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Change these values to test various parameters combinations.\nscale = 0.5\nnorm = False\ncolormap = None\nradial_scale = True\nopacity = 1.0\nglobal_cm = False\n\n# ODF slicer for axial slice\nodf_actor_z = actor.odf_slicer(\n sh,\n affine=affine,\n sphere=sphere_low,\n scale=scale,\n norm=norm,\n radial_scale=radial_scale,\n opacity=opacity,\n colormap=colormap,\n global_cm=global_cm,\n B_matrix=B_low,\n)\n\n# ODF slicer for coronal slice\nodf_actor_y = actor.odf_slicer(\n sh,\n affine=affine,\n sphere=sphere_low,\n scale=scale,\n norm=norm,\n radial_scale=radial_scale,\n opacity=opacity,\n colormap=colormap,\n global_cm=global_cm,\n B_matrix=B_low,\n)\nodf_actor_y.display_extent(\n 0, grid_shape[0] - 1, grid_shape[1] // 2, grid_shape[1] // 2, 0, grid_shape[2] - 1\n)\n\n# ODF slicer for sagittal slice\nodf_actor_x = actor.odf_slicer(\n sh,\n affine=affine,\n sphere=sphere_low,\n scale=scale,\n norm=norm,\n radial_scale=radial_scale,\n opacity=opacity,\n colormap=colormap,\n global_cm=global_cm,\n B_matrix=B_low,\n)\nodf_actor_x.display_extent(\n grid_shape[0] // 2, grid_shape[0] // 2, 0, grid_shape[1] - 1, 0, grid_shape[2] - 1\n)\n\nscene = window.Scene()\nscene.add(odf_actor_z)\nscene.add(odf_actor_y)\nscene.add(odf_actor_x)\n\nshow_m = window.ShowManager(scene, reset_camera=True, size=(1200, 900))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now that we have a `ShowManager` containing our slicer, we can go on and\nconfigure our UI for changing the slices to visualize.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "line_slider_z = ui.LineSlider2D(\n min_value=0,\n max_value=grid_shape[2] - 1,\n initial_value=grid_shape[2] / 2,\n text_template='{value:.0f}',\n length=140,\n)\n\nline_slider_y = ui.LineSlider2D(\n min_value=0,\n max_value=grid_shape[1] - 1,\n initial_value=grid_shape[1] / 2,\n text_template='{value:.0f}',\n length=140,\n)\n\nline_slider_x = ui.LineSlider2D(\n min_value=0,\n max_value=grid_shape[0] - 1,\n initial_value=grid_shape[0] / 2,\n text_template='{value:.0f}',\n length=140,\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We also define a high resolution sphere to demonstrate the capability to\ndynamically change the sphere used for SH to SF projection.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "sphere_high = get_sphere('symmetric362')\n\n# We fix the order of the faces' three vertices to a clockwise winding. This\n# ensures all faces have a normal going away from the center of the sphere.\nsphere_high.faces = fix_winding_order(sphere_high.vertices, sphere_high.faces, True)\nB_high = sh_to_sf_matrix(sphere_high, 8, return_inv=False)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We add a combobox for choosing the sphere resolution during execution.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "sphere_dict = {\n 'Low resolution': (sphere_low, B_low),\n 'High resolution': (sphere_high, B_high),\n}\ncombobox = ui.ComboBox2D(items=list(sphere_dict))\nscene.add(combobox)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Here we will write callbacks for the sliders and combo box and register them.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def change_slice_z(slider):\n i = int(np.round(slider.value))\n odf_actor_z.slice_along_axis(i)\n\n\ndef change_slice_y(slider):\n i = int(np.round(slider.value))\n odf_actor_y.slice_along_axis(i, 'yaxis')\n\n\ndef change_slice_x(slider):\n i = int(np.round(slider.value))\n odf_actor_x.slice_along_axis(i, 'xaxis')\n\n\ndef change_sphere(combobox):\n sphere, B = sphere_dict[combobox.selected_text]\n odf_actor_x.update_sphere(sphere.vertices, sphere.faces, B)\n odf_actor_y.update_sphere(sphere.vertices, sphere.faces, B)\n odf_actor_z.update_sphere(sphere.vertices, sphere.faces, B)\n\n\nline_slider_z.on_change = change_slice_z\nline_slider_y.on_change = change_slice_y\nline_slider_x.on_change = change_slice_x\ncombobox.on_change = change_sphere" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We then add labels for the sliders and position them inside a panel.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def build_label(text):\n label = ui.TextBlock2D()\n label.message = text\n label.font_size = 18\n label.font_family = 'Arial'\n label.justification = 'left'\n label.bold = False\n label.italic = False\n label.shadow = False\n label.background_color = (0, 0, 0)\n label.color = (1, 1, 1)\n\n return label\n\n\nline_slider_label_z = build_label(text='Z Slice')\nline_slider_label_y = build_label(text='Y Slice')\nline_slider_label_x = build_label(text='X Slice')\n\npanel = ui.Panel2D(size=(300, 200), color=(1, 1, 1), opacity=0.1, align='right')\npanel.center = (1030, 120)\n\npanel.add_element(line_slider_label_x, (0.1, 0.75))\npanel.add_element(line_slider_x, (0.38, 0.75))\npanel.add_element(line_slider_label_y, (0.1, 0.55))\npanel.add_element(line_slider_y, (0.38, 0.55))\npanel.add_element(line_slider_label_z, (0.1, 0.35))\npanel.add_element(line_slider_z, (0.38, 0.35))\n\nshow_m.scene.add(panel)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Then, we can render all the widgets and everything else in the screen and\nstart the interaction using ``show_m.start()``.\n\nHowever, if you change the window size, the panel will not update its\nposition properly. The solution to this issue is to update the position of\nthe panel using its ``re_align`` method every time the window size changes.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "size = scene.GetSize()\n\n\ndef win_callback(obj, _event):\n global size\n if size != obj.GetSize():\n size_old = size\n size = obj.GetSize()\n size_change = [size[0] - size_old[0], 0]\n panel.re_align(size_change)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Finally, please set the following variable to ``True`` to interact with the\ndatasets in 3D.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "interactive = False\n\nif interactive:\n show_m.add_window_callback(win_callback)\n show_m.render()\n show_m.start()\nelse:\n window.record(\n scene, out_path='odf_slicer_3D.png', size=(1200, 900), reset_camera=False\n )\n\ndel show_m" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.8" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/v0.10.x/_downloads/18f7c71044fd9fd6355153b36a44c393/viz_ui_slider.ipynb b/v0.10.x/_downloads/18f7c71044fd9fd6355153b36a44c393/viz_ui_slider.ipynb new file mode 100644 index 000000000..b48ae6553 --- /dev/null +++ b/v0.10.x/_downloads/18f7c71044fd9fd6355153b36a44c393/viz_ui_slider.ipynb @@ -0,0 +1,187 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Cube & Slider Control\n\nThis example shows how to use the UI API. We will demonstrate how to\ncreate a cube and control with sliders.\n\nFirst, some imports.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "import numpy as np\n\nfrom fury import actor, ui, window\nfrom fury.data import fetch_viz_icons" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "First we need to fetch some icons that are included in FURY.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "fetch_viz_icons()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Cube and sliders\n\nAdd a cube to the scene .\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "cube = actor.cube(\n centers=np.array([[15, 0, 0]]),\n colors=np.array([[0, 0, 1]]),\n scales=np.array([[20, 20, 20]]),\n directions=np.array([[0, 0, 1]]),\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we'll add five sliders: 1 circular and 4 linear sliders.\nBy default the alignments are 'bottom' for horizontal and 'top' for vertical.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "ring_slider = ui.RingSlider2D(\n center=(630, 400), initial_value=0, text_template='{angle:5.1f}\u00b0'\n)\n\nhor_line_slider_text_top = ui.LineSlider2D(\n center=(400, 230),\n initial_value=0,\n orientation='horizontal',\n min_value=-10,\n max_value=10,\n text_alignment='top',\n)\n\nhor_line_slider_text_bottom = ui.LineSlider2D(\n center=(400, 200),\n initial_value=0,\n orientation='horizontal',\n min_value=-10,\n max_value=10,\n text_alignment='bottom',\n)\n\nver_line_slider_text_left = ui.LineSlider2D(\n center=(100, 400),\n initial_value=0,\n orientation='vertical',\n min_value=-10,\n max_value=10,\n text_alignment='left',\n)\n\nver_line_slider_text_right = ui.LineSlider2D(\n center=(150, 400),\n initial_value=0,\n orientation='vertical',\n min_value=-10,\n max_value=10,\n text_alignment='right',\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can use a callback to rotate the cube with the ring slider.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def rotate_cube(slider):\n angle = slider.value\n previous_angle = slider.previous_value\n rotation_angle = angle - previous_angle\n cube.RotateX(rotation_angle)\n\n\nring_slider.on_change = rotate_cube" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Similarly, we can translate the cube with the line slider.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def translate_cube_ver(slider):\n value = slider.value\n cube.SetPosition(0, value, 0)\n\n\ndef translate_cube_hor(slider):\n value = slider.value\n cube.SetPosition(value, 0, 0)\n\n\nhor_line_slider_text_top.on_change = translate_cube_hor\nhor_line_slider_text_bottom.on_change = translate_cube_hor\nver_line_slider_text_left.on_change = translate_cube_ver\nver_line_slider_text_right.on_change = translate_cube_ver" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Show Manager\n\nNow that all the elements have been initialised, we add them to the show\nmanager.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "current_size = (800, 800)\nshow_manager = window.ShowManager(size=current_size, title='FURY Cube Example')\n\nshow_manager.scene.add(cube)\nshow_manager.scene.add(ring_slider)\nshow_manager.scene.add(hor_line_slider_text_top)\nshow_manager.scene.add(hor_line_slider_text_bottom)\nshow_manager.scene.add(ver_line_slider_text_left)\nshow_manager.scene.add(ver_line_slider_text_right)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Visibility by default is True\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "cube.SetVisibility(True)\nring_slider.set_visibility(True)\nhor_line_slider_text_top.set_visibility(True)\nhor_line_slider_text_bottom.set_visibility(True)\nver_line_slider_text_left.set_visibility(True)\nver_line_slider_text_right.set_visibility(True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Set camera for better visualization\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "show_manager.scene.reset_camera()\nshow_manager.scene.set_camera(position=(0, 0, 150))\nshow_manager.scene.reset_clipping_range()\nshow_manager.scene.azimuth(30)\ninteractive = False\n\nif interactive:\n show_manager.start()\n\nwindow.record(show_manager.scene, size=current_size, out_path='viz_slider.png')" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.8" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/v0.10.x/_downloads/1aed981eaa1875aa30849f0d22d80711/viz_gltf_animated.ipynb b/v0.10.x/_downloads/1aed981eaa1875aa30849f0d22d80711/viz_gltf_animated.ipynb new file mode 100644 index 000000000..ec6ce1543 --- /dev/null +++ b/v0.10.x/_downloads/1aed981eaa1875aa30849f0d22d80711/viz_gltf_animated.ipynb @@ -0,0 +1,133 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Visualizing a glTF file\nIn this tutorial, we will show how to display a simple animated glTF in a\nscene.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "from fury import window\nfrom fury.data import fetch_gltf, read_viz_gltf\nfrom fury.gltf import glTF" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Create a scene.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "scene = window.Scene()\n\nshowm = window.ShowManager(\n scene, size=(900, 768), reset_camera=False, order_transparent=True\n)\nshowm.initialize()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Retrieving the gltf model.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "fetch_gltf('InterpolationTest', 'glTF')\nfilename = read_viz_gltf('InterpolationTest')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Initialize the glTF object and get actors using `actors` method.\nGet the main_timeline (which contains multiple Timeline objects).\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "gltf_obj = glTF(filename)\ntimeline = gltf_obj.main_animation()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Add the timeline to the scene (No need to add actors separately).\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "scene.add(timeline)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "define a timer_callback that updates the timeline.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "interactive = False\n\n\ndef timer_callback(_obj, _event):\n timeline.update_animation()\n showm.render()\n\n\nshowm.add_timer_callback(True, 10, timer_callback)\n\nif interactive:\n showm.start()\n\nwindow.record(scene, out_path='viz_gltf_animated.png', size=(900, 768))" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.8" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/v0.10.x/_downloads/1d951c714c2deed5aafc8e2ac04a3a76/viz_emwave_animation.py b/v0.10.x/_downloads/1d951c714c2deed5aafc8e2ac04a3a76/viz_emwave_animation.py new file mode 100644 index 000000000..52beb9735 --- /dev/null +++ b/v0.10.x/_downloads/1d951c714c2deed5aafc8e2ac04a3a76/viz_emwave_animation.py @@ -0,0 +1,181 @@ +""" +=============================================== +Electromagnetic Wave Propagation Animation +=============================================== + +A linearly polarized sinusoidal electromagnetic wave, propagating in the +direction +x through a homogeneous, isotropic, dissipationless medium, +such as vacuum. The electric field (blue arrows) oscillates in the +±z-direction, and the orthogonal magnetic field (red arrows) oscillates in +phase with the electric field, but in the ±y-direction. + +Function of the sinusoid used in the animation = sin(k*x - w*t + d) +Where, k:wavenumber, x:abscissa, w:angular frequency, t:time, d:phase angle + +Importing necessary modules +""" + +import itertools + +import numpy as np + +from fury import actor, ui, utils, window + +############################################################################### +# function that updates and returns the coordinates of the waves which are +# changing with time + + +def update_coordinates(wavenumber, ang_frq, time, phase_angle): + x = np.linspace(-3, 3, npoints) + y = np.sin(wavenumber * x - ang_frq * time + phase_angle) + z = np.array([0 for i in range(npoints)]) + return x, y, z + + +############################################################################### +# Variable(s) and their description- +# npoints: For high quality rendering, keep the number of npoints high +# but kindly note that higher values for npoints will slow down the +# rendering process (default = 800) +# wavelength : wavelength of the wave (default = 2) +# wavenumber : 2*pi/wavelength +# time: time (default time i.e. time at beginning of the animation = 0) +# incre_time: value by which time is incremented for each call of +# timer_callback (default = 0.1) +# angular_frq: angular frequency (default = 0.1) +# phase_angle: phase angle (default = 0.002) + + +npoints = 800 +wavelength = 2 +wavenumber = 2 * np.pi / wavelength +time = 0 +incre_time = 0.1 +angular_frq = 0.1 +phase_angle = 0.002 + +############################################################################### +# Creating a scene object and configuring the camera's position + +scene = window.Scene() +scene.set_camera( + position=(-6, 5, -10), focal_point=(0.0, 0.0, 0.0), view_up=(0.0, 0.0, 0.0) +) +showm = window.ShowManager( + scene, size=(800, 600), reset_camera=True, order_transparent=True +) + + +############################################################################### +# Creating a yellow colored arrow to show the direction of propagation of +# electromagnetic wave + +centers = np.array([[3, 0, 0]]) +directions = np.array([[-1, 0, 0]]) +heights = np.array([6.4]) +arrow_actor = actor.arrow( + centers, + directions, + window.colors.yellow, + heights, + resolution=20, + tip_length=0.06, + tip_radius=0.012, + shaft_radius=0.005, +) +scene.add(arrow_actor) + + +############################################################################### +# Creating point actor that renders the magnetic field + +x = np.linspace(-3, 3, npoints) +y = np.sin(wavenumber * x - angular_frq * time + phase_angle) +z = np.array([0 for i in range(npoints)]) + +pts = np.array([(a, b, c) for (a, b, c) in zip(x, y, z)]) +pts = [pts] +colors = window.colors.red +wave_actor1 = actor.line(pts, colors, linewidth=3) +scene.add(wave_actor1) + +vertices = utils.vertices_from_actor(wave_actor1) +vcolors = utils.colors_from_actor(wave_actor1, 'colors') +no_vertices_per_point = len(vertices) / npoints +initial_vertices = vertices.copy() - np.repeat(pts, no_vertices_per_point, axis=0) + + +############################################################################### +# Creating point actor that renders the electric field + +xx = np.linspace(-3, 3, npoints) +yy = np.array([0 for i in range(npoints)]) +zz = np.sin(wavenumber * xx - angular_frq * time + phase_angle) + +pts2 = np.array([(a, b, c) for (a, b, c) in zip(xx, yy, zz)]) +pts2 = [pts2] +colors2 = window.colors.blue +wave_actor2 = actor.line(pts2, colors2, linewidth=3) +scene.add(wave_actor2) + +vertices2 = utils.vertices_from_actor(wave_actor2) +vcolors2 = utils.colors_from_actor(wave_actor2, 'colors') +no_vertices_per_point2 = len(vertices2) / npoints +initial_vertices2 = vertices2.copy() - np.repeat(pts2, no_vertices_per_point2, axis=0) + + +############################################################################### +# Initializing text box to display the title of the animation + +tb = ui.TextBlock2D(bold=True, position=(160, 90)) +tb.message = 'Electromagnetic Wave' +scene.add(tb) + +############################################################################### +# end is used to decide when to end the animation + +end = 300 + +############################################################################### +# Initializing counter + +counter = itertools.count() + + +############################################################################### +# Coordinates to be plotted are changed every time timer_callback is called by +# using the update_coordinates function. The wave is rendered here. + + +def timer_callback(_obj, _event): + global pts, pts2, time, time_incre, angular_frq, phase_angle, wavenumber + time += incre_time + cnt = next(counter) + + x, y, z = update_coordinates(wavenumber, angular_frq, phase_angle, time) + pts = np.array([(a, b, c) for (a, b, c) in zip(x, y, z)]) + vertices[:] = initial_vertices + np.repeat(pts, no_vertices_per_point, axis=0) + utils.update_actor(wave_actor1) + + xx, zz, yy = update_coordinates(wavenumber, angular_frq, phase_angle, time) + pts2 = np.array([(a, b, c) for (a, b, c) in zip(xx, yy, zz)]) + vertices2[:] = initial_vertices2 + np.repeat(pts2, no_vertices_per_point2, axis=0) + utils.update_actor(wave_actor2) + + showm.render() + + # to end the animation + if cnt == end: + showm.exit() + + +############################################################################### +# Run every 25 milliseconds + +showm.add_timer_callback(True, 25, timer_callback) + +interactive = False +if interactive: + showm.start() +window.record(showm.scene, size=(800, 600), out_path='viz_emwave.png') diff --git a/v0.10.x/_downloads/1df8e277ac4cffc66aae9d565b9aa134/viz_multithread.ipynb b/v0.10.x/_downloads/1df8e277ac4cffc66aae9d565b9aa134/viz_multithread.ipynb new file mode 100644 index 000000000..b38e33f71 --- /dev/null +++ b/v0.10.x/_downloads/1df8e277ac4cffc66aae9d565b9aa134/viz_multithread.ipynb @@ -0,0 +1,43 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Multithreading Example\n\nThe goal of this demo is to show how to use different threads\nto interact with FURY. In particular, the main thread is used\nto update interactions and render the scene, while thread A\nrotates the camera, thread B prints a counter, and thread C\nadds and removes elements from the scene.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "import time\nfrom threading import Thread\n\nimport numpy as np\n\nfrom fury import actor, ui, window\n\n# Preparing to draw some spheres\nxyz = 10 * (np.random.random((100, 3)) - 0.5)\ncolors = np.random.random((100, 4))\nradii = np.random.random(100) + 0.5\n\nscene = window.Scene()\nsphere_actor = actor.sphere(\n centers=xyz, colors=colors, radii=radii, use_primitive=False\n)\nscene.add(sphere_actor)\n\n\n# Preparing the show manager as usual\nshowm = window.ShowManager(\n scene, size=(900, 768), reset_camera=False, order_transparent=True\n)\n\n# showm.initialize()\n\n# Creating a text block to show a message and reset the camera\ntb = ui.TextBlock2D(bold=True)\nscene.add(tb)\nscene.ResetCamera()\n\n\n# Create a function to print a counter to the console\ndef print_counter():\n print('')\n for i in range(100):\n print('\\rCounter: %d' % i, end='')\n message = \"Let's count up to 100 and exit :\" + str(i + 1)\n tb.message = message\n time.sleep(0.05)\n if showm.is_done():\n break\n showm.exit()\n print('')\n\n\n# Create a function to rotate the camera\n\n\ndef rotate_camera():\n for i in range(100):\n if showm.lock_current():\n scene.azimuth(0.01 * i)\n showm.release_current()\n time.sleep(0.05)\n else:\n break\n\n\n# Create a function to add or remove the axes and increase its scale\n\n\ndef add_remove_axes():\n current_axes = None\n for i in range(100):\n if showm.lock_current():\n if current_axes is None:\n current_axes = actor.axes(scale=(0.20 * i, 0.20 * i, 0.20 * i))\n scene.add(current_axes)\n pass\n else:\n scene.rm(current_axes)\n current_axes = None\n pass\n showm.release_current()\n time.sleep(0.1)\n else:\n break\n\n\n# Start the threads\n# Multiple threads can be started here\n# First, one to rotate the camera\nthread_a = Thread(target=rotate_camera)\nthread_a.start()\n\n# Now let's start a thread that will print a counter\nthread_b = Thread(target=print_counter)\nthread_b.start()\n\n# Now let's start a thread that will add or remove axes\nthread_c = Thread(target=add_remove_axes)\nthread_c.start()\n\n# Let's start the show manager loop with multithreading option\nshowm.start(multithreaded=True)\n\n# Wait for the threads to finish\nthread_a.join()\nthread_b.join()\nthread_c.join()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.8" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/v0.10.x/_downloads/1eea113c6585adb2d083bb97f64612ed/viz_bezier_interpolator.ipynb b/v0.10.x/_downloads/1eea113c6585adb2d083bb97f64612ed/viz_bezier_interpolator.ipynb new file mode 100644 index 000000000..1f3d8fcf1 --- /dev/null +++ b/v0.10.x/_downloads/1eea113c6585adb2d083bb97f64612ed/viz_bezier_interpolator.ipynb @@ -0,0 +1,403 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Bezier Interpolator\n\nKeyframe animation using cubic Bezier interpolator.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "import numpy as np\n\nfrom fury import actor, window\nfrom fury.animation import Animation, Timeline\nfrom fury.animation.interpolator import cubic_bezier_interpolator" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Position interpolation using cubic Bezier curve\n\nCubic bezier curve is a widely used method for interpolating motion paths.\nThis can be achieved using positions and control points between those\npositions.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "scene = window.Scene()\nshowm = window.ShowManager(\n scene, size=(900, 768), reset_camera=False, order_transparent=True\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Cubic Bezier curve parameters\nIn order to make a cubic bezier curve based animation, you need four values\nfor every keyframe:\n1- Timestamp: The time that the keyframe is assigned to.\n2- value: The value of the keyframe. This might be position, quaternion, or\n scale value.\n3- In control point: The control point used when the value is the destination\n value.\n4- Out control point: The control point used when the value is the departure\n value::\n\n keyframe 0 -----------------> keyframe 1\n(time-0) (value-0) (out-cp-0) -----------------> (time-1) (value-1) (in-cp-1)\n\n keyframe 1 -----------------> keyframe 2\n(time-1) (value-1) (out-cp-1) -----------------> (time-2) (value-2) (in-cp-2)\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "keyframe_1 = {'value': [-2, 0, 0], 'out_cp': [-15, 6, 0]}\nkeyframe_2 = {'value': [18, 0, 0], 'in_cp': [27, 18, 0]}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Visualizing points\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "pts_actor = actor.sphere(\n np.array([keyframe_1.get('value'), keyframe_2.get('value')]), (1, 0, 0), radii=0.3\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Visualizing the control points\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "cps_actor = actor.sphere(\n np.array([keyframe_2.get('in_cp'), keyframe_1.get('out_cp')]), (0, 0, 1), radii=0.6\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Visualizing the connection between the control points and the points\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "cline_actor = actor.line(\n np.array([list(keyframe_1.values()), list(keyframe_2.values())]),\n colors=np.array([0, 1, 0]),\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Initializing an ``Animation`` and adding sphere actor to it.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "animation = Animation()\nsphere = actor.sphere(np.array([[0, 0, 0]]), (1, 0, 1))\nanimation.add_actor(sphere)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Setting Cubic Bezier keyframes\n\nCubic Bezier keyframes consists of 4 data per keyframe\nTimestamp, position, in control point, and out control point.\n- In control point is the cubic bezier control point for the associated\n position when this position is the destination position.\n- Out control point is the cubic bezier control point for the associated\n position when this position is the origin position or departing position.\nNote: If a control point is not provided or set `None`, this control point\nwill be the same as the position itself.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "animation.set_position(\n 0.0, np.array(keyframe_1.get('value')), out_cp=np.array(keyframe_1.get('out_cp'))\n)\nanimation.set_position(\n 5.0, np.array(keyframe_2.get('value')), in_cp=np.array(keyframe_2.get('in_cp'))\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Changing position interpolation into cubic bezier interpolation\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "animation.set_position_interpolator(cubic_bezier_interpolator)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Adding the visualization actors to the scene.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "scene.add(pts_actor, cps_actor, cline_actor)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Adding the animation to the ``ShowManager``\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "showm.add_animation(animation)\n\ninteractive = False\n\nif interactive:\n showm.start()\n\nwindow.record(scene, out_path='viz_keyframe_animation_bezier_1.png', size=(900, 768))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## A more complex scene scene\n\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "scene = window.Scene()\nshow_manager = window.ShowManager(\n scene, size=(900, 768), reset_camera=False, order_transparent=True\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Note: If a control point is set to `None`, it gets the value of the\npoint it controls.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "keyframes = {\n # time - position - in control point - out control point\n 0.0: {'value': [-2, 0, 0], 'out_cp': [-15, 6, 0]},\n 5.0: {'value': [18, 0, 0], 'in_cp': [27, 18, 0], 'out_cp': [27, -18, 0]},\n 9.0: {'value': [-5, -10, -10]},\n}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Create the sphere actor.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "sphere = actor.sphere(np.array([[0, 0, 0]]), (1, 0, 1))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Create an ``Animation`` and adding the sphere actor to it.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "animation = Animation(sphere)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Setting Cubic Bezier keyframes\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "animation.set_position_keyframes(keyframes)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "changing position interpolation into cubic bezier interpolation\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "animation.set_position_interpolator(cubic_bezier_interpolator)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "visualizing the points and control points (only for demonstration)\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "for t, keyframe in keyframes.items():\n pos = keyframe.get('value')\n in_control_point = keyframe.get('in_cp')\n out_control_point = keyframe.get('out_cp')\n\n ###########################################################################\n # visualizing position keyframe\n vis_point = actor.sphere(np.array([pos]), (1, 0, 0), radii=0.3)\n scene.add(vis_point)\n\n ###########################################################################\n # Visualizing the control points and their length (if exist)\n for cp in [in_control_point, out_control_point]:\n if cp is not None:\n vis_cps = actor.sphere(np.array([cp]), (0, 0, 1), radii=0.6)\n cline_actor = actor.line(np.array([[pos, cp]]), colors=np.array([0, 1, 0]))\n scene.add(vis_cps, cline_actor)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Initializing the timeline to be able to control the playback of the\nanimation.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "timeline = Timeline(animation, playback_panel=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We only need to add the ``Timeline`` to the ``ShowManager``\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "show_manager.add_animation(timeline)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Start the animation\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "if interactive:\n show_manager.start()\n\nwindow.record(scene, out_path='viz_keyframe_animation_bezier_2.png', size=(900, 768))" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.8" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/v0.10.x/_downloads/20d6b1b9d9435694678289791050d29e/viz_color_interpolators.ipynb b/v0.10.x/_downloads/20d6b1b9d9435694678289791050d29e/viz_color_interpolators.ipynb new file mode 100644 index 000000000..43a6709b3 --- /dev/null +++ b/v0.10.x/_downloads/20d6b1b9d9435694678289791050d29e/viz_color_interpolators.ipynb @@ -0,0 +1,212 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Keyframe Color Interpolators\n\nColor animation explained in this tutorial and how to use different color\nspace interpolators.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "import numpy as np\n\nfrom fury import actor, window\nfrom fury.animation import Animation\nfrom fury.animation.interpolator import (\n hsv_color_interpolator,\n lab_color_interpolator,\n step_interpolator,\n xyz_color_interpolator,\n)\nfrom fury.animation.timeline import Timeline\nfrom fury.colormap import distinguishable_colormap\n\nscene = window.Scene()\n\nshowm = window.ShowManager(\n scene, size=(900, 768), reset_camera=False, order_transparent=True\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Initializing positions of the cubes that will be color-animated.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "cubes_pos = np.array(\n [\n [[-2, 0, 0]],\n [[0, 0, 0]],\n [[2, 0, 0]],\n [[4, 0, 0]],\n [[6, 0, 0]],\n ]\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Static labels for different interpolators (for show)\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "linear_text = actor.vector_text('Linear', (-2.64, -1, 0))\nlab_text = actor.vector_text('LAB', (-0.37, -1, 0))\nhsv_text = actor.vector_text('HSV', (1.68, -1, 0))\nxyz_text = actor.vector_text('XYZ', (3.6, -1, 0))\nstep_text = actor.vector_text('Step', (5.7, -1, 0))\nscene.add(step_text, lab_text, linear_text, hsv_text, xyz_text)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Creating an animation to animate the actor.\nAlso cube actor is provided for each timeline to handle as follows:\n``Animation(actor)``, ``Animation(list_of_actors)``, or actors can be added\nlater using ``animation.add()`` or ``animation.add_actor()``\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "anim_linear_color = Animation(actor.cube(cubes_pos[0]))\nanim_LAB_color = Animation(actor.cube(cubes_pos[1]))\nanim_HSV_color = Animation(actor.cube(cubes_pos[2]))\nanim_XYZ_color = Animation(actor.cube(cubes_pos[3]))\nanim_step_color = Animation(actor.cube(cubes_pos[4]))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Creating a timeline to control all the animations (one for each color\ninterpolation method)\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "timeline = Timeline(playback_panel=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Adding animations to a Timeline.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "timeline.add_animation(\n [anim_linear_color, anim_LAB_color, anim_HSV_color, anim_XYZ_color, anim_step_color]\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Setting color keyframes\n\nSetting the same color keyframes to all the animations\n\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "First, we generate some distinguishable colors\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "colors = distinguishable_colormap(nb_colors=4)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Then, we set them as keyframes for the animations\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "for t in range(0, 20, 5):\n col = colors.pop()\n anim_linear_color.set_color(t, col)\n anim_LAB_color.set_color(t, col)\n anim_HSV_color.set_color(t, col)\n anim_XYZ_color.set_color(t, col)\n anim_step_color.set_color(t, col)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Changing the default scale interpolator to be a step interpolator\nThe default is linear interpolator for color keyframes\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "anim_HSV_color.set_color_interpolator(hsv_color_interpolator)\nanim_LAB_color.set_color_interpolator(lab_color_interpolator)\nanim_step_color.set_color_interpolator(step_interpolator)\nanim_XYZ_color.set_color_interpolator(xyz_color_interpolator)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Adding the main timeline to the show manager\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "showm.add_animation(timeline)\n\ninteractive = False\n\nif interactive:\n showm.start()\n\nwindow.record(scene, out_path='viz_keyframe_animation_colors.png', size=(900, 768))" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.8" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/v0.10.x/_downloads/2340ac441d0bbb69818b33bbf7e60075/viz_selection.ipynb b/v0.10.x/_downloads/2340ac441d0bbb69818b33bbf7e60075/viz_selection.ipynb new file mode 100644 index 000000000..3d0276cd4 --- /dev/null +++ b/v0.10.x/_downloads/2340ac441d0bbb69818b33bbf7e60075/viz_selection.ipynb @@ -0,0 +1,295 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Selecting multiple objects\n\nHere we show how to select objects in the\n3D world. In this example all objects to be picked are part of\na single actor.\n\nFURY likes to bundle objects in a few actors to reduce code and\nincrease speed. Nonetheless the method works for multiple actors too.\n\nThe difference with the picking tutorial is that here we will\nbe able to select more than one object. In addition we can\nselect interactively many vertices or faces.\n\nIn summary, we will create an actor with thousands of cubes and\nthen interactively we will be moving a rectangular box by\nhovering the mouse and making transparent everything that is\nbehind that box.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "import numpy as np\n\nfrom fury import actor, pick, utils, window" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Adding many cubes of different sizes and colors\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "num_cubes = 50000\n\ncenters = 10000 * (np.random.rand(num_cubes, 3) - 0.5)\ncolors = np.random.rand(num_cubes, 4)\ncolors[:, 3] = 1.0\nradii = 100 * np.random.rand(num_cubes) + 0.1" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Keep track of total number of triangle faces\nNote that every quad of each cube has 2 triangles\nand each cube has 6 quads in total.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "num_faces = num_cubes * 6 * 2" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Build scene and add an actor with many objects.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "scene = window.Scene()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Build the actor containing all the cubes\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "cube_actor = actor.cube(centers, directions=(1, 0, 0), colors=colors, scales=radii)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Access the memory of the vertices of all the cubes\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "vertices = utils.vertices_from_actor(cube_actor)\nnum_vertices = vertices.shape[0]\nnum_objects = centers.shape[0]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Access the memory of the colors of all the cubes\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "vcolors = utils.colors_from_actor(cube_actor, 'colors')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Create a rectangular 2d box as a texture\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "rgba = 255 * np.ones((100, 200, 4))\nrgba[1:-1, 1:-1] = np.zeros((98, 198, 4)) + 100\ntexa = actor.texture_2d(rgba.astype(np.uint8))\n\nscene.add(cube_actor)\nscene.add(texa)\nscene.reset_camera()\nscene.zoom(3.0)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Create the Selection Manager\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "selm = pick.SelectionManager(select='faces')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Tell Selection Manager to avoid selecting specific actors\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "selm.selectable_off(texa)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's make the callback which will be called\nwhen we hover the mouse\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def hover_callback(_obj, _event):\n event_pos = selm.event_position(showm.iren)\n # updates rectangular box around mouse\n texa.SetPosition(event_pos[0] - 200 // 2, event_pos[1] - 100 // 2)\n\n # defines selection region and returns information from selected objects\n info = selm.select(event_pos, showm.scene, (200 // 2, 100 // 2))\n for node in info.keys():\n if info[node]['face'] is not None:\n if info[node]['actor'] is cube_actor:\n for face_index in info[node]['face']:\n # generates an object_index to help with coloring\n # by dividing by the number of faces of each cube (6 * 2)\n object_index = face_index // 12\n sec = int(num_vertices / num_objects)\n color_change = np.array([150, 0, 0, 255], dtype='uint8')\n vcolors[\n object_index * sec : object_index * sec + sec\n ] = color_change\n utils.update_actor(cube_actor)\n showm.render()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Make the window appear\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "showm = window.ShowManager(\n scene, size=(1024, 768), order_transparent=True, reset_camera=False\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Bind the callback to the actor\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "showm.add_iren_callback(hover_callback)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Change interactive to True to start interacting with the scene\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "interactive = False\n\nif interactive:\n\n showm.start()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Save the current framebuffer in a PNG file\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "window.record(showm.scene, size=(1024, 768), out_path='viz_selection.png')" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.8" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/v0.10.x/_downloads/243115b8109a8fe07f4e77ba5e473042/viz_gltf.py b/v0.10.x/_downloads/243115b8109a8fe07f4e77ba5e473042/viz_gltf.py new file mode 100644 index 000000000..fd64cacad --- /dev/null +++ b/v0.10.x/_downloads/243115b8109a8fe07f4e77ba5e473042/viz_gltf.py @@ -0,0 +1,49 @@ +""" +======================= +Visualizing a glTF file +======================= +In this tutorial, we will show how to display a glTF file in a scene. +""" + +from fury import window +from fury.data import fetch_gltf, read_viz_gltf +from fury.gltf import glTF + +############################################################################## +# Create a scene. + +scene = window.Scene() +scene.SetBackground(0.1, 0.1, 0.4) + +############################################################################## +# Retrieving the gltf model. +fetch_gltf('Duck', 'glTF') +filename = read_viz_gltf('Duck') + +############################################################################## +# Initialize the glTF object and get actors using `actors` method. +# Note: You can always manually create actor from polydata, and apply texture +# or materials manually afterwards. +# Experimental: For smooth mesh/actor you can set `apply_normals=True`. + +gltf_obj = glTF(filename, apply_normals=False) +actors = gltf_obj.actors() + +############################################################################## +# Add all the actor from list of actors to the scene. + +scene.add(*actors) + +############################################################################## +# Applying camera + +cameras = gltf_obj.cameras +if cameras: + scene.SetActiveCamera(cameras[0]) + +interactive = False + +if interactive: + window.show(scene, size=(1280, 720)) + +window.record(scene, out_path='viz_gltf.png', size=(1280, 720)) diff --git a/v0.10.x/_downloads/245bd5cc0efc250ae0c363790023423e/viz_helical_motion.ipynb b/v0.10.x/_downloads/245bd5cc0efc250ae0c363790023423e/viz_helical_motion.ipynb new file mode 100644 index 000000000..0bef23034 --- /dev/null +++ b/v0.10.x/_downloads/245bd5cc0efc250ae0c363790023423e/viz_helical_motion.ipynb @@ -0,0 +1,241 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Motion of a charged particle in a combined magnetic and electric field\n\nA charged particle follows a curved path in a magnetic field.\nIn an electric field, the particle tends to accelerate in a direction\nparallel/antiparallel to the electric field depending on the nature of\ncharge on the particle. In a combined electric and magnetic field,\nthe particle moves along a helical path.\n\nIn this animation, there's a magnetic and an electric field present in +x\ndirection under whose influence the positively charged particle follows a\nhelical path.\n\nImporting necessary modules\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "import itertools\n\nimport numpy as np\n\nfrom fury import actor, ui, utils, window" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's define some variable and their description:\n\n* `radius_particle`: radius of the point that will represent the particle\n (default = 0.08)\n* `initial_velocity`: initial velocity of the particle along +x\n (default = 0.09)\n* `acc`: acceleration of the particle along +x (due to the electric field)\n (default = 0.004)\n* `time`: time (default time i.e. time at beginning of the animation = 0)\n* `incre_time`: value by which time is incremented for each call of\n timer_callback (default = 0.09)\n* `angular_frq`: angular frequency (default = 0.1)\n* `phase_angle`: phase angle (default = 0.002)\n\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "radius_particle = 0.08\ninitial_velocity = 0.09\nacc = 0.004\ntime = 0\nincre_time = 0.09\nangular_frq = 0.1\nphase_angle = 0.002" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Creating a scene object and configuring the camera's position\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "scene = window.Scene()\nscene.zoom(1.2)\nscene.set_camera(\n position=(10, 12.5, 19), focal_point=(3.0, 0.0, 0.0), view_up=(0.0, 0.0, 0.0)\n)\nshowm = window.ShowManager(\n scene, size=(800, 600), reset_camera=True, order_transparent=True\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Creating a blue colored arrow which shows the direction of magnetic field and\nelectric field.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "color_arrow = window.colors.blue # color of the arrow can be manipulated\ncenters = np.array([[0, 0, 0]])\ndirections = np.array([[1, 0, 0]])\nheights = np.array([8])\narrow_actor = actor.arrow(\n centers,\n directions,\n color_arrow,\n heights,\n resolution=20,\n tip_length=0.06,\n tip_radius=0.012,\n shaft_radius=0.005,\n)\nscene.add(arrow_actor)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Initializing the initial coordinates of the particle\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "x = initial_velocity * time + 0.5 * acc * (time**2)\ny = np.sin(angular_frq * time + phase_angle)\nz = np.cos(angular_frq * time + phase_angle)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Initializing point actor which will represent the charged particle\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "color_particle = window.colors.red # color of particle can be manipulated\npts = np.array([[x, y, z]])\ncharge_actor = actor.point(pts, color_particle, point_radius=radius_particle)\nscene.add(charge_actor)\n\nvertices = utils.vertices_from_actor(charge_actor)\nvcolors = utils.colors_from_actor(charge_actor, 'colors')\nno_vertices_per_point = len(vertices)\ninitial_vertices = vertices.copy() - np.repeat(pts, no_vertices_per_point, axis=0)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Initializing text box to display the name of the animation\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "tb = ui.TextBlock2D(bold=True, position=(100, 90))\nm1 = 'Motion of a charged particle in a '\nm2 = 'combined electric and magnetic field'\ntb.message = m1 + m2\nscene.add(tb)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Initializing counter\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "counter = itertools.count()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "end is used to decide when to end the animation\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "end = 200" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This will be useful for plotting path of the particle\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "coor_1 = np.array([0, 0, 0])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Coordinates to be plotted are changed every time timer_callback is called by\nusing the update_coordinates function. The wave is rendered here.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def timer_callback(_obj, _event):\n global pts, time, incre_time, coor_1\n time += incre_time\n cnt = next(counter)\n\n x = initial_velocity * time + 0.5 * acc * (time**2)\n y = np.sin(10 * angular_frq * time + phase_angle)\n z = np.cos(10 * angular_frq * time + phase_angle)\n pts = np.array([[x, y, z]])\n\n vertices[:] = initial_vertices + np.repeat(pts, no_vertices_per_point, axis=0)\n\n utils.update_actor(charge_actor)\n\n # Plotting the path followed by the particle\n coor_2 = np.array([x, y, z])\n coors = np.array([coor_1, coor_2])\n coors = [coors]\n line_actor = actor.line(coors, window.colors.cyan, linewidth=3)\n scene.add(line_actor)\n coor_1 = coor_2\n\n showm.render()\n\n # to end the animation\n if cnt == end:\n showm.exit()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Run every 15 milliseconds\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "showm.add_timer_callback(True, 15, timer_callback)\nshowm.start()\nwindow.record(showm.scene, size=(800, 600), out_path='viz_helical_motion.png')" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.8" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/v0.10.x/_downloads/24863fd43b88b22f56e64d3300236114/viz_combobox.py b/v0.10.x/_downloads/24863fd43b88b22f56e64d3300236114/viz_combobox.py new file mode 100644 index 000000000..c6a6f5687 --- /dev/null +++ b/v0.10.x/_downloads/24863fd43b88b22f56e64d3300236114/viz_combobox.py @@ -0,0 +1,89 @@ +""" +======== +ComboBox +======== + +This example shows how to use the Combobox UI. We will demonstrate how to +create ComboBoxes for selecting colors for a label. + +First, some imports. +""" +from fury import ui, window +from fury.data import fetch_viz_icons + +############################################################################## +# First we need to fetch some icons that are included in FURY. + +fetch_viz_icons() + +######################################################################### +# First, we create a label. + +label = ui.TextBlock2D( + position=(200, 300), + font_size=40, + color=(1, 0.5, 0), + justification='center', + vertical_justification='top', + text='FURY rocks!!!', +) + +######################################################################## +# Now we create a dictionary to store colors as its key and their +# RGB values as its value. + +colors = { + 'Violet': (0.6, 0, 0.8), + 'Indigo': (0.3, 0, 0.5), + 'Blue': (0, 0, 1), + 'Green': (0, 1, 0), + 'Yellow': (1, 1, 0), + 'Orange': (1, 0.5, 0), + 'Red': (1, 0, 0), +} + +######################################################################## +# ComboBox +# =================== +# +# Now we create a ComboBox UI component for selecting colors. + +color_combobox = ui.ComboBox2D( + items=list(colors.keys()), + placeholder='Choose Text Color', + position=(75, 50), + size=(250, 150), +) + +######################################################################## +# Callbacks +# ================================== +# +# Now we create a callback for setting the chosen color. + + +def change_color(combobox): + label.color = colors[combobox.selected_text] + + +# `on_change` callback is set to `change_color` method so that +# it's called whenever a different option is selected. +color_combobox.on_change = change_color + +############################################################################### +# Show Manager +# ================================== +# +# Now we add label and combobox to the scene. + +current_size = (400, 400) +showm = window.ShowManager(size=current_size, title='ComboBox UI Example') +showm.scene.add(label, color_combobox) + +# To interact with the UI, set interactive = True +interactive = False + +if interactive: + showm.start() + +window.record(showm.scene, out_path='combobox_ui.png', size=(400, 400)) diff --git a/v0.10.x/_downloads/2487956207605b03f0b4f341a38e0722/viz_fine_tuning_gl_context.ipynb b/v0.10.x/_downloads/2487956207605b03f0b4f341a38e0722/viz_fine_tuning_gl_context.ipynb new file mode 100644 index 000000000..75f400226 --- /dev/null +++ b/v0.10.x/_downloads/2487956207605b03f0b4f341a38e0722/viz_fine_tuning_gl_context.ipynb @@ -0,0 +1,122 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Fine-tuning the OpenGL state using shader callbacks\n\nSometimes we need to get more control about how\nOpenGL will render the actors. This example shows how to change the OpenGL\nstate of one or more actors. This can be useful when we need to create\nspecialized visualization effects.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "First, let's import some functions\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "import itertools\n\nimport numpy as np\n\nfrom fury import actor, window\nfrom fury.shaders import shader_apply_effects\nfrom fury.utils import remove_observer_from_actor" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We just proceed as usual: creating the actors and initializing a scene in\nFURY\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "centers = np.array([[0, 0, 0], [-0.1, 0, 0], [0.1, 0, 0]])\ncolors = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]])\n\nactor_no_depth_test = actor.markers(\n centers,\n marker='s',\n colors=colors,\n marker_opacity=0.5,\n scales=0.2,\n)\nactor_normal_blending = actor.markers(\n centers - np.array([[0, -0.5, 0]]),\n marker='s',\n colors=colors,\n marker_opacity=0.5,\n scales=0.2,\n)\nactor_add_blending = actor.markers(\n centers - np.array([[0, -1, 0]]),\n marker='s',\n colors=colors,\n marker_opacity=0.5,\n scales=0.2,\n)\n\nactor_sub_blending = actor.markers(\n centers - np.array([[0, -1.5, 0]]),\n marker='s',\n colors=colors,\n marker_opacity=0.5,\n scales=0.2,\n)\nactor_mul_blending = actor.markers(\n centers - np.array([[0, -2, 0]]),\n marker='s',\n colors=colors,\n marker_opacity=0.5,\n scales=0.2,\n)\n\n\nscene = window.Scene()\n\n\nscene.background((0.5, 0.5, 0.5))\nshowm = window.ShowManager(\n scene, size=(900, 768), reset_camera=False, order_transparent=False\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "All actors must be added in the scene\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "scene.add(actor_no_depth_test)\nscene.add(actor_normal_blending)\nscene.add(actor_add_blending)\nscene.add(actor_sub_blending)\nscene.add(actor_mul_blending)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now, we will enter in the topic of this example. First, we need to create\n(or use one of the pre-built gl_function of FURY) to\nchange the OpenGL state of a given fury window instance (showm.window).\n\nHere we're using the pre-build FURY window functions which has already a\nset of specific behaviors to be applied in the OpenGL context\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "shader_apply_effects(\n showm.window, actor_normal_blending, effects=window.gl_set_normal_blending\n)\n\n# ###############################################################################\n# It's also possible use a list of effects. The final opengl state it'll\n# be the composition of each effect that each function has in the opengl state\n\nid_observer = shader_apply_effects(\n showm.window,\n actor_no_depth_test,\n effects=[window.gl_reset_blend, window.gl_disable_blend, window.gl_disable_depth],\n)\n\nshader_apply_effects(\n showm.window,\n actor_add_blending,\n effects=[\n window.gl_reset_blend,\n window.gl_enable_depth,\n window.gl_set_additive_blending,\n ],\n)\n\nshader_apply_effects(\n showm.window, actor_sub_blending, effects=window.gl_set_subtractive_blending\n)\n\nshader_apply_effects(\n showm.window, actor_mul_blending, effects=window.gl_set_multiplicative_blending\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Finally, just render and see the results\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "counter = itertools.count()\n\n# After some steps we will remove the no_depth_test effect\n\n\ndef timer_callback(obj, event):\n cnt = next(counter)\n showm.render()\n # we will rotate the visualization just to help you to see\n # the results of each specific opengl-state\n showm.scene.azimuth(1)\n if cnt == 400:\n remove_observer_from_actor(actor_no_depth_test, id_observer)\n shader_apply_effects(\n showm.window, actor_no_depth_test, effects=window.gl_set_additive_blending\n )\n if cnt == 1000:\n showm.exit()\n\n\ninteractive = False\nshowm.add_timer_callback(interactive, 5, timer_callback)\nif interactive:\n showm.start()\n\nwindow.record(scene, out_path='viz_fine_tuning_gl_context.png', size=(600, 600))" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.8" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/v0.10.x/_downloads/29cddb7ad3c81ce7a762e6a514af5ebc/viz_skinning.py b/v0.10.x/_downloads/29cddb7ad3c81ce7a762e6a514af5ebc/viz_skinning.py new file mode 100644 index 000000000..5a83ab54f --- /dev/null +++ b/v0.10.x/_downloads/29cddb7ad3c81ce7a762e6a514af5ebc/viz_skinning.py @@ -0,0 +1,76 @@ +""" +================================= +Skeletal Animation in a glTF file +================================= +In this tutorial, we will show how to use skeletal animations (skinning) in a +glTF model in FURY. +""" + +from fury import window +from fury.data import fetch_gltf, read_viz_gltf +from fury.gltf import glTF + +############################################################################## +# Retrieving the model with skeletal animations. +# We're choosing the `RiggedFigure` model here. + +fetch_gltf('RiggedFigure', 'glTF') +filename = read_viz_gltf('RiggedFigure') + +############################################################################## +# Initializing the glTF object, You can additionally set `apply_normals=True`. +# Note: Normals might not work well as intended with skinning animations. + +gltf_obj = glTF(filename, apply_normals=False) + +############################################################################## +# Get the skinning timeline using `skin_timeline` method, Choose the animation +# name you want to visualize. +# Note: If there's no name for animation, It's stored as `anim_0`, `anim_1` etc + +animation = gltf_obj.skin_animation()['anim_0'] + +# After we get the timeline object, We want to initialise the skinning process. +# You can set `bones=true` to visualize each bone transformation. Additionally, +# you can set `length` of bones in the `initialise_skin` method. +# Note: Make sure to call this method before you initialize ShowManager, else +# bones won't be added to the scene. + +gltf_obj.initialize_skin(animation, bones=False) + +############################################################################## +# Create a scene, and show manager. +# Initialize the show manager and add timeline to the scene (No need to add +# actors to the scene separately). + +scene = window.Scene() +showm = window.ShowManager( + scene, size=(900, 768), reset_camera=True, order_transparent=True +) +showm.initialize() +scene.add(animation) + +############################################################################## +# define a timer_callback. +# Use the `update_skin` method, It updates the timeline and applies skinning to +# actors (and bones). + + +def timer_callback(_obj, _event): + gltf_obj.update_skin(animation) + showm.render() + + +############################################################################## +# Optional: `timeline.play()` auto plays the animations. + + +showm.add_timer_callback(True, 20, timer_callback) +scene.reset_camera() + +interactive = False + +if interactive: + showm.start() + +window.record(scene, out_path='viz_skinning.png', size=(900, 768)) diff --git a/v0.10.x/_downloads/2a3ba48d37afb1f863bee6f45c238d1c/viz_earth_coordinates.py b/v0.10.x/_downloads/2a3ba48d37afb1f863bee6f45c238d1c/viz_earth_coordinates.py new file mode 100644 index 000000000..48232a3c0 --- /dev/null +++ b/v0.10.x/_downloads/2a3ba48d37afb1f863bee6f45c238d1c/viz_earth_coordinates.py @@ -0,0 +1,160 @@ +""" +============================ +Earth Coordinate Conversion +============================ + +In this tutorial, we will show how to place actors on specific locations +on the surface of the Earth using a new function. +""" + +import itertools +import math + +import numpy as np + +from fury import actor, io, utils, window +from fury.data import fetch_viz_textures, read_viz_textures + +############################################################################### +# Create a new scene, and load in the image of the Earth using +# ``fetch_viz_textures`` and ``read_viz_textures``. We will use a 16k +# resolution texture for maximum detail. + +scene = window.Scene() + +fetch_viz_textures() +earth_file = read_viz_textures('1_earth_16k.jpg') +earth_image = io.load_image(earth_file) +earth_actor = actor.texture_on_sphere(earth_image) +scene.add(earth_actor) + +############################################################################### +# Rotate the Earth to make sure the texture is correctly oriented. Change it's +# scale using ``actor.SetScale()``. + +utils.rotate(earth_actor, (-90, 1, 0, 0)) +utils.rotate(earth_actor, (180, 0, 1, 0)) +earth_actor.SetScale(2, 2, 2) + +############################################################################### +# Define the function to convert geographical coordinates of a location in +# latitude and longitude degrees to coordinates on the ``earth_actor`` surface. +# In this function, convert to radians, then to spherical coordinates, and +# lastly, to cartesian coordinates. + + +def latlong_coordinates(lat, lon): + # Convert latitude and longitude to spherical coordinates + degrees_to_radians = math.pi / 180.0 + # phi = 90 - latitude + phi = (90 - lat) * degrees_to_radians + # theta = longitude + theta = lon * degrees_to_radians * -1 + # now convert to cartesian + x = np.sin(phi) * np.cos(theta) + y = np.sin(phi) * np.sin(theta) + z = np.cos(phi) + # flipping z to y for FURY coordinates + return (x, z, y) + + +############################################################################### +# Use this new function to place some sphere actors on several big cities +# around the Earth. + +locationone = latlong_coordinates(40.730610, -73.935242) # new york city, us +locationtwo = latlong_coordinates(39.916668, 116.383331) # beijing, china +locationthree = latlong_coordinates(48.864716, 2.349014) # paris, france + +############################################################################### +# Set the centers, radii, and colors of these spheres, and create a new +# ``sphere_actor`` for each location to add to the scene. + +centers = np.array([[*locationone], [*locationtwo], [*locationthree]]) +colors = np.random.rand(3, 3) +radii = np.array([0.005, 0.005, 0.005]) +sphere_actor = actor.sphere(centers, colors, radii) +scene.add(sphere_actor) + +############################################################################### +# Create some text actors to add to the scene indicating each location and its +# geographical coordinates. + +nyc_actor = actor.text_3d( + 'New York City, New York\n40.7128° N, 74.0060° W', + (locationone[0] - 0.04, locationone[1], locationone[2] + 0.07), + window.colors.white, + 0.01, +) +paris_actor = actor.text_3d( + 'Paris, France\n48.8566° N, 2.3522° E', + (locationthree[0] - 0.04, locationthree[1], locationthree[2] - 0.07), + window.colors.white, + 0.01, +) +beijing_actor = actor.text_3d( + 'Beijing, China\n39.9042° N, 116.4074° E', + (locationtwo[0] - 0.06, locationtwo[1], locationtwo[2] - 0.07), + window.colors.white, + 0.01, +) +utils.rotate(paris_actor, (85, 0, 1, 0)) +utils.rotate(beijing_actor, (180, 0, 1, 0)) +utils.rotate(nyc_actor, (5, 1, 0, 0)) + +############################################################################## +# Create a ShowManager object, which acts as the interface between the scene, +# the window and the interactor. + +showm = window.ShowManager( + scene, size=(900, 768), reset_camera=False, order_transparent=True +) + +############################################################################### +# Let's create a ``timer_callback`` function to add some animation to the +# Earth. Change the camera position and angle to fly over and zoom in on each +# new location. + +counter = itertools.count() + + +def timer_callback(_obj, _event): + cnt = next(counter) + showm.render() + if cnt == 0: + scene.set_camera(position=(1.5, 3.5, 7.0)) + if cnt < 200 and cnt > 25: + scene.zoom(1.015) + scene.pitch(0.01) + if cnt == 200: + scene.add(nyc_actor) + if cnt > 250 and cnt < 350: + scene.zoom(0.985) + if cnt > 350 and cnt < 425: + scene.azimuth(1) + if cnt > 425 and cnt < 525: + scene.zoom(1.015) + scene.pitch(0.011) + if cnt == 525: + scene.add(paris_actor) + if cnt > 575 and cnt < 700: + scene.zoom(0.985) + if cnt > 700 and cnt < 820: + scene.azimuth(1) + if cnt > 820 and cnt < 930: + scene.zoom(1.015) + if cnt == 930: + scene.add(beijing_actor) + if cnt == 1000: + showm.exit() + + +############################################################################### +# Initialize the ShowManager object, add the timer_callback, and watch the +# new animation take place! + + +showm.add_timer_callback(True, 25, timer_callback) +showm.start() + +window.record(showm.scene, size=(900, 768), out_path='viz_earth_coordinates.png') diff --git a/v0.10.x/_downloads/2a610242af9c8f9082b55166f2e1dfcb/viz_play_video.py b/v0.10.x/_downloads/2a610242af9c8f9082b55166f2e1dfcb/viz_play_video.py new file mode 100644 index 000000000..7437d0582 --- /dev/null +++ b/v0.10.x/_downloads/2a610242af9c8f9082b55166f2e1dfcb/viz_play_video.py @@ -0,0 +1,93 @@ +""" +======================================================= +Play a video in the 3D world +======================================================= + +The goal of this demo is to show how to visualize a video +on a rectangle by updating a texture. +""" + +import time + +import cv2 +import numpy as np + +from fury import actor, window + + +# The VideoCapturer Class +# This Class wraps OpenCV Videocapture +class VideoCapturer: + def __init__(self, video, time): + self.path = video + self.video = cv2.VideoCapture(self.path) + self.fps = int(self.video.get(cv2.CAP_PROP_FPS)) + self.frames = int(self.video.get(cv2.CAP_PROP_FRAME_COUNT)) + self.time = time + + # A generator to yield video frames on every call + def get_frame(self): + start = time.time() + for _ in range(self.frames): + isframe, frame = self.video.read() + dur = time.time() - start + if dur > self.time: + break + if isframe: + yield cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) + self.video.release() + yield None + + +class VideoPlayer: + def __init__(self, video, time=10): + # Initializes the Video object with the given Video + self.video = VideoCapturer(video, time) + self.video_generator = self.video.get_frame() + self.current_video_frame = next(self.video_generator) + # Initialize Scene + self.initialize_scene() + # Create a Show Manager and Initialize it + self.show_manager = window.ShowManager( + self.scene, size=(900, 768), reset_camera=False, order_transparent=True + ) + + # Initialize the Scene with actors + def initialize_scene(self): + self.scene = window.Scene() + # Initialize a Plane actor with the 1st video frame along with + # the actor grid which is to be updated in each iteration + self.plane_actor = actor.texture(self.current_video_frame) + self.scene.add(self.plane_actor) + + # The timer_callback function getting called by the show manager + def timer_callback(self, _obj, _event): + self.current_video_frame = next(self.video_generator) + if isinstance(self.current_video_frame, np.ndarray): + # update texture of the actor with the current frame image + # by updating the actor grid + actor.texture_update(self.plane_actor, self.current_video_frame) + self.show_manager.scene.azimuth(1.5) # to rotate the camera + else: + self.show_manager.exit() + + self.show_manager.render() + + def run(self): + # Add a timer callback to show manager after with + # video frame duration as the interval + self.frame_duration = int(1000 / self.video.fps) + self.show_manager.add_timer_callback( + True, self.frame_duration, self.timer_callback + ) + self.show_manager.start() + + +# Create VideoPlayer Object and run it +video_url = ( + 'http://commondatastorage.googleapis.com/' + + 'gtv-videos-bucket/sample/BigBuckBunny.mp4' +) +vp = VideoPlayer(video_url) +vp.run() +window.record(vp.show_manager.scene, out_path='viz_play_video.png', size=(600, 600)) diff --git a/v0.10.x/_downloads/2ce5a3331efbae4a6fa22a8011311a6c/viz_ui_listbox.py b/v0.10.x/_downloads/2ce5a3331efbae4a6fa22a8011311a6c/viz_ui_listbox.py new file mode 100644 index 000000000..118a00e8a --- /dev/null +++ b/v0.10.x/_downloads/2ce5a3331efbae4a6fa22a8011311a6c/viz_ui_listbox.py @@ -0,0 +1,77 @@ +# -*- coding: utf-8 -*- +""" +========= +ListBox +========= + +This example shows how to use the UI API. We will create a list +some geometric shapes from FURY UI elements. + +First, a bunch of imports. +""" +from fury import ui, window +from fury.data import fetch_viz_icons + +############################################################################## +# First we need to fetch some icons that are included in FURY. + +fetch_viz_icons() + +############################################################################### +# Create some text blocks that will be shown when +# list elements will be selected + +welcome_text = ui.TextBlock2D(text='Welcome', font_size=30, position=(500, 400)) +bye_text = ui.TextBlock2D(text='Bye', font_size=30, position=(500, 400)) +fury_text = ui.TextBlock2D(text='Fury', font_size=30, position=(500, 400)) + +example = [welcome_text, bye_text, fury_text] + +############################################################################### +# Hide these text blocks for now + + +def hide_all_examples(): + for element in example: + element.set_visibility(False) + + +hide_all_examples() + +############################################################################### +# Create ListBox with the values as parameter. + +values = ['Welcome', 'Bye', 'Fury'] +listbox = ui.ListBox2D( + values=values, position=(10, 300), size=(200, 200), multiselection=False +) + +############################################################################### +# Function to show selected element. + + +def display_element(): + hide_all_examples() + element = example[values.index(listbox.selected[0])] + element.set_visibility(True) + + +listbox.on_change = display_element + +############################################################################### +# Now that all the elements have been initialised, we add them to the show +# manager. + +current_size = (800, 800) +show_manager = window.ShowManager(size=current_size, title='FURY UI ListBox_Example') + +show_manager.scene.add(listbox) +show_manager.scene.add(welcome_text) +show_manager.scene.add(bye_text) +show_manager.scene.add(fury_text) +interactive = False + +if interactive: + show_manager.start() + +window.record(show_manager.scene, size=current_size, out_path='viz_listbox.png') diff --git a/v0.10.x/_downloads/2ee6af1d676ac045ad09ea8ee0fe3271/viz_spline_interpolator.py b/v0.10.x/_downloads/2ee6af1d676ac045ad09ea8ee0fe3271/viz_spline_interpolator.py new file mode 100644 index 000000000..2023647b0 --- /dev/null +++ b/v0.10.x/_downloads/2ee6af1d676ac045ad09ea8ee0fe3271/viz_spline_interpolator.py @@ -0,0 +1,97 @@ +""" +============================= +Keyframes Spline Interpolator +============================= + +Tutorial on making keyframe-based animation in FURY using Spline interpolators. +""" + +import numpy as np + +from fury import actor, window +from fury.animation import Animation, Timeline +from fury.animation.interpolator import spline_interpolator + +scene = window.Scene() + +showm = window.ShowManager( + scene, size=(900, 768), reset_camera=False, order_transparent=True +) + + +############################################################################### +# Position keyframes as a dict object containing timestamps as keys and +# positions as values. +position_keyframes = { + 0.0: np.array([0, 0, 0]), + 2.0: np.array([10, 3, 5]), + 4.0: np.array([20, 14, 13]), + 6.0: np.array([-20, 20, 0]), + 8.0: np.array([17, -10, 15]), + 10.0: np.array([0, -6, 0]), +} + +############################################################################### +# creating FURY dots to visualize the position values. +pos_dots = actor.dot(np.array(list(position_keyframes.values()))) + +############################################################################### +# creating two timelines (one uses linear and the other uses' spline +# interpolator), each timeline controls a sphere actor + +sphere_linear = actor.sphere(np.array([[0, 0, 0]]), (1, 0.5, 0.2), 0.5) + +linear_anim = Animation() +linear_anim.add_actor(sphere_linear) + +linear_anim.set_position_keyframes(position_keyframes) + +############################################################################### +# Note: linear_interpolator is used by default. So, no need to set it for this +# first animation that we need to linearly interpolate positional animation. + +############################################################################### +# creating a second timeline that translates another larger sphere actor using +# spline interpolator. +sphere_spline = actor.sphere(np.array([[0, 0, 0]]), (0.3, 0.9, 0.6), 1) +spline_anim = Animation(sphere_spline) +spline_anim.set_position_keyframes(position_keyframes) + +############################################################################### +# Setting 5th degree spline interpolator for position keyframes. +spline_anim.set_position_interpolator(spline_interpolator, degree=5) + +############################################################################### +# Wrapping animations up! +# ============================================================================= +# +# Adding everything to a ``Timeline`` to control the two timelines. + +############################################################################### +# First we create a timeline with a playback panel: +timeline = Timeline(playback_panel=True) + +############################################################################### +# Add visualization dots actor to the scene. +scene.add(pos_dots) + +############################################################################### +# Adding the animations to the timeline (so that it controls their playback). +timeline.add_animation([linear_anim, spline_anim]) + +############################################################################### +# Adding the timeline to the show manager. +showm.add_animation(timeline) + + +############################################################################### +# Now that these two animations are added to timeline, if the timeline +# is played, paused, ..., all these changes will reflect on the animations. + + +interactive = False + +if interactive: + showm.start() + +window.record(scene, out_path='viz_keyframe_animation_spline.png', size=(900, 768)) diff --git a/v0.10.x/_downloads/2f01a9981d2aeddb0bc9cb04446c5657/viz_sdfactor.py b/v0.10.x/_downloads/2f01a9981d2aeddb0bc9cb04446c5657/viz_sdfactor.py new file mode 100644 index 000000000..748d02ea1 --- /dev/null +++ b/v0.10.x/_downloads/2f01a9981d2aeddb0bc9cb04446c5657/viz_sdfactor.py @@ -0,0 +1,63 @@ +""" +=================== +Visualize SDF Actor +=================== +Here is a simple tutorial that shows how to visualize SDF primitives using +FURY. + +SDFs or Signed-distance functions when passed the coordinates of a point in +space, return the shortest distance between that point and some surface. +This property of SDFs can be used to model 3D geometry at a faster rate +compared to traditional polygons based modeling. + +In this example we use the raymarching algorithm to render the SDF primitives +shapes using shaders +""" + +import numpy as np + +from fury import actor, window + +############################################################################### +# Lets define variables for the SDF Actor + +dirs = np.random.rand(4, 3) +colors = np.random.rand(4, 3) * 255 +centers = np.array([[1, 0, 0], [0, 0, 0], [-1, 0, 0], [0, 1, 0]]) +scales = np.random.rand(4, 1) + + +############################################################################### +# Create SDF Actor + +sdfactor = actor.sdf( + centers=centers, + directions=dirs, + colors=colors, + primitives=['sphere', 'torus', 'ellipsoid', 'capsule'], + scales=scales, +) + +############################################################################## +# Create a scene + +scene = window.Scene() +scene.background((1.0, 0.8, 0.8)) +scene.add(sdfactor) + + +############################################################################### +# Show Manager +# +# Since all the elements have been initialised ,we add them to the show +# manager. + +current_size = (1024, 720) +showm = window.ShowManager(scene, size=current_size, title='Visualize SDF Actor') + +interactive = False + +if interactive: + showm.start() + +window.record(scene, out_path='viz_sdfactor.png', size=current_size) diff --git a/v0.10.x/_downloads/3134cf19e2b114c2a6ed97b1bea2a925/viz_ui.ipynb b/v0.10.x/_downloads/3134cf19e2b114c2a6ed97b1bea2a925/viz_ui.ipynb new file mode 100644 index 000000000..61acc1cb6 --- /dev/null +++ b/v0.10.x/_downloads/3134cf19e2b114c2a6ed97b1bea2a925/viz_ui.ipynb @@ -0,0 +1,403 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# User Interfaces\n\nThis example shows how to use the UI API. We will demonstrate how to create\nseveral FURY UI elements, then use a list box to toggle which element is shown.\n\nFirst, a bunch of imports.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "import numpy as np\n\nfrom fury import actor, ui, window\nfrom fury.data import fetch_viz_icons, read_viz_icons" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Shapes\n\nLet's start by drawing some simple shapes. First, a rectangle.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "rect = ui.Rectangle2D(size=(200, 200), position=(400, 300), color=(1, 0, 1))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Then we can draw a solid circle, or disk.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "disk = ui.Disk2D(outer_radius=50, center=(500, 500), color=(1, 1, 0))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Add an inner radius to make a ring.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "ring = ui.Disk2D(outer_radius=50, inner_radius=45, center=(500, 300), color=(0, 1, 1))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Image\n\nNow let's display an image. First we need to fetch some icons that are\nincluded in FURY.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "fetch_viz_icons()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we can create an image container.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "img = ui.ImageContainer2D(\n img_path=read_viz_icons(fname='home3.png'), position=(450, 350)\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Panel with buttons and text\n\nLet's create some buttons and text and put them in a panel. First we'll\nmake the panel.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "panel = ui.Panel2D(size=(300, 150), color=(1, 1, 1), align='right')\npanel.center = (500, 400)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Then we'll make two text labels and place them on the panel.\nNote that we specify the position with integer numbers of pixels.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "text = ui.TextBlock2D(text='Click me')\ntext2 = ui.TextBlock2D(text='Me too')\npanel.add_element(text, (50, 100))\npanel.add_element(text2, (180, 100))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Then we'll create two buttons and add them to the panel.\n\nNote that here we specify the positions with floats. In this case, these are\npercentages of the panel size.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "button_example = ui.Button2D(\n icon_fnames=[('square', read_viz_icons(fname='stop2.png'))]\n)\n\nicon_files = []\nicon_files.append(('down', read_viz_icons(fname='circle-down.png')))\nicon_files.append(('left', read_viz_icons(fname='circle-left.png')))\nicon_files.append(('up', read_viz_icons(fname='circle-up.png')))\nicon_files.append(('right', read_viz_icons(fname='circle-right.png')))\n\nsecond_button_example = ui.Button2D(icon_fnames=icon_files)\n\npanel.add_element(button_example, (0.25, 0.33))\npanel.add_element(second_button_example, (0.66, 0.33))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can add a callback to each button to perform some action.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def change_text_callback(i_ren, _obj, _button):\n text.message = 'Clicked!'\n i_ren.force_render()\n\n\ndef change_icon_callback(i_ren, _obj, _button):\n _button.next_icon()\n i_ren.force_render()\n\n\nbutton_example.on_left_mouse_button_clicked = change_text_callback\nsecond_button_example.on_left_mouse_button_pressed = change_icon_callback" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Cube and sliders\n\nLet's add a cube to the scene and control it with sliders.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "cube = actor.cube(\n centers=np.array([[15, 0, 0]]),\n colors=np.array([[0, 0, 1]]),\n scales=np.array([[20, 20, 20]]),\n directions=np.array([[0, 0, 1]]),\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we'll add three sliders: one circular and two linear.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "ring_slider = ui.RingSlider2D(\n center=(740, 400), initial_value=0, text_template='{angle:5.1f}\u00b0'\n)\n\nline_slider_x = ui.LineSlider2D(\n center=(500, 250),\n initial_value=0,\n min_value=-10,\n max_value=10,\n orientation='horizontal',\n)\n\nline_slider_y = ui.LineSlider2D(\n center=(650, 350),\n initial_value=0,\n min_value=-10,\n max_value=10,\n orientation='vertical',\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can use a callback to rotate the cube with the ring slider.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def rotate_cube(slider):\n angle = slider.value\n previous_angle = slider.previous_value\n rotation_angle = angle - previous_angle\n cube.RotateX(rotation_angle)\n\n\nring_slider.on_change = rotate_cube" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Similarly, we can translate the cube with line sliders.\nWe use global variables to keep track of the position of the cube.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "cube_x = 0\ncube_y = 0\n\n\ndef translate_cube_x(slider):\n global cube_x, cube_y\n cube_x = slider.value\n cube.SetPosition(cube_x, cube_y, 0)\n\n\ndef translate_cube_y(slider):\n global cube_x, cube_y\n cube_y = slider.value\n cube.SetPosition(cube_x, cube_y, 0)\n\n\nline_slider_x.on_change = translate_cube_x\nline_slider_y.on_change = translate_cube_y" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Range Slider\n\nFinally, we can add a range slider. This element is composed of two sliders.\nThe first slider has two handles which let you set the range of the second.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "range_slider_x = ui.RangeSlider(\n line_width=8,\n handle_side=25,\n range_slider_center=(450, 450),\n value_slider_center=(450, 350),\n length=150,\n min_value=0,\n max_value=10,\n font_size=18,\n range_precision=2,\n value_precision=4,\n shape='square',\n)\n\nrange_slider_y = ui.RangeSlider(\n line_width=8,\n handle_side=25,\n range_slider_center=(750, 400),\n value_slider_center=(650, 400),\n length=150,\n min_value=0,\n max_value=10,\n font_size=18,\n range_precision=2,\n value_precision=4,\n orientation='vertical',\n shape='square',\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Select menu\n\nWe just added many examples. If we showed them all at once, they would fill\nthe screen. Let's make a simple menu to choose which example is shown.\n\nWe'll first make a list of the examples.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "examples = [\n [rect],\n [disk, ring],\n [img],\n [panel],\n [ring_slider, line_slider_x, line_slider_y],\n [range_slider_x, range_slider_y],\n]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we'll make a function to hide all the examples. Then we'll call it so\nthat none are shown initially.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def hide_all_examples():\n for example in examples:\n for element in example:\n element.set_visibility(False)\n cube.SetVisibility(False)\n\n\nhide_all_examples()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To make the menu, we'll first need to create a list of labels which\ncorrespond with the examples.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "values = [\n 'Rectangle',\n 'Disks',\n 'Image',\n 'Button Panel',\n 'Line & Ring Slider',\n 'Range Slider',\n]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we can create the menu.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "listbox = ui.ListBox2D(\n values=values, position=(10, 300), size=(300, 200), multiselection=False\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Then we will use a callback to show the correct example when a label is\nclicked.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def display_element():\n hide_all_examples()\n example = examples[values.index(listbox.selected[0])]\n for element in example:\n element.set_visibility(True)\n if values.index(listbox.selected[0]) == 4:\n cube.SetVisibility(True)\n\n\nlistbox.on_change = display_element" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Show Manager\n\nNow that all the elements have been initialised, we add them to the show\nmanager.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "current_size = (800, 800)\nshow_manager = window.ShowManager(size=current_size, title='FURY UI Example')\n\nshow_manager.scene.add(listbox)\nfor example in examples:\n for element in example:\n show_manager.scene.add(element)\nshow_manager.scene.add(cube)\nshow_manager.scene.reset_camera()\nshow_manager.scene.set_camera(position=(0, 0, 200))\nshow_manager.scene.reset_clipping_range()\nshow_manager.scene.azimuth(30)\n\n# To interact with the UI, set interactive = True\ninteractive = False\n\nif interactive:\n show_manager.start()\n\nwindow.record(show_manager.scene, size=current_size, out_path='viz_ui.png')" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.8" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/v0.10.x/_downloads/352429e70db79ae93c188dcb793070c8/viz_earth_animation.ipynb b/v0.10.x/_downloads/352429e70db79ae93c188dcb793070c8/viz_earth_animation.ipynb new file mode 100644 index 000000000..c24a73d07 --- /dev/null +++ b/v0.10.x/_downloads/352429e70db79ae93c188dcb793070c8/viz_earth_animation.ipynb @@ -0,0 +1,295 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Texture Sphere Animation\nIn this tutorial, we will show how to animate a textured sphere.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "import itertools\n\nimport numpy as np\n\nfrom fury import actor, io, utils, window\nfrom fury.data import (\n fetch_viz_models,\n fetch_viz_textures,\n read_viz_models,\n read_viz_textures,\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Create a scene to start.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "scene = window.Scene()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Next, load in a texture for each of the actors. For this tutorial, we will\nbe creating one textured sphere for the Earth, and another for the moon.\nCollect the Earth texture from the FURY github using ``fetch_viz_textures``\nand ``read_viz_textures``, then use ``io.load_image`` to load in the\nimage.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "fetch_viz_textures()\nearth_filename = read_viz_textures('1_earth_8k.jpg')\nearth_image = io.load_image(earth_filename)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Using ``actor.texture_on_sphere()``, create an earth_actor with your newly\nloaded texture.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "earth_actor = actor.texture_on_sphere(earth_image)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Then, do the same for the moon.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "moon_filename = read_viz_textures('moon-8k.jpg')\nmoon_image = io.load_image(moon_filename)\n\nmoon_actor = actor.texture_on_sphere(moon_image)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Add both actors to the already existing scene.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "scene.add(earth_actor)\nscene.add(moon_actor)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Next, alter the position and scale of the moon to correctly size it in\ncomparison to the Earth using ``actor.SetPosition()`` and\n``actor.SetScale()``, and rotate the Earth using ``utils.rotate`` to\ncorrectly align the texture.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "moon_actor.SetPosition(1, 0.1, 0.5)\nmoon_actor.SetScale(0.25, 0.25, 0.25)\nutils.rotate(earth_actor, (-90, 1, 0, 0))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The ShowManager class is the interface between the scene, the window and the\ninteractor.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "showm = window.ShowManager(\n scene, size=(900, 768), reset_camera=False, order_transparent=True\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Next, let's focus on creating the animation.\nWe can determine the duration of animation with using the ``counter``.\nUse itertools to avoid global variables.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "counter = itertools.count()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Use ``set_camera`` to ensure the camera is in the optimal position for the\nscene.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "scene.set_camera(\n position=(0.24, 0.00, 4.34),\n focal_point=(0.00, 0.00, 0.00),\n view_up=(0.00, 1.00, 0.00),\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's create a sphere actor to add to the Earth. We will place this sphere\non the Earth's surface on Bloomington, IN, home of FURY's headquarters!\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "center = np.array([[-0.39, 0.3175, 0.025]])\nradius = 0.002\nsphere_actor = actor.sphere(center, window.colors.blue_medium, radius)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Also creating a text actor to add below the sphere.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "text_actor = actor.text_3d(\n 'Bloomington, Indiana', (-0.42, 0.31, 0.03), window.colors.white, 0.004\n)\nutils.rotate(text_actor, (-90, 0, 1, 0))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's also import a model of a satellite to visualize circling the moon.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "fetch_viz_models()\nsatellite_filename = read_viz_models('satellite_obj.obj')\nsatellite = io.load_polydata(satellite_filename)\nsatellite_actor = utils.get_actor_from_polydata(satellite)\n\nsatellite_actor.SetPosition(-0.75, 0.1, 0.4)\nsatellite_actor.SetScale(0.005, 0.005, 0.005)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In the ``timer_callback`` function, use if statements to specify when\ncertain events will happen in the animation, based on the position that\nthe counter is at. So, for example, the earth actor will continue to\nrotate while the count is less than 450.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def timer_callback(_obj, _event):\n cnt = next(counter)\n showm.render()\n if cnt < 450:\n utils.rotate(earth_actor, (1, 0, 1, 0))\n if cnt % 5 == 0 and cnt < 450:\n showm.scene.azimuth(-1)\n if cnt == 300:\n scene.set_camera(\n position=(-3.679, 0.00, 2.314),\n focal_point=(0.0, 0.35, 0.00),\n view_up=(0.00, 1.00, 0.00),\n )\n if cnt > 300 and cnt < 450:\n scene.zoom(1.01)\n if cnt >= 450 and cnt < 1500:\n scene.add(sphere_actor)\n scene.add(text_actor)\n if cnt >= 450 and cnt < 550:\n scene.zoom(1.01)\n if cnt == 575:\n moon_actor.SetPosition(-1, 0.1, 0.5)\n scene.set_camera(\n position=(-0.5, 0.1, 0.00),\n focal_point=(-1, 0.1, 0.5),\n view_up=(0.00, 1.00, 0.00),\n )\n scene.zoom(0.03)\n scene.add(satellite_actor)\n utils.rotate(satellite_actor, (180, 0, 1, 0))\n scene.rm(earth_actor)\n if cnt > 575 and cnt < 750:\n showm.scene.azimuth(-2)\n utils.rotate(moon_actor, (-2, 0, 1, 0))\n satellite_actor.SetPosition(-0.8, 0.1 - cnt / 10000, 0.4)\n if cnt >= 750 and cnt < 1100:\n showm.scene.azimuth(-2)\n utils.rotate(moon_actor, (-2, 0, 1, 0))\n satellite_actor.SetPosition(-0.8, -0.07 + cnt / 10000, 0.4)\n if cnt == 1100:\n showm.exit()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Watch your new animation take place!\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "showm.add_timer_callback(True, 35, timer_callback)\nshowm.start()\nwindow.record(showm.scene, size=(900, 768), out_path='viz_earth_animation.png')" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.8" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/v0.10.x/_downloads/35de4ad1a7ff55aeb7f746c9159f26be/viz_skinning.ipynb b/v0.10.x/_downloads/35de4ad1a7ff55aeb7f746c9159f26be/viz_skinning.ipynb new file mode 100644 index 000000000..4512a9dfe --- /dev/null +++ b/v0.10.x/_downloads/35de4ad1a7ff55aeb7f746c9159f26be/viz_skinning.ipynb @@ -0,0 +1,151 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Skeletal Animation in a glTF file\nIn this tutorial, we will show how to use skeletal animations (skinning) in a\nglTF model in FURY.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "from fury import window\nfrom fury.data import fetch_gltf, read_viz_gltf\nfrom fury.gltf import glTF" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Retrieving the model with skeletal animations.\nWe're choosing the `RiggedFigure` model here.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "fetch_gltf('RiggedFigure', 'glTF')\nfilename = read_viz_gltf('RiggedFigure')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Initializing the glTF object, You can additionally set `apply_normals=True`.\nNote: Normals might not work well as intended with skinning animations.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "gltf_obj = glTF(filename, apply_normals=False)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Get the skinning timeline using `skin_timeline` method, Choose the animation\nname you want to visualize.\nNote: If there's no name for animation, It's stored as `anim_0`, `anim_1` etc\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "animation = gltf_obj.skin_animation()['anim_0']\n\n# After we get the timeline object, We want to initialise the skinning process.\n# You can set `bones=true` to visualize each bone transformation. Additionally,\n# you can set `length` of bones in the `initialise_skin` method.\n# Note: Make sure to call this method before you initialize ShowManager, else\n# bones won't be added to the scene.\n\ngltf_obj.initialize_skin(animation, bones=False)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Create a scene, and show manager.\nInitialize the show manager and add timeline to the scene (No need to add\nactors to the scene separately).\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "scene = window.Scene()\nshowm = window.ShowManager(\n scene, size=(900, 768), reset_camera=True, order_transparent=True\n)\nshowm.initialize()\nscene.add(animation)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "define a timer_callback.\nUse the `update_skin` method, It updates the timeline and applies skinning to\nactors (and bones).\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def timer_callback(_obj, _event):\n gltf_obj.update_skin(animation)\n showm.render()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Optional: `timeline.play()` auto plays the animations.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "showm.add_timer_callback(True, 20, timer_callback)\nscene.reset_camera()\n\ninteractive = False\n\nif interactive:\n showm.start()\n\nwindow.record(scene, out_path='viz_skinning.png', size=(900, 768))" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.8" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/v0.10.x/_downloads/39aa8822f7757cc0da0e64c18082f036/viz_robot_arm_animation.py b/v0.10.x/_downloads/39aa8822f7757cc0da0e64c18082f036/viz_robot_arm_animation.py new file mode 100644 index 000000000..24dc53700 --- /dev/null +++ b/v0.10.x/_downloads/39aa8822f7757cc0da0e64c18082f036/viz_robot_arm_animation.py @@ -0,0 +1,121 @@ +""" +=================== +Arm Robot Animation +=================== + +Tutorial on making a robot arm animation in FURY. +""" +import numpy as np + +from fury import actor, window +from fury.animation import Animation, Timeline +from fury.utils import set_actor_origin + +scene = window.Scene() + +showm = window.ShowManager( + scene, size=(900, 768), reset_camera=False, order_transparent=True +) +showm.initialize() + + +############################################################################### +# Creating robot arm components + +base = actor.cylinder( + np.array([[0, 0, 0]]), np.array([[0, 1, 0]]), colors=(0, 1, 0), radius=1 +) +main_arm = actor.box(np.array([[0, 0, 0]]), colors=(1, 0.5, 0), scales=(12, 1, 1)) + +sub_arm = actor.box(np.array([[0, 0, 0]]), colors=(0, 0.5, 0.8), scales=(8, 0.7, 0.7)) +joint_1 = actor.sphere(np.array([[0, 0, 0]]), colors=np.array([1, 0, 1]), radii=1.2) +joint_2 = actor.sphere(np.array([[0, 0, 0]]), colors=np.array([1, 0, 1])) + +end = actor.cone( + np.array([[0, 0, 0]]), + np.array([[1, 0, 0]]), + np.array([[1, 0, 0]]), + heights=2.2, + resolution=6, +) + +############################################################################### +# Setting the center of both shafts to the beginning. +set_actor_origin(main_arm, np.array([-6, 0, 0])) +set_actor_origin(sub_arm, np.array([-4, 0, 0])) + +############################################################################### +# Creating a timeline +timeline = Timeline(playback_panel=True) + +############################################################################### +# Creating animations +main_arm_animation = Animation([main_arm, joint_1], length=2 * np.pi) +child_arm_animation = Animation([sub_arm, joint_2]) +drill_animation = Animation(end) + + +############################################################################### +# Adding other Animations in hierarchical order +main_arm_animation.add_child_animation(child_arm_animation) +child_arm_animation.add_child_animation(drill_animation) + + +############################################################################### +# Creating Arm joints time dependent animation functions. + + +def rot_main_arm(t): + return np.array([np.sin(t / 2) * 180, np.cos(t / 2) * 180, 0]) + + +def rot_sub_arm(t): + return np.array([np.sin(t) * 180, np.cos(t) * 70, np.cos(t) * 40]) + + +def rot_drill(t): + return np.array([t * 1000, 0, 0]) + + +############################################################################### +# Setting timelines (joints) relative position +# 1- Placing the main arm on the cube static base. +main_arm_animation.set_position(0, np.array([0, 1.3, 0])) + +############################################################################### +# 2- Translating the timeline containing the sub arm to the end of the first +# arm. +child_arm_animation.set_position(0, np.array([12, 0, 0])) + +############################################################################### +# 3- Translating the timeline containing the drill to the end of the sub arm. +drill_animation.set_position(0, np.array([8, 0, 0])) + +############################################################################### +# Setting rotation time-based evaluators +main_arm_animation.set_rotation_interpolator(rot_main_arm, is_evaluator=True) +child_arm_animation.set_rotation_interpolator(rot_sub_arm, is_evaluator=True) +drill_animation.set_rotation_interpolator(rot_drill, is_evaluator=True) + +############################################################################### +# Setting camera position to observe the robot arm. +scene.camera().SetPosition(0, 0, 90) + +############################################################################### +# Adding the base actor to the scene +scene.add(base) + +############################################################################### +# Adding the main parent animation to the Timeline. +timeline.add_animation(main_arm_animation) + +############################################################################### +# Now we add the timeline to the ShowManager +showm.add_animation(timeline) + +interactive = False + +if interactive: + showm.start() + +window.record(scene, out_path='viz_robot_arm.png', size=(900, 768)) diff --git a/v0.10.x/_downloads/3aa38a61f3ecdfc816b700db8adb0518/viz_spiky.ipynb b/v0.10.x/_downloads/3aa38a61f3ecdfc816b700db8adb0518/viz_spiky.ipynb new file mode 100644 index 000000000..00f01d915 --- /dev/null +++ b/v0.10.x/_downloads/3aa38a61f3ecdfc816b700db8adb0518/viz_spiky.ipynb @@ -0,0 +1,230 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Spiky Sphere\nIn this tutorial, we show how to create a sphere with spikes.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "import itertools\n\nimport numpy as np\n\nfrom fury import actor, primitive, utils, window" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Create a sphere actor. Define the center, radius and color of a sphere.\nThe sphere actor is made of points (vertices) evenly distributed on a\nsphere.\nLet's create a scene.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "scene = window.Scene()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The vertices are connected with triangles in order to specify the direction\nof the surface normal.\n``prim_sphere`` provides a sphere with evenly distributed points\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "vertices, triangles = primitive.prim_sphere(name='symmetric362', gen_faces=False)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To be able to visualize the vertices, let's define a point actor with\ngreen color.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "point_actor = actor.point(vertices, point_radius=0.01, colors=(0, 1, 0))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Normals are the vectors that are perpendicular to the surface at each\nvertex. We specify the normals at the vertices to tell the system\nwhether triangles represent curved surfaces.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "normals = utils.normals_from_v_f(vertices, triangles)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The normals are usually used to calculate how the light will bounce on\nthe surface of an object. However, here we will use them to direct the\nspikes (represented with arrows).\nSo, let's create an arrow actor at the center of each vertex.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "arrow_actor = actor.arrow(\n centers=vertices,\n directions=normals,\n colors=(1, 0, 0),\n heights=0.2,\n resolution=10,\n vertices=None,\n faces=None,\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To be able to visualize the surface of the primitive sphere, we use\n``get_actor_from_primitive``.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "primitive_colors = np.zeros(vertices.shape)\nprimitive_colors[:, 2] = 180\nprimitive_actor = utils.get_actor_from_primitive(\n vertices=vertices,\n triangles=triangles,\n colors=primitive_colors,\n normals=normals,\n backface_culling=True,\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We add all actors (visual objects) defined above to the scene.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "scene.add(point_actor)\nscene.add(arrow_actor)\nscene.add(primitive_actor)\nscene.add(actor.axes())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The ShowManager class is the interface between the scene, the window and the\ninteractor.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "showm = window.ShowManager(\n scene, size=(900, 768), reset_camera=False, order_transparent=True\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We want to make a small animation for fun!\nWe can determine the duration of animation with using the ``counter``.\nUse itertools to avoid global variables.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "counter = itertools.count()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The timer will call this user defined callback every 200 milliseconds. The\napplication will exit after the callback has been called 20 times.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def timer_callback(_obj, _event):\n cnt = next(counter)\n showm.scene.azimuth(0.05 * cnt)\n primitive_actor.GetProperty().SetOpacity(cnt / 10.0)\n showm.render()\n if cnt == 20:\n showm.exit()\n\n\nshowm.add_timer_callback(True, 200, timer_callback)\nshowm.start()\nwindow.record(showm.scene, size=(900, 768), out_path='viz_spiky.png')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Instead of arrows, you can choose other geometrical objects\nsuch as cones, cubes or spheres.\n\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.8" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/v0.10.x/_downloads/3b433bf413a4790ff3c6b290992444ee/viz_sphere.py b/v0.10.x/_downloads/3b433bf413a4790ff3c6b290992444ee/viz_sphere.py new file mode 100644 index 000000000..45b9489da --- /dev/null +++ b/v0.10.x/_downloads/3b433bf413a4790ff3c6b290992444ee/viz_sphere.py @@ -0,0 +1,44 @@ +""" +====================================================================== +FURY sphere Actor +====================================================================== +This example shows how to use both primitive and vtkSource sphere actor. +""" + +import numpy as np + +from fury import actor, window + +############################################################################ +# First thing, you have to specify centers and colors of the sphere + +centers = np.zeros([1, 3]) +colors = np.array([0, 0, 1]) + +############################################################################ +# The below sphere actor is generated by repeating the sphere primitive. + +prim_sphere_actor = actor.sphere(centers, colors=colors, radii=5) + +############################################################################ +# This time, we're using vtkSphereSource to generate the sphere actor + +cen2 = np.add(centers, np.array([12, 0, 0])) +cols2 = np.array([1, 0, 0]) + +vtk_sphere_actor = actor.sphere(cen2, colors=cols2, radii=5, use_primitive=False) + +scene = window.Scene() + +############################################################################ +# Adding our sphere actors to scene. + +scene.add(prim_sphere_actor) +scene.add(vtk_sphere_actor) + +interactive = False + +if interactive: + window.show(scene, size=(600, 600)) + +window.record(scene, out_path='viz_sphere.png', size=(600, 600)) diff --git a/v0.10.x/_downloads/3c120f2cd63e5ca4560f16b7a034fa6c/viz_ball_collide.ipynb b/v0.10.x/_downloads/3c120f2cd63e5ca4560f16b7a034fa6c/viz_ball_collide.ipynb new file mode 100644 index 000000000..54beef57a --- /dev/null +++ b/v0.10.x/_downloads/3c120f2cd63e5ca4560f16b7a034fa6c/viz_ball_collide.ipynb @@ -0,0 +1,133 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Ball Collision Simulation\n\nThis example simulation shows how to use pybullet to render physics simulations\nin fury. In this example we render the collision between a blue ball and red\nball and also display a message by confirming the collision.\n\nFirst some imports.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "import itertools\n\nimport numpy as np\nimport pybullet as p\n\nfrom fury import actor, ui, window\n\nclient = p.connect(p.DIRECT)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Parameters and definition of red and blue balls.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "red_radius = 0.5\nblue_radius = 0.5\nduration = 50\n\n# Red Ball\nred_ball_actor = actor.sphere(\n centers=np.array([[0, 0, 0]]), colors=np.array([[1, 0, 0]]), radii=red_radius\n)\n\nred_ball_coll = p.createCollisionShape(p.GEOM_SPHERE, radius=red_radius)\n\nred_ball = p.createMultiBody(\n baseMass=0.5,\n baseCollisionShapeIndex=red_ball_coll,\n basePosition=[10, 0, 0],\n baseOrientation=[0, 0, 0, 1],\n)\n\n# Blue ball\nblue_ball_actor = actor.sphere(\n centers=np.array([[0, 0, 0]]), colors=np.array([[0, 0, 1]]), radii=blue_radius\n)\n\nblue_ball_coll = p.createCollisionShape(p.GEOM_SPHERE, radius=blue_radius)\n\nblue_ball = p.createMultiBody(\n baseMass=0.5,\n baseCollisionShapeIndex=blue_ball_coll,\n basePosition=[-10, 0, 0],\n baseOrientation=[0, 0, 0, 1],\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We set the coefficient of restitution of both the balls to `0.6`.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "p.changeDynamics(red_ball, -1, restitution=0.6)\np.changeDynamics(blue_ball, -1, restitution=0.6)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We add all the actors to the scene.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "scene = window.Scene()\nscene.add(actor.axes())\nscene.add(red_ball_actor)\nscene.add(blue_ball_actor)\n\nshowm = window.ShowManager(\n scene, size=(900, 700), reset_camera=False, order_transparent=True\n)\n\n\ncounter = itertools.count()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Method to sync objects.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def sync_actor(actor, multibody):\n pos, orn = p.getBasePositionAndOrientation(multibody)\n actor.SetPosition(*pos)\n orn_deg = np.degrees(p.getEulerFromQuaternion(orn))\n actor.SetOrientation(*orn_deg)\n\n\napply_force = True\ntb = ui.TextBlock2D(position=(0, 600), font_size=30, color=(1, 0.5, 0), text='')\nscene.add(tb)\nscene.set_camera(\n position=(0.30, -18.78, 0.89), focal_point=(0.15, 0.25, 0.40), view_up=(0, 0, 1.00)\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Timer callback to sync and step simulation every second.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def timer_callback(_obj, _event):\n global apply_force\n cnt = next(counter)\n showm.render()\n red_pos, red_orn = p.getBasePositionAndOrientation(red_ball)\n blue_pos, blue_orn = p.getBasePositionAndOrientation(blue_ball)\n\n # Apply force for the first step of the simulation.\n if apply_force:\n p.applyExternalForce(\n red_ball, -1, forceObj=[-40000, 0, 0], posObj=red_pos, flags=p.WORLD_FRAME\n )\n\n p.applyExternalForce(\n blue_ball, -1, forceObj=[40000, 0, 0], posObj=blue_pos, flags=p.WORLD_FRAME\n )\n\n apply_force = 0\n\n sync_actor(blue_ball_actor, blue_ball)\n sync_actor(red_ball_actor, red_ball)\n\n # Get various collision information using `p.getContactPoints`.\n contact = p.getContactPoints(red_ball, blue_ball, -1, -1)\n if len(contact) != 0:\n tb.message = 'Collision!!'\n\n p.stepSimulation()\n\n if cnt == 50:\n showm.exit()\n\n\nshowm.add_timer_callback(True, duration, timer_callback)\n\ninteractive = False\n\nif interactive:\n showm.start()\n\nwindow.record(scene, size=(900, 700), out_path='viz_ball_collide.png')" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.8" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/v0.10.x/_downloads/44c6770f18ab25e2228c6f470d88452f/viz_tab.py b/v0.10.x/_downloads/44c6770f18ab25e2228c6f470d88452f/viz_tab.py new file mode 100644 index 000000000..adcfcbdc9 --- /dev/null +++ b/v0.10.x/_downloads/44c6770f18ab25e2228c6f470d88452f/viz_tab.py @@ -0,0 +1,233 @@ +""" +======== +Tab UI +======== + +This example shows how to use the Tab UI. We will demonstrate how to +create Tabs for: + +1. Slider controls for a Cube +2. Checkboxes for Cylinder and Sphere +3. Color combobox for Fury. + +First, some imports. +""" +import numpy as np + +from fury import actor, ui, window +from fury.data import fetch_viz_icons + +############################################################################## +# First we need to fetch some icons that are included in FURY. + +fetch_viz_icons() + +############################################################################### +# First, we create the Tab UI. + +tab_ui = ui.TabUI(position=(49, 94), size=(300, 300), nb_tabs=3, draggable=True) + +############################################################################### +# Slider Controls for a Cube for Tab Index 0 +# ========================================== +# +# Now we prepare content for the first tab. + +ring_slider = ui.RingSlider2D(initial_value=0, text_template='{angle:5.1f}°') + +line_slider_x = ui.LineSlider2D( + initial_value=0, + min_value=-10, + max_value=10, + orientation='horizontal', + text_alignment='Top', +) + +line_slider_y = ui.LineSlider2D( + initial_value=0, + min_value=-10, + max_value=10, + orientation='vertical', + text_alignment='Right', +) + +cube = actor.box( + centers=np.array([[10, 0, 0]]), + directions=np.array([[0, 1, 0]]), + colors=np.array([[0, 0, 1]]), + scales=np.array([[1, 1, 1]]), +) +cube_x = 0 +cube_y = 0 + + +def rotate_cube(slider): + angle = slider.value + previous_angle = slider.previous_value + rotation_angle = angle - previous_angle + cube.RotateX(rotation_angle) + + +def translate_cube_x(slider): + global cube_x, cube_y + cube_x = slider.value + cube.SetPosition(cube_x, cube_y, 0) + + +def translate_cube_y(slider): + global cube_x, cube_y + cube_y = slider.value + cube.SetPosition(cube_x, cube_y, 0) + + +ring_slider.on_change = rotate_cube +line_slider_x.on_change = translate_cube_x +line_slider_y.on_change = translate_cube_y + +############################################################################### +# After defining content, we define properties for the tab. + +tab_ui.tabs[0].title = 'Sliders' +tab_ui.add_element(0, ring_slider, (0.3, 0.3)) +tab_ui.add_element(0, line_slider_x, (0.0, 0.0)) +tab_ui.add_element(0, line_slider_y, (0.0, 0.1)) + +############################################################################### +# CheckBoxes For Cylinder and Sphere for Tab Index 1 +# ================================================== +# +# Now we prepare content for second tab. + +cylinder = actor.cylinder( + centers=np.array([[0, 0, 0]]), + directions=np.array([[1, 1, 0]]), + colors=np.array([[0, 1, 1]]), + radius=1.0, +) + +sphere = actor.sphere(centers=np.array([[5, 0, 0]]), colors=(1, 1, 0)) + +figure_dict = {'cylinder': cylinder, 'sphere': sphere} +checkbox = ui.Checkbox(labels=['cylinder', 'sphere']) + + +# Get difference between two lists. +def sym_diff(l1, l2): + return list(set(l1).symmetric_difference(set(l2))) + + +# Set Visibility of the figures +def set_figure_visiblity(checkboxes): + checked = checkboxes.checked_labels + unchecked = sym_diff(list(figure_dict), checked) + + for visible in checked: + figure_dict[visible].SetVisibility(True) + + for invisible in unchecked: + figure_dict[invisible].SetVisibility(False) + + +checkbox.on_change = set_figure_visiblity + +############################################################################### +# After defining content, we define properties for the tab. + +tab_ui.tabs[1].title = 'Checkbox' +tab_ui.add_element(1, checkbox, (0.2, 0.2)) + +############################################################################### +# Color Combobox for Fury for Tab Index 2 +# ======================================= +# +# Now we prepare content for third tab. + +label = ui.TextBlock2D( + position=(600, 300), + font_size=40, + color=(1, 0.5, 0), + justification='center', + vertical_justification='top', + text='FURY rocks!!!', +) + +colors = { + 'Violet': (0.6, 0, 0.8), + 'Indigo': (0.3, 0, 0.5), + 'Blue': (0, 0, 1), + 'Green': (0, 1, 0), + 'Yellow': (1, 1, 0), + 'Orange': (1, 0.5, 0), + 'Red': (1, 0, 0), +} + +color_combobox = ui.ComboBox2D( + items=list(colors.keys()), + placeholder='Choose Text Color', + size=(250, 150), + draggable=True, +) + + +def change_color(combobox): + label.color = colors[combobox.selected_text] + + +color_combobox.on_change = change_color + +############################################################################### +# After defining content, we define properties for the tab. + +tab_ui.tabs[2].title = 'Colors' +tab_ui.add_element(2, color_combobox, (0.1, 0.3)) + +############################################################################### +# Define on_change & on_collapsed methods for tab ui to perform certain tasks +# while active tab is changed or when the tab is collapsed. +# Note: Tab UI can be collapsed by right clicking on it. + + +def hide_actors(tab_ui): + if tab_ui.tabs[tab_ui.active_tab_idx].title == 'Sliders': + cube.SetVisibility(True) + cylinder.SetVisibility(False) + sphere.SetVisibility(False) + label.set_visibility(False) + + elif tab_ui.tabs[tab_ui.active_tab_idx].title == 'Checkbox': + cube.SetVisibility(False) + set_figure_visiblity(checkbox) + label.set_visibility(False) + + else: + cube.SetVisibility(False) + cylinder.SetVisibility(False) + sphere.SetVisibility(False) + label.set_visibility(True) + + +def collapse(tab_ui): + if tab_ui.collapsed: + cube.SetVisibility(False) + cylinder.SetVisibility(False) + sphere.SetVisibility(False) + label.set_visibility(False) + + +tab_ui.on_change = hide_actors +tab_ui.on_collapse = collapse + + +############################################################################### +# Next we prepare the scene and render it with the help of show manager. + +sm = window.ShowManager(size=(800, 500), title='Viz Tab') +sm.scene.add(tab_ui, cube, cylinder, sphere, label) + +# To interact with the ui set interactive = True +interactive = False + +if interactive: + sm.start() + +window.record(sm.scene, size=(500, 500), out_path='viz_tab.png') diff --git a/v0.10.x/_downloads/44cc07131741749deeb136c3113bbd03/viz_interpolators.py b/v0.10.x/_downloads/44cc07131741749deeb136c3113bbd03/viz_interpolators.py new file mode 100644 index 000000000..6a63c112b --- /dev/null +++ b/v0.10.x/_downloads/44cc07131741749deeb136c3113bbd03/viz_interpolators.py @@ -0,0 +1,136 @@ +""" +===================== +Keyframe animation +===================== + +Minimal tutorial of making keyframe-based animation in FURY. +""" + +############################################################################### +# What is an ``Animation`` +# ======================== +# +# ``Animation`` is responsible for animating FURY actors using a set of +# keyframes by interpolating values between timestamps of these keyframes. + +import numpy as np + +from fury import actor, window +from fury.animation import Animation +from fury.animation.interpolator import cubic_spline_interpolator + +keyframes = { + 1.0: {'value': np.array([0, 0, 0])}, + 2.0: {'value': np.array([-4, 1, 0])}, + 5.0: {'value': np.array([0, 0, 12])}, + 6.0: {'value': np.array([25, 0, 12])}, +} + +############################################################################### +# Why keyframes data are also a dictionary ``{'value': np.array([0, 0, 0])})``? +# -> Since some keyframes data can only be defined by a set of data i.e. a +# single position keyframe could consist of a position, in control point, and +# out control point or any other data that helps to define this keyframe. + + +############################################################################### +# What are the interpolators +# ========================== +# +# The keyframes interpolators are functions that takes a set of keyframes and +# returns a function that calculates an interpolated value between these +# keyframes. +# Below there is an example on how to use interpolators manually to interpolate +# the above defined ``keyframes``. + +interpolation_function = cubic_spline_interpolator(keyframes) + +############################################################################### +# Now, if we feed any time to this function it would return the cubic +# interpolated position at that time. + +position = interpolation_function(1.44434) + +############################################################################### +# ``position`` would contain an interpolated position at time equals 1.44434 + +############################################################################### +# Creating the environment +# ======================== +# +# In order to make any animations in FURY, a `ShowManager` is needed to handle +# updating the animation and rendering the scene. + +scene = window.Scene() + +showm = window.ShowManager( + scene, size=(900, 768), reset_camera=False, order_transparent=True +) +showm.initialize() + +arrow = actor.arrow(np.array([[0, 0, 0]]), (0, 0, 0), (1, 0, 1), scales=6) + +############################################################################### +# Creating an ``Animation`` +# ========================= +# +# First step is creating the Animation. +animation = Animation() + +############################################################################### +# Adding the sphere actor to the timeline +# This could've been done during initialization. +animation.add_actor(arrow) + +############################################################################### +# Setting position keyframes +# ========================== +# +# Adding some position keyframes +animation.set_position(0.0, np.array([0, 0, 0])) +animation.set_position(2.0, np.array([10, 10, 10])) +animation.set_position(5.0, np.array([-10, -3, -6])) +animation.set_position(9.0, np.array([10, 6, 20])) + +############################################################################### +# Changing the default interpolator for a single property +# ======================================================= +# +# For all properties except **rotation**, linear interpolator is used by +# default. In order to change the default interpolator and set another +# interpolator, call ``animation.set__interpolator(interpolator)`` +# FURY already has some interpolators located at: +# ``fury.animation.interpolator``. +# +# Below we set the interpolator for position keyframes to be +# **cubic spline interpolator**. +animation.set_position_interpolator(cubic_spline_interpolator) + +############################################################################### +# Adding some rotation keyframes. +animation.set_rotation(0.0, np.array([160, 50, 0])) +animation.set_rotation(8.0, np.array([60, 160, 0])) + +############################################################################### +# For Rotation keyframes, Slerp is used as the default interpolator. +# What is Slerp? +# Slerp (spherical linear interpolation) of quaternions results in a constant +# speed rotation in keyframe animation. +# Reed more about Slerp: https://en.wikipedia.org/wiki/Slerp + +############################################################################### +# Setting camera position to see the animation better. +scene.set_camera(position=(0, 0, 90)) + +############################################################################### +# Adding main animation to the ``ShowManager``. +showm.add_animation(animation) + +############################################################################### +# Start the ``ShowManager`` to start playing the animation +interactive = False + +if interactive: + showm.start() + +window.record(scene, out_path='viz_keyframe_interpolator.png', size=(900, 768)) diff --git a/v0.10.x/_downloads/4517c6a513f7b72c17aad95afd1a161f/viz_markers.ipynb b/v0.10.x/_downloads/4517c6a513f7b72c17aad95afd1a161f/viz_markers.ipynb new file mode 100644 index 000000000..b37c032d6 --- /dev/null +++ b/v0.10.x/_downloads/4517c6a513f7b72c17aad95afd1a161f/viz_markers.ipynb @@ -0,0 +1,97 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Fury Markers\n\nThis example shows how to use the marker actor.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "import numpy as np\n\nfrom fury import actor, window\n\nn = 10000" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "There are nine types 2d markers: circle, square, diamond, triangle, pentagon,\nhexagon, heptagon, cross and plus.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "marker_symbols = ['o', 's', 'd', '^', 'p', 'h', 's6', 'x', '+']\nmarkers = [np.random.choice(marker_symbols) for i in range(n)]\n\ncenters = np.random.normal(size=(n, 3), scale=10)\n\ncolors = np.random.uniform(size=(n, 3))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You can control the edge color and edge width for each marker\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "nodes_actor = actor.markers(\n centers,\n marker=markers,\n edge_width=0.1,\n edge_color=[255, 255, 0],\n colors=colors,\n scales=0.5,\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In addition, an 3D sphere it's also a valid type of marker\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "nodes_3d_actor = actor.markers(\n centers + np.ones_like(centers) * 25,\n marker='3d',\n colors=colors,\n scales=0.5,\n)\n\nscene = window.Scene()\n\nscene.add(nodes_actor)\nscene.add(nodes_3d_actor)\n\ninteractive = False\n\nif interactive:\n window.show(scene, size=(600, 600))\n\nwindow.record(scene, out_path='viz_markers.png', size=(600, 600))" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.8" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/v0.10.x/_downloads/4702bc8bbbcaf0f639ae036269723231/viz_domino.py b/v0.10.x/_downloads/4702bc8bbbcaf0f639ae036269723231/viz_domino.py new file mode 100644 index 000000000..8316c96eb --- /dev/null +++ b/v0.10.x/_downloads/4702bc8bbbcaf0f639ae036269723231/viz_domino.py @@ -0,0 +1,246 @@ +""" +========================= +Domino Physics Simulation +========================= + +This example simulation shows how to use pybullet to render physics simulations +in fury. In this example we specifically render a series of Dominoes which are +under Domino Effect. + +First some imports. +""" +import itertools + +import numpy as np +import pybullet as p + +from fury import actor, ui, utils, window + +# Next, we initialize a pybullet client to render the physics. +# We use `DIRECT` mode to initialize pybullet without a GUI. +client = p.connect(p.DIRECT) + +# Apply gravity to the scene. +p.setGravity(0, 0, -10, physicsClientId=client) + +############################################################################### +# Set the Number of Dominoes for Simulation. +number_of_dominoes = 10 + +# Base Plane Parameters +base_size = np.array([number_of_dominoes * 2, number_of_dominoes * 2, 0.2]) +base_color = np.array([1, 1, 1]) +base_position = np.array([0, 0, -0.1]) +base_orientation = np.array([0, 0, 0, 1]) + +# Render a BASE plane to support the Dominoes. +base_actor = actor.box( + centers=np.array([[0, 0, 0]]), + directions=[0, 0, 0], + scales=base_size, + colors=base_color, +) + +# half of the actual size. +base_coll = p.createCollisionShape(p.GEOM_BOX, halfExtents=base_size / 2) + +base = p.createMultiBody( + baseCollisionShapeIndex=base_coll, + basePosition=base_position, + baseOrientation=base_orientation, +) + +p.changeDynamics(base, -1, lateralFriction=1, restitution=0.5) + +############################################################################### +# We define some global parameters of the Dominoes so that its easier for +# us to tweak the simulation. + +domino_mass = 0.5 +domino_size = np.array([0.1, 1, 2]) + +domino_centers = np.zeros((number_of_dominoes, 3)) + +# Keeping all the dominos Parallel +domino_directions = np.zeros((number_of_dominoes, 3)) +domino_directions[:] = np.array([1.57, 0, 0]) + +domino_orns = np.zeros((number_of_dominoes, 4)) + +domino_sizes = np.zeros((number_of_dominoes, 3)) +domino_sizes[:] = domino_size + +domino_colors = np.random.rand(number_of_dominoes, 3) + +domino_coll = p.createCollisionShape(p.GEOM_BOX, halfExtents=domino_size / 2) + +# We use this array to store the reference of domino objects in pybullet world. +dominos = np.zeros(number_of_dominoes, dtype=np.int8) + +centers_list = np.zeros((number_of_dominoes, 3)) + +# Adding the dominoes +for i in range(number_of_dominoes): + center_pos = np.array([(i * 0.99) - 5.5, 0.4, 1]) + domino_centers[i] = center_pos + domino_orns[i] = np.array([0, 0, 0, 1]) + dominos[i] = p.createMultiBody( + baseMass=domino_mass, + baseCollisionShapeIndex=domino_coll, + basePosition=center_pos, + baseOrientation=domino_orns[i], + ) + p.changeDynamics(dominos[i], -1, lateralFriction=0.2, restitution=0.1) + + +domino_actor = actor.box( + centers=domino_centers, + directions=domino_directions, + scales=domino_sizes, + colors=domino_colors, +) + +############################################################################### +# Now, we define a scene and add actors to it. +scene = window.Scene() +scene.add(actor.axes()) +scene.add(base_actor) +scene.add(domino_actor) + +# Create show manager. +showm = window.ShowManager( + scene, size=(900, 768), reset_camera=False, order_transparent=True +) + + +# Counter iterator for tracking simulation steps. +counter = itertools.count() + +# Variable for tracking applied force. +apply_force = True +############################################################################### +# Now, we define methods to sync objects between fury and Pybullet. + +# Get the position of base and set it. +base_pos, _ = p.getBasePositionAndOrientation(base) +base_actor.SetPosition(*base_pos) + + +# Calculate the vertices of the dominos. +vertices = utils.vertices_from_actor(domino_actor) +num_vertices = vertices.shape[0] +num_objects = domino_centers.shape[0] +sec = int(num_vertices / num_objects) + +############################################################################### +# ================ +# Syncing Dominoes +# ================ +# +# Here, we perform three major steps to sync Dominoes accurately. +# * Get the position and orientation of the Dominoes from pybullet. +# * Calculate the Rotation Matrix. +# +# - Get the difference in orientations (Quaternion). +# - Generate the corresponding rotation matrix according to that difference. +# - Reshape it in a 3x3 matrix. +# +# * Perform calculations to get the required position and orientation. +# * Update the position and orientation. + + +def sync_domino(object_index, multibody): + pos, orn = p.getBasePositionAndOrientation(multibody) + + rot_mat = np.reshape( + p.getMatrixFromQuaternion( + p.getDifferenceQuaternion(orn, domino_orns[object_index]) + ), + (3, 3), + ) + + vertices[object_index * sec : object_index * sec + sec] = ( + vertices[object_index * sec : object_index * sec + sec] + - domino_centers[object_index] + ) @ rot_mat + pos + + domino_centers[object_index] = pos + domino_orns[object_index] = orn + + +############################################################################### +# Here, we define a textblock to display the Avg. FPS and simulation steps. + +fpss = np.array([]) +tb = ui.TextBlock2D( + text='Avg. FPS: \nSim Steps: ', position=(0, 680), font_size=30, color=(1, 0.5, 0) +) +scene.add(tb) + +############################################################################### +# Set the camera for better visualization. + +scene.set_camera( + position=(10.46, -8.13, 6.18), + focal_point=(0.0, 0.0, 0.79), + view_up=(-0.27, 0.26, 0.90), +) + + +############################################################################### +# Timer callback is created which is responsible for calling the sync and +# simulation methods. + + +# Create timer callback which will execute at each step of simulation. +def timer_callback(_obj, _event): + global apply_force, fpss + cnt = next(counter) + showm.render() + + if cnt % 1 == 0: + fps = showm.frame_rate + fpss = np.append(fpss, fps) + tb.message = ( + 'Avg. FPS: ' + str(np.round(np.mean(fpss), 0)) + '\nSim Steps: ' + str(cnt) + ) + + # Get the position and orientation of the first domino. + domino1_pos, domino1_orn = p.getBasePositionAndOrientation(dominos[0]) + + # Apply force on the First Domino (domino) above the Center of Mass. + if apply_force: + # Apply the force. + p.applyExternalForce( + dominos[0], + -1, + forceObj=[100, 0, 0], + posObj=domino1_pos + np.array([0, 0, 1.7]), + flags=p.WORLD_FRAME, + ) + apply_force = False + + # Updating the position and orientation of individual dominos. + for idx, domino in enumerate(dominos): + sync_domino(idx, domino) + utils.update_actor(domino_actor) + + # Simulate a step. + p.stepSimulation() + + # Exit after 300 steps of simulation. + if cnt == 300: + showm.exit() + + +# Add the timer callback to showmanager. +# Increasing the duration value will slow down the simulation. +showm.add_timer_callback(True, 1, timer_callback) + +interactive = False + +# start simulation +if interactive: + showm.start() + +window.record(scene, out_path='viz_domino.png', size=(900, 768)) diff --git a/v0.10.x/_downloads/4978e6bab44b48e4a6aba1c6548ccfde/viz_texture.py b/v0.10.x/_downloads/4978e6bab44b48e4a6aba1c6548ccfde/viz_texture.py new file mode 100644 index 000000000..69b7426bc --- /dev/null +++ b/v0.10.x/_downloads/4978e6bab44b48e4a6aba1c6548ccfde/viz_texture.py @@ -0,0 +1,41 @@ +""" +=============== +Sphere Texture +=============== +In this tutorial, we will show how to create a sphere with a texture. +""" + +from fury import actor, io, window +from fury.data import fetch_viz_textures, read_viz_textures + +############################################################################## +# Create a scene to start. + +scene = window.Scene() + +############################################################################## +# Load an image (png, bmp, jpeg or jpg) using ``io.load_image``. In this +# example, we will use ``read_viz_textures`` to access an image of the +# Earth's surface from the fury Github after using ''fetch_viz_textures()'' +# to download the available textures. + +fetch_viz_textures() +filename = read_viz_textures('1_earth_8k.jpg') +image = io.load_image(filename) + +############################################################################## +# Next, use ``actor.texture_on_sphere`` to add a sphere with the texture from +# your loaded image to the already existing scene. +# To add a texture to your scene as visualized on a plane, use +# ``actor.texture`` instead. + +scene.add(actor.texture_on_sphere(image)) + +############################################################################## +# Lastly, record the scene, or set interactive to True if you would like to +# manipulate your new sphere. + +interactive = False +if interactive: + window.show(scene, size=(600, 600), reset_camera=False) +window.record(scene, size=(900, 768), out_path='viz_texture.png') diff --git a/v0.10.x/_downloads/4a6c68d172a47177e2e66c9bc5836ceb/viz_custom_interpolator.py b/v0.10.x/_downloads/4a6c68d172a47177e2e66c9bc5836ceb/viz_custom_interpolator.py new file mode 100644 index 000000000..067b45b80 --- /dev/null +++ b/v0.10.x/_downloads/4a6c68d172a47177e2e66c9bc5836ceb/viz_custom_interpolator.py @@ -0,0 +1,166 @@ +""" +============================ +Making a custom interpolator +============================ + +Keyframe animation using custom interpolator. +""" +import numpy as np + +from fury import actor, window +from fury.animation import Animation, helpers + +############################################################################### +# Implementing a custom interpolator +# =============================================== +# +# A keyframe interpolator function must return a function which take the time +# as an argument and returns a value. +# It's recommended to import `fury.animation.helpers`, which has some useful +# functions that would help to implement the interpolator. + +############################################################################### +# In glTF, animations using cubic spline interpolator needs at least two +# points, and each point has two tangent vectors. +# The interpolation equation for such data is in the glTF tutorials below: +# https://github.khronos.org/glTF-Tutorials/gltfTutorial/gltfTutorial_007_Animations.html#cubic-spline-interpolation +# +# Tangent based cubic spline interpolation function: +# +# >>> def cubicSpline(previousPoint, previousTangent, nextPoint, nextTangent, +# >>> interpolationValue): +# >>> t = interpolationValue +# >>> t2 = t * t +# >>> t3 = t2 * t +# >>> return (2 * t3 - 3 * t2 + 1) * previousPoint + +# >>> (t3 - 2 * t2 + t) * previousTangent + +# >>> (-2 * t3 + 3 * t2) * nextPoint + +# >>> (t3 - t2) * nextTangent +# +# First we create a function that must take a dict object that contains the +# animation keyframes when initialized as follows: +# +# >>> def tan_cubic_spline_interpolator(keyframes): +# >>> ... +# >>> def interpolate(t): +# >>> return interpolated_value +# >>> return interpolator +# +# Note: Also any other additional arguments are ok, see `spline_interpolator` +# Second step is to implement the `interpolate` closure that only takes the +# current time as input. + + +def tan_cubic_spline_interpolator(keyframes): + # First we must get ordered timestamps array: + timestamps = helpers.get_timestamps_from_keyframes(keyframes) + + # keyframes should be on the following form: + # { + # 1: {'value': ndarray, 'in_tangent': ndarray, 'out_tangent': ndarray}, + # 2: {'value': np.array([1, 2, 3], 'in_tangent': ndarray}, + # } + # See here, we might get incomplete data (out_tangent) in the second + # keyframe. In this case we need to have a default behaviour dealing + # with these missing data. + # Setting the tangent to a zero vector in this case is the best choice + for time in keyframes: + data = keyframes.get(time) + value = data.get('value') + if data.get('in_tangent') is None: + data['in_tangent'] = np.zeros_like(value) + if data.get('in_tangent') is None: + data['in_tangent'] = np.zeros_like(value) + + def interpolate(t): + # `get_previous_timestamp`and `get_next_timestamp` functions take + # timestamps array and current time as inputs and returns the + # surrounding timestamps. + t0 = helpers.get_previous_timestamp(timestamps, t) + t1 = helpers.get_next_timestamp(timestamps, t) + + # `get_time_tau` function takes current time and surrounding + # timestamps and returns a value from 0 to 1 + dt = helpers.get_time_tau(t, t0, t1) + + time_delta = t1 - t0 + + # to get a keyframe data at a specific timestamp, use + # `keyframes.get(t0)`. This keyframe data contains `value` and any + # other data set as a custom argument using keyframe setters. + # for example: + # >>> animation = Animation() + # >>> animation.set_position(0, np.array([1, 1, 1]), + # >>> custom_field=np.array([2, 3, 1])) + # In this case `keyframes.get(0)` would return: + # {'value': array(1, 1, 1), 'custom_field': array(2, 3, 1)} + # + # now we continue with the cubic spline equation. + p0 = keyframes.get(t0).get('value') + tan_0 = keyframes.get(t0).get('out_tangent') * time_delta + p1 = keyframes.get(t1).get('value') + tan_1 = keyframes.get(t1).get('in_tangent') * time_delta + # cubic spline equation using tangents + t2 = dt * dt + t3 = t2 * dt + return ( + (2 * t3 - 3 * t2 + 1) * p0 + + (t3 - 2 * t2 + dt) * tan_0 + + (-2 * t3 + 3 * t2) * p1 + + (t3 - t2) * tan_1 + ) + + return interpolate + + +scene = window.Scene() +showm = window.ShowManager( + scene, size=(900, 768), reset_camera=False, order_transparent=True +) + + +############################################################################### +# Cubic spline keyframes data same as the one you get from glTF file. +# =================================================================== + +# t in tangent position out tangent +translation = [ + [0.0, [0.0, 0.0, 0.0], [3.3051798, 6.640117, 0.0], [1.0, 0.0, 0.0]], + [1.0, [0.0, 0.0, 0.0], [3.3051798, 8.0, 0.0], [-1.0, 0.0, 0.0]], + [2.0, [-1.0, 0.0, 0.0], [3.3051798, 6.0, 0.0], [1.0, 0.0, 0.0]], + [3.0, [0.0, 0.0, 0.0], [3.3051798, 8.0, 0.0], [-1.0, 0.0, 0.0]], + [4.0, [0, -1.0, 0.0], [3.3051798, 6.0, 0.0], [0.0, 0.0, 0.0]], +] + +############################################################################### +# Initializing an ``Animation`` and adding sphere actor to it. +animation = Animation(motion_path_res=100) + +sphere = actor.sphere(np.array([[0, 0, 0]]), (1, 0, 1), radii=0.1) + +animation.add_actor(sphere) + +############################################################################### +# Setting position keyframes +# ========================== +for keyframe_data in translation: + t, in_tan, pos, out_tan = keyframe_data + # Since we used the name 'in_tangent' and 'out_tangent' in the interpolator + # We must use the same name as an argument to set it in the keyframe data. + animation.set_position(t, pos, in_tangent=in_tan, out_tangent=out_tan) + +############################################################################### +# Set the new interpolator to interpolate position keyframes +animation.set_position_interpolator(tan_cubic_spline_interpolator) + +############################################################################### +# adding the animation to the show manager. +showm.add_animation(animation) + + +interactive = False + +if interactive: + showm.start() + +window.record(scene, out_path='viz_keyframe_custom_interpolator.png', size=(900, 768)) diff --git a/v0.10.x/_downloads/4c208c4e684fa517d9857142424cd6c6/viz_gltf.ipynb b/v0.10.x/_downloads/4c208c4e684fa517d9857142424cd6c6/viz_gltf.ipynb new file mode 100644 index 000000000..b910c38c5 --- /dev/null +++ b/v0.10.x/_downloads/4c208c4e684fa517d9857142424cd6c6/viz_gltf.ipynb @@ -0,0 +1,133 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Visualizing a glTF file\nIn this tutorial, we will show how to display a glTF file in a scene.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "from fury import window\nfrom fury.data import fetch_gltf, read_viz_gltf\nfrom fury.gltf import glTF" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Create a scene.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "scene = window.Scene()\nscene.SetBackground(0.1, 0.1, 0.4)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Retrieving the gltf model.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "fetch_gltf('Duck', 'glTF')\nfilename = read_viz_gltf('Duck')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Initialize the glTF object and get actors using `actors` method.\nNote: You can always manually create actor from polydata, and apply texture\nor materials manually afterwards.\nExperimental: For smooth mesh/actor you can set `apply_normals=True`.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "gltf_obj = glTF(filename, apply_normals=False)\nactors = gltf_obj.actors()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Add all the actor from list of actors to the scene.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "scene.add(*actors)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Applying camera\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "cameras = gltf_obj.cameras\nif cameras:\n scene.SetActiveCamera(cameras[0])\n\ninteractive = False\n\nif interactive:\n window.show(scene, size=(1280, 720))\n\nwindow.record(scene, out_path='viz_gltf.png', size=(1280, 720))" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.8" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/v0.10.x/_downloads/4e53b22d1225ea833489e050bf68a366/viz_custom_interpolator.ipynb b/v0.10.x/_downloads/4e53b22d1225ea833489e050bf68a366/viz_custom_interpolator.ipynb new file mode 100644 index 000000000..5ceda7ade --- /dev/null +++ b/v0.10.x/_downloads/4e53b22d1225ea833489e050bf68a366/viz_custom_interpolator.ipynb @@ -0,0 +1,158 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Making a custom interpolator\n\nKeyframe animation using custom interpolator.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "import numpy as np\n\nfrom fury import actor, window\nfrom fury.animation import Animation, helpers" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Implementing a custom interpolator\n\nA keyframe interpolator function must return a function which take the time\nas an argument and returns a value.\nIt's recommended to import `fury.animation.helpers`, which has some useful\nfunctions that would help to implement the interpolator.\n\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In glTF, animations using cubic spline interpolator needs at least two\npoints, and each point has two tangent vectors.\nThe interpolation equation for such data is in the glTF tutorials below:\nhttps://github.khronos.org/glTF-Tutorials/gltfTutorial/gltfTutorial_007_Animations.html#cubic-spline-interpolation\n\nTangent based cubic spline interpolation function:\n\n>>> def cubicSpline(previousPoint, previousTangent, nextPoint, nextTangent,\n>>> interpolationValue):\n>>> t = interpolationValue\n>>> t2 = t * t\n>>> t3 = t2 * t\n>>> return (2 * t3 - 3 * t2 + 1) * previousPoint +\n>>> (t3 - 2 * t2 + t) * previousTangent +\n>>> (-2 * t3 + 3 * t2) * nextPoint +\n>>> (t3 - t2) * nextTangent\n\nFirst we create a function that must take a dict object that contains the\nanimation keyframes when initialized as follows:\n\n>>> def tan_cubic_spline_interpolator(keyframes):\n>>> ...\n>>> def interpolate(t):\n>>> return interpolated_value\n>>> return interpolator\n\nNote: Also any other additional arguments are ok, see `spline_interpolator`\nSecond step is to implement the `interpolate` closure that only takes the\ncurrent time as input.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def tan_cubic_spline_interpolator(keyframes):\n # First we must get ordered timestamps array:\n timestamps = helpers.get_timestamps_from_keyframes(keyframes)\n\n # keyframes should be on the following form:\n # {\n # 1: {'value': ndarray, 'in_tangent': ndarray, 'out_tangent': ndarray},\n # 2: {'value': np.array([1, 2, 3], 'in_tangent': ndarray},\n # }\n # See here, we might get incomplete data (out_tangent) in the second\n # keyframe. In this case we need to have a default behaviour dealing\n # with these missing data.\n # Setting the tangent to a zero vector in this case is the best choice\n for time in keyframes:\n data = keyframes.get(time)\n value = data.get('value')\n if data.get('in_tangent') is None:\n data['in_tangent'] = np.zeros_like(value)\n if data.get('in_tangent') is None:\n data['in_tangent'] = np.zeros_like(value)\n\n def interpolate(t):\n # `get_previous_timestamp`and `get_next_timestamp` functions take\n # timestamps array and current time as inputs and returns the\n # surrounding timestamps.\n t0 = helpers.get_previous_timestamp(timestamps, t)\n t1 = helpers.get_next_timestamp(timestamps, t)\n\n # `get_time_tau` function takes current time and surrounding\n # timestamps and returns a value from 0 to 1\n dt = helpers.get_time_tau(t, t0, t1)\n\n time_delta = t1 - t0\n\n # to get a keyframe data at a specific timestamp, use\n # `keyframes.get(t0)`. This keyframe data contains `value` and any\n # other data set as a custom argument using keyframe setters.\n # for example:\n # >>> animation = Animation()\n # >>> animation.set_position(0, np.array([1, 1, 1]),\n # >>> custom_field=np.array([2, 3, 1]))\n # In this case `keyframes.get(0)` would return:\n # {'value': array(1, 1, 1), 'custom_field': array(2, 3, 1)}\n #\n # now we continue with the cubic spline equation.\n p0 = keyframes.get(t0).get('value')\n tan_0 = keyframes.get(t0).get('out_tangent') * time_delta\n p1 = keyframes.get(t1).get('value')\n tan_1 = keyframes.get(t1).get('in_tangent') * time_delta\n # cubic spline equation using tangents\n t2 = dt * dt\n t3 = t2 * dt\n return (\n (2 * t3 - 3 * t2 + 1) * p0\n + (t3 - 2 * t2 + dt) * tan_0\n + (-2 * t3 + 3 * t2) * p1\n + (t3 - t2) * tan_1\n )\n\n return interpolate\n\n\nscene = window.Scene()\nshowm = window.ShowManager(\n scene, size=(900, 768), reset_camera=False, order_transparent=True\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Cubic spline keyframes data same as the one you get from glTF file.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# t in tangent position out tangent\ntranslation = [\n [0.0, [0.0, 0.0, 0.0], [3.3051798, 6.640117, 0.0], [1.0, 0.0, 0.0]],\n [1.0, [0.0, 0.0, 0.0], [3.3051798, 8.0, 0.0], [-1.0, 0.0, 0.0]],\n [2.0, [-1.0, 0.0, 0.0], [3.3051798, 6.0, 0.0], [1.0, 0.0, 0.0]],\n [3.0, [0.0, 0.0, 0.0], [3.3051798, 8.0, 0.0], [-1.0, 0.0, 0.0]],\n [4.0, [0, -1.0, 0.0], [3.3051798, 6.0, 0.0], [0.0, 0.0, 0.0]],\n]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Initializing an ``Animation`` and adding sphere actor to it.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "animation = Animation(motion_path_res=100)\n\nsphere = actor.sphere(np.array([[0, 0, 0]]), (1, 0, 1), radii=0.1)\n\nanimation.add_actor(sphere)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Setting position keyframes\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "for keyframe_data in translation:\n t, in_tan, pos, out_tan = keyframe_data\n # Since we used the name 'in_tangent' and 'out_tangent' in the interpolator\n # We must use the same name as an argument to set it in the keyframe data.\n animation.set_position(t, pos, in_tangent=in_tan, out_tangent=out_tan)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Set the new interpolator to interpolate position keyframes\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "animation.set_position_interpolator(tan_cubic_spline_interpolator)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "adding the animation to the show manager.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "showm.add_animation(animation)\n\n\ninteractive = False\n\nif interactive:\n showm.start()\n\nwindow.record(scene, out_path='viz_keyframe_custom_interpolator.png', size=(900, 768))" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.8" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/v0.10.x/_downloads/4f6296d5a4667d45e0c3b07ea0a64dfd/viz_brick_wall.ipynb b/v0.10.x/_downloads/4f6296d5a4667d45e0c3b07ea0a64dfd/viz_brick_wall.ipynb new file mode 100644 index 000000000..1fea8783d --- /dev/null +++ b/v0.10.x/_downloads/4f6296d5a4667d45e0c3b07ea0a64dfd/viz_brick_wall.ipynb @@ -0,0 +1,277 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Brick Wall Simulation\n\nThis example simulation shows how to use pybullet to render physics simulations\nin fury. In this example we specifically render a ball beign thrown at a brick\nwall.\n\nFirst some imports.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "import itertools\n\nimport numpy as np\nimport pybullet as p\n\nfrom fury import actor, ui, utils, window" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Next, we initialize a pybullet client to render the physics. We use `DIRECT`\nmode to initialize pybullet without a GUI.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "p.connect(p.DIRECT)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Apply gravity to the scene. In pybullet all values are in SI units.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "p.setGravity(0, 0, -10)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We define some global parameters so that its easier for us to tweak the\ntweak the simulation.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Ball Parameters\nball_radius = 0.3\nball_color = np.array([1, 0, 0])\nball_mass = 3\nball_position = np.array([2, 0, 1.5])\nball_orientation = np.array([0, 0, 0, 1])\n\n# Base Plane Parameters\nbase_size = np.array([5, 5, 0.2])\nbase_color = np.array([1, 1, 1])\nbase_position = np.array([0, 0, -0.1])\nbase_orientation = np.array([0, 0, 0, 1])\n\n# Wall Parameters\nwall_height = 10\nwall_width = 10\nbrick_mass = 0.5\nbrick_size = np.array([0.2, 0.4, 0.2])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we define the required parameters to render the Ball.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Ball actor\nball_actor = actor.sphere(\n centers=np.array([[0, 0, 0]]), colors=ball_color, radii=ball_radius\n)\n\n# Collision shape for the ball.\nball_coll = p.createCollisionShape(p.GEOM_SPHERE, radius=ball_radius)\n\n# Creating a multi-body which will be tracked by pybullet.\nball = p.createMultiBody(\n baseMass=3,\n baseCollisionShapeIndex=ball_coll,\n basePosition=ball_position,\n baseOrientation=ball_orientation,\n)\n\n# Change the dynamics of the ball by adding friction and restitution.\np.changeDynamics(ball, -1, lateralFriction=0.3, restitution=0.5)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Render a base plane to support the bricks.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "base_actor = actor.box(\n centers=np.array([[0, 0, 0]]),\n directions=[0, 0, 0],\n scales=base_size,\n colors=base_color,\n)\n\nbase_coll = p.createCollisionShape(p.GEOM_BOX, halfExtents=base_size / 2)\n# half of the actual size.\n\nbase = p.createMultiBody(\n baseCollisionShapeIndex=base_coll,\n basePosition=base_position,\n baseOrientation=base_orientation,\n)\n\np.changeDynamics(base, -1, lateralFriction=0.3, restitution=0.5)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we render the bricks. All the bricks are rendered by a single actor for\nbetter performance.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "nb_bricks = wall_height * wall_width\n\nbrick_centers = np.zeros((nb_bricks, 3))\n\nbrick_directions = np.zeros((nb_bricks, 3))\nbrick_directions[:] = np.array([1.57, 0, 0])\n\nbrick_orns = np.zeros((nb_bricks, 4))\n\nbrick_sizes = np.zeros((nb_bricks, 3))\nbrick_sizes[:] = brick_size\n\nbrick_colors = np.random.rand(nb_bricks, 3)\n\nbrick_coll = p.createCollisionShape(p.GEOM_BOX, halfExtents=brick_size / 2)\n\n# We use this array to store the reference of brick objects in pybullet world.\nbricks = np.zeros(nb_bricks, dtype=np.int8)\n\n# Logic to position the bricks appropriately to form a wall.\ni = 0\nfor k in range(wall_height):\n for j in range(wall_width):\n center_pos = np.array([-1, (j * 0.4) - 1.8, (0.2 * k) + 0.1])\n brick_centers[i] = center_pos\n brick_orns[i] = np.array([0, 0, 0, 1])\n bricks[i] = p.createMultiBody(\n baseMass=brick_mass,\n baseCollisionShapeIndex=brick_coll,\n basePosition=center_pos,\n baseOrientation=brick_orns[i],\n )\n p.changeDynamics(bricks[i], -1, lateralFriction=0.1, restitution=0.1)\n i += 1\n\nbrick_actor = actor.box(\n centers=brick_centers,\n directions=brick_directions,\n scales=brick_sizes,\n colors=brick_colors,\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now, we define a scene and add actors to it.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "scene = window.Scene()\nscene.add(actor.axes())\nscene.add(ball_actor)\nscene.add(base_actor)\nscene.add(brick_actor)\n\n# Create show manager.\nshowm = window.ShowManager(\n scene, size=(900, 768), reset_camera=False, order_transparent=True\n)\n\n\n# Counter iterator for tracking simulation steps.\ncounter = itertools.count()\n\n# Variable for tracking applied force.\napply_force = True" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now, we define methods to sync objects between fury and Pybullet.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Get the position of base and set it.\nbase_pos, _ = p.getBasePositionAndOrientation(base)\nbase_actor.SetPosition(*base_pos)\n\n# Do the same for ball.\nball_pos, _ = p.getBasePositionAndOrientation(ball)\nball_actor.SetPosition(*ball_pos)\n\n# Calculate the vertices of the bricks.\nvertices = utils.vertices_from_actor(brick_actor)\nnum_vertices = vertices.shape[0]\nnum_objects = brick_centers.shape[0]\nsec = int(num_vertices / num_objects)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Syncing Bricks\n\nHere, we perform three major steps to sync bricks accurately.\n* Get the position and orientation of the bricks from pybullet.\n* Calculate the Rotation Matrix.\n\n - Get the difference in orientations (Quaternion).\n - Generate the corresponding rotation matrix according to that difference.\n - Reshape it in a 3x3 matrix.\n\n* Perform calculations to get the required position and orientation.\n* Update the position and orientation.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def sync_brick(object_index, multibody):\n pos, orn = p.getBasePositionAndOrientation(multibody)\n\n rot_mat = np.reshape(\n p.getMatrixFromQuaternion(\n p.getDifferenceQuaternion(orn, brick_orns[object_index])\n ),\n (3, 3),\n )\n\n vertices[object_index * sec : object_index * sec + sec] = (\n vertices[object_index * sec : object_index * sec + sec]\n - brick_centers[object_index]\n ) @ rot_mat + pos\n\n brick_centers[object_index] = pos\n brick_orns[object_index] = orn" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "A simpler but inaccurate approach is used here to update the position and\norientation.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def sync_actor(actor, multibody):\n pos, orn = p.getBasePositionAndOrientation(multibody)\n actor.SetPosition(*pos)\n orn_deg = np.degrees(p.getEulerFromQuaternion(orn))\n actor.SetOrientation(*orn_deg)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Here, we define a textblock to display the Avg. FPS and simulation steps.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "fpss = np.array([])\ntb = ui.TextBlock2D(\n text='Avg. FPS: \\nSim Steps: ', position=(0, 680), font_size=30, color=(1, 0.5, 0)\n)\nscene.add(tb)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Set the camera for better visualization.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "scene.set_camera(\n position=(10.46, -8.13, 6.18),\n focal_point=(0.0, 0.0, 0.79),\n view_up=(-0.27, 0.26, 0.90),\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Timer callback is created which is responsible for calling the sync and\nsimulation methods.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Create timer callback which will execute at each step of simulation.\ndef timer_callback(_obj, _event):\n global apply_force, fpss\n cnt = next(counter)\n showm.render()\n\n if cnt % 1 == 0:\n fps = showm.frame_rate\n fpss = np.append(fpss, fps)\n tb.message = (\n 'Avg. FPS: ' + str(np.round(np.mean(fpss), 0)) + '\\nSim Steps: ' + str(cnt)\n )\n\n # Get the position and orientation of the ball.\n ball_pos, ball_orn = p.getBasePositionAndOrientation(ball)\n\n # Apply force for 5 times for the first step of simulation.\n if apply_force:\n # Apply the force.\n p.applyExternalForce(\n ball, -1, forceObj=[-10000, 0, 0], posObj=ball_pos, flags=p.WORLD_FRAME\n )\n apply_force = False\n\n # Set position and orientation of the ball.\n sync_actor(ball_actor, ball)\n\n # Updating the position and orientation of each individual brick.\n for idx, brick in enumerate(bricks):\n sync_brick(idx, brick)\n utils.update_actor(brick_actor)\n\n # Simulate a step.\n p.stepSimulation()\n\n # Exit after 2000 steps of simulation.\n if cnt == 130:\n showm.exit()\n\n\n# Add the timer callback to showmanager.\n# Increasing the duration value will slow down the simulation.\nshowm.add_timer_callback(True, 1, timer_callback)\n\ninteractive = False\n\n# start simulation\nif interactive:\n showm.start()\n\nwindow.record(scene, out_path='viz_brick_wall.png', size=(900, 768))" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.8" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/v0.10.x/_downloads/50d8940d1ce732009cff55c7ae40b100/viz_tesseract.py b/v0.10.x/_downloads/50d8940d1ce732009cff55c7ae40b100/viz_tesseract.py new file mode 100644 index 000000000..64ea04702 --- /dev/null +++ b/v0.10.x/_downloads/50d8940d1ce732009cff55c7ae40b100/viz_tesseract.py @@ -0,0 +1,189 @@ +""" +====================================================================== +Tesseract (Hypercube) +====================================================================== +A tesseract is a four-dimensional cube. A tesseract can +be unfolded into eight cubes, Just as a cube can be unfolded into eight +squares. +""" + +############################################################################### +# First, import some useful functions + +import itertools + +import numpy as np + +from fury import actor, utils, window +from fury.ui import TextBlock2D + +############################################################################### +# Let's define some variables and their descriptions: +# +# Use `wireframe = True` to show wireframe like representation of the tesseract +# `wireframe = False` will render it with point actor on each vertex. + +wireframe = False + +# p_color: color of the point actor (default: (0, 0.5, 1, 1)) +# e_color: color of the line actor (default: (1, 1, 1, 1)) +# dtheta: change in `angle` on each iteration. It determines the "speed" of the +# animation. Increase dtheta to increase speed of rotation, It may +# result in less smoother rotation (default: 0.02) +# angle: defines the angle to be rotated to perform the animation, It changes +# as we run the `callback` method later on. (initial value: 0) + +p_color = np.array([0, 0.5, 1, 1]) +e_color = np.array([1, 1, 1, 1]) +dtheta = 0.02 +angle = 0 + +############################################################################### +# Let's define vertices for our 4D cube, `verts4D` contains the coordinates of +# our 4D tesseract. + +verts3D = np.array( + [ + [1, 1, 1], + [1, -1, 1], + [-1, -1, 1], + [-1, 1, 1], + [-1, 1, -1], + [1, 1, -1], + [1, -1, -1], + [-1, -1, -1], + ] +) + +# We can use primitive.box alternatively to get the cube's 3-D vertices. + +u = np.insert(verts3D, 3, 1, axis=1) +v = np.insert(verts3D, 3, -1, axis=1) +verts4D = np.append(u, v, axis=0) + +############################################################################### +# We define a `rotate4D` function that takes 4D matrix as parameter and rotates +# it in XY plane (Z axis) and ZW plane (an imaginary axis), projects it to the +# 3D plane so that we can render it in a scene. + + +def rotate4D(verts4D): + cos = np.cos(angle) + sin = np.sin(angle) + rotation4d_xy = np.array( + [[cos, -sin, 0, 0], [sin, cos, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]] + ) + rotation4d_zw = np.array( + [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, cos, -sin], [0, 0, sin, cos]] + ) + distance = 2 + projected_marix = np.zeros((16, 3)) + for i, vert in enumerate(verts4D): + rotated_3D = np.dot(rotation4d_xy, vert) + rotated_3D = np.dot(rotation4d_zw, rotated_3D) + w = 1 / (distance - rotated_3D[3]) + proj_mat4D = np.array([[w, 0, 0, 0], [0, w, 0, 0], [0, 0, w, 0]]) + + projeced_mat3D = np.dot(proj_mat4D, rotated_3D) + projected_marix[i] = projeced_mat3D # vertices to be proj (3D) + return projected_marix + + +############################################################################### +# Now, We have 4D points projected to 3D. Let's define a function to connect +# lines. + + +def connect_points(verts3D): + lines = np.array([]) + len_vert = len(verts3D) + + for i in range(len_vert - 1): + if i < 8: + lines = np.append(lines, [verts3D[i], verts3D[i + 8]]) + if i == 7: + pass + else: + lines = np.append(lines, [verts3D[i], verts3D[i + 1]]) + if i % 4 == 0: + lines = np.append(lines, [verts3D[i], verts3D[i + 3]]) + + for i in range(3): + lines = np.append(lines, [verts3D[i], verts3D[i + 5]]) + lines = np.append(lines, [verts3D[i + 8], verts3D[i + 5 + 8]]) + + return np.reshape(lines, (-1, 2, 3)) + + +############################################################################### +# Creating a scene object and configuring the camera's position + +scene = window.Scene() +scene.set_camera( + position=(0, 10, -1), focal_point=(0.0, 0.0, 0.0), view_up=(0.0, 0.0, 0.0) +) +showm = window.ShowManager(scene, size=(1920, 1080), order_transparent=True) + + +############################################################################### +# Creating vertices and points actors + +verts3D = rotate4D(verts4D) +if not wireframe: + points = actor.point(verts3D, colors=p_color) + point_verts = utils.vertices_from_actor(points) + no_vertices = len(point_verts) / 16 + initial_verts = point_verts.copy() - np.repeat(verts3D, no_vertices, axis=0) + + scene.add(points) + +############################################################################### +# Connecting points with lines actor + +lines = connect_points(verts3D) +edges = actor.line(lines=lines, colors=e_color, lod=False, fake_tube=True, linewidth=4) +lines_verts = utils.vertices_from_actor(edges) +initial_lines = lines_verts.copy() - np.reshape(lines, (-1, 3)) + +scene.add(edges) + +############################################################################### +# Initializing text box to display the name + +tb = TextBlock2D(text='Tesseract', position=(900, 950), font_size=20) +showm.scene.add(tb) + +############################################################################### +# Define a timer_callback in which we'll update the vertices of point and lines +# actor using `rotate4D`. + +counter = itertools.count() +end = 200 + + +def timer_callback(_obj, _event): + global verts3D, angle + cnt = next(counter) + verts3D = rotate4D(verts4D) + if not wireframe: + point_verts[:] = initial_verts + np.repeat(verts3D, no_vertices, axis=0) + utils.update_actor(points) + + lines = connect_points(verts3D) + lines_verts[:] = initial_lines + np.reshape(lines, (-1, 3)) + utils.update_actor(edges) + + showm.render() + angle += dtheta + + if cnt == end: + showm.exit() + + +############################################################################### +# Run every 20 milliseconds + + +showm.add_timer_callback(True, 20, timer_callback) +showm.start() +window.record(showm.scene, size=(600, 600), out_path='viz_tesseract.png') diff --git a/v0.10.x/_downloads/519bcb86df2cb7c1998b6adfe2610479/viz_arrow.ipynb b/v0.10.x/_downloads/519bcb86df2cb7c1998b6adfe2610479/viz_arrow.ipynb new file mode 100644 index 000000000..beceb43b2 --- /dev/null +++ b/v0.10.x/_downloads/519bcb86df2cb7c1998b6adfe2610479/viz_arrow.ipynb @@ -0,0 +1,133 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Fury Arrow Actor\n\nThis example shows how to use the arrow actor.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "import numpy as np\n\nfrom fury import actor, window" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "First thing, you have to specify centers, directions, and colors of the\narrow(s)\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "centers = np.zeros([3, 3])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "np.identity is the same as specifying x, y, and z directions.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "dirs = np.identity(3)\ncolors = np.identity(3)\nscales = np.array([2.1, 2.6, 2.5])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The below arrow actor is generated by repeating the arrow primitive.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "arrow_actor = actor.arrow(centers, dirs, colors=colors, scales=1.5)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "repeating what we did but this time with random centers, directions, and\ncolors.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "cen2 = np.random.rand(5, 3)\ndir2 = np.random.rand(5, 3)\ncols2 = np.random.rand(5, 3)\n\narrow_actor2 = actor.arrow(cen2, dir2, colors=cols2, scales=1.5)\n\nscene = window.Scene()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Adding our Arrow actors to scene.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "scene.add(arrow_actor)\nscene.add(arrow_actor2)\n\ninteractive = False\n\nif interactive:\n window.show(scene, size=(600, 600))\n\nwindow.record(scene, out_path='viz_arrow.png', size=(600, 600))" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.8" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/v0.10.x/_downloads/5396abe89159c12e803367ea8e179107/viz_fine_tuning_gl_context.py b/v0.10.x/_downloads/5396abe89159c12e803367ea8e179107/viz_fine_tuning_gl_context.py new file mode 100644 index 000000000..8b3dec517 --- /dev/null +++ b/v0.10.x/_downloads/5396abe89159c12e803367ea8e179107/viz_fine_tuning_gl_context.py @@ -0,0 +1,153 @@ +""" +======================================================= +Fine-tuning the OpenGL state using shader callbacks +======================================================= + +Sometimes we need to get more control about how +OpenGL will render the actors. This example shows how to change the OpenGL +state of one or more actors. This can be useful when we need to create +specialized visualization effects. +""" + +############################################################################### +# First, let's import some functions + +import itertools + +import numpy as np + +from fury import actor, window +from fury.shaders import shader_apply_effects +from fury.utils import remove_observer_from_actor + +############################################################################### +# We just proceed as usual: creating the actors and initializing a scene in +# FURY + +centers = np.array([[0, 0, 0], [-0.1, 0, 0], [0.1, 0, 0]]) +colors = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]]) + +actor_no_depth_test = actor.markers( + centers, + marker='s', + colors=colors, + marker_opacity=0.5, + scales=0.2, +) +actor_normal_blending = actor.markers( + centers - np.array([[0, -0.5, 0]]), + marker='s', + colors=colors, + marker_opacity=0.5, + scales=0.2, +) +actor_add_blending = actor.markers( + centers - np.array([[0, -1, 0]]), + marker='s', + colors=colors, + marker_opacity=0.5, + scales=0.2, +) + +actor_sub_blending = actor.markers( + centers - np.array([[0, -1.5, 0]]), + marker='s', + colors=colors, + marker_opacity=0.5, + scales=0.2, +) +actor_mul_blending = actor.markers( + centers - np.array([[0, -2, 0]]), + marker='s', + colors=colors, + marker_opacity=0.5, + scales=0.2, +) + + +scene = window.Scene() + + +scene.background((0.5, 0.5, 0.5)) +showm = window.ShowManager( + scene, size=(900, 768), reset_camera=False, order_transparent=False +) + +############################################################################### +# All actors must be added in the scene + +scene.add(actor_no_depth_test) +scene.add(actor_normal_blending) +scene.add(actor_add_blending) +scene.add(actor_sub_blending) +scene.add(actor_mul_blending) +############################################################################### +# Now, we will enter in the topic of this example. First, we need to create +# (or use one of the pre-built gl_function of FURY) to +# change the OpenGL state of a given fury window instance (showm.window). +# +# Here we're using the pre-build FURY window functions which has already a +# set of specific behaviors to be applied in the OpenGL context + +shader_apply_effects( + showm.window, actor_normal_blending, effects=window.gl_set_normal_blending +) + +# ############################################################################### +# It's also possible use a list of effects. The final opengl state it'll +# be the composition of each effect that each function has in the opengl state + +id_observer = shader_apply_effects( + showm.window, + actor_no_depth_test, + effects=[window.gl_reset_blend, window.gl_disable_blend, window.gl_disable_depth], +) + +shader_apply_effects( + showm.window, + actor_add_blending, + effects=[ + window.gl_reset_blend, + window.gl_enable_depth, + window.gl_set_additive_blending, + ], +) + +shader_apply_effects( + showm.window, actor_sub_blending, effects=window.gl_set_subtractive_blending +) + +shader_apply_effects( + showm.window, actor_mul_blending, effects=window.gl_set_multiplicative_blending +) + +############################################################################### +# Finally, just render and see the results + + +counter = itertools.count() + +# After some steps we will remove the no_depth_test effect + + +def timer_callback(obj, event): + cnt = next(counter) + showm.render() + # we will rotate the visualization just to help you to see + # the results of each specific opengl-state + showm.scene.azimuth(1) + if cnt == 400: + remove_observer_from_actor(actor_no_depth_test, id_observer) + shader_apply_effects( + showm.window, actor_no_depth_test, effects=window.gl_set_additive_blending + ) + if cnt == 1000: + showm.exit() + + +interactive = False +showm.add_timer_callback(interactive, 5, timer_callback) +if interactive: + showm.start() + +window.record(scene, out_path='viz_fine_tuning_gl_context.png', size=(600, 600)) diff --git a/v0.10.x/_downloads/5628bd14c230cc10efd070d96a508073/viz_sdf_cylinder.ipynb b/v0.10.x/_downloads/5628bd14c230cc10efd070d96a508073/viz_sdf_cylinder.ipynb new file mode 100644 index 000000000..e359b178f --- /dev/null +++ b/v0.10.x/_downloads/5628bd14c230cc10efd070d96a508073/viz_sdf_cylinder.ipynb @@ -0,0 +1,399 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Make a Cylinder using polygons vs SDF\nThis tutorial is intended to show two ways of primitives creation with the use\nof polygons, and Signed Distance Functions (SDFs). We will use cylinders as an\nexample since they have a simpler polygonal representation. Hence, it allows us\nto see better the difference between using one or the other method.\n\nFor the cylinder representation with polygons, we will use cylinder actor\nimplementation on FURY, and for the visualization using SDFs, we will\nimplement shader code to create the cylinder and use a box actor to put our\nimplementation inside.\n\nWe start by importing the necessary modules:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "import os\n\nimport numpy as np\n\nfrom fury import actor, window\nfrom fury.shaders import (\n attribute_to_actor,\n compose_shader,\n import_fury_shader,\n shader_to_actor,\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Cylinder using polygons\nPolygons-based modeling, use smaller components namely triangles or polygons\nto represent 3D objects. Each polygon is defined by the position of its\nvertices and its connecting edges. In order to get a better representation\nof an object, it may be necessary to increase the number of polygons in the\nmodel, which is translated into the use of more space to store data and more\nrendering time to display the object.\n\nNow we define some properties of our actors, use them to create a set of\ncylinders, and add them to the scene.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "centers = np.array(\n [\n [-3.2, 0.9, 0.4],\n [-3.5, -0.5, 1],\n [-2.1, 0, 0.4],\n [-0.2, 0.9, 0.4],\n [-0.5, -0.5, 1],\n [0.9, 0, 0.4],\n [2.8, 0.9, 1.4],\n [2.5, -0.5, 2],\n [3.9, 0, 1.4],\n ]\n)\ndirs = np.array(\n [\n [-0.2, 0.9, 0.4],\n [-0.5, -0.5, 1],\n [0.9, 0, 0.4],\n [-0.2, 0.9, 0.4],\n [-0.5, -0.5, 1],\n [0.9, 0, 0.4],\n [-0.2, 0.9, 0.4],\n [-0.5, -0.5, 1],\n [0.9, 0, 0.4],\n ]\n)\ncolors = np.array(\n [\n [1, 0, 0],\n [1, 0, 0],\n [1, 0, 0],\n [0, 1, 0],\n [0, 1, 0],\n [0, 1, 0],\n [0, 0, 1],\n [0, 0, 1],\n [0, 0, 1],\n ]\n)\nradius = 0.5\nheight = 1" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In order to see how cylinders are made, we set different resolutions (number\nof sides used to define the bases of the cylinder) to see how it changes the\nsurface of the primitive.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "cylinders_8 = actor.cylinder(\n centers[:3],\n dirs[:3],\n colors[:3],\n radius=radius,\n heights=height,\n capped=True,\n resolution=8,\n)\ncylinders_16 = actor.cylinder(\n centers[3:6],\n dirs[3:6],\n colors[3:6],\n radius=radius,\n heights=height,\n capped=True,\n resolution=16,\n)\ncylinders_32 = actor.cylinder(\n centers[6:9],\n dirs[6:9],\n colors[6:9],\n radius=radius,\n heights=height,\n capped=True,\n resolution=32,\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Next, we set up a new scene to add and visualize the actors created.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "scene = window.Scene()\n\nscene.add(cylinders_8)\nscene.add(cylinders_16)\nscene.add(cylinders_32)\n\ninteractive = False\n\nif interactive:\n window.show(scene)\n\nwindow.record(scene, size=(600, 600), out_path='viz_poly_cylinder.png')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Visualize the surface geometry representation for the object.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "cylinders_8.GetProperty().SetRepresentationToWireframe()\ncylinders_16.GetProperty().SetRepresentationToWireframe()\ncylinders_32.GetProperty().SetRepresentationToWireframe()\n\nif interactive:\n window.show(scene)\n\nwindow.record(scene, size=(600, 600), out_path='viz_poly_cylinder_geom.png')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Then we clean the scene to render the boxes we will use to render our\nSDF-based actors.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "scene.clear()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Cylinder using SDF\nSigned Distance Functions are mathematical functions that take as input a\npoint in a metric space and return the distance from that point to the\nboundary of an object.\n\nWe will use the ray marching algorithm to render the SDF primitive using\nshaders. Ray marching is a technique where you step along a ray in order to\nfind intersections with solid geometry. Objects in the scene are defined by\nSDF, and because we don\u2019t use polygonal meshes it is possible to define\nperfectly smooth surfaces and allows a faster rendering in comparison to\npolygon-based modeling (more details in [Hart1996]_).\n\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we create cylinders using box actor and SDF implementation on shaders.\nFor this, we first create a box actor.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "box_actor = actor.box(\n centers=centers,\n directions=dirs,\n colors=colors,\n scales=(height, radius * 2, radius * 2),\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we use attribute_to_actor to link a NumPy array, with the centers and\ndirections data, with a vertex attribute. We do this to pass the data to\nthe vertex shader, with the corresponding attribute name.\n\nWe need to associate the data to each of the 8 vertices that make up the box\nsince we handle the processing of individual vertices in the vertex shader.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "rep_directions = np.repeat(dirs, 8, axis=0)\nrep_centers = np.repeat(centers, 8, axis=0)\nrep_radii = np.repeat(np.repeat(radius, 9), 8, axis=0)\nrep_heights = np.repeat(np.repeat(height, 9), 8, axis=0)\n\nattribute_to_actor(box_actor, rep_centers, 'center')\nattribute_to_actor(box_actor, rep_directions, 'direction')\nattribute_to_actor(box_actor, rep_radii, 'radius')\nattribute_to_actor(box_actor, rep_heights, 'height')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Then we have the shader code implementation corresponding to vertex and\nfragment shader. Here we are passing data to the fragment shader through\nthe vertex shader.\n\nVertex shaders perform basic processing of each individual vertex.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "vs_dec = \"\"\"\n in vec3 center;\n in vec3 direction;\n in float height;\n in float radius;\n\n out vec4 vertexMCVSOutput;\n out vec3 centerMCVSOutput;\n out vec3 directionVSOutput;\n out float heightVSOutput;\n out float radiusVSOutput;\n \"\"\"\n\nvs_impl = \"\"\"\n vertexMCVSOutput = vertexMC;\n centerMCVSOutput = center;\n directionVSOutput = direction;\n heightVSOutput = height;\n radiusVSOutput = radius;\n \"\"\"" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Then we add the vertex shader code to the box_actor. We use shader_to_actor\nto apply our implementation to the shader creation process, this function\njoins our code to the shader template that FURY has by default.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "shader_to_actor(box_actor, 'vertex', decl_code=vs_dec, impl_code=vs_impl)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Fragment shaders are used to define the colors of each pixel being processed,\nthe program runs on each of the pixels that the object occupies on the\nscreen.\n\nFragment shaders also allow us to have control over details of movement,\nlighting, and color in a scene. In this case, we are using vertex shader not\njust to define the colors of the cylinders but to manipulate its position in\nworld space, rotation with respect to the box, and lighting of the scene.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "fs_vars_dec = \"\"\"\n in vec4 vertexMCVSOutput;\n in vec3 centerMCVSOutput;\n in vec3 directionVSOutput;\n in float heightVSOutput;\n in float radiusVSOutput;\n\n uniform mat4 MCVCMatrix;\n \"\"\"" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We use this function to generate an appropriate rotation matrix which help us\nto transform our position vectors in order to align the direction of\ncylinder with respect to the box.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "vec_to_vec_rot_mat = import_fury_shader(\n os.path.join('utils', 'vec_to_vec_rot_mat.glsl')\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We calculate the distance using the SDF function for the cylinder.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "sd_cylinder = import_fury_shader(os.path.join('sdf', 'sd_cylinder.frag'))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This is used on calculations for surface normals of the cylinder.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "sdf_map = \"\"\"\n float map(in vec3 position)\n {\n // the sdCylinder function creates vertical cylinders by default, that\n // is the cylinder is created pointing in the up direction (0, 1, 0).\n // We want to rotate that vector to be aligned with the box's direction\n mat4 rot = vec2VecRotMat(normalize(directionVSOutput),\n normalize(vec3(0, 1, 0)));\n\n vec3 pos = (rot * vec4(position - centerMCVSOutput, 0.0)).xyz;\n\n // distance to the cylinder's boundary\n return sdCylinder(pos, radiusVSOutput, heightVSOutput / 2);\n }\n \"\"\"" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We use central differences technique for computing surface normals.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "central_diffs_normal = import_fury_shader(os.path.join('sdf', 'central_diffs.frag'))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We use cast_ray for the implementation of Ray Marching.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "cast_ray = import_fury_shader(os.path.join('ray_marching', 'cast_ray.frag'))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "For the illumination of the scene we use the Blinn-Phong model.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "blinn_phong_model = import_fury_shader(\n os.path.join('lighting', 'blinn_phong_model.frag')\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we use compose_shader to join our pieces of GLSL shader code.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "fs_dec = compose_shader(\n [\n fs_vars_dec,\n vec_to_vec_rot_mat,\n sd_cylinder,\n sdf_map,\n central_diffs_normal,\n cast_ray,\n blinn_phong_model,\n ]\n)\n\nshader_to_actor(box_actor, 'fragment', decl_code=fs_dec)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Here we have the implementation of all the previous code with all the\nnecessary variables and functions to build the cylinders.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "sdf_cylinder_frag_impl = \"\"\"\n vec3 point = vertexMCVSOutput.xyz;\n\n // ray origin\n vec4 ro = -MCVCMatrix[3] * MCVCMatrix; // camera position in world space\n\n // ray direction\n vec3 rd = normalize(point - ro.xyz);\n\n // light direction\n vec3 ld = normalize(ro.xyz - point);\n\n ro += vec4((point - ro.xyz), 0);\n\n float t = castRay(ro.xyz, rd);\n\n if(t < 20.0)\n {\n vec3 position = ro.xyz + t * rd;\n vec3 normal = centralDiffsNormals(position, .0001);\n float lightAttenuation = dot(ld, normal);\n vec3 color = blinnPhongIllumModel(\n lightAttenuation, lightColor0, diffuseColor,\n specularPower, specularColor, ambientColor);\n fragOutput0 = vec4(color, opacity);\n }\n else\n {\n discard;\n }\n \"\"\"\n\nshader_to_actor(box_actor, 'fragment', impl_code=sdf_cylinder_frag_impl, block='light')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Finally, we visualize the cylinders made using ray marching and SDFs.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "scene.add(box_actor)\n\nif interactive:\n window.show(scene)\n\nwindow.record(scene, size=(600, 600), out_path='viz_sdf_cylinder.png')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### References\n.. [Hart1996] Hart, John C. \"Sphere tracing: A geometric method for the\n antialiased ray tracing of implicit surfaces.\" The Visual\n Computer 12.10 (1996): 527-545.\n\n.. include:: ../links_names.inc\n\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.8" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/v0.10.x/_downloads/5c292f438915ad1fc458a15f186cea01/viz_arrow.py b/v0.10.x/_downloads/5c292f438915ad1fc458a15f186cea01/viz_arrow.py new file mode 100644 index 000000000..f65c6bf8e --- /dev/null +++ b/v0.10.x/_downloads/5c292f438915ad1fc458a15f186cea01/viz_arrow.py @@ -0,0 +1,53 @@ +""" +====================================================================== +Fury Arrow Actor +====================================================================== + +This example shows how to use the arrow actor. +""" + +import numpy as np + +from fury import actor, window + +############################################################################ +# First thing, you have to specify centers, directions, and colors of the +# arrow(s) + +centers = np.zeros([3, 3]) + +############################################################################ +# np.identity is the same as specifying x, y, and z directions. +dirs = np.identity(3) +colors = np.identity(3) +scales = np.array([2.1, 2.6, 2.5]) + +############################################################################ +# The below arrow actor is generated by repeating the arrow primitive. + +arrow_actor = actor.arrow(centers, dirs, colors=colors, scales=1.5) + +############################################################################ +# repeating what we did but this time with random centers, directions, and +# colors. + +cen2 = np.random.rand(5, 3) +dir2 = np.random.rand(5, 3) +cols2 = np.random.rand(5, 3) + +arrow_actor2 = actor.arrow(cen2, dir2, colors=cols2, scales=1.5) + +scene = window.Scene() + +############################################################################ +# Adding our Arrow actors to scene. + +scene.add(arrow_actor) +scene.add(arrow_actor2) + +interactive = False + +if interactive: + window.show(scene, size=(600, 600)) + +window.record(scene, out_path='viz_arrow.png', size=(600, 600)) diff --git a/v0.10.x/_downloads/5cd250c9f3b3f4ea2b64ca1198f2167c/viz_tesseract.ipynb b/v0.10.x/_downloads/5cd250c9f3b3f4ea2b64ca1198f2167c/viz_tesseract.ipynb new file mode 100644 index 000000000..a0371975c --- /dev/null +++ b/v0.10.x/_downloads/5cd250c9f3b3f4ea2b64ca1198f2167c/viz_tesseract.ipynb @@ -0,0 +1,230 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Tesseract (Hypercube)\nA tesseract is a four-dimensional cube. A tesseract can\nbe unfolded into eight cubes, Just as a cube can be unfolded into eight\nsquares.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "First, import some useful functions\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "import itertools\n\nimport numpy as np\n\nfrom fury import actor, utils, window\nfrom fury.ui import TextBlock2D" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's define some variables and their descriptions:\n\nUse `wireframe = True` to show wireframe like representation of the tesseract\n`wireframe = False` will render it with point actor on each vertex.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "wireframe = False\n\n# p_color: color of the point actor (default: (0, 0.5, 1, 1))\n# e_color: color of the line actor (default: (1, 1, 1, 1))\n# dtheta: change in `angle` on each iteration. It determines the \"speed\" of the\n# animation. Increase dtheta to increase speed of rotation, It may\n# result in less smoother rotation (default: 0.02)\n# angle: defines the angle to be rotated to perform the animation, It changes\n# as we run the `callback` method later on. (initial value: 0)\n\np_color = np.array([0, 0.5, 1, 1])\ne_color = np.array([1, 1, 1, 1])\ndtheta = 0.02\nangle = 0" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's define vertices for our 4D cube, `verts4D` contains the coordinates of\nour 4D tesseract.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "verts3D = np.array(\n [\n [1, 1, 1],\n [1, -1, 1],\n [-1, -1, 1],\n [-1, 1, 1],\n [-1, 1, -1],\n [1, 1, -1],\n [1, -1, -1],\n [-1, -1, -1],\n ]\n)\n\n# We can use primitive.box alternatively to get the cube's 3-D vertices.\n\nu = np.insert(verts3D, 3, 1, axis=1)\nv = np.insert(verts3D, 3, -1, axis=1)\nverts4D = np.append(u, v, axis=0)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We define a `rotate4D` function that takes 4D matrix as parameter and rotates\nit in XY plane (Z axis) and ZW plane (an imaginary axis), projects it to the\n3D plane so that we can render it in a scene.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def rotate4D(verts4D):\n cos = np.cos(angle)\n sin = np.sin(angle)\n rotation4d_xy = np.array(\n [[cos, -sin, 0, 0], [sin, cos, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]\n )\n rotation4d_zw = np.array(\n [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, cos, -sin], [0, 0, sin, cos]]\n )\n distance = 2\n projected_marix = np.zeros((16, 3))\n for i, vert in enumerate(verts4D):\n rotated_3D = np.dot(rotation4d_xy, vert)\n rotated_3D = np.dot(rotation4d_zw, rotated_3D)\n w = 1 / (distance - rotated_3D[3])\n proj_mat4D = np.array([[w, 0, 0, 0], [0, w, 0, 0], [0, 0, w, 0]])\n\n projeced_mat3D = np.dot(proj_mat4D, rotated_3D)\n projected_marix[i] = projeced_mat3D # vertices to be proj (3D)\n return projected_marix" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now, We have 4D points projected to 3D. Let's define a function to connect\nlines.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def connect_points(verts3D):\n lines = np.array([])\n len_vert = len(verts3D)\n\n for i in range(len_vert - 1):\n if i < 8:\n lines = np.append(lines, [verts3D[i], verts3D[i + 8]])\n if i == 7:\n pass\n else:\n lines = np.append(lines, [verts3D[i], verts3D[i + 1]])\n if i % 4 == 0:\n lines = np.append(lines, [verts3D[i], verts3D[i + 3]])\n\n for i in range(3):\n lines = np.append(lines, [verts3D[i], verts3D[i + 5]])\n lines = np.append(lines, [verts3D[i + 8], verts3D[i + 5 + 8]])\n\n return np.reshape(lines, (-1, 2, 3))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Creating a scene object and configuring the camera's position\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "scene = window.Scene()\nscene.set_camera(\n position=(0, 10, -1), focal_point=(0.0, 0.0, 0.0), view_up=(0.0, 0.0, 0.0)\n)\nshowm = window.ShowManager(scene, size=(1920, 1080), order_transparent=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Creating vertices and points actors\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "verts3D = rotate4D(verts4D)\nif not wireframe:\n points = actor.point(verts3D, colors=p_color)\n point_verts = utils.vertices_from_actor(points)\n no_vertices = len(point_verts) / 16\n initial_verts = point_verts.copy() - np.repeat(verts3D, no_vertices, axis=0)\n\n scene.add(points)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Connecting points with lines actor\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "lines = connect_points(verts3D)\nedges = actor.line(lines=lines, colors=e_color, lod=False, fake_tube=True, linewidth=4)\nlines_verts = utils.vertices_from_actor(edges)\ninitial_lines = lines_verts.copy() - np.reshape(lines, (-1, 3))\n\nscene.add(edges)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Initializing text box to display the name\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "tb = TextBlock2D(text='Tesseract', position=(900, 950), font_size=20)\nshowm.scene.add(tb)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Define a timer_callback in which we'll update the vertices of point and lines\nactor using `rotate4D`.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "counter = itertools.count()\nend = 200\n\n\ndef timer_callback(_obj, _event):\n global verts3D, angle\n cnt = next(counter)\n verts3D = rotate4D(verts4D)\n if not wireframe:\n point_verts[:] = initial_verts + np.repeat(verts3D, no_vertices, axis=0)\n utils.update_actor(points)\n\n lines = connect_points(verts3D)\n lines_verts[:] = initial_lines + np.reshape(lines, (-1, 3))\n utils.update_actor(edges)\n\n showm.render()\n angle += dtheta\n\n if cnt == end:\n showm.exit()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Run every 20 milliseconds\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "showm.add_timer_callback(True, 20, timer_callback)\nshowm.start()\nwindow.record(showm.scene, size=(600, 600), out_path='viz_tesseract.png')" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.8" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/v0.10.x/_downloads/5eb763eefc85684f957c4e42cf8b24bf/viz_advanced.ipynb b/v0.10.x/_downloads/5eb763eefc85684f957c4e42cf8b24bf/viz_advanced.ipynb new file mode 100644 index 000000000..74c511fec --- /dev/null +++ b/v0.10.x/_downloads/5eb763eefc85684f957c4e42cf8b24bf/viz_advanced.ipynb @@ -0,0 +1,331 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Advanced interactive visualization\n\nIn DIPY we created a thin interface to access many of the capabilities\navailable in the Visualization Toolkit framework (VTK) but tailored to the\nneeds of structural and diffusion imaging. Initially the 3D visualization\nmodule was named ``fvtk``, meaning functions using vtk. This is still available\nfor backwards compatibility but now there is a more comprehensive way to access\nthe main functions using the following modules.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "import numpy as np\nfrom dipy.data.fetcher import fetch_bundles_2_subjects, read_bundles_2_subjects" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In ``window`` we have all the objects that connect what needs to be rendered\nto the display or the disk e.g., for saving screenshots. So, there you will\nfind key objects and functions like the ``Scene`` class which holds and\nprovides access to all the actors and the ``show`` function which displays\nwhat is in the scene on a window. Also, this module provides access to\nfunctions for opening/saving dialogs and printing screenshots\n(see ``snapshot``).\n\nIn the ``actor`` module we can find all the different primitives e.g.,\nstreamtubes, lines, image slices, etc.\n\nIn the ``ui`` module we have some other objects which allow to add buttons\nand sliders and these interact both with windows and actors. Because of this\nthey need input from the operating system so they can process events.\n\nLet's get started. In this tutorial, we will visualize some bundles\ntogether with FA or T1. We will be able to change the slices using\na ``LineSlider2D`` widget.\n\nFirst we need to fetch and load some datasets.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "from dipy.tracking.streamline import Streamlines\n\nfrom fury import actor, ui, window\n\nfetch_bundles_2_subjects()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The following function outputs a dictionary with the required bundles e.g.\n``af left`` (left arcuate fasciculus) and maps, e.g. FA for a specific\nsubject.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "res = read_bundles_2_subjects('subj_1', ['t1', 'fa'], ['af.left', 'cst.right', 'cc_1'])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We will use 3 bundles, FA and the affine transformation that brings the voxel\ncoordinates to world coordinates (RAS 1mm).\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "streamlines = Streamlines(res['af.left'])\nstreamlines.extend(res['cst.right'])\nstreamlines.extend(res['cc_1'])\n\ndata = res['fa']\nshape = data.shape\naffine = res['affine']" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "With our current design it is easy to decide in which space you want the\nstreamlines and slices to appear. The default we have here is to appear in\nworld coordinates (RAS 1mm).\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "world_coords = True" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "If we want to see the objects in native space we need to make sure that all\nobjects which are currently in world coordinates are transformed back to\nnative space using the inverse of the affine.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "if not world_coords:\n from dipy.tracking.streamline import transform_streamlines\n\n streamlines = transform_streamlines(streamlines, np.linalg.inv(affine))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we create, a ``Scene`` object and add the streamlines using the\n``line`` function and an image plane using the ``slice`` function.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "scene = window.Scene()\nstream_actor = actor.line(streamlines)\n\nif not world_coords:\n image_actor_z = actor.slicer(data, affine=np.eye(4))\nelse:\n image_actor_z = actor.slicer(data, affine)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can also change also the opacity of the slicer.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "slicer_opacity = 0.6\nimage_actor_z.opacity(slicer_opacity)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can add additional slicers by copying the original and adjusting the\n``display_extent``.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "image_actor_x = image_actor_z.copy()\nx_midpoint = int(np.round(shape[0] / 2))\nimage_actor_x.display_extent(x_midpoint, x_midpoint, 0, shape[1] - 1, 0, shape[2] - 1)\n\nimage_actor_y = image_actor_z.copy()\ny_midpoint = int(np.round(shape[1] / 2))\nimage_actor_y.display_extent(0, shape[0] - 1, y_midpoint, y_midpoint, 0, shape[2] - 1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Connect the actors with the Scene.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "scene.add(stream_actor)\nscene.add(image_actor_z)\nscene.add(image_actor_x)\nscene.add(image_actor_y)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we would like to change the position of each ``image_actor`` using a\nslider. The sliders are widgets which require access to different areas of\nthe visualization pipeline and therefore we don't recommend using them with\n``show``. The more appropriate way is to use them with the ``ShowManager``\nobject which allows accessing the pipeline in different areas. Here is how:\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "show_m = window.ShowManager(scene, size=(1200, 900))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "After we have initialized the ``ShowManager`` we can go ahead and create\nsliders to move the slices and change their opacity.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "line_slider_z = ui.LineSlider2D(\n min_value=0,\n max_value=shape[2] - 1,\n initial_value=shape[2] / 2,\n text_template='{value:.0f}',\n length=140,\n)\n\nline_slider_x = ui.LineSlider2D(\n min_value=0,\n max_value=shape[0] - 1,\n initial_value=shape[0] / 2,\n text_template='{value:.0f}',\n length=140,\n)\n\nline_slider_y = ui.LineSlider2D(\n min_value=0,\n max_value=shape[1] - 1,\n initial_value=shape[1] / 2,\n text_template='{value:.0f}',\n length=140,\n)\n\nopacity_slider = ui.LineSlider2D(\n min_value=0.0, max_value=1.0, initial_value=slicer_opacity, length=140\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we will write callbacks for the sliders and register them.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def change_slice_z(slider):\n z = int(np.round(slider.value))\n image_actor_z.display_extent(0, shape[0] - 1, 0, shape[1] - 1, z, z)\n\n\ndef change_slice_x(slider):\n x = int(np.round(slider.value))\n image_actor_x.display_extent(x, x, 0, shape[1] - 1, 0, shape[2] - 1)\n\n\ndef change_slice_y(slider):\n y = int(np.round(slider.value))\n image_actor_y.display_extent(0, shape[0] - 1, y, y, 0, shape[2] - 1)\n\n\ndef change_opacity(slider):\n slicer_opacity = slider.value\n image_actor_z.opacity(slicer_opacity)\n image_actor_x.opacity(slicer_opacity)\n image_actor_y.opacity(slicer_opacity)\n\n\nline_slider_z.on_change = change_slice_z\nline_slider_x.on_change = change_slice_x\nline_slider_y.on_change = change_slice_y\nopacity_slider.on_change = change_opacity" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We'll also create text labels to identify the sliders.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def build_label(text):\n label = ui.TextBlock2D()\n label.message = text\n label.font_size = 18\n label.font_family = 'Arial'\n label.justification = 'left'\n label.bold = False\n label.italic = False\n label.shadow = False\n label.background_color = (0, 0, 0)\n label.color = (1, 1, 1)\n\n return label\n\n\nline_slider_label_z = build_label(text='Z Slice')\nline_slider_label_x = build_label(text='X Slice')\nline_slider_label_y = build_label(text='Y Slice')\nopacity_slider_label = build_label(text='Opacity')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we will create a ``panel`` to contain the sliders and labels.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "panel = ui.Panel2D(size=(300, 200), color=(1, 1, 1), opacity=0.1, align='right')\npanel.center = (1030, 120)\n\npanel.add_element(line_slider_label_x, (0.1, 0.75))\npanel.add_element(line_slider_x, (0.38, 0.75))\npanel.add_element(line_slider_label_y, (0.1, 0.55))\npanel.add_element(line_slider_y, (0.38, 0.55))\npanel.add_element(line_slider_label_z, (0.1, 0.35))\npanel.add_element(line_slider_z, (0.38, 0.35))\npanel.add_element(opacity_slider_label, (0.1, 0.15))\npanel.add_element(opacity_slider, (0.38, 0.15))\n\nshow_m.scene.add(panel)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Then, we can render all the widgets and everything else in the screen and\nstart the interaction using ``show_m.start()``.\n\n\nHowever, if you change the window size, the panel will not update its\nposition properly. The solution to this issue is to update the position of\nthe panel using its ``re_align`` method every time the window size changes.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "size = scene.GetSize()\n\n\ndef win_callback(obj, _event):\n global size\n if size != obj.GetSize():\n size_old = size\n size = obj.GetSize()\n size_change = [size[0] - size_old[0], 0]\n panel.re_align(size_change)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Finally, please set the following variable to ``True`` to interact with the\ndatasets in 3D.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "interactive = False\n\nscene.zoom(1.5)\nscene.reset_clipping_range()\n\nif interactive:\n\n show_m.add_window_callback(win_callback)\n show_m.render()\n show_m.start()\n\nelse:\n\n window.record(\n scene, out_path='bundles_and_3_slices.png', size=(1200, 900), reset_camera=False\n )\n\ndel show_m" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.8" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/v0.10.x/_downloads/5efd96037f0b528a5239a3eedeecde01/viz_solar_system.py b/v0.10.x/_downloads/5efd96037f0b528a5239a3eedeecde01/viz_solar_system.py new file mode 100644 index 000000000..185b044a3 --- /dev/null +++ b/v0.10.x/_downloads/5efd96037f0b528a5239a3eedeecde01/viz_solar_system.py @@ -0,0 +1,334 @@ +""" +======================= +Solar System Animation +======================= + +In this tutorial, we will create an animation of the solar system +using textured spheres. We will also show how to manipulate the +position of these sphere actors in a timer_callback function +to simulate orbital motion. +""" + +import itertools + +import numpy as np + +from fury import actor, io, ui, utils, window +from fury.data import fetch_viz_textures, read_viz_icons, read_viz_textures + +############################################################################## +# Create a scene to start. + +scene = window.Scene() + +# Create a panel and the start/pause buttons + +panel = ui.Panel2D(size=(300, 100), color=(1, 1, 1), align='right') +panel.center = (400, 50) + +pause_button = ui.Button2D(icon_fnames=[('square', read_viz_icons(fname='pause2.png'))]) +start_button = ui.Button2D(icon_fnames=[('square', read_viz_icons(fname='play3.png'))]) + +# Add the buttons on the panel + +panel.add_element(pause_button, (0.25, 0.33)) +panel.add_element(start_button, (0.66, 0.33)) + + +############################################################################## +# Define information relevant for each planet actor including its +# texture name, relative position, and scale. + +planets_data = [ + { + 'filename': '8k_mercury.jpg', + 'position': 7, + 'earth_days': 58, + 'scale': (0.4, 0.4, 0.4), + }, + { + 'filename': '8k_venus_surface.jpg', + 'position': 9, + 'earth_days': 243, + 'scale': (0.6, 0.6, 0.6), + }, + { + 'filename': '1_earth_8k.jpg', + 'position': 11, + 'earth_days': 1, + 'scale': (0.4, 0.4, 0.4), + }, + { + 'filename': '8k_mars.jpg', + 'position': 13, + 'earth_days': 1, + 'scale': (0.8, 0.8, 0.8), + }, + {'filename': 'jupiter.jpg', 'position': 16, 'earth_days': 0.41, 'scale': (2, 2, 2)}, + { + 'filename': '8k_saturn.jpg', + 'position': 19, + 'earth_days': 0.45, + 'scale': (2, 2, 2), + }, + { + 'filename': '8k_saturn_ring_alpha.png', + 'position': 19, + 'earth_days': 0.45, + 'scale': (3, 0.5, 3), + }, + { + 'filename': '2k_uranus.jpg', + 'position': 22, + 'earth_days': 0.70, + 'scale': (1, 1, 1), + }, + { + 'filename': '2k_neptune.jpg', + 'position': 25, + 'earth_days': 0.70, + 'scale': (1, 1, 1), + }, + {'filename': '8k_sun.jpg', 'position': 0, 'earth_days': 27, 'scale': (5, 5, 5)}, +] +fetch_viz_textures() + +############################################################################## +# To take advantage of the previously defined data structure we are going to +# create an auxiliary function that will load and apply the respective +# texture, set its respective properties (relative position and scale), +# and add the actor to a previously created scene. + + +def init_planet(planet_data): + """Initialize a planet actor. + + Parameters + ---------- + planet_data : dict + The planet_data is a dictionary, and the keys are filename(texture), + position and scale. + + Returns + ------- + planet_actor: actor + The corresponding sphere actor with texture applied. + """ + planet_file = read_viz_textures(planet_data['filename']) + planet_image = io.load_image(planet_file) + planet_actor = actor.texture_on_sphere(planet_image) + planet_actor.SetPosition(planet_data['position'], 0, 0) + if planet_data['filename'] != '8k_saturn_ring_alpha.png': + utils.rotate(planet_actor, (90, 1, 0, 0)) + planet_actor.SetScale(planet_data['scale']) + scene.add(planet_actor) + return planet_actor + + +############################################################################## +# Use the ``map`` function to create actors for each of the texture files +# in the ``planet_files`` list. Then, assign each actor to its corresponding +# actor in the list. + +planet_actor_list = list(map(init_planet, planets_data)) + +mercury_actor = planet_actor_list[0] +venus_actor = planet_actor_list[1] +earth_actor = planet_actor_list[2] +mars_actor = planet_actor_list[3] +jupiter_actor = planet_actor_list[4] +saturn_actor = planet_actor_list[5] +saturn_rings_actor = planet_actor_list[6] +uranus_actor = planet_actor_list[7] +neptune_actor = planet_actor_list[8] +sun_actor = planet_actor_list[9] + + +############################################################################## +# Define the gravitational constant G, the orbital radii of each of the +# planets, and the central mass of the sun. The gravity and mass will be +# used to calculate the orbital position, so multiply these two together to +# create a new constant, which we will call miu. + +g_exponent = np.float_power(10, -11) +g_constant = 6.673 * g_exponent + +m_exponent = 1073741824 # np.power(10, 30) +m_constant = 1.989 * m_exponent + +miu = m_constant * g_constant + +############################################################################## +# Let's define two functions that will help us calculate the position of each +# planet as it orbits around the sun: ``get_orbit_period`` and +# ``get_orbital_position``, using the constant miu and the orbital radii +# of each planet. + + +def get_orbit_period(radius): + return 2 * np.pi * np.sqrt(np.power(radius, 3) / miu) + + +def get_orbital_position(radius, time): + orbit_period = get_orbit_period(radius) + x = radius * np.cos((-2 * np.pi * time) / orbit_period) + y = radius * np.sin((-2 * np.pi * time) / orbit_period) + return x, y + + +############################################################################## +# Let's define a function to rotate the planet actor axially, we'll be defining +# axis of each planet and angle by which it should be rotated using +# ``rotate_axial`` funtction + + +def rotate_axial(actor, time, radius): + axis = (0, radius, 0) + angle = 50 / time + utils.rotate(actor, (angle, axis[0], axis[1], axis[2])) + return angle + + +############################################################################## +# Let's change the camera position to visualize the planets better. + +scene.set_camera(position=(-20, 60, 100)) + +############################################################################## +# Next, create a ShowManager object. The ShowManager class is the interface +# between the scene, the window and the interactor. + +showm = window.ShowManager( + scene, size=(900, 768), reset_camera=False, order_transparent=True +) +scene.add(panel) + +############################################################################## +# Next, let's focus on creating the animation. +# We can determine the duration of animation with using the ``counter``. +# Use itertools to avoid global variables. + +counter = itertools.count() + +############################################################################## +# Define one new function to use in ``timer_callback`` to update the planet +# positions ``update_planet_position``. + + +def update_planet_position(r_planet, planet_actor, cnt): + pos_planet = get_orbital_position(r_planet, cnt) + planet_actor.SetPosition(pos_planet[0], 0, pos_planet[1]) + return pos_planet + + +############################################################################## +# ``calculate_path`` function is for calculating the path/orbit +# of every planet. + + +def calculate_path(r_planet, c): + planet_track = [ + [get_orbital_position(r_planet, i)[0], 0, get_orbital_position(r_planet, i)[1]] + for i in range(c) + ] + return planet_track + + +############################################################################## +# First we are making a list that will contain radius from `planets_data`. +# Here we are not taking the radius of orbit/path for sun and saturn ring. +# `planet_actors` will contain all the planet actors. +# `r_times` will contain time taken (in days) by the planets to rotate +# around itself. + +r_planets = [ + p_data['position'] + for p_data in planets_data + if 'sun' not in p_data['filename'] + if 'saturn_ring' not in p_data['filename'] +] + +planet_actors = [ + mercury_actor, + venus_actor, + earth_actor, + mars_actor, + jupiter_actor, + saturn_actor, + uranus_actor, + neptune_actor, +] + + +sun_data = { + 'actor': sun_actor, + 'position': planets_data[9]['position'], + 'earth_days': planets_data[9]['earth_days'], +} + +r_times = [p_data['earth_days'] for p_data in planets_data] + +############################################################################## +# Here we are calculating and updating the path/orbit before animation starts. + +planet_tracks = [calculate_path(rplanet, rplanet * 85) for rplanet in r_planets] + +############################################################################## +# This is for orbit visualization. We are using line actor for orbits. +# After creating an actor we add it to the scene. + +orbit_actor = actor.line(planet_tracks, colors=(1, 1, 1), linewidth=0.1) +scene.add(orbit_actor) + +############################################################################## +# Define the ``timer_callback`` function, which controls what events happen +# at certain times, using the counter. Update the position of each planet +# actor using ``update_planet_position,`` assigning the x and y values of +# each planet's position with the newly calculated ones. + + +def timer_callback(_obj, _event): + cnt = next(counter) + showm.render() + + # Rotating the sun actor + rotate_axial(sun_actor, sun_data['earth_days'], 1) + + for r_planet, p_actor, r_time in zip(r_planets, planet_actors, r_times): + # if the planet is saturn then we also need to update the position + # of its rings. + if p_actor == saturn_actor: + pos_saturn = update_planet_position(19, saturn_actor, cnt) + saturn_rings_actor.SetPosition(pos_saturn[0], 0, pos_saturn[1]) + else: + update_planet_position(r_planet, p_actor, cnt) + rotate_axial(p_actor, r_time, r_planet) + + if cnt == 2000: + showm.exit() + + +############################################################################## +# We add a callback to each button to perform some action. + + +def start_animation(i_ren, _obj, _button): + showm.add_timer_callback(True, 10, timer_callback) + + +def pause_animation(i_ren, _obj, _button): + showm.destroy_timers() + + +start_button.on_left_mouse_button_clicked = start_animation +pause_button.on_left_mouse_button_clicked = pause_animation + + +############################################################################## +# Watch the planets orbit the sun in your new animation! + + +showm.add_timer_callback(True, 10, timer_callback) +showm.start() + +window.record(showm.scene, size=(900, 768), out_path='viz_solar_system_animation.png') diff --git a/v0.10.x/_downloads/6029834e15834dbb021718f73b5f56ad/viz_shader.ipynb b/v0.10.x/_downloads/6029834e15834dbb021718f73b5f56ad/viz_shader.ipynb new file mode 100644 index 000000000..edf520718 --- /dev/null +++ b/v0.10.x/_downloads/6029834e15834dbb021718f73b5f56ad/viz_shader.ipynb @@ -0,0 +1,187 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Varying Color\n\nThis example shows how to use shaders to generate a shaded output. We will\ndemonstrate how to load polydata then use a custom shader calls to render\na custom shaded model.\nFirst, a bunch of imports.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "from fury import io, ui, utils, window\nfrom fury.data.fetcher import fetch_viz_models, read_viz_models\nfrom fury.shaders import add_shader_callback, shader_to_actor" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's download and load the model\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "fetch_viz_models()\nmodel = read_viz_models('utah.obj')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's start by loading the polydata of choice.\nFor this example we use the standard utah teapot model.\ncurrently supported formats include OBJ, VTK, FIB, PLY, STL and XML\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "utah = io.load_polydata(model)\nutah = utils.get_polymapper_from_polydata(utah)\nutah = utils.get_actor_from_polymapper(utah)\nmapper = utah.GetMapper()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To change the default shader we add a shader replacement.\nSpecify vertex shader using vtkShader.Vertex\nSpecify fragment shader using vtkShader.Fragment\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "vertex_shader_code_decl = \"\"\"\n out vec4 myVertexVC;\n \"\"\"\n\nvertex_shader_code_impl = \"\"\"\n myVertexVC = vertexMC;\n \"\"\"\n\nfragment_shader_code_decl = \"\"\"\n uniform float time;\n varying vec4 myVertexVC;\n \"\"\"\n\nfragment_shader_code_impl = \"\"\"\n vec2 iResolution = vec2(1024,720);\n vec2 uv = myVertexVC.xy/iResolution;\n vec3 col = 0.5 + 0.5 * cos((time/30) + uv.xyx + vec3(0, 2, 4));\n fragOutput0 = vec4(col, fragOutput0.a);\n \"\"\"\n\nshader_to_actor(\n utah, 'vertex', impl_code=vertex_shader_code_impl, decl_code=vertex_shader_code_decl\n)\nshader_to_actor(utah, 'fragment', decl_code=fragment_shader_code_decl)\nshader_to_actor(utah, 'fragment', impl_code=fragment_shader_code_impl, block='light')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's create a scene.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "scene = window.Scene()\n\nglobal timer\ntimer = 0" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The timer will call this user defined callback every 30 milliseconds.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def timer_callback(obj, event):\n global timer\n timer += 1.0\n showm.render()\n scene.azimuth(5)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The shader callback will update the color of our utah pot via the update of\nthe timer variable.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def shader_callback(_caller, _event, calldata=None):\n program = calldata\n global timer\n if program is not None:\n try:\n program.SetUniformf('time', timer)\n except ValueError:\n pass\n\n\nadd_shader_callback(utah, shader_callback)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's add a textblock to the scene with a custom message\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "tb = ui.TextBlock2D()\ntb.message = 'Hello Shaders'" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Show Manager\n\nNow that all the elements have been initialised, we add them to the show\nmanager.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "current_size = (1024, 720)\nshowm = window.ShowManager(scene, size=current_size, reset_camera=False)\n\n\nshowm.add_timer_callback(True, 30, timer_callback)\n\nscene.add(utah)\nscene.add(tb)\n\ninteractive = False\nif interactive:\n showm.start()\n\nwindow.record(showm.scene, size=current_size, out_path='viz_shader.png')" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.8" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/v0.10.x/_downloads/6134a4d0d19a0e9efb6d00b24e096877/viz_card.py b/v0.10.x/_downloads/6134a4d0d19a0e9efb6d00b24e096877/viz_card.py new file mode 100644 index 000000000..61dbb5834 --- /dev/null +++ b/v0.10.x/_downloads/6134a4d0d19a0e9efb6d00b24e096877/viz_card.py @@ -0,0 +1,51 @@ +# -*- coding: utf-8 -*- +""" +==== +Card +==== + +This example shows how to create a card. + +First, some imports. +""" +from fury import ui, window +from fury.data import fetch_viz_icons + +############################################################################## +# First we need to fetch some icons that are included in FURY. + +fetch_viz_icons() + +############################################################################### +# Let's create a card and add it to the show manager + +img_url = "https://raw.githubusercontent.com/fury-gl"\ + "/fury-communication-assets/main/fury-logo.png" + +title = "FURY" +body = "FURY - Free Unified Rendering in pYthon."\ + "A software library for scientific visualization in Python." + +card = ui.elements.Card2D(image_path=img_url, title_text=title, + body_text=body, + image_scale=0.55, size=(300, 300), + bg_color=(1, 0.294, 0.180), + bg_opacity=0.8, border_width=5, + border_color=(0.1, 0.4, 0.4)) + +############################################################################### +# Now that the card has been initialised, we add it to the show +# manager. + +current_size = (1000, 1000) +show_manager = window.ShowManager(size=current_size, + title="FURY Card Example") + +show_manager.scene.add(card) +# To interact with the UI, set interactive = True +interactive = False + +if interactive: + show_manager.start() + +window.record(show_manager.scene, out_path="card_ui.png", size=(1000, 1000)) diff --git a/v0.10.x/_downloads/618515f9a1bb764be117d6b54207859a/viz_slice.py b/v0.10.x/_downloads/618515f9a1bb764be117d6b54207859a/viz_slice.py new file mode 100644 index 000000000..8a41b61b3 --- /dev/null +++ b/v0.10.x/_downloads/618515f9a1bb764be117d6b54207859a/viz_slice.py @@ -0,0 +1,263 @@ +""" +===================== +Simple volume slicing +===================== + +Here we present an example for visualizing slices from 3D images. +""" + +import os + +import nibabel as nib +from dipy.data import fetch_bundles_2_subjects + +from fury import actor, ui, window + +############################################################################### +# Let's download and load a T1. + +fetch_bundles_2_subjects() + +fname_t1 = os.path.join( + os.path.expanduser('~'), + '.dipy', + 'exp_bundles_and_maps', + 'bundles_2_subjects', + 'subj_1', + 't1_warped.nii.gz', +) + + +img = nib.load(fname_t1) +data = img.get_fdata() +affine = img.affine + +############################################################################### +# Create a Scene object which holds all the actors which we want to visualize. + +scene = window.Scene() +scene.background((0.5, 0.5, 0.5)) + +############################################################################### +# Render slices from T1 with a specific value range +# ================================================= +# +# The T1 has usually a higher range of values than what can be visualized in an +# image. We can set the range that we would like to see. + +mean, std = data[data > 0].mean(), data[data > 0].std() +value_range = (mean - 0.5 * std, mean + 1.5 * std) + +############################################################################### +# The ``slice`` function will read data and resample the data using an affine +# transformation matrix. The default behavior of this function is to show the +# middle slice of the last dimension of the resampled data. + +slice_actor = actor.slicer(data, affine, value_range) + +############################################################################### +# The ``slice_actor`` contains an axial slice. + +scene.add(slice_actor) + +############################################################################### +# The same actor can show any different slice from the given data using its +# ``display`` function. However, if we want to show multiple slices we need to +# copy the actor first. + +slice_actor2 = slice_actor.copy() + +############################################################################### +# Now we have a new ``slice_actor`` which displays the middle slice of sagittal +# plane. + +slice_actor2.display(slice_actor2.shape[0] // 2, None, None) + +scene.add(slice_actor2) + +scene.reset_camera() +scene.zoom(1.4) + +############################################################################### +# In order to interact with the data you will need to uncomment the line below. + +# window.show(scene, size=(600, 600), reset_camera=False) + +############################################################################### +# Otherwise, you can save a screenshot using the following command. + +window.record(scene, out_path='slices.png', size=(600, 600), reset_camera=False) + +############################################################################### +# Render slices from FA with your colormap +# ======================================== + +# It is also possible to set the colormap of your preference. Here we are +# loading an FA image and showing it in a non-standard way using an HSV +# colormap. + +fname_fa = os.path.join( + os.path.expanduser('~'), + '.dipy', + 'exp_bundles_and_maps', + 'bundles_2_subjects', + 'subj_1', + 'fa_1x1x1.nii.gz', +) + +img = nib.load(fname_fa) +fa = img.get_fdata() + +############################################################################### +# Notice here how the scale range is. We use FA min and max values to set it up + +lut = actor.colormap_lookup_table( + scale_range=(fa.min(), fa.max()), + hue_range=(0.4, 1.0), + saturation_range=(1, 1.0), + value_range=(0.0, 1.0), +) + +############################################################################### +# This is because the lookup table is applied in the slice after interpolating +# to (0, 255). + +fa_actor = actor.slicer(fa, affine, lookup_colormap=lut) + +scene.clear() +scene.add(fa_actor) + +scene.reset_camera() +scene.zoom(1.4) + +# window.show(scene, size=(600, 600), reset_camera=False) + +window.record(scene, out_path='slices_lut.png', size=(600, 600), reset_camera=False) + +############################################################################### +# Now we would like to add the ability to click on a voxel and show its value +# on a panel in the window. The panel is a UI element which requires access to +# different areas of the visualization pipeline and therefore we don't +# recommend using it with ``window.show``. The more appropriate way is to use +# the ``ShowManager`` object, which allows accessing the pipeline in different +# areas. + +show_m = window.ShowManager(scene, size=(1200, 900)) + + +############################################################################### +# We'll start by creating the panel and adding it to the ``ShowManager`` + +label_position = ui.TextBlock2D(text='Position:') +label_value = ui.TextBlock2D(text='Value:') + +result_position = ui.TextBlock2D(text='') +result_value = ui.TextBlock2D(text='') + +panel_picking = ui.Panel2D( + size=(250, 125), position=(20, 20), color=(0, 0, 0), opacity=0.75, align='left' +) + +panel_picking.add_element(label_position, (0.1, 0.55)) +panel_picking.add_element(label_value, (0.1, 0.25)) + +panel_picking.add_element(result_position, (0.45, 0.55)) +panel_picking.add_element(result_value, (0.45, 0.25)) + +show_m.scene.add(panel_picking) + +############################################################################## +# Add a left-click callback to the slicer. Also disable interpolation so you +# can see what you are picking. + + +def left_click_callback(obj, _ev): + """Get the value of the clicked voxel and show it in the panel.""" + event_pos = show_m.iren.GetEventPosition() + + obj.picker.Pick(event_pos[0], event_pos[1], 0, show_m.scene) + + i, j, k = obj.picker.GetPointIJK() + result_position.message = '({}, {}, {})'.format(str(i), str(j), str(k)) + result_value.message = '%.8f' % data[i, j, k] + + +fa_actor.SetInterpolate(False) +fa_actor.AddObserver('LeftButtonPressEvent', left_click_callback, 1.0) + +# show_m.start() + +############################################################################### +# Create a mosaic +# ================ +# +# By using the ``copy`` and ``display`` method of the ``slice_actor`` becomes +# easy and efficient to create a mosaic of all the slices. +# +# So, let's clear the scene and change the projection from perspective to +# parallel. We'll also need a new show manager and an associated callback. + +scene.clear() +scene.projection('parallel') + +result_position.message = '' +result_value.message = '' + +show_m_mosaic = window.ShowManager(scene, size=(1200, 900)) + + +def left_click_callback_mosaic(obj, _ev): + """Get the value of the clicked voxel and show it in the panel.""" + event_pos = show_m_mosaic.iren.GetEventPosition() + + obj.picker.Pick(event_pos[0], event_pos[1], 0, show_m_mosaic.scene) + + i, j, k = obj.picker.GetPointIJK() + result_position.message = '({}, {}, {})'.format(str(i), str(j), str(k)) + result_value.message = '%.8f' % data[i, j, k] + + +############################################################################### +# Now we need to create two nested for loops which will set the positions of +# the grid of the mosaic and add the new actors to the scene. We are going +# to use 15 columns and 10 rows but you can adjust those with your datasets. + +cnt = 0 + +X, Y, Z = slice_actor.shape[:3] + +rows = 10 +cols = 15 +border = 10 + +for j in range(rows): + for i in range(cols): + slice_mosaic = slice_actor.copy() + slice_mosaic.display(None, None, cnt) + slice_mosaic.SetPosition( + (X + border) * i, 0.5 * cols * (Y + border) - (Y + border) * j, 0 + ) + slice_mosaic.SetInterpolate(False) + slice_mosaic.AddObserver( + 'LeftButtonPressEvent', left_click_callback_mosaic, 1.0 + ) + scene.add(slice_mosaic) + cnt += 1 + if cnt > Z: + break + if cnt > Z: + break + +scene.reset_camera() +scene.zoom(1.0) + +# show_m_mosaic.scene.add(panel_picking) +# show_m_mosaic.start() + +############################################################################### +# If you uncomment the two lines above, you will be able to move +# the mosaic up/down and left/right using the middle mouse button drag, +# zoom in/out using the scroll wheel, and pick voxels with left click. + + +window.record(scene, out_path='mosaic.png', size=(900, 600), reset_camera=False) diff --git a/v0.10.x/_downloads/65de8bc78ef146e5712856a9fe0b2450/viz_emwave_animation.ipynb b/v0.10.x/_downloads/65de8bc78ef146e5712856a9fe0b2450/viz_emwave_animation.ipynb new file mode 100644 index 000000000..ed666a012 --- /dev/null +++ b/v0.10.x/_downloads/65de8bc78ef146e5712856a9fe0b2450/viz_emwave_animation.ipynb @@ -0,0 +1,241 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Electromagnetic Wave Propagation Animation\n\nA linearly polarized sinusoidal electromagnetic wave, propagating in the\ndirection +x through a homogeneous, isotropic, dissipationless medium,\nsuch as vacuum. The electric field (blue arrows) oscillates in the\n\u00b1z-direction, and the orthogonal magnetic field (red arrows) oscillates in\nphase with the electric field, but in the \u00b1y-direction.\n\nFunction of the sinusoid used in the animation = sin(k*x - w*t + d)\nWhere, k:wavenumber, x:abscissa, w:angular frequency, t:time, d:phase angle\n\nImporting necessary modules\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "import itertools\n\nimport numpy as np\n\nfrom fury import actor, ui, utils, window" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "function that updates and returns the coordinates of the waves which are\nchanging with time\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def update_coordinates(wavenumber, ang_frq, time, phase_angle):\n x = np.linspace(-3, 3, npoints)\n y = np.sin(wavenumber * x - ang_frq * time + phase_angle)\n z = np.array([0 for i in range(npoints)])\n return x, y, z" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Variable(s) and their description-\nnpoints: For high quality rendering, keep the number of npoints high\n but kindly note that higher values for npoints will slow down the\n rendering process (default = 800)\nwavelength : wavelength of the wave (default = 2)\nwavenumber : 2*pi/wavelength\ntime: time (default time i.e. time at beginning of the animation = 0)\nincre_time: value by which time is incremented for each call of\n timer_callback (default = 0.1)\nangular_frq: angular frequency (default = 0.1)\nphase_angle: phase angle (default = 0.002)\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "npoints = 800\nwavelength = 2\nwavenumber = 2 * np.pi / wavelength\ntime = 0\nincre_time = 0.1\nangular_frq = 0.1\nphase_angle = 0.002" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Creating a scene object and configuring the camera's position\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "scene = window.Scene()\nscene.set_camera(\n position=(-6, 5, -10), focal_point=(0.0, 0.0, 0.0), view_up=(0.0, 0.0, 0.0)\n)\nshowm = window.ShowManager(\n scene, size=(800, 600), reset_camera=True, order_transparent=True\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Creating a yellow colored arrow to show the direction of propagation of\nelectromagnetic wave\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "centers = np.array([[3, 0, 0]])\ndirections = np.array([[-1, 0, 0]])\nheights = np.array([6.4])\narrow_actor = actor.arrow(\n centers,\n directions,\n window.colors.yellow,\n heights,\n resolution=20,\n tip_length=0.06,\n tip_radius=0.012,\n shaft_radius=0.005,\n)\nscene.add(arrow_actor)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Creating point actor that renders the magnetic field\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "x = np.linspace(-3, 3, npoints)\ny = np.sin(wavenumber * x - angular_frq * time + phase_angle)\nz = np.array([0 for i in range(npoints)])\n\npts = np.array([(a, b, c) for (a, b, c) in zip(x, y, z)])\npts = [pts]\ncolors = window.colors.red\nwave_actor1 = actor.line(pts, colors, linewidth=3)\nscene.add(wave_actor1)\n\nvertices = utils.vertices_from_actor(wave_actor1)\nvcolors = utils.colors_from_actor(wave_actor1, 'colors')\nno_vertices_per_point = len(vertices) / npoints\ninitial_vertices = vertices.copy() - np.repeat(pts, no_vertices_per_point, axis=0)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Creating point actor that renders the electric field\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "xx = np.linspace(-3, 3, npoints)\nyy = np.array([0 for i in range(npoints)])\nzz = np.sin(wavenumber * xx - angular_frq * time + phase_angle)\n\npts2 = np.array([(a, b, c) for (a, b, c) in zip(xx, yy, zz)])\npts2 = [pts2]\ncolors2 = window.colors.blue\nwave_actor2 = actor.line(pts2, colors2, linewidth=3)\nscene.add(wave_actor2)\n\nvertices2 = utils.vertices_from_actor(wave_actor2)\nvcolors2 = utils.colors_from_actor(wave_actor2, 'colors')\nno_vertices_per_point2 = len(vertices2) / npoints\ninitial_vertices2 = vertices2.copy() - np.repeat(pts2, no_vertices_per_point2, axis=0)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Initializing text box to display the title of the animation\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "tb = ui.TextBlock2D(bold=True, position=(160, 90))\ntb.message = 'Electromagnetic Wave'\nscene.add(tb)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "end is used to decide when to end the animation\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "end = 300" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Initializing counter\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "counter = itertools.count()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Coordinates to be plotted are changed every time timer_callback is called by\nusing the update_coordinates function. The wave is rendered here.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def timer_callback(_obj, _event):\n global pts, pts2, time, time_incre, angular_frq, phase_angle, wavenumber\n time += incre_time\n cnt = next(counter)\n\n x, y, z = update_coordinates(wavenumber, angular_frq, phase_angle, time)\n pts = np.array([(a, b, c) for (a, b, c) in zip(x, y, z)])\n vertices[:] = initial_vertices + np.repeat(pts, no_vertices_per_point, axis=0)\n utils.update_actor(wave_actor1)\n\n xx, zz, yy = update_coordinates(wavenumber, angular_frq, phase_angle, time)\n pts2 = np.array([(a, b, c) for (a, b, c) in zip(xx, yy, zz)])\n vertices2[:] = initial_vertices2 + np.repeat(pts2, no_vertices_per_point2, axis=0)\n utils.update_actor(wave_actor2)\n\n showm.render()\n\n # to end the animation\n if cnt == end:\n showm.exit()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Run every 25 milliseconds\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "showm.add_timer_callback(True, 25, timer_callback)\n\ninteractive = False\nif interactive:\n showm.start()\nwindow.record(showm.scene, size=(800, 600), out_path='viz_emwave.png')" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.8" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/v0.10.x/_downloads/6beeb7a237877e054f039827371f2e22/viz_slice.ipynb b/v0.10.x/_downloads/6beeb7a237877e054f039827371f2e22/viz_slice.ipynb new file mode 100644 index 000000000..4949797be --- /dev/null +++ b/v0.10.x/_downloads/6beeb7a237877e054f039827371f2e22/viz_slice.ipynb @@ -0,0 +1,367 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Simple volume slicing\n\nHere we present an example for visualizing slices from 3D images.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "import os\n\nimport nibabel as nib\nfrom dipy.data import fetch_bundles_2_subjects\n\nfrom fury import actor, ui, window" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's download and load a T1.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "fetch_bundles_2_subjects()\n\nfname_t1 = os.path.join(\n os.path.expanduser('~'),\n '.dipy',\n 'exp_bundles_and_maps',\n 'bundles_2_subjects',\n 'subj_1',\n 't1_warped.nii.gz',\n)\n\n\nimg = nib.load(fname_t1)\ndata = img.get_fdata()\naffine = img.affine" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Create a Scene object which holds all the actors which we want to visualize.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "scene = window.Scene()\nscene.background((0.5, 0.5, 0.5))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Render slices from T1 with a specific value range\n\nThe T1 has usually a higher range of values than what can be visualized in an\nimage. We can set the range that we would like to see.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "mean, std = data[data > 0].mean(), data[data > 0].std()\nvalue_range = (mean - 0.5 * std, mean + 1.5 * std)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The ``slice`` function will read data and resample the data using an affine\ntransformation matrix. The default behavior of this function is to show the\nmiddle slice of the last dimension of the resampled data.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "slice_actor = actor.slicer(data, affine, value_range)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The ``slice_actor`` contains an axial slice.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "scene.add(slice_actor)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The same actor can show any different slice from the given data using its\n``display`` function. However, if we want to show multiple slices we need to\ncopy the actor first.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "slice_actor2 = slice_actor.copy()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we have a new ``slice_actor`` which displays the middle slice of sagittal\nplane.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "slice_actor2.display(slice_actor2.shape[0] // 2, None, None)\n\nscene.add(slice_actor2)\n\nscene.reset_camera()\nscene.zoom(1.4)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In order to interact with the data you will need to uncomment the line below.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# window.show(scene, size=(600, 600), reset_camera=False)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Otherwise, you can save a screenshot using the following command.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "window.record(scene, out_path='slices.png', size=(600, 600), reset_camera=False)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Render slices from FA with your colormap\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# It is also possible to set the colormap of your preference. Here we are\n# loading an FA image and showing it in a non-standard way using an HSV\n# colormap.\n\nfname_fa = os.path.join(\n os.path.expanduser('~'),\n '.dipy',\n 'exp_bundles_and_maps',\n 'bundles_2_subjects',\n 'subj_1',\n 'fa_1x1x1.nii.gz',\n)\n\nimg = nib.load(fname_fa)\nfa = img.get_fdata()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Notice here how the scale range is. We use FA min and max values to set it up\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "lut = actor.colormap_lookup_table(\n scale_range=(fa.min(), fa.max()),\n hue_range=(0.4, 1.0),\n saturation_range=(1, 1.0),\n value_range=(0.0, 1.0),\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This is because the lookup table is applied in the slice after interpolating\nto (0, 255).\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "fa_actor = actor.slicer(fa, affine, lookup_colormap=lut)\n\nscene.clear()\nscene.add(fa_actor)\n\nscene.reset_camera()\nscene.zoom(1.4)\n\n# window.show(scene, size=(600, 600), reset_camera=False)\n\nwindow.record(scene, out_path='slices_lut.png', size=(600, 600), reset_camera=False)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we would like to add the ability to click on a voxel and show its value\non a panel in the window. The panel is a UI element which requires access to\ndifferent areas of the visualization pipeline and therefore we don't\nrecommend using it with ``window.show``. The more appropriate way is to use\nthe ``ShowManager`` object, which allows accessing the pipeline in different\nareas.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "show_m = window.ShowManager(scene, size=(1200, 900))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We'll start by creating the panel and adding it to the ``ShowManager``\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "label_position = ui.TextBlock2D(text='Position:')\nlabel_value = ui.TextBlock2D(text='Value:')\n\nresult_position = ui.TextBlock2D(text='')\nresult_value = ui.TextBlock2D(text='')\n\npanel_picking = ui.Panel2D(\n size=(250, 125), position=(20, 20), color=(0, 0, 0), opacity=0.75, align='left'\n)\n\npanel_picking.add_element(label_position, (0.1, 0.55))\npanel_picking.add_element(label_value, (0.1, 0.25))\n\npanel_picking.add_element(result_position, (0.45, 0.55))\npanel_picking.add_element(result_value, (0.45, 0.25))\n\nshow_m.scene.add(panel_picking)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Add a left-click callback to the slicer. Also disable interpolation so you\ncan see what you are picking.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def left_click_callback(obj, _ev):\n \"\"\"Get the value of the clicked voxel and show it in the panel.\"\"\"\n event_pos = show_m.iren.GetEventPosition()\n\n obj.picker.Pick(event_pos[0], event_pos[1], 0, show_m.scene)\n\n i, j, k = obj.picker.GetPointIJK()\n result_position.message = '({}, {}, {})'.format(str(i), str(j), str(k))\n result_value.message = '%.8f' % data[i, j, k]\n\n\nfa_actor.SetInterpolate(False)\nfa_actor.AddObserver('LeftButtonPressEvent', left_click_callback, 1.0)\n\n# show_m.start()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create a mosaic\n\nBy using the ``copy`` and ``display`` method of the ``slice_actor`` becomes\neasy and efficient to create a mosaic of all the slices.\n\nSo, let's clear the scene and change the projection from perspective to\nparallel. We'll also need a new show manager and an associated callback.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "scene.clear()\nscene.projection('parallel')\n\nresult_position.message = ''\nresult_value.message = ''\n\nshow_m_mosaic = window.ShowManager(scene, size=(1200, 900))\n\n\ndef left_click_callback_mosaic(obj, _ev):\n \"\"\"Get the value of the clicked voxel and show it in the panel.\"\"\"\n event_pos = show_m_mosaic.iren.GetEventPosition()\n\n obj.picker.Pick(event_pos[0], event_pos[1], 0, show_m_mosaic.scene)\n\n i, j, k = obj.picker.GetPointIJK()\n result_position.message = '({}, {}, {})'.format(str(i), str(j), str(k))\n result_value.message = '%.8f' % data[i, j, k]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we need to create two nested for loops which will set the positions of\nthe grid of the mosaic and add the new actors to the scene. We are going\nto use 15 columns and 10 rows but you can adjust those with your datasets.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "cnt = 0\n\nX, Y, Z = slice_actor.shape[:3]\n\nrows = 10\ncols = 15\nborder = 10\n\nfor j in range(rows):\n for i in range(cols):\n slice_mosaic = slice_actor.copy()\n slice_mosaic.display(None, None, cnt)\n slice_mosaic.SetPosition(\n (X + border) * i, 0.5 * cols * (Y + border) - (Y + border) * j, 0\n )\n slice_mosaic.SetInterpolate(False)\n slice_mosaic.AddObserver(\n 'LeftButtonPressEvent', left_click_callback_mosaic, 1.0\n )\n scene.add(slice_mosaic)\n cnt += 1\n if cnt > Z:\n break\n if cnt > Z:\n break\n\nscene.reset_camera()\nscene.zoom(1.0)\n\n# show_m_mosaic.scene.add(panel_picking)\n# show_m_mosaic.start()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "If you uncomment the two lines above, you will be able to move\nthe mosaic up/down and left/right using the middle mouse button drag,\nzoom in/out using the scroll wheel, and pick voxels with left click.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "window.record(scene, out_path='mosaic.png', size=(900, 600), reset_camera=False)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.8" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/v0.10.x/_downloads/6c2daed92ac765c10464430a3aa60739/collision-particles.ipynb b/v0.10.x/_downloads/6c2daed92ac765c10464430a3aa60739/collision-particles.ipynb new file mode 100644 index 000000000..960a0e7b0 --- /dev/null +++ b/v0.10.x/_downloads/6c2daed92ac765c10464430a3aa60739/collision-particles.ipynb @@ -0,0 +1,122 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Collisions of particles in a box\n\nThis is a simple demonstration of how you can simulate moving\nparticles in a box using FURY.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In this example, the particles collide with each other and with the walls\nof the container. When the collision happens between two particles,\nthe particle with less velocity changes its color and gets the same color\nas the particle with higher velocity. For simplicity, in this demo we\ndo not apply forces.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "import itertools\n\nimport numpy as np\n\nfrom fury import actor, ui, utils, window" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Here, we define the edges of the box.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def box_edges(box_lx, box_ly, box_lz):\n\n edge1 = 0.5 * np.array(\n [\n [box_lx, box_ly, box_lz],\n [box_lx, box_ly, -box_lz],\n [-box_lx, box_ly, -box_lz],\n [-box_lx, box_ly, box_lz],\n [box_lx, box_ly, box_lz],\n ]\n )\n edge2 = 0.5 * np.array([[box_lx, box_ly, box_lz], [box_lx, -box_ly, box_lz]])\n edge3 = 0.5 * np.array([[box_lx, box_ly, -box_lz], [box_lx, -box_ly, -box_lz]])\n edge4 = 0.5 * np.array([[-box_lx, box_ly, -box_lz], [-box_lx, -box_ly, -box_lz]])\n edge5 = 0.5 * np.array([[-box_lx, box_ly, box_lz], [-box_lx, -box_ly, box_lz]])\n lines = [edge1, -edge1, edge2, edge3, edge4, edge5]\n return lines" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Here we define collision between walls-particles and particle-particle.\nWhen collision happens, the particle with lower velocity gets the\ncolor of the particle with higher velocity\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def collision():\n global xyz\n num_vertices = vertices.shape[0]\n sec = int(num_vertices / num_particles)\n\n for i, j in np.ndindex(num_particles, num_particles):\n\n if i == j:\n continue\n distance = np.linalg.norm(xyz[i] - xyz[j])\n vel_mag_i = np.linalg.norm(vel[i])\n vel_mag_j = np.linalg.norm(vel[j])\n # Collision happens if the distance between the centers of two\n # particles is less or equal to the sum of their radii\n if distance <= (radii[i] + radii[j]):\n vel[i] = -vel[i]\n vel[j] = -vel[j]\n if vel_mag_j > vel_mag_i:\n vcolors[i * sec : i * sec + sec] = vcolors[j * sec : j * sec + sec]\n if vel_mag_i > vel_mag_j:\n vcolors[j * sec : j * sec + sec] = vcolors[i * sec : i * sec + sec]\n xyz[i] = xyz[i] + vel[i] * dt\n xyz[j] = xyz[j] + vel[j] * dt\n # Collision between particles-walls;\n vel[:, 0] = np.where(\n (\n (xyz[:, 0] <= -0.5 * box_lx + radii[:])\n | (xyz[:, 0] >= (0.5 * box_lx - radii[:]))\n ),\n -vel[:, 0],\n vel[:, 0],\n )\n vel[:, 1] = np.where(\n (\n (xyz[:, 1] <= -0.5 * box_ly + radii[:])\n | (xyz[:, 1] >= (0.5 * box_ly - radii[:]))\n ),\n -vel[:, 1],\n vel[:, 1],\n )\n vel[:, 2] = np.where(\n (\n (xyz[:, 2] <= -0.5 * box_lz + radii[:])\n | (xyz[:, 2] >= (0.5 * box_lz - radii[:]))\n ),\n -vel[:, 2],\n vel[:, 2],\n )" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We define position, velocity, color and radius randomly for 50 particles\ninside the box.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "global xyz\nnum_particles = 50\nbox_lx = 20\nbox_ly = 20\nbox_lz = 10\nsteps = 1000\ndt = 0.05\nxyz = (\n np.array([box_lx, box_ly, box_lz]) * (np.random.rand(num_particles, 3) - 0.5) * 0.6\n)\nvel = 4 * (np.random.rand(num_particles, 3) - 0.5)\ncolors = np.random.rand(num_particles, 3)\nradii = np.random.rand(num_particles) + 0.01" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "With box, streamtube and sphere actors, we can create the box, the\nedges of the box and the spheres respectively.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "scene = window.Scene()\nbox_centers = np.array([[0, 0, 0]])\nbox_directions = np.array([[0, 1, 0]])\nbox_colors = np.array([[1, 1, 1, 0.2]])\nbox_actor = actor.box(\n box_centers, box_directions, box_colors, scales=(box_lx, box_ly, box_lz)\n)\nscene.add(box_actor)\n\nlines = box_edges(box_lx, box_ly, box_lz)\nline_actor = actor.streamtube(lines, colors=(1, 0.5, 0), linewidth=0.1)\nscene.add(line_actor)\n\nsphere_actor = actor.sphere(centers=xyz, colors=colors, radii=radii)\nscene.add(sphere_actor)\n\nshowm = window.ShowManager(\n scene, size=(900, 768), reset_camera=True, order_transparent=True\n)\n\ntb = ui.TextBlock2D(bold=True)\nscene.zoom(0.8)\nscene.azimuth(30)\n\n# use itertools to avoid global variables\ncounter = itertools.count()\n\nvertices = utils.vertices_from_actor(sphere_actor)\nvcolors = utils.colors_from_actor(sphere_actor, 'colors')\nno_vertices_per_sphere = len(vertices) / num_particles\ninitial_vertices = vertices.copy() - np.repeat(xyz, no_vertices_per_sphere, axis=0)\n\n\ndef timer_callback(_obj, _event):\n global xyz\n cnt = next(counter)\n tb.message = \"Let's count up to 1000 and exit :\" + str(cnt)\n xyz = xyz + vel * dt\n collision()\n\n vertices[:] = initial_vertices + np.repeat(xyz, no_vertices_per_sphere, axis=0)\n utils.update_actor(sphere_actor)\n\n scene.reset_clipping_range()\n showm.render()\n\n if cnt == steps:\n showm.exit()\n\n\nscene.add(tb)\nshowm.add_timer_callback(True, 50, timer_callback)\n\ninteractive = False\nif interactive:\n showm.start()\n\nwindow.record(showm.scene, size=(900, 768), out_path='simple_collisions.png')" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.8" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/v0.10.x/_downloads/6c96eb02c681c5d07657058bc1adec71/viz_network_animated.py b/v0.10.x/_downloads/6c96eb02c681c5d07657058bc1adec71/viz_network_animated.py new file mode 100644 index 000000000..cbdd5c179 --- /dev/null +++ b/v0.10.x/_downloads/6c96eb02c681c5d07657058bc1adec71/viz_network_animated.py @@ -0,0 +1,260 @@ +""" +======================================================= +Visualize Networks (Animated version) +======================================================= + +The goal of this demo is to show how to visualize a +complex network and use an force directed algorithm to +layout the network. A simpler animation of the network +made by adding some random displacements to nodes +positions is also demoed. +""" + +############################################################################### +# First, let's import some useful functions + +import math +from os.path import join as pjoin + +import numpy as np + +from fury import actor +from fury import colormap as cmap +from fury import window +from fury.utils import compute_bounds, update_actor, vertices_from_actor + +############################################################################### +# This demo has two modes. +# Use `mode = 0` to visualize a randomly generated geographic network by +# iterating it using a force-directed layout heuristic. +# +# Use `mode = 1` to visualize a large network being animated with random +# displacements +# + +mode = 0 + +############################################################################### +# Then let's download some available datasets. (mode 1) + +if mode == 1: + from fury.data.fetcher import fetch_viz_wiki_nw + + files, folder = fetch_viz_wiki_nw() + categories_file, edges_file, positions_file = sorted(files.keys()) + +############################################################################### +# We read our datasets (mode 1) + +if mode == 1: + positions = np.loadtxt(pjoin(folder, positions_file)) + categories = np.loadtxt(pjoin(folder, categories_file), dtype=str) + edges = np.loadtxt(pjoin(folder, edges_file), dtype=int) + vertices_count = len(positions) + +############################################################################### +# Generate a geographic random network, requires networkx package (mode 0) + +if mode == 0: + import networkx as nx + + vertices_count = 100 + view_size = 100 + network = nx.random_geometric_graph(vertices_count, 0.2) + positions = view_size * np.random.random((vertices_count, 3)) - view_size / 2.0 + categories = np.arange(0, vertices_count) + edges = np.array(network.edges()) + positions = view_size * np.random.random((vertices_count, 3)) - view_size / 2.0 + +############################################################################### +# We attribute a color to each category of our dataset which correspond to our +# nodes colors. + +category2index = {category: i for i, category in enumerate(np.unique(categories))} + +index2category = np.unique(categories) + +category_colors = cmap.distinguishable_colormap(nb_colors=len(index2category)) + +colors = np.array( + [category_colors[category2index[category]] for category in categories] +) + +############################################################################### +# We define our node size + +radii = 1 + np.random.rand(len(positions)) + +############################################################################### +# Let's create our edges now. They will indicate a citation between two nodes. +# The colors of each edge are interpolated between the two endpoints. + +edges_colors = [] +for source, target in edges: + edges_colors.append(np.array([colors[source], colors[target]])) + +edges_colors = np.average(np.array(edges_colors), axis=1) + +############################################################################### +# Our data preparation is ready, it is time to visualize them all. We start to +# build 2 actors that we represent our data : sphere_actor for the nodes and +# lines_actor for the edges. + +sphere_actor = actor.sphere( + centers=np.zeros(positions.shape), colors=colors, radii=radii * 0.5, theta=8, phi=8 +) + + +lines_actor = actor.line( + np.zeros((len(edges), 2, 3)), + colors=edges_colors, + lod=False, + fake_tube=True, + linewidth=3, +) + +############################################################################### +# Defining timer callback and layout iterator + + +def new_layout_timer( + showm, + edges_list, + vertices_count, + max_iterations=1000, + vertex_initial_positions=None, +): + view_size = 500 + viscosity = 0.10 + alpha = 0.5 + a = 0.0005 + b = 1.0 + deltaT = 1.0 + + sphere_geometry = np.array(vertices_from_actor(sphere_actor)) + geometry_length = sphere_geometry.shape[0] / vertices_count + + if vertex_initial_positions is not None: + pos = np.array(vertex_initial_positions) + else: + pos = view_size * np.random.random((vertices_count, 3)) - view_size / 2.0 + + velocities = np.zeros((vertices_count, 3)) + + def iterate(iterationCount): + nonlocal pos, velocities + for _ in range(iterationCount): + forces = np.zeros((vertices_count, 3)) + # repulstive forces + for vertex1 in range(vertices_count): + for vertex2 in range(vertex1): + x1, y1, z1 = pos[vertex1] + x2, y2, z2 = pos[vertex2] + distance = ( + math.sqrt( + (x2 - x1) * (x2 - x1) + + (y2 - y1) * (y2 - y1) + + (z2 - z1) * (z2 - z1) + ) + + alpha + ) + rx = (x2 - x1) / distance + ry = (y2 - y1) / distance + rz = (z2 - z1) / distance + Fx = -b * rx / distance / distance + Fy = -b * ry / distance / distance + Fz = -b * rz / distance / distance + forces[vertex1] += np.array([Fx, Fy, Fz]) + forces[vertex2] -= np.array([Fx, Fy, Fz]) + # attractive forces + for vFrom, vTo in edges_list: + if vFrom == vTo: + continue + x1, y1, z1 = pos[vFrom] + x2, y2, z2 = pos[vTo] + distance = math.sqrt( + (x2 - x1) * (x2 - x1) + + (y2 - y1) * (y2 - y1) + + (z2 - z1) * (z2 - z1) + ) + Rx = x2 - x1 + Ry = y2 - y1 + Rz = z2 - z1 + Fx = a * Rx * distance + Fy = a * Ry * distance + Fz = a * Rz * distance + forces[vFrom] += np.array([Fx, Fy, Fz]) + forces[vTo] -= np.array([Fx, Fy, Fz]) + velocities += forces * deltaT + velocities *= 1.0 - viscosity + pos += velocities * deltaT + pos[:, 0] -= np.mean(pos[:, 0]) + pos[:, 1] -= np.mean(pos[:, 1]) + pos[:, 2] -= np.mean(pos[:, 2]) + + counter = 0 + + def _timer(_obj, _event): + nonlocal counter, pos + counter += 1 + if mode == 0: + iterate(1) + else: + pos[:] += (np.random.random(pos.shape) - 0.5) * 1.5 + spheres_positions = vertices_from_actor(sphere_actor) + spheres_positions[:] = sphere_geometry + np.repeat(pos, geometry_length, axis=0) + + edges_positions = vertices_from_actor(lines_actor) + edges_positions[::2] = pos[edges_list[:, 0]] + edges_positions[1::2] = pos[edges_list[:, 1]] + + update_actor(lines_actor) + compute_bounds(lines_actor) + + update_actor(sphere_actor) + compute_bounds(lines_actor) + showm.scene.reset_clipping_range() + showm.render() + + if counter >= max_iterations: + showm.exit() + + return _timer + + +############################################################################### +# All actors need to be added in a scene, so we build one and add our +# lines_actor and sphere_actor. + + +scene = window.Scene() + +camera = scene.camera() + +scene.add(lines_actor) +scene.add(sphere_actor) + +############################################################################### +# The final step! Visualize the result of our creation! Also, we need to move +# the camera a little bit farther from the network. you can increase the +# parameter max_iteractions of the timer callback to let the animation run for +# more time. + +showm = window.ShowManager( + scene, reset_camera=False, size=(900, 768), order_transparent=True, multi_samples=8 +) + + +scene.set_camera(position=(0, 0, -300)) + +timer_callback = new_layout_timer( + showm, edges, vertices_count, max_iterations=200, vertex_initial_positions=positions +) + + +# Run every 16 milliseconds +showm.add_timer_callback(True, 16, timer_callback) + +showm.start() + +window.record(showm.scene, size=(900, 768), out_path='viz_animated_networks.png') diff --git a/v0.10.x/_downloads/6dee0175ad106d6bc47b567ecaf3bd7d/viz_interpolators.ipynb b/v0.10.x/_downloads/6dee0175ad106d6bc47b567ecaf3bd7d/viz_interpolators.ipynb new file mode 100644 index 000000000..0fa5f5598 --- /dev/null +++ b/v0.10.x/_downloads/6dee0175ad106d6bc47b567ecaf3bd7d/viz_interpolators.ipynb @@ -0,0 +1,269 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Keyframe animation\n\nMinimal tutorial of making keyframe-based animation in FURY.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## What is an ``Animation``\n\n``Animation`` is responsible for animating FURY actors using a set of\nkeyframes by interpolating values between timestamps of these keyframes.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "import numpy as np\n\nfrom fury import actor, window\nfrom fury.animation import Animation\nfrom fury.animation.interpolator import cubic_spline_interpolator\n\nkeyframes = {\n 1.0: {'value': np.array([0, 0, 0])},\n 2.0: {'value': np.array([-4, 1, 0])},\n 5.0: {'value': np.array([0, 0, 12])},\n 6.0: {'value': np.array([25, 0, 12])},\n}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Why keyframes data are also a dictionary ``{'value': np.array([0, 0, 0])})``?\n-> Since some keyframes data can only be defined by a set of data i.e. a\nsingle position keyframe could consist of a position, in control point, and\nout control point or any other data that helps to define this keyframe.\n\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## What are the interpolators\n\nThe keyframes interpolators are functions that takes a set of keyframes and\nreturns a function that calculates an interpolated value between these\nkeyframes.\nBelow there is an example on how to use interpolators manually to interpolate\nthe above defined ``keyframes``.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "interpolation_function = cubic_spline_interpolator(keyframes)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now, if we feed any time to this function it would return the cubic\ninterpolated position at that time.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "position = interpolation_function(1.44434)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "``position`` would contain an interpolated position at time equals 1.44434\n\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Creating the environment\n\nIn order to make any animations in FURY, a `ShowManager` is needed to handle\nupdating the animation and rendering the scene.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "scene = window.Scene()\n\nshowm = window.ShowManager(\n scene, size=(900, 768), reset_camera=False, order_transparent=True\n)\nshowm.initialize()\n\narrow = actor.arrow(np.array([[0, 0, 0]]), (0, 0, 0), (1, 0, 1), scales=6)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Creating an ``Animation``\n\nFirst step is creating the Animation.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "animation = Animation()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Adding the sphere actor to the timeline\nThis could've been done during initialization.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "animation.add_actor(arrow)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Setting position keyframes\n\nAdding some position keyframes\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "animation.set_position(0.0, np.array([0, 0, 0]))\nanimation.set_position(2.0, np.array([10, 10, 10]))\nanimation.set_position(5.0, np.array([-10, -3, -6]))\nanimation.set_position(9.0, np.array([10, 6, 20]))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Changing the default interpolator for a single property\n\nFor all properties except **rotation**, linear interpolator is used by\ndefault. In order to change the default interpolator and set another\ninterpolator, call ``animation.set__interpolator(interpolator)``\nFURY already has some interpolators located at:\n``fury.animation.interpolator``.\n\nBelow we set the interpolator for position keyframes to be\n**cubic spline interpolator**.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "animation.set_position_interpolator(cubic_spline_interpolator)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Adding some rotation keyframes.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "animation.set_rotation(0.0, np.array([160, 50, 0]))\nanimation.set_rotation(8.0, np.array([60, 160, 0]))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "For Rotation keyframes, Slerp is used as the default interpolator.\nWhat is Slerp?\nSlerp (spherical linear interpolation) of quaternions results in a constant\nspeed rotation in keyframe animation.\nReed more about Slerp: https://en.wikipedia.org/wiki/Slerp\n\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Setting camera position to see the animation better.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "scene.set_camera(position=(0, 0, 90))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Adding main animation to the ``ShowManager``.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "showm.add_animation(animation)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Start the ``ShowManager`` to start playing the animation\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "interactive = False\n\nif interactive:\n showm.start()\n\nwindow.record(scene, out_path='viz_keyframe_interpolator.png', size=(900, 768))" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.8" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/v0.10.x/_downloads/6f1e7a639e0699d6164445b55e6c116d/auto_examples_jupyter.zip b/v0.10.x/_downloads/6f1e7a639e0699d6164445b55e6c116d/auto_examples_jupyter.zip new file mode 100644 index 000000000..69ded4d8d Binary files /dev/null and b/v0.10.x/_downloads/6f1e7a639e0699d6164445b55e6c116d/auto_examples_jupyter.zip differ diff --git a/v0.10.x/_downloads/6f651295e5bc4bc569be5f51657eaee5/viz_tab.ipynb b/v0.10.x/_downloads/6f651295e5bc4bc569be5f51657eaee5/viz_tab.ipynb new file mode 100644 index 000000000..78b4ec670 --- /dev/null +++ b/v0.10.x/_downloads/6f651295e5bc4bc569be5f51657eaee5/viz_tab.ipynb @@ -0,0 +1,223 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Tab UI\n\nThis example shows how to use the Tab UI. We will demonstrate how to\ncreate Tabs for:\n\n1. Slider controls for a Cube\n2. Checkboxes for Cylinder and Sphere\n3. Color combobox for Fury.\n\nFirst, some imports.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "import numpy as np\n\nfrom fury import actor, ui, window\nfrom fury.data import fetch_viz_icons" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "First we need to fetch some icons that are included in FURY.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "fetch_viz_icons()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "First, we create the Tab UI.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "tab_ui = ui.TabUI(position=(49, 94), size=(300, 300), nb_tabs=3, draggable=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Slider Controls for a Cube for Tab Index 0\n\nNow we prepare content for the first tab.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "ring_slider = ui.RingSlider2D(initial_value=0, text_template='{angle:5.1f}\u00b0')\n\nline_slider_x = ui.LineSlider2D(\n initial_value=0,\n min_value=-10,\n max_value=10,\n orientation='horizontal',\n text_alignment='Top',\n)\n\nline_slider_y = ui.LineSlider2D(\n initial_value=0,\n min_value=-10,\n max_value=10,\n orientation='vertical',\n text_alignment='Right',\n)\n\ncube = actor.box(\n centers=np.array([[10, 0, 0]]),\n directions=np.array([[0, 1, 0]]),\n colors=np.array([[0, 0, 1]]),\n scales=np.array([[1, 1, 1]]),\n)\ncube_x = 0\ncube_y = 0\n\n\ndef rotate_cube(slider):\n angle = slider.value\n previous_angle = slider.previous_value\n rotation_angle = angle - previous_angle\n cube.RotateX(rotation_angle)\n\n\ndef translate_cube_x(slider):\n global cube_x, cube_y\n cube_x = slider.value\n cube.SetPosition(cube_x, cube_y, 0)\n\n\ndef translate_cube_y(slider):\n global cube_x, cube_y\n cube_y = slider.value\n cube.SetPosition(cube_x, cube_y, 0)\n\n\nring_slider.on_change = rotate_cube\nline_slider_x.on_change = translate_cube_x\nline_slider_y.on_change = translate_cube_y" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "After defining content, we define properties for the tab.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "tab_ui.tabs[0].title = 'Sliders'\ntab_ui.add_element(0, ring_slider, (0.3, 0.3))\ntab_ui.add_element(0, line_slider_x, (0.0, 0.0))\ntab_ui.add_element(0, line_slider_y, (0.0, 0.1))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## CheckBoxes For Cylinder and Sphere for Tab Index 1\n\nNow we prepare content for second tab.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "cylinder = actor.cylinder(\n centers=np.array([[0, 0, 0]]),\n directions=np.array([[1, 1, 0]]),\n colors=np.array([[0, 1, 1]]),\n radius=1.0,\n)\n\nsphere = actor.sphere(centers=np.array([[5, 0, 0]]), colors=(1, 1, 0))\n\nfigure_dict = {'cylinder': cylinder, 'sphere': sphere}\ncheckbox = ui.Checkbox(labels=['cylinder', 'sphere'])\n\n\n# Get difference between two lists.\ndef sym_diff(l1, l2):\n return list(set(l1).symmetric_difference(set(l2)))\n\n\n# Set Visibility of the figures\ndef set_figure_visiblity(checkboxes):\n checked = checkboxes.checked_labels\n unchecked = sym_diff(list(figure_dict), checked)\n\n for visible in checked:\n figure_dict[visible].SetVisibility(True)\n\n for invisible in unchecked:\n figure_dict[invisible].SetVisibility(False)\n\n\ncheckbox.on_change = set_figure_visiblity" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "After defining content, we define properties for the tab.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "tab_ui.tabs[1].title = 'Checkbox'\ntab_ui.add_element(1, checkbox, (0.2, 0.2))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Color Combobox for Fury for Tab Index 2\n\nNow we prepare content for third tab.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "label = ui.TextBlock2D(\n position=(600, 300),\n font_size=40,\n color=(1, 0.5, 0),\n justification='center',\n vertical_justification='top',\n text='FURY rocks!!!',\n)\n\ncolors = {\n 'Violet': (0.6, 0, 0.8),\n 'Indigo': (0.3, 0, 0.5),\n 'Blue': (0, 0, 1),\n 'Green': (0, 1, 0),\n 'Yellow': (1, 1, 0),\n 'Orange': (1, 0.5, 0),\n 'Red': (1, 0, 0),\n}\n\ncolor_combobox = ui.ComboBox2D(\n items=list(colors.keys()),\n placeholder='Choose Text Color',\n size=(250, 150),\n draggable=True,\n)\n\n\ndef change_color(combobox):\n label.color = colors[combobox.selected_text]\n\n\ncolor_combobox.on_change = change_color" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "After defining content, we define properties for the tab.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "tab_ui.tabs[2].title = 'Colors'\ntab_ui.add_element(2, color_combobox, (0.1, 0.3))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Define on_change & on_collapsed methods for tab ui to perform certain tasks\nwhile active tab is changed or when the tab is collapsed.\nNote: Tab UI can be collapsed by right clicking on it.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def hide_actors(tab_ui):\n if tab_ui.tabs[tab_ui.active_tab_idx].title == 'Sliders':\n cube.SetVisibility(True)\n cylinder.SetVisibility(False)\n sphere.SetVisibility(False)\n label.set_visibility(False)\n\n elif tab_ui.tabs[tab_ui.active_tab_idx].title == 'Checkbox':\n cube.SetVisibility(False)\n set_figure_visiblity(checkbox)\n label.set_visibility(False)\n\n else:\n cube.SetVisibility(False)\n cylinder.SetVisibility(False)\n sphere.SetVisibility(False)\n label.set_visibility(True)\n\n\ndef collapse(tab_ui):\n if tab_ui.collapsed:\n cube.SetVisibility(False)\n cylinder.SetVisibility(False)\n sphere.SetVisibility(False)\n label.set_visibility(False)\n\n\ntab_ui.on_change = hide_actors\ntab_ui.on_collapse = collapse" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Next we prepare the scene and render it with the help of show manager.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "sm = window.ShowManager(size=(800, 500), title='Viz Tab')\nsm.scene.add(tab_ui, cube, cylinder, sphere, label)\n\n# To interact with the ui set interactive = True\ninteractive = False\n\nif interactive:\n sm.start()\n\nwindow.record(sm.scene, size=(500, 500), out_path='viz_tab.png')" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.8" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/v0.10.x/_downloads/714d13c413f958429d90f34d3184ee5d/viz_layout.ipynb b/v0.10.x/_downloads/714d13c413f958429d90f34d3184ee5d/viz_layout.ipynb new file mode 100644 index 000000000..ab7b0facc --- /dev/null +++ b/v0.10.x/_downloads/714d13c413f958429d90f34d3184ee5d/viz_layout.ipynb @@ -0,0 +1,133 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Using Layouts with different UI elements\n\nThis example shows how to place different UI elements in different Layouts.\nThe Layouts used here is GridLayout (with different cell shapes).\n\nFirst, some imports.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "from fury import ui, window\nfrom fury.layout import GridLayout" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We create some panels and then we arrange them in a grid fashion\n\nFirst, we create some panels with different sizes/positions\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "panel_1 = ui.Panel2D(size=(200, 200), color=(0.4, 0.6, 0.3), position=(100, 100))\n\npanel_2 = ui.Panel2D(size=(250, 250), color=(0.8, 0.3, 0.5), position=(150, 150))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we create two listboxes\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "listbox_1 = ui.ListBox2D(size=(150, 150), values=['First', 'Second', 'Third'])\n\nlistbox_2 = ui.ListBox2D(size=(250, 250), values=['First', 'Second', 'Third'])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we create two different UI i.e. a slider and a listbox\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "slider = ui.LineSlider2D(length=150)\nlistbox = ui.ListBox2D(size=(150, 150), values=['First', 'Second', 'Third'])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now, we create grids with different shapes\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "rect_grid = GridLayout(position_offset=(0, 0, 0))\nsquare_grid = GridLayout(cell_shape='square', position_offset=(0, 300, 0))\ndiagonal_grid = GridLayout(cell_shape='diagonal', position_offset=(0, 600, 0))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Applying the grid to the ui elements\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "rect_grid.apply([panel_1, panel_2])\nsquare_grid.apply([listbox_1, listbox_2])\ndiagonal_grid.apply([slider, listbox])\n\ncurrent_size = (1500, 1500)\nshow_manager = window.ShowManager(size=current_size, title='FURY UI Layout')\n\nshow_manager.scene.add(panel_1, panel_2, listbox_1, listbox_2, slider, listbox)\n\n# To interact with the UI, set interactive = True\ninteractive = False\n\nif interactive:\n show_manager.start()\n\nwindow.record(show_manager.scene, out_path='ui_layout.png', size=(400, 400))" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.8" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/v0.10.x/_downloads/715e8e819426b94a79e2ba3da8e2a4a5/viz_fractals.ipynb b/v0.10.x/_downloads/715e8e819426b94a79e2ba3da8e2a4a5/viz_fractals.ipynb new file mode 100644 index 000000000..6c50f5d57 --- /dev/null +++ b/v0.10.x/_downloads/715e8e819426b94a79e2ba3da8e2a4a5/viz_fractals.ipynb @@ -0,0 +1,194 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Fractals\n\nFractals are geometric structures that are self-similar at any scale. These\nstructures are easy to generate using recursion. In this demo, we'll be\nimplementing the following fractals:\n\n- Sierpinski Tetrahedron or Tetrix\n- Menger Sponge\n- Moseley Snowflake\n\nLet's begin by importing some necessary modules. We need ``fury.primitive`` to\navoid having to hardcode the geometry of a tetrahedron and a cube.\n``fury.utils`` also contains a ``repeat_primitive`` function which we will use\nfor this demo.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "import math\n\nimport numpy as np\n\nfrom fury import primitive, ui, utils, window" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Before we create our first fractal, let's set some ground rules for us to\nwork with.\n\n1. Instead of creating a new actor to represent each primitive of the\nfractal, we will compute the centers of each primitive and draw them at once\nusing ``repeat_primitive()``.\n\n2. How many primitives do we need? For each fractal, we define a depth which\nwill prevent infinite recursion. Assuming we have a depth of $N$, and\nat each level the shape is divided into $k$ smaller parts, we will need\n$k^{N}$ primitives to represent the fractal.\n\n3. Ideally, we want to allocate the array of centers upfront. To achieve\nthis, we can use the method of representing a binary tree in an array, and\nextend it to work with k-ary trees (formulas for the same can be found\n`here`_). In this scheme of representation, we represent every primitive as a\nnode, and each sub-primitive as a child node. We can also skip storing the\nfirst $\\frac{k^{N} - 1}{k - 1} + 1$ entries as we only need to render\nthe leaf nodes. This allows us to create an array of exactly the required\nsize at the start, without any additional overhead.\n\n\n-----------------------------------------------------------------------------\n\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The tetrix is a classic 3d fractal, a natural three-dimensional extension of\nthe Sierpinski Triangle. At each level, we need to calculate the new centers\nfor the next level. We can use the vertices of a tetrahedron as the offsets\nfor the new centers, provided that the tetrahedron is centered at the origin\n(which is the case here).\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def tetrix(N):\n centers = np.zeros((4**N, 3))\n\n # skipping non-leaf nodes (see above)\n offset = (4**N - 1) // 3 + 1\n\n # just need the vertices\n U, _ = primitive.prim_tetrahedron()\n\n def gen_centers(depth, pos, center, dist):\n if depth == N:\n centers[pos - offset] = center\n else:\n idx = 4 * (pos - 1) + 2\n for i in range(4):\n # distance gets halved at each level\n gen_centers(depth + 1, idx + i, center + dist * U[i], dist / 2)\n\n # the division by sqrt(6) is to ensure correct scale\n gen_centers(0, 1, np.zeros(3), 2 / (6**0.5))\n\n vertices, faces = primitive.prim_tetrahedron()\n\n # primitive is scaled down depending on level\n vertices /= 2 ** (N - 1)\n\n # compute some pretty colors\n bounds_min, bounds_max = np.min(centers, axis=0), np.max(centers, axis=0)\n colors = (centers - bounds_min) / (bounds_max - bounds_min)\n\n vertices, triangles, colors, _ = primitive.repeat_primitive(\n centers=centers, colors=colors, vertices=vertices, faces=faces\n )\n return utils.get_actor_from_primitive(vertices, triangles, colors)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "For a Menger Sponge, each cube is divided into 27 smaller cubes, and we skip\nsome of them (face centers, and the center of the cube). This means that on\nevery level we get 20 new cubes.\n\nHere, to compute the points of each new center, we start at a corner cube's\ncenter and add the offsets to each smaller cube, scaled according to the\nlevel.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def sponge(N):\n centers = np.zeros((20**N, 3))\n offset = (20**N - 1) // 19 + 1\n\n # these are the offsets of the new centers at the next level of recursion\n # each cube is divided into 20 smaller cubes for a snowflake\n V = np.array(\n [\n [0, 0, 0],\n [0, 0, 1],\n [0, 0, 2],\n [0, 1, 0],\n [0, 1, 2],\n [0, 2, 0],\n [0, 2, 1],\n [0, 2, 2],\n [1, 0, 0],\n [1, 0, 2],\n [1, 2, 0],\n [1, 2, 2],\n [2, 0, 0],\n [2, 0, 1],\n [2, 0, 2],\n [2, 1, 0],\n [2, 1, 2],\n [2, 2, 0],\n [2, 2, 1],\n [2, 2, 2],\n ]\n )\n\n def gen_centers(depth, pos, center, dist):\n if depth == N:\n centers[pos - offset] = center\n else:\n # we consider a corner cube as our starting point\n start = center - np.array([1, 1, 1]) * dist**0.5\n idx = 20 * (pos - 1) + 2\n\n # this moves from the corner cube to each new cube's center\n for i in range(20):\n # each cube is divided into 27 cubes so side gets divided by 3\n gen_centers(depth + 1, idx + i, start + V[i] * dist, dist / 3)\n\n gen_centers(0, 1, np.zeros(3), 1 / 3)\n\n vertices, faces = primitive.prim_box()\n vertices /= 3**N\n\n bounds_min, bounds_max = np.min(centers, axis=0), np.max(centers, axis=0)\n colors = (centers - bounds_min) / (bounds_max - bounds_min)\n\n vertices, triangles, colors, _ = primitive.repeat_primitive(\n centers=centers, colors=colors, vertices=vertices, faces=faces\n )\n return utils.get_actor_from_primitive(vertices, triangles, colors)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "A snowflake is exactly the same as above, but we skip different cubes\n(corners and center). I think this looks quite interesting, and it is\npossible to see the Koch snowflake if you position the camera just right.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def snowflake(N):\n centers = np.zeros((18**N, 3))\n offset = (18**N - 1) // 17 + 1\n V = np.array(\n [\n [0, 0, 1],\n [0, 1, 0],\n [0, 1, 1],\n [0, 1, 2],\n [0, 2, 1],\n [1, 0, 0],\n [1, 0, 1],\n [1, 0, 2],\n [1, 1, 0],\n [1, 1, 2],\n [1, 2, 0],\n [1, 2, 1],\n [1, 2, 2],\n [2, 0, 1],\n [2, 1, 0],\n [2, 1, 1],\n [2, 1, 2],\n [2, 2, 1],\n ]\n )\n\n def gen_centers(depth, pos, center, side):\n if depth == N:\n centers[pos - offset] = center\n else:\n start = center - np.array([1, 1, 1]) * side**0.5\n idx = 18 * (pos - 1) + 2\n for i in range(18):\n gen_centers(depth + 1, idx + i, start + V[i] * side, side / 3)\n\n gen_centers(0, 1, np.zeros(3), 1 / 3)\n\n vertices, faces = primitive.prim_box()\n vertices /= 3**N\n\n bounds_min, bounds_max = np.min(centers, axis=0), np.max(centers, axis=0)\n colors = (centers - bounds_min) / (bounds_max - bounds_min)\n\n vertices, triangles, colors, _ = primitive.repeat_primitive(\n centers=centers, colors=colors, vertices=vertices, faces=faces\n )\n return utils.get_actor_from_primitive(vertices, triangles, colors)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now that we have the functions to generate fractals, we can start setting up\nthe Scene and ShowManager.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "scene = window.Scene()\nshowmgr = window.ShowManager(scene, 'Fractals', (800, 800), reset_camera=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "These values are what work nicely on my machine without lagging. If you have\na powerful machine, you could bump these up by around 2-3.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "fractals = [tetrix(6), sponge(3), snowflake(3)]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We want to be able to switch between the three fractals. To achieve this\nwe'll create a RadioButton and register a callback which will remove existing\nfractals and add the selected one. This also resets the camera.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "options = {\n 'Tetrix': 0,\n 'Sponge': 1,\n 'Snowflake': 2,\n}\n\nshape_chooser = ui.RadioButton(\n options.keys(),\n padding=10,\n font_size=16,\n checked_labels=['Tetrix'],\n position=(10, 10),\n)\n\n\ndef choose_shape(radio):\n showmgr.scene.rm(*fractals)\n showmgr.scene.add(fractals[options[radio.checked_labels[0]]])\n showmgr.scene.reset_camera()\n\n\nshape_chooser.on_change = choose_shape\n\n# selected at start\nshowmgr.scene.add(fractals[0])\nshowmgr.scene.add(shape_chooser)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's add some basic camera movement to make it look a little interesting.\nWe can use a callback here to update a counter and calculate the camera\npositions using the counter. ``sin`` and ``cos`` are used here to make smooth\nlooping movements.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "counter = 0\n\n\ndef timer_callback(_obj, _event):\n global counter\n counter += 1\n showmgr.scene.azimuth(math.sin(counter * 0.01))\n showmgr.scene.elevation(math.cos(counter * 0.01) / 4)\n showmgr.render()\n\n\nshowmgr.add_timer_callback(True, 20, timer_callback)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Finally, show the window if running in interactive mode or render to an image\notherwise. This is needed for generating the documentation that you are\nreading.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "interactive = False\nif interactive:\n showmgr.start()\nelse:\n window.record(showmgr.scene, out_path='fractals.png', size=(800, 800))" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.8" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/v0.10.x/_downloads/772d31df2ae71fa424c2d79524aea3b3/viz_drawpanel.ipynb b/v0.10.x/_downloads/772d31df2ae71fa424c2d79524aea3b3/viz_drawpanel.ipynb new file mode 100644 index 000000000..386ddd7b4 --- /dev/null +++ b/v0.10.x/_downloads/772d31df2ae71fa424c2d79524aea3b3/viz_drawpanel.ipynb @@ -0,0 +1,97 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# DrawPanel\n\nThis example shows how to use the DrawPanel UI. We will demonstrate how to\ncreate Various shapes and transform them.\n\nFirst, some imports.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "from fury import ui, window\nfrom fury.data import fetch_viz_new_icons" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "First we need to fetch some icons that are needed for DrawPanel.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "fetch_viz_new_icons()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We then create a DrawPanel Object.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "drawing_canvas = ui.DrawPanel(size=(560, 560), position=(40, 10))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Show Manager\n\nNow we add DrawPanel to the scene.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "current_size = (650, 650)\nshowm = window.ShowManager(size=current_size, title='DrawPanel UI Example')\n\nshowm.scene.add(drawing_canvas)\n\ninteractive = False\n\nif interactive:\n showm.start()\nelse:\n # If the UI isn't interactive, then adding a circle to the canvas\n drawing_canvas.current_mode = 'circle'\n drawing_canvas.draw_shape(shape_type='circle', current_position=(275, 275))\n drawing_canvas.shape_list[-1].resize((50, 50))\n\n window.record(showm.scene, size=current_size, out_path='viz_drawpanel.png')" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.8" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/v0.10.x/_downloads/7732fbac9f16a19e6cbe87842195f08d/viz_ball_collide.py b/v0.10.x/_downloads/7732fbac9f16a19e6cbe87842195f08d/viz_ball_collide.py new file mode 100644 index 000000000..517673a2e --- /dev/null +++ b/v0.10.x/_downloads/7732fbac9f16a19e6cbe87842195f08d/viz_ball_collide.py @@ -0,0 +1,140 @@ +""" +========================= +Ball Collision Simulation +========================= + +This example simulation shows how to use pybullet to render physics simulations +in fury. In this example we render the collision between a blue ball and red +ball and also display a message by confirming the collision. + +First some imports. +""" +import itertools + +import numpy as np +import pybullet as p + +from fury import actor, ui, window + +client = p.connect(p.DIRECT) + +############################################################################### +# Parameters and definition of red and blue balls. + +red_radius = 0.5 +blue_radius = 0.5 +duration = 50 + +# Red Ball +red_ball_actor = actor.sphere( + centers=np.array([[0, 0, 0]]), colors=np.array([[1, 0, 0]]), radii=red_radius +) + +red_ball_coll = p.createCollisionShape(p.GEOM_SPHERE, radius=red_radius) + +red_ball = p.createMultiBody( + baseMass=0.5, + baseCollisionShapeIndex=red_ball_coll, + basePosition=[10, 0, 0], + baseOrientation=[0, 0, 0, 1], +) + +# Blue ball +blue_ball_actor = actor.sphere( + centers=np.array([[0, 0, 0]]), colors=np.array([[0, 0, 1]]), radii=blue_radius +) + +blue_ball_coll = p.createCollisionShape(p.GEOM_SPHERE, radius=blue_radius) + +blue_ball = p.createMultiBody( + baseMass=0.5, + baseCollisionShapeIndex=blue_ball_coll, + basePosition=[-10, 0, 0], + baseOrientation=[0, 0, 0, 1], +) + +############################################################################### +# We set the coefficient of restitution of both the balls to `0.6`. + +p.changeDynamics(red_ball, -1, restitution=0.6) +p.changeDynamics(blue_ball, -1, restitution=0.6) + +############################################################################### +# We add all the actors to the scene. + +scene = window.Scene() +scene.add(actor.axes()) +scene.add(red_ball_actor) +scene.add(blue_ball_actor) + +showm = window.ShowManager( + scene, size=(900, 700), reset_camera=False, order_transparent=True +) + + +counter = itertools.count() + +############################################################################### +# Method to sync objects. + + +def sync_actor(actor, multibody): + pos, orn = p.getBasePositionAndOrientation(multibody) + actor.SetPosition(*pos) + orn_deg = np.degrees(p.getEulerFromQuaternion(orn)) + actor.SetOrientation(*orn_deg) + + +apply_force = True +tb = ui.TextBlock2D(position=(0, 600), font_size=30, color=(1, 0.5, 0), text='') +scene.add(tb) +scene.set_camera( + position=(0.30, -18.78, 0.89), focal_point=(0.15, 0.25, 0.40), view_up=(0, 0, 1.00) +) + + +############################################################################### +# Timer callback to sync and step simulation every second. + + +def timer_callback(_obj, _event): + global apply_force + cnt = next(counter) + showm.render() + red_pos, red_orn = p.getBasePositionAndOrientation(red_ball) + blue_pos, blue_orn = p.getBasePositionAndOrientation(blue_ball) + + # Apply force for the first step of the simulation. + if apply_force: + p.applyExternalForce( + red_ball, -1, forceObj=[-40000, 0, 0], posObj=red_pos, flags=p.WORLD_FRAME + ) + + p.applyExternalForce( + blue_ball, -1, forceObj=[40000, 0, 0], posObj=blue_pos, flags=p.WORLD_FRAME + ) + + apply_force = 0 + + sync_actor(blue_ball_actor, blue_ball) + sync_actor(red_ball_actor, red_ball) + + # Get various collision information using `p.getContactPoints`. + contact = p.getContactPoints(red_ball, blue_ball, -1, -1) + if len(contact) != 0: + tb.message = 'Collision!!' + + p.stepSimulation() + + if cnt == 50: + showm.exit() + + +showm.add_timer_callback(True, duration, timer_callback) + +interactive = False + +if interactive: + showm.start() + +window.record(scene, size=(900, 700), out_path='viz_ball_collide.png') diff --git a/v0.10.x/_downloads/773e34e8448bfc3cb6aa7fa1464ac1c6/viz_bundles.py b/v0.10.x/_downloads/773e34e8448bfc3cb6aa7fa1464ac1c6/viz_bundles.py new file mode 100644 index 000000000..147c1f70f --- /dev/null +++ b/v0.10.x/_downloads/773e34e8448bfc3cb6aa7fa1464ac1c6/viz_bundles.py @@ -0,0 +1,274 @@ +""" +======================================== +Visualize bundles and metrics on bundles +======================================== + +First, let's download some available datasets. Here we are using a dataset +which provides metrics and bundles. +""" + +import numpy as np +from dipy.data import fetch_bundles_2_subjects, read_bundles_2_subjects +from dipy.tracking.streamline import length, transform_streamlines + +from fury import actor, window + +interactive = False # set to True to show the interactive display window + +fetch_bundles_2_subjects() +dix = read_bundles_2_subjects( + subj_id='subj_1', metrics=['fa'], bundles=['cg.left', 'cst.right'] +) + +############################################################################### +# Store fractional anisotropy. + +fa = dix['fa'] + +############################################################################### +# Store grid to world transformation matrix. + +affine = dix['affine'] + +############################################################################### +# Store the cingulum bundle. A bundle is a list of streamlines. + +bundle = dix['cg.left'] + +############################################################################### +# It happened that this bundle is in world coordinates and therefore we need to +# transform it into native image coordinates so that it is in the same +# coordinate space as the ``fa`` image. + +bundle_native = transform_streamlines(bundle, np.linalg.inv(affine)) + +############################################################################### +# Show every streamline with an orientation color +# =============================================== +# +# This is the default option when you are using ``line`` or ``streamtube``. + +scene = window.Scene() + +stream_actor = actor.line(bundle_native) + +scene.set_camera( + position=(-176.42, 118.52, 128.20), + focal_point=(113.30, 128.31, 76.56), + view_up=(0.18, 0.00, 0.98), +) + +scene.add(stream_actor) + +if interactive: + window.show(scene, size=(600, 600), reset_camera=False) + +window.record(scene, out_path='bundle1.png', size=(600, 600)) + +############################################################################### +# You may wonder how we knew how to set the camera. This is very easy. You just +# need to run ``window.show`` once see how you want to see the object and then +# close the window and call the ``camera_info`` method which prints the +# position, focal point and view up vectors of the camera. + +scene.camera_info() + +############################################################################### +# Show every point with a value from a volume with default colormap +# ================================================================= +# +# Here we will need to input the ``fa`` map in ``streamtube`` or ``line``. + +scene.clear() +stream_actor2 = actor.line(bundle_native, fa, linewidth=0.1) + +############################################################################### +# We can also show the scalar bar. + +bar = actor.scalar_bar() + +scene.add(stream_actor2) +scene.add(bar) + +if interactive: + window.show(scene, size=(600, 600), reset_camera=False) + +window.record(scene, out_path='bundle2.png', size=(600, 600)) + +############################################################################## +# Show every point with a value from a volume with your colormap +# ============================================================== +# +# Here we will need to input the ``fa`` map in ``streamtube`` + +scene.clear() + +hue = (0.0, 0.0) # red only +saturation = (0.0, 1.0) # white to red + +lut_cmap = actor.colormap_lookup_table(hue_range=hue, saturation_range=saturation) + +stream_actor3 = actor.line(bundle_native, fa, linewidth=0.1, lookup_colormap=lut_cmap) +bar2 = actor.scalar_bar(lut_cmap) + +scene.add(stream_actor3) +scene.add(bar2) + +if interactive: + window.show(scene, size=(600, 600), reset_camera=False) + +window.record(scene, out_path='bundle3.png', size=(600, 600)) + +############################################################################### +# Show every bundle with a specific color +# ======================================== +# +# You can have a bundle with a specific color. In this example, we are choosing +# orange. + +scene.clear() +stream_actor4 = actor.line(bundle_native, (1.0, 0.5, 0), linewidth=0.1) + +scene.add(stream_actor4) + +if interactive: + window.show(scene, size=(600, 600), reset_camera=False) + +window.record(scene, out_path='bundle4.png', size=(600, 600)) + +############################################################################### +# Show every streamline of a bundle with a different color +# ======================================================== +# +# Let's make a colormap where every streamline of the bundle is colored by its +# length. + +scene.clear() + +lengths = length(bundle_native) + +hue = (0.5, 0.5) # blue only +saturation = (0.0, 1.0) # black to white + +lut_cmap = actor.colormap_lookup_table( + scale_range=(lengths.min(), lengths.max()), + hue_range=hue, + saturation_range=saturation, +) + +stream_actor5 = actor.line( + bundle_native, lengths, linewidth=0.1, lookup_colormap=lut_cmap +) + +scene.add(stream_actor5) +bar3 = actor.scalar_bar(lut_cmap) + +scene.add(bar3) + +if interactive: + window.show(scene, size=(600, 600), reset_camera=False) + +window.record(scene, out_path='bundle5.png', size=(600, 600)) + +############################################################################### +# Show every point of every streamline with a different color +# ============================================================ +# +# In this case in which we want to have a color per point and per streamline, +# we can create a list of the colors to correspond to the list of streamlines +# (bundles). Here in ``colors`` we will insert some random RGB colors. + +scene.clear() + +colors = [np.random.rand(*streamline.shape) for streamline in bundle_native] + +stream_actor6 = actor.line(bundle_native, np.vstack(colors), linewidth=0.2) + +scene.add(stream_actor6) + +if interactive: + window.show(scene, size=(600, 600), reset_camera=False) + +window.record(scene, out_path='bundle6.png', size=(600, 600)) + +############################################################################### +# Add depth cues to streamline rendering +# ============================================================ +# +# By default, lines are drawn with the same width on the screen, regardless of +# their distance from the camera. To increase realism, we can enable +# ``depth_cue`` to make the lines shrink with distance from the camera. We +# will return to the default color scheme from the first example. Note that +# ``depth_cue`` works best for ``linewidth`` <= 1. + +scene.clear() + +stream_actor7 = actor.line(bundle_native, linewidth=0.5, depth_cue=True) + +scene.add(stream_actor7) + +if interactive: + window.show(scene, size=(600, 600), reset_camera=False) + +window.record(scene, out_path='bundle7.png', size=(600, 600)) + +############################################################################### +# Render streamlines as fake tubes +# ============================================================ +# +# We can simulate the look of streamtubes by adding shading to streamlines with +# ``fake_tube``. Note that ``fake_tube`` requires ``linewidth`` > 1. + +scene.clear() + +stream_actor8 = actor.line(bundle_native, linewidth=3, fake_tube=True) + +scene.add(stream_actor8) + +if interactive: + window.show(scene, size=(600, 600), reset_camera=False) + +window.record(scene, out_path='bundle8.png', size=(600, 600)) + +############################################################################### +# Combine depth cues with fake tubes +# ============================================================ +# +# It is possible to fully simulate streamtubes by enabling both ``depth_cue`` +# and ``fake_tube``. However, it can be challenging to choose a ``linewidth`` +# that demonstrates both techniques well. + +scene.clear() + +stream_actor9 = actor.line(bundle_native, linewidth=3, depth_cue=True, fake_tube=True) + +scene.add(stream_actor9) + +if interactive: + window.show(scene, size=(600, 600), reset_camera=False) + +window.record(scene, out_path='bundle9.png', size=(600, 600)) + +############################################################################### +# Render streamlines as tubes +# ============================================================ +# +# For yet more realism, we can use ``streamtube``. Note that this actor +# generates much more geometry than ``line``, so it is more computationally +# expensive. For large datasets, it may be better to approximate tubes using +# the methods described above. + +scene.clear() + +stream_actor10 = actor.streamtube(bundle_native, linewidth=0.5) + +scene.add(stream_actor10) + +if interactive: + window.show(scene, size=(600, 600), reset_camera=False) + +window.record(scene, out_path='bundle10.png', size=(600, 600)) + +############################################################################### +# In summary, we showed that there are many useful ways for visualizing maps +# on bundles. diff --git a/v0.10.x/_downloads/7bc69e0cc2bca6e32b0632c9034e706f/viz_brownian_motion.py b/v0.10.x/_downloads/7bc69e0cc2bca6e32b0632c9034e706f/viz_brownian_motion.py new file mode 100644 index 000000000..8150bc28c --- /dev/null +++ b/v0.10.x/_downloads/7bc69e0cc2bca6e32b0632c9034e706f/viz_brownian_motion.py @@ -0,0 +1,158 @@ +""" +====================================================================== +Brownian motion +====================================================================== +Brownian motion, or pedesis, is the random motion of particles +suspended in a medium. In this animation, path followed by 20 particles +exhibiting brownian motion in 3D is plotted. + +Importing necessary modules +""" + +import numpy as np +from scipy.stats import norm + +from fury import actor, ui, utils, window + +############################################################################### +# Let's define some variable and their description: +# +# * **total_time**: time to be discretized via time_steps (default: 5) +# * **num_total_steps**: total number of steps each particle will take +# (default: 300) +# * **time_step**: By default, it is equal to total_time / num_total_steps +# * **counter_step**: to keep track of number of steps taken +# (initialised to 0) +# * **delta**: delta determines the "speed" of the Brownian motion. +# Increase delta to speed up the motion of the particle(s). The random +# variable of the position has a normal distribution whose mean is the +# position at counter_step = 0 and whose variance is equal to +# delta**2*time_step. (default: 1.8) +# * **num_particles**: number of particles whose path will be plotted +# (default: 20) +# * **path_thickness**: thickness of line(s) that will be used to plot the +# path(s) of the particle(s) (default: 3) +# * **origin**: coordinate from which the the particle(s) begin the motion +# (default: [0, 0, 0]) + +total_time = 5 +num_total_steps = 300 +counter_step = 0 +delta = 1.8 +num_particles = 20 +path_thickness = 3 +origin = [0, 0, 0] + +############################################################################### +# We define a particle function that will return an actor, store and update +# coordinates of the particles (the path of the particles). + + +def particle( + colors, + origin=[0, 0, 0], + num_total_steps=300, + total_time=5, + delta=1.8, + path_thickness=3, +): + origin = np.asarray(origin, dtype=float) + position = np.tile(origin, (num_total_steps, 1)) + path_actor = actor.line([position], colors, linewidth=path_thickness) + path_actor.position = position + path_actor.delta = delta + path_actor.num_total_steps = num_total_steps + path_actor.time_step = total_time / num_total_steps + path_actor.vertices = utils.vertices_from_actor(path_actor) + path_actor.no_vertices_per_point = len(path_actor.vertices) / num_total_steps + path_actor.initial_vertices = path_actor.vertices.copy() - np.repeat( + position, path_actor.no_vertices_per_point, axis=0 + ) + return path_actor + + +############################################################################### +# The function `update_path` will simulate the the brownian motion. + + +def update_path(act, counter_step): + if counter_step < act.num_total_steps: + x, y, z = act.position[counter_step - 1] + x += norm.rvs(scale=act.delta**2 * act.time_step) + y += norm.rvs(scale=act.delta**2 * act.time_step) + z += norm.rvs(scale=act.delta**2 * act.time_step) + act.position[counter_step:] = [x, y, z] + act.vertices[:] = act.initial_vertices + np.repeat( + act.position, act.no_vertices_per_point, axis=0 + ) + utils.update_actor(act) + + +############################################################################### +# Creating a scene object and configuring the camera's position + +scene = window.Scene() +scene.background((1.0, 1.0, 1.0)) +scene.zoom(1.7) +scene.set_camera( + position=(0, 0, 40), focal_point=(0.0, 0.0, 0.0), view_up=(0.0, 0.0, 0.0) +) +showm = window.ShowManager( + scene, size=(600, 600), reset_camera=True, order_transparent=True +) + + +############################################################################### +# Creating a list of particle objects + +l_particle = [ + particle( + colors=np.random.rand(1, 3), + origin=origin, + num_total_steps=num_total_steps, + total_time=total_time, + path_thickness=path_thickness, + ) + for _ in range(num_particles) +] + +scene.add(*l_particle) + +############################################################################### +# Creating a container (cube actor) inside which the particle(s) move around + +container_actor = actor.box( + centers=np.array([[0, 0, 0]]), colors=(0.5, 0.9, 0.7, 0.4), scales=6 +) +scene.add(container_actor) + +############################################################################### +# Initializing text box to display the name of the animation + +tb = ui.TextBlock2D(bold=True, position=(235, 40), color=(0, 0, 0)) +tb.message = 'Brownian Motion' +scene.add(tb) + + +############################################################################### +# The path of the particles exhibiting Brownian motion is plotted here + + +def timer_callback(_obj, _event): + global counter_step, list_particle + counter_step += 1 + for p in l_particle: + update_path(p, counter_step=counter_step) + showm.render() + scene.azimuth(2) + if counter_step == num_total_steps: + showm.exit() + + +############################################################################### +# Run every 30 milliseconds + + +showm.add_timer_callback(True, 30, timer_callback) +showm.start() +window.record(showm.scene, size=(600, 600), out_path='viz_brownian_motion.png') diff --git a/v0.10.x/_downloads/7e782ed48e09a9468a3200cc0f19ebfd/viz_radio_buttons.ipynb b/v0.10.x/_downloads/7e782ed48e09a9468a3200cc0f19ebfd/viz_radio_buttons.ipynb new file mode 100644 index 000000000..fa32e0f93 --- /dev/null +++ b/v0.10.x/_downloads/7e782ed48e09a9468a3200cc0f19ebfd/viz_radio_buttons.ipynb @@ -0,0 +1,115 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Sphere Color Control using Radio Buttons\n\nThis example shows how to use the UI API. We will demonstrate how to\ncreate a Sphere and control its color using radio buttons.\n\nFirst, some imports.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "import numpy as np\n\nfrom fury import actor, ui, utils, window\nfrom fury.data import fetch_viz_icons" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "First we need to fetch some icons that are included in FURY.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "fetch_viz_icons()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Sphere and Radio Buttons\n\nAdd a Sphere to the scene.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "sphere = actor.sphere(\n centers=np.array([[50, 0, 0]]),\n colors=np.array([[0, 0, 1]]),\n radii=11.0,\n theta=360,\n phi=360,\n)\n\n# Creating a dict of possible options and mapping it with their values.\noptions = {'Blue': (0, 0, 255), 'Red': (255, 0, 0), 'Green': (0, 255, 0)}\n\ncolor_toggler = ui.RadioButton(\n list(options),\n checked_labels=['Blue'],\n padding=1,\n font_size=16,\n font_family='Arial',\n position=(200, 200),\n)\n\n\n# A callback which will set the values for the box\ndef toggle_color(radio):\n vcolors = utils.colors_from_actor(sphere)\n color = options[radio.checked_labels[0]]\n vcolors[:] = np.array(color)\n utils.update_actor(sphere)\n\n\ncolor_toggler.on_change = toggle_color" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Show Manager\n\nNow that all the elements have been initialised, we add them to the show\nmanager.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "current_size = (800, 800)\nshow_manager = window.ShowManager(size=current_size, title='FURY Sphere Example')\n\nshow_manager.scene.add(sphere)\nshow_manager.scene.add(color_toggler)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Set camera for better visualization\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "show_manager.scene.reset_camera()\nshow_manager.scene.set_camera(position=(0, 0, 150))\nshow_manager.scene.reset_clipping_range()\nshow_manager.scene.azimuth(30)\ninteractive = False\n\nif interactive:\n show_manager.start()\n\nwindow.record(show_manager.scene, size=current_size, out_path='viz_radio_buttons.png')" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.8" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/v0.10.x/_downloads/7f7b4c1bdc885dd2c0a5375a5eab2c22/viz_billboard_sdf_spheres.ipynb b/v0.10.x/_downloads/7f7b4c1bdc885dd2c0a5375a5eab2c22/viz_billboard_sdf_spheres.ipynb new file mode 100644 index 000000000..90a9d4635 --- /dev/null +++ b/v0.10.x/_downloads/7f7b4c1bdc885dd2c0a5375a5eab2c22/viz_billboard_sdf_spheres.ipynb @@ -0,0 +1,539 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# SDF Impostors on Billboards\n\nTraditional rendering engines discretize surfaces using triangles or\nquadrilateral polygons. The visual quality of these elements depends on the\nnumber of polygons used to build the 3D mesh, i.e., a smoother surface will\nrequire more polygons. However, increasing the amount of rendered polygons\ncomes at the cost of performance as it decreases the number of frames per\nsecond (FPS), which might compromise the real-time interactivity of a\nvisualization.\n\nBillboarding is a technique that changes an object's orientation to always face\na specific direction, in most cases, the camera. This technique became popular\nin games and applications with a high polygonal quota requirement.\n\nSigned Distance Functions (SDFs) are mathematical functions that take as input\na point in a metric space and return the distance from that point to the\nboundary of the function. Depending on whether the point is contained within\nthis boundary or outside it, the function will return negative or positive\nvalues [Hart1996]_. For visualization purposes, the task is to display only the\npoints within the boundary or, in other words, those whose distance to the\nborder is either negative or positive, depending on the definition of the SDF.\n\nThis tutorial exemplifies why FURY's billboard actor is a suitable rendering\noption when thinking about performance and how it can be used to create\nimpostors using SDFs.\n\nLet's start by importing the necessary modules:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "import os\n\nimport numpy as np\n\nfrom fury import actor, window\nfrom fury.shaders import compose_shader, import_fury_shader\nfrom fury.utils import represent_actor_as_wireframe" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now set up a new scene to place our actors in.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "scene = window.Scene()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This tutorial is divided into two parts. First, we will render spheres in the\ntraditional way and then render them using SDFs on billboards.\n\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Traditional sphere rendering\nFURY provides an easy way to create sphere glyphs from numpy arrays as\nfollows:\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "centers = np.array([\n [0, 0, 0], [-6, -6, -6], [8, 8, 8], [8.5, 9.5, 9.5], [10, -10, 10],\n [-13, 13, -13], [-17, -17, 17]])\ncolors = np.array([\n [1, 1, 0], [1, 0, 1], [0, 0, 1], [1, 1, 1], [1, 0, 0], [0, 1, 0],\n [0, 1, 1]])\nscales = np.array([6, 1.2, 1, .2, .7, 3, 2])\nspheres_actor = actor.sphere(\n centers, colors, radii=scales, phi=8, theta=8, use_primitive=False)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To interactively visualize the recently created actors, we only need to add\nthem to the previously created `scene` and set the following variable to\n**True**, otherwise, we will screenshot the scene.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "scene.add(spheres_actor)\n\ninteractive = False\n\nif interactive:\n window.show(scene)\nelse:\n window.record(scene, size=(600, 600), out_path='viz_regular_spheres.png')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now, let's explore our scene to understand what we have created. Traditional\nFURY spheres are designed using a set of interconnected triangles. To\nvisualize them, we want to transform our representation from *Surface* to\n*Wireframe* using the following command.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "represent_actor_as_wireframe(spheres_actor)\n\nif interactive:\n window.show(scene)\nelse:\n window.record(scene, size=(600, 600), out_path='viz_low_res_wireframe.png')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's clean the scene and play with the parameters `phi` and `theta`.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "scene.clear()\nspheres_actor = actor.sphere(\n centers, colors, radii=scales, phi=16, theta=16, use_primitive=False)\nrepresent_actor_as_wireframe(spheres_actor)\nscene.add(spheres_actor)\n\nif interactive:\n window.show(scene)\nelse:\n window.record(scene, size=(600, 600), out_path='viz_hi_res_wireframe.png')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As you might have noticed, these parameters control the resolution of the\nspheres. Evidently, these parameters directly impact the quality of the\nvisualization, but increasing such resolution comes at the cost of\nperformance, i.e., more computing power will be needed and drawn to interact\nwith these actors.\n\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Luckily for us, a technique delivers high-resolution glyphs at a much lower\ncost. This technique is known as Signed Distance Functions (SDFs), and they\nwork as follows:\n\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## SDF sphere rendering\nIt is possible to render SDFs in FURY by using the following configuration,\nbut first, let's clear the scene.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "scene.clear()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The billboard actor is suited and continuously improved to render SDFs. To\ncreate and visualize it, we can use the following instructions:\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "billboards_actor = actor.billboard(centers, colors=colors, scales=scales)\nrepresent_actor_as_wireframe(billboards_actor)\nscene.add(billboards_actor)\n\nif interactive:\n window.show(scene)\nelse:\n window.record(\n scene, size=(600, 600), out_path='viz_billboards_wireframe.png')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "If you interacted with this actor, you might have noticed how it always\naligned itself to the camera or, in other words, your FURY window. Now that\nwe know how billboards work, we can start working on our Signed Distance\nSpheres. Let's clear our scene first.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "scene.clear()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "FURY already includes a shader function with the definition of a Signed\nDistance Sphere. So we can load it and use it like this:\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "sd_sphere = import_fury_shader(os.path.join('sdf', 'sd_sphere.frag'))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Additionally, we need to define the radii of our spheres. Since we prefer\nthese to be determined by the billboards' size, we will use the maximum\nradius distance allowed by our billboards.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "sphere_radius = 'const float RADIUS = 1.;'" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's calculate the distance to the sphere by combining the previously\ndefined variables.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "sphere_dist = 'float dist = sdSphere(point, RADIUS);'" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now, evaluate the signed distance function.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "sdf_eval = \\\n \"\"\"\n if (dist < 0)\n fragOutput0 = vec4(color, opacity);\n else\n discard;\n \"\"\"" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Putting all of our declarations (constants and function) and implementations\n(distance calculation and evaluation) together.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "fs_dec = compose_shader([sphere_radius, sd_sphere])\nfs_impl = compose_shader([sphere_dist, sdf_eval])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We are ready to create and visualize our SDF-billboard actors.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "spheres_actor = actor.billboard(\n centers, colors=colors, scales=scales, fs_dec=fs_dec, fs_impl=fs_impl)\nscene.add(spheres_actor)\n\nif interactive:\n window.show(scene)\nelse:\n window.record(\n scene, size=(600, 600), out_path='viz_billboards_circles.png')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Hold on, those actors don't look exactly like the ones we created using\ntraditional techniques; they don't even look 3D but 2D. Well, that's because\nwe still need an essential component: shading. So let's clear our scene and\nadd shading to our SDF billboard actors.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "scene.clear()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The first thing necessary to add shading to our SDF-billboard actors is to\ncalculate the normals of the SDFs. In this tutorial we are not going to get\ninto detail in the gradient and derivatives of SDFs, so we will use the\ncentral differences technique implemented in the following FURY shader\nfunction:\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "central_diffs_normal = import_fury_shader(\n os.path.join('sdf', 'central_diffs.frag'))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To use the central differences technique, we need to define a map function\nthat wraps our SDF and evaluates only a point.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "sd_sphere_normal = \\\n \"\"\"\n float map(vec3 p)\n {\n return sdSphere(p, RADIUS);\n }\n \"\"\"" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Then we can load the Blinn-Phong illumination model.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "blinn_phong_model = import_fury_shader(\n os.path.join('lighting', 'blinn_phong_model.frag'))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Again, let's bring all of our declarations (constants and functions)\ntogether.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "fs_dec = compose_shader([\n sphere_radius, sd_sphere, sd_sphere_normal, central_diffs_normal,\n blinn_phong_model])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now, we can start our fragment shader implementation with the signed distance\nfunction evaluation. You might notice that in this case, we are not using an\nif statement but a `step` function, which is a more efficient way to perform\nthis evaluation. You can also replace the `step` function with a `smoothstep`\noperation and, in that way, add a very efficient form of antialiasing.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "sdf_eval = 'opacity *= 1 - step(0, dist);'" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In this case, we also need the absolute value of the distance to compensate\nfor the depth of the SDF sphere.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "abs_dist = 'float absDist = abs(dist);'" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We are ready to calculate the normals.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "normal = 'vec3 normal = centralDiffsNormals(vec3(point.xy, absDist), .0001);'" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "With the normals we can calculate a light attenuation factor.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "light_attenuation = 'float lightAttenuation = normal.z;'" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now, we are ready to calculate the color and output it.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "color = \\\n \"\"\"\n color = blinnPhongIllumModel(\n lightAttenuation, lightColor0, diffuseColor, specularPower,\n specularColor, ambientColor);\n \"\"\"\n\nfrag_output = 'fragOutput0 = vec4(color, opacity);'" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As before, we can bring our implementation code together.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "fs_impl = compose_shader([\n sphere_dist, sdf_eval, abs_dist, normal, light_attenuation, color,\n frag_output])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Finally, recreate the SDF billboard actors and visualize them.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "spheres_actor = actor.billboard(\n centers, colors=colors, scales=scales, fs_dec=fs_dec, fs_impl=fs_impl)\nscene.add(spheres_actor)\n\nif interactive:\n window.show(scene)\nelse:\n window.record(\n scene, size=(600, 600), out_path='viz_billboards_spheres.png')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### References\n.. [Hart1996] Hart, John C. \"Sphere tracing: A geometric method for the\n antialiased ray tracing of implicit surfaces.\" The Visual\n Computer 12.10 (1996): 527-545.\n\n.. include:: ../links_names.inc\n\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.8" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/v0.10.x/_downloads/7f7ea9ef83cabfb8993df8e31149e92f/viz_shapes.py b/v0.10.x/_downloads/7f7ea9ef83cabfb8993df8e31149e92f/viz_shapes.py new file mode 100644 index 000000000..130fadbcd --- /dev/null +++ b/v0.10.x/_downloads/7f7ea9ef83cabfb8993df8e31149e92f/viz_shapes.py @@ -0,0 +1,53 @@ +# -*- coding: utf-8 -*- +""" +============== +Simple Shapes +============== + +This example shows how to use the UI API. We will demonstrate how to draw +some geometric shapes from FURY UI elements. + +First, a bunch of imports. +""" + +from fury import ui, window +from fury.data import fetch_viz_icons + +############################################################################## +# First we need to fetch some icons that are included in FURY. + +fetch_viz_icons() + +############################################################################### +# Let's draw some simple shapes. First, a rectangle. + +rect = ui.Rectangle2D(size=(100, 100), position=(400, 400), color=(1, 0, 1)) + +############################################################################### +# Then we can draw a solid circle, or disk. + +disk = ui.Disk2D(outer_radius=50, center=(400, 200), color=(1, 1, 0)) + +############################################################################### +# Add an inner radius to make a ring. + +ring = ui.Disk2D(outer_radius=50, inner_radius=45, center=(500, 600), color=(0, 1, 1)) + + +############################################################################### +# Now that all the elements have been initialised, we add them to the show +# manager. + +current_size = (800, 800) +show_manager = window.ShowManager(size=current_size, title='FURY Shapes Example') + +show_manager.scene.add(rect) +show_manager.scene.add(disk) +show_manager.scene.add(ring) + +interactive = False + +if interactive: + show_manager.start() + +window.record(show_manager.scene, size=current_size, out_path='viz_shapes.png') diff --git a/v0.10.x/_downloads/80519c91c57ffaf03d20f4e9e1cba7c7/viz_play_video.ipynb b/v0.10.x/_downloads/80519c91c57ffaf03d20f4e9e1cba7c7/viz_play_video.ipynb new file mode 100644 index 000000000..d18c69875 --- /dev/null +++ b/v0.10.x/_downloads/80519c91c57ffaf03d20f4e9e1cba7c7/viz_play_video.ipynb @@ -0,0 +1,43 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Play a video in the 3D world\n\nThe goal of this demo is to show how to visualize a video\non a rectangle by updating a texture.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "import time\n\nimport cv2\nimport numpy as np\n\nfrom fury import actor, window\n\n\n# The VideoCapturer Class\n# This Class wraps OpenCV Videocapture\nclass VideoCapturer:\n def __init__(self, video, time):\n self.path = video\n self.video = cv2.VideoCapture(self.path)\n self.fps = int(self.video.get(cv2.CAP_PROP_FPS))\n self.frames = int(self.video.get(cv2.CAP_PROP_FRAME_COUNT))\n self.time = time\n\n # A generator to yield video frames on every call\n def get_frame(self):\n start = time.time()\n for _ in range(self.frames):\n isframe, frame = self.video.read()\n dur = time.time() - start\n if dur > self.time:\n break\n if isframe:\n yield cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)\n self.video.release()\n yield None\n\n\nclass VideoPlayer:\n def __init__(self, video, time=10):\n # Initializes the Video object with the given Video\n self.video = VideoCapturer(video, time)\n self.video_generator = self.video.get_frame()\n self.current_video_frame = next(self.video_generator)\n # Initialize Scene\n self.initialize_scene()\n # Create a Show Manager and Initialize it\n self.show_manager = window.ShowManager(\n self.scene, size=(900, 768), reset_camera=False, order_transparent=True\n )\n\n # Initialize the Scene with actors\n def initialize_scene(self):\n self.scene = window.Scene()\n # Initialize a Plane actor with the 1st video frame along with\n # the actor grid which is to be updated in each iteration\n self.plane_actor = actor.texture(self.current_video_frame)\n self.scene.add(self.plane_actor)\n\n # The timer_callback function getting called by the show manager\n def timer_callback(self, _obj, _event):\n self.current_video_frame = next(self.video_generator)\n if isinstance(self.current_video_frame, np.ndarray):\n # update texture of the actor with the current frame image\n # by updating the actor grid\n actor.texture_update(self.plane_actor, self.current_video_frame)\n self.show_manager.scene.azimuth(1.5) # to rotate the camera\n else:\n self.show_manager.exit()\n\n self.show_manager.render()\n\n def run(self):\n # Add a timer callback to show manager after with\n # video frame duration as the interval\n self.frame_duration = int(1000 / self.video.fps)\n self.show_manager.add_timer_callback(\n True, self.frame_duration, self.timer_callback\n )\n self.show_manager.start()\n\n\n# Create VideoPlayer Object and run it\nvideo_url = (\n 'http://commondatastorage.googleapis.com/'\n + 'gtv-videos-bucket/sample/BigBuckBunny.mp4'\n)\nvp = VideoPlayer(video_url)\nvp.run()\nwindow.record(vp.show_manager.scene, out_path='viz_play_video.png', size=(600, 600))" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.8" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/v0.10.x/_downloads/840daccb467aacbf7bd35f5e98f12d5d/viz_buttons.py b/v0.10.x/_downloads/840daccb467aacbf7bd35f5e98f12d5d/viz_buttons.py new file mode 100644 index 000000000..58eaf8d0a --- /dev/null +++ b/v0.10.x/_downloads/840daccb467aacbf7bd35f5e98f12d5d/viz_buttons.py @@ -0,0 +1,90 @@ +# -*- coding: utf-8 -*- +""" +=============== +Buttons & Text +=============== + +This example shows how to use the UI API. We will demonstrate how to create +panel having buttons with callbacks. + +First, some imports. +""" +from fury import ui, window +from fury.data import fetch_viz_icons, read_viz_icons + +############################################################################## +# First we need to fetch some icons that are included in FURY. + +fetch_viz_icons() + +############################################################################### +# Let's create some buttons and text and put them in a panel. +# First we'll make the panel. + +panel = ui.Panel2D(size=(300, 150), color=(1, 1, 1), align='right') +panel.center = (500, 400) + +############################################################################### +# Then we'll make two text labels and place them on the panel. +# Note that we specify the position with integer numbers of pixels. + +text = ui.TextBlock2D(text='Click me') +text2 = ui.TextBlock2D(text='Me too') +panel.add_element(text, (50, 100)) +panel.add_element(text2, (180, 100)) + +############################################################################### +# Then we'll create two buttons and add them to the panel. +# +# Note that here we specify the positions with floats. In this case, these are +# percentages of the panel size. + + +button_example = ui.Button2D( + icon_fnames=[('square', read_viz_icons(fname='stop2.png'))] +) + +icon_files = [] +icon_files.append(('down', read_viz_icons(fname='circle-down.png'))) +icon_files.append(('left', read_viz_icons(fname='circle-left.png'))) +icon_files.append(('up', read_viz_icons(fname='circle-up.png'))) +icon_files.append(('right', read_viz_icons(fname='circle-right.png'))) + +second_button_example = ui.Button2D(icon_fnames=icon_files) + +panel.add_element(button_example, (0.25, 0.33)) +panel.add_element(second_button_example, (0.66, 0.33)) + + +############################################################################### +# We can add a callback to each button to perform some action. + + +def change_text_callback(i_ren, _obj, _button): + text.message = 'Clicked!' + i_ren.force_render() + + +def change_icon_callback(i_ren, _obj, _button): + _button.next_icon() + i_ren.force_render() + + +button_example.on_left_mouse_button_clicked = change_text_callback +second_button_example.on_left_mouse_button_pressed = change_icon_callback + +############################################################################### +# Now that all the elements have been initialised, we add them to the show +# manager. + +current_size = (800, 800) +show_manager = window.ShowManager(size=current_size, title='FURY Button Example') + +show_manager.scene.add(panel) + +interactive = False + +if interactive: + show_manager.start() + +window.record(show_manager.scene, size=current_size, out_path='viz_button.png') diff --git a/v0.10.x/_downloads/847206dc3712b90c8233d1e6e32ea576/viz_gltf_animated.py b/v0.10.x/_downloads/847206dc3712b90c8233d1e6e32ea576/viz_gltf_animated.py new file mode 100644 index 000000000..18fdc8b41 --- /dev/null +++ b/v0.10.x/_downloads/847206dc3712b90c8233d1e6e32ea576/viz_gltf_animated.py @@ -0,0 +1,57 @@ +""" +======================= +Visualizing a glTF file +======================= +In this tutorial, we will show how to display a simple animated glTF in a +scene. +""" + +from fury import window +from fury.data import fetch_gltf, read_viz_gltf +from fury.gltf import glTF + +############################################################################## +# Create a scene. + +scene = window.Scene() + +showm = window.ShowManager( + scene, size=(900, 768), reset_camera=False, order_transparent=True +) +showm.initialize() + + +############################################################################## +# Retrieving the gltf model. +fetch_gltf('InterpolationTest', 'glTF') +filename = read_viz_gltf('InterpolationTest') + +############################################################################## +# Initialize the glTF object and get actors using `actors` method. +# Get the main_timeline (which contains multiple Timeline objects). + +gltf_obj = glTF(filename) +timeline = gltf_obj.main_animation() + +############################################################################## +# Add the timeline to the scene (No need to add actors separately). + +scene.add(timeline) + +############################################################################## +# define a timer_callback that updates the timeline. + +interactive = False + + +def timer_callback(_obj, _event): + timeline.update_animation() + showm.render() + + +showm.add_timer_callback(True, 10, timer_callback) + +if interactive: + showm.start() + +window.record(scene, out_path='viz_gltf_animated.png', size=(900, 768)) diff --git a/v0.10.x/_downloads/89193b75dd3a4bdbe2786e1072a3e514/viz_ui_listbox.ipynb b/v0.10.x/_downloads/89193b75dd3a4bdbe2786e1072a3e514/viz_ui_listbox.ipynb new file mode 100644 index 000000000..ac2588652 --- /dev/null +++ b/v0.10.x/_downloads/89193b75dd3a4bdbe2786e1072a3e514/viz_ui_listbox.ipynb @@ -0,0 +1,151 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# ListBox\n\nThis example shows how to use the UI API. We will create a list\nsome geometric shapes from FURY UI elements.\n\nFirst, a bunch of imports.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "from fury import ui, window\nfrom fury.data import fetch_viz_icons" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "First we need to fetch some icons that are included in FURY.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "fetch_viz_icons()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Create some text blocks that will be shown when\nlist elements will be selected\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "welcome_text = ui.TextBlock2D(text='Welcome', font_size=30, position=(500, 400))\nbye_text = ui.TextBlock2D(text='Bye', font_size=30, position=(500, 400))\nfury_text = ui.TextBlock2D(text='Fury', font_size=30, position=(500, 400))\n\nexample = [welcome_text, bye_text, fury_text]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Hide these text blocks for now\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def hide_all_examples():\n for element in example:\n element.set_visibility(False)\n\n\nhide_all_examples()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Create ListBox with the values as parameter.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "values = ['Welcome', 'Bye', 'Fury']\nlistbox = ui.ListBox2D(\n values=values, position=(10, 300), size=(200, 200), multiselection=False\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Function to show selected element.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def display_element():\n hide_all_examples()\n element = example[values.index(listbox.selected[0])]\n element.set_visibility(True)\n\n\nlistbox.on_change = display_element" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now that all the elements have been initialised, we add them to the show\nmanager.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "current_size = (800, 800)\nshow_manager = window.ShowManager(size=current_size, title='FURY UI ListBox_Example')\n\nshow_manager.scene.add(listbox)\nshow_manager.scene.add(welcome_text)\nshow_manager.scene.add(bye_text)\nshow_manager.scene.add(fury_text)\ninteractive = False\n\nif interactive:\n show_manager.start()\n\nwindow.record(show_manager.scene, size=current_size, out_path='viz_listbox.png')" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.8" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/v0.10.x/_downloads/8cdc4ef9f45f14ed1686dc026e06087d/viz_morphing.py b/v0.10.x/_downloads/8cdc4ef9f45f14ed1686dc026e06087d/viz_morphing.py new file mode 100644 index 000000000..02f4e931f --- /dev/null +++ b/v0.10.x/_downloads/8cdc4ef9f45f14ed1686dc026e06087d/viz_morphing.py @@ -0,0 +1,74 @@ +""" +============================ +Morphing Animation in a glTF +============================ +In this tutorial, we will show how to use morphing in a glTF model in FURY. +""" + +from fury import window +from fury.data import fetch_gltf, read_viz_gltf +from fury.gltf import glTF + +############################################################################## +# Retrieving the model with morphing in it (look at Khronoos samples). +# We're choosing the `MorphStressTest` model here. + +fetch_gltf('MorphStressTest', 'glTF') +filename = read_viz_gltf('MorphStressTest') + +############################################################################## +# Initializing the glTF object, You can additionally set `apply_normals=True`. +# Note: Normals might not work as intended with morphing. + +gltf_obj = glTF(filename, apply_normals=True) + +############################################################################## +# Get the morph timeline using `morph_timeline` method, Choose the animation +# name you want to visualize. +# Note: If there's no name for animation, It's stored as `anim_0`, `anim_1` etc + +animation = gltf_obj.morph_animation()['TheWave'] + +############################################################################## +# Call the `update_morph` method once, This moves initialise the morphing at +# timestamp 0.0 seconds and ensures that camera fits all the actors perfectly. + +gltf_obj.update_morph(animation) + +############################################################################## +# Create a scene, and show manager. +# Initialize the show manager and add timeline to the scene (No need to add +# actors to the scene separately). + +scene = window.Scene() +showm = window.ShowManager( + scene, size=(900, 768), reset_camera=True, order_transparent=True +) + +showm.initialize() +scene.add(animation) + +############################################################################## +# define a timer_callback. +# Use the `update_morph` method again, It updates the timeline and applies +# morphing). + + +def timer_callback(_obj, _event): + gltf_obj.update_morph(animation) + showm.render() + + +############################################################################## +# Optional: `timeline.play()` auto plays the animations. + + +showm.add_timer_callback(True, 20, timer_callback) +scene.reset_camera() + +interactive = False + +if interactive: + showm.start() + +window.record(scene, out_path='viz_morphing.png', size=(900, 768)) diff --git a/v0.10.x/_downloads/8ddd5e4cbaa809e904914f3877e7a522/viz_card_sprite_sheet.py b/v0.10.x/_downloads/8ddd5e4cbaa809e904914f3877e7a522/viz_card_sprite_sheet.py new file mode 100644 index 000000000..cb8e8a771 --- /dev/null +++ b/v0.10.x/_downloads/8ddd5e4cbaa809e904914f3877e7a522/viz_card_sprite_sheet.py @@ -0,0 +1,100 @@ +# -*- coding: utf-8 -*- +""" +==== +Card +==== + +This example shows how to create a card and use a sprite +sheet to update the image in the card. + +First, some imports. +""" +import os +from fury import ui, window +from fury.data import fetch_viz_icons +from fury.io import load_image, load_sprite_sheet, save_image +from tempfile import TemporaryDirectory as InTemporaryDirectory + +############################################################################## +# First we need to fetch some icons that are included in FURY. + +TARGET_FPS = 15 +FRAME_TIME = (1.0 / TARGET_FPS) * 1000 + +fetch_viz_icons() + +sprite_sheet = load_sprite_sheet('https://raw.githubusercontent.com/fury-gl/' + 'fury-data/master/unittests/fury_sprite.png', + 5, 5) +CURRENT_SPRITE_IDX = 0 + +vtk_sprites = [] +############################################################################### +# Let's create a card and add it to the show manager + +img_url = "https://raw.githubusercontent.com/fury-gl"\ + "/fury-communication-assets/main/fury-logo.png" + +title = "FURY" +body = "FURY - Free Unified Rendering in pYthon."\ + "A software library for scientific visualization in Python." + +card = ui.elements.Card2D(image_path=img_url, title_text=title, + body_text=body, + image_scale=0.55, size=(300, 300), + bg_color=(1, 0.294, 0.180), + bg_opacity=0.8, border_width=5, + border_color=(0.1, 0.4, 0.8)) + +############################################################################### +# Now we define the callback to update the image on card after some delay. + + +def timer_callback(_obj, _evt): + global CURRENT_SPRITE_IDX, show_manager + CURRENT_SPRITE_IDX += 1 + sprite = vtk_sprites[CURRENT_SPRITE_IDX % len(vtk_sprites)] + card.image.set_img(sprite) + i_ren = show_manager.scene.GetRenderWindow()\ + .GetInteractor().GetInteractorStyle() + + i_ren.force_render() + +############################################################################### +# Lets create a function to convert the sprite to vtkImageData + + +def sprite_to_vtk(): + with InTemporaryDirectory() as tdir: + for idx, sprite in enumerate(list(sprite_sheet.values())): + sprite_path = os.path.join(tdir, f'{idx}.png') + save_image(sprite, sprite_path, compression_quality=100) + vtk_sprite = load_image(sprite_path, as_vtktype=True) + vtk_sprites.append(vtk_sprite) + + +############################################################################### +# Now that the card has been initialised, we add it to the show +# manager. + +current_size = (1000, 1000) +show_manager = window.ShowManager(size=current_size, + title="FURY Card Example") + +show_manager.scene.add(card) +show_manager.initialize() +############################################################################### +# Converting numpy array sprites to vtk images +sprite_to_vtk() + +############################################################################### +# Adding a timer to update the card image +show_manager.add_timer_callback(True, int(FRAME_TIME), timer_callback) + +# To interact with the UI, set interactive = True +interactive = False + +if interactive: + show_manager.start() + +window.record(show_manager.scene, out_path="card_ui.png", size=(1000, 1000)) diff --git a/v0.10.x/_downloads/8e284c61bd4308568ae92601a0a6626a/viz_solar_system.ipynb b/v0.10.x/_downloads/8e284c61bd4308568ae92601a0a6626a/viz_solar_system.ipynb new file mode 100644 index 000000000..6080e9029 --- /dev/null +++ b/v0.10.x/_downloads/8e284c61bd4308568ae92601a0a6626a/viz_solar_system.ipynb @@ -0,0 +1,367 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Solar System Animation\n\nIn this tutorial, we will create an animation of the solar system\nusing textured spheres. We will also show how to manipulate the\nposition of these sphere actors in a timer_callback function\nto simulate orbital motion.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "import itertools\n\nimport numpy as np\n\nfrom fury import actor, io, ui, utils, window\nfrom fury.data import fetch_viz_textures, read_viz_icons, read_viz_textures" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Create a scene to start.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "scene = window.Scene()\n\n# Create a panel and the start/pause buttons\n\npanel = ui.Panel2D(size=(300, 100), color=(1, 1, 1), align='right')\npanel.center = (400, 50)\n\npause_button = ui.Button2D(icon_fnames=[('square', read_viz_icons(fname='pause2.png'))])\nstart_button = ui.Button2D(icon_fnames=[('square', read_viz_icons(fname='play3.png'))])\n\n# Add the buttons on the panel\n\npanel.add_element(pause_button, (0.25, 0.33))\npanel.add_element(start_button, (0.66, 0.33))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Define information relevant for each planet actor including its\ntexture name, relative position, and scale.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "planets_data = [\n {\n 'filename': '8k_mercury.jpg',\n 'position': 7,\n 'earth_days': 58,\n 'scale': (0.4, 0.4, 0.4),\n },\n {\n 'filename': '8k_venus_surface.jpg',\n 'position': 9,\n 'earth_days': 243,\n 'scale': (0.6, 0.6, 0.6),\n },\n {\n 'filename': '1_earth_8k.jpg',\n 'position': 11,\n 'earth_days': 1,\n 'scale': (0.4, 0.4, 0.4),\n },\n {\n 'filename': '8k_mars.jpg',\n 'position': 13,\n 'earth_days': 1,\n 'scale': (0.8, 0.8, 0.8),\n },\n {'filename': 'jupiter.jpg', 'position': 16, 'earth_days': 0.41, 'scale': (2, 2, 2)},\n {\n 'filename': '8k_saturn.jpg',\n 'position': 19,\n 'earth_days': 0.45,\n 'scale': (2, 2, 2),\n },\n {\n 'filename': '8k_saturn_ring_alpha.png',\n 'position': 19,\n 'earth_days': 0.45,\n 'scale': (3, 0.5, 3),\n },\n {\n 'filename': '2k_uranus.jpg',\n 'position': 22,\n 'earth_days': 0.70,\n 'scale': (1, 1, 1),\n },\n {\n 'filename': '2k_neptune.jpg',\n 'position': 25,\n 'earth_days': 0.70,\n 'scale': (1, 1, 1),\n },\n {'filename': '8k_sun.jpg', 'position': 0, 'earth_days': 27, 'scale': (5, 5, 5)},\n]\nfetch_viz_textures()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To take advantage of the previously defined data structure we are going to\ncreate an auxiliary function that will load and apply the respective\ntexture, set its respective properties (relative position and scale),\nand add the actor to a previously created scene.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def init_planet(planet_data):\n \"\"\"Initialize a planet actor.\n\n Parameters\n ----------\n planet_data : dict\n The planet_data is a dictionary, and the keys are filename(texture),\n position and scale.\n\n Returns\n -------\n planet_actor: actor\n The corresponding sphere actor with texture applied.\n \"\"\"\n planet_file = read_viz_textures(planet_data['filename'])\n planet_image = io.load_image(planet_file)\n planet_actor = actor.texture_on_sphere(planet_image)\n planet_actor.SetPosition(planet_data['position'], 0, 0)\n if planet_data['filename'] != '8k_saturn_ring_alpha.png':\n utils.rotate(planet_actor, (90, 1, 0, 0))\n planet_actor.SetScale(planet_data['scale'])\n scene.add(planet_actor)\n return planet_actor" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Use the ``map`` function to create actors for each of the texture files\nin the ``planet_files`` list. Then, assign each actor to its corresponding\nactor in the list.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "planet_actor_list = list(map(init_planet, planets_data))\n\nmercury_actor = planet_actor_list[0]\nvenus_actor = planet_actor_list[1]\nearth_actor = planet_actor_list[2]\nmars_actor = planet_actor_list[3]\njupiter_actor = planet_actor_list[4]\nsaturn_actor = planet_actor_list[5]\nsaturn_rings_actor = planet_actor_list[6]\nuranus_actor = planet_actor_list[7]\nneptune_actor = planet_actor_list[8]\nsun_actor = planet_actor_list[9]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Define the gravitational constant G, the orbital radii of each of the\nplanets, and the central mass of the sun. The gravity and mass will be\nused to calculate the orbital position, so multiply these two together to\ncreate a new constant, which we will call miu.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "g_exponent = np.float_power(10, -11)\ng_constant = 6.673 * g_exponent\n\nm_exponent = 1073741824 # np.power(10, 30)\nm_constant = 1.989 * m_exponent\n\nmiu = m_constant * g_constant" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's define two functions that will help us calculate the position of each\nplanet as it orbits around the sun: ``get_orbit_period`` and\n``get_orbital_position``, using the constant miu and the orbital radii\nof each planet.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def get_orbit_period(radius):\n return 2 * np.pi * np.sqrt(np.power(radius, 3) / miu)\n\n\ndef get_orbital_position(radius, time):\n orbit_period = get_orbit_period(radius)\n x = radius * np.cos((-2 * np.pi * time) / orbit_period)\n y = radius * np.sin((-2 * np.pi * time) / orbit_period)\n return x, y" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's define a function to rotate the planet actor axially, we'll be defining\naxis of each planet and angle by which it should be rotated using\n``rotate_axial`` funtction\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def rotate_axial(actor, time, radius):\n axis = (0, radius, 0)\n angle = 50 / time\n utils.rotate(actor, (angle, axis[0], axis[1], axis[2]))\n return angle" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's change the camera position to visualize the planets better.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "scene.set_camera(position=(-20, 60, 100))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Next, create a ShowManager object. The ShowManager class is the interface\nbetween the scene, the window and the interactor.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "showm = window.ShowManager(\n scene, size=(900, 768), reset_camera=False, order_transparent=True\n)\nscene.add(panel)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Next, let's focus on creating the animation.\nWe can determine the duration of animation with using the ``counter``.\nUse itertools to avoid global variables.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "counter = itertools.count()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Define one new function to use in ``timer_callback`` to update the planet\npositions ``update_planet_position``.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def update_planet_position(r_planet, planet_actor, cnt):\n pos_planet = get_orbital_position(r_planet, cnt)\n planet_actor.SetPosition(pos_planet[0], 0, pos_planet[1])\n return pos_planet" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "``calculate_path`` function is for calculating the path/orbit\nof every planet.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def calculate_path(r_planet, c):\n planet_track = [\n [get_orbital_position(r_planet, i)[0], 0, get_orbital_position(r_planet, i)[1]]\n for i in range(c)\n ]\n return planet_track" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "First we are making a list that will contain radius from `planets_data`.\nHere we are not taking the radius of orbit/path for sun and saturn ring.\n`planet_actors` will contain all the planet actors.\n`r_times` will contain time taken (in days) by the planets to rotate\naround itself.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "r_planets = [\n p_data['position']\n for p_data in planets_data\n if 'sun' not in p_data['filename']\n if 'saturn_ring' not in p_data['filename']\n]\n\nplanet_actors = [\n mercury_actor,\n venus_actor,\n earth_actor,\n mars_actor,\n jupiter_actor,\n saturn_actor,\n uranus_actor,\n neptune_actor,\n]\n\n\nsun_data = {\n 'actor': sun_actor,\n 'position': planets_data[9]['position'],\n 'earth_days': planets_data[9]['earth_days'],\n}\n\nr_times = [p_data['earth_days'] for p_data in planets_data]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Here we are calculating and updating the path/orbit before animation starts.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "planet_tracks = [calculate_path(rplanet, rplanet * 85) for rplanet in r_planets]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This is for orbit visualization. We are using line actor for orbits.\nAfter creating an actor we add it to the scene.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "orbit_actor = actor.line(planet_tracks, colors=(1, 1, 1), linewidth=0.1)\nscene.add(orbit_actor)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Define the ``timer_callback`` function, which controls what events happen\nat certain times, using the counter. Update the position of each planet\nactor using ``update_planet_position,`` assigning the x and y values of\neach planet's position with the newly calculated ones.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def timer_callback(_obj, _event):\n cnt = next(counter)\n showm.render()\n\n # Rotating the sun actor\n rotate_axial(sun_actor, sun_data['earth_days'], 1)\n\n for r_planet, p_actor, r_time in zip(r_planets, planet_actors, r_times):\n # if the planet is saturn then we also need to update the position\n # of its rings.\n if p_actor == saturn_actor:\n pos_saturn = update_planet_position(19, saturn_actor, cnt)\n saturn_rings_actor.SetPosition(pos_saturn[0], 0, pos_saturn[1])\n else:\n update_planet_position(r_planet, p_actor, cnt)\n rotate_axial(p_actor, r_time, r_planet)\n\n if cnt == 2000:\n showm.exit()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We add a callback to each button to perform some action.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def start_animation(i_ren, _obj, _button):\n showm.add_timer_callback(True, 10, timer_callback)\n\n\ndef pause_animation(i_ren, _obj, _button):\n showm.destroy_timers()\n\n\nstart_button.on_left_mouse_button_clicked = start_animation\npause_button.on_left_mouse_button_clicked = pause_animation" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Watch the planets orbit the sun in your new animation!\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "showm.add_timer_callback(True, 10, timer_callback)\nshowm.start()\n\nwindow.record(showm.scene, size=(900, 768), out_path='viz_solar_system_animation.png')" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.8" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/v0.10.x/_downloads/8e68663fafb09c37d55ebb286aac72d5/viz_color_interpolators.py b/v0.10.x/_downloads/8e68663fafb09c37d55ebb286aac72d5/viz_color_interpolators.py new file mode 100644 index 000000000..a7347ef8b --- /dev/null +++ b/v0.10.x/_downloads/8e68663fafb09c37d55ebb286aac72d5/viz_color_interpolators.py @@ -0,0 +1,111 @@ +""" +============================ +Keyframe Color Interpolators +============================ + +Color animation explained in this tutorial and how to use different color +space interpolators. +""" + +import numpy as np + +from fury import actor, window +from fury.animation import Animation +from fury.animation.interpolator import ( + hsv_color_interpolator, + lab_color_interpolator, + step_interpolator, + xyz_color_interpolator, +) +from fury.animation.timeline import Timeline +from fury.colormap import distinguishable_colormap + +scene = window.Scene() + +showm = window.ShowManager( + scene, size=(900, 768), reset_camera=False, order_transparent=True +) + + +############################################################################### +# Initializing positions of the cubes that will be color-animated. +cubes_pos = np.array( + [ + [[-2, 0, 0]], + [[0, 0, 0]], + [[2, 0, 0]], + [[4, 0, 0]], + [[6, 0, 0]], + ] +) + +############################################################################### +# Static labels for different interpolators (for show) +linear_text = actor.vector_text('Linear', (-2.64, -1, 0)) +lab_text = actor.vector_text('LAB', (-0.37, -1, 0)) +hsv_text = actor.vector_text('HSV', (1.68, -1, 0)) +xyz_text = actor.vector_text('XYZ', (3.6, -1, 0)) +step_text = actor.vector_text('Step', (5.7, -1, 0)) +scene.add(step_text, lab_text, linear_text, hsv_text, xyz_text) + +############################################################################### +# Creating an animation to animate the actor. +# Also cube actor is provided for each timeline to handle as follows: +# ``Animation(actor)``, ``Animation(list_of_actors)``, or actors can be added +# later using ``animation.add()`` or ``animation.add_actor()`` +anim_linear_color = Animation(actor.cube(cubes_pos[0])) +anim_LAB_color = Animation(actor.cube(cubes_pos[1])) +anim_HSV_color = Animation(actor.cube(cubes_pos[2])) +anim_XYZ_color = Animation(actor.cube(cubes_pos[3])) +anim_step_color = Animation(actor.cube(cubes_pos[4])) + +############################################################################### +# Creating a timeline to control all the animations (one for each color +# interpolation method) + +timeline = Timeline(playback_panel=True) + +############################################################################### +# Adding animations to a Timeline. +timeline.add_animation( + [anim_linear_color, anim_LAB_color, anim_HSV_color, anim_XYZ_color, anim_step_color] +) + +############################################################################### +# Setting color keyframes +# ======================= +# +# Setting the same color keyframes to all the animations + +############################################################################### +# First, we generate some distinguishable colors +colors = distinguishable_colormap(nb_colors=4) + +############################################################################### +# Then, we set them as keyframes for the animations +for t in range(0, 20, 5): + col = colors.pop() + anim_linear_color.set_color(t, col) + anim_LAB_color.set_color(t, col) + anim_HSV_color.set_color(t, col) + anim_XYZ_color.set_color(t, col) + anim_step_color.set_color(t, col) + +############################################################################### +# Changing the default scale interpolator to be a step interpolator +# The default is linear interpolator for color keyframes +anim_HSV_color.set_color_interpolator(hsv_color_interpolator) +anim_LAB_color.set_color_interpolator(lab_color_interpolator) +anim_step_color.set_color_interpolator(step_interpolator) +anim_XYZ_color.set_color_interpolator(xyz_color_interpolator) + +############################################################################### +# Adding the main timeline to the show manager +showm.add_animation(timeline) + +interactive = False + +if interactive: + showm.start() + +window.record(scene, out_path='viz_keyframe_animation_colors.png', size=(900, 768)) diff --git a/v0.10.x/_downloads/936d16e7edb5f588db3721c6df358491/viz_pbr_spheres.py b/v0.10.x/_downloads/936d16e7edb5f588db3721c6df358491/viz_pbr_spheres.py new file mode 100644 index 000000000..05f401b03 --- /dev/null +++ b/v0.10.x/_downloads/936d16e7edb5f588db3721c6df358491/viz_pbr_spheres.py @@ -0,0 +1,156 @@ +""" +=============================================================================== +Physically-Based Rendering (PBR) on spheres +=============================================================================== + +PBR engines aim to simulate properties of light when it interacts with objects +in the scene in a physically plausible way. The interaction of light with an +object depends on the material the object is made of. In computer graphics, +materials are usually divided in 2 main categories based on their conductive +properties: dielectrics and metals. + +This tutorial, illustrates how to model some material properties in FURY by +using the PBR material. + +Let's start by importing the necessary modules: +""" + +import numpy as np + +from fury import actor, material, window +from fury.utils import ( + normals_from_actor, + tangents_from_direction_of_anisotropy, + tangents_to_actor, +) + +############################################################################### +# Now set up a new scene. + +scene = window.Scene() +scene.background((0.9, 0.9, 0.9)) + +############################################################################### +# Let's define the parameters we are going to showcase in this tutorial. +# These subset of parameters have their values constrained in the 0 to 1 range. + +material_params = [ + [[1, 1, 0], {'metallic': 0, 'roughness': 0}], + [(0, 0, 1), {'roughness': 0}], + [(1, 0, 1), {'anisotropy': 0, 'metallic': 0.25, 'roughness': 0.5}], + [ + (1, 0, 1), + {'anisotropy_rotation': 0, 'anisotropy': 1, 'metallic': 0.25, 'roughness': 0.5}, + ], + [(0, 1, 1), {'coat_strength': 0, 'roughness': 0}], + [(0, 1, 1), {'coat_roughness': 0, 'coat_strength': 1, 'roughness': 0}], +] + +############################################################################### +# Now we can start to add our actors to the scene and see how different values +# of the parameters produce interesting effects. For the purpose of this +# tutorial, we will see the effect of 11 different values of each parameter. + +num_values = 11 + +for i, mp in enumerate(material_params): + color = mp[0] + params = mp[1] + center = [[0, -5 * i, 0]] + for j in range(num_values): + center[0][0] = -25 + 5 * j + sphere = actor.sphere(center, color, radii=2, theta=32, phi=32) + normals = normals_from_actor(sphere) + tangents = tangents_from_direction_of_anisotropy(normals, (0, 1, 0.5)) + tangents_to_actor(sphere, tangents) + keys = list(params) + params[keys[0]] = np.round(0.1 * j, decimals=1) + material.manifest_pbr(sphere, **params) + scene.add(sphere) + +############################################################################### +# For interpretability purposes we will add some labels to guide us through our +# visualization. + +labels = [ + 'Metallic', + 'Roughness', + 'Anisotropy', + 'Anisotropy Rotation', + 'Coat Strength', + 'Coat Roughness', +] + +for i, l in enumerate(labels): + pos = [-40, -5 * i, 0] + label = actor.vector_text(l, pos=pos, scale=(0.8, 0.8, 0.8), color=(0, 0, 0)) + scene.add(label) + +for j in range(num_values): + pos = [-26 + 5 * j, 3, 0] + label = actor.vector_text( + str(np.round(j * 0.1, decimals=1)), + pos=pos, + scale=(0.8, 0.8, 0.8), + color=(0, 0, 0), + ) + scene.add(label) + +############################################################################### +# Some parameters of this material have their values constrained to be between +# 1 and 2.3. These parameters are the Base Index of Refraction (IOR) and the +# Clear coat Index of Refraction (IOR). Therefore, we will interpolate some +# values within this range and see how they affect the rendering. + +iors = np.round(np.linspace(1, 2.3, num=num_values), decimals=2) + +ior_params = [ + [(0, 1, 1), {'base_ior': iors[0], 'roughness': 0}], + [ + (0, 1, 1), + { + 'coat_ior': iors[0], + 'coat_roughness': 0.1, + 'coat_strength': 1, + 'roughness': 0, + }, + ], +] + +for i, iorp in enumerate(ior_params): + color = iorp[0] + params = iorp[1] + center = [[0, -35 - (5 * i), 0]] + for j in range(num_values): + center[0][0] = -25 + 5 * j + sphere = actor.sphere(center, color, radii=2, theta=32, phi=32) + keys = list(params) + params[keys[0]] = iors[j] + material.manifest_pbr(sphere, **params) + scene.add(sphere) + +############################################################################### +# Let's add the respective labels to the scene. + +labels = ['Base IoR', 'Coat IoR'] + +for i, l in enumerate(labels): + pos = [-40, -35 - (5 * i), 0] + label = actor.vector_text(l, pos=pos, scale=(0.8, 0.8, 0.8), color=(0, 0, 0)) + scene.add(label) + +for j in range(num_values): + pos = [-26 + 5 * j, -32, 0] + label = actor.vector_text( + '{:.02f}'.format(iors[j]), pos=pos, scale=(0.8, 0.8, 0.8), color=(0, 0, 0) + ) + scene.add(label) + +############################################################################### +# Finally, let's visualize our tutorial. + +interactive = False +if interactive: + window.show(scene) + +window.record(scene, size=(600, 600), out_path='viz_pbr_spheres.png') diff --git a/v0.10.x/_downloads/981f106388beb4e1abc724788ab86b5a/viz_using_time_equations.ipynb b/v0.10.x/_downloads/981f106388beb4e1abc724788ab86b5a/viz_using_time_equations.ipynb new file mode 100644 index 000000000..7dc2e33a3 --- /dev/null +++ b/v0.10.x/_downloads/981f106388beb4e1abc724788ab86b5a/viz_using_time_equations.ipynb @@ -0,0 +1,151 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Keyframe animation\n\nTutorial on making keyframe-based animation in FURY using custom functions.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "import numpy as np\n\nfrom fury import actor, window\nfrom fury.animation import Animation\n\nscene = window.Scene()\n\nshowm = window.ShowManager(\n scene, size=(900, 768), reset_camera=False, order_transparent=True\n)\n\n\ncube = actor.cube(np.array([[0, 0, 0]]), (0, 0, 0), (1, 0, 1), scales=6)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Creating an ``Animation`` to animate the actor and show its motion path.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "anim = Animation(length=2 * np.pi, loop=True, motion_path_res=200)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Adding the sphere actor to the timeline\nThis could've been done during initialization.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "anim.add_actor(cube)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Creating time dependent functions.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def pos_eval(t):\n return np.array([np.sin(t), np.cos(t) * np.sin(t), 0]) * 15\n\n\ndef color_eval(t):\n return (\n np.array([np.sin(t), np.sin(t - 2 * np.pi / 3), np.sin(t + np.pi / 3)])\n + np.ones(3)\n ) / 2\n\n\ndef rotation_eval(t):\n return np.array([np.sin(t) * 360, np.cos(t) * 360, 0])\n\n\ndef scale_eval(t):\n return (\n np.array([np.sin(t), np.sin(t - 2 * np.pi / 3), np.sin(t + np.pi / 3)])\n + np.ones(3) * 2\n ) / 5" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Setting evaluator functions is the same as setting interpolators, but with\none extra argument: `is_evaluator=True` since these functions does not need\nkeyframes as input.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "anim.set_position_interpolator(pos_eval, is_evaluator=True)\nanim.set_rotation_interpolator(rotation_eval, is_evaluator=True)\nanim.set_color_interpolator(color_eval, is_evaluator=True)\nanim.set_interpolator('scale', scale_eval, is_evaluator=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "changing camera position to observe the animation better.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "scene.set_camera(position=(0, 0, 90))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Adding the animation to the show manager.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "showm.add_animation(anim)\n\n\ninteractive = False\n\nif interactive:\n showm.start()\n\nwindow.record(scene, out_path='viz_keyframe_animation_evaluators.png', size=(900, 768))" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.8" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/v0.10.x/_downloads/98eee32aa3111f6bc8b5b2a404686a66/viz_principled_spheres.ipynb b/v0.10.x/_downloads/98eee32aa3111f6bc8b5b2a404686a66/viz_principled_spheres.ipynb new file mode 100644 index 000000000..522d2ba08 --- /dev/null +++ b/v0.10.x/_downloads/98eee32aa3111f6bc8b5b2a404686a66/viz_principled_spheres.ipynb @@ -0,0 +1,133 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Principled BRDF shader on spheres\n\nThe Principled Bidirectional Reflectance Distribution Function ([BRDF]\n(https://en.wikipedia.org/wiki/Bidirectional_reflectance_distribution_function)\n) was introduced by Brent Burley as part of the [SIGGRAPH 2012 Physically Based\nShading course]\n(https://blog.selfshadow.com/publications/s2012-shading-course/). Although it\nis not strictly physically based, it was designed so the parameters included\ncould model materials in the [MERL 100](https://www.merl.com/brdf/) (Material\nExchange and Research Library) database. Moreover, each parameter was\ncarefully chosen and limited to be easy to use and understand, so that\nblending multiple layers together would give intuitive results.\n\nIn this demo, we showcase our implementation of the Principled BRDF in FURY.\n\nLet's start by importing the necessary modules:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "import numpy as np\n\nfrom fury import actor, material, window" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now set up a new scene.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "scene = window.Scene()\nscene.background((0.9, 0.9, 0.9))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's define the parameters needed for our demo. In this demo we will see the\neffect of each one of the 10 parameters defined by the Principled shader.\nFor interpretability and usability purposes, each parameter is limited to\nvalues between the range 0 to 1.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "material_params = [\n [(1, 1, 1), {'subsurface': 0}],\n [[1, 1, 0], {'metallic': 0}],\n [(1, 0, 0), {'specular': 0}],\n [(1, 0, 0), {'specular_tint': 0, 'specular': 1}],\n [(0, 0, 1), {'roughness': 0}],\n [(1, 0, 1), {'anisotropic': 0, 'metallic': 0.25, 'roughness': 0.5}],\n [[0, 1, 0.5], {'sheen': 0}],\n [(0, 1, 0.5), {'sheen_tint': 0, 'sheen': 1}],\n [(0, 1, 1), {'clearcoat': 0}],\n [(0, 1, 1), {'clearcoat_gloss': 0, 'clearcoat': 1}],\n]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can start to add our actors to the scene and see how different values of\nthe parameters produce interesting effects.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "for i in range(10):\n center = np.array([[0, -5 * i, 0]])\n for j in range(11):\n center[0][0] = -25 + 5 * j\n sphere = actor.sphere(\n center, colors=material_params[i][0], radii=2, theta=32, phi=32\n )\n keys = list(material_params[i][1])\n material_params[i][1][keys[0]] = np.round(0.1 * j, decimals=1)\n material.manifest_principled(sphere, **material_params[i][1])\n scene.add(sphere)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Finally, let's add some labels to guide us through our visualization.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "labels = [\n 'Subsurface',\n 'Metallic',\n 'Specular',\n 'Specular Tint',\n 'Roughness',\n 'Anisotropic',\n 'Sheen',\n 'Sheen Tint',\n 'Clearcoat',\n 'Clearcoat Gloss',\n]\n\nfor i in range(10):\n pos = [-40, -5 * i, 0]\n label = actor.vector_text(\n labels[i], pos=pos, scale=(0.8, 0.8, 0.8), color=(0, 0, 0)\n )\n scene.add(label)\n\nfor j in range(11):\n pos = [-26 + 5 * j, 5, 0]\n label = actor.vector_text(\n str(np.round(j * 0.1, decimals=1)),\n pos=pos,\n scale=(0.8, 0.8, 0.8),\n color=(0, 0, 0),\n )\n scene.add(label)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "And visualize our demo.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "interactive = False\nif interactive:\n window.show(scene)\n\nwindow.record(scene, size=(600, 600), out_path='viz_principled_spheres.png')" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.8" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/v0.10.x/_downloads/99010aa2e5b2ef6899c5427c758cd74d/viz_roi_contour.py b/v0.10.x/_downloads/99010aa2e5b2ef6899c5427c758cd74d/viz_roi_contour.py new file mode 100644 index 000000000..af3383ab1 --- /dev/null +++ b/v0.10.x/_downloads/99010aa2e5b2ef6899c5427c758cd74d/viz_roi_contour.py @@ -0,0 +1,100 @@ +""" +====================================================== +Visualization of ROI Surface Rendered with Streamlines +====================================================== + +Here is a simple tutorial following the probabilistic CSA Tracking Example in +which we generate a dataset of streamlines from a corpus callosum ROI, and +then display them with the seed ROI rendered in 3D with 50% transparency. +""" + +from dipy.data import default_sphere, read_stanford_labels +from dipy.direction import peaks_from_model +from dipy.reconst.shm import CsaOdfModel + +try: + from dipy.tracking.local import LocalTracking + from dipy.tracking.local import ( + ThresholdTissueClassifier as ThresholdStoppingCriterion, + ) +except ImportError: + from dipy.tracking.stopping_criterion import ThresholdStoppingCriterion + from dipy.tracking.local_tracking import LocalTracking + +from dipy.tracking import utils +from dipy.tracking.streamline import Streamlines + +from fury import actor, window +from fury.colormap import line_colors + +############################################################################### +# First, we need to generate some streamlines. For a more complete +# description of these steps, please refer to the CSA Probabilistic Tracking +# Tutorial. + +hardi_img, gtab, labels_img = read_stanford_labels() +data = hardi_img.get_fdata() +labels = labels_img.get_fdata() +affine = hardi_img.affine + +white_matter = (labels == 1) | (labels == 2) + +csa_model = CsaOdfModel(gtab, sh_order=6) +csa_peaks = peaks_from_model( + csa_model, + data, + default_sphere, + relative_peak_threshold=0.8, + min_separation_angle=45, + mask=white_matter, +) + +classifier = ThresholdStoppingCriterion(csa_peaks.gfa, 0.25) + +seed_mask = labels == 2 +seeds = utils.seeds_from_mask(seed_mask, density=[1, 1, 1], affine=affine) + +# Initialization of LocalTracking. The computation happens in the next step. +streamlines = LocalTracking(csa_peaks, classifier, seeds, affine, step_size=2) + +# Compute streamlines and store as a list. +streamlines = Streamlines(streamlines) + +############################################################################### +# We will create a streamline actor from the streamlines. + +streamlines_actor = actor.line(streamlines, line_colors(streamlines)) + +############################################################################### +# Next, we create a surface actor from the corpus callosum seed ROI. We +# provide the ROI data, the affine, the color in [R,G,B], and the opacity as +# a decimal between zero and one. Here, we set the color as blue/green with +# 50% opacity. + +surface_opacity = 0.5 +surface_color = [0, 1, 1] + +seedroi_actor = actor.contour_from_roi( + seed_mask, affine, surface_color, surface_opacity +) + +############################################################################### +# Next, we initialize a ''Scene'' object and add both actors +# to the rendering. + +scene = window.Scene() +scene.add(streamlines_actor) +scene.add(seedroi_actor) + +############################################################################### +# If you uncomment the following line, the rendering will pop up in an +# interactive window. + +interactive = False +if interactive: + window.show(scene) + +# scene.zoom(1.5) +# scene.reset_clipping_range() + +window.record(scene, out_path='contour_from_roi_tutorial.png', size=(600, 600)) diff --git a/v0.10.x/_downloads/996009d546f7601d36ae9c3eaf775bfb/viz_combobox.ipynb b/v0.10.x/_downloads/996009d546f7601d36ae9c3eaf775bfb/viz_combobox.ipynb new file mode 100644 index 000000000..691df2846 --- /dev/null +++ b/v0.10.x/_downloads/996009d546f7601d36ae9c3eaf775bfb/viz_combobox.ipynb @@ -0,0 +1,151 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# ComboBox\n\nThis example shows how to use the Combobox UI. We will demonstrate how to\ncreate ComboBoxes for selecting colors for a label.\n\nFirst, some imports.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "from fury import ui, window\nfrom fury.data import fetch_viz_icons" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "First we need to fetch some icons that are included in FURY.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "fetch_viz_icons()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "First, we create a label.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "label = ui.TextBlock2D(\n position=(200, 300),\n font_size=40,\n color=(1, 0.5, 0),\n justification='center',\n vertical_justification='top',\n text='FURY rocks!!!',\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we create a dictionary to store colors as its key and their\nRGB values as its value.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "colors = {\n 'Violet': (0.6, 0, 0.8),\n 'Indigo': (0.3, 0, 0.5),\n 'Blue': (0, 0, 1),\n 'Green': (0, 1, 0),\n 'Yellow': (1, 1, 0),\n 'Orange': (1, 0.5, 0),\n 'Red': (1, 0, 0),\n}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## ComboBox\n\nNow we create a ComboBox UI component for selecting colors.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "color_combobox = ui.ComboBox2D(\n items=list(colors.keys()),\n placeholder='Choose Text Color',\n position=(75, 50),\n size=(250, 150),\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Callbacks\n\nNow we create a callback for setting the chosen color.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def change_color(combobox):\n label.color = colors[combobox.selected_text]\n\n\n# `on_change` callback is set to `change_color` method so that\n# it's called whenever a different option is selected.\ncolor_combobox.on_change = change_color" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Show Manager\n\nNow we add label and combobox to the scene.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "current_size = (400, 400)\nshowm = window.ShowManager(size=current_size, title='ComboBox UI Example')\nshowm.scene.add(label, color_combobox)\n\n# To interact with the UI, set interactive = True\ninteractive = False\n\nif interactive:\n showm.start()\n\nwindow.record(showm.scene, out_path='combobox_ui.png', size=(400, 400))" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.8" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/v0.10.x/_downloads/9a0690581f35d885a20f1f0fa0068842/viz_widget.ipynb b/v0.10.x/_downloads/9a0690581f35d885a20f1f0fa0068842/viz_widget.ipynb new file mode 100644 index 000000000..aa5f7e2e8 --- /dev/null +++ b/v0.10.x/_downloads/9a0690581f35d885a20f1f0fa0068842/viz_widget.ipynb @@ -0,0 +1,79 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Streaming FURY with WebRTC/MJPEG using the Widget Object\n\nThe Widget Object simplifies the process of streaming\nyour data visualization with WebRTC or MJPEG. Encoding.\nOther users can view and interact with your data visualization\nin real-time using a web-browser.\n\nBy default, the widget will open a local server on port 8000.\nWith the encoding parameter you can choose between mjpeg or\nwebrtc. WebRTC is a more robust option and can be used to perform\na live streaming with a low-latency connection. However, to use\nwebRTC you need to install the aiortc library.\n\n```bash\npip install aiortc\n```\nIn addition, if you don't have ffmpeg installed, you need\nto install it.\n\nLinux\n\n\n`apt install libavdevice-dev libavfilter-dev libopus-dev libvpx-dev pkg-config`\n\nOS X\n\n`brew install ffmpeg opus libvpx pkg-config`\n\n## Notes\nFor this example your python version should be 3.8 or greater\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "import asyncio\nimport platform\nimport time\n\nimport numpy as np\n\nfrom fury import actor, window\nfrom fury.stream.widget import Widget\n\ninteractive = False\nwindow_size = (720, 500)\nN = 4\ncenters = np.random.normal(size=(N, 3))\ncolors = np.random.uniform(0.1, 1.0, size=(N, 3))\nactors = actor.sphere(centers, opacity=0.5, radii=0.4, colors=colors)\nscene = window.Scene()\nscene.add(actors)\nshowm = window.ShowManager(scene, size=(window_size[0], window_size[1]))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Create a stream widget\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "widget = Widget(showm, port=8000)\n\n# if you want to use webRTC, you can pass the argument to choose this encoding\n# which is a more robust option.\n# `widget = Widget(showm, port=8000, encoding='webrtc')`\n\ntime_sleep = 1000 if interactive else 1" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "If you want to use the widget in a Windows environment without the WSL\nyou need to use the asyncio version of the widget.\n\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "if platform.system() == 'Windows':\n\n async def main():\n widget.start()\n await asyncio.sleep(time_sleep)\n widget.stop()\n\n loop = asyncio.get_event_loop()\n loop.run_until_complete(main())\nelse:\n # Running the widget in a normal Python environment in Linux or MacOS\n # we can use the normal version of the widget.\n widget.start()\n time.sleep(time_sleep)\n widget.stop()\n\nwindow.record(showm.scene, size=window_size, out_path='viz_widget.png')" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.8" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/v0.10.x/_downloads/9e6be02794740496fc4184b942139604/viz_ui_slider.py b/v0.10.x/_downloads/9e6be02794740496fc4184b942139604/viz_ui_slider.py new file mode 100644 index 000000000..648d45dde --- /dev/null +++ b/v0.10.x/_downloads/9e6be02794740496fc4184b942139604/viz_ui_slider.py @@ -0,0 +1,152 @@ +# -*- coding: utf-8 -*- +""" +===================== +Cube & Slider Control +===================== + +This example shows how to use the UI API. We will demonstrate how to +create a cube and control with sliders. + +First, some imports. +""" +import numpy as np + +from fury import actor, ui, window +from fury.data import fetch_viz_icons + +############################################################################## +# First we need to fetch some icons that are included in FURY. + +fetch_viz_icons() + +############################################################################### +# Cube and sliders +# ================ +# +# Add a cube to the scene . + +cube = actor.cube( + centers=np.array([[15, 0, 0]]), + colors=np.array([[0, 0, 1]]), + scales=np.array([[20, 20, 20]]), + directions=np.array([[0, 0, 1]]), +) + +############################################################################### +# Now we'll add five sliders: 1 circular and 4 linear sliders. +# By default the alignments are 'bottom' for horizontal and 'top' for vertical. + +ring_slider = ui.RingSlider2D( + center=(630, 400), initial_value=0, text_template='{angle:5.1f}°' +) + +hor_line_slider_text_top = ui.LineSlider2D( + center=(400, 230), + initial_value=0, + orientation='horizontal', + min_value=-10, + max_value=10, + text_alignment='top', +) + +hor_line_slider_text_bottom = ui.LineSlider2D( + center=(400, 200), + initial_value=0, + orientation='horizontal', + min_value=-10, + max_value=10, + text_alignment='bottom', +) + +ver_line_slider_text_left = ui.LineSlider2D( + center=(100, 400), + initial_value=0, + orientation='vertical', + min_value=-10, + max_value=10, + text_alignment='left', +) + +ver_line_slider_text_right = ui.LineSlider2D( + center=(150, 400), + initial_value=0, + orientation='vertical', + min_value=-10, + max_value=10, + text_alignment='right', +) + + +############################################################################### +# We can use a callback to rotate the cube with the ring slider. + + +def rotate_cube(slider): + angle = slider.value + previous_angle = slider.previous_value + rotation_angle = angle - previous_angle + cube.RotateX(rotation_angle) + + +ring_slider.on_change = rotate_cube + +############################################################################### +# Similarly, we can translate the cube with the line slider. + + +def translate_cube_ver(slider): + value = slider.value + cube.SetPosition(0, value, 0) + + +def translate_cube_hor(slider): + value = slider.value + cube.SetPosition(value, 0, 0) + + +hor_line_slider_text_top.on_change = translate_cube_hor +hor_line_slider_text_bottom.on_change = translate_cube_hor +ver_line_slider_text_left.on_change = translate_cube_ver +ver_line_slider_text_right.on_change = translate_cube_ver + +############################################################################### +# Show Manager +# ================================== +# +# Now that all the elements have been initialised, we add them to the show +# manager. + +current_size = (800, 800) +show_manager = window.ShowManager(size=current_size, title='FURY Cube Example') + +show_manager.scene.add(cube) +show_manager.scene.add(ring_slider) +show_manager.scene.add(hor_line_slider_text_top) +show_manager.scene.add(hor_line_slider_text_bottom) +show_manager.scene.add(ver_line_slider_text_left) +show_manager.scene.add(ver_line_slider_text_right) + + +############################################################################### +# Visibility by default is True + +cube.SetVisibility(True) +ring_slider.set_visibility(True) +hor_line_slider_text_top.set_visibility(True) +hor_line_slider_text_bottom.set_visibility(True) +ver_line_slider_text_left.set_visibility(True) +ver_line_slider_text_right.set_visibility(True) + +############################################################################### +# Set camera for better visualization + +show_manager.scene.reset_camera() +show_manager.scene.set_camera(position=(0, 0, 150)) +show_manager.scene.reset_clipping_range() +show_manager.scene.azimuth(30) +interactive = False + +if interactive: + show_manager.start() + +window.record(show_manager.scene, size=current_size, out_path='viz_slider.png') diff --git a/v0.10.x/_downloads/9ebe900db14d7cf8291982cfd64a5eae/viz_introduction.py b/v0.10.x/_downloads/9ebe900db14d7cf8291982cfd64a5eae/viz_introduction.py new file mode 100644 index 000000000..86b5fa3d4 --- /dev/null +++ b/v0.10.x/_downloads/9ebe900db14d7cf8291982cfd64a5eae/viz_introduction.py @@ -0,0 +1,118 @@ +""" +=============================== +Keyframe animation introduction +=============================== + +This tutorial explains keyframe animation in FURY. +""" +############################################################################### +# Animations in FURY +# ================== +# +# FURY provides an easy-to-use animation system that enables users creating +# complex animations based on keyframes. +# The user only need to provide the attributes of actors at certain +# times (keyframes), and the system will take care of animating everything +# through interpolating between those keyframes. + + +############################################################################### +# What exactly is a keyframe +# ========================== +# +# A Keyframe is simply a marker of time which stores the value of a property. +# +# A keyframe consists of a timestamp and some data. These data can be anything +# such as temperature, position, or scale. + +############################################################################### +# What is Keyframe Animation +# ========================== +# +# Keyframe animations is a technique to simplify the process of animating a +# scene. +# Instead of providing the actor attributes for each frame, only a small amount +# of keyframes are needed to create a smooth animation. Each keyframe encodes +# the state of an actor at a certain timestamp. For instance a keyframe might +# define that an actor should be positioned at the origin (0,0,0) at the start +# of the animation. Another keyframe may define that the actor should move to +# position (1,0,0) after 10 seconds. The system will take care of interpolating +# the position of that actor between these two keyframes. +# +# Almost any parameter that you can set for FURY actors can be animated +# using keyframes. +# +# For example, a Keyframe might define that the position of a FURY actor is +# (0, 0, 0) at time equals 1 second. +# +# The goal of a Keyframe is to allow for interpolated animation, meaning, +# for example, that the user could then add another key at time equals 3 +# seconds, specifying the actor's position is (1, 1, 0), +# +# Then the correct position of the actor for all the times between 3 and 10 +# will be interpolated. +# +# For this tutorial, we are going to use the FURY animation module to translate +# FURY sphere actor. + + +import numpy as np + +from fury import actor, window +from fury.animation import Animation + +scene = window.Scene() + +showm = window.ShowManager(scene, size=(900, 768)) +showm.initialize() + + +############################################################################### +# Translating a sphere +# ==================== +# +# This is a quick demo showing how to translate a sphere from (0, 0, 0) to +# (1, 1, 1). +# First, we create an ``Animation``. See ``viz_interpolators.py`` tutorial +animation = Animation() + +############################################################################### +# We also create the FURY sphere actor that will be animated. +sphere = actor.sphere(np.zeros([1, 3]), np.ones([1, 3])) + +############################################################################### +# Then lets add the sphere actor to the ``Animation`` +animation.add_actor(sphere) + +############################################################################### +# Then, we set our position keyframes at different timestamps +# Here we want the sphere's position at the beginning to be [0, 0, 0]. And then +# at time equals 3 seconds to be at [1, 1, 0] then finally at the end +# (time equals 6) to return to the initial position which is [0, 0, 0] again. + +animation.set_position(0.0, [-1, -1, 0]) +animation.set_position(3.0, [1, 1, 0]) +animation.set_position(6.0, [-1, -1, 0]) + +############################################################################### +# The ``Animation`` must be added to the ``ShowManager`` as follows: +showm.add_animation(animation) +scene.camera().SetPosition(0, 0, 10) + +############################################################################### +# Animation can be added to the scene instead of the ``ShowManager`` but, the +# animation will need to be updated and then render the scene manually. + + +############################################################################### +# No need to add the sphere actor to scene, since it's now a part of the +# ``Animation``. + +interactive = False + +if interactive: + showm.start() + +window.record( + scene, out_path='viz_keyframe_animation_introduction.png', size=(900, 768) +) diff --git a/v0.10.x/_downloads/9f4f7e3dea1f0e152b6d0c2f88f21109/viz_introduction.ipynb b/v0.10.x/_downloads/9f4f7e3dea1f0e152b6d0c2f88f21109/viz_introduction.ipynb new file mode 100644 index 000000000..ea93b2b26 --- /dev/null +++ b/v0.10.x/_downloads/9f4f7e3dea1f0e152b6d0c2f88f21109/viz_introduction.ipynb @@ -0,0 +1,179 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Keyframe animation introduction\n\nThis tutorial explains keyframe animation in FURY.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Animations in FURY\n\nFURY provides an easy-to-use animation system that enables users creating\ncomplex animations based on keyframes.\nThe user only need to provide the attributes of actors at certain\ntimes (keyframes), and the system will take care of animating everything\nthrough interpolating between those keyframes.\n\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## What exactly is a keyframe\n\nA Keyframe is simply a marker of time which stores the value of a property.\n\nA keyframe consists of a timestamp and some data. These data can be anything\nsuch as temperature, position, or scale.\n\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## What is Keyframe Animation\n\nKeyframe animations is a technique to simplify the process of animating a\nscene.\nInstead of providing the actor attributes for each frame, only a small amount\nof keyframes are needed to create a smooth animation. Each keyframe encodes\nthe state of an actor at a certain timestamp. For instance a keyframe might\ndefine that an actor should be positioned at the origin (0,0,0) at the start\nof the animation. Another keyframe may define that the actor should move to\nposition (1,0,0) after 10 seconds. The system will take care of interpolating\nthe position of that actor between these two keyframes.\n\nAlmost any parameter that you can set for FURY actors can be animated\nusing keyframes.\n\nFor example, a Keyframe might define that the position of a FURY actor is\n(0, 0, 0) at time equals 1 second.\n\nThe goal of a Keyframe is to allow for interpolated animation, meaning,\nfor example, that the user could then add another key at time equals 3\nseconds, specifying the actor's position is (1, 1, 0),\n\nThen the correct position of the actor for all the times between 3 and 10\nwill be interpolated.\n\nFor this tutorial, we are going to use the FURY animation module to translate\nFURY sphere actor.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "import numpy as np\n\nfrom fury import actor, window\nfrom fury.animation import Animation\n\nscene = window.Scene()\n\nshowm = window.ShowManager(scene, size=(900, 768))\nshowm.initialize()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Translating a sphere\n\nThis is a quick demo showing how to translate a sphere from (0, 0, 0) to\n(1, 1, 1).\nFirst, we create an ``Animation``. See ``viz_interpolators.py`` tutorial\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "animation = Animation()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We also create the FURY sphere actor that will be animated.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "sphere = actor.sphere(np.zeros([1, 3]), np.ones([1, 3]))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Then lets add the sphere actor to the ``Animation``\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "animation.add_actor(sphere)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Then, we set our position keyframes at different timestamps\nHere we want the sphere's position at the beginning to be [0, 0, 0]. And then\nat time equals 3 seconds to be at [1, 1, 0] then finally at the end\n(time equals 6) to return to the initial position which is [0, 0, 0] again.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "animation.set_position(0.0, [-1, -1, 0])\nanimation.set_position(3.0, [1, 1, 0])\nanimation.set_position(6.0, [-1, -1, 0])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The ``Animation`` must be added to the ``ShowManager`` as follows:\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "showm.add_animation(animation)\nscene.camera().SetPosition(0, 0, 10)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Animation can be added to the scene instead of the ``ShowManager`` but, the\nanimation will need to be updated and then render the scene manually.\n\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "No need to add the sphere actor to scene, since it's now a part of the\n``Animation``.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "interactive = False\n\nif interactive:\n showm.start()\n\nwindow.record(\n scene, out_path='viz_keyframe_animation_introduction.png', size=(900, 768)\n)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.8" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/v0.10.x/_downloads/a45e245b3472717786fb1ffc09a9f1c5/viz_dt_ellipsoids.ipynb b/v0.10.x/_downloads/a45e245b3472717786fb1ffc09a9f1c5/viz_dt_ellipsoids.ipynb new file mode 100644 index 000000000..ddfaa7d7a --- /dev/null +++ b/v0.10.x/_downloads/a45e245b3472717786fb1ffc09a9f1c5/viz_dt_ellipsoids.ipynb @@ -0,0 +1,349 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Display Tensor Ellipsoids for DTI using tensor_slicer vs ellipsoid actor\nThis tutorial is intended to show two ways of displaying diffusion tensor\nellipsoids for DTI visualization. The first is using the usual\n``tensor_slicer`` that allows us to slice many tensors as ellipsoids. The\nsecond is the generic ``ellipsoid`` actor that can be used to display different\namount of ellipsoids.\n\nWe start by importing the necessary modules:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "import itertools\n\nimport numpy as np\n\nfrom dipy.io.image import load_nifti\n\nfrom fury import window, actor, ui\nfrom fury.actor import _fa, _color_fa\nfrom fury.data import fetch_viz_dmri, read_viz_dmri\nfrom fury.primitive import prim_sphere" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now, we fetch and load the data needed to display the Diffusion Tensor\nImages.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "fetch_viz_dmri()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The tensor ellipsoids are expressed as eigenvalues and eigenvectors which are\nthe decomposition of the diffusion tensor that describes the water diffusion\nwithin a voxel.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "slice_evecs, _ = load_nifti(read_viz_dmri('slice_evecs.nii.gz'))\nslice_evals, _ = load_nifti(read_viz_dmri('slice_evals.nii.gz'))\nroi_evecs, _ = load_nifti(read_viz_dmri('roi_evecs.nii.gz'))\nroi_evals, _ = load_nifti(read_viz_dmri('roi_evals.nii.gz'))\nwhole_brain_evecs, _ = load_nifti(read_viz_dmri('whole_brain_evecs.nii.gz'))\nwhole_brain_evals, _ = load_nifti(read_viz_dmri('whole_brain_evals.nii.gz'))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Using tensor_slicer actor\nFirst we must define the 3 parameters needed to use the ``tensor_slicer``\nactor, which correspond to the eigenvalues, the eigenvectors, and the sphere.\nFor the sphere we use ``prim_sphere`` which provide vertices and triangles of\nthe spheres. These are labeled as 'repulsionN' with N been the number of\nvertices that made up the sphere, which have a standard number of 100, 200,\nand 724 vertices.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "vertices, faces = prim_sphere('repulsion100', True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As we need to provide a sphere object we create a class Sphere to which we\nassign the values obtained from vertices and faces.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "class Sphere:\n def __init__(self, vertices, faces):\n self.vertices = vertices\n self.faces = faces\n\n\nsphere100 = Sphere(vertices, faces)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we are ready to create the ``tensor_slicer`` actor with the values of a\nbrain slice. We also define the scale so that the tensors are not so large\nand overlap each other.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "tensor_slice = actor.tensor_slicer(evals=slice_evals, evecs=slice_evecs,\n sphere=sphere100, scale=.3)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Next, we set up a new scene to add and visualize the tensor ellipsoids\ncreated.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "scene = window.Scene()\nscene.background([255, 255, 255])\nscene.add(tensor_slice)\n\n# Create show manager\nshowm = window.ShowManager(scene, size=(600, 600))\n\n# Enables/disables interactive visualization\ninteractive = False\n\nif interactive:\n showm.start()\n\nwindow.record(showm.scene, size=(600, 600), out_path='tensor_slice_100.png')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "If we zoom in at the scene to see with detail the tensor ellipsoids displayed\nwith the different spheres, we get the following results.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "scene.roll(10)\nscene.pitch(90)\nshowm = window.ShowManager(scene, size=(600, 600), order_transparent=True)\nshowm.scene.zoom(50)\n\nif interactive:\n showm.render()\n showm.start()\n\nwindow.record(showm.scene, out_path='tensor_slice_100_zoom.png',\n size=(600, 300), reset_camera=False)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To render the same tensor slice using a different sphere we redefine the\nvertices and faces of the sphere using prim_sphere with other sphere\nspecification, as 'repulsion200' or 'repulsion724'.\n\nNow we clear the scene for the next visualization, and revert the scene\nrotations.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "showm.scene.clear()\nshowm.scene.pitch(-90)\nshowm.scene.roll(-10)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Using ellipsoid actor\nIn order to use the ``ellipsoid`` actor to display the same tensor slice we\nneed to set additional parameters. For this purpose, we define a helper\nfunction to facilitate the correct setting of the parameters before passing\nthem to the actor.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def get_params(evecs, evals):\n # We define the centers which corresponds to the ellipsoids positions.\n valid_mask = np.abs(evecs).max(axis=(-2, -1)) > 0\n indices = np.nonzero(valid_mask)\n centers = np.asarray(indices).T\n\n # We need to pass the data of the axes and lengths of the ellipsoid as a\n # ndarray, so it is necessary to rearrange the data of the eigenvectors and\n # eigenvalues.\n fevecs = evecs[indices]\n fevals = evals[indices]\n\n # We need to define the colors of the ellipsoids following the default\n # coloring in tensor_slicer that is uses _color_fa that is a way to map\n # colors to each tensor based on the fractional anisotropy (FA) of each\n # diffusion tensor.\n colors = _color_fa(_fa(fevals), fevecs)\n\n return centers, fevecs, fevals, colors" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "With this we now have the values we need to define the centers, axes,\nlengths, and colors of the ellipsoids.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "centers, evecs, evals, colors = get_params(slice_evecs, slice_evals)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now, we can use the ``ellipsoid`` actor to create the tensor ellipsoids as\nfollows.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "tensors = actor.ellipsoid(centers=centers, colors=colors, axes=evecs,\n lengths=evals, scales=.6)\nshowm.scene.add(tensors)\n\nif interactive:\n showm.start()\n\nwindow.record(scene, size=(600, 600), out_path='tensor_slice_sdf.png')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Thus, one can see that the same result is obtained, however there is a\ndifference in the visual quality and this is because the ``ellipsoid`` actor\nuses raymarching technique, so the objects that are generated are smoother\nsince they are not made with polygons but defined by an SDF function. Next we\ncan see in more detail the tensor ellipsoids generated.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "scene.roll(10)\nscene.pitch(90)\nshowm = window.ShowManager(scene, size=(600, 600), order_transparent=True)\nshowm.scene.zoom(50)\n\nif interactive:\n showm.render()\n showm.start()\n\nwindow.record(showm.scene, out_path='tensor_slice_sdf_zoom.png',\n size=(600, 300), reset_camera=False)\n\nshowm.scene.clear()\nshowm.scene.pitch(-90)\nshowm.scene.roll(-10)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Visual quality comparison\nOne can see that there is a different on the visual quality of both ways of\ndisplaying tensors and this is because ``tensor_slicer`` uses polygons while\n``ellipsoid`` uses raymarching. Let's display both implementations at the\nsame time, so we can see this in more detail.\n\nWe first set up the required data and create the actors.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "mevals = np.array([1.4, 1.0, 0.35]) * 10 ** (-3)\nmevecs = np.array([[2/3, -2/3, 1/3], [1/3, 2/3, 2/3], [2/3, 1/3, -2/3]])\n\nevals = np.zeros((1, 1, 1, 3))\nevecs = np.zeros((1, 1, 1, 3, 3))\n\nevals[..., :] = mevals\nevecs[..., :, :] = mevecs\n\nvertices, faces = prim_sphere('repulsion200', True)\nsphere200 = Sphere(vertices, faces)\nvertices, faces = prim_sphere('repulsion724', True)\nsphere724 = Sphere(vertices, faces)\n\ntensor_100 = actor.tensor_slicer(evals=evals, evecs=evecs,\n sphere=sphere100, scale=1.0)\ntensor_200 = actor.tensor_slicer(evals=evals, evecs=evecs,\n sphere=sphere200, scale=1.0)\ntensor_724 = actor.tensor_slicer(evals=evals, evecs=evecs,\n sphere=sphere724, scale=1.0)\n\ncenters, evecs, evals, colors = get_params(evecs=evecs, evals=evals)\ntensor_sdf = actor.ellipsoid(centers=centers, axes=evecs, lengths=evals,\n colors=colors, scales=2.0)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Next, we made use of `GridUI` which allows us to add the actors in a grid and\ninteract with them individually.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "objects = [tensor_100, tensor_200, tensor_724, tensor_sdf]\ntext = [actor.vector_text('Tensor 100'), actor.vector_text('Tensor 200'),\n actor.vector_text('Tensor 724'), actor.vector_text('Tensor SDF')]\n\ngrid_ui = ui.GridUI(actors=objects, captions=text, cell_padding=.1,\n caption_offset=(-0.7, -2.5, 0), dim=(1, 4))\n\nscene = window.Scene()\nscene.background([255, 255, 255])\nscene.zoom(3.5)\nscene.set_camera(position=(3.2, -20, 12), focal_point=(3.2, 0.0, 0.0))\nshowm = window.ShowManager(scene, size=(560, 200))\nshowm.scene.add(grid_ui)\n\nif interactive:\n showm.start()\n\nwindow.record(showm.scene, size=(560, 200), out_path='tensor_comparison.png',\n reset_camera=False, magnification=2)\n\nshowm.scene.clear()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Visualize a larger amount of data\nWith ``tensor_slicer`` is possible to visualize more than one slice using\n``display_extent()``. Here we can see an example of a region of interest\n(ROI) using a sphere of 100 vertices.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "tensor_roi = actor.tensor_slicer(evals=roi_evals, evecs=roi_evecs,\n sphere=sphere100, scale=.3)\n\ndata_shape = roi_evals.shape[:3]\ntensor_roi.display_extent(\n 0, data_shape[0], 0, data_shape[1], 0, data_shape[2])\n\nshowm.size = (600, 600)\nshowm.scene.background([0, 0, 0])\nshowm.scene.add(tensor_roi)\nshowm.scene.azimuth(87)\n\nif interactive:\n showm.start()\n\nwindow.record(showm.scene, size=(600, 600), out_path='tensor_roi_100.png')\n\nshowm.scene.clear()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can do it also with a sphere of 200 vertices, but if we try to do it with\none of 724 the visualization can no longer be rendered. In contrast, we can\nvisualize the ROI with the ``ellipsoid`` actor without compromising the\nquality of the visualization.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "centers, evecs, evals, colors = get_params(roi_evecs, roi_evals)\n\ntensors = actor.ellipsoid(centers=centers, colors=colors, axes=evecs,\n lengths=evals, scales=.6)\nshowm.scene.add(tensors)\n\nif interactive:\n showm.start()\n\nwindow.record(showm.scene, size=(600, 600), out_path='tensor_roi_sdf.png')\n\nshowm.scene.clear()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In fact, although with a low performance, this actor allows us to visualize\nthe whole brain, which contains a much larger amount of data, to be exact\n184512 tensor ellipsoids are displayed at the same time.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "centers, evecs, evals, colors = get_params(whole_brain_evecs,\n whole_brain_evals)\n\n# We remove all the noise around the brain to have a better visualization.\nfil = [len(set(elem)) != 1 for elem in evals]\ncenters = np.array(list(itertools.compress(centers, fil)))\ncolors = np.array(list(itertools.compress(colors, fil)))\nevecs = np.array(list(itertools.compress(evecs, fil)))\nevals = np.array(list(itertools.compress(evals, fil)))\n\ntensors = actor.ellipsoid(centers=centers, colors=colors, axes=evecs,\n lengths=evals, scales=.6)\n\nscene = window.Scene()\nscene.add(tensors)\nscene.pitch(180)\nshowm = window.ShowManager(scene, size=(600, 600))\n\nif interactive:\n showm.start()\n\nwindow.record(showm.scene, size=(600, 600), reset_camera=False,\n out_path='tensor_whole_brain_sdf.png')\n\nshowm.scene.clear()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.8" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/v0.10.x/_downloads/a58ef38299540de6143bfa8bdf807686/viz_helical_motion.py b/v0.10.x/_downloads/a58ef38299540de6143bfa8bdf807686/viz_helical_motion.py new file mode 100644 index 000000000..891bffeb0 --- /dev/null +++ b/v0.10.x/_downloads/a58ef38299540de6143bfa8bdf807686/viz_helical_motion.py @@ -0,0 +1,169 @@ +""" +====================================================================== +Motion of a charged particle in a combined magnetic and electric field +====================================================================== + +A charged particle follows a curved path in a magnetic field. +In an electric field, the particle tends to accelerate in a direction +parallel/antiparallel to the electric field depending on the nature of +charge on the particle. In a combined electric and magnetic field, +the particle moves along a helical path. + +In this animation, there's a magnetic and an electric field present in +x +direction under whose influence the positively charged particle follows a +helical path. + +Importing necessary modules +""" + +import itertools + +import numpy as np + +from fury import actor, ui, utils, window + +############################################################################### +# Let's define some variable and their description: +# +# * `radius_particle`: radius of the point that will represent the particle +# (default = 0.08) +# * `initial_velocity`: initial velocity of the particle along +x +# (default = 0.09) +# * `acc`: acceleration of the particle along +x (due to the electric field) +# (default = 0.004) +# * `time`: time (default time i.e. time at beginning of the animation = 0) +# * `incre_time`: value by which time is incremented for each call of +# timer_callback (default = 0.09) +# * `angular_frq`: angular frequency (default = 0.1) +# * `phase_angle`: phase angle (default = 0.002) +# + +radius_particle = 0.08 +initial_velocity = 0.09 +acc = 0.004 +time = 0 +incre_time = 0.09 +angular_frq = 0.1 +phase_angle = 0.002 + + +############################################################################### +# Creating a scene object and configuring the camera's position + +scene = window.Scene() +scene.zoom(1.2) +scene.set_camera( + position=(10, 12.5, 19), focal_point=(3.0, 0.0, 0.0), view_up=(0.0, 0.0, 0.0) +) +showm = window.ShowManager( + scene, size=(800, 600), reset_camera=True, order_transparent=True +) + + +############################################################################### +# Creating a blue colored arrow which shows the direction of magnetic field and +# electric field. + +color_arrow = window.colors.blue # color of the arrow can be manipulated +centers = np.array([[0, 0, 0]]) +directions = np.array([[1, 0, 0]]) +heights = np.array([8]) +arrow_actor = actor.arrow( + centers, + directions, + color_arrow, + heights, + resolution=20, + tip_length=0.06, + tip_radius=0.012, + shaft_radius=0.005, +) +scene.add(arrow_actor) + +############################################################################### +# Initializing the initial coordinates of the particle + +x = initial_velocity * time + 0.5 * acc * (time**2) +y = np.sin(angular_frq * time + phase_angle) +z = np.cos(angular_frq * time + phase_angle) + +############################################################################### +# Initializing point actor which will represent the charged particle + +color_particle = window.colors.red # color of particle can be manipulated +pts = np.array([[x, y, z]]) +charge_actor = actor.point(pts, color_particle, point_radius=radius_particle) +scene.add(charge_actor) + +vertices = utils.vertices_from_actor(charge_actor) +vcolors = utils.colors_from_actor(charge_actor, 'colors') +no_vertices_per_point = len(vertices) +initial_vertices = vertices.copy() - np.repeat(pts, no_vertices_per_point, axis=0) + + +############################################################################### +# Initializing text box to display the name of the animation + +tb = ui.TextBlock2D(bold=True, position=(100, 90)) +m1 = 'Motion of a charged particle in a ' +m2 = 'combined electric and magnetic field' +tb.message = m1 + m2 +scene.add(tb) + +############################################################################### +# Initializing counter + +counter = itertools.count() + +############################################################################### +# end is used to decide when to end the animation + +end = 200 + +############################################################################### +# This will be useful for plotting path of the particle + +coor_1 = np.array([0, 0, 0]) + + +############################################################################### +# Coordinates to be plotted are changed every time timer_callback is called by +# using the update_coordinates function. The wave is rendered here. + + +def timer_callback(_obj, _event): + global pts, time, incre_time, coor_1 + time += incre_time + cnt = next(counter) + + x = initial_velocity * time + 0.5 * acc * (time**2) + y = np.sin(10 * angular_frq * time + phase_angle) + z = np.cos(10 * angular_frq * time + phase_angle) + pts = np.array([[x, y, z]]) + + vertices[:] = initial_vertices + np.repeat(pts, no_vertices_per_point, axis=0) + + utils.update_actor(charge_actor) + + # Plotting the path followed by the particle + coor_2 = np.array([x, y, z]) + coors = np.array([coor_1, coor_2]) + coors = [coors] + line_actor = actor.line(coors, window.colors.cyan, linewidth=3) + scene.add(line_actor) + coor_1 = coor_2 + + showm.render() + + # to end the animation + if cnt == end: + showm.exit() + + +############################################################################### +# Run every 15 milliseconds + + +showm.add_timer_callback(True, 15, timer_callback) +showm.start() +window.record(showm.scene, size=(800, 600), out_path='viz_helical_motion.png') diff --git a/v0.10.x/_downloads/a9863b01fd713ba2099ade0ba562729a/viz_chain.py b/v0.10.x/_downloads/a9863b01fd713ba2099ade0ba562729a/viz_chain.py new file mode 100644 index 000000000..f9898c240 --- /dev/null +++ b/v0.10.x/_downloads/a9863b01fd713ba2099ade0ba562729a/viz_chain.py @@ -0,0 +1,265 @@ +""" +===================== +Chain Simulation +===================== + +This example simulation shows how to use pybullet to render physics simulations +in fury. In this example we specifically render a Chain oscillating to and from. + +First some imports. +""" +import itertools + +import numpy as np +import pybullet as p + +from fury import actor, ui, utils, window + +############################################################################### +# Setup pybullet and add gravity. + +p.connect(p.DIRECT) + +# Apply gravity to the scene. +p.setGravity(0, 0, -10) + +############################################################################### +# Now we render the Chain using the following parameters and definitions. + +# Parameters +n_links = 20 +dx_link = 0.1 # Size of segments +link_mass = 0.5 +base_mass = 0.1 +radii = 0.5 + +joint_friction = 0.0005 # rotational joint friction [N/(rad/s)] + +link_shape = p.createCollisionShape( + p.GEOM_CYLINDER, + radius=radii, + height=dx_link, + collisionFramePosition=[0, 0, -dx_link / 2], +) + +base_shape = p.createCollisionShape(p.GEOM_BOX, halfExtents=[0.01, 0.01, 0.01]) + +visualShapeId = -1 + +link_Masses = np.zeros(n_links) +link_Masses[:] = link_mass + +linkCollisionShapeIndices = np.zeros(n_links) +linkCollisionShapeIndices[:] = np.array(link_shape) +linkVisualShapeIndices = -1 * np.ones(n_links) +linkPositions = np.zeros((n_links, 3)) +linkPositions[:] = np.array([0, 0, -dx_link]) +linkOrientations = np.zeros((n_links, 4)) +linkOrientations[:] = np.array([0, 0, 0, 1]) +linkInertialFramePositions = np.zeros((n_links, 3)) +linkInertialFrameOrns = np.zeros((n_links, 4)) +linkInertialFrameOrns[:] = np.array([0, 0, 0, 1]) +indices = np.arange(n_links) +jointTypes = np.zeros(n_links) +jointTypes[:] = np.array(p.JOINT_SPHERICAL) +axis = np.zeros((n_links, 3)) +axis[:] = np.array([1, 0, 0]) + +linkDirections = np.zeros((n_links, 3)) +linkDirections[:] = np.array([1, 1, 1]) + +link_radii = np.zeros(n_links) +link_radii[:] = radii + +link_heights = np.zeros(n_links) +link_heights[:] = dx_link + +rope_actor = actor.cylinder( + centers=linkPositions, + directions=linkDirections, + colors=np.random.rand(n_links, 3), + radius=radii, + heights=link_heights, + capped=True, +) + +basePosition = [0, 0, 2] +baseOrientation = [0, 0, 0, 1] +rope = p.createMultiBody( + base_mass, + base_shape, + visualShapeId, + basePosition, + baseOrientation, + linkMasses=link_Masses, + linkCollisionShapeIndices=linkCollisionShapeIndices.astype(int), + linkVisualShapeIndices=linkVisualShapeIndices.astype(int), + linkPositions=linkPositions, + linkOrientations=linkOrientations, + linkInertialFramePositions=linkInertialFramePositions, + linkInertialFrameOrientations=linkInertialFrameOrns, + linkParentIndices=indices.astype(int), + linkJointTypes=jointTypes.astype(int), + linkJointAxis=axis.astype(int), +) + +############################################################################### +# We remove stiffness among the joints by adding friction to them. + +friction_vec = [joint_friction] * 3 # same all axis +control_mode = p.POSITION_CONTROL # set pos control mode +for j in range(p.getNumJoints(rope)): + p.setJointMotorControlMultiDof( + rope, + j, + control_mode, + targetPosition=[0, 0, 0, 1], + targetVelocity=[0, 0, 0], + positionGain=0, + velocityGain=1, + force=friction_vec, + ) + +############################################################################### +# Next, we define a constraint base that will help us in the oscillation of the +# chain. + +root_robe_c = p.createConstraint( + rope, -1, -1, -1, p.JOINT_FIXED, [0, 0, 0], [0, 0, 0], [0, 0, 2] +) + +# some traj to inject motion +amplitude_x = 0.3 +amplitude_y = 0.0 +freq = 0.6 + +base_actor = actor.box( + centers=np.array([[0, 0, 0]]), + directions=np.array([[0, 0, 0]]), + scales=(0.02, 0.02, 0.02), + colors=np.array([[1, 0, 0]]), +) + +############################################################################### +# We add the necessary actors to the scene. + +scene = window.Scene() +scene.background((1, 1, 1)) +scene.set_camera((2.2, -3.0, 3.0), (-0.3, 0.6, 0.7), (-0.2, 0.2, 1.0)) +scene.add(actor.axes(scale=(0.1, 0.1, 0.1))) +scene.add(rope_actor) +scene.add(base_actor) + +# Create show manager. +showm = window.ShowManager( + scene, size=(900, 768), reset_camera=False, order_transparent=True +) + + +# Counter iterator for tracking simulation steps. +counter = itertools.count() + + +############################################################################### +# We define a couple of syncing methods for the base and chain. + +# Function for syncing actors with multi-bodies. +def sync_actor(actor, multibody): + pos, orn = p.getBasePositionAndOrientation(multibody) + actor.SetPosition(*pos) + orn_deg = np.degrees(p.getEulerFromQuaternion(orn)) + actor.SetOrientation(*orn_deg) + + +vertices = utils.vertices_from_actor(rope_actor) +num_vertices = vertices.shape[0] +num_objects = linkPositions.shape[0] +sec = int(num_vertices / num_objects) + + +def sync_joints(actor_list, multibody): + for joint in range(p.getNumJoints(multibody)): + # `p.getLinkState` offers various information about the joints + # as a list and the values in 4th and 5th index refer to the joint's + # position and orientation respectively. + pos, orn = p.getLinkState(multibody, joint)[4:6] + + rot_mat = np.reshape( + p.getMatrixFromQuaternion( + p.getDifferenceQuaternion(orn, linkOrientations[joint]) + ), + (3, 3), + ) + + vertices[joint * sec : joint * sec + sec] = ( + vertices[joint * sec : joint * sec + sec] - linkPositions[joint] + ) @ rot_mat + pos + + linkPositions[joint] = pos + linkOrientations[joint] = orn + + +############################################################################### +# We define a TextBlock to display the Avg. FPS and Simulation steps. + +fpss = np.array([]) +tb = ui.TextBlock2D( + position=(0, 680), font_size=30, color=(1, 0.5, 0), text='Avg. FPS: \nSim Steps: ' +) +scene.add(tb) + +t = 0.0 +freq_sim = 240 + + +############################################################################### +# Timer callback to sync objects, simulate steps and oscillate the base. + + +def timer_callback(_obj, _event): + cnt = next(counter) + global t, fpss + showm.render() + + t += 1.0 / freq_sim + + if cnt % 1 == 0: + fps = showm.frame_rate + fpss = np.append(fpss, fps) + tb.message = ( + 'Avg. FPS: ' + str(np.round(np.mean(fpss), 0)) + '\nSim Steps: ' + str(cnt) + ) + + # some trajectory + ux = amplitude_x * np.sin(2 * np.pi * freq * t) + uy = amplitude_y * np.cos(2 * np.pi * freq * t) + + # move base around + pivot = [3 * ux, uy, 2] + orn = p.getQuaternionFromEuler([0, 0, 0]) + p.changeConstraint(root_robe_c, pivot, jointChildFrameOrientation=orn, maxForce=500) + + # Sync base and chain. + sync_actor(base_actor, rope) + sync_joints(rope_actor, rope) + utils.update_actor(rope_actor) + + # Simulate a step. + p.stepSimulation() + + # Exit after 2000 steps of simulation. + if cnt == 130: + showm.exit() + + +# Add the timer callback to showmanager. +# Increasing the duration value will slow down the simulation. +showm.add_timer_callback(True, 1, timer_callback) + +interactive = False + +# start simulation +if interactive: + showm.start() + +window.record(scene, size=(900, 768), out_path='viz_chain.png') diff --git a/v0.10.x/_downloads/adb09d2c560f3f2aad083f096adc3f3d/viz_animated_surfaces.ipynb b/v0.10.x/_downloads/adb09d2c560f3f2aad083f096adc3f3d/viz_animated_surfaces.ipynb new file mode 100644 index 000000000..b6c3e88b1 --- /dev/null +++ b/v0.10.x/_downloads/adb09d2c560f3f2aad083f096adc3f3d/viz_animated_surfaces.ipynb @@ -0,0 +1,302 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Animated 2D functions\n\nThis is a simple demonstration of how one can\nanimate 2D functions using FURY.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Importing necessary modules\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "import itertools\n\nimport numpy as np\n\nfrom fury import actor, colormap, ui, utils, window" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The following function is used to create and update the coordinates of the\npoints which are being used to plot the surface. It's also used to create\nand update the colormap being used to color the surface.\nKindly note that only the z coordinate is being modified with time as only\nthe z coordinate is a function of time.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def update_surface(x, y, equation, cmap_name='viridis'):\n\n # z is the function F i.e. F(x, y, t)\n z = eval(equation)\n xyz = np.vstack([x, y, z]).T\n\n # creating the colormap\n v = np.copy(z)\n m_v = np.max(np.abs(v), axis=0)\n v /= m_v if m_v else 1\n colors = colormap.create_colormap(v, name=cmap_name)\n\n return xyz, colors" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Variables and their usage:\n:time - float: initial value of the time variable i.e. value of the time variable at\n the beginning of the program; (default = 0)\ndt: float\n amount by which ``time`` variable is incremented for every iteration\n of timer_callback function (default = 0.1)\nlower_xbound: float\n lower bound of the x values in which the function is plotted\n (default = -1)\nupper_xbound: float\n Upper bound of the x values in which the function is plotted\n (default = 1)\nlower_ybound: float\n lower bound of the y values in which the function is plotted\n (default = -1)\nupper_ybound: float\n Upper bound of the y values in which the function is plotted\n (default = 1)\nnpoints: int\n For high quality rendering, keep the number high but kindly note\n that higher values for npoints slows down the animation\n (default = 128)\n\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "time = 0\ndt = 0.1\nlower_xbound = -1\nupper_xbound = 1\nlower_ybound = -1\nupper_ybound = 1\nnpoints = 128" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "creating the x, y points which will be used to fit the equation to get\nelevation and generate the surface\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "x = np.linspace(lower_xbound, upper_xbound, npoints)\ny = np.linspace(lower_ybound, upper_ybound, npoints)\nx, y = np.meshgrid(x, y)\nx = x.reshape(-1)\ny = y.reshape(-1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Function used to create surface obtained from 2D equation.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def create_surface(x, y, equation, colormap_name):\n xyz, colors = update_surface(x, y, equation=equation, cmap_name=colormap_name)\n surf = actor.surface(xyz, colors=colors)\n surf.equation = equation\n surf.cmap_name = colormap_name\n surf.vertices = utils.vertices_from_actor(surf)\n surf.no_vertices_per_point = len(surf.vertices) / npoints**2\n surf.initial_vertices = surf.vertices.copy() - np.repeat(\n xyz, surf.no_vertices_per_point, axis=0\n )\n return surf" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Equations to be plotted\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "eq1 = 'np.abs(np.sin(x*2*np.pi*np.cos(time/2)))**1*np.cos(time/2)*\\\n np.abs(np.cos(y*2*np.pi*np.sin(time/2)))**1*np.sin(time/2)*1.2'\neq2 = '((x**2 - y**2)/(x**2 + y**2))**(2)*np.cos(6*np.pi*x*y-1.8*time)*0.24'\neq3 = '(np.sin(np.pi*2*x-np.sin(1.8*time))*np.cos(np.pi*2*y+np.cos(1.8*time)))\\\n *0.48'\neq4 = 'np.cos(24*np.sqrt(x**2 + y**2) - 2*time)*0.18'\nequations = [eq1, eq2, eq3, eq4]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "List of colormaps to be used for the various functions.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "cmap_names = ['hot', 'plasma', 'viridis', 'ocean']" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Creating a list of surfaces.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "surfaces = []\nfor i in range(4):\n surfaces.append(\n create_surface(x, y, equation=equations[i], colormap_name=cmap_names[i])\n )" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Creating a scene object and configuring the camera's position\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "scene = window.Scene()\nscene.set_camera(\n position=(4.45, -21, 12), focal_point=(4.45, 0.0, 0.0), view_up=(0.0, 0.0, 1.0)\n)\nshowm = window.ShowManager(scene, size=(600, 600))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Creating a grid to interact with surfaces individually.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# To store the function names\ntext = []\nfor i in range(4):\n t_actor = actor.vector_text(\n 'Function ' + str(i + 1), pos=(0, 0, 0), scale=(0.17, 0.2, 0.2)\n )\n text.append(t_actor)\n\ngrid_ui = ui.GridUI(\n actors=surfaces,\n captions=text,\n caption_offset=(-0.7, -2.5, 0),\n dim=(1, 4),\n cell_padding=2,\n aspect_ratio=1,\n rotation_axis=(0, 1, 0),\n)\nshowm.scene.add(grid_ui)\n\n# Adding an axes actor to the first surface.\nshowm.scene.add(actor.axes())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Initializing text box to print the title of the animation\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "tb = ui.TextBlock2D(bold=True, position=(200, 60))\ntb.message = 'Animated 2D functions'\nscene.add(tb)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Initializing showm and counter\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "counter = itertools.count()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "end is used to decide when to end the animation\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "end = 200" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The 2D functions are updated and rendered here.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def timer_callback(_obj, _event):\n global xyz, time\n time += dt\n cnt = next(counter)\n\n # updating the colors and vertices of the triangles used to form the\n # surfaces\n for surf in surfaces:\n xyz, colors = update_surface(\n x, y, equation=surf.equation, cmap_name=surf.cmap_name\n )\n utils.update_surface_actor_colors(surf, colors)\n surf.vertices[:] = surf.initial_vertices + np.repeat(\n xyz, surf.no_vertices_per_point, axis=0\n )\n utils.update_actor(surf)\n\n showm.render()\n # to end the animation\n if cnt == end:\n showm.exit()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Run every 30 milliseconds\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "showm.add_timer_callback(True, 30, timer_callback)\n\ninteractive = False\nif interactive:\n showm.start()\n\nwindow.record(showm.scene, size=(600, 600), out_path='viz_animated_surfaces.png')" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.8" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/v0.10.x/_downloads/add7a5726ae59960b3bcb9ef1af5110c/viz_interaction.py b/v0.10.x/_downloads/add7a5726ae59960b3bcb9ef1af5110c/viz_interaction.py new file mode 100644 index 000000000..4775626cd --- /dev/null +++ b/v0.10.x/_downloads/add7a5726ae59960b3bcb9ef1af5110c/viz_interaction.py @@ -0,0 +1,146 @@ +""" +==================================== +Streaming FURY with user interaction +==================================== + +In this tutorial, we show how to use the FURY Streaming system to +serve an interactive visualization through a web browser. + +You can choose between two different encodings: WebRTC or MJPEG. +WebRTC is a more robust option and can be used to perform +a live streaming with a low-latency connection for example using +ngrok. However, to use webRTC you need to install the aiortc library. + +.. code-block:: bash + + pip install aiortc + + +Notes +----- +If you don't have ffmpeg installed, you need to install it to use WebRTC + +Linux + + +`apt install libavdevice-dev libavfilter-dev libopus-dev libvpx-dev pkg-config` + +OS X + +`brew install ffmpeg opus libvpx pkg-config` + +""" + +import multiprocessing +import sys + +import numpy as np + +from fury import actor, window +from fury.stream.client import FuryStreamClient, FuryStreamInteraction + +# if this example it's not working for you and you're using MacOs +# uncomment the following line +# multiprocessing.set_start_method('spawn') +from fury.stream.server.main import WEBRTC_AVAILABLE, web_server, web_server_raw_array + +if __name__ == '__main__': + interactive = False + # `use_raw_array` is a flag to tell the server to use python RawArray + # instead of SharedMemory which is a new feature in python 3.8 + # https://docs.python.org/3/library/multiprocessing.html#multiprocessing.Array + # https://docs.python.org/3/library/multiprocessing.html#shared-memory-objects + + use_raw_array = sys.version_info < (3, 8) + window_size = (300, 300) + # `max_window_size` are the maximum size of the window that will be + # allowed to be sent to the browser. For example, if you set + # `max_window_size=(800, 800)` then the browser will be limited to + # a window of size (800, 800). + + max_window_size = (400, 400) + # 0 ms_stream means that the frame will be sent to the server + # right after the rendering + + # `ms_interaction` is the time in milliseconds that the user will have + # to interact with the visualization + + ms_interaction = 1 + # `ms_stream` is the number of milliseconds that the server will + # wait before sending a new frame to the browser. If `ms_stream=0` + # then the server will send the frame right after the rendering. + + ms_stream = 0 + # max number of interactions to be stored inside the queue + max_queue_size = 17 + ###################################################################### + centers = np.array([[0, 0, 0], [-1, 0, 0], [1, 0, 0]]) + colors = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]]) + + actors = actor.sphere(centers, opacity=0.5, radii=0.4, colors=colors) + scene = window.Scene() + + scene.add(actors) + + showm = window.ShowManager(scene, size=(window_size[0], window_size[1])) + + stream = FuryStreamClient( + showm, max_window_size=max_window_size, use_raw_array=use_raw_array + ) + stream_interaction = FuryStreamInteraction( + showm, max_queue_size=max_queue_size, use_raw_array=use_raw_array + ) + + if use_raw_array: + p = multiprocessing.Process( + target=web_server_raw_array, + args=( + stream.img_manager.image_buffers, + stream.img_manager.info_buffer, + stream_interaction.circular_queue.head_tail_buffer, + stream_interaction.circular_queue.buffer._buffer, + 8000, + 'localhost', + True, + WEBRTC_AVAILABLE, + ), + ) + + else: + p = multiprocessing.Process( + target=web_server, + args=( + stream.img_manager.image_buffer_names, + stream.img_manager.info_buffer_name, + stream_interaction.circular_queue.head_tail_buffer_name, + stream_interaction.circular_queue.buffer.buffer_name, + 8000, + 'localhost', + True, + WEBRTC_AVAILABLE, + ), + ) + p.start() + stream_interaction.start(ms=ms_interaction) + stream.start( + ms_stream, + ) + ########################################################################### + # If you have aiortc in your system, you can see your live streaming + # through the following url: htttp://localhost:8000/?encoding=webrtc + # Other wise, you can use the following url: + # http://localhost:8000/?encoding=mjpeg + + if interactive: + showm.start() + + # We need to close the server after the show is over + p.kill() + ########################################################################### + # We release the resources and stop the interactive mode + stream.stop() + stream_interaction.stop() + stream.cleanup() + stream_interaction.cleanup() + + window.record(showm.scene, size=window_size, out_path='viz_interaction.png') diff --git a/v0.10.x/_downloads/b0147e9215e27233d0d56f5c5c388371/viz_surfaces.py b/v0.10.x/_downloads/b0147e9215e27233d0d56f5c5c388371/viz_surfaces.py new file mode 100644 index 000000000..6dbc9e124 --- /dev/null +++ b/v0.10.x/_downloads/b0147e9215e27233d0d56f5c5c388371/viz_surfaces.py @@ -0,0 +1,107 @@ +""" +================== +Visualize surfaces +================== + +Here is a simple tutorial that shows how to visualize surfaces using DIPY. It +also shows how to load/save, get/set and update ``PolyData`` and show +surfaces. + +``PolyData`` is a structure used by VTK to represent surfaces and other data +structures. Here we show how to visualize a simple cube but the same idea +should apply for any surface. +""" + +import numpy as np + +from fury import utils, window +from fury.io import load_polydata, save_polydata +from fury.lib import PolyData + +############################################################################### +# Import useful functions + + +############################################################################### +# Create an empty ``PolyData`` + +my_polydata = PolyData() + +############################################################################### +# Create a cube with vertices and triangles as numpy arrays + +my_vertices = np.array( + [ + [0.0, 0.0, 0.0], + [0.0, 0.0, 1.0], + [0.0, 1.0, 0.0], + [0.0, 1.0, 1.0], + [1.0, 0.0, 0.0], + [1.0, 0.0, 1.0], + [1.0, 1.0, 0.0], + [1.0, 1.0, 1.0], + ] +) +# the data type is needed to mention here, numpy.int64 +my_triangles = np.array( + [ + [0, 6, 4], + [0, 2, 6], + [0, 3, 2], + [0, 1, 3], + [2, 7, 6], + [2, 3, 7], + [4, 6, 7], + [4, 7, 5], + [0, 4, 5], + [0, 5, 1], + [1, 5, 7], + [1, 7, 3], + ], + dtype='i8', +) + + +############################################################################### +# Set vertices and triangles in the ``PolyData`` + +utils.set_polydata_vertices(my_polydata, my_vertices) +utils.set_polydata_triangles(my_polydata, my_triangles) + +############################################################################### +# Save the ``PolyData`` + +file_name = 'my_cube.vtk' +save_polydata(my_polydata, file_name) +print('Surface saved in ' + file_name) + +############################################################################### +# Load the ``PolyData`` + +cube_polydata = load_polydata(file_name) + +############################################################################### +# add color based on vertices position + +cube_vertices = utils.get_polydata_vertices(cube_polydata) +colors = cube_vertices * 255 +utils.set_polydata_colors(cube_polydata, colors) + +print('new surface colors') +print(utils.get_polydata_colors(cube_polydata)) + +############################################################################### +# Visualize surfaces + +# get Actor +cube_actor = utils.get_actor_from_polydata(cube_polydata) + +# Create a scene +scene = window.Scene() +scene.add(cube_actor) +scene.set_camera(position=(10, 5, 7), focal_point=(0.5, 0.5, 0.5)) +scene.zoom(3) + +# display +# window.show(scene, size=(600, 600), reset_camera=False) +window.record(scene, out_path='cube.png', size=(600, 600)) diff --git a/v0.10.x/_downloads/b03f0b0eb9b655c3899a93d34941848b/viz_network_animated.ipynb b/v0.10.x/_downloads/b03f0b0eb9b655c3899a93d34941848b/viz_network_animated.ipynb new file mode 100644 index 000000000..cd281b9be --- /dev/null +++ b/v0.10.x/_downloads/b03f0b0eb9b655c3899a93d34941848b/viz_network_animated.ipynb @@ -0,0 +1,248 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Visualize Networks (Animated version)\n\nThe goal of this demo is to show how to visualize a\ncomplex network and use an force directed algorithm to\nlayout the network. A simpler animation of the network\nmade by adding some random displacements to nodes\npositions is also demoed.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "First, let's import some useful functions\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "import math\nfrom os.path import join as pjoin\n\nimport numpy as np\n\nfrom fury import actor\nfrom fury import colormap as cmap\nfrom fury import window\nfrom fury.utils import compute_bounds, update_actor, vertices_from_actor" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This demo has two modes.\nUse `mode = 0` to visualize a randomly generated geographic network by\niterating it using a force-directed layout heuristic.\n\nUse `mode = 1` to visualize a large network being animated with random\ndisplacements\n\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "mode = 0" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Then let's download some available datasets. (mode 1)\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "if mode == 1:\n from fury.data.fetcher import fetch_viz_wiki_nw\n\n files, folder = fetch_viz_wiki_nw()\n categories_file, edges_file, positions_file = sorted(files.keys())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We read our datasets (mode 1)\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "if mode == 1:\n positions = np.loadtxt(pjoin(folder, positions_file))\n categories = np.loadtxt(pjoin(folder, categories_file), dtype=str)\n edges = np.loadtxt(pjoin(folder, edges_file), dtype=int)\n vertices_count = len(positions)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Generate a geographic random network, requires networkx package (mode 0)\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "if mode == 0:\n import networkx as nx\n\n vertices_count = 100\n view_size = 100\n network = nx.random_geometric_graph(vertices_count, 0.2)\n positions = view_size * np.random.random((vertices_count, 3)) - view_size / 2.0\n categories = np.arange(0, vertices_count)\n edges = np.array(network.edges())\n positions = view_size * np.random.random((vertices_count, 3)) - view_size / 2.0" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We attribute a color to each category of our dataset which correspond to our\nnodes colors.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "category2index = {category: i for i, category in enumerate(np.unique(categories))}\n\nindex2category = np.unique(categories)\n\ncategory_colors = cmap.distinguishable_colormap(nb_colors=len(index2category))\n\ncolors = np.array(\n [category_colors[category2index[category]] for category in categories]\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We define our node size\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "radii = 1 + np.random.rand(len(positions))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's create our edges now. They will indicate a citation between two nodes.\nThe colors of each edge are interpolated between the two endpoints.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "edges_colors = []\nfor source, target in edges:\n edges_colors.append(np.array([colors[source], colors[target]]))\n\nedges_colors = np.average(np.array(edges_colors), axis=1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Our data preparation is ready, it is time to visualize them all. We start to\nbuild 2 actors that we represent our data : sphere_actor for the nodes and\nlines_actor for the edges.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "sphere_actor = actor.sphere(\n centers=np.zeros(positions.shape), colors=colors, radii=radii * 0.5, theta=8, phi=8\n)\n\n\nlines_actor = actor.line(\n np.zeros((len(edges), 2, 3)),\n colors=edges_colors,\n lod=False,\n fake_tube=True,\n linewidth=3,\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Defining timer callback and layout iterator\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def new_layout_timer(\n showm,\n edges_list,\n vertices_count,\n max_iterations=1000,\n vertex_initial_positions=None,\n):\n view_size = 500\n viscosity = 0.10\n alpha = 0.5\n a = 0.0005\n b = 1.0\n deltaT = 1.0\n\n sphere_geometry = np.array(vertices_from_actor(sphere_actor))\n geometry_length = sphere_geometry.shape[0] / vertices_count\n\n if vertex_initial_positions is not None:\n pos = np.array(vertex_initial_positions)\n else:\n pos = view_size * np.random.random((vertices_count, 3)) - view_size / 2.0\n\n velocities = np.zeros((vertices_count, 3))\n\n def iterate(iterationCount):\n nonlocal pos, velocities\n for _ in range(iterationCount):\n forces = np.zeros((vertices_count, 3))\n # repulstive forces\n for vertex1 in range(vertices_count):\n for vertex2 in range(vertex1):\n x1, y1, z1 = pos[vertex1]\n x2, y2, z2 = pos[vertex2]\n distance = (\n math.sqrt(\n (x2 - x1) * (x2 - x1)\n + (y2 - y1) * (y2 - y1)\n + (z2 - z1) * (z2 - z1)\n )\n + alpha\n )\n rx = (x2 - x1) / distance\n ry = (y2 - y1) / distance\n rz = (z2 - z1) / distance\n Fx = -b * rx / distance / distance\n Fy = -b * ry / distance / distance\n Fz = -b * rz / distance / distance\n forces[vertex1] += np.array([Fx, Fy, Fz])\n forces[vertex2] -= np.array([Fx, Fy, Fz])\n # attractive forces\n for vFrom, vTo in edges_list:\n if vFrom == vTo:\n continue\n x1, y1, z1 = pos[vFrom]\n x2, y2, z2 = pos[vTo]\n distance = math.sqrt(\n (x2 - x1) * (x2 - x1)\n + (y2 - y1) * (y2 - y1)\n + (z2 - z1) * (z2 - z1)\n )\n Rx = x2 - x1\n Ry = y2 - y1\n Rz = z2 - z1\n Fx = a * Rx * distance\n Fy = a * Ry * distance\n Fz = a * Rz * distance\n forces[vFrom] += np.array([Fx, Fy, Fz])\n forces[vTo] -= np.array([Fx, Fy, Fz])\n velocities += forces * deltaT\n velocities *= 1.0 - viscosity\n pos += velocities * deltaT\n pos[:, 0] -= np.mean(pos[:, 0])\n pos[:, 1] -= np.mean(pos[:, 1])\n pos[:, 2] -= np.mean(pos[:, 2])\n\n counter = 0\n\n def _timer(_obj, _event):\n nonlocal counter, pos\n counter += 1\n if mode == 0:\n iterate(1)\n else:\n pos[:] += (np.random.random(pos.shape) - 0.5) * 1.5\n spheres_positions = vertices_from_actor(sphere_actor)\n spheres_positions[:] = sphere_geometry + np.repeat(pos, geometry_length, axis=0)\n\n edges_positions = vertices_from_actor(lines_actor)\n edges_positions[::2] = pos[edges_list[:, 0]]\n edges_positions[1::2] = pos[edges_list[:, 1]]\n\n update_actor(lines_actor)\n compute_bounds(lines_actor)\n\n update_actor(sphere_actor)\n compute_bounds(lines_actor)\n showm.scene.reset_clipping_range()\n showm.render()\n\n if counter >= max_iterations:\n showm.exit()\n\n return _timer" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "All actors need to be added in a scene, so we build one and add our\nlines_actor and sphere_actor.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "scene = window.Scene()\n\ncamera = scene.camera()\n\nscene.add(lines_actor)\nscene.add(sphere_actor)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The final step! Visualize the result of our creation! Also, we need to move\nthe camera a little bit farther from the network. you can increase the\nparameter max_iteractions of the timer callback to let the animation run for\nmore time.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "showm = window.ShowManager(\n scene, reset_camera=False, size=(900, 768), order_transparent=True, multi_samples=8\n)\n\n\nscene.set_camera(position=(0, 0, -300))\n\ntimer_callback = new_layout_timer(\n showm, edges, vertices_count, max_iterations=200, vertex_initial_positions=positions\n)\n\n\n# Run every 16 milliseconds\nshowm.add_timer_callback(True, 16, timer_callback)\n\nshowm.start()\n\nwindow.record(showm.scene, size=(900, 768), out_path='viz_animated_networks.png')" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.8" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/v0.10.x/_downloads/b117b7a1c76377c5cc90f0e7ba0e4af3/viz_hierarchical_animation.ipynb b/v0.10.x/_downloads/b117b7a1c76377c5cc90f0e7ba0e4af3/viz_hierarchical_animation.ipynb new file mode 100644 index 000000000..2ee81ad37 --- /dev/null +++ b/v0.10.x/_downloads/b117b7a1c76377c5cc90f0e7ba0e4af3/viz_hierarchical_animation.ipynb @@ -0,0 +1,338 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Keyframe hierarchical Animation\n\nCreating hierarchical keyframes animation in fury\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "import numpy as np\n\nfrom fury import actor, window\nfrom fury.animation import Animation\n\nscene = window.Scene()\n\nshowm = window.ShowManager(\n scene, size=(900, 768), reset_camera=False, order_transparent=True\n)\nshowm.initialize()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Creating the road\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "road = actor.box(\n np.array([[0, 0, 0]]), colors=np.array([[1, 1, 1]]), scales=np.array([[22, 0.1, 5]])\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Constructing the car geometry\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "body_actor = actor.box(\n np.array([[0, 0.5, 0], [-0.2, 1, 0]]),\n scales=((4, 1, 2), (2.5, 1.5, 1.8)),\n colors=(0.6, 0.3, 0.1),\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Adding the the car's body to an Animation to be able to animate it later.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "car_anim = Animation(body_actor)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Creating the wheels of the car\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "wheel_center = np.array([[0, 0, 0]])\n\nwheel_direction = np.array([[0, 0, 1]])\nwheel_positions = [\n [1.2, 0, 1.1],\n [-1.2, 0, 1.1],\n [1.2, 0, -1.1],\n [-1.2, 0, -1.1],\n]\n\nwheels = [\n actor.cylinder(\n wheel_center,\n wheel_direction,\n (0.1, 0.7, 0.3),\n radius=1.7,\n heights=0.3,\n resolution=10,\n capped=True,\n )\n for _ in range(4)\n]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Animating each wheel and setting its position to the right position using a\nsingle keyframe that will not change.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "wheels_animations = [Animation(wheel) for wheel in wheels]\n\nfor wheel_anim in wheels_animations:\n wheel_anim.set_position(0.0, wheel_positions.pop())\n wheel_anim.set_rotation(0.0, [0, 0, 1, 1])\n wheel_anim.set_rotation(1.0, [0, 0, 1, -1])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Creating a radar on top of the car\n\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "First we create the shaft holding and rotating the radar\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "radar_shaft = actor.cylinder(\n np.array([[0, 0, 0]]), np.array([[0, 1, 0]]), (0, 1, 0), heights=1\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In order to animate the shaft actor we have to add it to an Animation\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "radar_shaft_anim = Animation(radar_shaft)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Setting a single position keyframe will make sure the actor will be placed at\nthat position\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "radar_shaft_anim.set_position(0.0, [0, 2, 0])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Rotating the shaft around Y axis\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "radar_shaft_anim.set_rotation(0.0, [0, -250, 0])\nradar_shaft_anim.set_rotation(1.0, [0, 250, 0])\nradar_shaft_anim.set_rotation(2.0, [0, -250, 0])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we create the radar itself\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "radar = actor.cone(np.array([[0, 0, 0]]), directions=(0, 0, 0), colors=(0.2, 0.2, 0.9))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Then add it to an animation in order to rotate it\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "radar_animation = Animation(radar)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Set position and rotation as done above with the shaft.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "radar_animation.set_position(0, [-0.4, 0.5, 0])\nradar_animation.set_rotation(0.0, [0, 0, 0])\nradar_animation.set_rotation(1.0, [180, 0, 0])\nradar_animation.set_rotation(2.0, [0, 0, 0])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now, we want the radar to rotate when the shaft rotates in hierarchical way.\nTo do that we must add the radar animation as a child animation of the shaft\nanimation as below:\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "radar_shaft_anim.add_child_animation(radar_animation)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "After that we want everything to animate related to the car.\nThe wheels should always be attached to the car no matter where it moves.\nwe do that by adding them as child animations of the car's body animation\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "car_anim.add_child_animation([wheels_animations, radar_shaft_anim])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Moving the car\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "car_anim.set_position(0.0, [-10, 0.5, 0])\ncar_anim.set_position(6.0, [10, 0.5, 0])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Adding the car Animation to the show manager\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "showm.add_animation(car_anim)\nscene.add(road)\nscene.camera().SetPosition(0, 20, 30)\n\ninteractive = False\n\nif interactive:\n showm.start()\n\nwindow.record(\n scene, out_path='viz_keyframe_hierarchical_animation.png', size=(900, 768)\n)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.8" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/v0.10.x/_downloads/b122808cf73046bc60422ce4c48064a5/viz_camera.ipynb b/v0.10.x/_downloads/b122808cf73046bc60422ce4c48064a5/viz_camera.ipynb new file mode 100644 index 000000000..997f09be4 --- /dev/null +++ b/v0.10.x/_downloads/b122808cf73046bc60422ce4c48064a5/viz_camera.ipynb @@ -0,0 +1,320 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Keyframe animation: Camera and opacity\n\nCamera and opacity keyframe animation explained in this tutorial.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "import numpy as np\n\nfrom fury import actor, window\nfrom fury.animation import Animation, CameraAnimation, Timeline\nfrom fury.animation.interpolator import cubic_spline_interpolator" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## The Plan\n\nThe plan here is to animate (scale and translate) 50 spheres randomly, and\nshow `FURY` text that appears at the end!\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "scene = window.Scene()\n\nshowm = window.ShowManager(\n scene, size=(900, 768), reset_camera=False, order_transparent=True\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Creating the main ``Timeline`` and adding static actors to it\n\nHere we create a ``Timeline``. so that we can use it as a controller for the\n50 animations we will create.\nSo, Instead of updating and adding 50 Animations to the ``ShowManager``,\nwe only need to update the main ``Timeline``. Also, a playback panel can be\nassigned to this main Timeline.\n\nBut, why we need 50 ``Animations``, you may ask.\n-> A single ``Animation`` can handle each property once at a time. So we need\n50 ``Animations`` to translate and scale our 50 spheres.\n\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "``playback_panel=True`` assigns a playback panel that can control the\nplayback of its ``Animations``\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "timeline = Timeline(playback_panel=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Creating two actors for visualization, and to detect camera's animations.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "arrow = actor.arrow(\n np.array([[0, 0, 0]]), np.array([[0, 1, 0]]), np.array([[1, 1, 0]]), scales=5\n)\nplan = actor.box(\n np.array([[0, 0, 0]]),\n colors=np.array([[1, 1, 1]]),\n scales=np.array([[20, 0.2, 20]]),\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Creating \"FURY\" text\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "fury_text = actor.vector_text('FURY', pos=(-4.3, 15, 0), scale=(2, 2, 2))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Creating an ``Animation`` to animate the opacity of ``fury_text``\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "text_anim = Animation(fury_text, loop=False)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "opacity is set to 0 at time 29 and set to one at time 35.\nLinear interpolator is always used by default.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "text_anim.set_opacity(29, 0)\ntext_anim.set_opacity(35, 1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "``text_anim`` contains the text actor is added to the Timeline.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "timeline.add_animation(text_anim)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Creating and animating 50 Spheres\n\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "for i in range(50):\n ###########################################################################\n # create a sphere actor that's centered at the origin and has random color\n # and radius.\n actors = [\n actor.sphere(\n np.array([[0, 0, 0]]), np.random.random([1, 3]), np.random.random([1, 3])\n )\n ]\n\n ###########################################################################\n # create a timeline to animate this actor (single actor or list of actors)\n # Actors can be added later using `Timeline.add_actor(actor)`\n animation = Animation(actors)\n\n # We generate random position and scale values from time=0 to time=49 each\n # two seconds.\n for t in range(0, 50, 2):\n #######################################################################\n # Position and scale are set to a random value at the timestamps\n # mentioned above.\n animation.set_position(t, np.random.random(3) * 30 - np.array([15, 0, 15]))\n animation.set_scale(t, np.repeat(np.random.random(1), 3))\n\n ###########################################################################\n # change the position interpolator to cubic spline interpolator.\n animation.set_position_interpolator(cubic_spline_interpolator)\n\n ###########################################################################\n # Finally, the ``Animation`` is added to the ``Timeline``.\n timeline.add_animation(animation)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Animating the camera\n\nSince, only one camera is needed, camera animations are preferably done using\na separate ``Animation``.\nThree properties can control the camera's animation:\nPosition, focal position (referred to by `focal`), and up-view.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "camera_anim = CameraAnimation(loop=False)\ntimeline.add_animation(camera_anim)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Multiple keyframes can be set at once as follows.\ncamera focal positions\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "camera_positions = {\n # time: camera position\n 0: np.array([3, 3, 3]),\n 4: np.array([50, 25, -40]),\n 7: np.array([-50, 50, -40]),\n 10: np.array([-25, 25, 20]),\n 14: np.array([0, 16, 25]),\n 20: np.array([0, 14.5, 20]),\n}\n\n# camera focal positions\ncamera_focal_positions = {\n # time: focal position\n 15: np.array([0, 0, 0]),\n 20: np.array([3, 9, 5]),\n 23: np.array([7, 5, 3]),\n 25: np.array([-2, 9, -6]),\n 27: np.array([0, 16, 0]),\n 31: np.array([0, 14.5, 0]),\n}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "``set_camera_focal`` can only set one keyframe, but\n``set_camera_focal_keyframes`` can set a dictionary of keyframes.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "camera_anim.set_focal_keyframes(camera_focal_positions)\ncamera_anim.set_position_keyframes(camera_positions)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Change camera position and focal interpolators\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "camera_anim.set_position_interpolator(cubic_spline_interpolator)\ncamera_anim.set_focal_interpolator(cubic_spline_interpolator)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Adding non-animatable actors to the scene.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "scene.add(arrow, plan)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Adding the timeline to the ShowManager.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "showm.add_animation(timeline)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The ShowManager must go on!\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "interactive = False\n\nif interactive:\n showm.start()\n\nwindow.record(scene, out_path='viz_keyframe_animation_camera.png', size=(900, 768))" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.8" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/v0.10.x/_downloads/b33d67a49295c353364e99a202bc6e99/viz_selection.py b/v0.10.x/_downloads/b33d67a49295c353364e99a202bc6e99/viz_selection.py new file mode 100644 index 000000000..968d5f315 --- /dev/null +++ b/v0.10.x/_downloads/b33d67a49295c353364e99a202bc6e99/viz_selection.py @@ -0,0 +1,142 @@ +""" +========================== +Selecting multiple objects +========================== + +Here we show how to select objects in the +3D world. In this example all objects to be picked are part of +a single actor. + +FURY likes to bundle objects in a few actors to reduce code and +increase speed. Nonetheless the method works for multiple actors too. + +The difference with the picking tutorial is that here we will +be able to select more than one object. In addition we can +select interactively many vertices or faces. + +In summary, we will create an actor with thousands of cubes and +then interactively we will be moving a rectangular box by +hovering the mouse and making transparent everything that is +behind that box. +""" + +import numpy as np + +from fury import actor, pick, utils, window + +############################################################################### +# Adding many cubes of different sizes and colors + +num_cubes = 50000 + +centers = 10000 * (np.random.rand(num_cubes, 3) - 0.5) +colors = np.random.rand(num_cubes, 4) +colors[:, 3] = 1.0 +radii = 100 * np.random.rand(num_cubes) + 0.1 + +############################################################################### +# Keep track of total number of triangle faces +# Note that every quad of each cube has 2 triangles +# and each cube has 6 quads in total. + +num_faces = num_cubes * 6 * 2 + +############################################################################### +# Build scene and add an actor with many objects. + +scene = window.Scene() + +############################################################################### +# Build the actor containing all the cubes + +cube_actor = actor.cube(centers, directions=(1, 0, 0), colors=colors, scales=radii) + +############################################################################### +# Access the memory of the vertices of all the cubes + +vertices = utils.vertices_from_actor(cube_actor) +num_vertices = vertices.shape[0] +num_objects = centers.shape[0] + +############################################################################### +# Access the memory of the colors of all the cubes + +vcolors = utils.colors_from_actor(cube_actor, 'colors') + +############################################################################### +# Create a rectangular 2d box as a texture + +rgba = 255 * np.ones((100, 200, 4)) +rgba[1:-1, 1:-1] = np.zeros((98, 198, 4)) + 100 +texa = actor.texture_2d(rgba.astype(np.uint8)) + +scene.add(cube_actor) +scene.add(texa) +scene.reset_camera() +scene.zoom(3.0) + +############################################################################### +# Create the Selection Manager + +selm = pick.SelectionManager(select='faces') + +############################################################################### +# Tell Selection Manager to avoid selecting specific actors + +selm.selectable_off(texa) + +############################################################################### +# Let's make the callback which will be called +# when we hover the mouse + + +def hover_callback(_obj, _event): + event_pos = selm.event_position(showm.iren) + # updates rectangular box around mouse + texa.SetPosition(event_pos[0] - 200 // 2, event_pos[1] - 100 // 2) + + # defines selection region and returns information from selected objects + info = selm.select(event_pos, showm.scene, (200 // 2, 100 // 2)) + for node in info.keys(): + if info[node]['face'] is not None: + if info[node]['actor'] is cube_actor: + for face_index in info[node]['face']: + # generates an object_index to help with coloring + # by dividing by the number of faces of each cube (6 * 2) + object_index = face_index // 12 + sec = int(num_vertices / num_objects) + color_change = np.array([150, 0, 0, 255], dtype='uint8') + vcolors[ + object_index * sec : object_index * sec + sec + ] = color_change + utils.update_actor(cube_actor) + showm.render() + + +############################################################################### +# Make the window appear + +showm = window.ShowManager( + scene, size=(1024, 768), order_transparent=True, reset_camera=False +) + + +############################################################################### +# Bind the callback to the actor + +showm.add_iren_callback(hover_callback) + +############################################################################### +# Change interactive to True to start interacting with the scene + +interactive = False + +if interactive: + + showm.start() + + +############################################################################### +# Save the current framebuffer in a PNG file + +window.record(showm.scene, size=(1024, 768), out_path='viz_selection.png') diff --git a/v0.10.x/_downloads/b65e489e7aa31f9307df145524104173/viz_ui.py b/v0.10.x/_downloads/b65e489e7aa31f9307df145524104173/viz_ui.py new file mode 100644 index 000000000..253cbd662 --- /dev/null +++ b/v0.10.x/_downloads/b65e489e7aa31f9307df145524104173/viz_ui.py @@ -0,0 +1,312 @@ +# -*- coding: utf-8 -*- +""" +=============== +User Interfaces +=============== + +This example shows how to use the UI API. We will demonstrate how to create +several FURY UI elements, then use a list box to toggle which element is shown. + +First, a bunch of imports. +""" + +import numpy as np + +from fury import actor, ui, window +from fury.data import fetch_viz_icons, read_viz_icons + +############################################################################### +# Shapes +# ====== +# +# Let's start by drawing some simple shapes. First, a rectangle. + +rect = ui.Rectangle2D(size=(200, 200), position=(400, 300), color=(1, 0, 1)) + +############################################################################### +# Then we can draw a solid circle, or disk. + +disk = ui.Disk2D(outer_radius=50, center=(500, 500), color=(1, 1, 0)) + +############################################################################### +# Add an inner radius to make a ring. + +ring = ui.Disk2D(outer_radius=50, inner_radius=45, center=(500, 300), color=(0, 1, 1)) + +############################################################################### +# Image +# ===== +# +# Now let's display an image. First we need to fetch some icons that are +# included in FURY. + +fetch_viz_icons() + +############################################################################### +# Now we can create an image container. + +img = ui.ImageContainer2D( + img_path=read_viz_icons(fname='home3.png'), position=(450, 350) +) + +############################################################################### +# Panel with buttons and text +# =========================== +# +# Let's create some buttons and text and put them in a panel. First we'll +# make the panel. + +panel = ui.Panel2D(size=(300, 150), color=(1, 1, 1), align='right') +panel.center = (500, 400) + +############################################################################### +# Then we'll make two text labels and place them on the panel. +# Note that we specify the position with integer numbers of pixels. + +text = ui.TextBlock2D(text='Click me') +text2 = ui.TextBlock2D(text='Me too') +panel.add_element(text, (50, 100)) +panel.add_element(text2, (180, 100)) + +############################################################################### +# Then we'll create two buttons and add them to the panel. +# +# Note that here we specify the positions with floats. In this case, these are +# percentages of the panel size. + + +button_example = ui.Button2D( + icon_fnames=[('square', read_viz_icons(fname='stop2.png'))] +) + +icon_files = [] +icon_files.append(('down', read_viz_icons(fname='circle-down.png'))) +icon_files.append(('left', read_viz_icons(fname='circle-left.png'))) +icon_files.append(('up', read_viz_icons(fname='circle-up.png'))) +icon_files.append(('right', read_viz_icons(fname='circle-right.png'))) + +second_button_example = ui.Button2D(icon_fnames=icon_files) + +panel.add_element(button_example, (0.25, 0.33)) +panel.add_element(second_button_example, (0.66, 0.33)) + +############################################################################### +# We can add a callback to each button to perform some action. + + +def change_text_callback(i_ren, _obj, _button): + text.message = 'Clicked!' + i_ren.force_render() + + +def change_icon_callback(i_ren, _obj, _button): + _button.next_icon() + i_ren.force_render() + + +button_example.on_left_mouse_button_clicked = change_text_callback +second_button_example.on_left_mouse_button_pressed = change_icon_callback + +############################################################################### +# Cube and sliders +# ================ +# +# Let's add a cube to the scene and control it with sliders. + + +cube = actor.cube( + centers=np.array([[15, 0, 0]]), + colors=np.array([[0, 0, 1]]), + scales=np.array([[20, 20, 20]]), + directions=np.array([[0, 0, 1]]), +) + +############################################################################### +# Now we'll add three sliders: one circular and two linear. + +ring_slider = ui.RingSlider2D( + center=(740, 400), initial_value=0, text_template='{angle:5.1f}°' +) + +line_slider_x = ui.LineSlider2D( + center=(500, 250), + initial_value=0, + min_value=-10, + max_value=10, + orientation='horizontal', +) + +line_slider_y = ui.LineSlider2D( + center=(650, 350), + initial_value=0, + min_value=-10, + max_value=10, + orientation='vertical', +) + +############################################################################### +# We can use a callback to rotate the cube with the ring slider. + + +def rotate_cube(slider): + angle = slider.value + previous_angle = slider.previous_value + rotation_angle = angle - previous_angle + cube.RotateX(rotation_angle) + + +ring_slider.on_change = rotate_cube + +############################################################################### +# Similarly, we can translate the cube with line sliders. +# We use global variables to keep track of the position of the cube. + +cube_x = 0 +cube_y = 0 + + +def translate_cube_x(slider): + global cube_x, cube_y + cube_x = slider.value + cube.SetPosition(cube_x, cube_y, 0) + + +def translate_cube_y(slider): + global cube_x, cube_y + cube_y = slider.value + cube.SetPosition(cube_x, cube_y, 0) + + +line_slider_x.on_change = translate_cube_x +line_slider_y.on_change = translate_cube_y + +############################################################################### +# Range Slider +# ============ +# +# Finally, we can add a range slider. This element is composed of two sliders. +# The first slider has two handles which let you set the range of the second. + +range_slider_x = ui.RangeSlider( + line_width=8, + handle_side=25, + range_slider_center=(450, 450), + value_slider_center=(450, 350), + length=150, + min_value=0, + max_value=10, + font_size=18, + range_precision=2, + value_precision=4, + shape='square', +) + +range_slider_y = ui.RangeSlider( + line_width=8, + handle_side=25, + range_slider_center=(750, 400), + value_slider_center=(650, 400), + length=150, + min_value=0, + max_value=10, + font_size=18, + range_precision=2, + value_precision=4, + orientation='vertical', + shape='square', +) +############################################################################### +# Select menu +# ============ +# +# We just added many examples. If we showed them all at once, they would fill +# the screen. Let's make a simple menu to choose which example is shown. +# +# We'll first make a list of the examples. + +examples = [ + [rect], + [disk, ring], + [img], + [panel], + [ring_slider, line_slider_x, line_slider_y], + [range_slider_x, range_slider_y], +] + +############################################################################### +# Now we'll make a function to hide all the examples. Then we'll call it so +# that none are shown initially. + + +def hide_all_examples(): + for example in examples: + for element in example: + element.set_visibility(False) + cube.SetVisibility(False) + + +hide_all_examples() + +############################################################################### +# To make the menu, we'll first need to create a list of labels which +# correspond with the examples. + +values = [ + 'Rectangle', + 'Disks', + 'Image', + 'Button Panel', + 'Line & Ring Slider', + 'Range Slider', +] + +############################################################################### +# Now we can create the menu. + +listbox = ui.ListBox2D( + values=values, position=(10, 300), size=(300, 200), multiselection=False +) + +############################################################################### +# Then we will use a callback to show the correct example when a label is +# clicked. + + +def display_element(): + hide_all_examples() + example = examples[values.index(listbox.selected[0])] + for element in example: + element.set_visibility(True) + if values.index(listbox.selected[0]) == 4: + cube.SetVisibility(True) + + +listbox.on_change = display_element + +############################################################################### +# Show Manager +# ================================== +# +# Now that all the elements have been initialised, we add them to the show +# manager. + +current_size = (800, 800) +show_manager = window.ShowManager(size=current_size, title='FURY UI Example') + +show_manager.scene.add(listbox) +for example in examples: + for element in example: + show_manager.scene.add(element) +show_manager.scene.add(cube) +show_manager.scene.reset_camera() +show_manager.scene.set_camera(position=(0, 0, 200)) +show_manager.scene.reset_clipping_range() +show_manager.scene.azimuth(30) + +# To interact with the UI, set interactive = True +interactive = False + +if interactive: + show_manager.start() + +window.record(show_manager.scene, size=current_size, out_path='viz_ui.png') diff --git a/v0.10.x/_downloads/b990604c3b5a2778e66d16988eb16560/viz_wrecking_ball.py b/v0.10.x/_downloads/b990604c3b5a2778e66d16988eb16560/viz_wrecking_ball.py new file mode 100644 index 000000000..8909f369d --- /dev/null +++ b/v0.10.x/_downloads/b990604c3b5a2778e66d16988eb16560/viz_wrecking_ball.py @@ -0,0 +1,376 @@ +""" +======================== +Wrecking Ball Simulation +======================== + +This example simulation shows how to use pybullet to render physics simulations +in fury. In this example we specifically render a brick wall being destroyed by +a wrecking ball. + +First some imports. +""" +import itertools + +import numpy as np +import pybullet as p + +from fury import actor, ui, utils, window + +############################################################################### +# Initiate pybullet and enable gravity. + +p.connect(p.DIRECT) +p.setGravity(0, 0, -10) + +############################################################################### +# Define some handy parameters to customize simulation. + +# Parameters +wall_length = 5 +wall_breadth = 5 +wall_height = 5 + +brick_size = np.array([0.2, 0.4, 0.2]) + +n_links = 15 +# Size of segments +dx_link = 0.1 +link_mass = 0.5 +base_mass = 0.1 +# radius of the cylindrical links or the rope +radii = 0.1 + +ball_mass = 10 +# radius of the wrecking ball +ball_radius = 0.5 +ball_color = np.array([[1, 0, 0]]) + +joint_friction = 0.0005 + +############################################################################### +# Creating the base plane actor. + +# Base +base_actor = actor.box( + centers=np.array([[0, 0, 0]]), + directions=[0, 0, 0], + scales=(5, 5, 0.2), + colors=(1, 1, 1), +) +base_coll = p.createCollisionShape(p.GEOM_BOX, halfExtents=[2.5, 2.5, 0.1]) +base = p.createMultiBody( + baseCollisionShapeIndex=base_coll, + basePosition=[0, 0, -0.1], + baseOrientation=[0, 0, 0, 1], +) +p.changeDynamics(base, -1, lateralFriction=0.3, restitution=0.5) + +############################################################################### +# The following definitions are made to render a NxNxN brick wall. + +# Generate bricks. +nb_bricks = wall_length * wall_breadth * wall_height +brick_centers = np.zeros((nb_bricks, 3)) + +brick_directions = np.zeros((nb_bricks, 3)) +brick_directions[:] = np.array([1.57, 0, 0]) + +brick_orns = np.zeros((nb_bricks, 4)) + +brick_sizes = np.zeros((nb_bricks, 3)) +brick_sizes[:] = brick_size + +brick_colors = np.random.rand(nb_bricks, 3) + +brick_coll = p.createCollisionShape(p.GEOM_BOX, halfExtents=brick_size / 2) + +bricks = np.zeros(nb_bricks, dtype=np.int16) + +############################################################################### +# The following is the logic to position the bricks in our desired location and +# generate the actor. + +idx = 0 +# Setting up wall +for i in range(wall_length): + for k in range(wall_height): + for j in range(wall_breadth): + center_pos = np.array([(i * 0.2) - 1.8, (j * 0.4) - 0.9, (0.2 * k) + 0.1]) + brick_centers[idx] = center_pos + brick_orns[idx] = np.array([0, 0, 0, 1]) + bricks[idx] = p.createMultiBody( + baseMass=0.5, + baseCollisionShapeIndex=brick_coll, + basePosition=center_pos, + baseOrientation=brick_orns[i], + ) + p.changeDynamics(bricks[idx], -1, lateralFriction=0.1, restitution=0.1) + idx += 1 + +brick_actor = actor.box( + centers=brick_centers, + directions=brick_directions, + scales=brick_sizes, + colors=brick_colors, +) + +############################################################################### +# Now we render the wrecking ball consisting of a fixed hinge, a ball and rope. + +# Generate wrecking ball +link_shape = p.createCollisionShape( + p.GEOM_CYLINDER, + radius=radii, + height=dx_link, + collisionFramePosition=[0, 0, -dx_link / 2], +) + +base_shape = p.createCollisionShape(p.GEOM_BOX, halfExtents=[0.01, 0.01, 0.01]) +ball_shape = p.createCollisionShape(p.GEOM_SPHERE, radius=ball_radius) + +visualShapeId = -1 + +link_Masses = np.zeros(n_links) +link_Masses[:] = link_mass +link_Masses[-1] = 5 +linkCollisionShapeIndices = np.zeros(n_links) +linkCollisionShapeIndices[:] = np.array(link_shape) +linkCollisionShapeIndices[-1] = ball_shape +linkVisualShapeIndices = -1 * np.ones(n_links) +linkPositions = np.zeros((n_links, 3)) +linkPositions[:] = np.array([0, 0, -dx_link]) +linkOrientations = np.zeros((n_links, 4)) +linkOrientations[:] = np.array([0, 0, 0, 1]) +linkInertialFramePositions = np.zeros((n_links, 3)) +linkInertialFrameOrns = np.zeros((n_links, 4)) +linkInertialFrameOrns[:] = np.array([0, 0, 0, 1]) +indices = np.arange(n_links) +jointTypes = np.zeros(n_links) +jointTypes[:] = np.array(p.JOINT_SPHERICAL) +axis = np.zeros((n_links, 3)) +axis[:] = np.array([1, 0, 0]) + +linkDirections = np.zeros((n_links, 3)) +linkDirections[:] = np.array([1, 1, 1]) + +link_radii = np.zeros(n_links) +link_radii[:] = radii + +link_heights = np.zeros(n_links) +link_heights[:] = dx_link + +rope_actor = actor.cylinder( + centers=linkPositions, + directions=linkDirections, + colors=np.random.rand(n_links, 3), + radius=radii, + heights=link_heights, + capped=True, +) + +basePosition = [0, 0, 2] +baseOrientation = [0, 0, 0, 1] +rope = p.createMultiBody( + base_mass, + base_shape, + visualShapeId, + basePosition, + baseOrientation, + linkMasses=link_Masses, + linkCollisionShapeIndices=linkCollisionShapeIndices.astype(int), + linkVisualShapeIndices=linkVisualShapeIndices.astype(int), + linkPositions=linkPositions.astype(int), + linkOrientations=linkOrientations.astype(int), + linkInertialFramePositions=linkInertialFramePositions.astype(int), + linkInertialFrameOrientations=linkInertialFrameOrns.astype(int), + linkParentIndices=indices.astype(int), + linkJointTypes=jointTypes.astype(int), + linkJointAxis=axis.astype(int), +) + +############################################################################### +# Next we define the frictional force between the joints of wrecking ball. + +friction_vec = [joint_friction] * 3 # same all axis +control_mode = p.POSITION_CONTROL # set pos control mode +for j in range(p.getNumJoints(rope)): + p.setJointMotorControlMultiDof( + rope, + j, + control_mode, + targetPosition=[0, 0, 0, 1], + targetVelocity=[0, 0, 0], + positionGain=0, + velocityGain=1, + force=friction_vec, + ) + +############################################################################### +# We add the following constraint to keep the cubical hinge fixed. + +root_robe_c = p.createConstraint( + rope, -1, -1, -1, p.JOINT_FIXED, [0, 0, 0], [0, 0, 0], [0, 0, 2] +) + +box_actor = actor.box( + centers=np.array([[0, 0, 0]]), + directions=np.array([[0, 0, 0]]), + scales=(0.02, 0.02, 0.02), + colors=np.array([[1, 0, 0]]), +) + +ball_actor = actor.sphere( + centers=np.array([[0, 0, 0]]), radii=ball_radius, colors=np.array([1, 0, 1]) +) + +############################################################################### +# Now we add the necessary actors to the scene and set the camera for better +# visualization. + +scene = window.Scene() +scene.set_camera((10.28, -7.10, 6.39), (0.0, 0.0, 0.4), (-0.35, 0.26, 1.0)) +scene.add(actor.axes(scale=(0.5, 0.5, 0.5)), base_actor, brick_actor) +scene.add(rope_actor, box_actor, ball_actor) + +showm = window.ShowManager( + scene, size=(900, 768), reset_camera=False, order_transparent=True +) + + +############################################################################### +# Position the base correctly. + +base_pos, base_orn = p.getBasePositionAndOrientation(base) +base_actor.SetPosition(*base_pos) + +############################################################################### +# Calculate the vertices of the bricks. + +brick_vertices = utils.vertices_from_actor(brick_actor) +num_vertices = brick_vertices.shape[0] +num_objects = brick_centers.shape[0] +brick_sec = int(num_vertices / num_objects) + +############################################################################### +# Calculate the vertices of the wrecking ball. + +chain_vertices = utils.vertices_from_actor(rope_actor) +num_vertices = chain_vertices.shape[0] +num_objects = brick_centers.shape[0] +chain_sec = int(num_vertices / num_objects) + + +############################################################################### +# We define methods to sync bricks and wrecking ball. + +# Function for syncing actors with multibodies. +def sync_brick(object_index, multibody): + pos, orn = p.getBasePositionAndOrientation(multibody) + + rot_mat = np.reshape( + p.getMatrixFromQuaternion( + p.getDifferenceQuaternion(orn, brick_orns[object_index]) + ), + (3, 3), + ) + + sec = brick_sec + + brick_vertices[object_index * sec : object_index * sec + sec] = ( + brick_vertices[object_index * sec : object_index * sec + sec] + - brick_centers[object_index] + ) @ rot_mat + pos + + brick_centers[object_index] = pos + brick_orns[object_index] = orn + + +def sync_chain(actor_list, multibody): + for joint in range(p.getNumJoints(multibody)): + # `p.getLinkState` offers various information about the joints + # as a list and the values in 4th and 5th index refer to the joint's + # position and orientation respectively. + pos, orn = p.getLinkState(multibody, joint)[4:6] + + rot_mat = np.reshape( + p.getMatrixFromQuaternion( + p.getDifferenceQuaternion(orn, linkOrientations[joint]) + ), + (3, 3), + ) + + sec = chain_sec + + chain_vertices[joint * sec : joint * sec + sec] = ( + chain_vertices[joint * sec : joint * sec + sec] - linkPositions[joint] + ) @ rot_mat + pos + + linkPositions[joint] = pos + linkOrientations[joint] = orn + + +############################################################################### +# Some helper tools to keep track of avg. FPS and simulation steps. + +counter = itertools.count() +fpss = np.array([]) +tb = ui.TextBlock2D( + position=(0, 680), font_size=30, color=(1, 0.5, 0), text='Avg. FPS: \nSim Steps: ' +) +scene.add(tb) + +############################################################################### +# Timer callback to sync objects, simulate steps and apply force. + +apply_force = True + + +# Create timer callback which will execute at each step of simulation. +def timer_callback(_obj, _event): + global apply_force, fpss + cnt = next(counter) + showm.render() + + if cnt % 1 == 0: + fps = showm.frame_rate + fpss = np.append(fpss, fps) + tb.message = ( + 'Avg. FPS: ' + str(np.round(np.mean(fpss), 0)) + '\nSim Steps: ' + str(cnt) + ) + + # Updating the position and orientation of each individual brick. + for idx, brick in enumerate(bricks): + sync_brick(idx, brick) + + pos, _ = p.getBasePositionAndOrientation(rope) + + if apply_force: + p.applyExternalForce( + rope, -1, forceObj=[-500, 0, 0], posObj=pos, flags=p.WORLD_FRAME + ) + apply_force = False + + pos = p.getLinkState(rope, p.getNumJoints(rope) - 1)[4] + ball_actor.SetPosition(*pos) + sync_chain(rope_actor, rope) + utils.update_actor(brick_actor) + utils.update_actor(rope_actor) + + # Simulate a step. + p.stepSimulation() + + if cnt == 130: + showm.exit() + + +# Add the timer callback to showmanager. +# Increasing the duration value will slow down the simulation. +showm.add_timer_callback(True, 1, timer_callback) + +interactive = True #False + +# start simulation +if interactive: + showm.start() + +window.record(scene, size=(900, 768), out_path='viz_wrecking_ball.png') diff --git a/v0.10.x/_downloads/bd014674b55899498e6c47d54b8c1e50/viz_widget.py b/v0.10.x/_downloads/bd014674b55899498e6c47d54b8c1e50/viz_widget.py new file mode 100644 index 000000000..5a500803a --- /dev/null +++ b/v0.10.x/_downloads/bd014674b55899498e6c47d54b8c1e50/viz_widget.py @@ -0,0 +1,89 @@ +""" +======================================================== +Streaming FURY with WebRTC/MJPEG using the Widget Object +======================================================== + +The Widget Object simplifies the process of streaming +your data visualization with WebRTC or MJPEG. Encoding. +Other users can view and interact with your data visualization +in real-time using a web-browser. + +By default, the widget will open a local server on port 8000. +With the encoding parameter you can choose between mjpeg or +webrtc. WebRTC is a more robust option and can be used to perform +a live streaming with a low-latency connection. However, to use +webRTC you need to install the aiortc library. + +.. code-block:: bash + + pip install aiortc + +In addition, if you don't have ffmpeg installed, you need +to install it. + +Linux + + +`apt install libavdevice-dev libavfilter-dev libopus-dev libvpx-dev pkg-config` + +OS X + +`brew install ffmpeg opus libvpx pkg-config` + +Notes +----- +For this example your python version should be 3.8 or greater + +""" + +import asyncio +import platform +import time + +import numpy as np + +from fury import actor, window +from fury.stream.widget import Widget + +interactive = False +window_size = (720, 500) +N = 4 +centers = np.random.normal(size=(N, 3)) +colors = np.random.uniform(0.1, 1.0, size=(N, 3)) +actors = actor.sphere(centers, opacity=0.5, radii=0.4, colors=colors) +scene = window.Scene() +scene.add(actors) +showm = window.ShowManager(scene, size=(window_size[0], window_size[1])) + +########################################################################## +# Create a stream widget + +widget = Widget(showm, port=8000) + +# if you want to use webRTC, you can pass the argument to choose this encoding +# which is a more robust option. +# `widget = Widget(showm, port=8000, encoding='webrtc')` + +time_sleep = 1000 if interactive else 1 + +########################################################################### +# If you want to use the widget in a Windows environment without the WSL +# you need to use the asyncio version of the widget. +# +if platform.system() == 'Windows': + + async def main(): + widget.start() + await asyncio.sleep(time_sleep) + widget.stop() + + loop = asyncio.get_event_loop() + loop.run_until_complete(main()) +else: + # Running the widget in a normal Python environment in Linux or MacOS + # we can use the normal version of the widget. + widget.start() + time.sleep(time_sleep) + widget.stop() + +window.record(showm.scene, size=window_size, out_path='viz_widget.png') diff --git a/v0.10.x/_downloads/bda8ef3a26a1a05148ae2a99f6db2ade/viz_radio_buttons.py b/v0.10.x/_downloads/bda8ef3a26a1a05148ae2a99f6db2ade/viz_radio_buttons.py new file mode 100644 index 000000000..8cec217b0 --- /dev/null +++ b/v0.10.x/_downloads/bda8ef3a26a1a05148ae2a99f6db2ade/viz_radio_buttons.py @@ -0,0 +1,85 @@ +""" +======================================== +Sphere Color Control using Radio Buttons +======================================== + +This example shows how to use the UI API. We will demonstrate how to +create a Sphere and control its color using radio buttons. + +First, some imports. +""" + +import numpy as np + +from fury import actor, ui, utils, window +from fury.data import fetch_viz_icons + +############################################################################## +# First we need to fetch some icons that are included in FURY. + +fetch_viz_icons() + +######################################################################## +# Sphere and Radio Buttons +# ======================== +# +# Add a Sphere to the scene. + +sphere = actor.sphere( + centers=np.array([[50, 0, 0]]), + colors=np.array([[0, 0, 1]]), + radii=11.0, + theta=360, + phi=360, +) + +# Creating a dict of possible options and mapping it with their values. +options = {'Blue': (0, 0, 255), 'Red': (255, 0, 0), 'Green': (0, 255, 0)} + +color_toggler = ui.RadioButton( + list(options), + checked_labels=['Blue'], + padding=1, + font_size=16, + font_family='Arial', + position=(200, 200), +) + + +# A callback which will set the values for the box +def toggle_color(radio): + vcolors = utils.colors_from_actor(sphere) + color = options[radio.checked_labels[0]] + vcolors[:] = np.array(color) + utils.update_actor(sphere) + + +color_toggler.on_change = toggle_color + + +############################################################################### +# Show Manager +# ============ +# +# Now that all the elements have been initialised, we add them to the show +# manager. + +current_size = (800, 800) +show_manager = window.ShowManager(size=current_size, title='FURY Sphere Example') + +show_manager.scene.add(sphere) +show_manager.scene.add(color_toggler) + +############################################################################### +# Set camera for better visualization + +show_manager.scene.reset_camera() +show_manager.scene.set_camera(position=(0, 0, 150)) +show_manager.scene.reset_clipping_range() +show_manager.scene.azimuth(30) +interactive = False + +if interactive: + show_manager.start() + +window.record(show_manager.scene, size=current_size, out_path='viz_radio_buttons.png') diff --git a/v0.10.x/_downloads/bde366869ce48437300434c5b06ac5d2/viz_buttons.ipynb b/v0.10.x/_downloads/bde366869ce48437300434c5b06ac5d2/viz_buttons.ipynb new file mode 100644 index 000000000..b2a64791d --- /dev/null +++ b/v0.10.x/_downloads/bde366869ce48437300434c5b06ac5d2/viz_buttons.ipynb @@ -0,0 +1,151 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Buttons & Text\n\nThis example shows how to use the UI API. We will demonstrate how to create\npanel having buttons with callbacks.\n\nFirst, some imports.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "from fury import ui, window\nfrom fury.data import fetch_viz_icons, read_viz_icons" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "First we need to fetch some icons that are included in FURY.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "fetch_viz_icons()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's create some buttons and text and put them in a panel.\nFirst we'll make the panel.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "panel = ui.Panel2D(size=(300, 150), color=(1, 1, 1), align='right')\npanel.center = (500, 400)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Then we'll make two text labels and place them on the panel.\nNote that we specify the position with integer numbers of pixels.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "text = ui.TextBlock2D(text='Click me')\ntext2 = ui.TextBlock2D(text='Me too')\npanel.add_element(text, (50, 100))\npanel.add_element(text2, (180, 100))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Then we'll create two buttons and add them to the panel.\n\nNote that here we specify the positions with floats. In this case, these are\npercentages of the panel size.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "button_example = ui.Button2D(\n icon_fnames=[('square', read_viz_icons(fname='stop2.png'))]\n)\n\nicon_files = []\nicon_files.append(('down', read_viz_icons(fname='circle-down.png')))\nicon_files.append(('left', read_viz_icons(fname='circle-left.png')))\nicon_files.append(('up', read_viz_icons(fname='circle-up.png')))\nicon_files.append(('right', read_viz_icons(fname='circle-right.png')))\n\nsecond_button_example = ui.Button2D(icon_fnames=icon_files)\n\npanel.add_element(button_example, (0.25, 0.33))\npanel.add_element(second_button_example, (0.66, 0.33))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can add a callback to each button to perform some action.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def change_text_callback(i_ren, _obj, _button):\n text.message = 'Clicked!'\n i_ren.force_render()\n\n\ndef change_icon_callback(i_ren, _obj, _button):\n _button.next_icon()\n i_ren.force_render()\n\n\nbutton_example.on_left_mouse_button_clicked = change_text_callback\nsecond_button_example.on_left_mouse_button_pressed = change_icon_callback" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now that all the elements have been initialised, we add them to the show\nmanager.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "current_size = (800, 800)\nshow_manager = window.ShowManager(size=current_size, title='FURY Button Example')\n\nshow_manager.scene.add(panel)\n\ninteractive = False\n\nif interactive:\n show_manager.start()\n\nwindow.record(show_manager.scene, size=current_size, out_path='viz_button.png')" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.8" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/v0.10.x/_downloads/c2aaa3511941c3de8cde8d6048f25338/viz_gltf_export.ipynb b/v0.10.x/_downloads/c2aaa3511941c3de8cde8d6048f25338/viz_gltf_export.ipynb new file mode 100644 index 000000000..f4f1117c2 --- /dev/null +++ b/v0.10.x/_downloads/c2aaa3511941c3de8cde8d6048f25338/viz_gltf_export.ipynb @@ -0,0 +1,169 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Exporting scene as a glTF file\nIn this tutorial, we will show how to create a glTF file for a scene.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "import numpy as np\n\nfrom fury import actor, gltf, window\nfrom fury.data import fetch_gltf, read_viz_gltf" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Specifying centers and colors for actors. We will use these parameters\nlater.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "centers = np.zeros((3, 3))\ncolors = np.array([1, 1, 1])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Create a scene.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "scene = window.Scene()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Creating actors and adding to scene.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "cube = actor.cube(np.add(centers, np.array([2, 0, 0])), colors=colors / 2)\nscene.add(cube)\n\nsphere = actor.sphere(np.add(centers, np.array([0, 2, 0])), colors=colors)\nscene.add(sphere)\n\nfetch_gltf('BoxTextured', 'glTF')\nfilename = read_viz_gltf('BoxTextured')\ngltf_obj = gltf.glTF(filename)\nbox_actor = gltf_obj.actors()\nscene.add(box_actor[0])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Setting camera to the scene.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "scene.set_camera(\n position=(4.45, -21, 12), focal_point=(4.45, 0.0, 0.0), view_up=(0.0, 0.0, 1.0)\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Exporting scene as a glTF file\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "gltf.export_scene(scene, filename='viz_gltf_export.gltf')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Reading the newly created glTF file and get actors.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "gltf_obj = gltf.glTF('viz_gltf_export.gltf')\nactors = gltf_obj.actors()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Add all the actor from list of actors to the scene.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "scene.add(*actors)\n\ninteractive = False\n\nif interactive:\n window.show(scene, size=(1280, 720))\n\nwindow.record(scene, out_path='viz_gltf_export.png', size=(1280, 720))" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.8" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/v0.10.x/_downloads/c539298c1966ce620bae10e2057d5ee7/viz_no_interaction.py b/v0.10.x/_downloads/c539298c1966ce620bae10e2057d5ee7/viz_no_interaction.py new file mode 100644 index 000000000..56862bbda --- /dev/null +++ b/v0.10.x/_downloads/c539298c1966ce620bae10e2057d5ee7/viz_no_interaction.py @@ -0,0 +1,106 @@ +""" +==================================== +Streaming FURY with WebRTC/MJPEG +==================================== +""" + +import multiprocessing +from os.path import join as pjoin + +# if this example it's not working for you and you're using MacOs +# uncomment the following line +# multiprocessing.set_start_method('spawn') +import numpy as np + +from fury import actor +from fury import colormap as cmap +from fury import window +from fury.data.fetcher import fetch_viz_wiki_nw +from fury.stream.client import FuryStreamClient +from fury.stream.server.main import web_server_raw_array + +if __name__ == '__main__': + + interactive = False + ########################################################################### + # First we will set the resolution which it'll be used by the streamer + + window_size = (400, 400) + + files, folder = fetch_viz_wiki_nw() + categories_file, edges_file, positions_file = sorted(files.keys()) + positions = np.loadtxt(pjoin(folder, positions_file)) + categories = np.loadtxt(pjoin(folder, categories_file), dtype=str) + edges = np.loadtxt(pjoin(folder, edges_file), dtype=int) + category2index = {category: i for i, category in enumerate(np.unique(categories))} + + index2category = np.unique(categories) + + categoryColors = cmap.distinguishable_colormap(nb_colors=len(index2category)) + + colors = np.array( + [categoryColors[category2index[category]] for category in categories] + ) + radii = 1 + np.random.rand(len(positions)) + + edgesPositions = [] + edgesColors = [] + for source, target in edges: + edgesPositions.append(np.array([positions[source], positions[target]])) + edgesColors.append(np.array([colors[source], colors[target]])) + + edgesPositions = np.array(edgesPositions) + edgesColors = np.average(np.array(edgesColors), axis=1) + + sphere_actor = actor.sdf( + centers=positions, + colors=colors, + primitives='sphere', + scales=radii * 0.5, + ) + + lines_actor = actor.line( + edgesPositions, + colors=edgesColors, + opacity=0.1, + ) + scene = window.Scene() + + scene.add(lines_actor) + scene.add(sphere_actor) + + scene.set_camera( + position=(0, 0, 1000), focal_point=(0.0, 0.0, 0.0), view_up=(0.0, 0.0, 0.0) + ) + + showm = window.ShowManager( + scene, + reset_camera=False, + size=(window_size[0], window_size[1]), + order_transparent=False, + ) + + ########################################################################### + # ms define the amount of mileseconds that will be used in the timer event. + + ms = 0 + + stream = FuryStreamClient(showm, use_raw_array=True) + p = multiprocessing.Process( + target=web_server_raw_array, + args=( + stream.img_manager.image_buffers, + stream.img_manager.info_buffer, + ), + ) + p.start() + + stream.start( + ms, + ) + if interactive: + showm.start() + stream.stop() + stream.cleanup() + + window.record(showm.scene, size=window_size, out_path='viz_no_interaction.png') diff --git a/v0.10.x/_downloads/c5580fbbf92d43a5a1e9ea1d9fc0854d/viz_dt_ellipsoids.py b/v0.10.x/_downloads/c5580fbbf92d43a5a1e9ea1d9fc0854d/viz_dt_ellipsoids.py new file mode 100644 index 000000000..d45536732 --- /dev/null +++ b/v0.10.x/_downloads/c5580fbbf92d43a5a1e9ea1d9fc0854d/viz_dt_ellipsoids.py @@ -0,0 +1,329 @@ +""" +=============================================================================== +Display Tensor Ellipsoids for DTI using tensor_slicer vs ellipsoid actor +=============================================================================== +This tutorial is intended to show two ways of displaying diffusion tensor +ellipsoids for DTI visualization. The first is using the usual +``tensor_slicer`` that allows us to slice many tensors as ellipsoids. The +second is the generic ``ellipsoid`` actor that can be used to display different +amount of ellipsoids. + +We start by importing the necessary modules: +""" +import itertools + +import numpy as np + +from dipy.io.image import load_nifti + +from fury import window, actor, ui +from fury.actor import _fa, _color_fa +from fury.data import fetch_viz_dmri, read_viz_dmri +from fury.primitive import prim_sphere + +############################################################################### +# Now, we fetch and load the data needed to display the Diffusion Tensor +# Images. + +fetch_viz_dmri() + +############################################################################### +# The tensor ellipsoids are expressed as eigenvalues and eigenvectors which are +# the decomposition of the diffusion tensor that describes the water diffusion +# within a voxel. + +slice_evecs, _ = load_nifti(read_viz_dmri('slice_evecs.nii.gz')) +slice_evals, _ = load_nifti(read_viz_dmri('slice_evals.nii.gz')) +roi_evecs, _ = load_nifti(read_viz_dmri('roi_evecs.nii.gz')) +roi_evals, _ = load_nifti(read_viz_dmri('roi_evals.nii.gz')) +whole_brain_evecs, _ = load_nifti(read_viz_dmri('whole_brain_evecs.nii.gz')) +whole_brain_evals, _ = load_nifti(read_viz_dmri('whole_brain_evals.nii.gz')) + +############################################################################### +# Using tensor_slicer actor +# ========================= +# First we must define the 3 parameters needed to use the ``tensor_slicer`` +# actor, which correspond to the eigenvalues, the eigenvectors, and the sphere. +# For the sphere we use ``prim_sphere`` which provide vertices and triangles of +# the spheres. These are labeled as 'repulsionN' with N been the number of +# vertices that made up the sphere, which have a standard number of 100, 200, +# and 724 vertices. + +vertices, faces = prim_sphere('repulsion100', True) + + +############################################################################### +# As we need to provide a sphere object we create a class Sphere to which we +# assign the values obtained from vertices and faces. + +class Sphere: + def __init__(self, vertices, faces): + self.vertices = vertices + self.faces = faces + + +sphere100 = Sphere(vertices, faces) + +############################################################################### +# Now we are ready to create the ``tensor_slicer`` actor with the values of a +# brain slice. We also define the scale so that the tensors are not so large +# and overlap each other. + +tensor_slice = actor.tensor_slicer(evals=slice_evals, evecs=slice_evecs, + sphere=sphere100, scale=.3) + +############################################################################### +# Next, we set up a new scene to add and visualize the tensor ellipsoids +# created. + +scene = window.Scene() +scene.background([255, 255, 255]) +scene.add(tensor_slice) + +# Create show manager +showm = window.ShowManager(scene, size=(600, 600)) + +# Enables/disables interactive visualization +interactive = False + +if interactive: + showm.start() + +window.record(showm.scene, size=(600, 600), out_path='tensor_slice_100.png') + +############################################################################### +# If we zoom in at the scene to see with detail the tensor ellipsoids displayed +# with the different spheres, we get the following results. + +scene.roll(10) +scene.pitch(90) +showm = window.ShowManager(scene, size=(600, 600), order_transparent=True) +showm.scene.zoom(50) + +if interactive: + showm.render() + showm.start() + +window.record(showm.scene, out_path='tensor_slice_100_zoom.png', + size=(600, 300), reset_camera=False) + +############################################################################### +# To render the same tensor slice using a different sphere we redefine the +# vertices and faces of the sphere using prim_sphere with other sphere +# specification, as 'repulsion200' or 'repulsion724'. +# +# Now we clear the scene for the next visualization, and revert the scene +# rotations. + +showm.scene.clear() +showm.scene.pitch(-90) +showm.scene.roll(-10) + + +############################################################################### +# Using ellipsoid actor +# ===================== +# In order to use the ``ellipsoid`` actor to display the same tensor slice we +# need to set additional parameters. For this purpose, we define a helper +# function to facilitate the correct setting of the parameters before passing +# them to the actor. + +def get_params(evecs, evals): + # We define the centers which corresponds to the ellipsoids positions. + valid_mask = np.abs(evecs).max(axis=(-2, -1)) > 0 + indices = np.nonzero(valid_mask) + centers = np.asarray(indices).T + + # We need to pass the data of the axes and lengths of the ellipsoid as a + # ndarray, so it is necessary to rearrange the data of the eigenvectors and + # eigenvalues. + fevecs = evecs[indices] + fevals = evals[indices] + + # We need to define the colors of the ellipsoids following the default + # coloring in tensor_slicer that is uses _color_fa that is a way to map + # colors to each tensor based on the fractional anisotropy (FA) of each + # diffusion tensor. + colors = _color_fa(_fa(fevals), fevecs) + + return centers, fevecs, fevals, colors + + +############################################################################### +# With this we now have the values we need to define the centers, axes, +# lengths, and colors of the ellipsoids. + +centers, evecs, evals, colors = get_params(slice_evecs, slice_evals) + +############################################################################### +# Now, we can use the ``ellipsoid`` actor to create the tensor ellipsoids as +# follows. + +tensors = actor.ellipsoid(centers=centers, colors=colors, axes=evecs, + lengths=evals, scales=.6) +showm.scene.add(tensors) + +if interactive: + showm.start() + +window.record(scene, size=(600, 600), out_path='tensor_slice_sdf.png') + +############################################################################### +# Thus, one can see that the same result is obtained, however there is a +# difference in the visual quality and this is because the ``ellipsoid`` actor +# uses raymarching technique, so the objects that are generated are smoother +# since they are not made with polygons but defined by an SDF function. Next we +# can see in more detail the tensor ellipsoids generated. + +scene.roll(10) +scene.pitch(90) +showm = window.ShowManager(scene, size=(600, 600), order_transparent=True) +showm.scene.zoom(50) + +if interactive: + showm.render() + showm.start() + +window.record(showm.scene, out_path='tensor_slice_sdf_zoom.png', + size=(600, 300), reset_camera=False) + +showm.scene.clear() +showm.scene.pitch(-90) +showm.scene.roll(-10) + +############################################################################### +# Visual quality comparison +# ========================= +# One can see that there is a different on the visual quality of both ways of +# displaying tensors and this is because ``tensor_slicer`` uses polygons while +# ``ellipsoid`` uses raymarching. Let's display both implementations at the +# same time, so we can see this in more detail. +# +# We first set up the required data and create the actors. + +mevals = np.array([1.4, 1.0, 0.35]) * 10 ** (-3) +mevecs = np.array([[2/3, -2/3, 1/3], [1/3, 2/3, 2/3], [2/3, 1/3, -2/3]]) + +evals = np.zeros((1, 1, 1, 3)) +evecs = np.zeros((1, 1, 1, 3, 3)) + +evals[..., :] = mevals +evecs[..., :, :] = mevecs + +vertices, faces = prim_sphere('repulsion200', True) +sphere200 = Sphere(vertices, faces) +vertices, faces = prim_sphere('repulsion724', True) +sphere724 = Sphere(vertices, faces) + +tensor_100 = actor.tensor_slicer(evals=evals, evecs=evecs, + sphere=sphere100, scale=1.0) +tensor_200 = actor.tensor_slicer(evals=evals, evecs=evecs, + sphere=sphere200, scale=1.0) +tensor_724 = actor.tensor_slicer(evals=evals, evecs=evecs, + sphere=sphere724, scale=1.0) + +centers, evecs, evals, colors = get_params(evecs=evecs, evals=evals) +tensor_sdf = actor.ellipsoid(centers=centers, axes=evecs, lengths=evals, + colors=colors, scales=2.0) + +############################################################################### +# Next, we made use of `GridUI` which allows us to add the actors in a grid and +# interact with them individually. + +objects = [tensor_100, tensor_200, tensor_724, tensor_sdf] +text = [actor.vector_text('Tensor 100'), actor.vector_text('Tensor 200'), + actor.vector_text('Tensor 724'), actor.vector_text('Tensor SDF')] + +grid_ui = ui.GridUI(actors=objects, captions=text, cell_padding=.1, + caption_offset=(-0.7, -2.5, 0), dim=(1, 4)) + +scene = window.Scene() +scene.background([255, 255, 255]) +scene.zoom(3.5) +scene.set_camera(position=(3.2, -20, 12), focal_point=(3.2, 0.0, 0.0)) +showm = window.ShowManager(scene, size=(560, 200)) +showm.scene.add(grid_ui) + +if interactive: + showm.start() + +window.record(showm.scene, size=(560, 200), out_path='tensor_comparison.png', + reset_camera=False, magnification=2) + +showm.scene.clear() + +############################################################################### +# Visualize a larger amount of data +# ================================= +# With ``tensor_slicer`` is possible to visualize more than one slice using +# ``display_extent()``. Here we can see an example of a region of interest +# (ROI) using a sphere of 100 vertices. + +tensor_roi = actor.tensor_slicer(evals=roi_evals, evecs=roi_evecs, + sphere=sphere100, scale=.3) + +data_shape = roi_evals.shape[:3] +tensor_roi.display_extent( + 0, data_shape[0], 0, data_shape[1], 0, data_shape[2]) + +showm.size = (600, 600) +showm.scene.background([0, 0, 0]) +showm.scene.add(tensor_roi) +showm.scene.azimuth(87) + +if interactive: + showm.start() + +window.record(showm.scene, size=(600, 600), out_path='tensor_roi_100.png') + +showm.scene.clear() + +############################################################################### +# We can do it also with a sphere of 200 vertices, but if we try to do it with +# one of 724 the visualization can no longer be rendered. In contrast, we can +# visualize the ROI with the ``ellipsoid`` actor without compromising the +# quality of the visualization. + +centers, evecs, evals, colors = get_params(roi_evecs, roi_evals) + +tensors = actor.ellipsoid(centers=centers, colors=colors, axes=evecs, + lengths=evals, scales=.6) +showm.scene.add(tensors) + +if interactive: + showm.start() + +window.record(showm.scene, size=(600, 600), out_path='tensor_roi_sdf.png') + +showm.scene.clear() + +############################################################################### +# In fact, although with a low performance, this actor allows us to visualize +# the whole brain, which contains a much larger amount of data, to be exact +# 184512 tensor ellipsoids are displayed at the same time. + +centers, evecs, evals, colors = get_params(whole_brain_evecs, + whole_brain_evals) + +# We remove all the noise around the brain to have a better visualization. +fil = [len(set(elem)) != 1 for elem in evals] +centers = np.array(list(itertools.compress(centers, fil))) +colors = np.array(list(itertools.compress(colors, fil))) +evecs = np.array(list(itertools.compress(evecs, fil))) +evals = np.array(list(itertools.compress(evals, fil))) + +tensors = actor.ellipsoid(centers=centers, colors=colors, axes=evecs, + lengths=evals, scales=.6) + +scene = window.Scene() +scene.add(tensors) +scene.pitch(180) +showm = window.ShowManager(scene, size=(600, 600)) + +if interactive: + showm.start() + +window.record(showm.scene, size=(600, 600), reset_camera=False, + out_path='tensor_whole_brain_sdf.png') + +showm.scene.clear() diff --git a/v0.10.x/_downloads/c7f697171b4b08caef3e59c0dec874d3/collision-particles.py b/v0.10.x/_downloads/c7f697171b4b08caef3e59c0dec874d3/collision-particles.py new file mode 100644 index 000000000..c93167615 --- /dev/null +++ b/v0.10.x/_downloads/c7f697171b4b08caef3e59c0dec874d3/collision-particles.py @@ -0,0 +1,180 @@ +""" +Collisions of particles in a box +================================ + +This is a simple demonstration of how you can simulate moving +particles in a box using FURY. +""" + +############################################################################## +# In this example, the particles collide with each other and with the walls +# of the container. When the collision happens between two particles, +# the particle with less velocity changes its color and gets the same color +# as the particle with higher velocity. For simplicity, in this demo we +# do not apply forces. + +import itertools + +import numpy as np + +from fury import actor, ui, utils, window + +############################################################################## +# Here, we define the edges of the box. + + +def box_edges(box_lx, box_ly, box_lz): + + edge1 = 0.5 * np.array( + [ + [box_lx, box_ly, box_lz], + [box_lx, box_ly, -box_lz], + [-box_lx, box_ly, -box_lz], + [-box_lx, box_ly, box_lz], + [box_lx, box_ly, box_lz], + ] + ) + edge2 = 0.5 * np.array([[box_lx, box_ly, box_lz], [box_lx, -box_ly, box_lz]]) + edge3 = 0.5 * np.array([[box_lx, box_ly, -box_lz], [box_lx, -box_ly, -box_lz]]) + edge4 = 0.5 * np.array([[-box_lx, box_ly, -box_lz], [-box_lx, -box_ly, -box_lz]]) + edge5 = 0.5 * np.array([[-box_lx, box_ly, box_lz], [-box_lx, -box_ly, box_lz]]) + lines = [edge1, -edge1, edge2, edge3, edge4, edge5] + return lines + + +############################################################################## +# Here we define collision between walls-particles and particle-particle. +# When collision happens, the particle with lower velocity gets the +# color of the particle with higher velocity + + +def collision(): + global xyz + num_vertices = vertices.shape[0] + sec = int(num_vertices / num_particles) + + for i, j in np.ndindex(num_particles, num_particles): + + if i == j: + continue + distance = np.linalg.norm(xyz[i] - xyz[j]) + vel_mag_i = np.linalg.norm(vel[i]) + vel_mag_j = np.linalg.norm(vel[j]) + # Collision happens if the distance between the centers of two + # particles is less or equal to the sum of their radii + if distance <= (radii[i] + radii[j]): + vel[i] = -vel[i] + vel[j] = -vel[j] + if vel_mag_j > vel_mag_i: + vcolors[i * sec : i * sec + sec] = vcolors[j * sec : j * sec + sec] + if vel_mag_i > vel_mag_j: + vcolors[j * sec : j * sec + sec] = vcolors[i * sec : i * sec + sec] + xyz[i] = xyz[i] + vel[i] * dt + xyz[j] = xyz[j] + vel[j] * dt + # Collision between particles-walls; + vel[:, 0] = np.where( + ( + (xyz[:, 0] <= -0.5 * box_lx + radii[:]) + | (xyz[:, 0] >= (0.5 * box_lx - radii[:])) + ), + -vel[:, 0], + vel[:, 0], + ) + vel[:, 1] = np.where( + ( + (xyz[:, 1] <= -0.5 * box_ly + radii[:]) + | (xyz[:, 1] >= (0.5 * box_ly - radii[:])) + ), + -vel[:, 1], + vel[:, 1], + ) + vel[:, 2] = np.where( + ( + (xyz[:, 2] <= -0.5 * box_lz + radii[:]) + | (xyz[:, 2] >= (0.5 * box_lz - radii[:])) + ), + -vel[:, 2], + vel[:, 2], + ) + + +############################################################################## +# We define position, velocity, color and radius randomly for 50 particles +# inside the box. + +global xyz +num_particles = 50 +box_lx = 20 +box_ly = 20 +box_lz = 10 +steps = 1000 +dt = 0.05 +xyz = ( + np.array([box_lx, box_ly, box_lz]) * (np.random.rand(num_particles, 3) - 0.5) * 0.6 +) +vel = 4 * (np.random.rand(num_particles, 3) - 0.5) +colors = np.random.rand(num_particles, 3) +radii = np.random.rand(num_particles) + 0.01 + +############################################################################## +# With box, streamtube and sphere actors, we can create the box, the +# edges of the box and the spheres respectively. + +scene = window.Scene() +box_centers = np.array([[0, 0, 0]]) +box_directions = np.array([[0, 1, 0]]) +box_colors = np.array([[1, 1, 1, 0.2]]) +box_actor = actor.box( + box_centers, box_directions, box_colors, scales=(box_lx, box_ly, box_lz) +) +scene.add(box_actor) + +lines = box_edges(box_lx, box_ly, box_lz) +line_actor = actor.streamtube(lines, colors=(1, 0.5, 0), linewidth=0.1) +scene.add(line_actor) + +sphere_actor = actor.sphere(centers=xyz, colors=colors, radii=radii) +scene.add(sphere_actor) + +showm = window.ShowManager( + scene, size=(900, 768), reset_camera=True, order_transparent=True +) + +tb = ui.TextBlock2D(bold=True) +scene.zoom(0.8) +scene.azimuth(30) + +# use itertools to avoid global variables +counter = itertools.count() + +vertices = utils.vertices_from_actor(sphere_actor) +vcolors = utils.colors_from_actor(sphere_actor, 'colors') +no_vertices_per_sphere = len(vertices) / num_particles +initial_vertices = vertices.copy() - np.repeat(xyz, no_vertices_per_sphere, axis=0) + + +def timer_callback(_obj, _event): + global xyz + cnt = next(counter) + tb.message = "Let's count up to 1000 and exit :" + str(cnt) + xyz = xyz + vel * dt + collision() + + vertices[:] = initial_vertices + np.repeat(xyz, no_vertices_per_sphere, axis=0) + utils.update_actor(sphere_actor) + + scene.reset_clipping_range() + showm.render() + + if cnt == steps: + showm.exit() + + +scene.add(tb) +showm.add_timer_callback(True, 50, timer_callback) + +interactive = False +if interactive: + showm.start() + +window.record(showm.scene, size=(900, 768), out_path='simple_collisions.png') diff --git a/v0.10.x/_downloads/c825ae147a5ad6b73c459b53773372f1/viz_network.py b/v0.10.x/_downloads/c825ae147a5ad6b73c459b53773372f1/viz_network.py new file mode 100644 index 000000000..5ac3cc05b --- /dev/null +++ b/v0.10.x/_downloads/c825ae147a5ad6b73c459b53773372f1/viz_network.py @@ -0,0 +1,109 @@ +""" +======================================================= +Visualize Interdisciplinary map of the journals network +======================================================= + +The goal of this app is to show an overview of the journals network structure +as a complex network. Each journal is shown as a node and their connections +indicates a citation between two of them. +""" + +############################################################################### +# First, let's import some useful functions + +from os.path import join as pjoin + +import numpy as np + +from fury import actor +from fury import colormap as cmap +from fury import window +from fury.data import fetch_viz_wiki_nw + +############################################################################### +# Then let's download some available datasets. + + +files, folder = fetch_viz_wiki_nw() +categories_file, edges_file, positions_file = sorted(files.keys()) + +############################################################################### +# We read our datasets + +positions = np.loadtxt(pjoin(folder, positions_file)) +categories = np.loadtxt(pjoin(folder, categories_file), dtype=str) +edges = np.loadtxt(pjoin(folder, edges_file), dtype=int) + +############################################################################### +# We attribute a color to each category of our dataset which correspond to our +# nodes colors. + +category2index = {category: i for i, category in enumerate(np.unique(categories))} + +index2category = np.unique(categories) + +categoryColors = cmap.distinguishable_colormap(nb_colors=len(index2category)) + +colors = np.array([categoryColors[category2index[category]] for category in categories]) + +############################################################################### +# We define our node size + +radii = 1 + np.random.rand(len(positions)) + +############################################################################### +# Lets create our edges now. They will indicate a citation between two nodes. +# OF course, the colors of each edges will be an interpolation between the two +# node that it connects. + +edgesPositions = [] +edgesColors = [] +for source, target in edges: + edgesPositions.append(np.array([positions[source], positions[target]])) + edgesColors.append(np.array([colors[source], colors[target]])) + +edgesPositions = np.array(edgesPositions) +edgesColors = np.average(np.array(edgesColors), axis=1) + +############################################################################### +# Our data preparation is ready, it is time to visualize them all. We start to +# build 2 actors that we represent our data : sphere_actor for the nodes and +# lines_actor for the edges. + +sphere_actor = actor.sphere( + centers=positions, + colors=colors, + radii=radii * 0.5, + theta=8, + phi=8, +) + +lines_actor = actor.line( + edgesPositions, + colors=edgesColors, + opacity=0.1, +) + +############################################################################### +# All actors need to be added in a scene, so we build one and add our +# lines_actor and sphere_actor. + +scene = window.Scene() + +scene.add(lines_actor) +scene.add(sphere_actor) + +############################################################################### +# The final step ! Visualize and save the result of our creation! Please, +# switch interactive variable to True if you want to visualize it. + +interactive = False + +if interactive: + window.show(scene, size=(600, 600)) + +window.record(scene, out_path='journal_networks.png', size=(600, 600)) + +############################################################################### +# This example can be improved by adding some interactivy with slider, +# picking, etc. Play with it, improve it! diff --git a/v0.10.x/_downloads/ca23d044295b307e6e55c0617576e486/viz_picking.py b/v0.10.x/_downloads/ca23d044295b307e6e55c0617576e486/viz_picking.py new file mode 100644 index 000000000..00b14c5f8 --- /dev/null +++ b/v0.10.x/_downloads/ca23d044295b307e6e55c0617576e486/viz_picking.py @@ -0,0 +1,160 @@ +""" +===================== +Simple picking +===================== + +Here we present a tutorial showing how to interact with objects in the +3D world. All objects to be picked are part of a single actor. +FURY likes to bundle objects in a few actors to reduce code and +increase speed. + +When the objects are picked they will change size and color. +""" + +import numpy as np + +from fury import actor, pick, ui, utils, window + +centers = 0.5 * np.array([[0, 0, 0], [100, 0, 0], [200, 0, 0.0]]) +colors = np.array([[0.8, 0, 0], [0, 0.8, 0], [0, 0, 0.8]]) +radii = 0.1 * np.array([50, 100, 150.0]) + +selected = np.zeros(3, dtype=bool) + +############################################################################### +# Let's create a panel to show what is picked + +panel = ui.Panel2D(size=(400, 200), color=(1, 0.5, 0.0), align='right') +panel.center = (150, 200) + +text_block = ui.TextBlock2D(text='Left click on object \n') +panel.add_element(text_block, (0.3, 0.3)) + +############################################################################### +# Build scene and add an actor with many objects. + +scene = window.Scene() + +label_actor = actor.vector_text(text='Test') + +############################################################################### +# This actor is made with 3 cubes of different orientation + +directions = np.array( + [ + [np.sqrt(2) / 2, 0, np.sqrt(2) / 2], + [np.sqrt(2) / 2, np.sqrt(2) / 2, 0], + [0, np.sqrt(2) / 2, np.sqrt(2) / 2], + ] +) +fury_actor = actor.cube(centers, directions, colors, scales=radii) + +############################################################################### +# Access the memory of the vertices of all the cubes + +vertices = utils.vertices_from_actor(fury_actor) +num_vertices = vertices.shape[0] +num_objects = centers.shape[0] + +############################################################################### +# Access the memory of the colors of all the cubes + +vcolors = utils.colors_from_actor(fury_actor, 'colors') + +############################################################################### +# Adding an actor showing the axes of the world coordinates +ax = actor.axes(scale=(10, 10, 10)) + +scene.add(fury_actor) +scene.add(label_actor) +scene.add(ax) +scene.reset_camera() + +############################################################################### +# Create the Picking manager + +pickm = pick.PickingManager() + +############################################################################### +# Time to make the callback which will be called when we pick an object + + +def left_click_callback(obj, event): + + # Get the event position on display and pick + + event_pos = pickm.event_position(showm.iren) + picked_info = pickm.pick(event_pos, showm.scene) + + vertex_index = picked_info['vertex'] + + # Calculate the objects index + + object_index = int(np.floor((vertex_index / num_vertices) * num_objects)) + + # Find how many vertices correspond to each object + sec = int(num_vertices / num_objects) + + if not selected[object_index]: + scale = 6 / 5 + color_add = np.array([30, 30, 30], dtype='uint8') + selected[object_index] = True + else: + scale = 5 / 6 + color_add = np.array([-30, -30, -30], dtype='uint8') + selected[object_index] = False + + # Update vertices positions + vertices[object_index * sec : object_index * sec + sec] = ( + scale + * ( + vertices[object_index * sec : object_index * sec + sec] + - centers[object_index] + ) + + centers[object_index] + ) + + # Update colors + vcolors[object_index * sec : object_index * sec + sec] += color_add + + # Tell actor that memory is modified + utils.update_actor(fury_actor) + + face_index = picked_info['face'] + + # Show some info + text = 'Object ' + str(object_index) + '\n' + text += 'Vertex ID ' + str(vertex_index) + '\n' + text += 'Face ID ' + str(face_index) + '\n' + text += 'World pos ' + str(np.round(picked_info['xyz'], 2)) + '\n' + text += 'Actor ID ' + str(id(picked_info['actor'])) + text_block.message = text + showm.render() + + +############################################################################### +# Bind the callback to the actor + +fury_actor.AddObserver('LeftButtonPressEvent', left_click_callback, 1) + +############################################################################### +# Make the window appear + +showm = window.ShowManager(scene, size=(1024, 768), order_transparent=True) + +scene.add(panel) + +############################################################################### +# Change interactive to True to start interacting with the scene + +interactive = False + +if interactive: + + showm.start() + + +############################################################################### +# Save the current framebuffer in a PNG file + +window.record(showm.scene, size=(1024, 768), out_path='viz_picking.png') diff --git a/v0.10.x/_downloads/caf4c43950f532b475434f7bc65da7ef/viz_drawpanel.py b/v0.10.x/_downloads/caf4c43950f532b475434f7bc65da7ef/viz_drawpanel.py new file mode 100644 index 000000000..f872b5870 --- /dev/null +++ b/v0.10.x/_downloads/caf4c43950f532b475434f7bc65da7ef/viz_drawpanel.py @@ -0,0 +1,45 @@ +""" +========= +DrawPanel +========= + +This example shows how to use the DrawPanel UI. We will demonstrate how to +create Various shapes and transform them. + +First, some imports. +""" +from fury import ui, window +from fury.data import fetch_viz_new_icons + +############################################################################## +# First we need to fetch some icons that are needed for DrawPanel. + +fetch_viz_new_icons() + +######################################################################### +# We then create a DrawPanel Object. + +drawing_canvas = ui.DrawPanel(size=(560, 560), position=(40, 10)) + +############################################################################### +# Show Manager +# ============ +# +# Now we add DrawPanel to the scene. + +current_size = (650, 650) +showm = window.ShowManager(size=current_size, title='DrawPanel UI Example') + +showm.scene.add(drawing_canvas) + +interactive = False + +if interactive: + showm.start() +else: + # If the UI isn't interactive, then adding a circle to the canvas + drawing_canvas.current_mode = 'circle' + drawing_canvas.draw_shape(shape_type='circle', current_position=(275, 275)) + drawing_canvas.shape_list[-1].resize((50, 50)) + + window.record(showm.scene, size=current_size, out_path='viz_drawpanel.png') diff --git a/v0.10.x/_downloads/cb7379ccde41afc5022ffdb11d613265/viz_spinbox.py b/v0.10.x/_downloads/cb7379ccde41afc5022ffdb11d613265/viz_spinbox.py new file mode 100644 index 000000000..1c8c8d7e8 --- /dev/null +++ b/v0.10.x/_downloads/cb7379ccde41afc5022ffdb11d613265/viz_spinbox.py @@ -0,0 +1,70 @@ +# -*- coding: utf-8 -*- +""" +=========== +SpinBox UI +=========== + +This example shows how to use the UI API. We will demonstrate how to create +a SpinBox UI. + +First, some imports. +""" +from fury import actor, ui, utils, window +from fury.data import fetch_viz_icons +import numpy as np + +############################################################################## +# First we need to fetch some icons that are included in FURY. + +fetch_viz_icons() + +############################################################################### +# Let's create a Cone. + +cone = actor.cone(centers=np.random.rand(1, 3), + directions=np.random.rand(1, 3), + colors=(1, 1, 1), heights=np.random.rand(1)) + +############################################################################### +# Creating the SpinBox UI. + +spinbox = ui.SpinBox(position=(200, 100), size=(300, 100), min_val=0, + max_val=360, initial_val=180, step=10) + +############################################################################### +# Now that all the elements have been initialised, we add them to the show +# manager. + +current_size = (800, 800) +show_manager = window.ShowManager(size=current_size, + title="FURY SpinBox Example") + +show_manager.scene.add(cone) +show_manager.scene.add(spinbox) + +############################################################################### +# Using the on_change hook to rotate the cone. + +# Tracking previous value to check in/decrement. +previous_value = spinbox.value + + +def rotate_cone(spinbox): + global previous_value + change_in_value = spinbox.value - previous_value + utils.rotate(cone, (change_in_value, 1, 0, 0)) + previous_value = spinbox.value + + +spinbox.on_change = rotate_cone + +############################################################################### +# Starting the ShowManager. + +interactive = False + +if interactive: + show_manager.start() + +window.record(show_manager.scene, size=current_size, + out_path="viz_spinbox.png") diff --git a/v0.10.x/_downloads/ce084c5d62b1757151cc5b4f2b066273/viz_billboard_sdf_spheres.py b/v0.10.x/_downloads/ce084c5d62b1757151cc5b4f2b066273/viz_billboard_sdf_spheres.py new file mode 100644 index 000000000..10bc5b698 --- /dev/null +++ b/v0.10.x/_downloads/ce084c5d62b1757151cc5b4f2b066273/viz_billboard_sdf_spheres.py @@ -0,0 +1,281 @@ +""" +=============================================================================== +SDF Impostors on Billboards +=============================================================================== + +Traditional rendering engines discretize surfaces using triangles or +quadrilateral polygons. The visual quality of these elements depends on the +number of polygons used to build the 3D mesh, i.e., a smoother surface will +require more polygons. However, increasing the amount of rendered polygons +comes at the cost of performance as it decreases the number of frames per +second (FPS), which might compromise the real-time interactivity of a +visualization. + +Billboarding is a technique that changes an object's orientation to always face +a specific direction, in most cases, the camera. This technique became popular +in games and applications with a high polygonal quota requirement. + +Signed Distance Functions (SDFs) are mathematical functions that take as input +a point in a metric space and return the distance from that point to the +boundary of the function. Depending on whether the point is contained within +this boundary or outside it, the function will return negative or positive +values [Hart1996]_. For visualization purposes, the task is to display only the +points within the boundary or, in other words, those whose distance to the +border is either negative or positive, depending on the definition of the SDF. + +This tutorial exemplifies why FURY's billboard actor is a suitable rendering +option when thinking about performance and how it can be used to create +impostors using SDFs. + +Let's start by importing the necessary modules: +""" + +import os + +import numpy as np + +from fury import actor, window +from fury.shaders import compose_shader, import_fury_shader +from fury.utils import represent_actor_as_wireframe + +############################################################################### +# Now set up a new scene to place our actors in. +scene = window.Scene() + +############################################################################### +# This tutorial is divided into two parts. First, we will render spheres in the +# traditional way and then render them using SDFs on billboards. + +############################################################################### +# Traditional sphere rendering +# ============================ +# FURY provides an easy way to create sphere glyphs from numpy arrays as +# follows: +centers = np.array([ + [0, 0, 0], [-6, -6, -6], [8, 8, 8], [8.5, 9.5, 9.5], [10, -10, 10], + [-13, 13, -13], [-17, -17, 17]]) +colors = np.array([ + [1, 1, 0], [1, 0, 1], [0, 0, 1], [1, 1, 1], [1, 0, 0], [0, 1, 0], + [0, 1, 1]]) +scales = np.array([6, 1.2, 1, .2, .7, 3, 2]) +spheres_actor = actor.sphere( + centers, colors, radii=scales, phi=8, theta=8, use_primitive=False) + +############################################################################### +# To interactively visualize the recently created actors, we only need to add +# them to the previously created `scene` and set the following variable to +# **True**, otherwise, we will screenshot the scene. +scene.add(spheres_actor) + +interactive = False + +if interactive: + window.show(scene) +else: + window.record(scene, size=(600, 600), out_path='viz_regular_spheres.png') + +############################################################################### +# Now, let's explore our scene to understand what we have created. Traditional +# FURY spheres are designed using a set of interconnected triangles. To +# visualize them, we want to transform our representation from *Surface* to +# *Wireframe* using the following command. +represent_actor_as_wireframe(spheres_actor) + +if interactive: + window.show(scene) +else: + window.record(scene, size=(600, 600), out_path='viz_low_res_wireframe.png') + +############################################################################### +# Let's clean the scene and play with the parameters `phi` and `theta`. +scene.clear() +spheres_actor = actor.sphere( + centers, colors, radii=scales, phi=16, theta=16, use_primitive=False) +represent_actor_as_wireframe(spheres_actor) +scene.add(spheres_actor) + +if interactive: + window.show(scene) +else: + window.record(scene, size=(600, 600), out_path='viz_hi_res_wireframe.png') + +############################################################################### +# As you might have noticed, these parameters control the resolution of the +# spheres. Evidently, these parameters directly impact the quality of the +# visualization, but increasing such resolution comes at the cost of +# performance, i.e., more computing power will be needed and drawn to interact +# with these actors. + +############################################################################### +# Luckily for us, a technique delivers high-resolution glyphs at a much lower +# cost. This technique is known as Signed Distance Functions (SDFs), and they +# work as follows: + +############################################################################### +# SDF sphere rendering +# ==================== +# It is possible to render SDFs in FURY by using the following configuration, +# but first, let's clear the scene. +scene.clear() + +############################################################################### +# The billboard actor is suited and continuously improved to render SDFs. To +# create and visualize it, we can use the following instructions: +billboards_actor = actor.billboard(centers, colors=colors, scales=scales) +represent_actor_as_wireframe(billboards_actor) +scene.add(billboards_actor) + +if interactive: + window.show(scene) +else: + window.record( + scene, size=(600, 600), out_path='viz_billboards_wireframe.png') + +############################################################################### +# If you interacted with this actor, you might have noticed how it always +# aligned itself to the camera or, in other words, your FURY window. Now that +# we know how billboards work, we can start working on our Signed Distance +# Spheres. Let's clear our scene first. +scene.clear() + +############################################################################### +# FURY already includes a shader function with the definition of a Signed +# Distance Sphere. So we can load it and use it like this: +sd_sphere = import_fury_shader(os.path.join('sdf', 'sd_sphere.frag')) + +############################################################################### +# Additionally, we need to define the radii of our spheres. Since we prefer +# these to be determined by the billboards' size, we will use the maximum +# radius distance allowed by our billboards. +sphere_radius = 'const float RADIUS = 1.;' + +############################################################################### +# Let's calculate the distance to the sphere by combining the previously +# defined variables. +sphere_dist = 'float dist = sdSphere(point, RADIUS);' + +############################################################################### +# Now, evaluate the signed distance function. +sdf_eval = \ + """ + if (dist < 0) + fragOutput0 = vec4(color, opacity); + else + discard; + """ + +############################################################################### +# Putting all of our declarations (constants and function) and implementations +# (distance calculation and evaluation) together. +fs_dec = compose_shader([sphere_radius, sd_sphere]) +fs_impl = compose_shader([sphere_dist, sdf_eval]) + +############################################################################### +# We are ready to create and visualize our SDF-billboard actors. +spheres_actor = actor.billboard( + centers, colors=colors, scales=scales, fs_dec=fs_dec, fs_impl=fs_impl) +scene.add(spheres_actor) + +if interactive: + window.show(scene) +else: + window.record( + scene, size=(600, 600), out_path='viz_billboards_circles.png') + +############################################################################### +# Hold on, those actors don't look exactly like the ones we created using +# traditional techniques; they don't even look 3D but 2D. Well, that's because +# we still need an essential component: shading. So let's clear our scene and +# add shading to our SDF billboard actors. +scene.clear() + +############################################################################### +# The first thing necessary to add shading to our SDF-billboard actors is to +# calculate the normals of the SDFs. In this tutorial we are not going to get +# into detail in the gradient and derivatives of SDFs, so we will use the +# central differences technique implemented in the following FURY shader +# function: +central_diffs_normal = import_fury_shader( + os.path.join('sdf', 'central_diffs.frag')) + +############################################################################### +# To use the central differences technique, we need to define a map function +# that wraps our SDF and evaluates only a point. +sd_sphere_normal = \ + """ + float map(vec3 p) + { + return sdSphere(p, RADIUS); + } + """ + +############################################################################### +# Then we can load the Blinn-Phong illumination model. +blinn_phong_model = import_fury_shader( + os.path.join('lighting', 'blinn_phong_model.frag')) + +############################################################################### +# Again, let's bring all of our declarations (constants and functions) +# together. +fs_dec = compose_shader([ + sphere_radius, sd_sphere, sd_sphere_normal, central_diffs_normal, + blinn_phong_model]) + +############################################################################### +# Now, we can start our fragment shader implementation with the signed distance +# function evaluation. You might notice that in this case, we are not using an +# if statement but a `step` function, which is a more efficient way to perform +# this evaluation. You can also replace the `step` function with a `smoothstep` +# operation and, in that way, add a very efficient form of antialiasing. +sdf_eval = 'opacity *= 1 - step(0, dist);' + +############################################################################### +# In this case, we also need the absolute value of the distance to compensate +# for the depth of the SDF sphere. +abs_dist = 'float absDist = abs(dist);' + +############################################################################### +# We are ready to calculate the normals. +normal = 'vec3 normal = centralDiffsNormals(vec3(point.xy, absDist), .0001);' + +############################################################################### +# With the normals we can calculate a light attenuation factor. +light_attenuation = 'float lightAttenuation = normal.z;' + +############################################################################### +# Now, we are ready to calculate the color and output it. +color = \ + """ + color = blinnPhongIllumModel( + lightAttenuation, lightColor0, diffuseColor, specularPower, + specularColor, ambientColor); + """ + +frag_output = 'fragOutput0 = vec4(color, opacity);' + +############################################################################### +# As before, we can bring our implementation code together. +fs_impl = compose_shader([ + sphere_dist, sdf_eval, abs_dist, normal, light_attenuation, color, + frag_output]) + +############################################################################### +# Finally, recreate the SDF billboard actors and visualize them. +spheres_actor = actor.billboard( + centers, colors=colors, scales=scales, fs_dec=fs_dec, fs_impl=fs_impl) +scene.add(spheres_actor) + +if interactive: + window.show(scene) +else: + window.record( + scene, size=(600, 600), out_path='viz_billboards_spheres.png') + +############################################################################### +# References +# ---------- +# .. [Hart1996] Hart, John C. "Sphere tracing: A geometric method for the +# antialiased ray tracing of implicit surfaces." The Visual +# Computer 12.10 (1996): 527-545. +# +# .. include:: ../links_names.inc diff --git a/v0.10.x/_downloads/cea8135f3a57dc35a0e1b4e124816727/viz_bezier_interpolator.py b/v0.10.x/_downloads/cea8135f3a57dc35a0e1b4e124816727/viz_bezier_interpolator.py new file mode 100644 index 000000000..241370a62 --- /dev/null +++ b/v0.10.x/_downloads/cea8135f3a57dc35a0e1b4e124816727/viz_bezier_interpolator.py @@ -0,0 +1,184 @@ +""" +=================== +Bezier Interpolator +=================== + +Keyframe animation using cubic Bezier interpolator. +""" +import numpy as np + +from fury import actor, window +from fury.animation import Animation, Timeline +from fury.animation.interpolator import cubic_bezier_interpolator + +############################################################################### +# Position interpolation using cubic Bezier curve +# =============================================== +# +# Cubic bezier curve is a widely used method for interpolating motion paths. +# This can be achieved using positions and control points between those +# positions. + +scene = window.Scene() +showm = window.ShowManager( + scene, size=(900, 768), reset_camera=False, order_transparent=True +) + + +############################################################################### +# Cubic Bezier curve parameters +# ============================= +# In order to make a cubic bezier curve based animation, you need four values +# for every keyframe: +# 1- Timestamp: The time that the keyframe is assigned to. +# 2- value: The value of the keyframe. This might be position, quaternion, or +# scale value. +# 3- In control point: The control point used when the value is the destination +# value. +# 4- Out control point: The control point used when the value is the departure +# value:: +# +# keyframe 0 -----------------> keyframe 1 +# (time-0) (value-0) (out-cp-0) -----------------> (time-1) (value-1) (in-cp-1) +# +# keyframe 1 -----------------> keyframe 2 +# (time-1) (value-1) (out-cp-1) -----------------> (time-2) (value-2) (in-cp-2) + +keyframe_1 = {'value': [-2, 0, 0], 'out_cp': [-15, 6, 0]} +keyframe_2 = {'value': [18, 0, 0], 'in_cp': [27, 18, 0]} + +############################################################################### +# Visualizing points +pts_actor = actor.sphere( + np.array([keyframe_1.get('value'), keyframe_2.get('value')]), (1, 0, 0), radii=0.3 +) + +############################################################################### +# Visualizing the control points +cps_actor = actor.sphere( + np.array([keyframe_2.get('in_cp'), keyframe_1.get('out_cp')]), (0, 0, 1), radii=0.6 +) + +############################################################################### +# Visualizing the connection between the control points and the points +cline_actor = actor.line( + np.array([list(keyframe_1.values()), list(keyframe_2.values())]), + colors=np.array([0, 1, 0]), +) + +############################################################################### +# Initializing an ``Animation`` and adding sphere actor to it. +animation = Animation() +sphere = actor.sphere(np.array([[0, 0, 0]]), (1, 0, 1)) +animation.add_actor(sphere) + +############################################################################### +# Setting Cubic Bezier keyframes +# ============================== +# +# Cubic Bezier keyframes consists of 4 data per keyframe +# Timestamp, position, in control point, and out control point. +# - In control point is the cubic bezier control point for the associated +# position when this position is the destination position. +# - Out control point is the cubic bezier control point for the associated +# position when this position is the origin position or departing position. +# Note: If a control point is not provided or set `None`, this control point +# will be the same as the position itself. + +animation.set_position( + 0.0, np.array(keyframe_1.get('value')), out_cp=np.array(keyframe_1.get('out_cp')) +) +animation.set_position( + 5.0, np.array(keyframe_2.get('value')), in_cp=np.array(keyframe_2.get('in_cp')) +) + +############################################################################### +# Changing position interpolation into cubic bezier interpolation +animation.set_position_interpolator(cubic_bezier_interpolator) + +############################################################################### +# Adding the visualization actors to the scene. +scene.add(pts_actor, cps_actor, cline_actor) + +############################################################################### +# Adding the animation to the ``ShowManager`` +showm.add_animation(animation) + +interactive = False + +if interactive: + showm.start() + +window.record(scene, out_path='viz_keyframe_animation_bezier_1.png', size=(900, 768)) + +############################################################################### +# A more complex scene scene +# ========================== +# + +scene = window.Scene() +show_manager = window.ShowManager( + scene, size=(900, 768), reset_camera=False, order_transparent=True +) + +############################################################################### +# Note: If a control point is set to `None`, it gets the value of the +# point it controls. +keyframes = { + # time - position - in control point - out control point + 0.0: {'value': [-2, 0, 0], 'out_cp': [-15, 6, 0]}, + 5.0: {'value': [18, 0, 0], 'in_cp': [27, 18, 0], 'out_cp': [27, -18, 0]}, + 9.0: {'value': [-5, -10, -10]}, +} + +############################################################################### +# Create the sphere actor. +sphere = actor.sphere(np.array([[0, 0, 0]]), (1, 0, 1)) + +############################################################################### +# Create an ``Animation`` and adding the sphere actor to it. +animation = Animation(sphere) + +############################################################################### +# Setting Cubic Bezier keyframes +animation.set_position_keyframes(keyframes) + +############################################################################### +# changing position interpolation into cubic bezier interpolation +animation.set_position_interpolator(cubic_bezier_interpolator) + +########################################################################### +# visualizing the points and control points (only for demonstration) +for t, keyframe in keyframes.items(): + pos = keyframe.get('value') + in_control_point = keyframe.get('in_cp') + out_control_point = keyframe.get('out_cp') + + ########################################################################### + # visualizing position keyframe + vis_point = actor.sphere(np.array([pos]), (1, 0, 0), radii=0.3) + scene.add(vis_point) + + ########################################################################### + # Visualizing the control points and their length (if exist) + for cp in [in_control_point, out_control_point]: + if cp is not None: + vis_cps = actor.sphere(np.array([cp]), (0, 0, 1), radii=0.6) + cline_actor = actor.line(np.array([[pos, cp]]), colors=np.array([0, 1, 0])) + scene.add(vis_cps, cline_actor) + +############################################################################### +# Initializing the timeline to be able to control the playback of the +# animation. +timeline = Timeline(animation, playback_panel=True) + +############################################################################### +# We only need to add the ``Timeline`` to the ``ShowManager`` +show_manager.add_animation(timeline) + +############################################################################### +# Start the animation +if interactive: + show_manager.start() + +window.record(scene, out_path='viz_keyframe_animation_bezier_2.png', size=(900, 768)) diff --git a/v0.10.x/_downloads/cfcb5d4d39a58e85f65d2637f4f0909b/viz_timers.ipynb b/v0.10.x/_downloads/cfcb5d4d39a58e85f65d2637f4f0909b/viz_timers.ipynb new file mode 100644 index 000000000..bdb0fd667 --- /dev/null +++ b/v0.10.x/_downloads/cfcb5d4d39a58e85f65d2637f4f0909b/viz_timers.ipynb @@ -0,0 +1,43 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Using a timer\n\nThis example shows how to create a simple animation using a timer callback.\n\nWe will use a sphere actor that generates many spheres of different colors,\nradii and opacity. Then we will animate this actor by rotating and changing\nglobal opacity levels from inside a user defined callback.\n\nThe timer will call this user defined callback every 200 milliseconds. The\napplication will exit after the callback has been called 100 times.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "import itertools\n\nimport numpy as np\n\nfrom fury import actor, ui, window\n\nxyz = 10 * np.random.rand(100, 3)\ncolors = np.random.rand(100, 4)\nradii = np.random.rand(100) + 0.5\n\nscene = window.Scene()\n\nsphere_actor = actor.sphere(centers=xyz, colors=colors, radii=radii)\n\nscene.add(sphere_actor)\n\nshowm = window.ShowManager(\n scene, size=(900, 768), reset_camera=False, order_transparent=True\n)\n\n\ntb = ui.TextBlock2D(bold=True)\n\n# use itertools to avoid global variables\ncounter = itertools.count()\n\n\ndef timer_callback(_obj, _event):\n global timer_id\n cnt = next(counter)\n tb.message = \"Let's count up to 300 and exit :\" + str(cnt)\n showm.scene.azimuth(0.05 * cnt)\n sphere_actor.GetProperty().SetOpacity(cnt / 100.0)\n showm.render()\n\n if cnt == 10:\n # destroy the first timer and replace it with another faster timer\n showm.destroy_timer(timer_id)\n timer_id = showm.add_timer_callback(True, 10, timer_callback)\n\n if cnt == 300:\n # destroy the second timer and exit\n showm.destroy_timer(timer_id)\n showm.exit()\n\n\nscene.add(tb)\n\n# Run every 200 milliseconds\ntimer_id = showm.add_timer_callback(True, 200, timer_callback)\n\nshowm.start()\n\nwindow.record(showm.scene, size=(900, 768), out_path='viz_timer.png')" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.8" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/v0.10.x/_downloads/d0fe92f1570268989d4b00931b6d390c/viz_using_time_equations.py b/v0.10.x/_downloads/d0fe92f1570268989d4b00931b6d390c/viz_using_time_equations.py new file mode 100644 index 000000000..da8a5c2a7 --- /dev/null +++ b/v0.10.x/_downloads/d0fe92f1570268989d4b00931b6d390c/viz_using_time_equations.py @@ -0,0 +1,79 @@ +""" +===================== +Keyframe animation +===================== + +Tutorial on making keyframe-based animation in FURY using custom functions. +""" +import numpy as np + +from fury import actor, window +from fury.animation import Animation + +scene = window.Scene() + +showm = window.ShowManager( + scene, size=(900, 768), reset_camera=False, order_transparent=True +) + + +cube = actor.cube(np.array([[0, 0, 0]]), (0, 0, 0), (1, 0, 1), scales=6) + +############################################################################### +# Creating an ``Animation`` to animate the actor and show its motion path. +anim = Animation(length=2 * np.pi, loop=True, motion_path_res=200) + +############################################################################### +# Adding the sphere actor to the timeline +# This could've been done during initialization. +anim.add_actor(cube) + + +############################################################################### +# Creating time dependent functions. +def pos_eval(t): + return np.array([np.sin(t), np.cos(t) * np.sin(t), 0]) * 15 + + +def color_eval(t): + return ( + np.array([np.sin(t), np.sin(t - 2 * np.pi / 3), np.sin(t + np.pi / 3)]) + + np.ones(3) + ) / 2 + + +def rotation_eval(t): + return np.array([np.sin(t) * 360, np.cos(t) * 360, 0]) + + +def scale_eval(t): + return ( + np.array([np.sin(t), np.sin(t - 2 * np.pi / 3), np.sin(t + np.pi / 3)]) + + np.ones(3) * 2 + ) / 5 + + +############################################################################### +# Setting evaluator functions is the same as setting interpolators, but with +# one extra argument: `is_evaluator=True` since these functions does not need +# keyframes as input. +anim.set_position_interpolator(pos_eval, is_evaluator=True) +anim.set_rotation_interpolator(rotation_eval, is_evaluator=True) +anim.set_color_interpolator(color_eval, is_evaluator=True) +anim.set_interpolator('scale', scale_eval, is_evaluator=True) + +############################################################################### +# changing camera position to observe the animation better. +scene.set_camera(position=(0, 0, 90)) + +############################################################################### +# Adding the animation to the show manager. +showm.add_animation(anim) + + +interactive = False + +if interactive: + showm.start() + +window.record(scene, out_path='viz_keyframe_animation_evaluators.png', size=(900, 768)) diff --git a/v0.10.x/_downloads/d18e69af9880ae2cf3636fac156c00dc/viz_morphing.ipynb b/v0.10.x/_downloads/d18e69af9880ae2cf3636fac156c00dc/viz_morphing.ipynb new file mode 100644 index 000000000..f8b0cca44 --- /dev/null +++ b/v0.10.x/_downloads/d18e69af9880ae2cf3636fac156c00dc/viz_morphing.ipynb @@ -0,0 +1,169 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Morphing Animation in a glTF\nIn this tutorial, we will show how to use morphing in a glTF model in FURY.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "from fury import window\nfrom fury.data import fetch_gltf, read_viz_gltf\nfrom fury.gltf import glTF" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Retrieving the model with morphing in it (look at Khronoos samples).\nWe're choosing the `MorphStressTest` model here.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "fetch_gltf('MorphStressTest', 'glTF')\nfilename = read_viz_gltf('MorphStressTest')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Initializing the glTF object, You can additionally set `apply_normals=True`.\nNote: Normals might not work as intended with morphing.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "gltf_obj = glTF(filename, apply_normals=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Get the morph timeline using `morph_timeline` method, Choose the animation\nname you want to visualize.\nNote: If there's no name for animation, It's stored as `anim_0`, `anim_1` etc\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "animation = gltf_obj.morph_animation()['TheWave']" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Call the `update_morph` method once, This moves initialise the morphing at\ntimestamp 0.0 seconds and ensures that camera fits all the actors perfectly.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "gltf_obj.update_morph(animation)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Create a scene, and show manager.\nInitialize the show manager and add timeline to the scene (No need to add\nactors to the scene separately).\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "scene = window.Scene()\nshowm = window.ShowManager(\n scene, size=(900, 768), reset_camera=True, order_transparent=True\n)\n\nshowm.initialize()\nscene.add(animation)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "define a timer_callback.\nUse the `update_morph` method again, It updates the timeline and applies\nmorphing).\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def timer_callback(_obj, _event):\n gltf_obj.update_morph(animation)\n showm.render()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Optional: `timeline.play()` auto plays the animations.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "showm.add_timer_callback(True, 20, timer_callback)\nscene.reset_camera()\n\ninteractive = False\n\nif interactive:\n showm.start()\n\nwindow.record(scene, out_path='viz_morphing.png', size=(900, 768))" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.8" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/v0.10.x/_downloads/d382633f4061b2697f332de205293aab/viz_hierarchical_animation.py b/v0.10.x/_downloads/d382633f4061b2697f332de205293aab/viz_hierarchical_animation.py new file mode 100644 index 000000000..35c9b454d --- /dev/null +++ b/v0.10.x/_downloads/d382633f4061b2697f332de205293aab/viz_hierarchical_animation.py @@ -0,0 +1,144 @@ +""" +=============================== +Keyframe hierarchical Animation +=============================== + +Creating hierarchical keyframes animation in fury +""" +import numpy as np + +from fury import actor, window +from fury.animation import Animation + +scene = window.Scene() + +showm = window.ShowManager( + scene, size=(900, 768), reset_camera=False, order_transparent=True +) +showm.initialize() + +############################################################################### +# Creating the road +road = actor.box( + np.array([[0, 0, 0]]), colors=np.array([[1, 1, 1]]), scales=np.array([[22, 0.1, 5]]) +) + +############################################################################### +# Constructing the car geometry + +body_actor = actor.box( + np.array([[0, 0.5, 0], [-0.2, 1, 0]]), + scales=((4, 1, 2), (2.5, 1.5, 1.8)), + colors=(0.6, 0.3, 0.1), +) + +############################################################################### +# Adding the the car's body to an Animation to be able to animate it later. +car_anim = Animation(body_actor) + +############################################################################### +# Creating the wheels of the car +wheel_center = np.array([[0, 0, 0]]) + +wheel_direction = np.array([[0, 0, 1]]) +wheel_positions = [ + [1.2, 0, 1.1], + [-1.2, 0, 1.1], + [1.2, 0, -1.1], + [-1.2, 0, -1.1], +] + +wheels = [ + actor.cylinder( + wheel_center, + wheel_direction, + (0.1, 0.7, 0.3), + radius=1.7, + heights=0.3, + resolution=10, + capped=True, + ) + for _ in range(4) +] + +############################################################################### +# Animating each wheel and setting its position to the right position using a +# single keyframe that will not change. + +wheels_animations = [Animation(wheel) for wheel in wheels] + +for wheel_anim in wheels_animations: + wheel_anim.set_position(0.0, wheel_positions.pop()) + wheel_anim.set_rotation(0.0, [0, 0, 1, 1]) + wheel_anim.set_rotation(1.0, [0, 0, 1, -1]) + +############################################################################### +# Creating a radar on top of the car + +############################################################################### +# First we create the shaft holding and rotating the radar +radar_shaft = actor.cylinder( + np.array([[0, 0, 0]]), np.array([[0, 1, 0]]), (0, 1, 0), heights=1 +) + +############################################################################### +# In order to animate the shaft actor we have to add it to an Animation +radar_shaft_anim = Animation(radar_shaft) + +############################################################################### +# Setting a single position keyframe will make sure the actor will be placed at +# that position +radar_shaft_anim.set_position(0.0, [0, 2, 0]) + +############################################################################### +# Rotating the shaft around Y axis +radar_shaft_anim.set_rotation(0.0, [0, -250, 0]) +radar_shaft_anim.set_rotation(1.0, [0, 250, 0]) +radar_shaft_anim.set_rotation(2.0, [0, -250, 0]) + +############################################################################### +# Now we create the radar itself +radar = actor.cone(np.array([[0, 0, 0]]), directions=(0, 0, 0), colors=(0.2, 0.2, 0.9)) + +############################################################################### +# Then add it to an animation in order to rotate it +radar_animation = Animation(radar) + +############################################################################### +# Set position and rotation as done above with the shaft. +radar_animation.set_position(0, [-0.4, 0.5, 0]) +radar_animation.set_rotation(0.0, [0, 0, 0]) +radar_animation.set_rotation(1.0, [180, 0, 0]) +radar_animation.set_rotation(2.0, [0, 0, 0]) + +############################################################################### +# Now, we want the radar to rotate when the shaft rotates in hierarchical way. +# To do that we must add the radar animation as a child animation of the shaft +# animation as below: +radar_shaft_anim.add_child_animation(radar_animation) + +############################################################################### +# After that we want everything to animate related to the car. +# The wheels should always be attached to the car no matter where it moves. +# we do that by adding them as child animations of the car's body animation +car_anim.add_child_animation([wheels_animations, radar_shaft_anim]) + +############################################################################### +# Moving the car +car_anim.set_position(0.0, [-10, 0.5, 0]) +car_anim.set_position(6.0, [10, 0.5, 0]) + +############################################################################### +# Adding the car Animation to the show manager +showm.add_animation(car_anim) +scene.add(road) +scene.camera().SetPosition(0, 20, 30) + +interactive = False + +if interactive: + showm.start() + +window.record( + scene, out_path='viz_keyframe_hierarchical_animation.png', size=(900, 768) +) diff --git a/v0.10.x/_downloads/d76da8f3e26537c0ef63589ec7058bc2/viz_spinbox.ipynb b/v0.10.x/_downloads/d76da8f3e26537c0ef63589ec7058bc2/viz_spinbox.ipynb new file mode 100644 index 000000000..49d41b60c --- /dev/null +++ b/v0.10.x/_downloads/d76da8f3e26537c0ef63589ec7058bc2/viz_spinbox.ipynb @@ -0,0 +1,151 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# SpinBox UI\n\nThis example shows how to use the UI API. We will demonstrate how to create\na SpinBox UI.\n\nFirst, some imports.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "from fury import actor, ui, utils, window\nfrom fury.data import fetch_viz_icons\nimport numpy as np" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "First we need to fetch some icons that are included in FURY.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "fetch_viz_icons()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's create a Cone.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "cone = actor.cone(centers=np.random.rand(1, 3),\n directions=np.random.rand(1, 3),\n colors=(1, 1, 1), heights=np.random.rand(1))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Creating the SpinBox UI.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "spinbox = ui.SpinBox(position=(200, 100), size=(300, 100), min_val=0,\n max_val=360, initial_val=180, step=10)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now that all the elements have been initialised, we add them to the show\nmanager.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "current_size = (800, 800)\nshow_manager = window.ShowManager(size=current_size,\n title=\"FURY SpinBox Example\")\n\nshow_manager.scene.add(cone)\nshow_manager.scene.add(spinbox)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Using the on_change hook to rotate the cone.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Tracking previous value to check in/decrement.\nprevious_value = spinbox.value\n\n\ndef rotate_cone(spinbox):\n global previous_value\n change_in_value = spinbox.value - previous_value\n utils.rotate(cone, (change_in_value, 1, 0, 0))\n previous_value = spinbox.value\n\n\nspinbox.on_change = rotate_cone" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Starting the ShowManager.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "interactive = False\n\nif interactive:\n show_manager.start()\n\nwindow.record(show_manager.scene, size=current_size,\n out_path=\"viz_spinbox.png\")" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.8" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/v0.10.x/_downloads/db8ea9730d7543ee2928686a3bce6b6a/viz_markers.py b/v0.10.x/_downloads/db8ea9730d7543ee2928686a3bce6b6a/viz_markers.py new file mode 100644 index 000000000..6f2849569 --- /dev/null +++ b/v0.10.x/_downloads/db8ea9730d7543ee2928686a3bce6b6a/viz_markers.py @@ -0,0 +1,57 @@ +""" +====================================================================== +Fury Markers +====================================================================== + +This example shows how to use the marker actor. +""" +import numpy as np + +from fury import actor, window + +n = 10000 + +############################################################################### +# There are nine types 2d markers: circle, square, diamond, triangle, pentagon, +# hexagon, heptagon, cross and plus. + +marker_symbols = ['o', 's', 'd', '^', 'p', 'h', 's6', 'x', '+'] +markers = [np.random.choice(marker_symbols) for i in range(n)] + +centers = np.random.normal(size=(n, 3), scale=10) + +colors = np.random.uniform(size=(n, 3)) + +############################################################################ +# You can control the edge color and edge width for each marker + +nodes_actor = actor.markers( + centers, + marker=markers, + edge_width=0.1, + edge_color=[255, 255, 0], + colors=colors, + scales=0.5, +) + +############################################################################ +# In addition, an 3D sphere it's also a valid type of marker + +nodes_3d_actor = actor.markers( + centers + np.ones_like(centers) * 25, + marker='3d', + colors=colors, + scales=0.5, +) + +scene = window.Scene() + +scene.add(nodes_actor) +scene.add(nodes_3d_actor) + +interactive = False + +if interactive: + window.show(scene, size=(600, 600)) + +window.record(scene, out_path='viz_markers.png', size=(600, 600)) diff --git a/v0.10.x/_downloads/dcdf39b4d97dafd1f4f26748b9189057/viz_card_sprite_sheet.ipynb b/v0.10.x/_downloads/dcdf39b4d97dafd1f4f26748b9189057/viz_card_sprite_sheet.ipynb new file mode 100644 index 000000000..e45e1bfc0 --- /dev/null +++ b/v0.10.x/_downloads/dcdf39b4d97dafd1f4f26748b9189057/viz_card_sprite_sheet.ipynb @@ -0,0 +1,169 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Card\n\nThis example shows how to create a card and use a sprite\nsheet to update the image in the card.\n\nFirst, some imports.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "import os\nfrom fury import ui, window\nfrom fury.data import fetch_viz_icons\nfrom fury.io import load_image, load_sprite_sheet, save_image\nfrom tempfile import TemporaryDirectory as InTemporaryDirectory" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "First we need to fetch some icons that are included in FURY.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "TARGET_FPS = 15\nFRAME_TIME = (1.0 / TARGET_FPS) * 1000\n\nfetch_viz_icons()\n\nsprite_sheet = load_sprite_sheet('https://raw.githubusercontent.com/fury-gl/'\n 'fury-data/master/unittests/fury_sprite.png',\n 5, 5)\nCURRENT_SPRITE_IDX = 0\n\nvtk_sprites = []" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's create a card and add it to the show manager\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "img_url = \"https://raw.githubusercontent.com/fury-gl\"\\\n \"/fury-communication-assets/main/fury-logo.png\"\n\ntitle = \"FURY\"\nbody = \"FURY - Free Unified Rendering in pYthon.\"\\\n \"A software library for scientific visualization in Python.\"\n\ncard = ui.elements.Card2D(image_path=img_url, title_text=title,\n body_text=body,\n image_scale=0.55, size=(300, 300),\n bg_color=(1, 0.294, 0.180),\n bg_opacity=0.8, border_width=5,\n border_color=(0.1, 0.4, 0.8))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we define the callback to update the image on card after some delay.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def timer_callback(_obj, _evt):\n global CURRENT_SPRITE_IDX, show_manager\n CURRENT_SPRITE_IDX += 1\n sprite = vtk_sprites[CURRENT_SPRITE_IDX % len(vtk_sprites)]\n card.image.set_img(sprite)\n i_ren = show_manager.scene.GetRenderWindow()\\\n .GetInteractor().GetInteractorStyle()\n\n i_ren.force_render()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Lets create a function to convert the sprite to vtkImageData\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def sprite_to_vtk():\n with InTemporaryDirectory() as tdir:\n for idx, sprite in enumerate(list(sprite_sheet.values())):\n sprite_path = os.path.join(tdir, f'{idx}.png')\n save_image(sprite, sprite_path, compression_quality=100)\n vtk_sprite = load_image(sprite_path, as_vtktype=True)\n vtk_sprites.append(vtk_sprite)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now that the card has been initialised, we add it to the show\nmanager.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "current_size = (1000, 1000)\nshow_manager = window.ShowManager(size=current_size,\n title=\"FURY Card Example\")\n\nshow_manager.scene.add(card)\nshow_manager.initialize()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Converting numpy array sprites to vtk images\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "sprite_to_vtk()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Adding a timer to update the card image\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "show_manager.add_timer_callback(True, int(FRAME_TIME), timer_callback)\n\n# To interact with the UI, set interactive = True\ninteractive = False\n\nif interactive:\n show_manager.start()\n\nwindow.record(show_manager.scene, out_path=\"card_ui.png\", size=(1000, 1000))" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.8" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/v0.10.x/_downloads/dd50aac101aff72c6d6a22bf9439ed6f/viz_animated_surfaces.py b/v0.10.x/_downloads/dd50aac101aff72c6d6a22bf9439ed6f/viz_animated_surfaces.py new file mode 100644 index 000000000..2ff361e0e --- /dev/null +++ b/v0.10.x/_downloads/dd50aac101aff72c6d6a22bf9439ed6f/viz_animated_surfaces.py @@ -0,0 +1,210 @@ +""" +=============================================== +Animated 2D functions +=============================================== + +This is a simple demonstration of how one can +animate 2D functions using FURY. +""" + +############################################################################### +# Importing necessary modules + +import itertools + +import numpy as np + +from fury import actor, colormap, ui, utils, window + +############################################################################### +# The following function is used to create and update the coordinates of the +# points which are being used to plot the surface. It's also used to create +# and update the colormap being used to color the surface. +# Kindly note that only the z coordinate is being modified with time as only +# the z coordinate is a function of time. + + +def update_surface(x, y, equation, cmap_name='viridis'): + + # z is the function F i.e. F(x, y, t) + z = eval(equation) + xyz = np.vstack([x, y, z]).T + + # creating the colormap + v = np.copy(z) + m_v = np.max(np.abs(v), axis=0) + v /= m_v if m_v else 1 + colors = colormap.create_colormap(v, name=cmap_name) + + return xyz, colors + + +############################################################################### +# Variables and their usage: +# :time - float: initial value of the time variable i.e. value of the time variable at +# the beginning of the program; (default = 0) +# dt: float +# amount by which ``time`` variable is incremented for every iteration +# of timer_callback function (default = 0.1) +# lower_xbound: float +# lower bound of the x values in which the function is plotted +# (default = -1) +# upper_xbound: float +# Upper bound of the x values in which the function is plotted +# (default = 1) +# lower_ybound: float +# lower bound of the y values in which the function is plotted +# (default = -1) +# upper_ybound: float +# Upper bound of the y values in which the function is plotted +# (default = 1) +# npoints: int +# For high quality rendering, keep the number high but kindly note +# that higher values for npoints slows down the animation +# (default = 128) +# + +time = 0 +dt = 0.1 +lower_xbound = -1 +upper_xbound = 1 +lower_ybound = -1 +upper_ybound = 1 +npoints = 128 + +############################################################################### +# creating the x, y points which will be used to fit the equation to get +# elevation and generate the surface +x = np.linspace(lower_xbound, upper_xbound, npoints) +y = np.linspace(lower_ybound, upper_ybound, npoints) +x, y = np.meshgrid(x, y) +x = x.reshape(-1) +y = y.reshape(-1) + +############################################################################### +# Function used to create surface obtained from 2D equation. + + +def create_surface(x, y, equation, colormap_name): + xyz, colors = update_surface(x, y, equation=equation, cmap_name=colormap_name) + surf = actor.surface(xyz, colors=colors) + surf.equation = equation + surf.cmap_name = colormap_name + surf.vertices = utils.vertices_from_actor(surf) + surf.no_vertices_per_point = len(surf.vertices) / npoints**2 + surf.initial_vertices = surf.vertices.copy() - np.repeat( + xyz, surf.no_vertices_per_point, axis=0 + ) + return surf + + +############################################################################### +# Equations to be plotted +eq1 = 'np.abs(np.sin(x*2*np.pi*np.cos(time/2)))**1*np.cos(time/2)*\ + np.abs(np.cos(y*2*np.pi*np.sin(time/2)))**1*np.sin(time/2)*1.2' +eq2 = '((x**2 - y**2)/(x**2 + y**2))**(2)*np.cos(6*np.pi*x*y-1.8*time)*0.24' +eq3 = '(np.sin(np.pi*2*x-np.sin(1.8*time))*np.cos(np.pi*2*y+np.cos(1.8*time)))\ + *0.48' +eq4 = 'np.cos(24*np.sqrt(x**2 + y**2) - 2*time)*0.18' +equations = [eq1, eq2, eq3, eq4] + +############################################################################### +# List of colormaps to be used for the various functions. +cmap_names = ['hot', 'plasma', 'viridis', 'ocean'] + +############################################################################### +# Creating a list of surfaces. +surfaces = [] +for i in range(4): + surfaces.append( + create_surface(x, y, equation=equations[i], colormap_name=cmap_names[i]) + ) + + +############################################################################### +# Creating a scene object and configuring the camera's position + +scene = window.Scene() +scene.set_camera( + position=(4.45, -21, 12), focal_point=(4.45, 0.0, 0.0), view_up=(0.0, 0.0, 1.0) +) +showm = window.ShowManager(scene, size=(600, 600)) + +############################################################################### +# Creating a grid to interact with surfaces individually. + +# To store the function names +text = [] +for i in range(4): + t_actor = actor.vector_text( + 'Function ' + str(i + 1), pos=(0, 0, 0), scale=(0.17, 0.2, 0.2) + ) + text.append(t_actor) + +grid_ui = ui.GridUI( + actors=surfaces, + captions=text, + caption_offset=(-0.7, -2.5, 0), + dim=(1, 4), + cell_padding=2, + aspect_ratio=1, + rotation_axis=(0, 1, 0), +) +showm.scene.add(grid_ui) + +# Adding an axes actor to the first surface. +showm.scene.add(actor.axes()) + + +############################################################################### +# Initializing text box to print the title of the animation +tb = ui.TextBlock2D(bold=True, position=(200, 60)) +tb.message = 'Animated 2D functions' +scene.add(tb) + +############################################################################### +# Initializing showm and counter + +counter = itertools.count() + +############################################################################### +# end is used to decide when to end the animation +end = 200 + + +############################################################################### +# The 2D functions are updated and rendered here. + + +def timer_callback(_obj, _event): + global xyz, time + time += dt + cnt = next(counter) + + # updating the colors and vertices of the triangles used to form the + # surfaces + for surf in surfaces: + xyz, colors = update_surface( + x, y, equation=surf.equation, cmap_name=surf.cmap_name + ) + utils.update_surface_actor_colors(surf, colors) + surf.vertices[:] = surf.initial_vertices + np.repeat( + xyz, surf.no_vertices_per_point, axis=0 + ) + utils.update_actor(surf) + + showm.render() + # to end the animation + if cnt == end: + showm.exit() + + +############################################################################### +# Run every 30 milliseconds +showm.add_timer_callback(True, 30, timer_callback) + +interactive = False +if interactive: + showm.start() + +window.record(showm.scene, size=(600, 600), out_path='viz_animated_surfaces.png') diff --git a/v0.10.x/_downloads/e10ebe91cf15f050273fb5e66223062d/viz_chain.ipynb b/v0.10.x/_downloads/e10ebe91cf15f050273fb5e66223062d/viz_chain.ipynb new file mode 100644 index 000000000..efc47ba35 --- /dev/null +++ b/v0.10.x/_downloads/e10ebe91cf15f050273fb5e66223062d/viz_chain.ipynb @@ -0,0 +1,187 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Chain Simulation\n\nThis example simulation shows how to use pybullet to render physics simulations\nin fury. In this example we specifically render a Chain oscillating to and from.\n\nFirst some imports.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "import itertools\n\nimport numpy as np\nimport pybullet as p\n\nfrom fury import actor, ui, utils, window" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Setup pybullet and add gravity.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "p.connect(p.DIRECT)\n\n# Apply gravity to the scene.\np.setGravity(0, 0, -10)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we render the Chain using the following parameters and definitions.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Parameters\nn_links = 20\ndx_link = 0.1 # Size of segments\nlink_mass = 0.5\nbase_mass = 0.1\nradii = 0.5\n\njoint_friction = 0.0005 # rotational joint friction [N/(rad/s)]\n\nlink_shape = p.createCollisionShape(\n p.GEOM_CYLINDER,\n radius=radii,\n height=dx_link,\n collisionFramePosition=[0, 0, -dx_link / 2],\n)\n\nbase_shape = p.createCollisionShape(p.GEOM_BOX, halfExtents=[0.01, 0.01, 0.01])\n\nvisualShapeId = -1\n\nlink_Masses = np.zeros(n_links)\nlink_Masses[:] = link_mass\n\nlinkCollisionShapeIndices = np.zeros(n_links)\nlinkCollisionShapeIndices[:] = np.array(link_shape)\nlinkVisualShapeIndices = -1 * np.ones(n_links)\nlinkPositions = np.zeros((n_links, 3))\nlinkPositions[:] = np.array([0, 0, -dx_link])\nlinkOrientations = np.zeros((n_links, 4))\nlinkOrientations[:] = np.array([0, 0, 0, 1])\nlinkInertialFramePositions = np.zeros((n_links, 3))\nlinkInertialFrameOrns = np.zeros((n_links, 4))\nlinkInertialFrameOrns[:] = np.array([0, 0, 0, 1])\nindices = np.arange(n_links)\njointTypes = np.zeros(n_links)\njointTypes[:] = np.array(p.JOINT_SPHERICAL)\naxis = np.zeros((n_links, 3))\naxis[:] = np.array([1, 0, 0])\n\nlinkDirections = np.zeros((n_links, 3))\nlinkDirections[:] = np.array([1, 1, 1])\n\nlink_radii = np.zeros(n_links)\nlink_radii[:] = radii\n\nlink_heights = np.zeros(n_links)\nlink_heights[:] = dx_link\n\nrope_actor = actor.cylinder(\n centers=linkPositions,\n directions=linkDirections,\n colors=np.random.rand(n_links, 3),\n radius=radii,\n heights=link_heights,\n capped=True,\n)\n\nbasePosition = [0, 0, 2]\nbaseOrientation = [0, 0, 0, 1]\nrope = p.createMultiBody(\n base_mass,\n base_shape,\n visualShapeId,\n basePosition,\n baseOrientation,\n linkMasses=link_Masses,\n linkCollisionShapeIndices=linkCollisionShapeIndices.astype(int),\n linkVisualShapeIndices=linkVisualShapeIndices.astype(int),\n linkPositions=linkPositions,\n linkOrientations=linkOrientations,\n linkInertialFramePositions=linkInertialFramePositions,\n linkInertialFrameOrientations=linkInertialFrameOrns,\n linkParentIndices=indices.astype(int),\n linkJointTypes=jointTypes.astype(int),\n linkJointAxis=axis.astype(int),\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We remove stiffness among the joints by adding friction to them.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "friction_vec = [joint_friction] * 3 # same all axis\ncontrol_mode = p.POSITION_CONTROL # set pos control mode\nfor j in range(p.getNumJoints(rope)):\n p.setJointMotorControlMultiDof(\n rope,\n j,\n control_mode,\n targetPosition=[0, 0, 0, 1],\n targetVelocity=[0, 0, 0],\n positionGain=0,\n velocityGain=1,\n force=friction_vec,\n )" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Next, we define a constraint base that will help us in the oscillation of the\nchain.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "root_robe_c = p.createConstraint(\n rope, -1, -1, -1, p.JOINT_FIXED, [0, 0, 0], [0, 0, 0], [0, 0, 2]\n)\n\n# some traj to inject motion\namplitude_x = 0.3\namplitude_y = 0.0\nfreq = 0.6\n\nbase_actor = actor.box(\n centers=np.array([[0, 0, 0]]),\n directions=np.array([[0, 0, 0]]),\n scales=(0.02, 0.02, 0.02),\n colors=np.array([[1, 0, 0]]),\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We add the necessary actors to the scene.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "scene = window.Scene()\nscene.background((1, 1, 1))\nscene.set_camera((2.2, -3.0, 3.0), (-0.3, 0.6, 0.7), (-0.2, 0.2, 1.0))\nscene.add(actor.axes(scale=(0.1, 0.1, 0.1)))\nscene.add(rope_actor)\nscene.add(base_actor)\n\n# Create show manager.\nshowm = window.ShowManager(\n scene, size=(900, 768), reset_camera=False, order_transparent=True\n)\n\n\n# Counter iterator for tracking simulation steps.\ncounter = itertools.count()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We define a couple of syncing methods for the base and chain.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Function for syncing actors with multi-bodies.\ndef sync_actor(actor, multibody):\n pos, orn = p.getBasePositionAndOrientation(multibody)\n actor.SetPosition(*pos)\n orn_deg = np.degrees(p.getEulerFromQuaternion(orn))\n actor.SetOrientation(*orn_deg)\n\n\nvertices = utils.vertices_from_actor(rope_actor)\nnum_vertices = vertices.shape[0]\nnum_objects = linkPositions.shape[0]\nsec = int(num_vertices / num_objects)\n\n\ndef sync_joints(actor_list, multibody):\n for joint in range(p.getNumJoints(multibody)):\n # `p.getLinkState` offers various information about the joints\n # as a list and the values in 4th and 5th index refer to the joint's\n # position and orientation respectively.\n pos, orn = p.getLinkState(multibody, joint)[4:6]\n\n rot_mat = np.reshape(\n p.getMatrixFromQuaternion(\n p.getDifferenceQuaternion(orn, linkOrientations[joint])\n ),\n (3, 3),\n )\n\n vertices[joint * sec : joint * sec + sec] = (\n vertices[joint * sec : joint * sec + sec] - linkPositions[joint]\n ) @ rot_mat + pos\n\n linkPositions[joint] = pos\n linkOrientations[joint] = orn" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We define a TextBlock to display the Avg. FPS and Simulation steps.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "fpss = np.array([])\ntb = ui.TextBlock2D(\n position=(0, 680), font_size=30, color=(1, 0.5, 0), text='Avg. FPS: \\nSim Steps: '\n)\nscene.add(tb)\n\nt = 0.0\nfreq_sim = 240" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Timer callback to sync objects, simulate steps and oscillate the base.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def timer_callback(_obj, _event):\n cnt = next(counter)\n global t, fpss\n showm.render()\n\n t += 1.0 / freq_sim\n\n if cnt % 1 == 0:\n fps = showm.frame_rate\n fpss = np.append(fpss, fps)\n tb.message = (\n 'Avg. FPS: ' + str(np.round(np.mean(fpss), 0)) + '\\nSim Steps: ' + str(cnt)\n )\n\n # some trajectory\n ux = amplitude_x * np.sin(2 * np.pi * freq * t)\n uy = amplitude_y * np.cos(2 * np.pi * freq * t)\n\n # move base around\n pivot = [3 * ux, uy, 2]\n orn = p.getQuaternionFromEuler([0, 0, 0])\n p.changeConstraint(root_robe_c, pivot, jointChildFrameOrientation=orn, maxForce=500)\n\n # Sync base and chain.\n sync_actor(base_actor, rope)\n sync_joints(rope_actor, rope)\n utils.update_actor(rope_actor)\n\n # Simulate a step.\n p.stepSimulation()\n\n # Exit after 2000 steps of simulation.\n if cnt == 130:\n showm.exit()\n\n\n# Add the timer callback to showmanager.\n# Increasing the duration value will slow down the simulation.\nshowm.add_timer_callback(True, 1, timer_callback)\n\ninteractive = False\n\n# start simulation\nif interactive:\n showm.start()\n\nwindow.record(scene, size=(900, 768), out_path='viz_chain.png')" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.8" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/v0.10.x/_downloads/e1e6c372eb29cd003ddeed8cbb6a2f43/viz_robot_arm_animation.ipynb b/v0.10.x/_downloads/e1e6c372eb29cd003ddeed8cbb6a2f43/viz_robot_arm_animation.ipynb new file mode 100644 index 000000000..5ec299285 --- /dev/null +++ b/v0.10.x/_downloads/e1e6c372eb29cd003ddeed8cbb6a2f43/viz_robot_arm_animation.ipynb @@ -0,0 +1,295 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Arm Robot Animation\n\nTutorial on making a robot arm animation in FURY.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "import numpy as np\n\nfrom fury import actor, window\nfrom fury.animation import Animation, Timeline\nfrom fury.utils import set_actor_origin\n\nscene = window.Scene()\n\nshowm = window.ShowManager(\n scene, size=(900, 768), reset_camera=False, order_transparent=True\n)\nshowm.initialize()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Creating robot arm components\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "base = actor.cylinder(\n np.array([[0, 0, 0]]), np.array([[0, 1, 0]]), colors=(0, 1, 0), radius=1\n)\nmain_arm = actor.box(np.array([[0, 0, 0]]), colors=(1, 0.5, 0), scales=(12, 1, 1))\n\nsub_arm = actor.box(np.array([[0, 0, 0]]), colors=(0, 0.5, 0.8), scales=(8, 0.7, 0.7))\njoint_1 = actor.sphere(np.array([[0, 0, 0]]), colors=np.array([1, 0, 1]), radii=1.2)\njoint_2 = actor.sphere(np.array([[0, 0, 0]]), colors=np.array([1, 0, 1]))\n\nend = actor.cone(\n np.array([[0, 0, 0]]),\n np.array([[1, 0, 0]]),\n np.array([[1, 0, 0]]),\n heights=2.2,\n resolution=6,\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Setting the center of both shafts to the beginning.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "set_actor_origin(main_arm, np.array([-6, 0, 0]))\nset_actor_origin(sub_arm, np.array([-4, 0, 0]))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Creating a timeline\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "timeline = Timeline(playback_panel=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Creating animations\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "main_arm_animation = Animation([main_arm, joint_1], length=2 * np.pi)\nchild_arm_animation = Animation([sub_arm, joint_2])\ndrill_animation = Animation(end)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Adding other Animations in hierarchical order\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "main_arm_animation.add_child_animation(child_arm_animation)\nchild_arm_animation.add_child_animation(drill_animation)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Creating Arm joints time dependent animation functions.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def rot_main_arm(t):\n return np.array([np.sin(t / 2) * 180, np.cos(t / 2) * 180, 0])\n\n\ndef rot_sub_arm(t):\n return np.array([np.sin(t) * 180, np.cos(t) * 70, np.cos(t) * 40])\n\n\ndef rot_drill(t):\n return np.array([t * 1000, 0, 0])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Setting timelines (joints) relative position\n1- Placing the main arm on the cube static base.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "main_arm_animation.set_position(0, np.array([0, 1.3, 0]))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "2- Translating the timeline containing the sub arm to the end of the first\narm.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "child_arm_animation.set_position(0, np.array([12, 0, 0]))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "3- Translating the timeline containing the drill to the end of the sub arm.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "drill_animation.set_position(0, np.array([8, 0, 0]))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Setting rotation time-based evaluators\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "main_arm_animation.set_rotation_interpolator(rot_main_arm, is_evaluator=True)\nchild_arm_animation.set_rotation_interpolator(rot_sub_arm, is_evaluator=True)\ndrill_animation.set_rotation_interpolator(rot_drill, is_evaluator=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Setting camera position to observe the robot arm.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "scene.camera().SetPosition(0, 0, 90)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Adding the base actor to the scene\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "scene.add(base)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Adding the main parent animation to the Timeline.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "timeline.add_animation(main_arm_animation)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we add the timeline to the ShowManager\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "showm.add_animation(timeline)\n\ninteractive = False\n\nif interactive:\n showm.start()\n\nwindow.record(scene, out_path='viz_robot_arm.png', size=(900, 768))" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.8" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/v0.10.x/_downloads/e1e95fd074de6c909319935378baea6e/viz_sdf_cylinder.py b/v0.10.x/_downloads/e1e95fd074de6c909319935378baea6e/viz_sdf_cylinder.py new file mode 100644 index 000000000..b694e02bc --- /dev/null +++ b/v0.10.x/_downloads/e1e95fd074de6c909319935378baea6e/viz_sdf_cylinder.py @@ -0,0 +1,372 @@ +""" +=============================================================================== +Make a Cylinder using polygons vs SDF +=============================================================================== +This tutorial is intended to show two ways of primitives creation with the use +of polygons, and Signed Distance Functions (SDFs). We will use cylinders as an +example since they have a simpler polygonal representation. Hence, it allows us +to see better the difference between using one or the other method. + +For the cylinder representation with polygons, we will use cylinder actor +implementation on FURY, and for the visualization using SDFs, we will +implement shader code to create the cylinder and use a box actor to put our +implementation inside. + +We start by importing the necessary modules: +""" + +import os + +import numpy as np + +from fury import actor, window +from fury.shaders import ( + attribute_to_actor, + compose_shader, + import_fury_shader, + shader_to_actor, +) + +############################################################################### +# Cylinder using polygons +# ======================= +# Polygons-based modeling, use smaller components namely triangles or polygons +# to represent 3D objects. Each polygon is defined by the position of its +# vertices and its connecting edges. In order to get a better representation +# of an object, it may be necessary to increase the number of polygons in the +# model, which is translated into the use of more space to store data and more +# rendering time to display the object. +# +# Now we define some properties of our actors, use them to create a set of +# cylinders, and add them to the scene. + +centers = np.array( + [ + [-3.2, 0.9, 0.4], + [-3.5, -0.5, 1], + [-2.1, 0, 0.4], + [-0.2, 0.9, 0.4], + [-0.5, -0.5, 1], + [0.9, 0, 0.4], + [2.8, 0.9, 1.4], + [2.5, -0.5, 2], + [3.9, 0, 1.4], + ] +) +dirs = np.array( + [ + [-0.2, 0.9, 0.4], + [-0.5, -0.5, 1], + [0.9, 0, 0.4], + [-0.2, 0.9, 0.4], + [-0.5, -0.5, 1], + [0.9, 0, 0.4], + [-0.2, 0.9, 0.4], + [-0.5, -0.5, 1], + [0.9, 0, 0.4], + ] +) +colors = np.array( + [ + [1, 0, 0], + [1, 0, 0], + [1, 0, 0], + [0, 1, 0], + [0, 1, 0], + [0, 1, 0], + [0, 0, 1], + [0, 0, 1], + [0, 0, 1], + ] +) +radius = 0.5 +height = 1 + +############################################################################### +# In order to see how cylinders are made, we set different resolutions (number +# of sides used to define the bases of the cylinder) to see how it changes the +# surface of the primitive. + +cylinders_8 = actor.cylinder( + centers[:3], + dirs[:3], + colors[:3], + radius=radius, + heights=height, + capped=True, + resolution=8, +) +cylinders_16 = actor.cylinder( + centers[3:6], + dirs[3:6], + colors[3:6], + radius=radius, + heights=height, + capped=True, + resolution=16, +) +cylinders_32 = actor.cylinder( + centers[6:9], + dirs[6:9], + colors[6:9], + radius=radius, + heights=height, + capped=True, + resolution=32, +) + +############################################################################### +# Next, we set up a new scene to add and visualize the actors created. + +scene = window.Scene() + +scene.add(cylinders_8) +scene.add(cylinders_16) +scene.add(cylinders_32) + +interactive = False + +if interactive: + window.show(scene) + +window.record(scene, size=(600, 600), out_path='viz_poly_cylinder.png') + +############################################################################### +# Visualize the surface geometry representation for the object. + +cylinders_8.GetProperty().SetRepresentationToWireframe() +cylinders_16.GetProperty().SetRepresentationToWireframe() +cylinders_32.GetProperty().SetRepresentationToWireframe() + +if interactive: + window.show(scene) + +window.record(scene, size=(600, 600), out_path='viz_poly_cylinder_geom.png') + +############################################################################### +# Then we clean the scene to render the boxes we will use to render our +# SDF-based actors. + +scene.clear() + +############################################################################### +# Cylinder using SDF +# ================== +# Signed Distance Functions are mathematical functions that take as input a +# point in a metric space and return the distance from that point to the +# boundary of an object. +# +# We will use the ray marching algorithm to render the SDF primitive using +# shaders. Ray marching is a technique where you step along a ray in order to +# find intersections with solid geometry. Objects in the scene are defined by +# SDF, and because we don’t use polygonal meshes it is possible to define +# perfectly smooth surfaces and allows a faster rendering in comparison to +# polygon-based modeling (more details in [Hart1996]_). + +############################################################################### +# Now we create cylinders using box actor and SDF implementation on shaders. +# For this, we first create a box actor. + +box_actor = actor.box( + centers=centers, + directions=dirs, + colors=colors, + scales=(height, radius * 2, radius * 2), +) + +############################################################################### +# Now we use attribute_to_actor to link a NumPy array, with the centers and +# directions data, with a vertex attribute. We do this to pass the data to +# the vertex shader, with the corresponding attribute name. +# +# We need to associate the data to each of the 8 vertices that make up the box +# since we handle the processing of individual vertices in the vertex shader. + +rep_directions = np.repeat(dirs, 8, axis=0) +rep_centers = np.repeat(centers, 8, axis=0) +rep_radii = np.repeat(np.repeat(radius, 9), 8, axis=0) +rep_heights = np.repeat(np.repeat(height, 9), 8, axis=0) + +attribute_to_actor(box_actor, rep_centers, 'center') +attribute_to_actor(box_actor, rep_directions, 'direction') +attribute_to_actor(box_actor, rep_radii, 'radius') +attribute_to_actor(box_actor, rep_heights, 'height') + +############################################################################### +# Then we have the shader code implementation corresponding to vertex and +# fragment shader. Here we are passing data to the fragment shader through +# the vertex shader. +# +# Vertex shaders perform basic processing of each individual vertex. + +vs_dec = """ + in vec3 center; + in vec3 direction; + in float height; + in float radius; + + out vec4 vertexMCVSOutput; + out vec3 centerMCVSOutput; + out vec3 directionVSOutput; + out float heightVSOutput; + out float radiusVSOutput; + """ + +vs_impl = """ + vertexMCVSOutput = vertexMC; + centerMCVSOutput = center; + directionVSOutput = direction; + heightVSOutput = height; + radiusVSOutput = radius; + """ + +############################################################################### +# Then we add the vertex shader code to the box_actor. We use shader_to_actor +# to apply our implementation to the shader creation process, this function +# joins our code to the shader template that FURY has by default. + +shader_to_actor(box_actor, 'vertex', decl_code=vs_dec, impl_code=vs_impl) + +############################################################################### +# Fragment shaders are used to define the colors of each pixel being processed, +# the program runs on each of the pixels that the object occupies on the +# screen. +# +# Fragment shaders also allow us to have control over details of movement, +# lighting, and color in a scene. In this case, we are using vertex shader not +# just to define the colors of the cylinders but to manipulate its position in +# world space, rotation with respect to the box, and lighting of the scene. + +fs_vars_dec = """ + in vec4 vertexMCVSOutput; + in vec3 centerMCVSOutput; + in vec3 directionVSOutput; + in float heightVSOutput; + in float radiusVSOutput; + + uniform mat4 MCVCMatrix; + """ + +############################################################################### +# We use this function to generate an appropriate rotation matrix which help us +# to transform our position vectors in order to align the direction of +# cylinder with respect to the box. + +vec_to_vec_rot_mat = import_fury_shader( + os.path.join('utils', 'vec_to_vec_rot_mat.glsl') +) + +############################################################################### +# We calculate the distance using the SDF function for the cylinder. + +sd_cylinder = import_fury_shader(os.path.join('sdf', 'sd_cylinder.frag')) + +############################################################################### +# This is used on calculations for surface normals of the cylinder. + +sdf_map = """ + float map(in vec3 position) + { + // the sdCylinder function creates vertical cylinders by default, that + // is the cylinder is created pointing in the up direction (0, 1, 0). + // We want to rotate that vector to be aligned with the box's direction + mat4 rot = vec2VecRotMat(normalize(directionVSOutput), + normalize(vec3(0, 1, 0))); + + vec3 pos = (rot * vec4(position - centerMCVSOutput, 0.0)).xyz; + + // distance to the cylinder's boundary + return sdCylinder(pos, radiusVSOutput, heightVSOutput / 2); + } + """ + +############################################################################### +# We use central differences technique for computing surface normals. + +central_diffs_normal = import_fury_shader(os.path.join('sdf', 'central_diffs.frag')) + +############################################################################### +# We use cast_ray for the implementation of Ray Marching. + +cast_ray = import_fury_shader(os.path.join('ray_marching', 'cast_ray.frag')) + +############################################################################### +# For the illumination of the scene we use the Blinn-Phong model. + +blinn_phong_model = import_fury_shader( + os.path.join('lighting', 'blinn_phong_model.frag') +) + +############################################################################### +# Now we use compose_shader to join our pieces of GLSL shader code. + +fs_dec = compose_shader( + [ + fs_vars_dec, + vec_to_vec_rot_mat, + sd_cylinder, + sdf_map, + central_diffs_normal, + cast_ray, + blinn_phong_model, + ] +) + +shader_to_actor(box_actor, 'fragment', decl_code=fs_dec) + +############################################################################### +# Here we have the implementation of all the previous code with all the +# necessary variables and functions to build the cylinders. + +sdf_cylinder_frag_impl = """ + vec3 point = vertexMCVSOutput.xyz; + + // ray origin + vec4 ro = -MCVCMatrix[3] * MCVCMatrix; // camera position in world space + + // ray direction + vec3 rd = normalize(point - ro.xyz); + + // light direction + vec3 ld = normalize(ro.xyz - point); + + ro += vec4((point - ro.xyz), 0); + + float t = castRay(ro.xyz, rd); + + if(t < 20.0) + { + vec3 position = ro.xyz + t * rd; + vec3 normal = centralDiffsNormals(position, .0001); + float lightAttenuation = dot(ld, normal); + vec3 color = blinnPhongIllumModel( + lightAttenuation, lightColor0, diffuseColor, + specularPower, specularColor, ambientColor); + fragOutput0 = vec4(color, opacity); + } + else + { + discard; + } + """ + +shader_to_actor(box_actor, 'fragment', impl_code=sdf_cylinder_frag_impl, block='light') + +############################################################################### +# Finally, we visualize the cylinders made using ray marching and SDFs. + +scene.add(box_actor) + +if interactive: + window.show(scene) + +window.record(scene, size=(600, 600), out_path='viz_sdf_cylinder.png') + +############################################################################### +# References +# ---------- +# .. [Hart1996] Hart, John C. "Sphere tracing: A geometric method for the +# antialiased ray tracing of implicit surfaces." The Visual +# Computer 12.10 (1996): 527-545. +# +# .. include:: ../links_names.inc diff --git a/v0.10.x/_downloads/e1f57a2229a86d1b9868d9f5fd1ca494/viz_fiber_odf.py b/v0.10.x/_downloads/e1f57a2229a86d1b9868d9f5fd1ca494/viz_fiber_odf.py new file mode 100644 index 000000000..de50c413e --- /dev/null +++ b/v0.10.x/_downloads/e1f57a2229a86d1b9868d9f5fd1ca494/viz_fiber_odf.py @@ -0,0 +1,252 @@ +""" +==================================== +Brain Fiber ODF Visualisation +==================================== + +This example demonstrate how to create a simple viewer for fiber +orientation distribution functions (ODF) using fury's odf_slicer. +""" + +import nibabel as nib + +# First, we import some useful modules and methods. +import numpy as np +from dipy.data import get_sphere +from dipy.reconst.shm import sh_to_sf_matrix + +from fury import actor, ui, window +from fury.data import fetch_viz_dmri, fetch_viz_icons, read_viz_dmri +from fury.utils import fix_winding_order + +############################################################################### +# Here, we fetch and load the fiber ODF volume to display. The ODF are +# expressed as spherical harmonics (SH) coefficients in a 3D grid. +fetch_viz_dmri() +fetch_viz_icons() + +fodf_img = nib.load(read_viz_dmri('fodf.nii.gz')) +sh = fodf_img.get_fdata() +affine = fodf_img.affine +grid_shape = sh.shape[:-1] + +############################################################################### +# We then define a low resolution sphere used to visualize SH coefficients +# as spherical functions (SF) as well as a matrix `B_low` to project SH +# onto the sphere. +sphere_low = get_sphere('repulsion100') +B_low = sh_to_sf_matrix(sphere_low, 8, return_inv=False) + +############################################################################### +# Now, we create a slicer for each orientation to display a slice in +# the middle of the volume and we add them to a `scene`. + +# Change these values to test various parameters combinations. +scale = 0.5 +norm = False +colormap = None +radial_scale = True +opacity = 1.0 +global_cm = False + +# ODF slicer for axial slice +odf_actor_z = actor.odf_slicer( + sh, + affine=affine, + sphere=sphere_low, + scale=scale, + norm=norm, + radial_scale=radial_scale, + opacity=opacity, + colormap=colormap, + global_cm=global_cm, + B_matrix=B_low, +) + +# ODF slicer for coronal slice +odf_actor_y = actor.odf_slicer( + sh, + affine=affine, + sphere=sphere_low, + scale=scale, + norm=norm, + radial_scale=radial_scale, + opacity=opacity, + colormap=colormap, + global_cm=global_cm, + B_matrix=B_low, +) +odf_actor_y.display_extent( + 0, grid_shape[0] - 1, grid_shape[1] // 2, grid_shape[1] // 2, 0, grid_shape[2] - 1 +) + +# ODF slicer for sagittal slice +odf_actor_x = actor.odf_slicer( + sh, + affine=affine, + sphere=sphere_low, + scale=scale, + norm=norm, + radial_scale=radial_scale, + opacity=opacity, + colormap=colormap, + global_cm=global_cm, + B_matrix=B_low, +) +odf_actor_x.display_extent( + grid_shape[0] // 2, grid_shape[0] // 2, 0, grid_shape[1] - 1, 0, grid_shape[2] - 1 +) + +scene = window.Scene() +scene.add(odf_actor_z) +scene.add(odf_actor_y) +scene.add(odf_actor_x) + +show_m = window.ShowManager(scene, reset_camera=True, size=(1200, 900)) + + +############################################################################### +# Now that we have a `ShowManager` containing our slicer, we can go on and +# configure our UI for changing the slices to visualize. +line_slider_z = ui.LineSlider2D( + min_value=0, + max_value=grid_shape[2] - 1, + initial_value=grid_shape[2] / 2, + text_template='{value:.0f}', + length=140, +) + +line_slider_y = ui.LineSlider2D( + min_value=0, + max_value=grid_shape[1] - 1, + initial_value=grid_shape[1] / 2, + text_template='{value:.0f}', + length=140, +) + +line_slider_x = ui.LineSlider2D( + min_value=0, + max_value=grid_shape[0] - 1, + initial_value=grid_shape[0] / 2, + text_template='{value:.0f}', + length=140, +) + +############################################################################### +# We also define a high resolution sphere to demonstrate the capability to +# dynamically change the sphere used for SH to SF projection. +sphere_high = get_sphere('symmetric362') + +# We fix the order of the faces' three vertices to a clockwise winding. This +# ensures all faces have a normal going away from the center of the sphere. +sphere_high.faces = fix_winding_order(sphere_high.vertices, sphere_high.faces, True) +B_high = sh_to_sf_matrix(sphere_high, 8, return_inv=False) + +############################################################################### +# We add a combobox for choosing the sphere resolution during execution. +sphere_dict = { + 'Low resolution': (sphere_low, B_low), + 'High resolution': (sphere_high, B_high), +} +combobox = ui.ComboBox2D(items=list(sphere_dict)) +scene.add(combobox) + +############################################################################### +# Here we will write callbacks for the sliders and combo box and register them. + + +def change_slice_z(slider): + i = int(np.round(slider.value)) + odf_actor_z.slice_along_axis(i) + + +def change_slice_y(slider): + i = int(np.round(slider.value)) + odf_actor_y.slice_along_axis(i, 'yaxis') + + +def change_slice_x(slider): + i = int(np.round(slider.value)) + odf_actor_x.slice_along_axis(i, 'xaxis') + + +def change_sphere(combobox): + sphere, B = sphere_dict[combobox.selected_text] + odf_actor_x.update_sphere(sphere.vertices, sphere.faces, B) + odf_actor_y.update_sphere(sphere.vertices, sphere.faces, B) + odf_actor_z.update_sphere(sphere.vertices, sphere.faces, B) + + +line_slider_z.on_change = change_slice_z +line_slider_y.on_change = change_slice_y +line_slider_x.on_change = change_slice_x +combobox.on_change = change_sphere + +############################################################################### +# We then add labels for the sliders and position them inside a panel. + + +def build_label(text): + label = ui.TextBlock2D() + label.message = text + label.font_size = 18 + label.font_family = 'Arial' + label.justification = 'left' + label.bold = False + label.italic = False + label.shadow = False + label.background_color = (0, 0, 0) + label.color = (1, 1, 1) + + return label + + +line_slider_label_z = build_label(text='Z Slice') +line_slider_label_y = build_label(text='Y Slice') +line_slider_label_x = build_label(text='X Slice') + +panel = ui.Panel2D(size=(300, 200), color=(1, 1, 1), opacity=0.1, align='right') +panel.center = (1030, 120) + +panel.add_element(line_slider_label_x, (0.1, 0.75)) +panel.add_element(line_slider_x, (0.38, 0.75)) +panel.add_element(line_slider_label_y, (0.1, 0.55)) +panel.add_element(line_slider_y, (0.38, 0.55)) +panel.add_element(line_slider_label_z, (0.1, 0.35)) +panel.add_element(line_slider_z, (0.38, 0.35)) + +show_m.scene.add(panel) + +############################################################################### +# Then, we can render all the widgets and everything else in the screen and +# start the interaction using ``show_m.start()``. +# +# However, if you change the window size, the panel will not update its +# position properly. The solution to this issue is to update the position of +# the panel using its ``re_align`` method every time the window size changes. +size = scene.GetSize() + + +def win_callback(obj, _event): + global size + if size != obj.GetSize(): + size_old = size + size = obj.GetSize() + size_change = [size[0] - size_old[0], 0] + panel.re_align(size_change) + + +############################################################################### +# Finally, please set the following variable to ``True`` to interact with the +# datasets in 3D. +interactive = False + +if interactive: + show_m.add_window_callback(win_callback) + show_m.render() + show_m.start() +else: + window.record( + scene, out_path='odf_slicer_3D.png', size=(1200, 900), reset_camera=False + ) + +del show_m diff --git a/v0.10.x/_downloads/e22a09689bdb9d1c7847fe275f1e83ba/viz_pbr_interactive.ipynb b/v0.10.x/_downloads/e22a09689bdb9d1c7847fe275f1e83ba/viz_pbr_interactive.ipynb new file mode 100644 index 000000000..4d314114a --- /dev/null +++ b/v0.10.x/_downloads/e22a09689bdb9d1c7847fe275f1e83ba/viz_pbr_interactive.ipynb @@ -0,0 +1,439 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Interactive PBR demo\n\nThis is a demonstration of how Physically-Based Rendering (PBR) can be used to\nsimulate different materials.\n\nLet's start by importing the necessary modules:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "from fury import actor, material, ui, window\nfrom fury.data import fetch_viz_cubemaps, read_viz_cubemap\nfrom fury.io import load_cubemap_texture\nfrom fury.utils import (\n normals_from_actor,\n tangents_from_direction_of_anisotropy,\n tangents_to_actor,\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The following functions will help us to manage the sliders events.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def change_slice_metallic(slider):\n global pbr_params\n pbr_params.metallic = slider.value\n\n\ndef change_slice_roughness(slider):\n global pbr_params\n pbr_params.roughness = slider.value\n\n\ndef change_slice_anisotropy(slider):\n global pbr_params\n pbr_params.anisotropy = slider.value\n\n\ndef change_slice_anisotropy_direction_x(slider):\n global doa, normals, sphere\n doa[0] = slider.value\n tangents = tangents_from_direction_of_anisotropy(normals, doa)\n tangents_to_actor(sphere, tangents)\n\n\ndef change_slice_anisotropy_direction_y(slider):\n global doa, normals, sphere\n doa[1] = slider.value\n tangents = tangents_from_direction_of_anisotropy(normals, doa)\n tangents_to_actor(sphere, tangents)\n\n\ndef change_slice_anisotropy_direction_z(slider):\n global doa, normals, sphere\n doa[2] = slider.value\n tangents = tangents_from_direction_of_anisotropy(normals, doa)\n tangents_to_actor(sphere, tangents)\n\n\ndef change_slice_anisotropy_rotation(slider):\n global pbr_params\n pbr_params.anisotropy_rotation = slider.value\n\n\ndef change_slice_coat_strength(slider):\n global pbr_params\n pbr_params.coat_strength = slider.value\n\n\ndef change_slice_coat_roughness(slider):\n global pbr_params\n pbr_params.coat_roughness = slider.value\n\n\ndef change_slice_base_ior(slider):\n global pbr_params\n pbr_params.base_ior = slider.value\n\n\ndef change_slice_coat_ior(slider):\n global pbr_params\n pbr_params.coat_ior = slider.value" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Last, but not least, we define the following function to help us to\nreposition the UI elements every time we resize the window.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def win_callback(obj, event):\n global control_panel, size\n if size != obj.GetSize():\n size_old = size\n size = obj.GetSize()\n size_change = [size[0] - size_old[0], 0]\n control_panel.re_align(size_change)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's fetch a skybox texture from the FURY data repository.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "fetch_viz_cubemaps()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The following function returns the full path of the 6 images composing the\nskybox.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "textures = read_viz_cubemap('skybox')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now that we have the location of the textures, let's load them and create a\nCube Map Texture object.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "cubemap = load_cubemap_texture(textures)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The Scene object in FURY can handle cube map textures and extract light\ninformation from them, so it can be used to create more plausible materials\ninteractions. The ``skybox`` parameter takes as input a cube map texture and\nperforms the previously described process.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "scene = window.Scene(skybox=cubemap)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "With the scene created, we can then populate it. In this demo we will only\nadd a sphere actor.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "sphere = actor.sphere([[0, 0, 0]], (0.7, 0.7, 0.7), radii=2, theta=64, phi=64)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The direction of anisotropy (DoA) defines the direction at which all the\ntangents of our actor are pointing.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "doa = [0, 1, 0.5]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The following process gets the normals of the actor and computes the tangents\nthat are aligned to the provided DoA. Then it registers those tangents to the\nactor.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "normals = normals_from_actor(sphere)\ntangents = tangents_from_direction_of_anisotropy(normals, doa)\ntangents_to_actor(sphere, tangents)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "With the tangents computed and in place, we have all the elements needed to\nadd some material properties to the actor.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "pbr_params = material.manifest_pbr(sphere)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Our actor is now ready to be added to the scene.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "scene.add(sphere)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's setup now the window and the UI.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "show_m = window.ShowManager(\n scene=scene, size=(1920, 1080), reset_camera=False, order_transparent=True\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We will create one single panel with all of our labels and sliders.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "control_panel = ui.Panel2D(\n (400, 500), position=(5, 5), color=(0.25, 0.25, 0.25), opacity=0.75, align='right'\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "By using our previously defined function, we can easily create all the labels\nwe need for this demo. And then add them to the panel.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "slider_label_metallic = ui.TextBlock2D(text='Metallic', font_size=16)\nslider_label_roughness = ui.TextBlock2D(text='Roughness', font_size=16)\nslider_label_anisotropy = ui.TextBlock2D(text='Anisotropy', font_size=16)\nslider_label_anisotropy_rotation = ui.TextBlock2D(\n text='Anisotropy Rotation', font_size=16\n)\nslider_label_anisotropy_direction_x = ui.TextBlock2D(\n text='Anisotropy Direction X', font_size=16\n)\nslider_label_anisotropy_direction_y = ui.TextBlock2D(\n text='Anisotropy Direction Y', font_size=16\n)\nslider_label_anisotropy_direction_z = ui.TextBlock2D(\n text='Anisotropy Direction Z', font_size=16\n)\nslider_label_coat_strength = ui.TextBlock2D(text='Coat Strength', font_size=16)\nslider_label_coat_roughness = ui.TextBlock2D(text='Coat Roughness', font_size=16)\nslider_label_base_ior = ui.TextBlock2D(text='Base IoR', font_size=16)\nslider_label_coat_ior = ui.TextBlock2D(text='Coat IoR', font_size=16)\n\ncontrol_panel.add_element(slider_label_metallic, (0.01, 0.95))\ncontrol_panel.add_element(slider_label_roughness, (0.01, 0.86))\ncontrol_panel.add_element(slider_label_anisotropy, (0.01, 0.77))\ncontrol_panel.add_element(slider_label_anisotropy_rotation, (0.01, 0.68))\ncontrol_panel.add_element(slider_label_anisotropy_direction_x, (0.01, 0.59))\ncontrol_panel.add_element(slider_label_anisotropy_direction_y, (0.01, 0.5))\ncontrol_panel.add_element(slider_label_anisotropy_direction_z, (0.01, 0.41))\ncontrol_panel.add_element(slider_label_coat_strength, (0.01, 0.32))\ncontrol_panel.add_element(slider_label_coat_roughness, (0.01, 0.23))\ncontrol_panel.add_element(slider_label_base_ior, (0.01, 0.14))\ncontrol_panel.add_element(slider_label_coat_ior, (0.01, 0.05))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Our sliders are created and added to the panel in the following way.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "slider_slice_metallic = ui.LineSlider2D(\n initial_value=pbr_params.metallic,\n max_value=1,\n length=195,\n text_template='{value:.1f}',\n)\nslider_slice_roughness = ui.LineSlider2D(\n initial_value=pbr_params.roughness,\n max_value=1,\n length=195,\n text_template='{value:.1f}',\n)\nslider_slice_anisotropy = ui.LineSlider2D(\n initial_value=pbr_params.anisotropy,\n max_value=1,\n length=195,\n text_template='{value:.1f}',\n)\nslider_slice_anisotropy_rotation = ui.LineSlider2D(\n initial_value=pbr_params.anisotropy_rotation,\n max_value=1,\n length=195,\n text_template='{value:.1f}',\n)\nslider_slice_coat_strength = ui.LineSlider2D(\n initial_value=pbr_params.coat_strength,\n max_value=1,\n length=195,\n text_template='{value:.1f}',\n)\nslider_slice_coat_roughness = ui.LineSlider2D(\n initial_value=pbr_params.coat_roughness,\n max_value=1,\n length=195,\n text_template='{value:.1f}',\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Notice that we are defining a range of [-1, 1] for the DoA. This is because\nwithin that range we cover all the possible 3D directions needed to align the\ntangents.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "slider_slice_anisotropy_direction_x = ui.LineSlider2D(\n initial_value=doa[0],\n min_value=-1,\n max_value=1,\n length=195,\n text_template='{value:.1f}',\n)\nslider_slice_anisotropy_direction_y = ui.LineSlider2D(\n initial_value=doa[1],\n min_value=-1,\n max_value=1,\n length=195,\n text_template='{value:.1f}',\n)\nslider_slice_anisotropy_direction_z = ui.LineSlider2D(\n initial_value=doa[2],\n min_value=-1,\n max_value=1,\n length=195,\n text_template='{value:.1f}',\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Another special case are the Index of Refraction (IoR) sliders. In these\ncases, the values are defined in the range [1, 2.3] according to the\ndocumentation of the material.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "slider_slice_base_ior = ui.LineSlider2D(\n initial_value=pbr_params.base_ior,\n min_value=1,\n max_value=2.3,\n length=195,\n text_template='{value:.02f}',\n)\nslider_slice_coat_ior = ui.LineSlider2D(\n initial_value=pbr_params.coat_ior,\n min_value=1,\n max_value=2.3,\n length=195,\n text_template='{value:.02f}',\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's add the event handlers functions to the corresponding sliders.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "slider_slice_metallic.on_change = change_slice_metallic\nslider_slice_roughness.on_change = change_slice_roughness\nslider_slice_anisotropy.on_change = change_slice_anisotropy\nslider_slice_anisotropy_rotation.on_change = change_slice_anisotropy_rotation\nslider_slice_anisotropy_direction_x.on_change = change_slice_anisotropy_direction_x\nslider_slice_anisotropy_direction_y.on_change = change_slice_anisotropy_direction_y\nslider_slice_anisotropy_direction_z.on_change = change_slice_anisotropy_direction_z\nslider_slice_coat_strength.on_change = change_slice_coat_strength\nslider_slice_coat_roughness.on_change = change_slice_coat_roughness\nslider_slice_base_ior.on_change = change_slice_base_ior\nslider_slice_coat_ior.on_change = change_slice_coat_ior" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "And then add the sliders to the panel.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "control_panel.add_element(slider_slice_metallic, (0.44, 0.95))\ncontrol_panel.add_element(slider_slice_roughness, (0.44, 0.86))\ncontrol_panel.add_element(slider_slice_anisotropy, (0.44, 0.77))\ncontrol_panel.add_element(slider_slice_anisotropy_rotation, (0.44, 0.68))\ncontrol_panel.add_element(slider_slice_anisotropy_direction_x, (0.44, 0.59))\ncontrol_panel.add_element(slider_slice_anisotropy_direction_y, (0.44, 0.5))\ncontrol_panel.add_element(slider_slice_anisotropy_direction_z, (0.44, 0.41))\ncontrol_panel.add_element(slider_slice_coat_strength, (0.44, 0.32))\ncontrol_panel.add_element(slider_slice_coat_roughness, (0.44, 0.23))\ncontrol_panel.add_element(slider_slice_base_ior, (0.44, 0.14))\ncontrol_panel.add_element(slider_slice_coat_ior, (0.44, 0.05))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Consequently, we add the panel to the scene.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "scene.add(control_panel)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Previously we defined a function to help us when we resize the window, so\nlet's capture the current size and add our helper function as a\n`window_callback` to the window.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "size = scene.GetSize()\n\nshow_m.add_window_callback(win_callback)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Finally, let's visualize our demo.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "interactive = False\nif interactive:\n show_m.start()\n\nwindow.record(scene, size=(1920, 1080), out_path='viz_pbr_interactive.png')" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.8" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/v0.10.x/_downloads/e23bfcec8d867b7ad34707395cebc46b/viz_sphere.ipynb b/v0.10.x/_downloads/e23bfcec8d867b7ad34707395cebc46b/viz_sphere.ipynb new file mode 100644 index 000000000..295f296aa --- /dev/null +++ b/v0.10.x/_downloads/e23bfcec8d867b7ad34707395cebc46b/viz_sphere.ipynb @@ -0,0 +1,115 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# FURY sphere Actor\nThis example shows how to use both primitive and vtkSource sphere actor.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "import numpy as np\n\nfrom fury import actor, window" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "First thing, you have to specify centers and colors of the sphere\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "centers = np.zeros([1, 3])\ncolors = np.array([0, 0, 1])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The below sphere actor is generated by repeating the sphere primitive.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "prim_sphere_actor = actor.sphere(centers, colors=colors, radii=5)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This time, we're using vtkSphereSource to generate the sphere actor\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "cen2 = np.add(centers, np.array([12, 0, 0]))\ncols2 = np.array([1, 0, 0])\n\nvtk_sphere_actor = actor.sphere(cen2, colors=cols2, radii=5, use_primitive=False)\n\nscene = window.Scene()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Adding our sphere actors to scene.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "scene.add(prim_sphere_actor)\nscene.add(vtk_sphere_actor)\n\ninteractive = False\n\nif interactive:\n window.show(scene, size=(600, 600))\n\nwindow.record(scene, out_path='viz_sphere.png', size=(600, 600))" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.8" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/v0.10.x/_downloads/e2cb98487fda751bd396a35d69fea694/viz_brownian_motion.ipynb b/v0.10.x/_downloads/e2cb98487fda751bd396a35d69fea694/viz_brownian_motion.ipynb new file mode 100644 index 000000000..0491101dd --- /dev/null +++ b/v0.10.x/_downloads/e2cb98487fda751bd396a35d69fea694/viz_brownian_motion.ipynb @@ -0,0 +1,205 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Brownian motion\nBrownian motion, or pedesis, is the random motion of particles\nsuspended in a medium. In this animation, path followed by 20 particles\nexhibiting brownian motion in 3D is plotted.\n\nImporting necessary modules\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "import numpy as np\nfrom scipy.stats import norm\n\nfrom fury import actor, ui, utils, window" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's define some variable and their description:\n\n* **total_time**: time to be discretized via time_steps (default: 5)\n* **num_total_steps**: total number of steps each particle will take\n (default: 300)\n* **time_step**: By default, it is equal to total_time / num_total_steps\n* **counter_step**: to keep track of number of steps taken\n (initialised to 0)\n* **delta**: delta determines the \"speed\" of the Brownian motion.\n Increase delta to speed up the motion of the particle(s). The random\n variable of the position has a normal distribution whose mean is the\n position at counter_step = 0 and whose variance is equal to\n delta**2*time_step. (default: 1.8)\n* **num_particles**: number of particles whose path will be plotted\n (default: 20)\n* **path_thickness**: thickness of line(s) that will be used to plot the\n path(s) of the particle(s) (default: 3)\n* **origin**: coordinate from which the the particle(s) begin the motion\n (default: [0, 0, 0])\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "total_time = 5\nnum_total_steps = 300\ncounter_step = 0\ndelta = 1.8\nnum_particles = 20\npath_thickness = 3\norigin = [0, 0, 0]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We define a particle function that will return an actor, store and update\ncoordinates of the particles (the path of the particles).\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def particle(\n colors,\n origin=[0, 0, 0],\n num_total_steps=300,\n total_time=5,\n delta=1.8,\n path_thickness=3,\n):\n origin = np.asarray(origin, dtype=float)\n position = np.tile(origin, (num_total_steps, 1))\n path_actor = actor.line([position], colors, linewidth=path_thickness)\n path_actor.position = position\n path_actor.delta = delta\n path_actor.num_total_steps = num_total_steps\n path_actor.time_step = total_time / num_total_steps\n path_actor.vertices = utils.vertices_from_actor(path_actor)\n path_actor.no_vertices_per_point = len(path_actor.vertices) / num_total_steps\n path_actor.initial_vertices = path_actor.vertices.copy() - np.repeat(\n position, path_actor.no_vertices_per_point, axis=0\n )\n return path_actor" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The function `update_path` will simulate the the brownian motion.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def update_path(act, counter_step):\n if counter_step < act.num_total_steps:\n x, y, z = act.position[counter_step - 1]\n x += norm.rvs(scale=act.delta**2 * act.time_step)\n y += norm.rvs(scale=act.delta**2 * act.time_step)\n z += norm.rvs(scale=act.delta**2 * act.time_step)\n act.position[counter_step:] = [x, y, z]\n act.vertices[:] = act.initial_vertices + np.repeat(\n act.position, act.no_vertices_per_point, axis=0\n )\n utils.update_actor(act)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Creating a scene object and configuring the camera's position\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "scene = window.Scene()\nscene.background((1.0, 1.0, 1.0))\nscene.zoom(1.7)\nscene.set_camera(\n position=(0, 0, 40), focal_point=(0.0, 0.0, 0.0), view_up=(0.0, 0.0, 0.0)\n)\nshowm = window.ShowManager(\n scene, size=(600, 600), reset_camera=True, order_transparent=True\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Creating a list of particle objects\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "l_particle = [\n particle(\n colors=np.random.rand(1, 3),\n origin=origin,\n num_total_steps=num_total_steps,\n total_time=total_time,\n path_thickness=path_thickness,\n )\n for _ in range(num_particles)\n]\n\nscene.add(*l_particle)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Creating a container (cube actor) inside which the particle(s) move around\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "container_actor = actor.box(\n centers=np.array([[0, 0, 0]]), colors=(0.5, 0.9, 0.7, 0.4), scales=6\n)\nscene.add(container_actor)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Initializing text box to display the name of the animation\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "tb = ui.TextBlock2D(bold=True, position=(235, 40), color=(0, 0, 0))\ntb.message = 'Brownian Motion'\nscene.add(tb)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The path of the particles exhibiting Brownian motion is plotted here\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def timer_callback(_obj, _event):\n global counter_step, list_particle\n counter_step += 1\n for p in l_particle:\n update_path(p, counter_step=counter_step)\n showm.render()\n scene.azimuth(2)\n if counter_step == num_total_steps:\n showm.exit()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Run every 30 milliseconds\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "showm.add_timer_callback(True, 30, timer_callback)\nshowm.start()\nwindow.record(showm.scene, size=(600, 600), out_path='viz_brownian_motion.png')" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.8" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/v0.10.x/_downloads/e7ac72a3cdf9ab5794a35aa4267b6b25/viz_bundles.ipynb b/v0.10.x/_downloads/e7ac72a3cdf9ab5794a35aa4267b6b25/viz_bundles.ipynb new file mode 100644 index 000000000..c0d576cec --- /dev/null +++ b/v0.10.x/_downloads/e7ac72a3cdf9ab5794a35aa4267b6b25/viz_bundles.ipynb @@ -0,0 +1,338 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Visualize bundles and metrics on bundles\n\nFirst, let's download some available datasets. Here we are using a dataset\nwhich provides metrics and bundles.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "import numpy as np\nfrom dipy.data import fetch_bundles_2_subjects, read_bundles_2_subjects\nfrom dipy.tracking.streamline import length, transform_streamlines\n\nfrom fury import actor, window\n\ninteractive = False # set to True to show the interactive display window\n\nfetch_bundles_2_subjects()\ndix = read_bundles_2_subjects(\n subj_id='subj_1', metrics=['fa'], bundles=['cg.left', 'cst.right']\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Store fractional anisotropy.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "fa = dix['fa']" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Store grid to world transformation matrix.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "affine = dix['affine']" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Store the cingulum bundle. A bundle is a list of streamlines.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "bundle = dix['cg.left']" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "It happened that this bundle is in world coordinates and therefore we need to\ntransform it into native image coordinates so that it is in the same\ncoordinate space as the ``fa`` image.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "bundle_native = transform_streamlines(bundle, np.linalg.inv(affine))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Show every streamline with an orientation color\n\nThis is the default option when you are using ``line`` or ``streamtube``.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "scene = window.Scene()\n\nstream_actor = actor.line(bundle_native)\n\nscene.set_camera(\n position=(-176.42, 118.52, 128.20),\n focal_point=(113.30, 128.31, 76.56),\n view_up=(0.18, 0.00, 0.98),\n)\n\nscene.add(stream_actor)\n\nif interactive:\n window.show(scene, size=(600, 600), reset_camera=False)\n\nwindow.record(scene, out_path='bundle1.png', size=(600, 600))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You may wonder how we knew how to set the camera. This is very easy. You just\nneed to run ``window.show`` once see how you want to see the object and then\nclose the window and call the ``camera_info`` method which prints the\nposition, focal point and view up vectors of the camera.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "scene.camera_info()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Show every point with a value from a volume with default colormap\n\nHere we will need to input the ``fa`` map in ``streamtube`` or ``line``.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "scene.clear()\nstream_actor2 = actor.line(bundle_native, fa, linewidth=0.1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can also show the scalar bar.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "bar = actor.scalar_bar()\n\nscene.add(stream_actor2)\nscene.add(bar)\n\nif interactive:\n window.show(scene, size=(600, 600), reset_camera=False)\n\nwindow.record(scene, out_path='bundle2.png', size=(600, 600))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Show every point with a value from a volume with your colormap\n\nHere we will need to input the ``fa`` map in ``streamtube``\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "scene.clear()\n\nhue = (0.0, 0.0) # red only\nsaturation = (0.0, 1.0) # white to red\n\nlut_cmap = actor.colormap_lookup_table(hue_range=hue, saturation_range=saturation)\n\nstream_actor3 = actor.line(bundle_native, fa, linewidth=0.1, lookup_colormap=lut_cmap)\nbar2 = actor.scalar_bar(lut_cmap)\n\nscene.add(stream_actor3)\nscene.add(bar2)\n\nif interactive:\n window.show(scene, size=(600, 600), reset_camera=False)\n\nwindow.record(scene, out_path='bundle3.png', size=(600, 600))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Show every bundle with a specific color\n\nYou can have a bundle with a specific color. In this example, we are choosing\norange.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "scene.clear()\nstream_actor4 = actor.line(bundle_native, (1.0, 0.5, 0), linewidth=0.1)\n\nscene.add(stream_actor4)\n\nif interactive:\n window.show(scene, size=(600, 600), reset_camera=False)\n\nwindow.record(scene, out_path='bundle4.png', size=(600, 600))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Show every streamline of a bundle with a different color\n\nLet's make a colormap where every streamline of the bundle is colored by its\nlength.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "scene.clear()\n\nlengths = length(bundle_native)\n\nhue = (0.5, 0.5) # blue only\nsaturation = (0.0, 1.0) # black to white\n\nlut_cmap = actor.colormap_lookup_table(\n scale_range=(lengths.min(), lengths.max()),\n hue_range=hue,\n saturation_range=saturation,\n)\n\nstream_actor5 = actor.line(\n bundle_native, lengths, linewidth=0.1, lookup_colormap=lut_cmap\n)\n\nscene.add(stream_actor5)\nbar3 = actor.scalar_bar(lut_cmap)\n\nscene.add(bar3)\n\nif interactive:\n window.show(scene, size=(600, 600), reset_camera=False)\n\nwindow.record(scene, out_path='bundle5.png', size=(600, 600))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Show every point of every streamline with a different color\n\nIn this case in which we want to have a color per point and per streamline,\nwe can create a list of the colors to correspond to the list of streamlines\n(bundles). Here in ``colors`` we will insert some random RGB colors.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "scene.clear()\n\ncolors = [np.random.rand(*streamline.shape) for streamline in bundle_native]\n\nstream_actor6 = actor.line(bundle_native, np.vstack(colors), linewidth=0.2)\n\nscene.add(stream_actor6)\n\nif interactive:\n window.show(scene, size=(600, 600), reset_camera=False)\n\nwindow.record(scene, out_path='bundle6.png', size=(600, 600))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Add depth cues to streamline rendering\n\nBy default, lines are drawn with the same width on the screen, regardless of\ntheir distance from the camera. To increase realism, we can enable\n``depth_cue`` to make the lines shrink with distance from the camera. We\nwill return to the default color scheme from the first example. Note that\n``depth_cue`` works best for ``linewidth`` <= 1.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "scene.clear()\n\nstream_actor7 = actor.line(bundle_native, linewidth=0.5, depth_cue=True)\n\nscene.add(stream_actor7)\n\nif interactive:\n window.show(scene, size=(600, 600), reset_camera=False)\n\nwindow.record(scene, out_path='bundle7.png', size=(600, 600))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Render streamlines as fake tubes\n\nWe can simulate the look of streamtubes by adding shading to streamlines with\n``fake_tube``. Note that ``fake_tube`` requires ``linewidth`` > 1.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "scene.clear()\n\nstream_actor8 = actor.line(bundle_native, linewidth=3, fake_tube=True)\n\nscene.add(stream_actor8)\n\nif interactive:\n window.show(scene, size=(600, 600), reset_camera=False)\n\nwindow.record(scene, out_path='bundle8.png', size=(600, 600))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Combine depth cues with fake tubes\n\nIt is possible to fully simulate streamtubes by enabling both ``depth_cue``\nand ``fake_tube``. However, it can be challenging to choose a ``linewidth``\nthat demonstrates both techniques well.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "scene.clear()\n\nstream_actor9 = actor.line(bundle_native, linewidth=3, depth_cue=True, fake_tube=True)\n\nscene.add(stream_actor9)\n\nif interactive:\n window.show(scene, size=(600, 600), reset_camera=False)\n\nwindow.record(scene, out_path='bundle9.png', size=(600, 600))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Render streamlines as tubes\n\nFor yet more realism, we can use ``streamtube``. Note that this actor\ngenerates much more geometry than ``line``, so it is more computationally\nexpensive. For large datasets, it may be better to approximate tubes using\nthe methods described above.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "scene.clear()\n\nstream_actor10 = actor.streamtube(bundle_native, linewidth=0.5)\n\nscene.add(stream_actor10)\n\nif interactive:\n window.show(scene, size=(600, 600), reset_camera=False)\n\nwindow.record(scene, out_path='bundle10.png', size=(600, 600))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In summary, we showed that there are many useful ways for visualizing maps\non bundles.\n\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.8" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/v0.10.x/_downloads/e999b22bbd0e40cb805df5bd6e5d97dd/viz_earth_animation.py b/v0.10.x/_downloads/e999b22bbd0e40cb805df5bd6e5d97dd/viz_earth_animation.py new file mode 100644 index 000000000..38cd7f286 --- /dev/null +++ b/v0.10.x/_downloads/e999b22bbd0e40cb805df5bd6e5d97dd/viz_earth_animation.py @@ -0,0 +1,175 @@ +""" +========================= +Texture Sphere Animation +========================= +In this tutorial, we will show how to animate a textured sphere. +""" + +import itertools + +import numpy as np + +from fury import actor, io, utils, window +from fury.data import ( + fetch_viz_models, + fetch_viz_textures, + read_viz_models, + read_viz_textures, +) + +############################################################################## +# Create a scene to start. + +scene = window.Scene() + +############################################################################## +# Next, load in a texture for each of the actors. For this tutorial, we will +# be creating one textured sphere for the Earth, and another for the moon. +# Collect the Earth texture from the FURY github using ``fetch_viz_textures`` +# and ``read_viz_textures``, then use ``io.load_image`` to load in the +# image. + +fetch_viz_textures() +earth_filename = read_viz_textures('1_earth_8k.jpg') +earth_image = io.load_image(earth_filename) + +############################################################################## +# Using ``actor.texture_on_sphere()``, create an earth_actor with your newly +# loaded texture. + +earth_actor = actor.texture_on_sphere(earth_image) + +############################################################################## +# Then, do the same for the moon. + +moon_filename = read_viz_textures('moon-8k.jpg') +moon_image = io.load_image(moon_filename) + +moon_actor = actor.texture_on_sphere(moon_image) + +############################################################################## +# Add both actors to the already existing scene. + +scene.add(earth_actor) +scene.add(moon_actor) + +############################################################################## +# Next, alter the position and scale of the moon to correctly size it in +# comparison to the Earth using ``actor.SetPosition()`` and +# ``actor.SetScale()``, and rotate the Earth using ``utils.rotate`` to +# correctly align the texture. + +moon_actor.SetPosition(1, 0.1, 0.5) +moon_actor.SetScale(0.25, 0.25, 0.25) +utils.rotate(earth_actor, (-90, 1, 0, 0)) + +############################################################################## +# The ShowManager class is the interface between the scene, the window and the +# interactor. + +showm = window.ShowManager( + scene, size=(900, 768), reset_camera=False, order_transparent=True +) + +############################################################################## +# Next, let's focus on creating the animation. +# We can determine the duration of animation with using the ``counter``. +# Use itertools to avoid global variables. + +counter = itertools.count() + +############################################################################## +# Use ``set_camera`` to ensure the camera is in the optimal position for the +# scene. + +scene.set_camera( + position=(0.24, 0.00, 4.34), + focal_point=(0.00, 0.00, 0.00), + view_up=(0.00, 1.00, 0.00), +) + +############################################################################## +# Let's create a sphere actor to add to the Earth. We will place this sphere +# on the Earth's surface on Bloomington, IN, home of FURY's headquarters! + +center = np.array([[-0.39, 0.3175, 0.025]]) +radius = 0.002 +sphere_actor = actor.sphere(center, window.colors.blue_medium, radius) + +############################################################################## +# Also creating a text actor to add below the sphere. + +text_actor = actor.text_3d( + 'Bloomington, Indiana', (-0.42, 0.31, 0.03), window.colors.white, 0.004 +) +utils.rotate(text_actor, (-90, 0, 1, 0)) + +############################################################################## +# Let's also import a model of a satellite to visualize circling the moon. + +fetch_viz_models() +satellite_filename = read_viz_models('satellite_obj.obj') +satellite = io.load_polydata(satellite_filename) +satellite_actor = utils.get_actor_from_polydata(satellite) + +satellite_actor.SetPosition(-0.75, 0.1, 0.4) +satellite_actor.SetScale(0.005, 0.005, 0.005) + + +############################################################################## +# In the ``timer_callback`` function, use if statements to specify when +# certain events will happen in the animation, based on the position that +# the counter is at. So, for example, the earth actor will continue to +# rotate while the count is less than 450. + + +def timer_callback(_obj, _event): + cnt = next(counter) + showm.render() + if cnt < 450: + utils.rotate(earth_actor, (1, 0, 1, 0)) + if cnt % 5 == 0 and cnt < 450: + showm.scene.azimuth(-1) + if cnt == 300: + scene.set_camera( + position=(-3.679, 0.00, 2.314), + focal_point=(0.0, 0.35, 0.00), + view_up=(0.00, 1.00, 0.00), + ) + if cnt > 300 and cnt < 450: + scene.zoom(1.01) + if cnt >= 450 and cnt < 1500: + scene.add(sphere_actor) + scene.add(text_actor) + if cnt >= 450 and cnt < 550: + scene.zoom(1.01) + if cnt == 575: + moon_actor.SetPosition(-1, 0.1, 0.5) + scene.set_camera( + position=(-0.5, 0.1, 0.00), + focal_point=(-1, 0.1, 0.5), + view_up=(0.00, 1.00, 0.00), + ) + scene.zoom(0.03) + scene.add(satellite_actor) + utils.rotate(satellite_actor, (180, 0, 1, 0)) + scene.rm(earth_actor) + if cnt > 575 and cnt < 750: + showm.scene.azimuth(-2) + utils.rotate(moon_actor, (-2, 0, 1, 0)) + satellite_actor.SetPosition(-0.8, 0.1 - cnt / 10000, 0.4) + if cnt >= 750 and cnt < 1100: + showm.scene.azimuth(-2) + utils.rotate(moon_actor, (-2, 0, 1, 0)) + satellite_actor.SetPosition(-0.8, -0.07 + cnt / 10000, 0.4) + if cnt == 1100: + showm.exit() + + +############################################################################## +# Watch your new animation take place! + + +showm.add_timer_callback(True, 35, timer_callback) +showm.start() +window.record(showm.scene, size=(900, 768), out_path='viz_earth_animation.png') diff --git a/v0.10.x/_downloads/ea42b6e1d50eac5b2d3d01d0757008ef/viz_pbr_interactive.py b/v0.10.x/_downloads/ea42b6e1d50eac5b2d3d01d0757008ef/viz_pbr_interactive.py new file mode 100644 index 000000000..2bee8e0e7 --- /dev/null +++ b/v0.10.x/_downloads/ea42b6e1d50eac5b2d3d01d0757008ef/viz_pbr_interactive.py @@ -0,0 +1,346 @@ +""" +=============================================== +Interactive PBR demo +=============================================== + +This is a demonstration of how Physically-Based Rendering (PBR) can be used to +simulate different materials. + +Let's start by importing the necessary modules: +""" + +from fury import actor, material, ui, window +from fury.data import fetch_viz_cubemaps, read_viz_cubemap +from fury.io import load_cubemap_texture +from fury.utils import ( + normals_from_actor, + tangents_from_direction_of_anisotropy, + tangents_to_actor, +) + +############################################################################### +# The following functions will help us to manage the sliders events. + + +def change_slice_metallic(slider): + global pbr_params + pbr_params.metallic = slider.value + + +def change_slice_roughness(slider): + global pbr_params + pbr_params.roughness = slider.value + + +def change_slice_anisotropy(slider): + global pbr_params + pbr_params.anisotropy = slider.value + + +def change_slice_anisotropy_direction_x(slider): + global doa, normals, sphere + doa[0] = slider.value + tangents = tangents_from_direction_of_anisotropy(normals, doa) + tangents_to_actor(sphere, tangents) + + +def change_slice_anisotropy_direction_y(slider): + global doa, normals, sphere + doa[1] = slider.value + tangents = tangents_from_direction_of_anisotropy(normals, doa) + tangents_to_actor(sphere, tangents) + + +def change_slice_anisotropy_direction_z(slider): + global doa, normals, sphere + doa[2] = slider.value + tangents = tangents_from_direction_of_anisotropy(normals, doa) + tangents_to_actor(sphere, tangents) + + +def change_slice_anisotropy_rotation(slider): + global pbr_params + pbr_params.anisotropy_rotation = slider.value + + +def change_slice_coat_strength(slider): + global pbr_params + pbr_params.coat_strength = slider.value + + +def change_slice_coat_roughness(slider): + global pbr_params + pbr_params.coat_roughness = slider.value + + +def change_slice_base_ior(slider): + global pbr_params + pbr_params.base_ior = slider.value + + +def change_slice_coat_ior(slider): + global pbr_params + pbr_params.coat_ior = slider.value + + +############################################################################### +# Last, but not least, we define the following function to help us to +# reposition the UI elements every time we resize the window. + + +def win_callback(obj, event): + global control_panel, size + if size != obj.GetSize(): + size_old = size + size = obj.GetSize() + size_change = [size[0] - size_old[0], 0] + control_panel.re_align(size_change) + + +############################################################################### +# Let's fetch a skybox texture from the FURY data repository. + +fetch_viz_cubemaps() + +############################################################################### +# The following function returns the full path of the 6 images composing the +# skybox. + +textures = read_viz_cubemap('skybox') + +############################################################################### +# Now that we have the location of the textures, let's load them and create a +# Cube Map Texture object. + +cubemap = load_cubemap_texture(textures) + +############################################################################### +# The Scene object in FURY can handle cube map textures and extract light +# information from them, so it can be used to create more plausible materials +# interactions. The ``skybox`` parameter takes as input a cube map texture and +# performs the previously described process. + +scene = window.Scene(skybox=cubemap) + +############################################################################### +# With the scene created, we can then populate it. In this demo we will only +# add a sphere actor. + +sphere = actor.sphere([[0, 0, 0]], (0.7, 0.7, 0.7), radii=2, theta=64, phi=64) + +############################################################################### +# The direction of anisotropy (DoA) defines the direction at which all the +# tangents of our actor are pointing. + +doa = [0, 1, 0.5] + +############################################################################### +# The following process gets the normals of the actor and computes the tangents +# that are aligned to the provided DoA. Then it registers those tangents to the +# actor. + +normals = normals_from_actor(sphere) +tangents = tangents_from_direction_of_anisotropy(normals, doa) +tangents_to_actor(sphere, tangents) + +############################################################################### +# With the tangents computed and in place, we have all the elements needed to +# add some material properties to the actor. + +pbr_params = material.manifest_pbr(sphere) + +############################################################################### +# Our actor is now ready to be added to the scene. + +scene.add(sphere) + +############################################################################### +# Let's setup now the window and the UI. + +show_m = window.ShowManager( + scene=scene, size=(1920, 1080), reset_camera=False, order_transparent=True +) + + +############################################################################### +# We will create one single panel with all of our labels and sliders. + +control_panel = ui.Panel2D( + (400, 500), position=(5, 5), color=(0.25, 0.25, 0.25), opacity=0.75, align='right' +) + +############################################################################### +# By using our previously defined function, we can easily create all the labels +# we need for this demo. And then add them to the panel. + +slider_label_metallic = ui.TextBlock2D(text='Metallic', font_size=16) +slider_label_roughness = ui.TextBlock2D(text='Roughness', font_size=16) +slider_label_anisotropy = ui.TextBlock2D(text='Anisotropy', font_size=16) +slider_label_anisotropy_rotation = ui.TextBlock2D( + text='Anisotropy Rotation', font_size=16 +) +slider_label_anisotropy_direction_x = ui.TextBlock2D( + text='Anisotropy Direction X', font_size=16 +) +slider_label_anisotropy_direction_y = ui.TextBlock2D( + text='Anisotropy Direction Y', font_size=16 +) +slider_label_anisotropy_direction_z = ui.TextBlock2D( + text='Anisotropy Direction Z', font_size=16 +) +slider_label_coat_strength = ui.TextBlock2D(text='Coat Strength', font_size=16) +slider_label_coat_roughness = ui.TextBlock2D(text='Coat Roughness', font_size=16) +slider_label_base_ior = ui.TextBlock2D(text='Base IoR', font_size=16) +slider_label_coat_ior = ui.TextBlock2D(text='Coat IoR', font_size=16) + +control_panel.add_element(slider_label_metallic, (0.01, 0.95)) +control_panel.add_element(slider_label_roughness, (0.01, 0.86)) +control_panel.add_element(slider_label_anisotropy, (0.01, 0.77)) +control_panel.add_element(slider_label_anisotropy_rotation, (0.01, 0.68)) +control_panel.add_element(slider_label_anisotropy_direction_x, (0.01, 0.59)) +control_panel.add_element(slider_label_anisotropy_direction_y, (0.01, 0.5)) +control_panel.add_element(slider_label_anisotropy_direction_z, (0.01, 0.41)) +control_panel.add_element(slider_label_coat_strength, (0.01, 0.32)) +control_panel.add_element(slider_label_coat_roughness, (0.01, 0.23)) +control_panel.add_element(slider_label_base_ior, (0.01, 0.14)) +control_panel.add_element(slider_label_coat_ior, (0.01, 0.05)) + +############################################################################### +# Our sliders are created and added to the panel in the following way. + +slider_slice_metallic = ui.LineSlider2D( + initial_value=pbr_params.metallic, + max_value=1, + length=195, + text_template='{value:.1f}', +) +slider_slice_roughness = ui.LineSlider2D( + initial_value=pbr_params.roughness, + max_value=1, + length=195, + text_template='{value:.1f}', +) +slider_slice_anisotropy = ui.LineSlider2D( + initial_value=pbr_params.anisotropy, + max_value=1, + length=195, + text_template='{value:.1f}', +) +slider_slice_anisotropy_rotation = ui.LineSlider2D( + initial_value=pbr_params.anisotropy_rotation, + max_value=1, + length=195, + text_template='{value:.1f}', +) +slider_slice_coat_strength = ui.LineSlider2D( + initial_value=pbr_params.coat_strength, + max_value=1, + length=195, + text_template='{value:.1f}', +) +slider_slice_coat_roughness = ui.LineSlider2D( + initial_value=pbr_params.coat_roughness, + max_value=1, + length=195, + text_template='{value:.1f}', +) + +############################################################################### +# Notice that we are defining a range of [-1, 1] for the DoA. This is because +# within that range we cover all the possible 3D directions needed to align the +# tangents. + +slider_slice_anisotropy_direction_x = ui.LineSlider2D( + initial_value=doa[0], + min_value=-1, + max_value=1, + length=195, + text_template='{value:.1f}', +) +slider_slice_anisotropy_direction_y = ui.LineSlider2D( + initial_value=doa[1], + min_value=-1, + max_value=1, + length=195, + text_template='{value:.1f}', +) +slider_slice_anisotropy_direction_z = ui.LineSlider2D( + initial_value=doa[2], + min_value=-1, + max_value=1, + length=195, + text_template='{value:.1f}', +) + +############################################################################### +# Another special case are the Index of Refraction (IoR) sliders. In these +# cases, the values are defined in the range [1, 2.3] according to the +# documentation of the material. + +slider_slice_base_ior = ui.LineSlider2D( + initial_value=pbr_params.base_ior, + min_value=1, + max_value=2.3, + length=195, + text_template='{value:.02f}', +) +slider_slice_coat_ior = ui.LineSlider2D( + initial_value=pbr_params.coat_ior, + min_value=1, + max_value=2.3, + length=195, + text_template='{value:.02f}', +) + +############################################################################### +# Let's add the event handlers functions to the corresponding sliders. + +slider_slice_metallic.on_change = change_slice_metallic +slider_slice_roughness.on_change = change_slice_roughness +slider_slice_anisotropy.on_change = change_slice_anisotropy +slider_slice_anisotropy_rotation.on_change = change_slice_anisotropy_rotation +slider_slice_anisotropy_direction_x.on_change = change_slice_anisotropy_direction_x +slider_slice_anisotropy_direction_y.on_change = change_slice_anisotropy_direction_y +slider_slice_anisotropy_direction_z.on_change = change_slice_anisotropy_direction_z +slider_slice_coat_strength.on_change = change_slice_coat_strength +slider_slice_coat_roughness.on_change = change_slice_coat_roughness +slider_slice_base_ior.on_change = change_slice_base_ior +slider_slice_coat_ior.on_change = change_slice_coat_ior + +############################################################################### +# And then add the sliders to the panel. + +control_panel.add_element(slider_slice_metallic, (0.44, 0.95)) +control_panel.add_element(slider_slice_roughness, (0.44, 0.86)) +control_panel.add_element(slider_slice_anisotropy, (0.44, 0.77)) +control_panel.add_element(slider_slice_anisotropy_rotation, (0.44, 0.68)) +control_panel.add_element(slider_slice_anisotropy_direction_x, (0.44, 0.59)) +control_panel.add_element(slider_slice_anisotropy_direction_y, (0.44, 0.5)) +control_panel.add_element(slider_slice_anisotropy_direction_z, (0.44, 0.41)) +control_panel.add_element(slider_slice_coat_strength, (0.44, 0.32)) +control_panel.add_element(slider_slice_coat_roughness, (0.44, 0.23)) +control_panel.add_element(slider_slice_base_ior, (0.44, 0.14)) +control_panel.add_element(slider_slice_coat_ior, (0.44, 0.05)) + +############################################################################### +# Consequently, we add the panel to the scene. + +scene.add(control_panel) + +############################################################################### +# Previously we defined a function to help us when we resize the window, so +# let's capture the current size and add our helper function as a +# `window_callback` to the window. + +size = scene.GetSize() + +show_m.add_window_callback(win_callback) + +############################################################################### +# Finally, let's visualize our demo. + +interactive = False +if interactive: + show_m.start() + +window.record(scene, size=(1920, 1080), out_path='viz_pbr_interactive.png') diff --git a/v0.10.x/_downloads/ec52deca8981326834fd5f59a66090bb/viz_advanced.py b/v0.10.x/_downloads/ec52deca8981326834fd5f59a66090bb/viz_advanced.py new file mode 100644 index 000000000..2b8ff92fd --- /dev/null +++ b/v0.10.x/_downloads/ec52deca8981326834fd5f59a66090bb/viz_advanced.py @@ -0,0 +1,276 @@ +""" +================================== +Advanced interactive visualization +================================== + +In DIPY we created a thin interface to access many of the capabilities +available in the Visualization Toolkit framework (VTK) but tailored to the +needs of structural and diffusion imaging. Initially the 3D visualization +module was named ``fvtk``, meaning functions using vtk. This is still available +for backwards compatibility but now there is a more comprehensive way to access +the main functions using the following modules. +""" + +import numpy as np +from dipy.data.fetcher import fetch_bundles_2_subjects, read_bundles_2_subjects + +############################################################################### +# In ``window`` we have all the objects that connect what needs to be rendered +# to the display or the disk e.g., for saving screenshots. So, there you will +# find key objects and functions like the ``Scene`` class which holds and +# provides access to all the actors and the ``show`` function which displays +# what is in the scene on a window. Also, this module provides access to +# functions for opening/saving dialogs and printing screenshots +# (see ``snapshot``). +# +# In the ``actor`` module we can find all the different primitives e.g., +# streamtubes, lines, image slices, etc. +# +# In the ``ui`` module we have some other objects which allow to add buttons +# and sliders and these interact both with windows and actors. Because of this +# they need input from the operating system so they can process events. +# +# Let's get started. In this tutorial, we will visualize some bundles +# together with FA or T1. We will be able to change the slices using +# a ``LineSlider2D`` widget. +# +# First we need to fetch and load some datasets. +from dipy.tracking.streamline import Streamlines + +from fury import actor, ui, window + +fetch_bundles_2_subjects() + +############################################################################### +# The following function outputs a dictionary with the required bundles e.g. +# ``af left`` (left arcuate fasciculus) and maps, e.g. FA for a specific +# subject. + +res = read_bundles_2_subjects('subj_1', ['t1', 'fa'], ['af.left', 'cst.right', 'cc_1']) + +############################################################################### +# We will use 3 bundles, FA and the affine transformation that brings the voxel +# coordinates to world coordinates (RAS 1mm). + +streamlines = Streamlines(res['af.left']) +streamlines.extend(res['cst.right']) +streamlines.extend(res['cc_1']) + +data = res['fa'] +shape = data.shape +affine = res['affine'] + +############################################################################### +# With our current design it is easy to decide in which space you want the +# streamlines and slices to appear. The default we have here is to appear in +# world coordinates (RAS 1mm). + +world_coords = True + +############################################################################### +# If we want to see the objects in native space we need to make sure that all +# objects which are currently in world coordinates are transformed back to +# native space using the inverse of the affine. + + +if not world_coords: + from dipy.tracking.streamline import transform_streamlines + + streamlines = transform_streamlines(streamlines, np.linalg.inv(affine)) + +############################################################################### +# Now we create, a ``Scene`` object and add the streamlines using the +# ``line`` function and an image plane using the ``slice`` function. + +scene = window.Scene() +stream_actor = actor.line(streamlines) + +if not world_coords: + image_actor_z = actor.slicer(data, affine=np.eye(4)) +else: + image_actor_z = actor.slicer(data, affine) + +############################################################################### +# We can also change also the opacity of the slicer. + +slicer_opacity = 0.6 +image_actor_z.opacity(slicer_opacity) + +############################################################################### +# We can add additional slicers by copying the original and adjusting the +# ``display_extent``. + +image_actor_x = image_actor_z.copy() +x_midpoint = int(np.round(shape[0] / 2)) +image_actor_x.display_extent(x_midpoint, x_midpoint, 0, shape[1] - 1, 0, shape[2] - 1) + +image_actor_y = image_actor_z.copy() +y_midpoint = int(np.round(shape[1] / 2)) +image_actor_y.display_extent(0, shape[0] - 1, y_midpoint, y_midpoint, 0, shape[2] - 1) + +############################################################################### +# Connect the actors with the Scene. + +scene.add(stream_actor) +scene.add(image_actor_z) +scene.add(image_actor_x) +scene.add(image_actor_y) + +############################################################################### +# Now we would like to change the position of each ``image_actor`` using a +# slider. The sliders are widgets which require access to different areas of +# the visualization pipeline and therefore we don't recommend using them with +# ``show``. The more appropriate way is to use them with the ``ShowManager`` +# object which allows accessing the pipeline in different areas. Here is how: + +show_m = window.ShowManager(scene, size=(1200, 900)) + + +############################################################################### +# After we have initialized the ``ShowManager`` we can go ahead and create +# sliders to move the slices and change their opacity. + +line_slider_z = ui.LineSlider2D( + min_value=0, + max_value=shape[2] - 1, + initial_value=shape[2] / 2, + text_template='{value:.0f}', + length=140, +) + +line_slider_x = ui.LineSlider2D( + min_value=0, + max_value=shape[0] - 1, + initial_value=shape[0] / 2, + text_template='{value:.0f}', + length=140, +) + +line_slider_y = ui.LineSlider2D( + min_value=0, + max_value=shape[1] - 1, + initial_value=shape[1] / 2, + text_template='{value:.0f}', + length=140, +) + +opacity_slider = ui.LineSlider2D( + min_value=0.0, max_value=1.0, initial_value=slicer_opacity, length=140 +) + +############################################################################### +# Now we will write callbacks for the sliders and register them. + + +def change_slice_z(slider): + z = int(np.round(slider.value)) + image_actor_z.display_extent(0, shape[0] - 1, 0, shape[1] - 1, z, z) + + +def change_slice_x(slider): + x = int(np.round(slider.value)) + image_actor_x.display_extent(x, x, 0, shape[1] - 1, 0, shape[2] - 1) + + +def change_slice_y(slider): + y = int(np.round(slider.value)) + image_actor_y.display_extent(0, shape[0] - 1, y, y, 0, shape[2] - 1) + + +def change_opacity(slider): + slicer_opacity = slider.value + image_actor_z.opacity(slicer_opacity) + image_actor_x.opacity(slicer_opacity) + image_actor_y.opacity(slicer_opacity) + + +line_slider_z.on_change = change_slice_z +line_slider_x.on_change = change_slice_x +line_slider_y.on_change = change_slice_y +opacity_slider.on_change = change_opacity + +############################################################################### +# We'll also create text labels to identify the sliders. + + +def build_label(text): + label = ui.TextBlock2D() + label.message = text + label.font_size = 18 + label.font_family = 'Arial' + label.justification = 'left' + label.bold = False + label.italic = False + label.shadow = False + label.background_color = (0, 0, 0) + label.color = (1, 1, 1) + + return label + + +line_slider_label_z = build_label(text='Z Slice') +line_slider_label_x = build_label(text='X Slice') +line_slider_label_y = build_label(text='Y Slice') +opacity_slider_label = build_label(text='Opacity') + +############################################################################### +# Now we will create a ``panel`` to contain the sliders and labels. + +panel = ui.Panel2D(size=(300, 200), color=(1, 1, 1), opacity=0.1, align='right') +panel.center = (1030, 120) + +panel.add_element(line_slider_label_x, (0.1, 0.75)) +panel.add_element(line_slider_x, (0.38, 0.75)) +panel.add_element(line_slider_label_y, (0.1, 0.55)) +panel.add_element(line_slider_y, (0.38, 0.55)) +panel.add_element(line_slider_label_z, (0.1, 0.35)) +panel.add_element(line_slider_z, (0.38, 0.35)) +panel.add_element(opacity_slider_label, (0.1, 0.15)) +panel.add_element(opacity_slider, (0.38, 0.15)) + +show_m.scene.add(panel) + +############################################################################### +# Then, we can render all the widgets and everything else in the screen and +# start the interaction using ``show_m.start()``. +# +# +# However, if you change the window size, the panel will not update its +# position properly. The solution to this issue is to update the position of +# the panel using its ``re_align`` method every time the window size changes. + + +size = scene.GetSize() + + +def win_callback(obj, _event): + global size + if size != obj.GetSize(): + size_old = size + size = obj.GetSize() + size_change = [size[0] - size_old[0], 0] + panel.re_align(size_change) + + +############################################################################### +# Finally, please set the following variable to ``True`` to interact with the +# datasets in 3D. + +interactive = False + +scene.zoom(1.5) +scene.reset_clipping_range() + +if interactive: + + show_m.add_window_callback(win_callback) + show_m.render() + show_m.start() + +else: + + window.record( + scene, out_path='bundles_and_3_slices.png', size=(1200, 900), reset_camera=False + ) + +del show_m diff --git a/v0.10.x/_downloads/ec724f11972569a9f66d96083989ac90/viz_cone.ipynb b/v0.10.x/_downloads/ec724f11972569a9f66d96083989ac90/viz_cone.ipynb new file mode 100644 index 000000000..6012e0798 --- /dev/null +++ b/v0.10.x/_downloads/ec724f11972569a9f66d96083989ac90/viz_cone.ipynb @@ -0,0 +1,115 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Fury Cone Actor\nThis example shows how to use the cone actor.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "import numpy as np\n\nfrom fury import actor, window" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "First thing, you have to specify centers, directions, and colors of the cone\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "centers = np.zeros([3, 3])\ndirs = np.identity(3)\ncolors = np.identity(3)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The below cone actor is generated by repeating the cone primitive.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "cone_actor1 = actor.cone(centers, dirs, colors=colors, heights=1.5)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "repeating what we did but this time with random directions, and colors\nHere, we're using vtkConeSource to generate the cone actor\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "cen2 = np.add(centers, np.array([3, 0, 0]))\ndir2 = np.random.rand(5, 3)\ncols2 = np.random.rand(5, 3)\n\ncone_actor2 = actor.cone(cen2, dir2, colors=cols2, heights=1.5, use_primitive=False)\n\nscene = window.Scene()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Adding our cone actors to scene.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "scene.add(cone_actor1)\nscene.add(cone_actor2)\n\ninteractive = False\n\nif interactive:\n window.show(scene, size=(600, 600))\n\nwindow.record(scene, out_path='viz_cone.png', size=(600, 600))" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.8" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/v0.10.x/_downloads/ed25feb190d28892577f2b94ad0ba829/viz_pbr_spheres.ipynb b/v0.10.x/_downloads/ed25feb190d28892577f2b94ad0ba829/viz_pbr_spheres.ipynb new file mode 100644 index 000000000..6dab533d9 --- /dev/null +++ b/v0.10.x/_downloads/ed25feb190d28892577f2b94ad0ba829/viz_pbr_spheres.ipynb @@ -0,0 +1,169 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Physically-Based Rendering (PBR) on spheres\n\nPBR engines aim to simulate properties of light when it interacts with objects\nin the scene in a physically plausible way. The interaction of light with an\nobject depends on the material the object is made of. In computer graphics,\nmaterials are usually divided in 2 main categories based on their conductive\nproperties: dielectrics and metals.\n\nThis tutorial, illustrates how to model some material properties in FURY by\nusing the PBR material.\n\nLet's start by importing the necessary modules:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "import numpy as np\n\nfrom fury import actor, material, window\nfrom fury.utils import (\n normals_from_actor,\n tangents_from_direction_of_anisotropy,\n tangents_to_actor,\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now set up a new scene.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "scene = window.Scene()\nscene.background((0.9, 0.9, 0.9))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's define the parameters we are going to showcase in this tutorial.\nThese subset of parameters have their values constrained in the 0 to 1 range.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "material_params = [\n [[1, 1, 0], {'metallic': 0, 'roughness': 0}],\n [(0, 0, 1), {'roughness': 0}],\n [(1, 0, 1), {'anisotropy': 0, 'metallic': 0.25, 'roughness': 0.5}],\n [\n (1, 0, 1),\n {'anisotropy_rotation': 0, 'anisotropy': 1, 'metallic': 0.25, 'roughness': 0.5},\n ],\n [(0, 1, 1), {'coat_strength': 0, 'roughness': 0}],\n [(0, 1, 1), {'coat_roughness': 0, 'coat_strength': 1, 'roughness': 0}],\n]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we can start to add our actors to the scene and see how different values\nof the parameters produce interesting effects. For the purpose of this\ntutorial, we will see the effect of 11 different values of each parameter.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "num_values = 11\n\nfor i, mp in enumerate(material_params):\n color = mp[0]\n params = mp[1]\n center = [[0, -5 * i, 0]]\n for j in range(num_values):\n center[0][0] = -25 + 5 * j\n sphere = actor.sphere(center, color, radii=2, theta=32, phi=32)\n normals = normals_from_actor(sphere)\n tangents = tangents_from_direction_of_anisotropy(normals, (0, 1, 0.5))\n tangents_to_actor(sphere, tangents)\n keys = list(params)\n params[keys[0]] = np.round(0.1 * j, decimals=1)\n material.manifest_pbr(sphere, **params)\n scene.add(sphere)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "For interpretability purposes we will add some labels to guide us through our\nvisualization.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "labels = [\n 'Metallic',\n 'Roughness',\n 'Anisotropy',\n 'Anisotropy Rotation',\n 'Coat Strength',\n 'Coat Roughness',\n]\n\nfor i, l in enumerate(labels):\n pos = [-40, -5 * i, 0]\n label = actor.vector_text(l, pos=pos, scale=(0.8, 0.8, 0.8), color=(0, 0, 0))\n scene.add(label)\n\nfor j in range(num_values):\n pos = [-26 + 5 * j, 3, 0]\n label = actor.vector_text(\n str(np.round(j * 0.1, decimals=1)),\n pos=pos,\n scale=(0.8, 0.8, 0.8),\n color=(0, 0, 0),\n )\n scene.add(label)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Some parameters of this material have their values constrained to be between\n1 and 2.3. These parameters are the Base Index of Refraction (IOR) and the\nClear coat Index of Refraction (IOR). Therefore, we will interpolate some\nvalues within this range and see how they affect the rendering.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "iors = np.round(np.linspace(1, 2.3, num=num_values), decimals=2)\n\nior_params = [\n [(0, 1, 1), {'base_ior': iors[0], 'roughness': 0}],\n [\n (0, 1, 1),\n {\n 'coat_ior': iors[0],\n 'coat_roughness': 0.1,\n 'coat_strength': 1,\n 'roughness': 0,\n },\n ],\n]\n\nfor i, iorp in enumerate(ior_params):\n color = iorp[0]\n params = iorp[1]\n center = [[0, -35 - (5 * i), 0]]\n for j in range(num_values):\n center[0][0] = -25 + 5 * j\n sphere = actor.sphere(center, color, radii=2, theta=32, phi=32)\n keys = list(params)\n params[keys[0]] = iors[j]\n material.manifest_pbr(sphere, **params)\n scene.add(sphere)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's add the respective labels to the scene.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "labels = ['Base IoR', 'Coat IoR']\n\nfor i, l in enumerate(labels):\n pos = [-40, -35 - (5 * i), 0]\n label = actor.vector_text(l, pos=pos, scale=(0.8, 0.8, 0.8), color=(0, 0, 0))\n scene.add(label)\n\nfor j in range(num_values):\n pos = [-26 + 5 * j, -32, 0]\n label = actor.vector_text(\n '{:.02f}'.format(iors[j]), pos=pos, scale=(0.8, 0.8, 0.8), color=(0, 0, 0)\n )\n scene.add(label)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Finally, let's visualize our tutorial.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "interactive = False\nif interactive:\n window.show(scene)\n\nwindow.record(scene, size=(600, 600), out_path='viz_pbr_spheres.png')" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.8" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/v0.10.x/_downloads/ed99262b8dc9297dcfb48d0a134bec54/viz_network.ipynb b/v0.10.x/_downloads/ed99262b8dc9297dcfb48d0a134bec54/viz_network.ipynb new file mode 100644 index 000000000..9c9d5e6b1 --- /dev/null +++ b/v0.10.x/_downloads/ed99262b8dc9297dcfb48d0a134bec54/viz_network.ipynb @@ -0,0 +1,201 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Visualize Interdisciplinary map of the journals network\n\nThe goal of this app is to show an overview of the journals network structure\nas a complex network. Each journal is shown as a node and their connections\nindicates a citation between two of them.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "First, let's import some useful functions\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "from os.path import join as pjoin\n\nimport numpy as np\n\nfrom fury import actor\nfrom fury import colormap as cmap\nfrom fury import window\nfrom fury.data import fetch_viz_wiki_nw" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Then let's download some available datasets.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "files, folder = fetch_viz_wiki_nw()\ncategories_file, edges_file, positions_file = sorted(files.keys())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We read our datasets\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "positions = np.loadtxt(pjoin(folder, positions_file))\ncategories = np.loadtxt(pjoin(folder, categories_file), dtype=str)\nedges = np.loadtxt(pjoin(folder, edges_file), dtype=int)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We attribute a color to each category of our dataset which correspond to our\nnodes colors.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "category2index = {category: i for i, category in enumerate(np.unique(categories))}\n\nindex2category = np.unique(categories)\n\ncategoryColors = cmap.distinguishable_colormap(nb_colors=len(index2category))\n\ncolors = np.array([categoryColors[category2index[category]] for category in categories])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We define our node size\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "radii = 1 + np.random.rand(len(positions))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Lets create our edges now. They will indicate a citation between two nodes.\nOF course, the colors of each edges will be an interpolation between the two\nnode that it connects.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "edgesPositions = []\nedgesColors = []\nfor source, target in edges:\n edgesPositions.append(np.array([positions[source], positions[target]]))\n edgesColors.append(np.array([colors[source], colors[target]]))\n\nedgesPositions = np.array(edgesPositions)\nedgesColors = np.average(np.array(edgesColors), axis=1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Our data preparation is ready, it is time to visualize them all. We start to\nbuild 2 actors that we represent our data : sphere_actor for the nodes and\nlines_actor for the edges.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "sphere_actor = actor.sphere(\n centers=positions,\n colors=colors,\n radii=radii * 0.5,\n theta=8,\n phi=8,\n)\n\nlines_actor = actor.line(\n edgesPositions,\n colors=edgesColors,\n opacity=0.1,\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "All actors need to be added in a scene, so we build one and add our\nlines_actor and sphere_actor.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "scene = window.Scene()\n\nscene.add(lines_actor)\nscene.add(sphere_actor)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The final step ! Visualize and save the result of our creation! Please,\nswitch interactive variable to True if you want to visualize it.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "interactive = False\n\nif interactive:\n window.show(scene, size=(600, 600))\n\nwindow.record(scene, out_path='journal_networks.png', size=(600, 600))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This example can be improved by adding some interactivy with slider,\npicking, etc. Play with it, improve it!\n\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.8" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/v0.10.x/_downloads/edb95e013adc4d6a38a4673686c7cfc1/viz_shader.py b/v0.10.x/_downloads/edb95e013adc4d6a38a4673686c7cfc1/viz_shader.py new file mode 100644 index 000000000..2c7feab13 --- /dev/null +++ b/v0.10.x/_downloads/edb95e013adc4d6a38a4673686c7cfc1/viz_shader.py @@ -0,0 +1,127 @@ +# -*- coding: utf-8 -*- +""" +============= +Varying Color +============= + +This example shows how to use shaders to generate a shaded output. We will +demonstrate how to load polydata then use a custom shader calls to render +a custom shaded model. +First, a bunch of imports. +""" + +from fury import io, ui, utils, window +from fury.data.fetcher import fetch_viz_models, read_viz_models +from fury.shaders import add_shader_callback, shader_to_actor + +############################################################################### +# Let's download and load the model + + +fetch_viz_models() +model = read_viz_models('utah.obj') + + +############################################################################### +# +# Let's start by loading the polydata of choice. +# For this example we use the standard utah teapot model. +# currently supported formats include OBJ, VTK, FIB, PLY, STL and XML + +utah = io.load_polydata(model) +utah = utils.get_polymapper_from_polydata(utah) +utah = utils.get_actor_from_polymapper(utah) +mapper = utah.GetMapper() + + +############################################################################### +# To change the default shader we add a shader replacement. +# Specify vertex shader using vtkShader.Vertex +# Specify fragment shader using vtkShader.Fragment +vertex_shader_code_decl = """ + out vec4 myVertexVC; + """ + +vertex_shader_code_impl = """ + myVertexVC = vertexMC; + """ + +fragment_shader_code_decl = """ + uniform float time; + varying vec4 myVertexVC; + """ + +fragment_shader_code_impl = """ + vec2 iResolution = vec2(1024,720); + vec2 uv = myVertexVC.xy/iResolution; + vec3 col = 0.5 + 0.5 * cos((time/30) + uv.xyx + vec3(0, 2, 4)); + fragOutput0 = vec4(col, fragOutput0.a); + """ + +shader_to_actor( + utah, 'vertex', impl_code=vertex_shader_code_impl, decl_code=vertex_shader_code_decl +) +shader_to_actor(utah, 'fragment', decl_code=fragment_shader_code_decl) +shader_to_actor(utah, 'fragment', impl_code=fragment_shader_code_impl, block='light') + +############################################################################### +# Let's create a scene. + +scene = window.Scene() + +global timer +timer = 0 + +############################################################################## +# The timer will call this user defined callback every 30 milliseconds. + + +def timer_callback(obj, event): + global timer + timer += 1.0 + showm.render() + scene.azimuth(5) + + +############################################################################### +# The shader callback will update the color of our utah pot via the update of +# the timer variable. + + +def shader_callback(_caller, _event, calldata=None): + program = calldata + global timer + if program is not None: + try: + program.SetUniformf('time', timer) + except ValueError: + pass + + +add_shader_callback(utah, shader_callback) +############################################################################### +# Let's add a textblock to the scene with a custom message + +tb = ui.TextBlock2D() +tb.message = 'Hello Shaders' + +############################################################################### +# Show Manager +# +# Now that all the elements have been initialised, we add them to the show +# manager. + +current_size = (1024, 720) +showm = window.ShowManager(scene, size=current_size, reset_camera=False) + + +showm.add_timer_callback(True, 30, timer_callback) + +scene.add(utah) +scene.add(tb) + +interactive = False +if interactive: + showm.start() + +window.record(showm.scene, size=current_size, out_path='viz_shader.png') diff --git a/v0.10.x/_downloads/ede8d00fe58f4888e7fb492de5c81453/viz_check_boxes.ipynb b/v0.10.x/_downloads/ede8d00fe58f4888e7fb492de5c81453/viz_check_boxes.ipynb new file mode 100644 index 000000000..749f694ae --- /dev/null +++ b/v0.10.x/_downloads/ede8d00fe58f4888e7fb492de5c81453/viz_check_boxes.ipynb @@ -0,0 +1,169 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Figure and Color Control using Check boxes and Radio Buttons\n\nThis example shows how to use the CheckBox UI API. We will demonstrate how to\ncreate a cube, sphere, cone and arrow and control its color and visibility\nusing checkboxes.\n\nFirst, some imports.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "import numpy as np\n\nfrom fury import actor, ui, utils, window\nfrom fury.data import fetch_viz_icons" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "First we need to fetch some icons that are included in FURY.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "fetch_viz_icons()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We create the corresponding object actors for cube, sphere, cone and arrow.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "cube = actor.cube(\n centers=np.array([[15, 0, 0]]),\n colors=np.array([[0, 0, 1]]),\n scales=np.array([[20, 20, 20]]),\n directions=np.array([[0, 0, 1]]),\n)\n\nsphere = actor.sphere(\n centers=np.array([[50, 0, 0]]),\n colors=np.array([[0, 0, 1]]),\n radii=11.0,\n theta=360,\n phi=360,\n)\n\ncone = actor.cone(\n centers=np.array([[-20, -0.5, 0]]),\n directions=np.array([[0, 1, 0]]),\n colors=np.array([[0, 0, 1]]),\n heights=20,\n resolution=100,\n)\n\narrow = actor.arrow(\n centers=np.array([[0, 25, 0]]),\n colors=np.array([[0, 0, 1]]),\n directions=np.array([[1, 0, 0]]),\n heights=40,\n resolution=100,\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We perform symmetric difference to determine the unchecked options.\nWe also define methods to render visibility and color.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Get difference between two lists.\ndef sym_diff(l1, l2):\n return list(set(l1).symmetric_difference(set(l2)))\n\n\n# Set Visibility of the figures\ndef set_figure_visiblity(checkboxes):\n checked = checkboxes.checked_labels\n unchecked = sym_diff(list(figure_dict), checked)\n\n for visible in checked:\n figure_dict[visible].SetVisibility(True)\n\n for invisible in unchecked:\n figure_dict[invisible].SetVisibility(False)\n\n\ndef update_colors(color_array):\n for _, figure in figure_dict.items():\n vcolors = utils.colors_from_actor(figure)\n vcolors[:] = color_array\n utils.update_actor(figure)\n\n\n# Toggle colors of the figures\ndef toggle_color(checkboxes):\n colors = checkboxes.checked_labels\n\n color_array = np.array([0, 0, 0])\n\n for col in colors:\n if col == 'Red':\n color_array[0] = 255\n elif col == 'Green':\n color_array[1] = 255\n else:\n color_array[2] = 255\n\n update_colors(color_array)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We define a dictionary to store the actors with their names as keys.\nA checkbox is created with actor names as it's options.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "figure_dict = {'cube': cube, 'sphere': sphere, 'cone': cone, 'arrow': arrow}\ncheck_box = ui.Checkbox(\n list(figure_dict),\n list(figure_dict),\n padding=1,\n font_size=18,\n font_family='Arial',\n position=(400, 85),\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "A similar checkbox is created for changing colors.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "options = {'Blue': (0, 0, 1), 'Red': (1, 0, 0), 'Green': (0, 1, 0)}\ncolor_toggler = ui.Checkbox(\n list(options),\n checked_labels=['Blue'],\n padding=1,\n font_size=16,\n font_family='Arial',\n position=(600, 120),\n)\n\n\ncheck_box.on_change = set_figure_visiblity\ncolor_toggler.on_change = toggle_color" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Show Manager\n\nNow that all the elements have been initialised, we add them to the show\nmanager.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "current_size = (1000, 1000)\nshow_manager = window.ShowManager(size=current_size, title='FURY Checkbox Example')\n\nshow_manager.scene.add(cube)\nshow_manager.scene.add(sphere)\nshow_manager.scene.add(cone)\nshow_manager.scene.add(arrow)\nshow_manager.scene.add(check_box)\nshow_manager.scene.add(color_toggler)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Set camera for better visualization\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "show_manager.scene.reset_camera()\nshow_manager.scene.set_camera(position=(0, 0, 150))\nshow_manager.scene.reset_clipping_range()\nshow_manager.scene.azimuth(30)\ninteractive = False\n\nif interactive:\n show_manager.start()\n\nwindow.record(show_manager.scene, size=current_size, out_path='viz_checkbox.png')" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.8" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/v0.10.x/_downloads/eec6c7e397f6bb2f6b871a05aa32751a/viz_sdfactor.ipynb b/v0.10.x/_downloads/eec6c7e397f6bb2f6b871a05aa32751a/viz_sdfactor.ipynb new file mode 100644 index 000000000..9dd7571c3 --- /dev/null +++ b/v0.10.x/_downloads/eec6c7e397f6bb2f6b871a05aa32751a/viz_sdfactor.ipynb @@ -0,0 +1,115 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Visualize SDF Actor\nHere is a simple tutorial that shows how to visualize SDF primitives using\nFURY.\n\nSDFs or Signed-distance functions when passed the coordinates of a point in\nspace, return the shortest distance between that point and some surface.\nThis property of SDFs can be used to model 3D geometry at a faster rate\ncompared to traditional polygons based modeling.\n\nIn this example we use the raymarching algorithm to render the SDF primitives\nshapes using shaders\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "import numpy as np\n\nfrom fury import actor, window" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Lets define variables for the SDF Actor\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "dirs = np.random.rand(4, 3)\ncolors = np.random.rand(4, 3) * 255\ncenters = np.array([[1, 0, 0], [0, 0, 0], [-1, 0, 0], [0, 1, 0]])\nscales = np.random.rand(4, 1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Create SDF Actor\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "sdfactor = actor.sdf(\n centers=centers,\n directions=dirs,\n colors=colors,\n primitives=['sphere', 'torus', 'ellipsoid', 'capsule'],\n scales=scales,\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Create a scene\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "scene = window.Scene()\nscene.background((1.0, 0.8, 0.8))\nscene.add(sdfactor)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Show Manager\n\nSince all the elements have been initialised ,we add them to the show\nmanager.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "current_size = (1024, 720)\nshowm = window.ShowManager(scene, size=current_size, title='Visualize SDF Actor')\n\ninteractive = False\n\nif interactive:\n showm.start()\n\nwindow.record(scene, out_path='viz_sdfactor.png', size=current_size)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.8" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/v0.10.x/_downloads/ef81dbce7a8fdf5d5ce02e1cdb7f5529/viz_domino.ipynb b/v0.10.x/_downloads/ef81dbce7a8fdf5d5ce02e1cdb7f5529/viz_domino.ipynb new file mode 100644 index 000000000..be6b050b3 --- /dev/null +++ b/v0.10.x/_downloads/ef81dbce7a8fdf5d5ce02e1cdb7f5529/viz_domino.ipynb @@ -0,0 +1,187 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Domino Physics Simulation\n\nThis example simulation shows how to use pybullet to render physics simulations\nin fury. In this example we specifically render a series of Dominoes which are\nunder Domino Effect.\n\nFirst some imports.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "import itertools\n\nimport numpy as np\nimport pybullet as p\n\nfrom fury import actor, ui, utils, window\n\n# Next, we initialize a pybullet client to render the physics.\n# We use `DIRECT` mode to initialize pybullet without a GUI.\nclient = p.connect(p.DIRECT)\n\n# Apply gravity to the scene.\np.setGravity(0, 0, -10, physicsClientId=client)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Set the Number of Dominoes for Simulation.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "number_of_dominoes = 10\n\n# Base Plane Parameters\nbase_size = np.array([number_of_dominoes * 2, number_of_dominoes * 2, 0.2])\nbase_color = np.array([1, 1, 1])\nbase_position = np.array([0, 0, -0.1])\nbase_orientation = np.array([0, 0, 0, 1])\n\n# Render a BASE plane to support the Dominoes.\nbase_actor = actor.box(\n centers=np.array([[0, 0, 0]]),\n directions=[0, 0, 0],\n scales=base_size,\n colors=base_color,\n)\n\n# half of the actual size.\nbase_coll = p.createCollisionShape(p.GEOM_BOX, halfExtents=base_size / 2)\n\nbase = p.createMultiBody(\n baseCollisionShapeIndex=base_coll,\n basePosition=base_position,\n baseOrientation=base_orientation,\n)\n\np.changeDynamics(base, -1, lateralFriction=1, restitution=0.5)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We define some global parameters of the Dominoes so that its easier for\nus to tweak the simulation.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "domino_mass = 0.5\ndomino_size = np.array([0.1, 1, 2])\n\ndomino_centers = np.zeros((number_of_dominoes, 3))\n\n# Keeping all the dominos Parallel\ndomino_directions = np.zeros((number_of_dominoes, 3))\ndomino_directions[:] = np.array([1.57, 0, 0])\n\ndomino_orns = np.zeros((number_of_dominoes, 4))\n\ndomino_sizes = np.zeros((number_of_dominoes, 3))\ndomino_sizes[:] = domino_size\n\ndomino_colors = np.random.rand(number_of_dominoes, 3)\n\ndomino_coll = p.createCollisionShape(p.GEOM_BOX, halfExtents=domino_size / 2)\n\n# We use this array to store the reference of domino objects in pybullet world.\ndominos = np.zeros(number_of_dominoes, dtype=np.int8)\n\ncenters_list = np.zeros((number_of_dominoes, 3))\n\n# Adding the dominoes\nfor i in range(number_of_dominoes):\n center_pos = np.array([(i * 0.99) - 5.5, 0.4, 1])\n domino_centers[i] = center_pos\n domino_orns[i] = np.array([0, 0, 0, 1])\n dominos[i] = p.createMultiBody(\n baseMass=domino_mass,\n baseCollisionShapeIndex=domino_coll,\n basePosition=center_pos,\n baseOrientation=domino_orns[i],\n )\n p.changeDynamics(dominos[i], -1, lateralFriction=0.2, restitution=0.1)\n\n\ndomino_actor = actor.box(\n centers=domino_centers,\n directions=domino_directions,\n scales=domino_sizes,\n colors=domino_colors,\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now, we define a scene and add actors to it.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "scene = window.Scene()\nscene.add(actor.axes())\nscene.add(base_actor)\nscene.add(domino_actor)\n\n# Create show manager.\nshowm = window.ShowManager(\n scene, size=(900, 768), reset_camera=False, order_transparent=True\n)\n\n\n# Counter iterator for tracking simulation steps.\ncounter = itertools.count()\n\n# Variable for tracking applied force.\napply_force = True" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now, we define methods to sync objects between fury and Pybullet.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Get the position of base and set it.\nbase_pos, _ = p.getBasePositionAndOrientation(base)\nbase_actor.SetPosition(*base_pos)\n\n\n# Calculate the vertices of the dominos.\nvertices = utils.vertices_from_actor(domino_actor)\nnum_vertices = vertices.shape[0]\nnum_objects = domino_centers.shape[0]\nsec = int(num_vertices / num_objects)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Syncing Dominoes\n\nHere, we perform three major steps to sync Dominoes accurately.\n* Get the position and orientation of the Dominoes from pybullet.\n* Calculate the Rotation Matrix.\n\n - Get the difference in orientations (Quaternion).\n - Generate the corresponding rotation matrix according to that difference.\n - Reshape it in a 3x3 matrix.\n\n* Perform calculations to get the required position and orientation.\n* Update the position and orientation.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def sync_domino(object_index, multibody):\n pos, orn = p.getBasePositionAndOrientation(multibody)\n\n rot_mat = np.reshape(\n p.getMatrixFromQuaternion(\n p.getDifferenceQuaternion(orn, domino_orns[object_index])\n ),\n (3, 3),\n )\n\n vertices[object_index * sec : object_index * sec + sec] = (\n vertices[object_index * sec : object_index * sec + sec]\n - domino_centers[object_index]\n ) @ rot_mat + pos\n\n domino_centers[object_index] = pos\n domino_orns[object_index] = orn" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Here, we define a textblock to display the Avg. FPS and simulation steps.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "fpss = np.array([])\ntb = ui.TextBlock2D(\n text='Avg. FPS: \\nSim Steps: ', position=(0, 680), font_size=30, color=(1, 0.5, 0)\n)\nscene.add(tb)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Set the camera for better visualization.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "scene.set_camera(\n position=(10.46, -8.13, 6.18),\n focal_point=(0.0, 0.0, 0.79),\n view_up=(-0.27, 0.26, 0.90),\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Timer callback is created which is responsible for calling the sync and\nsimulation methods.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Create timer callback which will execute at each step of simulation.\ndef timer_callback(_obj, _event):\n global apply_force, fpss\n cnt = next(counter)\n showm.render()\n\n if cnt % 1 == 0:\n fps = showm.frame_rate\n fpss = np.append(fpss, fps)\n tb.message = (\n 'Avg. FPS: ' + str(np.round(np.mean(fpss), 0)) + '\\nSim Steps: ' + str(cnt)\n )\n\n # Get the position and orientation of the first domino.\n domino1_pos, domino1_orn = p.getBasePositionAndOrientation(dominos[0])\n\n # Apply force on the First Domino (domino) above the Center of Mass.\n if apply_force:\n # Apply the force.\n p.applyExternalForce(\n dominos[0],\n -1,\n forceObj=[100, 0, 0],\n posObj=domino1_pos + np.array([0, 0, 1.7]),\n flags=p.WORLD_FRAME,\n )\n apply_force = False\n\n # Updating the position and orientation of individual dominos.\n for idx, domino in enumerate(dominos):\n sync_domino(idx, domino)\n utils.update_actor(domino_actor)\n\n # Simulate a step.\n p.stepSimulation()\n\n # Exit after 300 steps of simulation.\n if cnt == 300:\n showm.exit()\n\n\n# Add the timer callback to showmanager.\n# Increasing the duration value will slow down the simulation.\nshowm.add_timer_callback(True, 1, timer_callback)\n\ninteractive = False\n\n# start simulation\nif interactive:\n showm.start()\n\nwindow.record(scene, out_path='viz_domino.png', size=(900, 768))" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.8" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/v0.10.x/_downloads/f04511f11775c06091bec37717652f01/viz_shapes.ipynb b/v0.10.x/_downloads/f04511f11775c06091bec37717652f01/viz_shapes.ipynb new file mode 100644 index 000000000..5e5e1cb35 --- /dev/null +++ b/v0.10.x/_downloads/f04511f11775c06091bec37717652f01/viz_shapes.ipynb @@ -0,0 +1,133 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Simple Shapes\n\nThis example shows how to use the UI API. We will demonstrate how to draw\nsome geometric shapes from FURY UI elements.\n\nFirst, a bunch of imports.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "from fury import ui, window\nfrom fury.data import fetch_viz_icons" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "First we need to fetch some icons that are included in FURY.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "fetch_viz_icons()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's draw some simple shapes. First, a rectangle.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "rect = ui.Rectangle2D(size=(100, 100), position=(400, 400), color=(1, 0, 1))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Then we can draw a solid circle, or disk.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "disk = ui.Disk2D(outer_radius=50, center=(400, 200), color=(1, 1, 0))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Add an inner radius to make a ring.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "ring = ui.Disk2D(outer_radius=50, inner_radius=45, center=(500, 600), color=(0, 1, 1))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now that all the elements have been initialised, we add them to the show\nmanager.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "current_size = (800, 800)\nshow_manager = window.ShowManager(size=current_size, title='FURY Shapes Example')\n\nshow_manager.scene.add(rect)\nshow_manager.scene.add(disk)\nshow_manager.scene.add(ring)\n\ninteractive = False\n\nif interactive:\n show_manager.start()\n\nwindow.record(show_manager.scene, size=current_size, out_path='viz_shapes.png')" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.8" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/v0.10.x/_downloads/f3c12cee7268b7b98cd3da9316478888/viz_interaction.ipynb b/v0.10.x/_downloads/f3c12cee7268b7b98cd3da9316478888/viz_interaction.ipynb new file mode 100644 index 000000000..5417ffb54 --- /dev/null +++ b/v0.10.x/_downloads/f3c12cee7268b7b98cd3da9316478888/viz_interaction.ipynb @@ -0,0 +1,43 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Streaming FURY with user interaction\n\nIn this tutorial, we show how to use the FURY Streaming system to\nserve an interactive visualization through a web browser.\n\nYou can choose between two different encodings: WebRTC or MJPEG.\nWebRTC is a more robust option and can be used to perform\na live streaming with a low-latency connection for example using\nngrok. However, to use webRTC you need to install the aiortc library.\n\n```bash\npip install aiortc\n```\n## Notes\nIf you don't have ffmpeg installed, you need to install it to use WebRTC\n\nLinux\n\n\n`apt install libavdevice-dev libavfilter-dev libopus-dev libvpx-dev pkg-config`\n\nOS X\n\n`brew install ffmpeg opus libvpx pkg-config`\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "import multiprocessing\nimport sys\n\nimport numpy as np\n\nfrom fury import actor, window\nfrom fury.stream.client import FuryStreamClient, FuryStreamInteraction\n\n# if this example it's not working for you and you're using MacOs\n# uncomment the following line\n# multiprocessing.set_start_method('spawn')\nfrom fury.stream.server.main import WEBRTC_AVAILABLE, web_server, web_server_raw_array\n\nif __name__ == '__main__':\n interactive = False\n # `use_raw_array` is a flag to tell the server to use python RawArray\n # instead of SharedMemory which is a new feature in python 3.8\n # https://docs.python.org/3/library/multiprocessing.html#multiprocessing.Array\n # https://docs.python.org/3/library/multiprocessing.html#shared-memory-objects\n\n use_raw_array = sys.version_info < (3, 8)\n window_size = (300, 300)\n # `max_window_size` are the maximum size of the window that will be\n # allowed to be sent to the browser. For example, if you set\n # `max_window_size=(800, 800)` then the browser will be limited to\n # a window of size (800, 800).\n\n max_window_size = (400, 400)\n # 0 ms_stream means that the frame will be sent to the server\n # right after the rendering\n\n # `ms_interaction` is the time in milliseconds that the user will have\n # to interact with the visualization\n\n ms_interaction = 1\n # `ms_stream` is the number of milliseconds that the server will\n # wait before sending a new frame to the browser. If `ms_stream=0`\n # then the server will send the frame right after the rendering.\n\n ms_stream = 0\n # max number of interactions to be stored inside the queue\n max_queue_size = 17\n ######################################################################\n centers = np.array([[0, 0, 0], [-1, 0, 0], [1, 0, 0]])\n colors = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]])\n\n actors = actor.sphere(centers, opacity=0.5, radii=0.4, colors=colors)\n scene = window.Scene()\n\n scene.add(actors)\n\n showm = window.ShowManager(scene, size=(window_size[0], window_size[1]))\n\n stream = FuryStreamClient(\n showm, max_window_size=max_window_size, use_raw_array=use_raw_array\n )\n stream_interaction = FuryStreamInteraction(\n showm, max_queue_size=max_queue_size, use_raw_array=use_raw_array\n )\n\n if use_raw_array:\n p = multiprocessing.Process(\n target=web_server_raw_array,\n args=(\n stream.img_manager.image_buffers,\n stream.img_manager.info_buffer,\n stream_interaction.circular_queue.head_tail_buffer,\n stream_interaction.circular_queue.buffer._buffer,\n 8000,\n 'localhost',\n True,\n WEBRTC_AVAILABLE,\n ),\n )\n\n else:\n p = multiprocessing.Process(\n target=web_server,\n args=(\n stream.img_manager.image_buffer_names,\n stream.img_manager.info_buffer_name,\n stream_interaction.circular_queue.head_tail_buffer_name,\n stream_interaction.circular_queue.buffer.buffer_name,\n 8000,\n 'localhost',\n True,\n WEBRTC_AVAILABLE,\n ),\n )\n p.start()\n stream_interaction.start(ms=ms_interaction)\n stream.start(\n ms_stream,\n )\n ###########################################################################\n # If you have aiortc in your system, you can see your live streaming\n # through the following url: htttp://localhost:8000/?encoding=webrtc\n # Other wise, you can use the following url:\n # http://localhost:8000/?encoding=mjpeg\n\n if interactive:\n showm.start()\n\n # We need to close the server after the show is over\n p.kill()\n ###########################################################################\n # We release the resources and stop the interactive mode\n stream.stop()\n stream_interaction.stop()\n stream.cleanup()\n stream_interaction.cleanup()\n\n window.record(showm.scene, size=window_size, out_path='viz_interaction.png')" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.8" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/v0.10.x/_downloads/f4c4ff3a5276191c800c59f6da1b84df/viz_no_interaction.ipynb b/v0.10.x/_downloads/f4c4ff3a5276191c800c59f6da1b84df/viz_no_interaction.ipynb new file mode 100644 index 000000000..a3f85bbf7 --- /dev/null +++ b/v0.10.x/_downloads/f4c4ff3a5276191c800c59f6da1b84df/viz_no_interaction.ipynb @@ -0,0 +1,43 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Streaming FURY with WebRTC/MJPEG\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "import multiprocessing\nfrom os.path import join as pjoin\n\n# if this example it's not working for you and you're using MacOs\n# uncomment the following line\n# multiprocessing.set_start_method('spawn')\nimport numpy as np\n\nfrom fury import actor\nfrom fury import colormap as cmap\nfrom fury import window\nfrom fury.data.fetcher import fetch_viz_wiki_nw\nfrom fury.stream.client import FuryStreamClient\nfrom fury.stream.server.main import web_server_raw_array\n\nif __name__ == '__main__':\n\n interactive = False\n ###########################################################################\n # First we will set the resolution which it'll be used by the streamer\n\n window_size = (400, 400)\n\n files, folder = fetch_viz_wiki_nw()\n categories_file, edges_file, positions_file = sorted(files.keys())\n positions = np.loadtxt(pjoin(folder, positions_file))\n categories = np.loadtxt(pjoin(folder, categories_file), dtype=str)\n edges = np.loadtxt(pjoin(folder, edges_file), dtype=int)\n category2index = {category: i for i, category in enumerate(np.unique(categories))}\n\n index2category = np.unique(categories)\n\n categoryColors = cmap.distinguishable_colormap(nb_colors=len(index2category))\n\n colors = np.array(\n [categoryColors[category2index[category]] for category in categories]\n )\n radii = 1 + np.random.rand(len(positions))\n\n edgesPositions = []\n edgesColors = []\n for source, target in edges:\n edgesPositions.append(np.array([positions[source], positions[target]]))\n edgesColors.append(np.array([colors[source], colors[target]]))\n\n edgesPositions = np.array(edgesPositions)\n edgesColors = np.average(np.array(edgesColors), axis=1)\n\n sphere_actor = actor.sdf(\n centers=positions,\n colors=colors,\n primitives='sphere',\n scales=radii * 0.5,\n )\n\n lines_actor = actor.line(\n edgesPositions,\n colors=edgesColors,\n opacity=0.1,\n )\n scene = window.Scene()\n\n scene.add(lines_actor)\n scene.add(sphere_actor)\n\n scene.set_camera(\n position=(0, 0, 1000), focal_point=(0.0, 0.0, 0.0), view_up=(0.0, 0.0, 0.0)\n )\n\n showm = window.ShowManager(\n scene,\n reset_camera=False,\n size=(window_size[0], window_size[1]),\n order_transparent=False,\n )\n\n ###########################################################################\n # ms define the amount of mileseconds that will be used in the timer event.\n\n ms = 0\n\n stream = FuryStreamClient(showm, use_raw_array=True)\n p = multiprocessing.Process(\n target=web_server_raw_array,\n args=(\n stream.img_manager.image_buffers,\n stream.img_manager.info_buffer,\n ),\n )\n p.start()\n\n stream.start(\n ms,\n )\n if interactive:\n showm.start()\n stream.stop()\n stream.cleanup()\n\n window.record(showm.scene, size=window_size, out_path='viz_no_interaction.png')" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.8" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/v0.10.x/_downloads/f5e1926c83f933b9b5ab0716ab98ddc6/viz_roi_contour.ipynb b/v0.10.x/_downloads/f5e1926c83f933b9b5ab0716ab98ddc6/viz_roi_contour.ipynb new file mode 100644 index 000000000..8df50fbe0 --- /dev/null +++ b/v0.10.x/_downloads/f5e1926c83f933b9b5ab0716ab98ddc6/viz_roi_contour.ipynb @@ -0,0 +1,133 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Visualization of ROI Surface Rendered with Streamlines\n\nHere is a simple tutorial following the probabilistic CSA Tracking Example in\nwhich we generate a dataset of streamlines from a corpus callosum ROI, and\nthen display them with the seed ROI rendered in 3D with 50% transparency.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "from dipy.data import default_sphere, read_stanford_labels\nfrom dipy.direction import peaks_from_model\nfrom dipy.reconst.shm import CsaOdfModel\n\ntry:\n from dipy.tracking.local import LocalTracking\n from dipy.tracking.local import (\n ThresholdTissueClassifier as ThresholdStoppingCriterion,\n )\nexcept ImportError:\n from dipy.tracking.stopping_criterion import ThresholdStoppingCriterion\n from dipy.tracking.local_tracking import LocalTracking\n\nfrom dipy.tracking import utils\nfrom dipy.tracking.streamline import Streamlines\n\nfrom fury import actor, window\nfrom fury.colormap import line_colors" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "First, we need to generate some streamlines. For a more complete\ndescription of these steps, please refer to the CSA Probabilistic Tracking\nTutorial.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "hardi_img, gtab, labels_img = read_stanford_labels()\ndata = hardi_img.get_fdata()\nlabels = labels_img.get_fdata()\naffine = hardi_img.affine\n\nwhite_matter = (labels == 1) | (labels == 2)\n\ncsa_model = CsaOdfModel(gtab, sh_order=6)\ncsa_peaks = peaks_from_model(\n csa_model,\n data,\n default_sphere,\n relative_peak_threshold=0.8,\n min_separation_angle=45,\n mask=white_matter,\n)\n\nclassifier = ThresholdStoppingCriterion(csa_peaks.gfa, 0.25)\n\nseed_mask = labels == 2\nseeds = utils.seeds_from_mask(seed_mask, density=[1, 1, 1], affine=affine)\n\n# Initialization of LocalTracking. The computation happens in the next step.\nstreamlines = LocalTracking(csa_peaks, classifier, seeds, affine, step_size=2)\n\n# Compute streamlines and store as a list.\nstreamlines = Streamlines(streamlines)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We will create a streamline actor from the streamlines.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "streamlines_actor = actor.line(streamlines, line_colors(streamlines))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Next, we create a surface actor from the corpus callosum seed ROI. We\nprovide the ROI data, the affine, the color in [R,G,B], and the opacity as\na decimal between zero and one. Here, we set the color as blue/green with\n50% opacity.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "surface_opacity = 0.5\nsurface_color = [0, 1, 1]\n\nseedroi_actor = actor.contour_from_roi(\n seed_mask, affine, surface_color, surface_opacity\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Next, we initialize a ''Scene'' object and add both actors\nto the rendering.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "scene = window.Scene()\nscene.add(streamlines_actor)\nscene.add(seedroi_actor)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "If you uncomment the following line, the rendering will pop up in an\ninteractive window.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "interactive = False\nif interactive:\n window.show(scene)\n\n# scene.zoom(1.5)\n# scene.reset_clipping_range()\n\nwindow.record(scene, out_path='contour_from_roi_tutorial.png', size=(600, 600))" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.8" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/v0.10.x/_downloads/f73fb8b83b88c1bc236749fe0958cc99/viz_card.ipynb b/v0.10.x/_downloads/f73fb8b83b88c1bc236749fe0958cc99/viz_card.ipynb new file mode 100644 index 000000000..0bcacd1a7 --- /dev/null +++ b/v0.10.x/_downloads/f73fb8b83b88c1bc236749fe0958cc99/viz_card.ipynb @@ -0,0 +1,97 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Card\n\nThis example shows how to create a card.\n\nFirst, some imports.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "from fury import ui, window\nfrom fury.data import fetch_viz_icons" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "First we need to fetch some icons that are included in FURY.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "fetch_viz_icons()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's create a card and add it to the show manager\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "img_url = \"https://raw.githubusercontent.com/fury-gl\"\\\n \"/fury-communication-assets/main/fury-logo.png\"\n\ntitle = \"FURY\"\nbody = \"FURY - Free Unified Rendering in pYthon.\"\\\n \"A software library for scientific visualization in Python.\"\n\ncard = ui.elements.Card2D(image_path=img_url, title_text=title,\n body_text=body,\n image_scale=0.55, size=(300, 300),\n bg_color=(1, 0.294, 0.180),\n bg_opacity=0.8, border_width=5,\n border_color=(0.1, 0.4, 0.4))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now that the card has been initialised, we add it to the show\nmanager.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "current_size = (1000, 1000)\nshow_manager = window.ShowManager(size=current_size,\n title=\"FURY Card Example\")\n\nshow_manager.scene.add(card)\n# To interact with the UI, set interactive = True\ninteractive = False\n\nif interactive:\n show_manager.start()\n\nwindow.record(show_manager.scene, out_path=\"card_ui.png\", size=(1000, 1000))" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.8" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/v0.10.x/_downloads/fc9197994069181d3183d289ea25d40c/viz_spiky.py b/v0.10.x/_downloads/fc9197994069181d3183d289ea25d40c/viz_spiky.py new file mode 100644 index 000000000..0cf3ffcd5 --- /dev/null +++ b/v0.10.x/_downloads/fc9197994069181d3183d289ea25d40c/viz_spiky.py @@ -0,0 +1,115 @@ +""" +=============== +Spiky Sphere +=============== +In this tutorial, we show how to create a sphere with spikes. +""" + +import itertools + +import numpy as np + +from fury import actor, primitive, utils, window + +############################################################################## +# Create a sphere actor. Define the center, radius and color of a sphere. +# The sphere actor is made of points (vertices) evenly distributed on a +# sphere. +# Let's create a scene. + +scene = window.Scene() + +############################################################################## +# The vertices are connected with triangles in order to specify the direction +# of the surface normal. +# ``prim_sphere`` provides a sphere with evenly distributed points + +vertices, triangles = primitive.prim_sphere(name='symmetric362', gen_faces=False) + +############################################################################## +# To be able to visualize the vertices, let's define a point actor with +# green color. + +point_actor = actor.point(vertices, point_radius=0.01, colors=(0, 1, 0)) + +############################################################################## +# Normals are the vectors that are perpendicular to the surface at each +# vertex. We specify the normals at the vertices to tell the system +# whether triangles represent curved surfaces. + +normals = utils.normals_from_v_f(vertices, triangles) + +############################################################################## +# The normals are usually used to calculate how the light will bounce on +# the surface of an object. However, here we will use them to direct the +# spikes (represented with arrows). +# So, let's create an arrow actor at the center of each vertex. + +arrow_actor = actor.arrow( + centers=vertices, + directions=normals, + colors=(1, 0, 0), + heights=0.2, + resolution=10, + vertices=None, + faces=None, +) + +############################################################################## +# To be able to visualize the surface of the primitive sphere, we use +# ``get_actor_from_primitive``. + +primitive_colors = np.zeros(vertices.shape) +primitive_colors[:, 2] = 180 +primitive_actor = utils.get_actor_from_primitive( + vertices=vertices, + triangles=triangles, + colors=primitive_colors, + normals=normals, + backface_culling=True, +) + +############################################################################## +# We add all actors (visual objects) defined above to the scene. + +scene.add(point_actor) +scene.add(arrow_actor) +scene.add(primitive_actor) +scene.add(actor.axes()) + +############################################################################## +# The ShowManager class is the interface between the scene, the window and the +# interactor. + +showm = window.ShowManager( + scene, size=(900, 768), reset_camera=False, order_transparent=True +) + +############################################################################## +# We want to make a small animation for fun! +# We can determine the duration of animation with using the ``counter``. +# Use itertools to avoid global variables. + +counter = itertools.count() + +############################################################################## +# The timer will call this user defined callback every 200 milliseconds. The +# application will exit after the callback has been called 20 times. + + +def timer_callback(_obj, _event): + cnt = next(counter) + showm.scene.azimuth(0.05 * cnt) + primitive_actor.GetProperty().SetOpacity(cnt / 10.0) + showm.render() + if cnt == 20: + showm.exit() + + +showm.add_timer_callback(True, 200, timer_callback) +showm.start() +window.record(showm.scene, size=(900, 768), out_path='viz_spiky.png') + +############################################################################## +# Instead of arrows, you can choose other geometrical objects +# such as cones, cubes or spheres. diff --git a/v0.10.x/_downloads/fd6b3303da550634ecd70b21004cd373/viz_camera.py b/v0.10.x/_downloads/fd6b3303da550634ecd70b21004cd373/viz_camera.py new file mode 100644 index 000000000..6593a7a4a --- /dev/null +++ b/v0.10.x/_downloads/fd6b3303da550634ecd70b21004cd373/viz_camera.py @@ -0,0 +1,179 @@ +""" +====================================== +Keyframe animation: Camera and opacity +====================================== + +Camera and opacity keyframe animation explained in this tutorial. +""" + +import numpy as np + +from fury import actor, window +from fury.animation import Animation, CameraAnimation, Timeline +from fury.animation.interpolator import cubic_spline_interpolator + +############################################################################### +# The Plan +# ======== +# +# The plan here is to animate (scale and translate) 50 spheres randomly, and +# show `FURY` text that appears at the end! + +scene = window.Scene() + +showm = window.ShowManager( + scene, size=(900, 768), reset_camera=False, order_transparent=True +) + + +############################################################################### +# Creating the main ``Timeline`` and adding static actors to it +# ============================================================= +# +# Here we create a ``Timeline``. so that we can use it as a controller for the +# 50 animations we will create. +# So, Instead of updating and adding 50 Animations to the ``ShowManager``, +# we only need to update the main ``Timeline``. Also, a playback panel can be +# assigned to this main Timeline. +# +# But, why we need 50 ``Animations``, you may ask. +# -> A single ``Animation`` can handle each property once at a time. So we need +# 50 ``Animations`` to translate and scale our 50 spheres. + +############################################################################### +# ``playback_panel=True`` assigns a playback panel that can control the +# playback of its ``Animations`` + +timeline = Timeline(playback_panel=True) + +############################################################################### +# Creating two actors for visualization, and to detect camera's animations. +arrow = actor.arrow( + np.array([[0, 0, 0]]), np.array([[0, 1, 0]]), np.array([[1, 1, 0]]), scales=5 +) +plan = actor.box( + np.array([[0, 0, 0]]), + colors=np.array([[1, 1, 1]]), + scales=np.array([[20, 0.2, 20]]), +) + +############################################################################### +# Creating "FURY" text +# ==================== +fury_text = actor.vector_text('FURY', pos=(-4.3, 15, 0), scale=(2, 2, 2)) + +############################################################################### +# Creating an ``Animation`` to animate the opacity of ``fury_text`` +text_anim = Animation(fury_text, loop=False) + +############################################################################### +# opacity is set to 0 at time 29 and set to one at time 35. +# Linear interpolator is always used by default. +text_anim.set_opacity(29, 0) +text_anim.set_opacity(35, 1) + +############################################################################### +# ``text_anim`` contains the text actor is added to the Timeline. +timeline.add_animation(text_anim) + +############################################################################### +# Creating and animating 50 Spheres +# ================================= +# + +for i in range(50): + ########################################################################### + # create a sphere actor that's centered at the origin and has random color + # and radius. + actors = [ + actor.sphere( + np.array([[0, 0, 0]]), np.random.random([1, 3]), np.random.random([1, 3]) + ) + ] + + ########################################################################### + # create a timeline to animate this actor (single actor or list of actors) + # Actors can be added later using `Timeline.add_actor(actor)` + animation = Animation(actors) + + # We generate random position and scale values from time=0 to time=49 each + # two seconds. + for t in range(0, 50, 2): + ####################################################################### + # Position and scale are set to a random value at the timestamps + # mentioned above. + animation.set_position(t, np.random.random(3) * 30 - np.array([15, 0, 15])) + animation.set_scale(t, np.repeat(np.random.random(1), 3)) + + ########################################################################### + # change the position interpolator to cubic spline interpolator. + animation.set_position_interpolator(cubic_spline_interpolator) + + ########################################################################### + # Finally, the ``Animation`` is added to the ``Timeline``. + timeline.add_animation(animation) + +############################################################################### +# Animating the camera +# ==================== +# +# Since, only one camera is needed, camera animations are preferably done using +# a separate ``Animation``. +# Three properties can control the camera's animation: +# Position, focal position (referred to by `focal`), and up-view. + +camera_anim = CameraAnimation(loop=False) +timeline.add_animation(camera_anim) + +############################################################################### +# Multiple keyframes can be set at once as follows. +# camera focal positions +camera_positions = { + # time: camera position + 0: np.array([3, 3, 3]), + 4: np.array([50, 25, -40]), + 7: np.array([-50, 50, -40]), + 10: np.array([-25, 25, 20]), + 14: np.array([0, 16, 25]), + 20: np.array([0, 14.5, 20]), +} + +# camera focal positions +camera_focal_positions = { + # time: focal position + 15: np.array([0, 0, 0]), + 20: np.array([3, 9, 5]), + 23: np.array([7, 5, 3]), + 25: np.array([-2, 9, -6]), + 27: np.array([0, 16, 0]), + 31: np.array([0, 14.5, 0]), +} + +############################################################################### +# ``set_camera_focal`` can only set one keyframe, but +# ``set_camera_focal_keyframes`` can set a dictionary of keyframes. +camera_anim.set_focal_keyframes(camera_focal_positions) +camera_anim.set_position_keyframes(camera_positions) + +############################################################################### +# Change camera position and focal interpolators +camera_anim.set_position_interpolator(cubic_spline_interpolator) +camera_anim.set_focal_interpolator(cubic_spline_interpolator) + +############################################################################### +# Adding non-animatable actors to the scene. +scene.add(arrow, plan) + +############################################################################### +# Adding the timeline to the ShowManager. +showm.add_animation(timeline) + +############################################################################### +# The ShowManager must go on! + +interactive = False + +if interactive: + showm.start() + +window.record(scene, out_path='viz_keyframe_animation_camera.png', size=(900, 768)) diff --git a/v0.10.x/_downloads/ff3034e7477e72f293a2b90710745b59/viz_surfaces.ipynb b/v0.10.x/_downloads/ff3034e7477e72f293a2b90710745b59/viz_surfaces.ipynb new file mode 100644 index 000000000..e13d43648 --- /dev/null +++ b/v0.10.x/_downloads/ff3034e7477e72f293a2b90710745b59/viz_surfaces.ipynb @@ -0,0 +1,176 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Visualize surfaces\n\nHere is a simple tutorial that shows how to visualize surfaces using DIPY. It\nalso shows how to load/save, get/set and update ``PolyData`` and show\nsurfaces.\n\n``PolyData`` is a structure used by VTK to represent surfaces and other data\nstructures. Here we show how to visualize a simple cube but the same idea\nshould apply for any surface.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "import numpy as np\n\nfrom fury import utils, window\nfrom fury.io import load_polydata, save_polydata\nfrom fury.lib import PolyData" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Import useful functions\n\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Create an empty ``PolyData``\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "my_polydata = PolyData()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Create a cube with vertices and triangles as numpy arrays\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "my_vertices = np.array(\n [\n [0.0, 0.0, 0.0],\n [0.0, 0.0, 1.0],\n [0.0, 1.0, 0.0],\n [0.0, 1.0, 1.0],\n [1.0, 0.0, 0.0],\n [1.0, 0.0, 1.0],\n [1.0, 1.0, 0.0],\n [1.0, 1.0, 1.0],\n ]\n)\n# the data type is needed to mention here, numpy.int64\nmy_triangles = np.array(\n [\n [0, 6, 4],\n [0, 2, 6],\n [0, 3, 2],\n [0, 1, 3],\n [2, 7, 6],\n [2, 3, 7],\n [4, 6, 7],\n [4, 7, 5],\n [0, 4, 5],\n [0, 5, 1],\n [1, 5, 7],\n [1, 7, 3],\n ],\n dtype='i8',\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Set vertices and triangles in the ``PolyData``\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "utils.set_polydata_vertices(my_polydata, my_vertices)\nutils.set_polydata_triangles(my_polydata, my_triangles)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Save the ``PolyData``\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "file_name = 'my_cube.vtk'\nsave_polydata(my_polydata, file_name)\nprint('Surface saved in ' + file_name)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Load the ``PolyData``\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "cube_polydata = load_polydata(file_name)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "add color based on vertices position\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "cube_vertices = utils.get_polydata_vertices(cube_polydata)\ncolors = cube_vertices * 255\nutils.set_polydata_colors(cube_polydata, colors)\n\nprint('new surface colors')\nprint(utils.get_polydata_colors(cube_polydata))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Visualize surfaces\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# get Actor\ncube_actor = utils.get_actor_from_polydata(cube_polydata)\n\n# Create a scene\nscene = window.Scene()\nscene.add(cube_actor)\nscene.set_camera(position=(10, 5, 7), focal_point=(0.5, 0.5, 0.5))\nscene.zoom(3)\n\n# display\n# window.show(scene, size=(600, 600), reset_camera=False)\nwindow.record(scene, out_path='cube.png', size=(600, 600))" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.8" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/v0.10.x/_images/Melpomene_Brain-Streamlines-shader-experiment_by_David-Reagan.jpg b/v0.10.x/_images/Melpomene_Brain-Streamlines-shader-experiment_by_David-Reagan.jpg new file mode 100644 index 000000000..d5abdafc6 Binary files /dev/null and b/v0.10.x/_images/Melpomene_Brain-Streamlines-shader-experiment_by_David-Reagan.jpg differ diff --git a/v0.10.x/_images/sphx_glr_collision-particles_001.png b/v0.10.x/_images/sphx_glr_collision-particles_001.png new file mode 100644 index 000000000..b464c70ff Binary files /dev/null and b/v0.10.x/_images/sphx_glr_collision-particles_001.png differ diff --git a/v0.10.x/_images/sphx_glr_collision-particles_thumb.png b/v0.10.x/_images/sphx_glr_collision-particles_thumb.png new file mode 100644 index 000000000..34f00e14b Binary files /dev/null and b/v0.10.x/_images/sphx_glr_collision-particles_thumb.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_advanced_001.png b/v0.10.x/_images/sphx_glr_viz_advanced_001.png new file mode 100644 index 000000000..dea2bd8f6 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_advanced_001.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_advanced_thumb.png b/v0.10.x/_images/sphx_glr_viz_advanced_thumb.png new file mode 100644 index 000000000..243d96bda Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_advanced_thumb.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_animated_surfaces_001.png b/v0.10.x/_images/sphx_glr_viz_animated_surfaces_001.png new file mode 100644 index 000000000..6bcd5d2a3 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_animated_surfaces_001.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_animated_surfaces_thumb.png b/v0.10.x/_images/sphx_glr_viz_animated_surfaces_thumb.png new file mode 100644 index 000000000..dc53afef1 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_animated_surfaces_thumb.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_arrow_001.png b/v0.10.x/_images/sphx_glr_viz_arrow_001.png new file mode 100644 index 000000000..57003ab66 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_arrow_001.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_arrow_thumb.png b/v0.10.x/_images/sphx_glr_viz_arrow_thumb.png new file mode 100644 index 000000000..0ca61b2ee Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_arrow_thumb.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_ball_collide_001.png b/v0.10.x/_images/sphx_glr_viz_ball_collide_001.png new file mode 100644 index 000000000..efdb96baf Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_ball_collide_001.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_ball_collide_thumb.png b/v0.10.x/_images/sphx_glr_viz_ball_collide_thumb.png new file mode 100644 index 000000000..ad6dda191 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_ball_collide_thumb.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_bezier_interpolator_001.png b/v0.10.x/_images/sphx_glr_viz_bezier_interpolator_001.png new file mode 100644 index 000000000..3102c972b Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_bezier_interpolator_001.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_bezier_interpolator_002.png b/v0.10.x/_images/sphx_glr_viz_bezier_interpolator_002.png new file mode 100644 index 000000000..170da4a35 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_bezier_interpolator_002.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_bezier_interpolator_thumb.png b/v0.10.x/_images/sphx_glr_viz_bezier_interpolator_thumb.png new file mode 100644 index 000000000..99d06ca9a Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_bezier_interpolator_thumb.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_billboard_sdf_spheres_001.png b/v0.10.x/_images/sphx_glr_viz_billboard_sdf_spheres_001.png new file mode 100644 index 000000000..a955471e3 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_billboard_sdf_spheres_001.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_billboard_sdf_spheres_002.png b/v0.10.x/_images/sphx_glr_viz_billboard_sdf_spheres_002.png new file mode 100644 index 000000000..bc67158bd Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_billboard_sdf_spheres_002.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_billboard_sdf_spheres_003.png b/v0.10.x/_images/sphx_glr_viz_billboard_sdf_spheres_003.png new file mode 100644 index 000000000..683d27e41 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_billboard_sdf_spheres_003.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_billboard_sdf_spheres_004.png b/v0.10.x/_images/sphx_glr_viz_billboard_sdf_spheres_004.png new file mode 100644 index 000000000..678a51656 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_billboard_sdf_spheres_004.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_billboard_sdf_spheres_005.png b/v0.10.x/_images/sphx_glr_viz_billboard_sdf_spheres_005.png new file mode 100644 index 000000000..01fd68d92 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_billboard_sdf_spheres_005.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_billboard_sdf_spheres_006.png b/v0.10.x/_images/sphx_glr_viz_billboard_sdf_spheres_006.png new file mode 100644 index 000000000..704b810ff Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_billboard_sdf_spheres_006.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_billboard_sdf_spheres_thumb.png b/v0.10.x/_images/sphx_glr_viz_billboard_sdf_spheres_thumb.png new file mode 100644 index 000000000..c790c386b Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_billboard_sdf_spheres_thumb.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_brick_wall_001.png b/v0.10.x/_images/sphx_glr_viz_brick_wall_001.png new file mode 100644 index 000000000..de00762aa Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_brick_wall_001.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_brick_wall_thumb.png b/v0.10.x/_images/sphx_glr_viz_brick_wall_thumb.png new file mode 100644 index 000000000..d194b1566 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_brick_wall_thumb.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_brownian_motion_001.png b/v0.10.x/_images/sphx_glr_viz_brownian_motion_001.png new file mode 100644 index 000000000..70c473ae8 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_brownian_motion_001.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_brownian_motion_thumb.png b/v0.10.x/_images/sphx_glr_viz_brownian_motion_thumb.png new file mode 100644 index 000000000..70669fa47 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_brownian_motion_thumb.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_bundles_001.png b/v0.10.x/_images/sphx_glr_viz_bundles_001.png new file mode 100644 index 000000000..0c12ca37b Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_bundles_001.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_bundles_002.png b/v0.10.x/_images/sphx_glr_viz_bundles_002.png new file mode 100644 index 000000000..95f7e93ba Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_bundles_002.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_bundles_003.png b/v0.10.x/_images/sphx_glr_viz_bundles_003.png new file mode 100644 index 000000000..c61b6afbd Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_bundles_003.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_bundles_004.png b/v0.10.x/_images/sphx_glr_viz_bundles_004.png new file mode 100644 index 000000000..9a3be865a Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_bundles_004.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_bundles_005.png b/v0.10.x/_images/sphx_glr_viz_bundles_005.png new file mode 100644 index 000000000..161fd086d Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_bundles_005.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_bundles_006.png b/v0.10.x/_images/sphx_glr_viz_bundles_006.png new file mode 100644 index 000000000..01a8fd261 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_bundles_006.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_bundles_007.png b/v0.10.x/_images/sphx_glr_viz_bundles_007.png new file mode 100644 index 000000000..0c12ca37b Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_bundles_007.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_bundles_008.png b/v0.10.x/_images/sphx_glr_viz_bundles_008.png new file mode 100644 index 000000000..50b04dd5b Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_bundles_008.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_bundles_009.png b/v0.10.x/_images/sphx_glr_viz_bundles_009.png new file mode 100644 index 000000000..50b04dd5b Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_bundles_009.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_bundles_010.png b/v0.10.x/_images/sphx_glr_viz_bundles_010.png new file mode 100644 index 000000000..3aac63a37 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_bundles_010.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_bundles_thumb.png b/v0.10.x/_images/sphx_glr_viz_bundles_thumb.png new file mode 100644 index 000000000..654a73c85 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_bundles_thumb.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_buttons_001.png b/v0.10.x/_images/sphx_glr_viz_buttons_001.png new file mode 100644 index 000000000..6d33ad290 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_buttons_001.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_buttons_thumb.png b/v0.10.x/_images/sphx_glr_viz_buttons_thumb.png new file mode 100644 index 000000000..99959e414 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_buttons_thumb.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_camera_001.png b/v0.10.x/_images/sphx_glr_viz_camera_001.png new file mode 100644 index 000000000..a21223c32 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_camera_001.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_camera_thumb.png b/v0.10.x/_images/sphx_glr_viz_camera_thumb.png new file mode 100644 index 000000000..b24a934aa Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_camera_thumb.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_card_001.png b/v0.10.x/_images/sphx_glr_viz_card_001.png new file mode 100644 index 000000000..17c2392e2 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_card_001.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_card_sprite_sheet_001.png b/v0.10.x/_images/sphx_glr_viz_card_sprite_sheet_001.png new file mode 100644 index 000000000..da9891a6c Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_card_sprite_sheet_001.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_card_sprite_sheet_thumb.png b/v0.10.x/_images/sphx_glr_viz_card_sprite_sheet_thumb.png new file mode 100644 index 000000000..c6b4f8ac2 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_card_sprite_sheet_thumb.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_card_thumb.png b/v0.10.x/_images/sphx_glr_viz_card_thumb.png new file mode 100644 index 000000000..ab4e0485a Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_card_thumb.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_chain_001.png b/v0.10.x/_images/sphx_glr_viz_chain_001.png new file mode 100644 index 000000000..86d90f66b Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_chain_001.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_chain_thumb.png b/v0.10.x/_images/sphx_glr_viz_chain_thumb.png new file mode 100644 index 000000000..c834b48c8 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_chain_thumb.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_check_boxes_001.png b/v0.10.x/_images/sphx_glr_viz_check_boxes_001.png new file mode 100644 index 000000000..1b41b9668 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_check_boxes_001.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_check_boxes_thumb.png b/v0.10.x/_images/sphx_glr_viz_check_boxes_thumb.png new file mode 100644 index 000000000..13e0753f3 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_check_boxes_thumb.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_color_interpolators_001.png b/v0.10.x/_images/sphx_glr_viz_color_interpolators_001.png new file mode 100644 index 000000000..b1fc52688 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_color_interpolators_001.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_color_interpolators_thumb.png b/v0.10.x/_images/sphx_glr_viz_color_interpolators_thumb.png new file mode 100644 index 000000000..db650d7be Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_color_interpolators_thumb.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_combobox_001.png b/v0.10.x/_images/sphx_glr_viz_combobox_001.png new file mode 100644 index 000000000..35c09b70f Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_combobox_001.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_combobox_thumb.png b/v0.10.x/_images/sphx_glr_viz_combobox_thumb.png new file mode 100644 index 000000000..d6265e797 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_combobox_thumb.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_cone_001.png b/v0.10.x/_images/sphx_glr_viz_cone_001.png new file mode 100644 index 000000000..ea809931c Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_cone_001.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_cone_thumb.png b/v0.10.x/_images/sphx_glr_viz_cone_thumb.png new file mode 100644 index 000000000..3457f0d0b Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_cone_thumb.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_custom_interpolator_001.png b/v0.10.x/_images/sphx_glr_viz_custom_interpolator_001.png new file mode 100644 index 000000000..88d3dc2eb Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_custom_interpolator_001.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_custom_interpolator_thumb.png b/v0.10.x/_images/sphx_glr_viz_custom_interpolator_thumb.png new file mode 100644 index 000000000..1ca73e921 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_custom_interpolator_thumb.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_domino_001.png b/v0.10.x/_images/sphx_glr_viz_domino_001.png new file mode 100644 index 000000000..43f3e75bd Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_domino_001.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_domino_thumb.png b/v0.10.x/_images/sphx_glr_viz_domino_thumb.png new file mode 100644 index 000000000..36055d2d9 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_domino_thumb.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_drawpanel_001.png b/v0.10.x/_images/sphx_glr_viz_drawpanel_001.png new file mode 100644 index 000000000..089f67766 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_drawpanel_001.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_drawpanel_thumb.png b/v0.10.x/_images/sphx_glr_viz_drawpanel_thumb.png new file mode 100644 index 000000000..b54ade76e Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_drawpanel_thumb.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_dt_ellipsoids_001.png b/v0.10.x/_images/sphx_glr_viz_dt_ellipsoids_001.png new file mode 100644 index 000000000..b7fc9784f Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_dt_ellipsoids_001.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_dt_ellipsoids_002.png b/v0.10.x/_images/sphx_glr_viz_dt_ellipsoids_002.png new file mode 100644 index 000000000..20800c902 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_dt_ellipsoids_002.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_dt_ellipsoids_003.png b/v0.10.x/_images/sphx_glr_viz_dt_ellipsoids_003.png new file mode 100644 index 000000000..1c4ed1126 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_dt_ellipsoids_003.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_dt_ellipsoids_004.png b/v0.10.x/_images/sphx_glr_viz_dt_ellipsoids_004.png new file mode 100644 index 000000000..b41839c94 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_dt_ellipsoids_004.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_dt_ellipsoids_005.png b/v0.10.x/_images/sphx_glr_viz_dt_ellipsoids_005.png new file mode 100644 index 000000000..f8d535e05 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_dt_ellipsoids_005.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_dt_ellipsoids_006.png b/v0.10.x/_images/sphx_glr_viz_dt_ellipsoids_006.png new file mode 100644 index 000000000..9536ce76d Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_dt_ellipsoids_006.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_dt_ellipsoids_007.png b/v0.10.x/_images/sphx_glr_viz_dt_ellipsoids_007.png new file mode 100644 index 000000000..306d4cd28 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_dt_ellipsoids_007.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_dt_ellipsoids_008.png b/v0.10.x/_images/sphx_glr_viz_dt_ellipsoids_008.png new file mode 100644 index 000000000..a754b9541 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_dt_ellipsoids_008.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_dt_ellipsoids_thumb.png b/v0.10.x/_images/sphx_glr_viz_dt_ellipsoids_thumb.png new file mode 100644 index 000000000..a1bf8f9a7 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_dt_ellipsoids_thumb.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_earth_animation_001.png b/v0.10.x/_images/sphx_glr_viz_earth_animation_001.png new file mode 100644 index 000000000..d72739551 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_earth_animation_001.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_earth_animation_thumb.png b/v0.10.x/_images/sphx_glr_viz_earth_animation_thumb.png new file mode 100644 index 000000000..c660072c2 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_earth_animation_thumb.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_earth_coordinates_001.png b/v0.10.x/_images/sphx_glr_viz_earth_coordinates_001.png new file mode 100644 index 000000000..88fdef469 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_earth_coordinates_001.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_earth_coordinates_thumb.png b/v0.10.x/_images/sphx_glr_viz_earth_coordinates_thumb.png new file mode 100644 index 000000000..d5c070511 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_earth_coordinates_thumb.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_emwave_animation_001.png b/v0.10.x/_images/sphx_glr_viz_emwave_animation_001.png new file mode 100644 index 000000000..24ab298c8 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_emwave_animation_001.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_emwave_animation_thumb.png b/v0.10.x/_images/sphx_glr_viz_emwave_animation_thumb.png new file mode 100644 index 000000000..dae818b49 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_emwave_animation_thumb.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_fiber_odf_001.png b/v0.10.x/_images/sphx_glr_viz_fiber_odf_001.png new file mode 100644 index 000000000..dd2914495 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_fiber_odf_001.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_fiber_odf_thumb.png b/v0.10.x/_images/sphx_glr_viz_fiber_odf_thumb.png new file mode 100644 index 000000000..55528ffd5 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_fiber_odf_thumb.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_fine_tuning_gl_context_001.png b/v0.10.x/_images/sphx_glr_viz_fine_tuning_gl_context_001.png new file mode 100644 index 000000000..c9ba00690 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_fine_tuning_gl_context_001.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_fine_tuning_gl_context_thumb.png b/v0.10.x/_images/sphx_glr_viz_fine_tuning_gl_context_thumb.png new file mode 100644 index 000000000..5451d5b61 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_fine_tuning_gl_context_thumb.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_fractals_001.png b/v0.10.x/_images/sphx_glr_viz_fractals_001.png new file mode 100644 index 000000000..81104a311 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_fractals_001.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_fractals_thumb.png b/v0.10.x/_images/sphx_glr_viz_fractals_thumb.png new file mode 100644 index 000000000..8f081fa91 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_fractals_thumb.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_gltf_001.png b/v0.10.x/_images/sphx_glr_viz_gltf_001.png new file mode 100644 index 000000000..ebb313538 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_gltf_001.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_gltf_animated_001.png b/v0.10.x/_images/sphx_glr_viz_gltf_animated_001.png new file mode 100644 index 000000000..f13abc9e1 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_gltf_animated_001.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_gltf_animated_thumb.png b/v0.10.x/_images/sphx_glr_viz_gltf_animated_thumb.png new file mode 100644 index 000000000..7583907ed Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_gltf_animated_thumb.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_gltf_export_001.png b/v0.10.x/_images/sphx_glr_viz_gltf_export_001.png new file mode 100644 index 000000000..17b512b0c Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_gltf_export_001.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_gltf_export_002.png b/v0.10.x/_images/sphx_glr_viz_gltf_export_002.png new file mode 100644 index 000000000..550b0d2b7 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_gltf_export_002.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_gltf_export_thumb.png b/v0.10.x/_images/sphx_glr_viz_gltf_export_thumb.png new file mode 100644 index 000000000..c7f835265 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_gltf_export_thumb.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_gltf_thumb.png b/v0.10.x/_images/sphx_glr_viz_gltf_thumb.png new file mode 100644 index 000000000..7b399485c Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_gltf_thumb.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_helical_motion_001.png b/v0.10.x/_images/sphx_glr_viz_helical_motion_001.png new file mode 100644 index 000000000..16d7686fb Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_helical_motion_001.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_helical_motion_thumb.png b/v0.10.x/_images/sphx_glr_viz_helical_motion_thumb.png new file mode 100644 index 000000000..1c41251f5 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_helical_motion_thumb.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_hierarchical_animation_001.png b/v0.10.x/_images/sphx_glr_viz_hierarchical_animation_001.png new file mode 100644 index 000000000..edaa43f0f Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_hierarchical_animation_001.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_hierarchical_animation_thumb.png b/v0.10.x/_images/sphx_glr_viz_hierarchical_animation_thumb.png new file mode 100644 index 000000000..181ad1bc9 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_hierarchical_animation_thumb.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_interaction_001.png b/v0.10.x/_images/sphx_glr_viz_interaction_001.png new file mode 100644 index 000000000..38f943467 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_interaction_001.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_interaction_thumb.png b/v0.10.x/_images/sphx_glr_viz_interaction_thumb.png new file mode 100644 index 000000000..4f661ceea Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_interaction_thumb.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_interpolators_001.png b/v0.10.x/_images/sphx_glr_viz_interpolators_001.png new file mode 100644 index 000000000..962cb361f Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_interpolators_001.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_interpolators_thumb.png b/v0.10.x/_images/sphx_glr_viz_interpolators_thumb.png new file mode 100644 index 000000000..188d9cd17 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_interpolators_thumb.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_introduction_001.png b/v0.10.x/_images/sphx_glr_viz_introduction_001.png new file mode 100644 index 000000000..406736aaa Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_introduction_001.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_introduction_thumb.png b/v0.10.x/_images/sphx_glr_viz_introduction_thumb.png new file mode 100644 index 000000000..5da955555 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_introduction_thumb.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_layout_001.png b/v0.10.x/_images/sphx_glr_viz_layout_001.png new file mode 100644 index 000000000..e54bc749c Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_layout_001.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_layout_thumb.png b/v0.10.x/_images/sphx_glr_viz_layout_thumb.png new file mode 100644 index 000000000..298098c9b Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_layout_thumb.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_markers_001.png b/v0.10.x/_images/sphx_glr_viz_markers_001.png new file mode 100644 index 000000000..3f14481bf Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_markers_001.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_markers_thumb.png b/v0.10.x/_images/sphx_glr_viz_markers_thumb.png new file mode 100644 index 000000000..23d30c28d Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_markers_thumb.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_morphing_001.png b/v0.10.x/_images/sphx_glr_viz_morphing_001.png new file mode 100644 index 000000000..6376237c0 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_morphing_001.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_morphing_thumb.png b/v0.10.x/_images/sphx_glr_viz_morphing_thumb.png new file mode 100644 index 000000000..e4b7dc1bc Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_morphing_thumb.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_multithread_thumb.png b/v0.10.x/_images/sphx_glr_viz_multithread_thumb.png new file mode 100644 index 000000000..8a5fed589 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_multithread_thumb.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_network_001.png b/v0.10.x/_images/sphx_glr_viz_network_001.png new file mode 100644 index 000000000..bdd7eda3c Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_network_001.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_network_animated_001.png b/v0.10.x/_images/sphx_glr_viz_network_animated_001.png new file mode 100644 index 000000000..ec5652267 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_network_animated_001.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_network_animated_thumb.png b/v0.10.x/_images/sphx_glr_viz_network_animated_thumb.png new file mode 100644 index 000000000..2212f9796 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_network_animated_thumb.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_network_thumb.png b/v0.10.x/_images/sphx_glr_viz_network_thumb.png new file mode 100644 index 000000000..d263d271e Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_network_thumb.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_no_interaction_001.png b/v0.10.x/_images/sphx_glr_viz_no_interaction_001.png new file mode 100644 index 000000000..7cba3c64f Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_no_interaction_001.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_no_interaction_thumb.png b/v0.10.x/_images/sphx_glr_viz_no_interaction_thumb.png new file mode 100644 index 000000000..103b85fa1 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_no_interaction_thumb.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_pbr_interactive_001.png b/v0.10.x/_images/sphx_glr_viz_pbr_interactive_001.png new file mode 100644 index 000000000..a273e4b39 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_pbr_interactive_001.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_pbr_interactive_thumb.png b/v0.10.x/_images/sphx_glr_viz_pbr_interactive_thumb.png new file mode 100644 index 000000000..18f1e0da9 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_pbr_interactive_thumb.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_pbr_spheres_001.png b/v0.10.x/_images/sphx_glr_viz_pbr_spheres_001.png new file mode 100644 index 000000000..3e6a3953b Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_pbr_spheres_001.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_pbr_spheres_thumb.png b/v0.10.x/_images/sphx_glr_viz_pbr_spheres_thumb.png new file mode 100644 index 000000000..63801be8c Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_pbr_spheres_thumb.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_picking_001.png b/v0.10.x/_images/sphx_glr_viz_picking_001.png new file mode 100644 index 000000000..97640a8b0 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_picking_001.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_picking_thumb.png b/v0.10.x/_images/sphx_glr_viz_picking_thumb.png new file mode 100644 index 000000000..783ac675f Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_picking_thumb.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_play_video_001.png b/v0.10.x/_images/sphx_glr_viz_play_video_001.png new file mode 100644 index 000000000..df15eb1e4 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_play_video_001.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_play_video_thumb.png b/v0.10.x/_images/sphx_glr_viz_play_video_thumb.png new file mode 100644 index 000000000..b38733230 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_play_video_thumb.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_principled_spheres_001.png b/v0.10.x/_images/sphx_glr_viz_principled_spheres_001.png new file mode 100644 index 000000000..3ae489dab Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_principled_spheres_001.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_principled_spheres_thumb.png b/v0.10.x/_images/sphx_glr_viz_principled_spheres_thumb.png new file mode 100644 index 000000000..0fd65b1c0 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_principled_spheres_thumb.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_radio_buttons_001.png b/v0.10.x/_images/sphx_glr_viz_radio_buttons_001.png new file mode 100644 index 000000000..e6a834c0f Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_radio_buttons_001.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_radio_buttons_thumb.png b/v0.10.x/_images/sphx_glr_viz_radio_buttons_thumb.png new file mode 100644 index 000000000..d7340aa0f Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_radio_buttons_thumb.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_robot_arm_animation_001.png b/v0.10.x/_images/sphx_glr_viz_robot_arm_animation_001.png new file mode 100644 index 000000000..50287e2bb Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_robot_arm_animation_001.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_robot_arm_animation_thumb.png b/v0.10.x/_images/sphx_glr_viz_robot_arm_animation_thumb.png new file mode 100644 index 000000000..2fecd5c51 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_robot_arm_animation_thumb.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_roi_contour_001.png b/v0.10.x/_images/sphx_glr_viz_roi_contour_001.png new file mode 100644 index 000000000..147ae44b1 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_roi_contour_001.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_roi_contour_thumb.png b/v0.10.x/_images/sphx_glr_viz_roi_contour_thumb.png new file mode 100644 index 000000000..b42153dc2 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_roi_contour_thumb.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_sdf_cylinder_001.png b/v0.10.x/_images/sphx_glr_viz_sdf_cylinder_001.png new file mode 100644 index 000000000..d71e56d24 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_sdf_cylinder_001.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_sdf_cylinder_002.png b/v0.10.x/_images/sphx_glr_viz_sdf_cylinder_002.png new file mode 100644 index 000000000..7b19e4c34 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_sdf_cylinder_002.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_sdf_cylinder_003.png b/v0.10.x/_images/sphx_glr_viz_sdf_cylinder_003.png new file mode 100644 index 000000000..f9f65fa48 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_sdf_cylinder_003.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_sdf_cylinder_thumb.png b/v0.10.x/_images/sphx_glr_viz_sdf_cylinder_thumb.png new file mode 100644 index 000000000..52314f00b Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_sdf_cylinder_thumb.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_sdfactor_001.png b/v0.10.x/_images/sphx_glr_viz_sdfactor_001.png new file mode 100644 index 000000000..c7c5156fd Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_sdfactor_001.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_sdfactor_thumb.png b/v0.10.x/_images/sphx_glr_viz_sdfactor_thumb.png new file mode 100644 index 000000000..84b39f3ac Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_sdfactor_thumb.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_selection_001.png b/v0.10.x/_images/sphx_glr_viz_selection_001.png new file mode 100644 index 000000000..f2651190c Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_selection_001.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_selection_thumb.png b/v0.10.x/_images/sphx_glr_viz_selection_thumb.png new file mode 100644 index 000000000..0aae8e3b0 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_selection_thumb.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_shader_001.png b/v0.10.x/_images/sphx_glr_viz_shader_001.png new file mode 100644 index 000000000..474fde90e Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_shader_001.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_shader_thumb.png b/v0.10.x/_images/sphx_glr_viz_shader_thumb.png new file mode 100644 index 000000000..2ada3ab11 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_shader_thumb.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_shapes_001.png b/v0.10.x/_images/sphx_glr_viz_shapes_001.png new file mode 100644 index 000000000..827da2da6 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_shapes_001.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_shapes_thumb.png b/v0.10.x/_images/sphx_glr_viz_shapes_thumb.png new file mode 100644 index 000000000..592f3808f Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_shapes_thumb.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_skinning_001.png b/v0.10.x/_images/sphx_glr_viz_skinning_001.png new file mode 100644 index 000000000..d4565e679 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_skinning_001.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_skinning_thumb.png b/v0.10.x/_images/sphx_glr_viz_skinning_thumb.png new file mode 100644 index 000000000..015c4479b Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_skinning_thumb.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_slice_001.png b/v0.10.x/_images/sphx_glr_viz_slice_001.png new file mode 100644 index 000000000..b4c4b063b Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_slice_001.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_slice_002.png b/v0.10.x/_images/sphx_glr_viz_slice_002.png new file mode 100644 index 000000000..b8bd2e8f1 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_slice_002.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_slice_003.png b/v0.10.x/_images/sphx_glr_viz_slice_003.png new file mode 100644 index 000000000..100892978 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_slice_003.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_slice_thumb.png b/v0.10.x/_images/sphx_glr_viz_slice_thumb.png new file mode 100644 index 000000000..31db9b7c0 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_slice_thumb.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_solar_system_001.png b/v0.10.x/_images/sphx_glr_viz_solar_system_001.png new file mode 100644 index 000000000..6e516ca85 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_solar_system_001.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_solar_system_thumb.png b/v0.10.x/_images/sphx_glr_viz_solar_system_thumb.png new file mode 100644 index 000000000..a8e5c5530 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_solar_system_thumb.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_sphere_001.png b/v0.10.x/_images/sphx_glr_viz_sphere_001.png new file mode 100644 index 000000000..2f9f44839 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_sphere_001.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_sphere_thumb.png b/v0.10.x/_images/sphx_glr_viz_sphere_thumb.png new file mode 100644 index 000000000..61218a64c Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_sphere_thumb.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_spiky_001.png b/v0.10.x/_images/sphx_glr_viz_spiky_001.png new file mode 100644 index 000000000..44d43e736 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_spiky_001.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_spiky_thumb.png b/v0.10.x/_images/sphx_glr_viz_spiky_thumb.png new file mode 100644 index 000000000..7fa01ed5d Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_spiky_thumb.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_spinbox_001.png b/v0.10.x/_images/sphx_glr_viz_spinbox_001.png new file mode 100644 index 000000000..76512e66d Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_spinbox_001.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_spinbox_thumb.png b/v0.10.x/_images/sphx_glr_viz_spinbox_thumb.png new file mode 100644 index 000000000..0833f3d87 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_spinbox_thumb.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_spline_interpolator_001.png b/v0.10.x/_images/sphx_glr_viz_spline_interpolator_001.png new file mode 100644 index 000000000..52a7f6e44 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_spline_interpolator_001.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_spline_interpolator_thumb.png b/v0.10.x/_images/sphx_glr_viz_spline_interpolator_thumb.png new file mode 100644 index 000000000..77d7323e5 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_spline_interpolator_thumb.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_surfaces_001.png b/v0.10.x/_images/sphx_glr_viz_surfaces_001.png new file mode 100644 index 000000000..0a95a9286 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_surfaces_001.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_surfaces_thumb.png b/v0.10.x/_images/sphx_glr_viz_surfaces_thumb.png new file mode 100644 index 000000000..706d234a5 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_surfaces_thumb.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_tab_001.png b/v0.10.x/_images/sphx_glr_viz_tab_001.png new file mode 100644 index 000000000..8f45b476f Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_tab_001.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_tab_thumb.png b/v0.10.x/_images/sphx_glr_viz_tab_thumb.png new file mode 100644 index 000000000..1df6eb150 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_tab_thumb.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_tesseract_001.png b/v0.10.x/_images/sphx_glr_viz_tesseract_001.png new file mode 100644 index 000000000..c7149f956 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_tesseract_001.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_tesseract_thumb.png b/v0.10.x/_images/sphx_glr_viz_tesseract_thumb.png new file mode 100644 index 000000000..0dacacf80 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_tesseract_thumb.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_texture_001.png b/v0.10.x/_images/sphx_glr_viz_texture_001.png new file mode 100644 index 000000000..3f28d30d0 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_texture_001.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_texture_thumb.png b/v0.10.x/_images/sphx_glr_viz_texture_thumb.png new file mode 100644 index 000000000..29e072d9a Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_texture_thumb.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_timeline_001.png b/v0.10.x/_images/sphx_glr_viz_timeline_001.png new file mode 100644 index 000000000..ba2d8bdc8 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_timeline_001.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_timeline_thumb.png b/v0.10.x/_images/sphx_glr_viz_timeline_thumb.png new file mode 100644 index 000000000..9df5905dc Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_timeline_thumb.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_timers_001.png b/v0.10.x/_images/sphx_glr_viz_timers_001.png new file mode 100644 index 000000000..758134637 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_timers_001.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_timers_thumb.png b/v0.10.x/_images/sphx_glr_viz_timers_thumb.png new file mode 100644 index 000000000..d6592e359 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_timers_thumb.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_ui_001.png b/v0.10.x/_images/sphx_glr_viz_ui_001.png new file mode 100644 index 000000000..13b0ff497 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_ui_001.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_ui_listbox_001.png b/v0.10.x/_images/sphx_glr_viz_ui_listbox_001.png new file mode 100644 index 000000000..77e566a57 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_ui_listbox_001.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_ui_listbox_thumb.png b/v0.10.x/_images/sphx_glr_viz_ui_listbox_thumb.png new file mode 100644 index 000000000..1c4150241 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_ui_listbox_thumb.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_ui_slider_001.png b/v0.10.x/_images/sphx_glr_viz_ui_slider_001.png new file mode 100644 index 000000000..ab9278e20 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_ui_slider_001.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_ui_slider_thumb.png b/v0.10.x/_images/sphx_glr_viz_ui_slider_thumb.png new file mode 100644 index 000000000..1c1f2dae1 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_ui_slider_thumb.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_ui_thumb.png b/v0.10.x/_images/sphx_glr_viz_ui_thumb.png new file mode 100644 index 000000000..13c67a6a5 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_ui_thumb.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_using_time_equations_001.png b/v0.10.x/_images/sphx_glr_viz_using_time_equations_001.png new file mode 100644 index 000000000..2c4206367 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_using_time_equations_001.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_using_time_equations_thumb.png b/v0.10.x/_images/sphx_glr_viz_using_time_equations_thumb.png new file mode 100644 index 000000000..969d439e2 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_using_time_equations_thumb.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_widget_001.png b/v0.10.x/_images/sphx_glr_viz_widget_001.png new file mode 100644 index 000000000..11661ab61 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_widget_001.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_widget_thumb.png b/v0.10.x/_images/sphx_glr_viz_widget_thumb.png new file mode 100644 index 000000000..5e3aab3b7 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_widget_thumb.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_wrecking_ball_001.png b/v0.10.x/_images/sphx_glr_viz_wrecking_ball_001.png new file mode 100644 index 000000000..d71f0ba15 Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_wrecking_ball_001.png differ diff --git a/v0.10.x/_images/sphx_glr_viz_wrecking_ball_thumb.png b/v0.10.x/_images/sphx_glr_viz_wrecking_ball_thumb.png new file mode 100644 index 000000000..dcbc2362e Binary files /dev/null and b/v0.10.x/_images/sphx_glr_viz_wrecking_ball_thumb.png differ diff --git a/v0.10.x/_images/suzanne.png b/v0.10.x/_images/suzanne.png new file mode 100644 index 000000000..e0c85c0da Binary files /dev/null and b/v0.10.x/_images/suzanne.png differ diff --git a/v0.10.x/_modules/fury.html b/v0.10.x/_modules/fury.html new file mode 100644 index 000000000..6a8fa68eb --- /dev/null +++ b/v0.10.x/_modules/fury.html @@ -0,0 +1,576 @@ + + + + + + + fury — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +

Source code for fury

+"""Init file for visualization package."""
+import warnings
+
+from fury.pkg_info import __version__, pkg_commit_hash
+
+
+
+[docs] +def get_info(verbose=False): + """Return dict describing the context of this package. + + Parameters + ---------- + pkg_path : str + path containing __init__.py for package + + Returns + ------- + context : dict + with named parameters of interest + + """ + import sys + from os.path import dirname + + import numpy + import scipy + import vtkmodules.vtkCommonCore as ccvtk + + from fury.optpkg import optional_package + + mpl, have_mpl, _ = optional_package('matplotlib') + dipy, have_dipy, _ = optional_package('dipy') + + install_type, commit_hash = pkg_commit_hash(dirname(__file__)) + + info = dict( + fury_version=__version__, + pkg_path=dirname(__file__), + commit_hash=commit_hash, + sys_version=sys.version, + sys_executable=sys.executable, + sys_platform=sys.platform, + numpy_version=numpy.__version__, + scipy_version=scipy.__version__, + vtk_version=ccvtk.vtkVersion.GetVTKVersion(), + ) + + d_mpl = dict(matplotlib_version=mpl.__version__) if have_mpl else {} + d_dipy = dict(dipy_version=dipy.__version__) if have_dipy else {} + + info.update(d_mpl) + info.update(d_dipy) + + if verbose: + print('\n'.join(['{0}: {1}'.format(k, v) for k, v in info.items()])) + + return info
+ + + +
+[docs] +def enable_warnings(warnings_origin=None): + """Enable global warnings. + + Parameters + ---------- + warnings_origin : list + list origin ['all', 'fury', 'vtk', 'matplotlib', ...] + + """ + warnings_origin = warnings_origin or ('all',) + + if 'all' in warnings_origin or 'vtk' in warnings_origin: + import vtkmodules.vtkCommonCore as ccvtk + + ccvtk.vtkObject.GlobalWarningDisplayOn()
+ + + +
+[docs] +def disable_warnings(warnings_origin=None): + """Disable global warnings. + + Parameters + ---------- + warnings_origin : list + list origin ['all', 'fury', 'vtk', 'matplotlib', ...] + + """ + warnings_origin = warnings_origin or ('all',) + + if 'all' in warnings_origin or 'vtk' in warnings_origin: + import vtkmodules.vtkCommonCore as ccvtk + + ccvtk.vtkObject.GlobalWarningDisplayOff()
+ + + +# We switch off the warning display during the release +if not ('post' in __version__) and not ('dev' in __version__): + disable_warnings() + +# Ignore this specific warning below from vtk < 8.2. +# FutureWarning: Conversion of the second argument of issubdtype from +# `complex` to `np.complexfloating` is deprecated. In future, it will be +# treated as `np.complex128 == np.dtype(complex).type`. +# assert not numpy.issubdtype(z.dtype, complex), \ +warnings.filterwarnings( + 'ignore', + message='Conversion of the second argument of' + ' issubdtype from `complex` to' + ' `np.complexfloating` is deprecated.*', + category=FutureWarning, +) +
+
+ + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/_modules/fury/actor.html b/v0.10.x/_modules/fury/actor.html new file mode 100644 index 000000000..85c6d4861 --- /dev/null +++ b/v0.10.x/_modules/fury/actor.html @@ -0,0 +1,4592 @@ + + + + + + + fury.actor — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +

Source code for fury.actor

+"""Module that provide actors to render."""
+
+import os
+import warnings
+from functools import partial
+
+import numpy as np
+
+import fury.primitive as fp
+from fury import layout
+from fury.actors.odf_slicer import OdfSlicerActor
+from fury.actors.peak import PeakActor
+from fury.actors.tensor import double_cone, main_dir_uncertainty, tensor_ellipsoid
+from fury.colormap import colormap_lookup_table
+from fury.deprecator import deprecate_with_version, deprecated_params
+from fury.io import load_image
+from fury.lib import (
+    VTK_UNSIGNED_CHAR,
+    Actor,
+    ArrowSource,
+    Assembly,
+    ButterflySubdivisionFilter,
+    CellArray,
+    CellPicker,
+    CleanPolyData,
+    ConeSource,
+    ContourFilter,
+    CylinderSource,
+    DiskSource,
+    FloatArray,
+    Follower,
+    ImageActor,
+    ImageData,
+    ImageMapToColors,
+    ImageReslice,
+    LinearExtrusionFilter,
+    LODActor,
+    LookupTable,
+    LoopSubdivisionFilter,
+    Matrix4x4,
+    OutlineFilter,
+    Points,
+    PolyData,
+    PolyDataMapper,
+    PolyDataMapper2D,
+    PolyDataNormals,
+    ScalarBarActor,
+    SphereSource,
+    SplineFilter,
+    TextActor3D,
+    Texture,
+    TexturedActor2D,
+    TexturedSphereSource,
+    TextureMapToPlane,
+    Transform,
+    TransformPolyDataFilter,
+    TriangleFilter,
+    TubeFilter,
+    VectorText,
+    numpy_support,
+)
+from fury.shaders import (
+    add_shader_callback,
+    attribute_to_actor,
+    compose_shader,
+    import_fury_shader,
+    replace_shader_in_actor,
+    shader_to_actor,
+)
+from fury.utils import (
+    apply_affine,
+    color_check,
+    fix_winding_order,
+    get_actor_from_primitive,
+    lines_to_vtk_polydata,
+    numpy_to_vtk_colors,
+    repeat_sources,
+    rgb_to_vtk,
+    set_input,
+    set_polydata_primitives_count,
+    set_polydata_triangles,
+    set_polydata_vertices,
+    shallow_copy,
+)
+
+
+
+[docs] +def slicer( + data, + affine=None, + value_range=None, + opacity=1.0, + lookup_colormap=None, + interpolation='linear', + picking_tol=0.025, +): + """Cut 3D scalar or rgb volumes into 2D images. + + Parameters + ---------- + data : array, shape (X, Y, Z) or (X, Y, Z, 3) + A grayscale or rgb 4D volume as a numpy array. If rgb then values + expected on the range [0, 255]. + affine : array, shape (4, 4) + Grid to space (usually RAS 1mm) transformation matrix. Default is None. + If None then the identity matrix is used. + value_range : None or tuple (2,) + If None then the values will be interpolated from (data.min(), + data.max()) to (0, 255). Otherwise from (value_range[0], + value_range[1]) to (0, 255). + opacity : float, optional + Opacity of 0 means completely transparent and 1 completely visible. + lookup_colormap : vtkLookupTable, optional + If None (default) then a grayscale map is created. + interpolation : string, optional + If 'linear' (default) then linear interpolation is used on the final + texture mapping. If 'nearest' then nearest neighbor interpolation is + used on the final texture mapping. + picking_tol : float, optional + The tolerance for the vtkCellPicker, specified as a fraction of + rendering window size. + + Returns + ------- + image_actor : ImageActor + An object that is capable of displaying different parts of the volume + as slices. The key method of this object is ``display_extent`` where + one can input grid coordinates and display the slice in space (or grid) + coordinates as calculated by the affine parameter. + + """ + if value_range is None: + value_range = (data.min(), data.max()) + + if data.ndim != 3: + if data.ndim == 4: + if data.shape[3] != 3: + raise ValueError('Only RGB 3D arrays are currently supported.') + else: + nb_components = 3 + else: + raise ValueError('Only 3D arrays are currently supported.') + else: + nb_components = 1 + + vol = data + + im = ImageData() + I, J, K = vol.shape[:3] + im.SetDimensions(I, J, K) + # for now setting up for 1x1x1 but transformation comes later. + voxsz = (1.0, 1.0, 1.0) + # im.SetOrigin(0,0,0) + im.SetSpacing(voxsz[2], voxsz[0], voxsz[1]) + + vtk_type = numpy_support.get_vtk_array_type(vol.dtype) + im.AllocateScalars(vtk_type, nb_components) + # im.AllocateScalars(VTK_UNSIGNED_CHAR, nb_components) + + # copy data + # what I do below is the same as what is + # commented here but much faster + # for index in ndindex(vol.shape): + # i, j, k = index + # im.SetScalarComponentFromFloat(i, j, k, 0, vol[i, j, k]) + vol = np.swapaxes(vol, 0, 2) + vol = np.ascontiguousarray(vol) + + if nb_components == 1: + vol = vol.ravel() + else: + vol = np.reshape(vol, [np.prod(vol.shape[:3]), vol.shape[3]]) + + uchar_array = numpy_support.numpy_to_vtk(vol, deep=0) + im.GetPointData().SetScalars(uchar_array) + + if affine is None: + affine = np.eye(4) + + # Set the transform (identity if none given) + transform = Transform() + transform_matrix = Matrix4x4() + transform_matrix.DeepCopy( + ( + affine[0][0], + affine[0][1], + affine[0][2], + affine[0][3], + affine[1][0], + affine[1][1], + affine[1][2], + affine[1][3], + affine[2][0], + affine[2][1], + affine[2][2], + affine[2][3], + affine[3][0], + affine[3][1], + affine[3][2], + affine[3][3], + ) + ) + transform.SetMatrix(transform_matrix) + transform.Inverse() + + # Set the reslicing + image_resliced = ImageReslice() + set_input(image_resliced, im) + image_resliced.SetResliceTransform(transform) + image_resliced.AutoCropOutputOn() + + # Adding this will allow to support anisotropic voxels + # and also gives the opportunity to slice per voxel coordinates + RZS = affine[:3, :3] + zooms = np.sqrt(np.sum(RZS * RZS, axis=0)) + image_resliced.SetOutputSpacing(*zooms) + + image_resliced.SetInterpolationModeToLinear() + image_resliced.Update() + + vtk_resliced_data = image_resliced.GetOutput() + + ex1, ex2, ey1, ey2, ez1, ez2 = vtk_resliced_data.GetExtent() + + resliced = numpy_support.vtk_to_numpy(vtk_resliced_data.GetPointData().GetScalars()) + + # swap axes here + if data.ndim == 4: + if data.shape[-1] == 3: + resliced = resliced.reshape(ez2 + 1, ey2 + 1, ex2 + 1, 3) + if data.ndim == 3: + resliced = resliced.reshape(ez2 + 1, ey2 + 1, ex2 + 1) + + class ImActor(ImageActor): + def __init__(self): + self.picker = CellPicker() + self.output = None + self.shape = None + self.outline_actor = None + + def input_connection(self, output): + + # outline only + outline = OutlineFilter() + outline.SetInputData(vtk_resliced_data) + outline_mapper = PolyDataMapper() + outline_mapper.SetInputConnection(outline.GetOutputPort()) + self.outline_actor = Actor() + self.outline_actor.SetMapper(outline_mapper) + self.outline_actor.GetProperty().SetColor(1, 0.5, 0) + self.outline_actor.GetProperty().SetLineWidth(5) + self.outline_actor.GetProperty().SetRenderLinesAsTubes(True) + # crucial + self.GetMapper().SetInputConnection(output.GetOutputPort()) + self.output = output + self.shape = (ex2 + 1, ey2 + 1, ez2 + 1) + + def display_extent(self, x1, x2, y1, y2, z1, z2): + self.SetDisplayExtent(x1, x2, y1, y2, z1, z2) + self.Update() + # bounds = self.GetBounds() + # xmin, xmax, ymin, ymax, zmin, zmax = bounds + # line = np.array([[xmin, ymin, zmin]]) + # self.outline_actor = actor.line() + + def display(self, x=None, y=None, z=None): + if x is None and y is None and z is None: + self.display_extent(ex1, ex2, ey1, ey2, ez2 // 2, ez2 // 2) + if x is not None: + self.display_extent(x, x, ey1, ey2, ez1, ez2) + if y is not None: + self.display_extent(ex1, ex2, y, y, ez1, ez2) + if z is not None: + self.display_extent(ex1, ex2, ey1, ey2, z, z) + + def resliced_array(self): + """Return resliced array as numpy array.""" + resliced = numpy_support.vtk_to_numpy( + vtk_resliced_data.GetPointData().GetScalars() + ) + + # swap axes here + if data.ndim == 4: + if data.shape[-1] == 3: + resliced = resliced.reshape(ez2 + 1, ey2 + 1, ex2 + 1, 3) + if data.ndim == 3: + resliced = resliced.reshape(ez2 + 1, ey2 + 1, ex2 + 1) + resliced = np.swapaxes(resliced, 0, 2) + resliced = np.ascontiguousarray(resliced) + return resliced + + def opacity(self, value): + self.GetProperty().SetOpacity(value) + + def tolerance(self, value): + self.picker.SetTolerance(value) + + def copy(self): + im_actor = ImActor() + im_actor.input_connection(self.output) + im_actor.SetDisplayExtent(*self.GetDisplayExtent()) + im_actor.opacity(self.GetOpacity()) + im_actor.tolerance(self.picker.GetTolerance()) + if interpolation == 'nearest': + im_actor.SetInterpolate(False) + else: + im_actor.SetInterpolate(True) + im_actor.GetMapper().BorderOn() + return im_actor + + def shallow_copy(self): + # TODO rename copy to shallow_copy + self.copy() + + r1, r2 = value_range + + image_actor = ImActor() + if nb_components == 1: + lut = lookup_colormap + if lookup_colormap is None: + # Create a black/white lookup table. + lut = colormap_lookup_table((r1, r2), (0, 0), (0, 0), (0, 1)) + + plane_colors = ImageMapToColors() + plane_colors.SetOutputFormatToRGB() + plane_colors.SetLookupTable(lut) + plane_colors.SetInputConnection(image_resliced.GetOutputPort()) + plane_colors.Update() + image_actor.input_connection(plane_colors) + else: + image_actor.input_connection(image_resliced) + image_actor.display() + image_actor.opacity(opacity) + image_actor.tolerance(picking_tol) + + if interpolation == 'nearest': + image_actor.SetInterpolate(False) + else: + image_actor.SetInterpolate(True) + + image_actor.GetMapper().BorderOn() + + return image_actor
+ + + +
+[docs] +def surface(vertices, faces=None, colors=None, smooth=None, subdivision=3): + """Generate a surface actor from an array of vertices. + + The color and smoothness of the surface can be customized by specifying + the type of subdivision algorithm and the number of subdivisions. + + Parameters + ---------- + vertices : array, shape (X, Y, Z) + The point cloud defining the surface. + faces : array + An array of precomputed triangulation for the point cloud. + It is an optional parameter, it is computed locally if None. + colors : (N, 3) array + Specifies the colors associated with each vertex in the + vertices array. Range should be 0 to 1. + Optional parameter, if not passed, all vertices + are colored white. + smooth : string - "loop" or "butterfly" + Defines the type of subdivision to be used + for smoothing the surface. + subdivision : integer, default = 3 + Defines the number of subdivisions to do for + each triangulation of the point cloud. + The higher the value, smoother the surface + but at the cost of higher computation. + + Returns + ------- + surface_actor : Actor + An Actor visualizing the final surface + computed from the point cloud is returned. + + """ + from scipy.spatial import Delaunay + + points = Points() + points.SetData(numpy_support.numpy_to_vtk(vertices)) + triangle_poly_data = PolyData() + triangle_poly_data.SetPoints(points) + + if colors is not None: + triangle_poly_data.GetPointData().SetScalars(numpy_to_vtk_colors(255 * colors)) + + if faces is None: + tri = Delaunay(vertices[:, [0, 1]]) + faces = np.array(tri.simplices, dtype='i8') + + set_polydata_triangles(triangle_poly_data, faces) + + clean_poly_data = CleanPolyData() + clean_poly_data.SetInputData(triangle_poly_data) + + mapper = PolyDataMapper() + surface_actor = Actor() + + if smooth is None: + mapper.SetInputData(triangle_poly_data) + surface_actor.SetMapper(mapper) + + elif smooth == 'loop': + smooth_loop = LoopSubdivisionFilter() + smooth_loop.SetNumberOfSubdivisions(subdivision) + smooth_loop.SetInputConnection(clean_poly_data.GetOutputPort()) + mapper.SetInputConnection(smooth_loop.GetOutputPort()) + surface_actor.SetMapper(mapper) + + elif smooth == 'butterfly': + smooth_butterfly = ButterflySubdivisionFilter() + smooth_butterfly.SetNumberOfSubdivisions(subdivision) + smooth_butterfly.SetInputConnection(clean_poly_data.GetOutputPort()) + mapper.SetInputConnection(smooth_butterfly.GetOutputPort()) + surface_actor.SetMapper(mapper) + + return surface_actor
+ + + +
+[docs] +def contour_from_roi(data, affine=None, color=np.array([1, 0, 0]), opacity=1): + """Generate surface actor from a binary ROI. + + The color and opacity of the surface can be customized. + + Parameters + ---------- + data : array, shape (X, Y, Z) + An ROI file that will be binarized and displayed. + affine : array, shape (4, 4) + Grid to space (usually RAS 1mm) transformation matrix. Default is None. + If None then the identity matrix is used. + color : (1, 3) ndarray + RGB values in [0,1]. + opacity : float + Opacity of surface between 0 and 1. + + Returns + ------- + contour_assembly : vtkAssembly + ROI surface object displayed in space + coordinates as calculated by the affine parameter. + + """ + if data.ndim != 3: + raise ValueError('Only 3D arrays are currently supported.') + + nb_components = 1 + + data = (data > 0) * 1 + vol = np.interp(data, xp=[data.min(), data.max()], fp=[0, 255]) + vol = vol.astype('uint8') + + im = ImageData() + di, dj, dk = vol.shape[:3] + im.SetDimensions(di, dj, dk) + voxsz = (1.0, 1.0, 1.0) + # im.SetOrigin(0,0,0) + im.SetSpacing(voxsz[2], voxsz[0], voxsz[1]) + im.AllocateScalars(VTK_UNSIGNED_CHAR, nb_components) + + # copy data + vol = np.swapaxes(vol, 0, 2) + vol = np.ascontiguousarray(vol) + + vol = vol.ravel() + + uchar_array = numpy_support.numpy_to_vtk(vol, deep=0) + im.GetPointData().SetScalars(uchar_array) + + if affine is None: + affine = np.eye(4) + + # Set the transform (identity if none given) + transform = Transform() + transform_matrix = Matrix4x4() + transform_matrix.DeepCopy( + ( + affine[0][0], + affine[0][1], + affine[0][2], + affine[0][3], + affine[1][0], + affine[1][1], + affine[1][2], + affine[1][3], + affine[2][0], + affine[2][1], + affine[2][2], + affine[2][3], + affine[3][0], + affine[3][1], + affine[3][2], + affine[3][3], + ) + ) + transform.SetMatrix(transform_matrix) + transform.Inverse() + + # Set the reslicing + image_resliced = ImageReslice() + set_input(image_resliced, im) + image_resliced.SetResliceTransform(transform) + image_resliced.AutoCropOutputOn() + + # Adding this will allow to support anisotropic voxels + # and also gives the opportunity to slice per voxel coordinates + + rzs = affine[:3, :3] + zooms = np.sqrt(np.sum(rzs * rzs, axis=0)) + image_resliced.SetOutputSpacing(*zooms) + + image_resliced.SetInterpolationModeToLinear() + image_resliced.Update() + + skin_extractor = ContourFilter() + skin_extractor.SetInputData(image_resliced.GetOutput()) + + skin_extractor.SetValue(0, 1) + skin_normals = PolyDataNormals() + skin_normals.SetInputConnection(skin_extractor.GetOutputPort()) + skin_normals.SetFeatureAngle(60.0) + + skin_mapper = PolyDataMapper() + skin_mapper.SetInputConnection(skin_normals.GetOutputPort()) + skin_mapper.ScalarVisibilityOff() + + skin_actor = Actor() + + skin_actor.SetMapper(skin_mapper) + skin_actor.GetProperty().SetColor(color[0], color[1], color[2]) + skin_actor.GetProperty().SetOpacity(opacity) + + return skin_actor
+ + + +
+[docs] +def contour_from_label(data, affine=None, color=None): + """Generate surface actor from a labeled Array. + + The color and opacity of individual surfaces can be customized. + + Parameters + ---------- + data : array, shape (X, Y, Z) + A labeled array file that will be binarized and displayed. + affine : array, shape (4, 4) + Grid to space (usually RAS 1mm) transformation matrix. Default is None. + If None then the identity matrix is used. + color : (N, 3) or (N, 4) ndarray + RGB/RGBA values in [0,1]. Default is None. + If None then random colors are used. + Alpha channel is set to 1 by default. + + Returns + ------- + contour_assembly : vtkAssembly + Array surface object displayed in space + coordinates as calculated by the affine parameter + in the order of their roi ids. + + """ + unique_roi_id = np.delete(np.unique(data), 0) + + nb_surfaces = len(unique_roi_id) + + unique_roi_surfaces = Assembly() + + if color is None: + color = np.random.rand(nb_surfaces, 3) + elif color.shape != (nb_surfaces, 3) and color.shape != (nb_surfaces, 4): + raise ValueError('Incorrect color array shape') + + if color.shape == (nb_surfaces, 4): + opacity = color[:, -1] + color = color[:, :-1] + else: + opacity = np.ones((nb_surfaces, 1)).astype(float) + + for i, roi_id in enumerate(unique_roi_id): + roi_data = np.isin(data, roi_id).astype(int) + roi_surface = contour_from_roi( + roi_data, affine, color=color[i], opacity=opacity[i] + ) + unique_roi_surfaces.AddPart(roi_surface) + + return unique_roi_surfaces
+ + + +
+[docs] +def streamtube( + lines, + colors=None, + opacity=1, + linewidth=0.1, + tube_sides=9, + lod=True, + lod_points=10**4, + lod_points_size=3, + spline_subdiv=None, + lookup_colormap=None, + replace_strips=False +): + """Use streamtubes to visualize polylines. + + Parameters + ---------- + lines : list + list of N curves represented as 2D ndarrays + colors : array (N, 3), list of arrays, tuple (3,), array (K,) + If None or False, a standard orientation colormap is used for every + line. + If one tuple of color is used. Then all streamlines will have the same + colour. + If an array (N, 3) is given, where N is equal to the number of lines. + Then every line is coloured with a different RGB color. + If a list of RGB arrays is given then every point of every line takes + a different color. + If an array (K, 3) is given, where K is the number of points of all + lines then every point is colored with a different RGB color. + If an array (K,) is given, where K is the number of points of all + lines then these are considered as the values to be used by the + colormap. + If an array (L,) is given, where L is the number of streamlines then + these are considered as the values to be used by the colormap per + streamline. + If an array (X, Y, Z) or (X, Y, Z, 3) is given then the values for the + colormap are interpolated automatically using trilinear interpolation. + opacity : float, optional + Takes values from 0 (fully transparent) to 1 (opaque). Default is 1. + linewidth : float, optional + Default is 0.01. + tube_sides : int, optional + Default is 9. + lod : bool, optional + Use LODActor(level of detail) rather than Actor. Default is True. + Level of detail actors do not render the full geometry when the + frame rate is low. + lod_points : int, optional + Number of points to be used when LOD is in effect. Default is 10000. + lod_points_size : int, optional + Size of points when lod is in effect. Default is 3. + spline_subdiv : int, optional + Number of splines subdivision to smooth streamtubes. Default is None. + lookup_colormap : vtkLookupTable, optional + Add a default lookup table to the colormap. Default is None which calls + :func:`fury.actor.colormap_lookup_table`. + replace_strips : bool, optional + If True it changes streamtube representation from triangle strips to + triangles. Useful with SelectionManager or PickingManager. + Default False. + + Examples + -------- + >>> import numpy as np + >>> from fury import actor, window + >>> scene = window.Scene() + >>> lines = [np.random.rand(10, 3), np.random.rand(20, 3)] + >>> colors = np.random.rand(2, 3) + >>> c = actor.streamtube(lines, colors) + >>> scene.add(c) + >>> #window.show(scene) + + Notes + ----- + Streamtubes can be heavy on GPU when loading many streamlines and + therefore, you may experience slow rendering time depending on system GPU. + A solution to this problem is to reduce the number of points in each + streamline. In Dipy we provide an algorithm that will reduce the number of + points on the straighter parts of the streamline but keep more points on + the curvier parts. This can be used in the following way:: + + from dipy.tracking.distances import approx_polygon_track + lines = [approx_polygon_track(line, 0.2) for line in lines] + + Alternatively we suggest using the ``line`` actor which is much more + efficient. + + See Also + -------- + :func:`fury.actor.line` + + """ + # Poly data with lines and colors + poly_data, color_is_scalar = lines_to_vtk_polydata(lines, colors) + next_input = poly_data + + # set primitives count + prim_count = len(lines) + set_polydata_primitives_count(poly_data, prim_count) + + # Set Normals + poly_normals = set_input(PolyDataNormals(), next_input) + poly_normals.ComputeCellNormalsOn() + poly_normals.ComputePointNormalsOn() + poly_normals.ConsistencyOn() + poly_normals.AutoOrientNormalsOn() + poly_normals.Update() + next_input = poly_normals.GetOutputPort() + + # Spline interpolation + if (spline_subdiv is not None) and (spline_subdiv > 0): + spline_filter = set_input(SplineFilter(), next_input) + spline_filter.SetSubdivideToSpecified() + spline_filter.SetNumberOfSubdivisions(spline_subdiv) + spline_filter.Update() + next_input = spline_filter.GetOutputPort() + + # Add thickness to the resulting lines + tube_filter = set_input(TubeFilter(), next_input) + tube_filter.SetNumberOfSides(tube_sides) + tube_filter.SetRadius(linewidth) + # TODO using the line above we will be able to visualize + # streamtubes of varying radius + # tube_filter.SetVaryRadiusToVaryRadiusByScalar() + tube_filter.CappingOn() + tube_filter.Update() + next_input = tube_filter.GetOutputPort() + + # Poly mapper + poly_mapper = set_input(PolyDataMapper(), next_input) + if replace_strips: + triangle_filter = set_input(TriangleFilter(), next_input) + poly_mapper = set_input(PolyDataMapper(), triangle_filter.GetOutputPort()) + + else: + poly_mapper = set_input(PolyDataMapper(), next_input) + poly_mapper.ScalarVisibilityOn() + poly_mapper.SetScalarModeToUsePointFieldData() + poly_mapper.SelectColorArray('colors') + poly_mapper.Update() + + # Color Scale with a lookup table + if color_is_scalar: + if lookup_colormap is None: + lookup_colormap = colormap_lookup_table() + poly_mapper.SetLookupTable(lookup_colormap) + poly_mapper.UseLookupTableScalarRangeOn() + poly_mapper.Update() + + # Set Actor + if lod: + actor = LODActor() + actor.SetNumberOfCloudPoints(lod_points) + actor.GetProperty().SetPointSize(lod_points_size) + else: + actor = Actor() + + actor.SetMapper(poly_mapper) + + actor.GetProperty().SetInterpolationToPhong() + actor.GetProperty().BackfaceCullingOn() + actor.GetProperty().SetOpacity(opacity) + + return actor
+ + + +
+[docs] +def line( + lines, + colors=None, + opacity=1, + linewidth=1, + spline_subdiv=None, + lod=True, + lod_points=10**4, + lod_points_size=3, + lookup_colormap=None, + depth_cue=False, + fake_tube=False, +): + """Create an actor for one or more lines. + + Parameters + ---------- + lines : list of arrays + colors : array (N, 3), list of arrays, tuple (3,), array (K,) + If None or False, a standard orientation colormap is used for every + line. + If one tuple of color is used. Then all streamlines will have the same + colour. + If an array (N, 3) is given, where N is equal to the number of lines. + Then every line is coloured with a different RGB color. + If a list of RGB arrays is given then every point of every line takes + a different color. + If an array (K, 3) is given, where K is the number of points of all + lines then every point is colored with a different RGB color. + If an array (K,) is given, where K is the number of points of all + lines then these are considered as the values to be used by the + colormap. + If an array (L,) is given, where L is the number of streamlines then + these are considered as the values to be used by the colormap per + streamline. + If an array (X, Y, Z) or (X, Y, Z, 3) is given then the values for the + colormap are interpolated automatically using trilinear interpolation. + opacity : float, optional + Takes values from 0 (fully transparent) to 1 (opaque). Default is 1. + linewidth : float, optional + Line thickness. Default is 1. + spline_subdiv : int, optional + Number of splines subdivision to smooth streamtubes. Default is None + which means no subdivision. + lod : bool, optional + Use LODActor(level of detail) rather than Actor. Default is True. + Level of detail actors do not render the full geometry when the + frame rate is low. + lod_points : int, optional + Number of points to be used when LOD is in effect. Default is 10000. + lod_points_size : int + Size of points when lod is in effect. Default is 3. + lookup_colormap : vtkLookupTable, optional + Add a default lookup table to the colormap. Default is None which calls + :func:`fury.actor.colormap_lookup_table`. + depth_cue : boolean, optional + Add a size depth cue so that lines shrink with distance to the camera. + Works best with linewidth <= 1. + fake_tube: boolean, optional + Add shading to lines to approximate the look of tubes. + + Returns + ------- + v : Actor or LODActor object + Line. + + Examples + -------- + >>> from fury import actor, window + >>> scene = window.Scene() + >>> lines = [np.random.rand(10, 3), np.random.rand(20, 3)] + >>> colors = np.random.rand(2, 3) + >>> c = actor.line(lines, colors) + >>> scene.add(c) + >>> #window.show(scene) + + """ + # Poly data with lines and colors + poly_data, color_is_scalar = lines_to_vtk_polydata(lines, colors) + next_input = poly_data + + # set primitives count + prim_count = len(lines) + set_polydata_primitives_count(poly_data, prim_count) + + # use spline interpolation + if (spline_subdiv is not None) and (spline_subdiv > 0): + spline_filter = set_input(SplineFilter(), next_input) + spline_filter.SetSubdivideToSpecified() + spline_filter.SetNumberOfSubdivisions(spline_subdiv) + spline_filter.Update() + next_input = spline_filter.GetOutputPort() + + poly_mapper = set_input(PolyDataMapper(), next_input) + poly_mapper.ScalarVisibilityOn() + poly_mapper.SetScalarModeToUsePointFieldData() + poly_mapper.SelectColorArray('colors') + poly_mapper.Update() + + # Color Scale with a lookup table + if color_is_scalar: + if lookup_colormap is None: + lookup_colormap = colormap_lookup_table() + + poly_mapper.SetLookupTable(lookup_colormap) + poly_mapper.UseLookupTableScalarRangeOn() + poly_mapper.Update() + + # Set Actor + if lod: + actor = LODActor() + actor.SetNumberOfCloudPoints(lod_points) + actor.GetProperty().SetPointSize(lod_points_size) + else: + actor = Actor() + + actor.SetMapper(poly_mapper) + actor.GetProperty().SetLineWidth(linewidth) + actor.GetProperty().SetOpacity(opacity) + + if depth_cue: + + def callback(_caller, _event, calldata=None): + program = calldata + if program is not None: + program.SetUniformf('linewidth', linewidth) + + replace_shader_in_actor(actor, 'geometry', import_fury_shader('line.geom')) + add_shader_callback(actor, callback) + + if fake_tube: + actor.GetProperty().SetRenderLinesAsTubes(True) + + return actor
+ + + +
+[docs] +def scalar_bar(lookup_table=None, title=' '): + """Default scalar bar actor for a given colormap (colorbar). + + Parameters + ---------- + lookup_table : vtkLookupTable or None + If None then ``colormap_lookup_table`` is called with default options. + title : str + + Returns + ------- + scalar_bar : vtkScalarBarActor + + See Also + -------- + :func:`fury.actor.colormap_lookup_table` + + """ + lookup_table_copy = LookupTable() + if lookup_table is None: + lookup_table = colormap_lookup_table() + # Deepcopy the lookup_table because sometimes vtkPolyDataMapper deletes it + lookup_table_copy.DeepCopy(lookup_table) + scalar_bar = ScalarBarActor() + scalar_bar.SetTitle(title) + scalar_bar.SetLookupTable(lookup_table_copy) + scalar_bar.SetNumberOfLabels(6) + + return scalar_bar
+ + + +
+[docs] +def axes( + scale=(1, 1, 1), colorx=(1, 0, 0), colory=(0, 1, 0), colorz=(0, 0, 1), opacity=1 +): + """Create an actor with the coordinate's system axes where + red = x, green = y, blue = z. + + Parameters + ---------- + scale : tuple (3,) + Axes size e.g. (100, 100, 100). Default is (1, 1, 1). + colorx : tuple (3,) + x-axis color. Default red (1, 0, 0). + colory : tuple (3,) + y-axis color. Default green (0, 1, 0). + colorz : tuple (3,) + z-axis color. Default blue (0, 0, 1). + opacity : float, optional + Takes values from 0 (fully transparent) to 1 (opaque). Default is 1. + + Returns + ------- + arrow_actor: Actor + + """ + centers = np.zeros((3, 3)) + dirs = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]]) + colors = np.array([colorx + (opacity,), colory + (opacity,), colorz + (opacity,)]) + + scales = np.asarray(scale) + arrow_actor = arrow(centers, dirs, colors, scales, repeat_primitive=False) + return arrow_actor
+ + + +
+[docs] +def odf_slicer( + odfs, + affine=None, + mask=None, + sphere=None, + scale=0.5, + norm=True, + radial_scale=True, + opacity=1.0, + colormap=None, + global_cm=False, + B_matrix=None, +): + """Create an actor for rendering a grid of ODFs given an array of + spherical function (SF) or spherical harmonics (SH) coefficients. + + Parameters + ---------- + odfs : ndarray + 4D ODFs array in SF or SH coefficients. If SH coefficients, + `B_matrix` must be supplied. + affine : array + 4x4 transformation array from native coordinates to world coordinates. + mask : ndarray + 3D mask to apply to ODF field. + sphere : dipy Sphere + The sphere used for SH to SF projection. If None, a default sphere + of 100 vertices will be used. + scale : float + Multiplicative factor to apply to ODF amplitudes. + norm : bool + Normalize SF amplitudes so that the maximum + ODF amplitude per voxel along a direction is 1. + radial_scale : bool + Scale sphere points by ODF values. + opacity : float + Takes values from 0 (fully transparent) to 1 (opaque). + colormap : None or str or tuple + The name of the colormap to use. Matplotlib colormaps are supported + (e.g., 'inferno'). A plain color can be supplied as a RGB tuple in + range [0, 255]. If None then a RGB colormap is used. + global_cm : bool + If True the colormap will be applied in all ODFs. If False + it will be applied individually at each voxel. + B_matrix : ndarray (n_coeffs, n_vertices) + Optional SH to SF matrix for projecting `odfs` given in SH + coefficients on the `sphere`. If None, then the input is assumed + to be expressed in SF coefficients. + + Returns + ------- + actor : OdfSlicerActor + Actor representing the ODF field. + + """ + # first we check if the input array is 4D + n_dims = len(odfs.shape) + if n_dims != 4: + raise ValueError( + 'Invalid number of dimensions for odfs. Expected 4 ' + 'dimensions, got {0} dimensions.'.format(n_dims) + ) + + # we generate indices for all nonzero voxels + valid_odf_mask = np.abs(odfs).max(axis=-1) > 0.0 + if mask is not None: + valid_odf_mask = np.logical_and(valid_odf_mask, mask) + indices = np.nonzero(valid_odf_mask) + shape = odfs.shape[:-1] + + if sphere is None: + # Use a default sphere with 100 vertices + vertices, faces = fp.prim_sphere('repulsion100') + else: + vertices = sphere.vertices + faces = fix_winding_order(vertices, sphere.faces, clockwise=True) + + if B_matrix is None: + if len(vertices) != odfs.shape[-1]: + raise ValueError( + 'Invalid number of SF coefficients. ' + 'Expected {0}, got {1}.'.format(len(vertices), odfs.shape[-1]) + ) + else: + if len(vertices) != B_matrix.shape[1]: + raise ValueError( + 'Invalid number of SH coefficients. ' + 'Expected {0}, got {1}.'.format(len(vertices), B_matrix.shape[1]) + ) + + # create and return an instance of OdfSlicerActor + return OdfSlicerActor( + odfs[indices], + vertices, + faces, + indices, + scale, + norm, + radial_scale, + shape, + global_cm, + colormap, + opacity, + affine, + B_matrix, + )
+ + + +def _makeNd(array, ndim): + """Pad as many 1s at the beginning of array's shape as are need to give + array ndim dimensions. + """ + new_shape = (1,) * (ndim - array.ndim) + array.shape + return array.reshape(new_shape) + + +def _roll_evals(evals, axis=-1): + """Check evals shape. + + Helper function to check that the evals provided to functions calculating + tensor statistics have the right shape. + + Parameters + ---------- + evals : array-like + Eigenvalues of a diffusion tensor. shape should be (...,3). + axis : int + The axis of the array which contains the 3 eigenvals. Default: -1 + + Returns + ------- + evals : array-like + Eigenvalues of a diffusion tensor, rolled so that the 3 eigenvals are + the last axis. + + """ + if evals.shape[-1] != 3: + msg = 'Expecting 3 eigenvalues, got {}'.format(evals.shape[-1]) + raise ValueError(msg) + + evals = np.rollaxis(evals, axis) + + return evals + + +def _fa(evals, axis=-1): + r"""Return Fractional anisotropy (FA) of a diffusion tensor. + + Parameters + ---------- + evals : array-like + Eigenvalues of a diffusion tensor. + axis : int + Axis of `evals` which contains 3 eigenvalues. + + Returns + ------- + fa : array + Calculated FA. Range is 0 <= FA <= 1. + + Notes + ----- + FA is calculated using the following equation: + + .. math:: + + FA = \sqrt{\frac{1}{2}\frac{(\lambda_1-\lambda_2)^2+(\lambda_1- + \lambda_3)^2+(\lambda_2-\lambda_3)^2}{\lambda_1^2+ + \lambda_2^2+\lambda_3^2}} + + """ + evals = _roll_evals(evals, axis) + # Make sure not to get nans + all_zero = (evals == 0).all(axis=0) + ev1, ev2, ev3 = evals + fa = np.sqrt( + 0.5 + * ((ev1 - ev2) ** 2 + (ev2 - ev3) ** 2 + (ev3 - ev1) ** 2) + / ((evals * evals).sum(0) + all_zero) + ) + + return fa + + +def _color_fa(fa, evecs): + r"""Color fractional anisotropy of diffusion tensor. + + Parameters + ---------- + fa : array-like + Array of the fractional anisotropy (can be 1D, 2D or 3D). + evecs : array-like + eigen vectors from the tensor model. + + Returns + ------- + rgb : Array with 3 channels for each color as the last dimension. + Colormap of the FA with red for the x value, y for the green + value and z for the blue value. + + Notes + ----- + It is computed from the clipped FA between 0 and 1 using the following + formula. + + .. math:: + + rgb = abs(max(\vec{e})) \times fa + + """ + if (fa.shape != evecs[..., 0, 0].shape) or ((3, 3) != evecs.shape[-2:]): + raise ValueError('Wrong number of dimensions for evecs') + + return np.abs(evecs[..., 0]) * np.clip(fa, 0, 1)[..., None] + + +
+[docs] +def tensor_slicer( + evals, + evecs, + affine=None, + mask=None, + sphere=None, + scale=2.2, + norm=True, + opacity=1.0, + scalar_colors=None, +): + """Slice many tensors as ellipsoids in native or world coordinates. + + Parameters + ---------- + evals : (3,) or (X, 3) or (X, Y, 3) or (X, Y, Z, 3) ndarray + eigenvalues + evecs : (3, 3) or (X, 3, 3) or (X, Y, 3, 3) or (X, Y, Z, 3, 3) ndarray + eigenvectors + affine : array + 4x4 transformation array from native coordinates to world coordinates* + mask : ndarray + 3D mask + sphere : Sphere + a sphere + scale : float + Distance between spheres. + norm : bool + Normalize `sphere_values`. + opacity : float + Takes values from 0 (fully transparent) to 1 (opaque). Default is 1. + scalar_colors : (3,) or (X, 3) or (X, Y, 3) or (X, Y, Z, 3) ndarray + RGB colors used to show the tensors + Default None, color the ellipsoids using ``color_fa`` + + Returns + ------- + tensor_actor : Actor + Ellipsoid + + """ + if not evals.shape == evecs.shape[:-1]: + raise RuntimeError( + "Eigenvalues shape {} is incompatible with eigenvectors' {}." + ' Please provide eigenvalue and' + ' eigenvector arrays that have compatible dimensions.'.format( + evals.shape, evecs.shape + ) + ) + + if mask is None: + mask = np.ones(evals.shape[:3], dtype=bool) + else: + mask = mask.astype(bool) + + szx, szy, szz = evals.shape[:3] + + class TensorSlicerActor(LODActor): + def __init__(self): + self.mapper = None + + def display_extent(self, x1, x2, y1, y2, z1, z2): + tmp_mask = np.zeros(evals.shape[:3], dtype=bool) + tmp_mask[x1 : x2 + 1, y1 : y2 + 1, z1 : z2 + 1] = True + tmp_mask = np.bitwise_and(tmp_mask, mask) + + self.mapper = _tensor_slicer_mapper( + evals=evals, + evecs=evecs, + affine=affine, + mask=tmp_mask, + sphere=sphere, + scale=scale, + norm=norm, + scalar_colors=scalar_colors, + ) + self.SetMapper(self.mapper) + + def display(self, x=None, y=None, z=None): + if x is None and y is None and z is None: + self.display_extent( + 0, + szx - 1, + 0, + szy - 1, + int(np.floor(szz / 2)), + int(np.floor(szz / 2)), + ) + if x is not None: + self.display_extent(x, x, 0, szy - 1, 0, szz - 1) + if y is not None: + self.display_extent(0, szx - 1, y, y, 0, szz - 1) + if z is not None: + self.display_extent(0, szx - 1, 0, szy - 1, z, z) + + tensor_actor = TensorSlicerActor() + tensor_actor.display_extent( + 0, szx - 1, 0, szy - 1, int(np.floor(szz / 2)), int(np.floor(szz / 2)) + ) + + tensor_actor.GetProperty().SetOpacity(opacity) + + return tensor_actor
+ + + +def _tensor_slicer_mapper( + evals, + evecs, + affine=None, + mask=None, + sphere=None, + scale=2.2, + norm=True, + scalar_colors=None, +): + """Return Helper function for slicing tensor fields. + + Parameters + ---------- + evals : (3,) or (X, 3) or (X, Y, 3) or (X, Y, Z, 3) ndarray + eigenvalues. + evecs : (3, 3) or (X, 3, 3) or (X, Y, 3, 3) or (X, Y, Z, 3, 3) ndarray + eigenvectors. + affine : array + 4x4 transformation array from native coordinates to world coordinates. + mask : ndarray + 3D mask. + sphere : Sphere + a sphere. + scale : float + Distance between spheres. + norm : bool + Normalize `sphere_values`. + scalar_colors : (3,) or (X, 3) or (X, Y, 3) or (X, Y, Z, 3) ndarray + RGB colors used to show the tensors + Default None, color the ellipsoids using ``color_fa`` + + Returns + ------- + mapper : vtkPolyDataMapper + Ellipsoid mapper + + """ + mask = np.ones(evals.shape[:3]) if mask is None else mask + + ijk = np.ascontiguousarray(np.array(np.nonzero(mask)).T) + if len(ijk) == 0: + return None + + if affine is not None: + ijk = np.ascontiguousarray(apply_affine(affine, ijk)) + + faces = np.asarray(sphere.faces, dtype=int) + vertices = sphere.vertices + + if scalar_colors is None: + # from dipy.reconst.dti import color_fa, fractional_anisotropy + cfa = _color_fa(_fa(evals), evecs) + else: + cfa = _makeNd(scalar_colors, 4) + + cols = np.zeros((ijk.shape[0],) + sphere.vertices.shape, dtype='f4') + + all_xyz = [] + all_faces = [] + for (k, center) in enumerate(ijk): + ea = evals[tuple(center.astype(int))] + if norm: + ea /= ea.max() + ea = np.diag(ea.copy()) + + ev = evecs[tuple(center.astype(int))].copy() + xyz = np.dot(ev, np.dot(ea, vertices.T)) + + xyz = xyz.T + all_xyz.append(scale * xyz + center) + all_faces.append(faces + k * xyz.shape[0]) + + cols[k, ...] = np.interp( + cfa[tuple(center.astype(int))], [0, 1], [0, 255] + ).astype('ubyte') + + all_xyz = np.ascontiguousarray(np.concatenate(all_xyz)) + all_xyz_vtk = numpy_support.numpy_to_vtk(all_xyz, deep=True) + + points = Points() + points.SetData(all_xyz_vtk) + + all_faces = np.concatenate(all_faces) + + cols = np.ascontiguousarray( + np.reshape(cols, (cols.shape[0] * cols.shape[1], cols.shape[2])), dtype='f4' + ) + + vtk_colors = numpy_support.numpy_to_vtk( + cols, deep=True, array_type=VTK_UNSIGNED_CHAR + ) + + vtk_colors.SetName('colors') + + polydata = PolyData() + polydata.SetPoints(points) + set_polydata_triangles(polydata, all_faces) + polydata.GetPointData().SetScalars(vtk_colors) + + mapper = PolyDataMapper() + mapper.SetInputData(polydata) + + return mapper + + +
+[docs] +def peak_slicer( + peaks_dirs, + peaks_values=None, + mask=None, + affine=None, + colors=(1, 0, 0), + opacity=1.0, + linewidth=1, + lod=False, + lod_points=10**4, + lod_points_size=3, + symmetric=True, +): + """Visualize peak directions as given from ``peaks_from_model``. + + Parameters + ---------- + peaks_dirs : ndarray + Peak directions. The shape of the array can be (M, 3) or (X, M, 3) or + (X, Y, M, 3) or (X, Y, Z, M, 3). + peaks_values : ndarray + Peak values. The shape of the array can be (M, ) or (X, M) or + (X, Y, M) or (X, Y, Z, M). + affine : array + 4x4 transformation array from native coordinates to world coordinates. + mask : ndarray + 3D mask. + colors : tuple or None + Default red color. If None then every peak gets an orientation color + in similarity to a DEC map. + opacity : float, optional + Takes values from 0 (fully transparent) to 1 (opaque). + linewidth : float, optional + Line thickness. Default is 1. + lod : bool + Use LODActor(level of detail) rather than Actor. + Default is False. Level of detail actors do not render the full + geometry when the frame rate is low. + lod_points : int + Number of points to be used when LOD is in effect. Default is 10000. + lod_points_size : int + Size of points when lod is in effect. Default is 3. + symmetric: bool, optional + If True, peaks are drawn for both peaks_dirs and -peaks_dirs. Else, + peaks are only drawn for directions given by peaks_dirs. Default is + True. + + Returns + ------- + peak_actor: Actor + + See Also + -------- + :func:`fury.actor.odf_slice` + + """ + peaks_dirs = np.asarray(peaks_dirs) + if peaks_dirs.ndim > 5: + raise ValueError('Wrong shape') + + peaks_dirs = _makeNd(peaks_dirs, 5) + if peaks_values is not None: + peaks_values = _makeNd(peaks_values, 4) + + grid_shape = np.array(peaks_dirs.shape[:3]) + + if mask is None: + mask = np.ones(grid_shape).astype(bool) + + class PeakSlicerActor(LODActor): + def __init__(self): + self.line = None + + def display_extent(self, x1, x2, y1, y2, z1, z2): + + tmp_mask = np.zeros(grid_shape, dtype=bool) + tmp_mask[x1 : x2 + 1, y1 : y2 + 1, z1 : z2 + 1] = True + tmp_mask = np.bitwise_and(tmp_mask, mask) + + ijk = np.ascontiguousarray(np.array(np.nonzero(tmp_mask)).T) + if len(ijk) == 0: + self.SetMapper(None) + return + if affine is not None: + ijk_trans = np.ascontiguousarray(apply_affine(affine, ijk)) + list_dirs = [] + for index, center in enumerate(ijk): + # center = tuple(center) + if affine is None: + xyz = center[:, None] + else: + xyz = ijk_trans[index][:, None] + xyz = xyz.T + for i in range(peaks_dirs[tuple(center)].shape[-2]): + + if peaks_values is not None: + pv = peaks_values[tuple(center)][i] + else: + pv = 1.0 + if symmetric: + dirs = np.vstack( + ( + -peaks_dirs[tuple(center)][i] * pv + xyz, + peaks_dirs[tuple(center)][i] * pv + xyz, + ) + ) + else: + dirs = np.vstack((xyz, peaks_dirs[tuple(center)][i] * pv + xyz)) + list_dirs.append(dirs) + + self.line = line( + list_dirs, + colors=colors, + opacity=opacity, + linewidth=linewidth, + lod=lod, + lod_points=lod_points, + lod_points_size=lod_points_size, + ) + + self.SetProperty(self.line.GetProperty()) + self.SetMapper(self.line.GetMapper()) + + def display(self, x=None, y=None, z=None): + if x is None and y is None and z is None: + self.display_extent( + 0, + szx - 1, + 0, + szy - 1, + int(np.floor(szz / 2)), + int(np.floor(szz / 2)), + ) + if x is not None: + self.display_extent(x, x, 0, szy - 1, 0, szz - 1) + if y is not None: + self.display_extent(0, szx - 1, y, y, 0, szz - 1) + if z is not None: + self.display_extent(0, szx - 1, 0, szy - 1, z, z) + + peak_actor = PeakSlicerActor() + + szx, szy, szz = grid_shape + peak_actor.display_extent( + 0, szx - 1, 0, szy - 1, int(np.floor(szz / 2)), int(np.floor(szz / 2)) + ) + + return peak_actor
+ + + +
+[docs] +def peak( + peaks_dirs, + peaks_values=None, + mask=None, + affine=None, + colors=None, + linewidth=1, + lookup_colormap=None, + symmetric=True, +): + """Visualize peak directions as given from ``peaks_from_model``. + + Parameters + ---------- + peaks_dirs : ndarray + Peak directions. The shape of the array should be (X, Y, Z, D, 3). + peaks_values : ndarray, optional + Peak values. The shape of the array should be (X, Y, Z, D). + affine : array, optional + 4x4 transformation array from native coordinates to world coordinates. + mask : ndarray, optional + 3D mask + colors : tuple or None, optional + Default None. If None then every peak gets an orientation color + in similarity to a DEC map. + lookup_colormap : vtkLookupTable, optional + Add a default lookup table to the colormap. Default is None which calls + :func:`fury.actor.colormap_lookup_table`. + linewidth : float, optional + Line thickness. Default is 1. + symmetric : bool, optional + If True, peaks are drawn for both peaks_dirs and -peaks_dirs. Else, + peaks are only drawn for directions given by peaks_dirs. Default is + True. + + Returns + ------- + peak_actor : PeakActor + Actor or LODActor representing the peaks directions and/or + magnitudes. + + Examples + -------- + >>> from fury import actor, window + >>> import numpy as np + >>> scene = window.Scene() + >>> peak_dirs = np.random.rand(3, 3, 3, 3, 3) + >>> c = actor.peak(peak_dirs) + >>> scene.add(c) + >>> #window.show(scene) + + """ + if peaks_dirs.ndim != 5: + raise ValueError( + 'Invalid peak directions. The shape of the structure ' + 'must be (XxYxZxDx3). Your data has {} dimensions.' + ''.format(peaks_dirs.ndim) + ) + if peaks_dirs.shape[4] != 3: + raise ValueError( + 'Invalid peak directions. The shape of the last ' + 'dimension must be 3. Your data has a last dimension ' + 'of {}.'.format(peaks_dirs.shape[4]) + ) + + dirs_shape = peaks_dirs.shape + + if peaks_values is not None: + if peaks_values.ndim != 4: + raise ValueError( + 'Invalid peak values. The shape of the structure ' + 'must be (XxYxZxD). Your data has {} dimensions.' + ''.format(peaks_values.ndim) + ) + vals_shape = peaks_values.shape + if vals_shape != dirs_shape[:4]: + raise ValueError( + 'Invalid peak values. The shape of the values ' + 'must coincide with the shape of the directions.' + ) + + valid_mask = np.abs(peaks_dirs).max(axis=(-2, -1)) > 0 + if mask is not None: + if mask.ndim != 3: + warnings.warn( + 'Invalid mask. The mask must be a 3D array. The ' + 'passed mask has {} dimensions. Ignoring passed ' + 'mask.'.format(mask.ndim), + UserWarning, + ) + elif mask.shape != dirs_shape[:3]: + warnings.warn( + 'Invalid mask. The shape of the mask must coincide ' + 'with the shape of the directions. Ignoring passed ' + 'mask.', + UserWarning, + ) + else: + valid_mask = np.logical_and(valid_mask, mask) + indices = np.nonzero(valid_mask) + + return PeakActor( + peaks_dirs, + indices, + values=peaks_values, + affine=affine, + colors=colors, + lookup_colormap=lookup_colormap, + linewidth=linewidth, + symmetric=symmetric, + )
+ + + +
+[docs] +def dot(points, colors=None, opacity=None, dot_size=5): + """Create one or more 3d points. + + Parameters + ---------- + points : ndarray, (N, 3) + dots positions. + colors : ndarray (N,3) or (N, 4) or tuple (3,) or tuple (4,) + RGB or RGBA (for opacity) R, G, B and A should be at the range [0, 1]. + opacity : float, optional + Takes values from 0 (fully transparent) to 1 (opaque). + If a value is given, each dot will have the same opacity otherwise + opacity is set to 1 by default, or is defined by Alpha parameter + in colors if given. + dot_size : int + + Returns + ------- + dot_actor: Actor + + See Also + -------- + :func:`fury.actor.point` + + """ + if points.ndim != 2: + raise ValueError( + 'Invalid points. The shape of the structure must be ' + '(Nx3). Your data has {} dimensions.'.format(points.ndim) + ) + + if points.shape[1] != 3: + raise ValueError( + 'Invalid points. The shape of the last dimension ' + 'must be 3. Your data has a last dimension of {}.'.format(points.shape[1]) + ) + + vtk_vertices = Points() + vtk_faces = CellArray() + + # Add points + for i in range(len(points)): + p = points[i] + idd = vtk_vertices.InsertNextPoint(p) + vtk_faces.InsertNextCell(1) + vtk_faces.InsertCellPoint(idd) + + color_tuple = color_check(len(points), colors) + color_array, global_opacity = color_tuple + + # Create a polydata object + polydata = PolyData() + polydata.SetPoints(vtk_vertices) + polydata.SetVerts(vtk_faces) + polydata.GetPointData().SetScalars(color_array) + + # set primitives count + prim_count = len(points) + set_polydata_primitives_count(polydata, prim_count) + + # Visualize + mapper = PolyDataMapper() + mapper.SetInputData(polydata) + + # Create an actor + poly_actor = Actor() + poly_actor.SetMapper(mapper) + + if opacity is not None: + poly_actor.GetProperty().SetOpacity(opacity) + elif global_opacity >= 0: + poly_actor.GetProperty().SetOpacity(global_opacity) + poly_actor.GetProperty().SetPointSize(dot_size) + + return poly_actor
+ + + +dots = deprecate_with_version( + message='dots function has been renamed dot', since='0.8.1', until='0.9.0' +)(dot) + + +
+[docs] +def point(points, colors, point_radius=0.1, phi=8, theta=8, opacity=1.0): + """Visualize points as sphere glyphs. + + Parameters + ---------- + points : ndarray, shape (N, 3) + colors : ndarray (N,3) or tuple (3,) + point_radius : float + phi : int + theta : int + opacity : float, optional + Takes values from 0 (fully transparent) to 1 (opaque). Default is 1. + + Returns + ------- + point_actor: Actor + + See Also + -------- + :func:`fury.actor.dot` + :func:`fury.actor.sphere` + + Examples + -------- + >>> from fury import window, actor + >>> scene = window.Scene() + >>> pts = np.random.rand(5, 3) + >>> point_actor = actor.point(pts, window.colors.coral) + >>> scene.add(point_actor) + >>> # window.show(scene) + + """ + return sphere( + centers=points, + colors=colors, + radii=point_radius, + phi=phi, + theta=theta, + vertices=None, + faces=None, + opacity=opacity, + )
+ + + +
+[docs] +def sphere( + centers, + colors, + radii=1.0, + phi=16, + theta=16, + vertices=None, + faces=None, + opacity=1, + use_primitive=False, +): + """Visualize one or many spheres with different colors and radii. + + Parameters + ---------- + centers : ndarray, shape (N, 3) + Spheres positions. + colors : ndarray (N,3) or (N, 4) or tuple (3,) or tuple (4,) + RGB or RGBA (for opacity) R, G, B and A should be at the range [0, 1]. + radii : float or ndarray, shape (N,) + Sphere radius. + phi : int, optional + Set the number of points in the latitude direction. + theta : int, optional + Set the number of points in the longitude direction. + vertices : ndarray, shape (N, 3) + The point cloud defining the sphere. + faces : ndarray, shape (M, 3) + If faces is None then a sphere is created based on theta and phi angles + If not then a sphere is created with the provided vertices and faces. + opacity : float, optional + Takes values from 0 (fully transparent) to 1 (opaque). Default is 1. + use_primitive : boolean, optional + If True, uses primitives to create an actor. + + Returns + ------- + sphere_actor: Actor + + Examples + -------- + >>> from fury import window, actor + >>> scene = window.Scene() + >>> centers = np.random.rand(5, 3) + >>> sphere_actor = actor.sphere(centers, window.colors.coral) + >>> scene.add(sphere_actor) + >>> # window.show(scene) + + """ + if not use_primitive: + src = SphereSource() if faces is None else None + + if src is not None: + src.SetRadius(1) + src.SetThetaResolution(theta) + src.SetPhiResolution(phi) + + sphere_actor = repeat_sources( + centers=centers, + colors=colors, + active_scalars=radii, + source=src, + vertices=vertices, + faces=faces, + ) + sphere_actor.GetProperty().SetOpacity(opacity) + return sphere_actor + + scales = radii + directions = (1, 0, 0) + + if faces is None and vertices is None: + vertices, faces = fp.prim_sphere(phi=phi, theta=theta) + + res = fp.repeat_primitive( + vertices, + faces, + directions=directions, + centers=centers, + colors=colors, + scales=scales, + ) + big_verts, big_faces, big_colors, _ = res + prim_count = len(centers) + sphere_actor = get_actor_from_primitive( + big_verts, big_faces, big_colors, prim_count=prim_count + ) + sphere_actor.GetProperty().SetOpacity(opacity) + return sphere_actor
+ + + +
+[docs] +def cylinder( + centers, + directions, + colors, + radius=0.05, + heights=1, + capped=False, + resolution=8, + vertices=None, + faces=None, + repeat_primitive=True, +): + """Visualize one or many cylinder with different features. + + Parameters + ---------- + centers : ndarray, shape (N, 3) + Cylinder positions. + directions : ndarray, shape (N, 3) + The orientation vector of the cylinder. + colors : ndarray (N,3) or (N, 4) or tuple (3,) or tuple (4,) + RGB or RGBA (for opacity) R, G, B and A should be at the range [0, 1]. + radius : float + cylinder radius. + heights : ndarray, shape (N) + The height of the cylinder. + capped : bool + Turn on/off whether to cap cylinder with polygons. Default (False). + resolution: int + Number of facets/sectors used to define cylinder. + vertices : ndarray, shape (N, 3) + The point cloud defining the sphere. + faces : ndarray, shape (M, 3) + If faces is None then a sphere is created based on theta and phi angles. + If not then a sphere is created with the provided vertices and faces. + repeat_primitive: bool + If True, cylinder will be generated with primitives + If False, repeat_sources will be invoked to use VTK filters for cylinder. + + Returns + ------- + cylinder_actor: Actor + + Examples + -------- + >>> from fury import window, actor + >>> scene = window.Scene() + >>> centers = np.random.rand(5, 3) + >>> dirs = np.random.rand(5, 3) + >>> heights = np.random.rand(5) + >>> actor = actor.cylinder(centers, dirs, (1, 1, 1), heights=heights) + >>> scene.add(actor) + >>> # window.show(scene) + + """ + if repeat_primitive: + + if resolution < 8: + # Sectors parameter should be greater than 7 in fp.prim_cylinder() + raise ValueError('resolution parameter should be greater than 7') + + verts, faces = fp.prim_cylinder( + radius=radius, + sectors=resolution, + capped=capped, + ) + res = fp.repeat_primitive( + verts, + faces, + centers=centers, + directions=directions, + colors=colors, + scales=heights, + ) + + big_verts, big_faces, big_colors, _ = res + prim_count = len(centers) + cylinder_actor = get_actor_from_primitive( + big_verts, big_faces, big_colors, prim_count=prim_count + ) + + else: + if faces is None: + src = CylinderSource() + src.SetCapping(capped) + src.SetResolution(resolution) + src.SetRadius(radius) + rotate = np.array([[0, 1, 0, 0], [-1, 0, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) + else: + src = None + rotate = None + + cylinder_actor = repeat_sources( + centers=centers, + colors=colors, + directions=directions, + active_scalars=heights, + source=src, + vertices=vertices, + faces=faces, + orientation=rotate, + ) + + return cylinder_actor
+ + + +
+[docs] +def disk( + centers, + directions, + colors, + rinner=0.3, + router=0.7, + cresolution=6, + rresolution=2, + vertices=None, + faces=None, +): + """Visualize one or many disks with different features. + + Parameters + ---------- + centers : ndarray, shape (N, 3) + Disk positions. + directions : ndarray, shape (N, 3) + The orientation vector of the disk. + colors : ndarray (N,3) or (N, 4) or tuple (3,) or tuple (4,) + RGB or RGBA (for opacity) R, G, B and A should be at the range [0, 1]. + rinner : float + disk inner radius, default: 0.3 + router : float + disk outer radius, default: 0.5 + cresolution: int, optional + Number of facets used to define perimeter of disk, default: 6 + rresolution: int, optional + Number of facets used radially, default: 2 + vertices : ndarray, shape (N, 3) + The point cloud defining the disk. + faces : ndarray, shape (M, 3) + If faces is None then a disk is created based on theta and phi angles. + If not then a disk is created with the provided vertices and faces. + + Returns + ------- + disk_actor: Actor + + Examples + -------- + >>> from fury import window, actor + >>> import numpy as np + >>> scene = window.Scene() + >>> centers = np.random.rand(5, 3) + >>> dirs = np.random.rand(5, 3) + >>> colors = np.random.rand(5, 4) + >>> actor = actor.disk(centers, dirs, colors, + >>> rinner=.1, router=.8, cresolution=30) + >>> scene.add(actor) + >>> window.show(scene) + + """ + if faces is None: + src = DiskSource() + src.SetCircumferentialResolution(cresolution) + src.SetRadialResolution(rresolution) + src.SetInnerRadius(rinner) + src.SetOuterRadius(router) + rotate = np.array([[0, 0, -1, 0], [0, 1, 0, 0], [1, 0, 0, 0], [0, 0, 0, 1]]) + else: + src = None + rotate = None + + disk_actor = repeat_sources( + centers=centers, + colors=colors, + directions=directions, + source=src, + vertices=vertices, + faces=faces, + orientation=rotate, + ) + + return disk_actor
+ + + +
+[docs] +def square(centers, directions=(1, 0, 0), colors=(1, 0, 0), scales=1): + """Visualize one or many squares with different features. + + Parameters + ---------- + centers : ndarray, shape (N, 3) + Square positions. + directions : ndarray, shape (N, 3), optional + The orientation vector of the square. + colors : ndarray (N,3) or (N, 4) or tuple (3,) or tuple (4,), optional + RGB or RGBA (for opacity) R, G, B and A should be at the range [0, 1]. + scales : int or ndarray (N,3) or tuple (3,), optional + Square size on each direction (x, y), default(1) + + Returns + ------- + sq_actor: Actor + + Examples + -------- + >>> from fury import window, actor + >>> scene = window.Scene() + >>> centers = np.random.rand(5, 3) + >>> dirs = np.random.rand(5, 3) + >>> sq_actor = actor.square(centers, dirs) + >>> scene.add(sq_actor) + >>> # window.show(scene) + + """ + verts, faces = fp.prim_square() + res = fp.repeat_primitive( + verts, + faces, + directions=directions, + centers=centers, + colors=colors, + scales=scales, + ) + + big_verts, big_faces, big_colors, _ = res + prim_count = len(centers) + sq_actor = get_actor_from_primitive( + big_verts, big_faces, big_colors, prim_count=prim_count + ) + sq_actor.GetProperty().BackfaceCullingOff() + return sq_actor
+ + + +
+[docs] +def rectangle(centers, directions=(1, 0, 0), colors=(1, 0, 0), scales=(1, 2, 0)): + """Visualize one or many rectangles with different features. + + Parameters + ---------- + centers : ndarray, shape (N, 3) + Rectangle positions. + directions : ndarray, shape (N, 3), optional + The orientation vector of the rectangle. + colors : ndarray (N,3) or (N, 4) or tuple (3,) or tuple (4,), optional + RGB or RGBA (for opacity) R, G, B and A should be at the range [0, 1]. + scales : int or ndarray (N,3) or tuple (3,), optional + Rectangle size on each direction (x, y), default(1) + + Returns + ------- + rect_actor: Actor + + See Also + -------- + :func:`fury.actor.square` + + Examples + -------- + >>> from fury import window, actor + >>> scene = window.Scene() + >>> centers = np.random.rand(5, 3) + >>> dirs = np.random.rand(5, 3) + >>> rect_actor = actor.rectangle(centers, dirs) + >>> scene.add(rect_actor) + >>> # window.show(scene) + + """ + return square(centers=centers, directions=directions, colors=colors, scales=scales)
+ + + +
+[docs] +@deprecated_params(['size', 'heights'], ['scales', 'scales'], since='0.6', until='0.8') +def box(centers, directions=(1, 0, 0), colors=(1, 0, 0), scales=(1, 2, 3)): + """Visualize one or many boxes with different features. + + Parameters + ---------- + centers : ndarray, shape (N, 3) + Box positions. + directions : ndarray, shape (N, 3), optional + The orientation vector of the box. + colors : ndarray (N,3) or (N, 4) or tuple (3,) or tuple (4,), optional + RGB or RGBA (for opacity) R, G, B and A should be at the range [0, 1]. + scales : int or ndarray (N,3) or tuple (3,), optional + Box size on each direction (x, y), default(1) + + Returns + ------- + box_actor: Actor + + Examples + -------- + >>> from fury import window, actor + >>> scene = window.Scene() + >>> centers = np.random.rand(5, 3) + >>> dirs = np.random.rand(5, 3) + >>> box_actor = actor.box(centers, dirs, (1, 1, 1)) + >>> scene.add(box_actor) + >>> # window.show(scene) + + """ + verts, faces = fp.prim_box() + res = fp.repeat_primitive( + verts, + faces, + directions=directions, + centers=centers, + colors=colors, + scales=scales, + ) + + big_verts, big_faces, big_colors, _ = res + prim_count = len(centers) + box_actor = get_actor_from_primitive( + big_verts, big_faces, big_colors, prim_count=prim_count + ) + return box_actor
+ + + +
+[docs] +@deprecated_params('heights', 'scales', since='0.6', until='0.8') +def cube(centers, directions=(1, 0, 0), colors=(1, 0, 0), scales=1): + """Visualize one or many cubes with different features. + + Parameters + ---------- + centers : ndarray, shape (N, 3) + Cube positions. + directions : ndarray, shape (N, 3), optional + The orientation vector of the cube. + colors : ndarray (N,3) or (N, 4) or tuple (3,) or tuple (4,), optional + RGB or RGBA (for opacity) R, G, B and A should be at the range [0, 1]. + scales : int or ndarray (N,3) or tuple (3,), optional + Cube size, default: 1 + + Returns + ------- + cube_actor: Actor + + Examples + -------- + >>> from fury import window, actor + >>> scene = window.Scene() + >>> centers = np.random.rand(5, 3) + >>> dirs = np.random.rand(5, 3) + >>> cube_actor = actor.cube(centers, dirs) + >>> scene.add(cube_actor) + >>> # window.show(scene) + + """ + return box(centers=centers, directions=directions, colors=colors, scales=scales)
+ + + +
+[docs] +def arrow( + centers, + directions, + colors, + heights=1.0, + resolution=10, + tip_length=0.35, + tip_radius=0.1, + shaft_radius=0.03, + scales=1, + vertices=None, + faces=None, + repeat_primitive=True, +): + """Visualize one or many arrows with different features. + + Parameters + ---------- + centers : ndarray, shape (N, 3) + Arrow positions. + directions : ndarray, shape (N, 3) + The orientation vector of the arrow. + colors : ndarray (N,3) or (N, 4) or tuple (3,) or tuple (4,) + RGB or RGBA (for opacity) R, G, B and A should be at the range [0, 1]. + heights : ndarray, shape (N) + The height of the arrow. + resolution : int + The resolution of the arrow. + tip_length : float + The tip size of the arrow (default: 0.35) + tip_radius : float + the tip radius of the arrow (default: 0.1) + shaft_radius : float + The shaft radius of the arrow (default: 0.03) + vertices : ndarray, shape (N, 3) + The point cloud defining the arrow. + faces : ndarray, shape (M, 3) + If faces is None then a arrow is created based on directions, heights + and resolution. If not then a arrow is created with the provided + vertices and faces. + + Returns + ------- + arrow_actor: Actor + + Examples + -------- + >>> from fury import window, actor + >>> scene = window.Scene() + >>> centers = np.random.rand(5, 3) + >>> directions = np.random.rand(5, 3) + >>> heights = np.random.rand(5) + >>> arrow_actor = actor.arrow(centers, directions, (1, 1, 1), heights) + >>> scene.add(arrow_actor) + >>> # window.show(scene) + + """ + if repeat_primitive: + vertices, faces = fp.prim_arrow() + res = fp.repeat_primitive( + vertices, + faces, + directions=directions, + centers=centers, + colors=colors, + scales=scales, + ) + big_vertices, big_faces, big_colors, _ = res + prim_count = len(centers) + arrow_actor = get_actor_from_primitive( + big_vertices, big_faces, big_colors, prim_count=prim_count + ) + return arrow_actor + + src = ArrowSource() if faces is None else None + + if src is not None: + src.SetTipResolution(resolution) + src.SetShaftResolution(resolution) + src.SetTipLength(tip_length) + src.SetTipRadius(tip_radius) + src.SetShaftRadius(shaft_radius) + + arrow_actor = repeat_sources( + centers=centers, + directions=directions, + colors=colors, + active_scalars=heights, + source=src, + vertices=vertices, + faces=faces, + ) + return arrow_actor
+ + + +
+[docs] +def cone( + centers, + directions, + colors, + heights=1.0, + resolution=10, + vertices=None, + faces=None, + use_primitive=True, +): + """Visualize one or many cones with different features. + + Parameters + ---------- + centers : ndarray, shape (N, 3) + Cone positions. + directions : ndarray, shape (N, 3) + The orientation vector of the cone. + colors : ndarray (N,3) or (N, 4) or tuple (3,) or tuple (4,) + RGB or RGBA (for opacity) R, G, B and A should be at the range [0, 1]. + heights : ndarray, shape (N) + The height of the cone. + resolution : int + The resolution of the cone. + vertices : ndarray, shape (N, 3) + The point cloud defining the cone. + faces : ndarray, shape (M, 3) + If faces is None then a cone is created based on directions, heights + and resolution. If not then a cone is created with the provided. + vertices and faces. + use_primitive : boolean, optional + If True uses primitives to create the cone actor. + + Returns + ------- + cone_actor: Actor + + Examples + -------- + >>> from fury import window, actor + >>> scene = window.Scene() + >>> centers = np.random.rand(5, 3) + >>> directions = np.random.rand(5, 3) + >>> heights = np.random.rand(5) + >>> cone_actor = actor.cone(centers, directions, (1, 1, 1), heights) + >>> scene.add(cone_actor) + >>> # window.show(scene) + + """ + if not use_primitive: + src = ConeSource() if faces is None else None + + if src is not None: + src.SetResolution(resolution) + + cone_actor = repeat_sources( + centers=centers, + directions=directions, + colors=colors, + active_scalars=heights, + source=src, + vertices=vertices, + faces=faces, + ) + return cone_actor + + if faces is None and vertices is None: + vertices, faces = fp.prim_cone(sectors=resolution) + + res = fp.repeat_primitive( + vertices, faces, centers, directions=directions, colors=colors, scales=heights + ) + + big_verts, big_faces, big_colors, _ = res + prim_count = len(centers) + cone_actor = get_actor_from_primitive( + big_verts, big_faces, big_colors, prim_count=prim_count + ) + + return cone_actor
+ + + +
+[docs] +def triangularprism(centers, directions=(1, 0, 0), colors=(1, 0, 0), scales=1): + """Visualize one or many regular triangular prisms with different features. + + Parameters + ---------- + centers : ndarray, shape (N, 3) + Triangular prism positions. + directions : ndarray, shape (N, 3) + The orientation vector(s) of the triangular prism(s). + colors : ndarray (N,3) or (N, 4) or tuple (3,) or tuple (4,) + RGB or RGBA (for opacity) R, G, B and A should be at the range [0, 1]. + scales : int or ndarray (N,3) or tuple (3,), optional + Triangular prism size on each direction (x, y), default(1) + + Returns + ------- + tprism_actor: Actor + + Examples + -------- + >>> from fury import window, actor + >>> scene = window.Scene() + >>> centers = np.random.rand(3, 3) + >>> dirs = np.random.rand(3, 3) + >>> colors = np.random.rand(3, 3) + >>> scales = np.random.rand(3, 1) + >>> actor = actor.triangularprism(centers, dirs, colors, scales) + >>> scene.add(actor) + >>> # window.show(scene) + + """ + verts, faces = fp.prim_triangularprism() + res = fp.repeat_primitive( + verts, + faces, + directions=directions, + centers=centers, + colors=colors, + scales=scales, + ) + big_verts, big_faces, big_colors, _ = res + prim_count = len(centers) + tprism_actor = get_actor_from_primitive( + big_verts, big_faces, big_colors, prim_count=prim_count + ) + return tprism_actor
+ + + +
+[docs] +def rhombicuboctahedron(centers, directions=(1, 0, 0), colors=(1, 0, 0), scales=1): + """Visualize one or many rhombicuboctahedron with different features. + + Parameters + ---------- + centers : ndarray, shape (N, 3) + Rhombicuboctahedron positions. + directions : ndarray, shape (N, 3) + The orientation vector(s) of the Rhombicuboctahedron(s). + colors : ndarray (N,3) or (N, 4) or tuple (3,) or tuple (4,) + RGB or RGBA (for opacity) R, G, B and A should be at the range [0, 1]. + scales : int or ndarray (N,3) or tuple (3,), optional + Rhombicuboctahedron size on each direction (x, y), default(1) + + Returns + ------- + rcoh_actor: Actor + + Examples + -------- + >>> from fury import window, actor + >>> scene = window.Scene() + >>> centers = np.random.rand(3, 3) + >>> dirs = np.random.rand(3, 3) + >>> colors = np.random.rand(3, 3) + >>> scales = np.random.rand(3, 1) + >>> actor = actor.rhombicuboctahedron(centers, dirs, colors, scales) + >>> scene.add(actor) + >>> # window.show(scene) + + """ + verts, faces = fp.prim_rhombicuboctahedron() + res = fp.repeat_primitive( + verts, + faces, + directions=directions, + centers=centers, + colors=colors, + scales=scales, + ) + big_verts, big_faces, big_colors, _ = res + prim_count = len(centers) + rcoh_actor = get_actor_from_primitive( + big_verts, big_faces, big_colors, prim_count=prim_count + ) + return rcoh_actor
+ + + +
+[docs] +def pentagonalprism(centers, directions=(1, 0, 0), colors=(1, 0, 0), scales=1): + """Visualize one or many pentagonal prisms with different features. + + Parameters + ---------- + centers : ndarray, shape (N, 3), optional + Pentagonal prism positions. + directions : ndarray, shape (N, 3), optional + The orientation vector of the pentagonal prism. + colors : ndarray (N,3) or (N, 4) or tuple (3,) or tuple (4,), optional + RGB or RGBA (for opacity) R, G, B and A should be at the range [0, 1]. + scales : int or ndarray (N,3) or tuple (3,), optional + Pentagonal prism size on each direction (x, y), default(1) + + Returns + ------- + pent_actor: Actor + + Examples + -------- + >>> import numpy as np + >>> from fury import window, actor + >>> scene = window.Scene() + >>> centers = np.random.rand(3, 3) + >>> dirs = np.random.rand(3, 3) + >>> colors = np.random.rand(3, 3) + >>> scales = np.random.rand(3, 1) + >>> actor_pentagonal = actor.pentagonalprism(centers, dirs, colors, scales) + >>> scene.add(actor_pentagonal) + >>> # window.show(scene) + + """ + verts, faces = fp.prim_pentagonalprism() + res = fp.repeat_primitive( + verts, + faces, + directions=directions, + centers=centers, + colors=colors, + scales=scales, + ) + + big_verts, big_faces, big_colors, _ = res + prim_count = len(centers) + pent_actor = get_actor_from_primitive( + big_verts, big_faces, big_colors, prim_count=prim_count + ) + return pent_actor
+ + + +
+[docs] +def octagonalprism(centers, directions=(1, 0, 0), colors=(1, 0, 0), scales=1): + """Visualize one or many octagonal prisms with different features. + + Parameters + ---------- + centers : ndarray, shape (N, 3) + Octagonal prism positions. + directions : ndarray, shape (N, 3) + The orientation vector of the octagonal prism. + colors : ndarray (N,3) or (N, 4) or tuple (3,) or tuple (4,) + RGB or RGBA (for opacity) R, G, B and A should be at the range [0, 1]. + scales : int or ndarray (N,3) or tuple (3,), optional + Octagonal prism size on each direction (x, y), default(1) + + Returns + ------- + oct_actor: Actor + + Examples + -------- + >>> from fury import window, actor + >>> scene = window.Scene() + >>> centers = np.random.rand(3, 3) + >>> dirs = np.random.rand(3, 3) + >>> colors = np.random.rand(3, 3) + >>> scales = np.random.rand(3, 1) + >>> actor = actor.octagonalprism(centers, dirs, colors, scales) + >>> scene.add(actor) + >>> # window.show(scene) + + """ + verts, faces = fp.prim_octagonalprism() + res = fp.repeat_primitive( + verts, + faces, + directions=directions, + centers=centers, + colors=colors, + scales=scales, + ) + + big_verts, big_faces, big_colors, _ = res + prim_count = len(centers) + oct_actor = get_actor_from_primitive( + big_verts, big_faces, big_colors, prim_count=prim_count + ) + return oct_actor
+ + + +
+[docs] +def frustum(centers, directions=(1, 0, 0), colors=(0, 1, 0), scales=1): + """Visualize one or many frustum pyramids with different features. + + Parameters + ---------- + centers : ndarray, shape (N, 3) + Frustum pyramid positions. + directions : ndarray, shape (N, 3) + The orientation vector of the frustum pyramid. + colors : ndarray (N,3) or (N, 4) or tuple (3,) or tuple (4,) + RGB or RGBA (for opacity) R, G, B and A should be at the range [0, 1]. + scales : int or ndarray (N,3) or tuple (3,), optional + Frustum pyramid size on each direction (x, y), default(1) + + Returns + ------- + frustum_actor: Actor + + Examples + -------- + >>> from fury import window, actor + >>> scene = window.Scene() + >>> centers = np.random.rand(4, 3) + >>> dirs = np.random.rand(4, 3) + >>> colors = np.random.rand(4, 3) + >>> scales = np.random.rand(4, 1) + >>> actor = actor.frustum(centers, dirs, colors, scales) + >>> scene.add(actor) + >>> # window.show(scene) + + """ + verts, faces = fp.prim_frustum() + res = fp.repeat_primitive( + verts, + faces, + directions=directions, + centers=centers, + colors=colors, + scales=scales, + ) + + big_verts, big_faces, big_colors, _ = res + prim_count = len(centers) + frustum_actor = get_actor_from_primitive( + big_verts, big_faces, big_colors, prim_count=prim_count + ) + return frustum_actor
+ + + +
+[docs] +def superquadric( + centers, roundness=(1, 1), directions=(1, 0, 0), colors=(1, 0, 0), scales=1 +): + """Visualize one or many superquadrics with different features. + + Parameters + ---------- + centers : ndarray, shape (N, 3) + Superquadrics positions. + roundness : ndarray, shape (N, 2) or tuple/list (2,), optional + parameters (Phi and Theta) that control the shape of the superquadric. + directions : ndarray, shape (N, 3) or tuple (3,), optional + The orientation vector of the cone. + colors : ndarray (N,3) or (N, 4) or tuple (3,) or tuple (4,) + RGB or RGBA (for opacity) R, G, B and A should be at the range [0, 1]. + scales : ndarray, shape (N) or (N,3) or float or int, optional + The height of the cone. + + Returns + ------- + spq_actor: Actor + + Examples + -------- + >>> from fury import window, actor + >>> scene = window.Scene() + >>> centers = np.random.rand(3, 3) * 10 + >>> directions = np.random.rand(3, 3) + >>> scales = np.random.rand(3) + >>> colors = np.random.rand(3, 3) + >>> roundness = np.array([[1, 1], [1, 2], [2, 1]]) + >>> sq_actor = actor.superquadric(centers, roundness=roundness, + ... directions=directions, + ... colors=colors, scales=scales) + >>> scene.add(sq_actor) + >>> # window.show(scene) + + """ + def have_2_dimensions(arr): + return all(isinstance(i, (list, tuple, np.ndarray)) for i in arr) + + # reshape roundness to a valid numpy array + if ( + isinstance(roundness, (tuple, list, np.ndarray)) + and len(roundness) == 2 + and not have_2_dimensions(roundness) + ): + roundness = np.array([roundness] * centers.shape[0]) + elif isinstance(roundness, np.ndarray) and len(roundness) == 1: + roundness = np.repeat(roundness, centers.shape[0], axis=0) + else: + roundness = np.array(roundness) + + res = fp.repeat_primitive_function( + func=fp.prim_superquadric, + centers=centers, + func_args=roundness, + directions=directions, + colors=colors, + scales=scales, + ) + + big_verts, big_faces, big_colors, _ = res + prim_count = len(centers) + spq_actor = get_actor_from_primitive( + big_verts, big_faces, big_colors, prim_count=prim_count + ) + return spq_actor
+ + + +
+[docs] +def billboard( + centers, + colors=(0, 1, 0), + scales=1, + vs_dec=None, + vs_impl=None, + gs_prog=None, + fs_dec=None, + fs_impl=None, + bb_type='spherical' +): + """Create a billboard actor. + - + Billboards are 2D elements placed in a 3D world. They offer possibility to + draw different shapes/elements at the fragment shader level. + + Parameters + ---------- + centers : ndarray, shape (N, 3) + Billboard positions. + colors : ndarray (N,3) or (N, 4) or tuple (3,) or tuple (4,) + RGB or RGBA (for opacity) R, G, B and A should be at the range [0, 1]. + scales : ndarray, shape (N) or (N,3) or float or int, optional + The scale of the billboards. + vs_dec : str or list of str, optional + Vertex Shader code that contains all variable/function declarations. + vs_impl : str or list of str, optional + Vertex Shaders code that contains all variable/function + implementations. + gs_prog : str, optional + Geometry Shader program. + fs_dec : str or list of str, optional + Fragment Shaders code that contains all variable/function declarations. + fs_impl : str or list of str, optional + Fragment Shaders code that contains all variable/function + implementation. + bb_type : str, optional + Type of billboard (spherical, cylindrical_x, cylindrical_y). + If spherical, billboard will always face the camera. + If cylindrical_x or cylindrical_y, billboard will face the camera only + when rotating around x-axis and y-axis respectively. + + Returns + ------- + billboard_actor: Actor + + """ + verts, faces = fp.prim_square() + res = fp.repeat_primitive( + verts, faces, centers=centers, colors=colors, scales=scales + ) + + big_verts, big_faces, big_colors, big_centers = res + + prim_count = len(centers) + bb_actor = get_actor_from_primitive( + big_verts, big_faces, big_colors, prim_count=prim_count + ) + bb_actor.GetMapper().SetVBOShiftScaleMethod(False) + bb_actor.GetProperty().BackfaceCullingOff() + attribute_to_actor(bb_actor, big_centers, 'center') + + bb_norm = import_fury_shader(os.path.join('utils', + 'billboard_normalization.glsl')) + + if bb_type.lower() == 'cylindrical_x': + bb_type_sd = import_fury_shader(os.path.join('billboard', + 'cylindrical_x.glsl') + ) + v_pos_mc = \ + """ + vec3 vertexPositionMC = cylindricalXVertexPos(center, MCVCMatrix, + normalizedVertexMCVSOutput, shape); + """ + elif bb_type.lower() == 'cylindrical_y': + bb_type_sd = import_fury_shader(os.path.join('billboard', + 'cylindrical_y.glsl') + ) + v_pos_mc = \ + """ + vec3 vertexPositionMC = cylindricalYVertexPos(center,MCVCMatrix, + normalizedVertexMCVSOutput, shape); + """ + elif bb_type.lower() == 'spherical': + bb_type_sd = import_fury_shader(os.path.join('billboard', + 'spherical.glsl')) + v_pos_mc = \ + """ + vec3 vertexPositionMC = sphericalVertexPos(center, MCVCMatrix, + normalizedVertexMCVSOutput, shape); + """ + else: + bb_type_sd = import_fury_shader(os.path.join('billboard', + 'spherical.glsl')) + v_pos_mc = \ + """ + vec3 vertexPositionMC = sphericalVertexPos(center, MCVCMatrix, + normalizedVertexMCVSOutput, shape); + """ + warnings.warn('Invalid option. The billboard will be generated ' + 'with the default spherical option. ', UserWarning) + + gl_position = \ + ''' + gl_Position = MCDCMatrix * vec4(vertexPositionMC, 1.); + ''' + + billboard_dec_vert = \ + ''' + /* Billboard vertex shader declaration */ + in vec3 center; + + out vec3 centerVertexMCVSOutput; + out vec3 normalizedVertexMCVSOutput; + ''' + + billboard_impl_vert = \ + ''' + /* Billboard vertex shader implementation */ + centerVertexMCVSOutput = center; + normalizedVertexMCVSOutput = bbNorm(vertexMC.xyz, center); + float scalingFactor = 1. / abs(normalizedVertexMCVSOutput.x); + float size = abs((vertexMC.xyz - center).x) * 2; + vec2 shape = vec2(size, size); // Fixes the scaling issue + ''' + + billboard_dec_frag = \ + ''' + /* Billboard fragment shader declaration */ + in vec3 centerVertexMCVSOutput; + in vec3 normalizedVertexMCVSOutput; + ''' + + billboard_impl_frag = \ + ''' + /* Billboard Fragment shader implementation */ + // Renaming variables passed from the Vertex Shader + vec3 color = vertexColorVSOutput.rgb; + vec3 point = normalizedVertexMCVSOutput; + fragOutput0 = vec4(color, 1.); + ''' + + billboard_vert_impl = compose_shader( + [billboard_impl_vert, v_pos_mc, gl_position]) + + vs_dec_code = compose_shader( + [billboard_dec_vert, compose_shader(vs_dec), bb_norm, bb_type_sd]) + vs_impl_code = compose_shader( + [compose_shader(vs_impl), billboard_vert_impl]) + + gs_code = compose_shader(gs_prog) + fs_dec_code = compose_shader( + [billboard_dec_frag, compose_shader(fs_dec)] + ) + fs_impl_code = compose_shader( + [billboard_impl_frag, compose_shader(fs_impl)] + ) + + shader_to_actor(bb_actor, 'vertex', impl_code=vs_impl_code, + decl_code=vs_dec_code) + replace_shader_in_actor(bb_actor, 'geometry', gs_code) + shader_to_actor(bb_actor, 'fragment', decl_code=fs_dec_code) + shader_to_actor(bb_actor, 'fragment', impl_code=fs_impl_code, + block='light') + + return bb_actor
+ + + +
+[docs] +def vector_text( + text='Origin', + pos=(0, 0, 0), + scale=(0.2, 0.2, 0.2), + color=(1, 1, 1), + direction=(0, 0, 1), + extrusion=0.0, + align_center=False, +): + """Create a label actor. + + This actor will always face the camera. + + Parameters + ---------- + text : str + Text for the label. + pos : (3,) array_like, optional + Left down position of the label. + scale : (3,) array_like + Changes the size of the label. + color : (3,) array_like + Label color as ``(r,g,b)`` tuple. + direction : (3,) array_like, optional, default: (0, 0, 1) + The direction of the label. If None, label will follow the camera. + extrusion : float, optional + The extrusion amount of the text in Z axis. + align_center : bool, optional, default: True + If `True`, the anchor of the actor will be the center of the text. + If `False`, the anchor will be at the left bottom of the text. + + Returns + ------- + l : Actor object + Label. + + Examples + -------- + >>> from fury import window, actor + >>> scene = window.Scene() + >>> l = actor.vector_text(text='Hello') + >>> scene.add(l) + >>> # window.show(scene) + + """ + atext = VectorText() + atext.SetText(text) + textm = PolyDataMapper() + + if extrusion: + extruded_text = LinearExtrusionFilter() + extruded_text.SetInputConnection(atext.GetOutputPort()) + extruded_text.SetExtrusionTypeToNormalExtrusion() + extruded_text.SetVector(0, 0, extrusion) + atext = extruded_text + + trans_matrix = Transform() + trans_matrix.PostMultiply() + + if direction is None: + # set text to follow the camera if direction is None. + texta = Follower() + + def add_to_scene(scene): + texta.SetCamera(scene.GetActiveCamera()) + scene.AddActor(texta) + + texta.add_to_scene = add_to_scene + + else: + texta = Actor() + textm.SetInputConnection(atext.GetOutputPort()) + + orig_dir = [0, 0, 1] + direction = np.array(direction, dtype=float) + direction /= np.linalg.norm(direction) + normal_vec = np.cross(orig_dir, direction) + angle = np.arccos(np.dot(orig_dir, direction)) + trans_matrix.RotateWXYZ(np.rad2deg(angle), *normal_vec) + + trans_matrix.Scale(*scale[0:2], 1) + + plan = TransformPolyDataFilter() + plan.SetInputConnection(atext.GetOutputPort()) + plan.SetTransform(trans_matrix) + textm.SetInputConnection(plan.GetOutputPort()) + + texta.SetMapper(textm) + + texta.GetProperty().SetColor(color) + + # Set rotation origin to the center of the text is following the camera + if align_center or direction is None: + trans_matrix.Translate(-np.array(textm.GetCenter())) + + texta.SetPosition(*pos) + return texta
+ + + +label = deprecate_with_version( + message='Label function has been renamed' ' vector_text', + since='0.7.1', + until='0.9.0', +)(vector_text) + + +
+[docs] +def text_3d( + text, + position=(0, 0, 0), + color=(1, 1, 1), + font_size=12, + font_family='Arial', + justification='left', + vertical_justification='bottom', + bold=False, + italic=False, + shadow=False, +): + """Generate 2D text that lives in the 3D world. + + Parameters + ---------- + text : str + position : tuple + color : tuple + font_size : int + font_family : str + justification : str + Left, center or right (default left). + vertical_justification : str + Bottom, middle or top (default bottom). + bold : bool + italic : bool + shadow : bool + + Returns + ------- + Text3D + + """ + class Text3D(TextActor3D): + def message(self, text): + self.set_message(text) + + def set_message(self, text): + self.SetInput(text) + + def get_message(self): + return self.GetInput() + + def font_size(self, size): + self.GetTextProperty().SetFontSize(24) + text_actor.SetScale((1.0 / 24.0 * size,) * 3) + + def font_family(self, _family='Arial'): + self.GetTextProperty().SetFontFamilyToArial() + + def justification(self, justification): + tprop = self.GetTextProperty() + if justification == 'left': + tprop.SetJustificationToLeft() + elif justification == 'center': + tprop.SetJustificationToCentered() + elif justification == 'right': + tprop.SetJustificationToRight() + else: + raise ValueError("Unknown justification: '{}'".format(justification)) + + def vertical_justification(self, justification): + tprop = self.GetTextProperty() + if justification == 'top': + tprop.SetVerticalJustificationToTop() + elif justification == 'middle': + tprop.SetVerticalJustificationToCentered() + elif justification == 'bottom': + tprop.SetVerticalJustificationToBottom() + else: + raise ValueError( + "Unknown vertical justification: '{}'".format(justification) + ) + + def font_style(self, bold=False, italic=False, shadow=False): + tprop = self.GetTextProperty() + if bold: + tprop.BoldOn() + else: + tprop.BoldOff() + if italic: + tprop.ItalicOn() + else: + tprop.ItalicOff() + if shadow: + tprop.ShadowOn() + else: + tprop.ShadowOff() + + def color(self, color): + self.GetTextProperty().SetColor(*color) + + def set_position(self, position): + self.SetPosition(position) + + def get_position(self): + return self.GetPosition() + + text_actor = Text3D() + text_actor.message(text) + text_actor.font_size(font_size) + text_actor.set_position(position) + text_actor.font_family(font_family) + text_actor.font_style(bold, italic, shadow) + text_actor.color(color) + text_actor.justification(justification) + text_actor.vertical_justification(vertical_justification) + + return text_actor
+ + + +
+[docs] +class Container: + """Provides functionalities for grouping multiple actors using a given + layout. + + Attributes + ---------- + anchor : 3-tuple of float + Anchor of this container used when laying out items in a container. + The anchor point is relative to the center of the container. + Default: (0, 0, 0). + + padding : 6-tuple of float + Padding around this container bounding box. The 6-tuple represents + (pad_x_neg, pad_x_pos, pad_y_neg, pad_y_pos, pad_z_neg, pad_z_pos). + Default: (0, 0, 0, 0, 0, 0). + + """ + +
+[docs] + def __init__(self, layout=layout.Layout()): + """Parameters + ---------- + layout : ``fury.layout.Layout`` object + Items of this container will be arranged according to `layout`. + + """ + self.layout = layout + self._items = [] + self._need_update = True + self._position = np.zeros(3) + self._visibility = True + self.anchor = np.zeros(3) + self.padding = np.zeros(6)
+ + + @property + def items(self): + if self._need_update: + self.update() + + return self._items + +
+[docs] + def add(self, *items, **kwargs): + """Adds some items to this container. + + Parameters + ---------- + items : `vtkProp3D` objects + Items to add to this container. + borrow : bool + If True the items are added as-is, otherwise a shallow copy is + made first. If you intend to reuse the items elsewhere you + should set `borrow=False`. Default: True. + + """ + self._need_update = True + + for item in items: + if not kwargs.get('borrow', True): + item = shallow_copy(item) + + self._items.append(item)
+ + +
+[docs] + def clear(self): + """Clears all items of this container.""" + self._need_update = True + del self._items[:]
+ + +
+[docs] + def update(self): + """Updates the position of the items of this container.""" + self.layout.apply(self._items) + self._need_update = False
+ + +
+[docs] + def add_to_scene(self, scene): + """Adds the items of this container to a given scene.""" + for item in self.items: + if isinstance(item, Container): + item.add_to_scene(scene) + else: + scene.add(item)
+ + +
+[docs] + def remove_from_scene(self, scene): + """Removes the items of this container from a given scene.""" + for item in self.items: + if isinstance(item, Container): + item.remove_from_scene(scene) + else: + scene.rm(item)
+ + +
+[docs] + def GetBounds(self): + """Get the bounds of the container.""" + bounds = np.zeros(6) # x1, x2, y1, y2, z1, z2 + bounds[::2] = np.inf # x1, y1, z1 + bounds[1::2] = -np.inf # x2, y2, z2 + + for item in self.items: + item_bounds = item.GetBounds() + bounds[::2] = np.minimum(bounds[::2], item_bounds[::2]) + bounds[1::2] = np.maximum(bounds[1::2], item_bounds[1::2]) + + # Add padding, if any. + bounds[::2] -= self.padding[::2] + bounds[1::2] += self.padding[1::2] + + return tuple(bounds)
+ + +
+[docs] + def GetVisibility(self): + return self._visibility
+ + +
+[docs] + def SetVisibility(self, visibility): + self._visibility = visibility + for item in self.items: + item.SetVisibility(visibility)
+ + +
+[docs] + def GetPosition(self): + return self._position
+ + +
+[docs] + def AddPosition(self, position): + self._position += position + for item in self.items: + item.AddPosition(position)
+ + +
+[docs] + def SetPosition(self, position): + self.AddPosition(np.array(position) - self._position)
+ + +
+[docs] + def GetCenter(self): + """Get the center of the bounding box.""" + x1, x2, y1, y2, z1, z2 = self.GetBounds() + return ((x1 + x2) / 2.0, (y1 + y2) / 2.0, (z1 + z2) / 2.0)
+ + +
+[docs] + def GetLength(self): + """Get the length of bounding box diagonal.""" + x1, x2, y1, y2, z1, z2 = self.GetBounds() + width, height, depth = x2 - x1, y2 - y1, z2 - z1 + return np.sqrt(np.sum([width**2, height**2, depth**2]))
+ + +
+[docs] + def NewInstance(self): + return Container(layout=self.layout)
+ + +
+[docs] + def ShallowCopy(self, other): + self._position = other._position.copy() + self.anchor = other.anchor + self.clear() + self.add(*other._items, borrow=False) + self.update()
+ + + def __len__(self): + return len(self._items)
+ + + +
+[docs] +def grid( + actors, + captions=None, + caption_offset=(0, -100, 0), + cell_padding=0, + cell_shape='rect', + aspect_ratio=16 / 9.0, + dim=None, +): + """Creates a grid of actors that lies in the xy-plane. + + Parameters + ---------- + actors : list of `vtkProp3D` objects + Actors to be layout in a grid manner. + captions : list of `vtkProp3D` objects or list of str + Objects serving as captions (can be any `vtkProp3D` object, not + necessarily text). There should be one caption per actor. By + default, there are no captions. + caption_offset : tuple of float (optional) + Tells where to position the caption w.r.t. the center of its + associated actor. Default: (0, -100, 0). + cell_padding : tuple of 2 floats or float + Each grid cell will be padded according to (pad_x, pad_y) i.e. + horizontally and vertically. Padding is evenly distributed on each + side of the cell. If a single float is provided then both pad_x and + pad_y will have the same value. + cell_shape : str + Specifies the desired shape of every grid cell. + 'rect' ensures the cells are the tightest. + 'square' ensures the cells are as wide as high. + 'diagonal' ensures the content of the cells can be rotated without + colliding with content of the neighboring cells. + aspect_ratio : float + Aspect ratio of the grid (width/height). Default: 16:9. + dim : tuple of int + Dimension (nb_rows, nb_cols) of the grid. If provided, + `aspect_ratio` will be ignored. + + Returns + ------- + ``fury.actor.Container`` object + Object that represents the grid containing all the actors and + captions, if any. + + """ + grid_layout = layout.GridLayout( + cell_padding=cell_padding, + cell_shape=cell_shape, + aspect_ratio=aspect_ratio, + dim=dim, + ) + grid = Container(layout=grid_layout) + + if captions is not None: + actors_with_caption = [] + for actor, caption in zip(actors, captions): + + actor_center = np.array(actor.GetCenter()) + + # Offset accordingly the caption w.r.t. + # the center of the associated actor. + if isinstance(caption, str): + caption = text_3d(caption, justification='center') + else: + caption = shallow_copy(caption) + caption.SetPosition(actor_center + caption_offset) + + actor_with_caption = Container() + actor_with_caption.add(actor, caption) + + # We change the anchor of the container so + # the actor will be centered in the + # grid cell. + actor_with_caption.anchor = actor_center - actor_with_caption.GetCenter() + actors_with_caption.append(actor_with_caption) + + actors = actors_with_caption + + grid.add(*actors) + return grid
+ + + +
+[docs] +def figure(pic, interpolation='nearest'): + """Return a figure as an image actor. + + Parameters + ---------- + pic : filename or numpy RGBA array + interpolation : str + Options are nearest, linear or cubic. Default is nearest. + + Returns + ------- + image_actor : vtkImageActor + + """ + if isinstance(pic, str): + vtk_image_data = load_image(pic, True) + else: + + if pic.ndim == 3 and pic.shape[2] == 4: + + vtk_image_data = ImageData() + vtk_image_data.AllocateScalars(VTK_UNSIGNED_CHAR, 4) + + # width, height + vtk_image_data.SetDimensions(pic.shape[1], pic.shape[0], 1) + vtk_image_data.SetExtent(0, pic.shape[1] - 1, 0, pic.shape[0] - 1, 0, 0) + pic_tmp = np.swapaxes(pic, 0, 1) + pic_tmp = pic.reshape(pic.shape[1] * pic.shape[0], 4) + pic_tmp = np.ascontiguousarray(pic_tmp) + uchar_array = numpy_support.numpy_to_vtk(pic_tmp, deep=True) + vtk_image_data.GetPointData().SetScalars(uchar_array) + + image_actor = ImageActor() + image_actor.SetInputData(vtk_image_data) + + if interpolation == 'nearest': + image_actor.GetProperty().SetInterpolationTypeToNearest() + + if interpolation == 'linear': + image_actor.GetProperty().SetInterpolationTypeToLinear() + + if interpolation == 'cubic': + image_actor.GetProperty().SetInterpolationTypeToCubic() + + image_actor.Update() + return image_actor
+ + + +
+[docs] +def texture(rgb, interp=True): + """Map an RGB or RGBA texture on a plane. + + Parameters + ---------- + rgb : ndarray + Input 2D RGB or RGBA array. Dtype should be uint8. + interp : bool + Interpolate between grid centers. Default True. + + Returns + ------- + act: Actor + + """ + arr = rgb + grid = rgb_to_vtk(np.ascontiguousarray(arr)) + + Y, X = arr.shape[:2] + + # Get vertices and triangles, then scale it + vertices, triangles = fp.prim_square() + vertices *= np.array([[X, Y, 0]]) + + # Create a polydata + my_polydata = PolyData() + set_polydata_vertices(my_polydata, vertices) + set_polydata_triangles(my_polydata, triangles) + + # Create texture object + texture = Texture() + texture.SetInputDataObject(grid) + # texture.UseSRGBColorSpaceOn() + # texture.SetPremultipliedAlpha(True) + if interp: + texture.InterpolateOn() + + # Map texture coordinates + map_to_sphere = TextureMapToPlane() + map_to_sphere.SetInputData(my_polydata) + + # Create mapper and set the mapped texture as input + mapper = PolyDataMapper() + mapper.SetInputConnection(map_to_sphere.GetOutputPort()) + mapper.Update() + + # Create actor and set the mapper and the texture + act = Actor() + act.SetMapper(mapper) + act.SetTexture(texture) + + return act
+ + + +
+[docs] +def texture_update(texture_actor, arr): + """Updates texture of an actor by updating the vtkImageData + assigned to the vtkTexture object. + + Parameters + ---------- + texture_actor: Actor + Actor whose texture is to be updated. + arr : ndarray + Input 2D image in the form of RGB or RGBA array. + This is the new image to be rendered on the actor. + Dtype should be uint8. + + Implementation + -------------- + Check docs/examples/viz_video_on_plane.py + + """ + grid = texture_actor.GetTexture().GetInput() + dim = arr.shape[-1] + img_data = np.flip(arr.swapaxes(0, 1), axis=1).reshape((-1, dim), order='F') + vtkarr = numpy_support.numpy_to_vtk(img_data, deep=False) + grid.GetPointData().SetScalars(vtkarr)
+ + + +def _textured_sphere_source(theta=60, phi=60): + """Use vtkTexturedSphereSource to set the theta and phi. + + Parameters + ---------- + theta : int, optional + Set the number of points in the longitude direction. + phi : int, optional + Set the number of points in the latitude direction. + + Returns + ------- + tss : TexturedSphereSource + + """ + tss = TexturedSphereSource() + tss.SetThetaResolution(theta) + tss.SetPhiResolution(phi) + + return tss + + +
+[docs] +def texture_on_sphere(rgb, theta=60, phi=60, interpolate=True): + """Map an RGB or RGBA texture on a sphere. + + Parameters + ---------- + rgb : ndarray + Input 2D RGB or RGBA array. Dtype should be uint8. + theta : int, optional + Set the number of points in the longitude direction. + phi : int, optional + Set the number of points in the latitude direction. + interpolate : bool, optional + Interpolate between grid centers. + + Returns + ------- + earthActor : Actor + + """ + tss = _textured_sphere_source(theta=theta, phi=phi) + earthMapper = PolyDataMapper() + earthMapper.SetInputConnection(tss.GetOutputPort()) + + earthActor = Actor() + earthActor.SetMapper(earthMapper) + + atext = Texture() + grid = rgb_to_vtk(rgb) + atext.SetInputDataObject(grid) + if interpolate: + atext.InterpolateOn() + earthActor.SetTexture(atext) + + return earthActor
+ + + +
+[docs] +def texture_2d(rgb, interp=False): + """Create 2D texture from array. + + Parameters + ---------- + rgb : ndarray + Input 2D RGB or RGBA array. Dtype should be uint8. + interp : bool, optional + Interpolate between grid centers. + + Returns + ------- + vtkTexturedActor + + """ + arr = rgb + Y, X = arr.shape[:2] + size = (X, Y) + grid = rgb_to_vtk(np.ascontiguousarray(arr)) + + texture_polydata = PolyData() + texture_points = Points() + texture_points.SetNumberOfPoints(4) + + polys = CellArray() + polys.InsertNextCell(4) + polys.InsertCellPoint(0) + polys.InsertCellPoint(1) + polys.InsertCellPoint(2) + polys.InsertCellPoint(3) + texture_polydata.SetPolys(polys) + + tc = FloatArray() + tc.SetNumberOfComponents(2) + tc.SetNumberOfTuples(4) + tc.InsertComponent(0, 0, 0.0) + tc.InsertComponent(0, 1, 0.0) + tc.InsertComponent(1, 0, 1.0) + tc.InsertComponent(1, 1, 0.0) + tc.InsertComponent(2, 0, 1.0) + tc.InsertComponent(2, 1, 1.0) + tc.InsertComponent(3, 0, 0.0) + tc.InsertComponent(3, 1, 1.0) + texture_polydata.GetPointData().SetTCoords(tc) + + texture_points.SetPoint(0, 0, 0, 0.0) + texture_points.SetPoint(1, size[0], 0, 0.0) + texture_points.SetPoint(2, size[0], size[1], 0.0) + texture_points.SetPoint(3, 0, size[1], 0.0) + texture_polydata.SetPoints(texture_points) + + texture_mapper = PolyDataMapper2D() + texture_mapper = set_input(texture_mapper, texture_polydata) + + act = TexturedActor2D() + act.SetMapper(texture_mapper) + + tex = Texture() + tex.SetInputDataObject(grid) + if interp: + tex.InterpolateOn() + tex.Update() + act.SetTexture(tex) + return act
+ + + +
+[docs] +def sdf(centers, directions=(1, 0, 0), colors=(1, 0, 0), primitives='torus', scales=1): + """Create a SDF primitive based actor. + + Parameters + ---------- + centers : ndarray, shape (N, 3) + SDF primitive positions. + colors : ndarray (N,3) or (N, 4) or tuple (3,) or tuple (4,), optional + RGB or RGBA (for opacity) R, G, B and A should be at the range [0, 1]. + directions : ndarray, shape (N, 3) + The orientation vector of the SDF primitive. + primitives : str, list, tuple, np.ndarray + The primitive of choice to be rendered. + Options are sphere, torus and ellipsoid. Default is torus. + scales : float + The size of the SDF primitive. + + Returns + ------- + box_actor: Actor + + """ + prims = {'sphere': 1, 'torus': 2, 'ellipsoid': 3, 'capsule': 4} + + verts, faces = fp.prim_box() + repeated = fp.repeat_primitive( + verts, + faces, + centers=centers, + colors=colors, + directions=directions, + scales=scales, + ) + + rep_verts, rep_faces, rep_colors, rep_centers = repeated + prim_count = len(centers) + box_actor = get_actor_from_primitive( + rep_verts, rep_faces, rep_colors, prim_count=prim_count + ) + box_actor.GetMapper().SetVBOShiftScaleMethod(False) + + if isinstance(primitives, (list, tuple, np.ndarray)): + primlist = [prims[prim] for prim in primitives] + if len(primitives) < len(centers): + primlist = primlist + [2] * (len(centers) - len(primitives)) + warnings.warn( + 'Not enough primitives provided,\ + defaulting to torus', + category=UserWarning, + ) + rep_prims = np.repeat(primlist, verts.shape[0]) + else: + rep_prims = np.repeat(prims[primitives], rep_centers.shape[0], axis=0) + + if isinstance(scales, (list, tuple, np.ndarray)): + rep_scales = np.repeat(scales, verts.shape[0]) + else: + rep_scales = np.repeat(scales, rep_centers.shape[0], axis=0) + + if isinstance(directions, (list, tuple, np.ndarray)) and len(directions) == 3: + rep_directions = np.repeat(directions, rep_centers.shape[0], axis=0) + else: + rep_directions = np.repeat(directions, verts.shape[0], axis=0) + + attribute_to_actor(box_actor, rep_centers, 'center') + attribute_to_actor(box_actor, rep_prims, 'primitive') + attribute_to_actor(box_actor, rep_scales, 'scale') + attribute_to_actor(box_actor, rep_directions, 'direction') + + vs_dec_code = import_fury_shader('sdf_dec.vert') + vs_impl_code = import_fury_shader('sdf_impl.vert') + fs_dec_code = import_fury_shader('sdf_dec.frag') + fs_impl_code = import_fury_shader('sdf_impl.frag') + + shader_to_actor(box_actor, 'vertex', impl_code=vs_impl_code, decl_code=vs_dec_code) + shader_to_actor(box_actor, 'fragment', decl_code=fs_dec_code) + shader_to_actor(box_actor, 'fragment', impl_code=fs_impl_code, block='light') + return box_actor
+ + + +
+[docs] +def markers( + centers, + colors=(0, 1, 0), + scales=1, + marker='3d', + marker_opacity=0.8, + edge_width=0.0, + edge_color=(255, 255, 255), + edge_opacity=0.8, +): + """Create a marker actor with different shapes. + + Parameters + ---------- + centers : ndarray, shape (N, 3) + colors : ndarray (N,3) or (N, 4) or tuple (3,) or tuple (4,) + RGB or RGBA (for opacity) R, G, B and A should be at the range [0, 1]. + scales : ndarray, shape (N) or (N,3) or float or int, optional + marker : str or a list + Available markers are: '3d', 'o', 's', 'd', '^', 'p', 'h', 's6', + 'x', '+', optional. + marker_opacity : float, optional + edge_width : int, optional + edge_color : ndarray, shape (3), optional + edge_opacity : float, optional + + Returns + ------- + sq_actor: Actor + + Examples + -------- + >>> import numpy as np + >>> from fury import actor, window + >>> scene = window.Scene() + >>> markers = ['o', 'x', '^', 's'] # some examples + >>> n = len(markers) + >>> centers = np.random.normal(size=(n, 3), scale=10) + >>> colors = np.random.rand(n, 4) + >>> nodes_actor = actor.markers( + centers, + marker=markers, + edge_width=.1, + edge_color=[255, 255, 0], + colors=colors, + scales=10, + ) + >>> center = np.random.normal(size=(1, 3), scale=10) + >>> nodes_3d_actor = actor.markers( + center, + marker='3d', + scales=5, + ) + >>> scene.add(nodes_actor, nodes_3d_actor) + >>> # window.show(scene, size=(600, 600)) + + """ + n_markers = centers.shape[0] + verts, faces = fp.prim_square() + res = fp.repeat_primitive( + verts, faces, centers=centers, colors=colors, scales=scales + ) + + big_verts, big_faces, big_colors, big_centers = res + prim_count = len(centers) + sq_actor = get_actor_from_primitive( + big_verts, big_faces, big_colors, prim_count=prim_count + ) + sq_actor.GetMapper().SetVBOShiftScaleMethod(False) + sq_actor.GetProperty().BackfaceCullingOff() + + attribute_to_actor(sq_actor, big_centers, 'center') + marker2id = { + 'o': 0, + 's': 1, + 'd': 2, + '^': 3, + 'p': 4, + 'h': 5, + 's6': 6, + 'x': 7, + '+': 8, + '3d': 0, + } + + bb_impl = \ + """ + vec3 vertexPositionMC = sphericalVertexPos(center, MCVCMatrix, + normalizedVertexMCVSOutput, shape); + gl_Position = MCDCMatrix * vec4(vertexPositionMC, 1.); + """ + + vs_dec_code = \ + ''' + /* Billboard vertex shader declaration */ + in vec3 center; + + out vec3 centerVertexMCVSOutput; + out vec3 normalizedVertexMCVSOutput; + ''' + vs_dec_code += \ + f'\n{import_fury_shader("utils/billboard_normalization.glsl")}' + vs_dec_code += f'\n{import_fury_shader("billboard/spherical.glsl")}' + vs_dec_code += f'\n{import_fury_shader("marker_billboard_dec.vert")}' + vs_impl_code = \ + ''' + /* Billboard vertex shader implementation */ + centerVertexMCVSOutput = center; + normalizedVertexMCVSOutput = bbNorm(vertexMC.xyz, center); + float scalingFactor = 1. / abs(normalizedVertexMCVSOutput.x); + float size = abs((vertexMC.xyz - center).x) * 2; + vec2 shape = vec2(size, size); // Fixes the scaling issue + ''' + vs_impl_code += f'\n{compose_shader(bb_impl)}' + vs_impl_code += f'\n{import_fury_shader("marker_billboard_impl.vert")}' + + fs_dec_code = \ + ''' + /* Billboard fragment shader declaration */ + in vec3 centerVertexMCVSOutput; + in vec3 normalizedVertexMCVSOutput; + ''' + fs_dec_code += f'\n{import_fury_shader("marker_billboard_dec.frag")}' + fs_impl_code = \ + ''' + /* Billboard Fragment shader implementation */ + // Renaming variables passed from the Vertex Shader + vec3 color = vertexColorVSOutput.rgb; + vec3 point = normalizedVertexMCVSOutput; + fragOutput0 = vec4(color, 1.); + ''' + + if marker == '3d': + fs_impl_code += f'{import_fury_shader("billboard_spheres_impl.frag")}' + else: + fs_impl_code += f'{import_fury_shader("marker_billboard_impl.frag")}' + if isinstance(marker, str): + list_of_markers = np.ones(n_markers) * marker2id[marker] + else: + list_of_markers = [marker2id[i] for i in marker] + + list_of_markers = np.repeat(list_of_markers, 4).astype('float') + attribute_to_actor(sq_actor, list_of_markers, 'marker') + + def callback( + _caller, _event, calldata=None, uniform_type='f', uniform_name=None, value=None + ): + program = calldata + if program is not None: + program.__getattribute__(f'SetUniform{uniform_type}')(uniform_name, value) + + add_shader_callback( + sq_actor, + partial(callback, uniform_type='f', uniform_name='edgeWidth', value=edge_width), + ) + add_shader_callback( + sq_actor, + partial( + callback, + uniform_type='f', + uniform_name='markerOpacity', + value=marker_opacity, + ), + ) + add_shader_callback( + sq_actor, + partial( + callback, uniform_type='f', uniform_name='edgeOpacity', value=edge_opacity + ), + ) + add_shader_callback( + sq_actor, + partial( + callback, uniform_type='3f', uniform_name='edgeColor', value=edge_color + ), + ) + + shader_to_actor(sq_actor, 'vertex', impl_code=vs_impl_code, decl_code=vs_dec_code) + shader_to_actor(sq_actor, 'fragment', decl_code=fs_dec_code) + shader_to_actor(sq_actor, 'fragment', impl_code=fs_impl_code, block='light') + + return sq_actor
+ + + +
+[docs] +def ellipsoid( + centers, + axes, + lengths, + colors=(1, 0, 0), + scales=1.0, + opacity=1.0 +): + """VTK actor for visualizing ellipsoids. + + Parameters + ---------- + centers : ndarray(N, 3) + Ellipsoid positions. + axes : ndarray (3, 3) or (N, 3, 3) + Axes of the ellipsoid. + lengths : ndarray (3, ) or (N, 3) + Axes lengths. + colors : ndarray (N,3) or tuple (3,), optional + Default red color. R, G and B should be in the range [0, 1]. + scales : float or ndarray (N, ), optional + Ellipsoid size, default(1.0). + opacity : float, optional + Takes values from 0 (fully transparent) to 1 (opaque), default(1.0). + + Returns + ------- + tensor_ellipsoid: Actor + + """ + if not isinstance(centers, np.ndarray): + centers = np.array(centers) + if centers.ndim == 1: + centers = np.array([centers]) + + if not isinstance(axes, np.ndarray): + axes = np.array(axes) + if axes.ndim == 2: + axes = np.array([axes]) + if axes.shape[0] != centers.shape[0]: + raise ValueError('number of axes defined does not match with number of' + 'centers') + + if not isinstance(lengths, np.ndarray): + lengths = np.array(lengths) + if lengths.ndim == 1: + lengths = np.array([lengths]) + if lengths.shape[0] != centers.shape[0]: + raise ValueError('number of lengths defined does not match with number' + 'of centers') + + if not isinstance(scales, np.ndarray): + scales = np.array(scales) + if scales.size == 1: + scales = np.repeat(scales, centers.shape[0]) + elif scales.size != centers.shape[0]: + scales = np.concatenate( + (scales, np.ones(centers.shape[0] - scales.shape[0])), axis=None) + + if isinstance(colors, tuple): + colors = np.array([colors]) + elif not isinstance(colors, np.ndarray): + colors = np.array(colors) + if colors.shape[1] == 4: + colors = colors[:, :-1] + + return tensor_ellipsoid(centers, axes, lengths, colors, scales, opacity)
+ + + +
+[docs] +def uncertainty_cone( + evals, + evecs, + signal, + sigma, + b_matrix, + scales=.6, + opacity=1.0 +): + """VTK actor for visualizing the cone of uncertainty representing the + variance of the main direction of diffusion. + + Parameters + ---------- + evals : ndarray (3, ) or (N, 3) + Eigenvalues. + evecs : ndarray (3, 3) or (N, 3, 3) + Eigenvectors. + signal : 3D or 4D ndarray + Predicted signal. + sigma : ndarray + Standard deviation of the noise. + b_matrix : array (N, 7) + Design matrix for DTI. + scales : float or ndarray (N, ), optional + Cones of uncertainty size. + opacity : float, optional + Takes values from 0 (fully transparent) to 1 (opaque), default(1.0). + + Returns + ------- + double_cone: Actor + + """ + valid_mask = np.abs(evecs).max(axis=(-2, -1)) > 0 + indices = np.nonzero(valid_mask) + + evecs = evecs[indices] + evals = evals[indices] + signal = signal[indices] + + centers = np.asarray(indices).T + colors = np.array([107, 107, 107]) + + x, y, z = evecs.shape + if not isinstance(scales, np.ndarray): + scales = np.array(scales) + if scales.size == 1: + scales = np.repeat(scales, x) + + angles = main_dir_uncertainty(evals, evecs, signal, sigma, b_matrix) + + return double_cone(centers, evecs, angles, colors, scales, opacity)
+ +
+
+ + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/_modules/fury/actors/odf_slicer.html b/v0.10.x/_modules/fury/actors/odf_slicer.html new file mode 100644 index 000000000..d92168118 --- /dev/null +++ b/v0.10.x/_modules/fury/actors/odf_slicer.html @@ -0,0 +1,762 @@ + + + + + + + fury.actors.odf_slicer — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +

Source code for fury.actors.odf_slicer

+# -*- coding: utf-8 -*-
+import numpy as np
+
+from fury.colormap import create_colormap
+from fury.lib import Actor, PolyData, PolyDataMapper
+from fury.utils import (
+    apply_affine,
+    set_polydata_colors,
+    set_polydata_triangles,
+    set_polydata_vertices,
+)
+
+
+
+[docs] +class OdfSlicerActor(Actor): + """VTK actor for visualizing slices of ODF field. + + Parameters + ---------- + odfs : ndarray + SF or SH coefficients 2-dimensional array. + vertices: ndarray + The sphere vertices used for SH to SF projection. + faces: ndarray + Indices of sphere vertices forming triangles. Should be + ordered clockwise (see fury.utils.fix_winding_order). + indices: tuple + Indices given in tuple(x_indices, y_indices, z_indices) + format for mapping 2D ODF array to 3D voxel grid. + scale : float + Multiplicative factor to apply to ODF amplitudes. + norm : bool + Normalize SF amplitudes so that the maximum + ODF amplitude per voxel along a direction is 1. + radial_scale : bool + Scale sphere points by ODF values. + global_cm : bool + If True the colormap will be applied in all ODFs. If False + it will be applied individually at each voxel. + colormap : None or str + The name of the colormap to use. Matplotlib colormaps are supported + (e.g., 'inferno'). If None then a RGB colormap is used. + opacity : float + Takes values from 0 (fully transparent) to 1 (opaque). + affine : array + optional 4x4 transformation array from native + coordinates to world coordinates. + B : ndarray (n_coeffs, n_vertices) + Optional SH to SF matrix for projecting `odfs` given in SH + coefficients on the `sphere`. If None, then the input is assumed + to be expressed in SF coefficients. + + """ + +
+[docs] + def __init__( + self, + odfs, + vertices, + faces, + indices, + scale, + norm, + radial_scale, + shape, + global_cm, + colormap, + opacity, + affine=None, + B=None, + ): + self.vertices = vertices + self.faces = faces + self.odfs = odfs + self.indices = indices + self.B = B + self.radial_scale = radial_scale + self.colormap = colormap + self.grid_shape = shape + self.global_cm = global_cm + + # declare a mask to be instantiated in slice_along_axis + self.mask = None + + # If a B matrix is given, odfs are expected to + # be in SH basis coefficients. + if self.B is not None: + # In that case, we need to save our normalisation and scale + # to apply them after conversion from SH to SF. + self.norm = norm + self.scale = scale + else: + # If our input is in SF coefficients, we can normalise and + # scale it only once, here. + if norm: + self.odfs /= np.abs(self.odfs).max(axis=-1, keepdims=True) + self.odfs *= scale + + # Compute world coordinates of an affine is supplied + self.affine = affine + if self.affine is not None: + self.w_verts = self.vertices.dot(affine[:3, :3]) + self.w_pos = apply_affine(affine, np.asarray(self.indices).T) + + # Initialize mapper and slice to the + # middle of the volume along Z axis + self.mapper = PolyDataMapper() + self.SetMapper(self.mapper) + self.slice_along_axis(self.grid_shape[-1] // 2) + self.set_opacity(opacity)
+ + +
+[docs] + def set_opacity(self, opacity): + """Set opacity value of ODFs to display. + """ + self.GetProperty().SetOpacity(opacity)
+ + +
+[docs] + def display_extent(self, x1, x2, y1, y2, z1, z2): + """Set visible volume from x1 (inclusive) to x2 (inclusive), + y1 (inclusive) to y2 (inclusive), z1 (inclusive) to z2 + (inclusive). + """ + mask = np.zeros(self.grid_shape, dtype=bool) + mask[x1 : x2 + 1, y1 : y2 + 1, z1 : z2 + 1] = True + self.mask = mask + + self._update_mapper()
+ + +
+[docs] + def slice_along_axis(self, slice_index, axis='zaxis'): + """Slice ODF field at given `slice_index` along axis + in ['xaxis', 'yaxis', zaxis']. + """ + if axis == 'xaxis': + self.display_extent( + slice_index, + slice_index, + 0, + self.grid_shape[1] - 1, + 0, + self.grid_shape[2] - 1, + ) + elif axis == 'yaxis': + self.display_extent( + 0, + self.grid_shape[0] - 1, + slice_index, + slice_index, + 0, + self.grid_shape[2] - 1, + ) + elif axis == 'zaxis': + self.display_extent( + 0, + self.grid_shape[0] - 1, + 0, + self.grid_shape[1] - 1, + slice_index, + slice_index, + ) + else: + raise ValueError('Invalid axis name {0}.'.format(axis))
+ + +
+[docs] + def display(self, x=None, y=None, z=None): + """Display a slice along x, y, or z axis. + """ + if x is None and y is None and z is None: + self.slice_along_axis(self.grid_shape[2] // 2) + elif x is not None: + self.slice_along_axis(x, 'xaxis') + elif y is not None: + self.slice_along_axis(y, 'yaxis') + elif z is not None: + self.slice_along_axis(z, 'zaxis')
+ + +
+[docs] + def update_sphere(self, vertices, faces, B): + """Dynamically change the sphere used for SH to SF projection. + """ + if self.B is None: + raise ValueError("Can't update sphere when using " 'SF coefficients.') + self.vertices = vertices + if self.affine is not None: + self.w_verts = self.vertices.dot(self.affine[:3, :3]) + self.faces = faces + self.B = B + + # draw ODFs with new sphere + self._update_mapper()
+ + + def _update_mapper(self): + """Map vtkPolyData to the actor. + """ + polydata = PolyData() + + offsets = self._get_odf_offsets(self.mask) + if len(offsets) == 0: + self.mapper.SetInputData(polydata) + return None + + sph_dirs = self._get_sphere_directions() + sf = self._get_sf(self.mask) + + all_vertices = self._get_all_vertices(offsets, sph_dirs, sf) + all_faces = self._get_all_faces(len(offsets), len(sph_dirs)) + all_colors = self._generate_color_for_vertices(sf) + + # TODO: There is a lot of deep copy here. + # Optimize (see viz_network.py example). + set_polydata_triangles(polydata, all_faces) + set_polydata_vertices(polydata, all_vertices) + set_polydata_colors(polydata, all_colors) + + self.mapper.SetInputData(polydata) + + def _get_odf_offsets(self, mask): + """Get the position of non-zero voxels inside `mask`. + """ + if self.affine is not None: + return self.w_pos[mask[self.indices]] + return np.asarray(self.indices).T[mask[self.indices]] + + def _get_sphere_directions(self): + """Get the sphere directions onto which is projected the signal. + """ + if self.affine is not None: + return self.w_verts + return self.vertices + + def _get_sf(self, mask): + """Get SF coefficients inside `mask`. + """ + # when odfs are expressed in SH coefficients + if self.B is not None: + sf = self.odfs[mask[self.indices]].dot(self.B) + # normalisation and scaling is done on SF coefficients + if self.norm: + sf /= np.abs(sf).max(axis=-1, keepdims=True) + return sf * self.scale + # when odfs are in SF coefficients, the normalisation and scaling + # are done during initialisation. We simply return them: + return self.odfs[mask[self.indices]] + + def _get_all_vertices(self, offsets, sph_dirs, sf): + """Get array of all the vertices of the ODFs to display. + """ + if self.radial_scale: + # apply SF amplitudes to all sphere + # directions and offset each voxel + return np.tile(sph_dirs, (len(offsets), 1)) * sf.reshape(-1, 1) + np.repeat( + offsets, len(sph_dirs), axis=0 + ) + # return scaled spheres offsetted by `offsets` + return np.tile(sph_dirs, (len(offsets), 1)) * self.scale + np.repeat( + offsets, len(sph_dirs), axis=0 + ) + + def _get_all_faces(self, nb_odfs, nb_dirs): + """Get array of all the faces of the ODFs to display. + """ + return np.tile(self.faces, (nb_odfs, 1)) + np.repeat( + np.arange(nb_odfs) * nb_dirs, len(self.faces) + ).reshape(-1, 1) + + def _generate_color_for_vertices(self, sf): + """Get array of all vertices colors. + """ + if self.global_cm: + if self.colormap is None: + raise IOError('if global_cm=True, colormap must be defined.') + else: + all_colors = create_colormap(sf.ravel(), self.colormap) * 255 + elif self.colormap is not None: + if isinstance(self.colormap, str): + # Map ODFs values [min, max] to [0, 1] for each ODF + range_sf = sf.max(axis=-1) - sf.min(axis=-1) + rescaled = sf - sf.min(axis=-1, keepdims=True) + rescaled[range_sf > 0] /= range_sf[range_sf > 0][..., None] + all_colors = create_colormap(rescaled.ravel(), self.colormap) * 255 + else: + all_colors = np.tile( + np.array(self.colormap).reshape(1, 3), + (sf.shape[0] * sf.shape[1], 1), + ) + else: + all_colors = np.tile(np.abs(self.vertices) * 255, (len(sf), 1)) + return all_colors.astype(np.uint8)
+ +
+
+ + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/_modules/fury/actors/peak.html b/v0.10.x/_modules/fury/actors/peak.html new file mode 100644 index 000000000..3a5bbe205 --- /dev/null +++ b/v0.10.x/_modules/fury/actors/peak.html @@ -0,0 +1,892 @@ + + + + + + + fury.actors.peak — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +

Source code for fury.actors.peak

+from os.path import join as pjoin
+
+import numpy as np
+
+from fury.colormap import boys2rgb, colormap_lookup_table, orient2rgb
+from fury.lib import (
+    VTK_OBJECT,
+    Actor,
+    CellArray,
+    Command,
+    PolyData,
+    PolyDataMapper,
+    calldata_type,
+    numpy_support,
+)
+from fury.shaders import (
+    attribute_to_actor,
+    compose_shader,
+    import_fury_shader,
+    shader_to_actor,
+)
+from fury.utils import apply_affine, numpy_to_vtk_colors, numpy_to_vtk_points
+
+
+
+[docs] +class PeakActor(Actor): + """FURY actor for visualizing DWI peaks. + + Parameters + ---------- + directions : ndarray + Peak directions. The shape of the array should be (X, Y, Z, D, 3). + indices : tuple + Indices given in tuple(x_indices, y_indices, z_indices) + format for mapping 2D ODF array to 3D voxel grid. + values : ndarray, optional + Peak values. The shape of the array should be (X, Y, Z, D). + affine : array, optional + 4x4 transformation array from native coordinates to world coordinates. + colors : None or string ('rgb_standard') or tuple (3D or 4D) or + array/ndarray (N, 3 or 4) or array/ndarray (K, 3 or 4) or + array/ndarray(N, ) or array/ndarray (K, ) + If None a standard orientation colormap is used for every line. + If one tuple of color is used. Then all streamlines will have the same + color. + If an array (N, 3 or 4) is given, where N is equal to the number of + points. Then every point is colored with a different RGB(A) color. + If an array (K, 3 or 4) is given, where K is equal to the number of + lines. Then every line is colored with a different RGB(A) color. + If an array (N, ) is given, where N is the number of points then these + are considered as the values to be used by the colormap. + If an array (K,) is given, where K is the number of lines then these + are considered as the values to be used by the colormap. + lookup_colormap : vtkLookupTable, optional + Add a default lookup table to the colormap. Default is None which calls + :func:`fury.actor.colormap_lookup_table`. + linewidth : float, optional + Line thickness. Default is 1. + symmetric: bool, optional + If True, peaks are drawn for both peaks_dirs and -peaks_dirs. Else, + peaks are only drawn for directions given by peaks_dirs. Default is + True. + + """ + +
+[docs] + def __init__( + self, + directions, + indices, + values=None, + affine=None, + colors=None, + lookup_colormap=None, + linewidth=1, + symmetric=True, + ): + if affine is not None: + w_pos = apply_affine(affine, np.asarray(indices).T) + + valid_dirs = directions[indices] + + num_dirs = len(np.nonzero(np.abs(valid_dirs).max(axis=-1) > 0)[0]) + + pnts_per_line = 2 + + points_array = np.empty((num_dirs * pnts_per_line, 3)) + centers_array = np.empty_like(points_array, dtype=int) + diffs_array = np.empty_like(points_array) + line_count = 0 + for idx, center in enumerate(zip(indices[0], indices[1], indices[2])): + if affine is None: + xyz = np.asarray(center) + else: + xyz = w_pos[idx, :] + valid_peaks = np.nonzero(np.abs(valid_dirs[idx, :, :]).max(axis=-1) > 0.0)[ + 0 + ] + for direction in valid_peaks: + if values is not None: + pv = values[center][direction] + else: + pv = 1.0 + + if symmetric: + point_i = directions[center][direction] * pv + xyz + point_e = -directions[center][direction] * pv + xyz + else: + point_i = directions[center][direction] * pv + xyz + point_e = xyz + + diff = point_e - point_i + points_array[line_count * pnts_per_line, :] = point_e + points_array[line_count * pnts_per_line + 1, :] = point_i + centers_array[line_count * pnts_per_line, :] = center + centers_array[line_count * pnts_per_line + 1, :] = center + diffs_array[line_count * pnts_per_line, :] = diff + diffs_array[line_count * pnts_per_line + 1, :] = diff + line_count += 1 + + vtk_points = numpy_to_vtk_points(points_array) + + vtk_cells = _points_to_vtk_cells(points_array) + + colors_tuple = _peaks_colors_from_points(points_array, colors=colors) + vtk_colors, colors_are_scalars, self.__global_opacity = colors_tuple + + poly_data = PolyData() + poly_data.SetPoints(vtk_points) + poly_data.SetLines(vtk_cells) + poly_data.GetPointData().SetScalars(vtk_colors) + + self.__mapper = PolyDataMapper() + self.__mapper.SetInputData(poly_data) + self.__mapper.ScalarVisibilityOn() + self.__mapper.SetScalarModeToUsePointFieldData() + self.__mapper.SelectColorArray('colors') + self.__mapper.Update() + + self.SetMapper(self.__mapper) + + attribute_to_actor(self, centers_array, 'center') + attribute_to_actor(self, diffs_array, 'diff') + + vs_var_dec = """ + in vec3 center; + in vec3 diff; + flat out vec3 centerVertexMCVSOutput; + """ + fs_var_dec = """ + flat in vec3 centerVertexMCVSOutput; + uniform bool isRange; + uniform vec3 crossSection; + uniform vec3 lowRanges; + uniform vec3 highRanges; + """ + orient_to_rgb = import_fury_shader(pjoin('utils', 'orient_to_rgb.glsl')) + visible_cross_section = import_fury_shader( + pjoin('interaction', 'visible_cross_section.glsl') + ) + visible_range = import_fury_shader(pjoin('interaction', 'visible_range.glsl')) + + vs_dec = compose_shader([vs_var_dec, orient_to_rgb]) + fs_dec = compose_shader([fs_var_dec, visible_cross_section, visible_range]) + + vs_impl = """ + centerVertexMCVSOutput = center; + if (vertexColorVSOutput.rgb == vec3(0)) + { + vertexColorVSOutput.rgb = orient2rgb(diff); + } + """ + + fs_impl = """ + if (isRange) + { + if (!inVisibleRange(centerVertexMCVSOutput)) + discard; + } + else + { + if (!inVisibleCrossSection(centerVertexMCVSOutput)) + discard; + } + """ + + shader_to_actor(self, 'vertex', decl_code=vs_dec, impl_code=vs_impl) + shader_to_actor(self, 'fragment', decl_code=fs_dec) + shader_to_actor(self, 'fragment', impl_code=fs_impl, block='light') + + # Color scale with a lookup table + if colors_are_scalars: + if lookup_colormap is None: + lookup_colormap = colormap_lookup_table() + + self.__mapper.SetLookupTable(lookup_colormap) + self.__mapper.UseLookupTableScalarRangeOn() + self.__mapper.Update() + + self.__lw = linewidth + self.GetProperty().SetLineWidth(self.__lw) + + if self.__global_opacity >= 0: + self.GetProperty().SetOpacity(self.__global_opacity) + + self.__min_centers = np.min(indices, axis=1) + self.__max_centers = np.max(indices, axis=1) + + self.__is_range = True + self.__low_ranges = self.__min_centers + self.__high_ranges = self.__max_centers + self.__cross_section = self.__high_ranges // 2 + + self.__mapper.AddObserver( + Command.UpdateShaderEvent, self.__display_peaks_vtk_callback + )
+ + + @calldata_type(VTK_OBJECT) + def __display_peaks_vtk_callback(self, caller, event, calldata=None): + if calldata is not None: + calldata.SetUniformi('isRange', self.__is_range) + calldata.SetUniform3f('highRanges', self.__high_ranges) + calldata.SetUniform3f('lowRanges', self.__low_ranges) + calldata.SetUniform3f('crossSection', self.__cross_section) + +
+[docs] + def display_cross_section(self, x, y, z): + if self.__is_range: + self.__is_range = False + self.__cross_section = [x, y, z]
+ + +
+[docs] + def display_extent(self, x1, x2, y1, y2, z1, z2): + if not self.__is_range: + self.__is_range = True + self.__low_ranges = [x1, y1, z1] + self.__high_ranges = [x2, y2, z2]
+ + + @property + def cross_section(self): + return self.__cross_section + + @property + def global_opacity(self): + return self.__global_opacity + + @global_opacity.setter + def global_opacity(self, opacity): + self.__global_opacity = opacity + self.GetProperty().SetOpacity(self.__global_opacity) + + @property + def high_ranges(self): + return self.__high_ranges + + @property + def is_range(self): + return self.__is_range + + @property + def low_ranges(self): + return self.__low_ranges + + @property + def linewidth(self): + return self.__lw + + @linewidth.setter + def linewidth(self, linewidth): + self.__lw = linewidth + self.GetProperty().SetLineWidth(self.__lw) + + @property + def max_centers(self): + return self.__max_centers + + @property + def min_centers(self): + return self.__min_centers
+ + + +def _orientation_colors(points, cmap='rgb_standard'): + """ + Parameters + ---------- + points : (N, 3) array or ndarray + points coordinates array. + cmap : string ('rgb_standard', 'boys_standard'), optional + colormap. + + Returns + ------- + colors_list : ndarray + list of Kx3 colors. Where K is the number of lines. + + """ + if cmap.lower() == 'rgb_standard': + col_list = [ + orient2rgb(points[i + 1] - points[i]) for i in range(0, len(points), 2) + ] + elif cmap.lower() == 'boys_standard': + col_list = [ + boys2rgb(points[i + 1] - points[i]) for i in range(0, len(points), 2) + ] + else: + raise ValueError( + 'Invalid colormap. The only available options are ' + "'rgb_standard' and 'boys_standard'." + ) + return np.asarray(col_list) + + +def _peaks_colors_from_points(points, colors=None, points_per_line=2): + """Return a VTK scalar array containing colors information for each one of + the peaks according to the policy defined by the parameter colors. + + Parameters + ---------- + points : (N, 3) array or ndarray + points coordinates array. + colors : None or string ('rgb_standard') or tuple (3D or 4D) or + array/ndarray (N, 3 or 4) or array/ndarray (K, 3 or 4) or + array/ndarray(N, ) or array/ndarray (K, ) + If None a standard orientation colormap is used for every line. + If one tuple of color is used. Then all streamlines will have the same + color. + If an array (N, 3 or 4) is given, where N is equal to the number of + points. Then every point is colored with a different RGB(A) color. + If an array (K, 3 or 4) is given, where K is equal to the number of + lines. Then every line is colored with a different RGB(A) color. + If an array (N, ) is given, where N is the number of points then these + are considered as the values to be used by the colormap. + If an array (K,) is given, where K is the number of lines then these + are considered as the values to be used by the colormap. + points_per_line : int (1 or 2), optional + number of points per peak direction. + + Returns + ------- + color_array : vtkDataArray + vtk scalar array with name 'colors'. + colors_are_scalars : bool + indicates whether or not the colors are scalars to be interpreted by a + colormap. + global_opacity : float + returns 1 if the colors array doesn't contain opacity otherwise -1. + + """ + num_pnts = len(points) + num_lines = num_pnts // points_per_line + colors_are_scalars = False + global_opacity = 1 + if colors is None or colors == 'rgb_standard': + # Automatic RGB colors + colors = np.asarray((0, 0, 0)) + color_array = numpy_to_vtk_colors(np.tile(255 * colors, (num_pnts, 1))) + elif type(colors) is tuple: + global_opacity = 1 if len(colors) == 3 else -1 + colors = np.asarray(colors) + color_array = numpy_to_vtk_colors(np.tile(255 * colors, (num_pnts, 1))) + else: + colors = np.asarray(colors) + if len(colors) == num_lines: + pnts_colors = np.repeat(colors, points_per_line, axis=0) + if colors.ndim == 1: # Scalar per line + color_array = numpy_support.numpy_to_vtk(pnts_colors, deep=True) + colors_are_scalars = True + elif colors.ndim == 2: # RGB(A) color per line + global_opacity = 1 if colors.shape[1] == 3 else -1 + color_array = numpy_to_vtk_colors(255 * pnts_colors) + elif len(colors) == num_pnts: + if colors.ndim == 1: # Scalar per point + color_array = numpy_support.numpy_to_vtk(colors, deep=True) + colors_are_scalars = True + elif colors.ndim == 2: # RGB(A) color per point + global_opacity = 1 if colors.shape[1] == 3 else -1 + color_array = numpy_to_vtk_colors(255 * colors) + + color_array.SetName('colors') + return color_array, colors_are_scalars, global_opacity + + +def _points_to_vtk_cells(points, points_per_line=2): + """Return the VTK cell array for the peaks given the set of points + coordinates. + + Parameters + ---------- + points : (N, 3) array or ndarray + points coordinates array. + points_per_line : int (1 or 2), optional + number of points per peak direction. + + Returns + ------- + cell_array : vtkCellArray + connectivity + offset information. + + """ + num_pnts = len(points) + num_cells = num_pnts // points_per_line + + cell_array = CellArray() + + """ + Connectivity is an array that contains the indices of the points that + need to be connected in the visualization. The indices start from 0. + """ + connectivity = np.asarray(list(range(0, num_pnts)), dtype=int) + """ + Offset is an array that contains the indices of the first point of + each line. The indices start from 0 and given the known geometry of + this actor the creation of this array requires a 2 points padding + between indices. + """ + offset = np.asarray(list(range(0, num_pnts + 1, points_per_line)), dtype=int) + + vtk_array_type = numpy_support.get_vtk_array_type(connectivity.dtype) + cell_array.SetData( + numpy_support.numpy_to_vtk(offset, deep=True, array_type=vtk_array_type), + numpy_support.numpy_to_vtk(connectivity, deep=True, array_type=vtk_array_type), + ) + + cell_array.SetNumberOfCells(num_cells) + return cell_array +
+
+ + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/_modules/fury/actors/tensor.html b/v0.10.x/_modules/fury/actors/tensor.html new file mode 100644 index 000000000..630e4ae87 --- /dev/null +++ b/v0.10.x/_modules/fury/actors/tensor.html @@ -0,0 +1,960 @@ + + + + + + + fury.actors.tensor — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +

Source code for fury.actors.tensor

+import os
+
+import numpy as np
+
+from fury import actor
+from fury.shaders import (
+    attribute_to_actor,
+    compose_shader,
+    import_fury_shader,
+    shader_to_actor,
+)
+
+
+
+[docs] +def tensor_ellipsoid(centers, axes, lengths, colors, scales, opacity): + """Visualize one or many Tensor Ellipsoids with different features. + + Parameters + ---------- + centers : ndarray(N, 3) + Tensor ellipsoid positions. + axes : ndarray (3, 3) or (N, 3, 3) + Axes of the tensor ellipsoid. + lengths : ndarray (3, ) or (N, 3) + Axes lengths. + colors : ndarray (N,3) or tuple (3,) + R, G and B should be in the range [0, 1]. + scales : float or ndarray (N, ) + Tensor ellipsoid size. + opacity : float + Takes values from 0 (fully transparent) to 1 (opaque). + + Returns + ------- + box_actor: Actor + + """ + box_actor = actor.box(centers, colors=colors, scales=scales) + box_actor.GetMapper().SetVBOShiftScaleMethod(False) + box_actor.GetProperty().SetOpacity(opacity) + + # Number of vertices that make up the box + n_verts = 8 + + big_centers = np.repeat(centers, n_verts, axis=0) + attribute_to_actor(box_actor, big_centers, 'center') + + big_scales = np.repeat(scales, n_verts, axis=0) + attribute_to_actor(box_actor, big_scales, 'scale') + + big_values = np.repeat(np.array(lengths, dtype=float), n_verts, axis=0) + attribute_to_actor(box_actor, big_values, 'evals') + + evec1 = np.array([item[0] for item in axes]) + evec2 = np.array([item[1] for item in axes]) + evec3 = np.array([item[2] for item in axes]) + + big_vectors_1 = np.repeat(evec1, n_verts, axis=0) + attribute_to_actor(box_actor, big_vectors_1, 'evec1') + big_vectors_2 = np.repeat(evec2, n_verts, axis=0) + attribute_to_actor(box_actor, big_vectors_2, 'evec2') + big_vectors_3 = np.repeat(evec3, n_verts, axis=0) + attribute_to_actor(box_actor, big_vectors_3, 'evec3') + + # Start of shader implementation + + vs_dec = \ + """ + in vec3 center; + in float scale; + in vec3 evals; + in vec3 evec1; + in vec3 evec2; + in vec3 evec3; + + out vec4 vertexMCVSOutput; + out vec3 centerMCVSOutput; + out float scaleVSOutput; + out vec3 evalsVSOutput; + out mat3 tensorMatrix; + """ + + # Variables assignment + v_assign = \ + """ + vertexMCVSOutput = vertexMC; + centerMCVSOutput = center; + scaleVSOutput = scale; + """ + + # Normalization + n_evals = "evalsVSOutput = evals/(max(evals.x, max(evals.y, evals.z)));" + + # Values constraint to avoid incorrect visualizations + evals = "evalsVSOutput = clamp(evalsVSOutput,0.05,1);" + + # Scaling matrix + sc_matrix = \ + """ + mat3 S = mat3(1/evalsVSOutput.x, 0.0, 0.0, + 0.0, 1/evalsVSOutput.y, 0.0, + 0.0, 0.0, 1/evalsVSOutput.z); + """ + + # Rotation matrix + rot_matrix = "mat3 R = mat3(evec1, evec2, evec3);" + + # Tensor matrix + t_matrix = "tensorMatrix = inverse(R) * S * R;" + + vs_impl = compose_shader([v_assign, n_evals, evals, sc_matrix, rot_matrix, + t_matrix]) + + # Adding shader implementation to actor + shader_to_actor(box_actor, 'vertex', decl_code=vs_dec, impl_code=vs_impl) + + fs_vars_dec = \ + """ + in vec4 vertexMCVSOutput; + in vec3 centerMCVSOutput; + in float scaleVSOutput; + in vec3 evalsVSOutput; + in mat3 tensorMatrix; + + uniform mat4 MCVCMatrix; + """ + + # Importing the sphere SDF + sd_sphere = import_fury_shader(os.path.join('sdf', 'sd_sphere.frag')) + + # SDF definition + sdf_map = \ + """ + float map(in vec3 position) + { + /* + As the scaling is not a rigid body transformation, we multiply + by a factor to compensate for distortion and not overestimate + the distance. + */ + float scFactor = min(evalsVSOutput.x, min(evalsVSOutput.y, + evalsVSOutput.z)); + + /* + The approximation of distance is calculated by stretching the + space such that the ellipsoid becomes a sphere (multiplying by + the transformation matrix) and then computing the distance to + a sphere in that space (using the sphere SDF). + */ + return sdSphere(tensorMatrix * (position - centerMCVSOutput), + scaleVSOutput*0.48) * scFactor; + } + """ + + # Importing central differences function for computing surface normals + central_diffs_normal = import_fury_shader(os.path.join( + 'sdf', 'central_diffs.frag')) + + # Importing raymarching function + cast_ray = import_fury_shader(os.path.join( + 'ray_marching', 'cast_ray.frag')) + + # Importing the function that generates the ray components + ray_generation = import_fury_shader(os.path.join( + 'ray_marching', 'gen_ray.frag')) + + # Importing Blinn-Phong model for lighting + blinn_phong_model = import_fury_shader(os.path.join( + 'lighting', 'blinn_phong_model.frag')) + + # Full fragment shader declaration + fs_dec = compose_shader([fs_vars_dec, sd_sphere, sdf_map, + central_diffs_normal, cast_ray, ray_generation, + blinn_phong_model]) + + shader_to_actor(box_actor, 'fragment', decl_code=fs_dec) + + ray_components = \ + """ + vec3 ro; vec3 rd; float t; + gen_ray(ro, rd, t); + """ + + # Fragment shader output definition + # If surface is detected, color is assigned, otherwise, nothing is painted + frag_output_def = \ + """ + if(t < 20) + { + vec3 pos = ro + t * rd; + vec3 normal = centralDiffsNormals(pos, .0001); + // Light Direction + vec3 ld = normalize(ro - pos); + // Light Attenuation + float la = dot(ld, normal); + vec3 color = blinnPhongIllumModel(la, lightColor0, + diffuseColor, specularPower, specularColor, ambientColor); + fragOutput0 = vec4(color, opacity); + } + else + { + discard; + } + """ + + # Full fragment shader implementation + sdf_frag_impl = compose_shader([ray_components, frag_output_def]) + + shader_to_actor(box_actor, 'fragment', impl_code=sdf_frag_impl, + block='light') + + return box_actor
+ + + +
+[docs] +def double_cone(centers, axes, angles, colors, scales, opacity): + """Visualize one or many Double Cones with different features. + + Parameters + ---------- + centers : ndarray(N, 3) + Cone positions. + axes : ndarray (3, 3) or (N, 3, 3) + Axes of the cone. + angles : float or ndarray (N, ) + Angles of the cone. + colors : ndarray (N, 3) or tuple (3,) + R, G and B should be in the range [0, 1]. + scales : float or ndarray (N, ) + Cone size. + opacity : float + Takes values from 0 (fully transparent) to 1 (opaque). + + Returns + ------- + box_actor: Actor + + """ + box_actor = actor.box(centers, colors=colors, scales=scales) + box_actor.GetMapper().SetVBOShiftScaleMethod(False) + box_actor.GetProperty().SetOpacity(opacity) + + # Number of vertices that make up the box + n_verts = 8 + + big_centers = np.repeat(centers, n_verts, axis=0) + attribute_to_actor(box_actor, big_centers, 'center') + + big_scales = np.repeat(scales, n_verts, axis=0) + attribute_to_actor(box_actor, big_scales, 'scale') + + evec1 = np.array([item[0] for item in axes]) + evec2 = np.array([item[1] for item in axes]) + evec3 = np.array([item[2] for item in axes]) + + big_vectors_1 = np.repeat(evec1, n_verts, axis=0) + attribute_to_actor(box_actor, big_vectors_1, 'evec1') + big_vectors_2 = np.repeat(evec2, n_verts, axis=0) + attribute_to_actor(box_actor, big_vectors_2, 'evec2') + big_vectors_3 = np.repeat(evec3, n_verts, axis=0) + attribute_to_actor(box_actor, big_vectors_3, 'evec3') + + big_angles = np.repeat(np.array(angles, dtype=float), n_verts, axis=0) + attribute_to_actor(box_actor, big_angles, 'angle') + + # Start of shader implementation + + vs_dec = \ + """ + in vec3 center; + in float scale; + in vec3 evec1; + in vec3 evec2; + in vec3 evec3; + in float angle; + + out vec4 vertexMCVSOutput; + out vec3 centerMCVSOutput; + out float scaleVSOutput; + out mat3 rotationMatrix; + out float angleVSOutput; + """ + + # Variables assignment + v_assign = \ + """ + vertexMCVSOutput = vertexMC; + centerMCVSOutput = center; + scaleVSOutput = scale; + angleVSOutput = angle; + """ + + # Rotation matrix + rot_matrix = \ + """ + mat3 R = mat3(normalize(evec1), normalize(evec2), normalize(evec3)); + float a = radians(90); + mat3 rot = mat3(cos(a),-sin(a), 0, + sin(a), cos(a), 0, + 0 , 0, 1); + rotationMatrix = transpose(R) * rot; + """ + + vs_impl = compose_shader([v_assign, rot_matrix]) + + shader_to_actor(box_actor, 'vertex', decl_code=vs_dec, + impl_code=vs_impl) + + fs_vars_dec = \ + """ + in vec4 vertexMCVSOutput; + in vec3 centerMCVSOutput; + in float scaleVSOutput; + in mat3 rotationMatrix; + in float angleVSOutput; + + uniform mat4 MCVCMatrix; + """ + + # Importing the cone SDF + sd_cone = import_fury_shader(os.path.join('sdf', 'sd_cone.frag')) + + # Importing the union operation SDF + sd_union = import_fury_shader(os.path.join('sdf', 'sd_union.frag')) + + # SDF definition + sdf_map = \ + """ + float map(in vec3 position) + { + vec3 p = (position - centerMCVSOutput)/scaleVSOutput + *rotationMatrix; + float angle = clamp(angleVSOutput, 0, 6.283); + vec2 a = vec2(sin(angle), cos(angle)); + float h = .5 * a.y; + return opUnion(sdCone(p,a,h), sdCone(-p,a,h)) * scaleVSOutput; + } + """ + + # Importing central differences function for computing surface normals + central_diffs_normal = import_fury_shader(os.path.join( + 'sdf', 'central_diffs.frag')) + + # Importing raymarching function + cast_ray = import_fury_shader(os.path.join( + 'ray_marching', 'cast_ray.frag')) + + # Importing the function that generates the ray components + ray_generation = import_fury_shader(os.path.join( + 'ray_marching', 'gen_ray.frag')) + + # Importing Blinn-Phong model for lighting + blinn_phong_model = import_fury_shader(os.path.join( + 'lighting', 'blinn_phong_model.frag')) + + # Full fragment shader declaration + fs_dec = compose_shader([fs_vars_dec, sd_cone, sd_union, sdf_map, + central_diffs_normal, cast_ray, ray_generation, + blinn_phong_model]) + + shader_to_actor(box_actor, 'fragment', decl_code=fs_dec) + + ray_components = \ + """ + vec3 ro; vec3 rd; float t; + gen_ray(ro, rd, t); + """ + + # Fragment shader output definition + # If surface is detected, color is assigned, otherwise, nothing is painted + frag_output_def = \ + """ + if(t < 20) + { + vec3 pos = ro + t * rd; + vec3 normal = centralDiffsNormals(pos, .0001); + // Light Direction + vec3 ld = normalize(ro - pos); + // Light Attenuation + float la = dot(ld, normal); + vec3 color = blinnPhongIllumModel(la, lightColor0, + diffuseColor, specularPower, specularColor, ambientColor); + fragOutput0 = vec4(color, opacity); + } + else + { + discard; + } + """ + + # Full fragment shader implementation + sdf_frag_impl = compose_shader([ray_components, frag_output_def]) + + shader_to_actor(box_actor, 'fragment', impl_code=sdf_frag_impl, + block='light') + + return box_actor
+ + + +
+[docs] +def main_dir_uncertainty(evals, evecs, signal, sigma, b_matrix): + """Calculate the angle of the cone of uncertainty that represents the + perturbation of the main eigenvector of the diffusion tensor matrix. + + Parameters + ---------- + evals : ndarray (3, ) or (N, 3) + Eigenvalues. + evecs : ndarray (3, 3) or (N, 3, 3) + Eigenvectors. + signal : 3D or 4D ndarray + Predicted signal. + sigma : ndarray + Standard deviation of the noise. + b_matrix : array (N, 7) + Design matrix for DTI. + + Returns + ------- + angles: array + + Notes + ----- + The uncertainty calculation is based on first-order matrix perturbation + analysis described in [1]_. The idea is to estimate the variance of the + main eigenvector which corresponds to the main direction of diffusion, + directly from estimated D and its estimated covariance matrix + :math:`\Delta D` (see [2]_, equation 4). The angle :math:`\\Theta` + between the perturbed principal eigenvector of D, + :math:`\\epsilon_1+\\Delta\\epsilon_1`, and the estimated eigenvector + :math:`\\epsilon_1`, measures the angular deviation of the main fiber + direction and can be approximated by: + + .. math:: + \\Theta=tan^{-1}(\\|\\Delta\\epsilon_1\\|) + + Giving way to a graphical construct for displaying both the main + eigenvector of D and its associated uncertainty, with the so-called + "uncertainty cone". + + References + ---------- + .. [1] Basser, P. J. (1997). Quantifying errors in fiber direction and + diffusion tensor field maps resulting from MR noise. In 5th Scientific + Meeting of the ISMRM (Vol. 1740). + + .. [2] Chang, L. C., Koay, C. G., Pierpaoli, C., & Basser, P. J. (2007). + Variance of estimated DTI-derived parameters via first-order perturbation + methods. Magnetic Resonance in Medicine: An Official Journal of the + International Society for Magnetic Resonance in Medicine, 57(1), 141-149. + + """ + angles = np.ones(evecs.shape[0]) + for i in range(evecs.shape[0]): + sigma_e = np.diag(signal[i] / sigma ** 2) + k = np.dot(np.transpose(b_matrix), sigma_e) + sigma_ = np.dot(k, b_matrix) + + dd = np.diag(sigma_) + delta_DD = np.array([[dd[0], dd[3], dd[4]], + [dd[3], dd[1], dd[5]], + [dd[4], dd[5], dd[2]]]) + + # perturbation matrix of tensor D + try: + delta_D = np.linalg.inv(delta_DD) + except np.linalg.LinAlgError: + delta_D = delta_DD + + D_ = evecs + eigen_vals = evals[i] + + e1, e2, e3 = np.array(D_[i, :, 0]), np.array(D_[i, :, 1]), \ + np.array(D_[i, :, 2]) + lambda1, lambda2, lambda3 = eigen_vals[0], eigen_vals[1], eigen_vals[2] + + if lambda1 > lambda2 and lambda1 > lambda3: + # The perturbation of the eigenvector associated with the largest + # eigenvalue is given by + a = np.dot(np.outer(np.dot(e1, delta_D), np.transpose(e2)) / + (lambda1 - lambda2), e2) + b = np.dot(np.outer(np.dot(e1, delta_D), np.transpose(e3)) / + (lambda1 - lambda3), e3) + delta_e1 = a + b + + # The angle \theta between the perturbed principal eigenvector of D + theta = np.arctan(np.linalg.norm(delta_e1)) + angles[i] = theta + else: + # If the condition is not satisfied it means that there is not a + # predominant diffusion direction, hence the uncertainty will be + # higher and a default value close to pi/2 is assigned + theta = 1.39626 + + return angles
+ +
+
+ + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/_modules/fury/animation/animation.html b/v0.10.x/_modules/fury/animation/animation.html new file mode 100644 index 000000000..dc0924c92 --- /dev/null +++ b/v0.10.x/_modules/fury/animation/animation.html @@ -0,0 +1,2055 @@ + + + + + + + fury.animation.animation — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +

Source code for fury.animation.animation

+from collections import defaultdict
+from time import perf_counter
+from warnings import warn
+
+import numpy as np
+from scipy.spatial import transform
+
+from fury import utils
+from fury.actor import line
+from fury.animation.interpolator import (  # noqa F401
+    linear_interpolator,
+    slerp,
+    spline_interpolator,
+    step_interpolator,
+)
+from fury.lib import Actor, Camera, Transform
+
+
+
+[docs] +class Animation: + """Keyframe animation class. + + Animation is responsible for keyframe animations for a single or a + group of actors. + It's used to handle multiple attributes and properties of Fury actors such + as transformations, color, and scale. + It also accepts custom data and interpolates them, such as temperature. + Linear interpolation is used by default to interpolate data between the + main keyframes. + + Attributes + ---------- + actors : Actor or list[Actor], optional, default: None + Actor/s to be animated. + length : float or int, default: None, optional + the fixed length of the animation. If set to None, the animation will + get its duration from the keyframes being set. + loop : bool, optional, default: True + Whether to loop the animation (True) of play once (False). + motion_path_res : int, default: None + the number of line segments used to visualizer the animation's motion + path (visualizing position). + + """ + +
+[docs] + def __init__(self, actors=None, length=None, loop=True, motion_path_res=None): + + super().__init__() + self._data = defaultdict(dict) + self._animations = [] + self._actors = [] + self._static_actors = [] + self._timeline = None + self._parent_animation = None + self._scene = None + self._start_time = 0 + self._length = length + self._duration = length if length else 0 + self._loop = loop + self._current_timestamp = 0 + self._max_timestamp = 0 + self._added_to_scene = True + self._motion_path_res = motion_path_res + self._motion_path_actor = None + self._transform = Transform() + self._general_callbacks = [] + # Adding actors to the animation + if actors is not None: + self.add_actor(actors)
+ + +
+[docs] + def update_duration(self): + """Update and return the duration of the Animation. + + Returns + ------- + float + The duration of the animation. + + """ + if self._length is not None: + self._duration = self._length + else: + self._duration = max( + self._max_timestamp, + max([0] + [anim.update_duration() for anim in self.child_animations]), + ) + + return self.duration
+ + + @property + def duration(self): + """Return the duration of the animation. + + Returns + ------- + float + The duration of the animation. + + """ + return self._duration + + @property + def current_timestamp(self): + """Return the current time of the animation. + + Returns + ------- + float + The current time of the animation. + + """ + if self._timeline: + return self._timeline.current_timestamp + elif self.parent_animation: + return self.parent_animation.current_timestamp + return self._current_timestamp + +
+[docs] + def update_motion_path(self): + """Update motion path visualization actor""" + res = self._motion_path_res + tl = self + while isinstance(tl._parent_animation, Animation): + if res: + break + tl = tl._parent_animation + res = tl._motion_path_res + if not res: + return + + lines = [] + colors = [] + if self.is_interpolatable('position'): + ts = np.linspace(0, self.duration, res) + [lines.append(self.get_position(t).tolist()) for t in ts] + if self.is_interpolatable('color'): + [colors.append(self.get_color(t)) for t in ts] + elif len(self._actors) >= 1: + colors = sum([i.vcolors[0] / 255 for i in self._actors]) / len( + self._actors + ) + else: + colors = [1, 1, 1] + + if len(lines) > 0: + lines = np.array([lines]) + if isinstance(colors, list): + colors = np.array([colors]) + + mpa = line(lines, colors=colors, opacity=0.6) + if self._scene: + # remove old motion path actor + if self._motion_path_actor is not None: + self._scene.rm(self._motion_path_actor) + self._scene.add(mpa) + self._motion_path_actor = mpa
+ + + def _get_data(self): + """Get animation data. + + Returns + ------- + dict: + The animation data containing keyframes and interpolators. + + """ + return self._data + + def _get_attribute_data(self, attrib): + """Get animation data for a specific attribute. + + Parameters + ---------- + attrib: str + The attribute name to get data for. + + Returns + ------- + dict: + The animation data for a specific attribute. + + """ + data = self._get_data() + + if attrib not in data: + data[attrib] = { + 'keyframes': defaultdict(dict), + 'interpolator': { + 'base': linear_interpolator if attrib != 'rotation' else slerp, + 'func': None, + 'args': defaultdict(), + }, + 'callbacks': [], + } + return data.get(attrib) + +
+[docs] + def get_keyframes(self, attrib=None): + """Get a keyframe for a specific or all attributes. + + Parameters + ---------- + attrib: str, optional, default: None + The name of the attribute. + If None, all keyframes for all set attributes will be returned. + + """ + data = self._get_data() + if attrib is None: + attribs = data.keys() + return { + attrib: data.get(attrib, {}).get('keyframes', {}) for attrib in attribs + } + return data.get(attrib, {}).get('keyframes', {})
+ + +
+[docs] + def set_keyframe( + self, attrib, timestamp, value, update_interpolator=True, **kwargs + ): + """Set a keyframe for a certain attribute. + + Parameters + ---------- + attrib: str + The name of the attribute. + timestamp: float + Timestamp of the keyframe. + value: ndarray or float or bool + Value of the keyframe at the given timestamp. + update_interpolator: bool, optional + Interpolator will be reinitialized if True + + Other Parameters + ---------------- + in_cp: ndarray, shape (1, M), optional + The in control point in case of using cubic Bézier interpolator. + out_cp: ndarray, shape (1, M), optional + The out control point in case of using cubic Bézier interpolator. + in_tangent: ndarray, shape (1, M), optional + The in tangent at that position for the cubic spline curve. + out_tangent: ndarray, shape (1, M), optional + The out tangent at that position for the cubic spline curve. + + """ + attrib_data = self._get_attribute_data(attrib) + keyframes = attrib_data.get('keyframes') + + keyframes[timestamp] = { + 'value': np.array(value).astype(float), + **{ + par: np.array(val).astype(float) + for par, val in kwargs.items() + if val is not None + }, + } + + if update_interpolator: + interp = attrib_data.get('interpolator') + interp_base = interp.get( + 'base', linear_interpolator if attrib != 'rotation' else slerp + ) + args = interp.get('args', {}) + self.set_interpolator(attrib, interp_base, **args) + + if timestamp > self._max_timestamp: + self._max_timestamp = timestamp + if self._timeline is not None: + self._timeline.update_duration() + else: + self.update_duration() + self.update_animation(0) + self.update_motion_path()
+ + +
+[docs] + def set_keyframes(self, attrib, keyframes): + """Set multiple keyframes for a certain attribute. + + Parameters + ---------- + attrib: str + The name of the attribute. + keyframes: dict + A dict object containing keyframes to be set. + + Notes + ----- + Keyframes can be on any of the following forms: + >>> key_frames_simple = {1: [1, 2, 1], 2: [3, 4, 5]} + >>> key_frames_bezier = {1: {'value': [1, 2, 1]}, + >>> 2: {'value': [3, 4, 5], 'in_cp': [1, 2, 3]}} + >>> pos_keyframes = {1: np.array([1, 2, 3]), 3: np.array([5, 5, 5])} + >>> Animation.set_keyframes('position', pos_keyframes) + + """ + for t, keyframe in keyframes.items(): + if isinstance(keyframe, dict): + self.set_keyframe(attrib, t, **keyframe) + else: + self.set_keyframe(attrib, t, keyframe)
+ + +
+[docs] + def is_inside_scene_at(self, timestamp): + """Check if the Animation is set to be inside the scene at a specific + timestamp. + + Returns + ------- + bool + True if the Animation is set to be inside the scene at the given + timestamp. + + Notes + ----- + If the parent Animation is set to be out of the scene at that time, all + of their child animations will be out of the scene as well. + + """ + parent = self._parent_animation + parent_in_scene = True + if parent is not None: + parent_in_scene = parent._added_to_scene + + if self.is_interpolatable('in_scene'): + in_scene = parent_in_scene and self.get_value('in_scene', timestamp) + else: + in_scene = parent_in_scene + return in_scene
+ + +
+[docs] + def add_to_scene_at(self, timestamp): + """Set timestamp for adding Animation to scene event. + + Parameters + ---------- + timestamp: float + Timestamp of the event. + + """ + if not self.is_interpolatable('in_scene'): + self.set_keyframe('in_scene', timestamp, True) + self.set_interpolator('in_scene', step_interpolator) + else: + self.set_keyframe('in_scene', timestamp, True)
+ + +
+[docs] + def remove_from_scene_at(self, timestamp): + """Set timestamp for removing Animation to scene event. + + Parameters + ---------- + timestamp: float + Timestamp of the event. + + """ + if not self.is_interpolatable('in_scene'): + self.set_keyframe('in_scene', timestamp, False) + self.set_interpolator('in_scene', step_interpolator) + else: + self.set_keyframe('in_scene', timestamp, False)
+ + + def _handle_scene_event(self, timestamp): + should_be_in_scene = self.is_inside_scene_at(timestamp) + if self._scene is not None: + if should_be_in_scene and not self._added_to_scene: + self._scene.add(*self._actors) + self._added_to_scene = True + elif not should_be_in_scene and self._added_to_scene: + self._scene.rm(*self._actors) + self._added_to_scene = False + +
+[docs] + def set_interpolator(self, attrib, interpolator, is_evaluator=False, **kwargs): + """Set keyframes interpolator for a certain property + + Parameters + ---------- + attrib: str + The name of the property. + interpolator: callable + The generator function of the interpolator to be used to + interpolate/evaluate keyframes. + is_evaluator: bool, optional + Specifies whether the `interpolator` is time-only based evaluation + function that does not depend on keyframes such as: + >>> def get_position(t): + >>> return np.array([np.sin(t), np.cos(t) * 5, 5]) + + Other Parameters + ---------------- + spline_degree: int, optional + The degree of the spline in case of setting a spline interpolator. + + Notes + ----- + If an evaluator is used to set the values of actor's properties such as + position, scale, color, rotation, or opacity, it has to return a value + with the same shape as the evaluated property, i.e.: for scale, it + has to return an array with shape 1x3, and for opacity, it has to + return a 1x1, an int, or a float value. + + Examples + -------- + >>> Animation.set_interpolator('position', linear_interpolator) + + >>> pos_fun = lambda t: np.array([np.sin(t), np.cos(t), 0]) + >>> Animation.set_interpolator('position', pos_fun) + + """ + attrib_data = self._get_attribute_data(attrib) + keyframes = attrib_data.get('keyframes', {}) + interp_data = attrib_data.get('interpolator', {}) + if is_evaluator: + interp_data['base'] = None + interp_data['func'] = interpolator + else: + interp_data['base'] = interpolator + interp_data['args'] = kwargs + # Maintain interpolator base in case new keyframes are added. + if len(keyframes) == 0: + return + new_interp = interpolator(keyframes, **kwargs) + interp_data['func'] = new_interp + + # update motion path + self.update_duration() + self.update_motion_path()
+ + +
+[docs] + def is_interpolatable(self, attrib): + """Check whether a property is interpolatable. + + Parameters + ---------- + attrib: str + The name of the property. + + Returns + ------- + bool + True if the property is interpolatable by the Animation. + + Notes + ----- + True means that it's safe to use `Interpolator.interpolate(t)` for the + specified property. And False means the opposite. + + """ + data = self._data + return bool(data.get(attrib, {}).get('interpolator', {}).get('func'))
+ + +
+[docs] + def set_position_interpolator(self, interpolator, is_evaluator=False, **kwargs): + """Set the position interpolator. + + Parameters + ---------- + interpolator: callable + The generator function of the interpolator that would handle the + position keyframes. + is_evaluator: bool, optional + Specifies whether the `interpolator` is time-only based evaluation + function that does not depend on keyframes. + + Other Parameters + ---------------- + degree: int + The degree of the spline interpolation in case of setting + the `spline_interpolator`. + + Examples + -------- + >>> Animation.set_position_interpolator(spline_interpolator, degree=5) + + """ + self.set_interpolator( + 'position', interpolator, is_evaluator=is_evaluator, **kwargs + )
+ + +
+[docs] + def set_scale_interpolator(self, interpolator, is_evaluator=False): + """Set the scale interpolator. + + Parameters + ---------- + interpolator: callable + The generator function of the interpolator that would handle + the scale keyframes. + is_evaluator: bool, optional + Specifies whether the `interpolator` is time-only based evaluation + function that does not depend on keyframes. + + Examples + -------- + >>> Animation.set_scale_interpolator(step_interpolator) + + """ + self.set_interpolator('scale', interpolator, is_evaluator=is_evaluator)
+ + +
+[docs] + def set_rotation_interpolator(self, interpolator, is_evaluator=False): + """Set the rotation interpolator . + + Parameters + ---------- + interpolator: callable + The generator function of the interpolator that would handle the + rotation (orientation) keyframes. + is_evaluator: bool, optional + Specifies whether the `interpolator` is time-only based evaluation + function that does not depend on keyframes. + + Examples + -------- + >>> Animation.set_rotation_interpolator(slerp) + + """ + self.set_interpolator('rotation', interpolator, is_evaluator=is_evaluator)
+ + +
+[docs] + def set_color_interpolator(self, interpolator, is_evaluator=False): + """Set the color interpolator. + + Parameters + ---------- + interpolator: callable + The generator function of the interpolator that would handle + the color keyframes. + is_evaluator: bool, optional + Specifies whether the `interpolator` is time-only based evaluation + function that does not depend on keyframes. + + Examples + -------- + >>> Animation.set_color_interpolator(lab_color_interpolator) + + """ + self.set_interpolator('color', interpolator, is_evaluator=is_evaluator)
+ + +
+[docs] + def set_opacity_interpolator(self, interpolator, is_evaluator=False): + """Set the opacity interpolator. + + Parameters + ---------- + interpolator: callable + The generator function of the interpolator that would handle + the opacity keyframes. + is_evaluator: bool, optional + Specifies whether the `interpolator` is time-only based evaluation + function that does not depend on keyframes. + + Examples + -------- + >>> Animation.set_opacity_interpolator(step_interpolator) + + """ + self.set_interpolator('opacity', interpolator, is_evaluator=is_evaluator)
+ + +
+[docs] + def get_value(self, attrib, timestamp): + """Return the value of an attribute at any given timestamp. + + Parameters + ---------- + attrib: str + The attribute name. + timestamp: float + The timestamp to interpolate at. + + """ + value = ( + self._data.get(attrib, {}).get('interpolator', {}).get('func')(timestamp) + ) + return value
+ + +
+[docs] + def get_current_value(self, attrib): + """Return the value of an attribute at current time. + + Parameters + ---------- + attrib: str + The attribute name. + + """ + return ( + self._data.get(attrib) + .get('interpolator') + .get('func')(self._timeline.current_timestamp) + )
+ + +
+[docs] + def set_position(self, timestamp, position, **kwargs): + """Set a position keyframe at a specific timestamp. + + Parameters + ---------- + timestamp: float + Timestamp of the keyframe + position: ndarray, shape (1, 3) + Position value + + Other Parameters + ---------------- + in_cp: float + The control point in case of using `cubic Bézier interpolator` when + time exceeds this timestamp. + out_cp: float + The control point in case of using `cubic Bézier interpolator` when + time precedes this timestamp. + in_tangent: ndarray, shape (1, M), optional + The in tangent at that position for the cubic spline curve. + out_tangent: ndarray, shape (1, M), optional + The out tangent at that position for the cubic spline curve. + + Notes + ----- + `in_cp` and `out_cp` only needed when using the cubic bezier + interpolation method. + + """ + self.set_keyframe('position', timestamp, position, **kwargs)
+ + +
+[docs] + def set_position_keyframes(self, keyframes): + """Set a dict of position keyframes at once. + Should be in the following form: + {timestamp_1: position_1, timestamp_2: position_2} + + Parameters + ---------- + keyframes: dict + A dict with timestamps as keys and positions as values. + + Examples + -------- + >>> pos_keyframes = {1, np.array([0, 0, 0]), 3, np.array([50, 6, 6])} + >>> Animation.set_position_keyframes(pos_keyframes) + + """ + self.set_keyframes('position', keyframes)
+ + +
+[docs] + def set_rotation(self, timestamp, rotation, **kwargs): + """Set a rotation keyframe at a specific timestamp. + + Parameters + ---------- + timestamp: float + Timestamp of the keyframe + rotation: ndarray, shape(1, 3) or shape(1, 4) + Rotation data in euler degrees with shape(1, 3) or in quaternions + with shape(1, 4). + + Notes + ----- + Euler rotations are executed by rotating first around Z then around X, + and finally around Y. + + """ + no_components = len(np.array(rotation).flatten()) + if no_components == 4: + self.set_keyframe('rotation', timestamp, rotation, **kwargs) + elif no_components == 3: + # user is expected to set rotation order by default as setting + # orientation of a `vtkActor` ordered as z->x->y. + rotation = np.asarray(rotation, dtype=float) + rotation = transform.Rotation.from_euler( + 'zxy', rotation[[2, 0, 1]], degrees=True + ).as_quat() + self.set_keyframe('rotation', timestamp, rotation, **kwargs) + else: + warn( + f'Keyframe with {no_components} components is not a ' + f'valid rotation data. Skipped!' + )
+ + +
+[docs] + def set_rotation_as_vector(self, timestamp, vector, **kwargs): + """Set a rotation keyframe at a specific timestamp. + + Parameters + ---------- + timestamp: float + Timestamp of the keyframe + vector: ndarray, shape(1, 3) + Directional vector that describes the rotation. + + """ + quat = transform.Rotation.from_rotvec(vector).as_quat() + self.set_keyframe('rotation', timestamp, quat, **kwargs)
+ + +
+[docs] + def set_scale(self, timestamp, scalar, **kwargs): + """Set a scale keyframe at a specific timestamp. + + Parameters + ---------- + timestamp: float + Timestamp of the keyframe + scalar: ndarray, shape(1, 3) + Scale keyframe value associated with the timestamp. + + """ + self.set_keyframe('scale', timestamp, scalar, **kwargs)
+ + +
+[docs] + def set_scale_keyframes(self, keyframes): + """Set a dict of scale keyframes at once. + Should be in the following form: + {timestamp_1: scale_1, timestamp_2: scale_2} + + Parameters + ---------- + keyframes: dict + A dict with timestamps as keys and scales as values. + + Examples + -------- + >>> scale_keyframes = {1, np.array([1, 1, 1]), 3, np.array([2, 2, 3])} + >>> Animation.set_scale_keyframes(scale_keyframes) + + """ + self.set_keyframes('scale', keyframes)
+ + +
+[docs] + def set_color(self, timestamp, color, **kwargs): + """Set color keyframe at a specific timestamp. + + Parameters + ---------- + timestamp: float + Timestamp of the keyframe + color: ndarray, shape(1, 3) + Color keyframe value associated with the timestamp. + + """ + self.set_keyframe('color', timestamp, color, **kwargs)
+ + +
+[docs] + def set_color_keyframes(self, keyframes): + """Set a dict of color keyframes at once. + Should be in the following form: + {timestamp_1: color_1, timestamp_2: color_2} + + Parameters + ---------- + keyframes: dict + A dict with timestamps as keys and color as values. + + Examples + -------- + >>> color_keyframes = {1, np.array([1, 0, 1]), 3, np.array([0, 0, 1])} + >>> Animation.set_color_keyframes(color_keyframes) + + """ + self.set_keyframes('color', keyframes)
+ + +
+[docs] + def set_opacity(self, timestamp, opacity, **kwargs): + """Set opacity keyframe at a specific timestamp. + + Parameters + ---------- + timestamp: float + Timestamp of the keyframe + opacity: ndarray, shape(1, 3) + Opacity keyframe value associated with the timestamp. + + """ + self.set_keyframe('opacity', timestamp, opacity, **kwargs)
+ + +
+[docs] + def set_opacity_keyframes(self, keyframes): + """Set a dict of opacity keyframes at once. + Should be in the following form: + {timestamp_1: opacity_1, timestamp_2: opacity_2} + + Parameters + ---------- + keyframes: dict(float: ndarray, shape(1, 1) or float or int) + A dict with timestamps as keys and opacities as values. + + Notes + ----- + Opacity values should be between 0 and 1. + + Examples + -------- + >>> opacity = {1, np.array([1, 1, 1]), 3, np.array([2, 2, 3])} + >>> Animation.set_scale_keyframes(opacity) + + """ + self.set_keyframes('opacity', keyframes)
+ + +
+[docs] + def get_position(self, t): + """Return the interpolated position. + + Parameters + ---------- + t: float + The time to interpolate position at. + + Returns + ------- + ndarray(1, 3): + The interpolated position. + + """ + return self.get_value('position', t)
+ + +
+[docs] + def get_rotation(self, t, as_quat=False): + """Return the interpolated rotation. + + Parameters + ---------- + t: float + the time to interpolate rotation at. + as_quat: bool + Returned rotation will be as quaternion if True. + + Returns + ------- + ndarray(1, 3): + The interpolated rotation as Euler degrees by default. + + """ + rot = self.get_value('rotation', t) + if len(rot) == 4: + if as_quat: + return rot + r = transform.Rotation.from_quat(rot) + degrees = r.as_euler('zxy', degrees=True)[[1, 2, 0]] + return degrees + elif not as_quat: + return rot + return transform.Rotation.from_euler( + 'zxy', rot[[2, 0, 1]], degrees=True + ).as_quat()
+ + +
+[docs] + def get_scale(self, t): + """Return the interpolated scale. + + Parameters + ---------- + t: float + The time to interpolate scale at. + + Returns + ------- + ndarray(1, 3): + The interpolated scale. + + """ + return self.get_value('scale', t)
+ + +
+[docs] + def get_color(self, t): + """Return the interpolated color. + + Parameters + ---------- + t: float + The time to interpolate color value at. + + Returns + ------- + ndarray(1, 3): + The interpolated color. + + """ + return self.get_value('color', t)
+ + +
+[docs] + def get_opacity(self, t): + """Return the opacity value. + + Parameters + ---------- + t: float + The time to interpolate opacity at. + + Returns + ------- + ndarray(1, 1): + The interpolated opacity. + + """ + return self.get_value('opacity', t)
+ + +
+[docs] + def add(self, item): + """Add an item to the Animation. + This item can be an Actor, Animation, list of Actors, or a list of + Animations. + + Parameters + ---------- + item: Animation, vtkActor, list[Animation], or list[vtkActor] + Actor/s to be animated by the Animation. + + """ + if isinstance(item, list): + for a in item: + self.add(a) + return + elif isinstance(item, Actor): + self.add_actor(item) + elif isinstance(item, Animation): + self.add_child_animation(item) + else: + raise ValueError(f"Object of type {type(item)} can't be animated")
+ + +
+[docs] + def add_child_animation(self, animation): + """Add child Animation or list of Animations. + + Parameters + ---------- + animation: Animation or list[Animation] + Animation/s to be added. + + """ + if isinstance(animation, list): + for a in animation: + self.add_child_animation(a) + return + animation._parent_animation = self + animation.update_motion_path() + self._animations.append(animation) + self.update_duration()
+ + +
+[docs] + def add_actor(self, actor, static=False): + """Add an actor or list of actors to the Animation. + + Parameters + ---------- + actor: vtkActor or list(vtkActor) + Actor/s to be animated by the Animation. + static: bool + Indicated whether the actor should be animated and controlled by + the animation or just a static actor that gets added to the scene + along with the Animation. + + """ + if isinstance(actor, list): + for a in actor: + self.add_actor(a, static=static) + elif static: + if actor not in self.static_actors: + self._static_actors.append(actor) + else: + if actor not in self._actors: + actor.vcolors = utils.colors_from_actor(actor) + self._actors.append(actor)
+ + + @property + def timeline(self): + """Return the Timeline handling the current animation. + + Returns + ------- + Timeline: + The Timeline handling the current animation, None, if there is no + associated Timeline. + + """ + return self._timeline + + @timeline.setter + def timeline(self, timeline): + """Assign the Timeline responsible for handling the Animation. + + Parameters + ---------- + timeline: Timeline + The Timeline handling the current animation, None, if there is no + associated Timeline. + + """ + self._timeline = timeline + if self._animations: + for animation in self._animations: + animation.timeline = timeline + + @property + def parent_animation(self): + """Return the hierarchical parent Animation for current Animation. + + Returns + ------- + Animation: + The parent Animation. + + """ + return self._parent_animation + + @parent_animation.setter + def parent_animation(self, parent_animation): + """Assign a parent Animation for the current Animation. + + Parameters + ---------- + parent_animation: Animation + The parent Animation instance. + + """ + self._parent_animation = parent_animation + + @property + def actors(self): + """Return a list of actors. + + Returns + ------- + list: + List of actors controlled by the Animation. + + """ + return self._actors + + @property + def child_animations(self) -> 'list[Animation]': + """Return a list of child Animations. + + Returns + ------- + list: + List of child Animations of this Animation. + + """ + return self._animations + +
+[docs] + def add_static_actor(self, actor): + """Add an actor or list of actors as static actor/s which will not be + controlled nor animated by the Animation. All static actors will be + added to the scene when the Animation is added to the scene. + + Parameters + ---------- + actor: vtkActor or list(vtkActor) + Static actor/s. + + """ + self.add_actor(actor, static=True)
+ + + @property + def static_actors(self): + """Return a list of static actors. + + Returns + ------- + list: + List of static actors. + + """ + return self._static_actors + +
+[docs] + def remove_animations(self): + """Remove all child Animations from the Animation""" + self._animations.clear()
+ + +
+[docs] + def remove_actor(self, actor): + """Remove an actor from the Animation. + + Parameters + ---------- + actor: vtkActor + Actor to be removed from the Animation. + + """ + self._actors.remove(actor)
+ + +
+[docs] + def remove_actors(self): + """Remove all actors from the Animation""" + self._actors.clear()
+ + + @property + def loop(self): + """Get loop condition of the current animation. + + Returns + ------- + bool + Whether the animation in loop mode (True) or play one mode (False). + + """ + return self._loop + + @loop.setter + def loop(self, loop): + """Set the animation to loop or play once. + + Parameters + ---------- + loop: bool + The loop condition to be set. (True) to loop the animation, and + (False) to play only once. + + """ + self._loop = loop + +
+[docs] + def add_update_callback(self, callback, prop=None): + """Add a function to be called each time animation is updated + This function must accept only one argument which is the current value + of the named property. + + + Parameters + ---------- + callback: callable + The function to be called whenever the animation is updated. + prop: str, optional, default: None + The name of the property. + + Notes + ----- + If no attribute name was provided, current time of the animation will + be provided instead of current value for the callback. + + """ + if prop is None: + self._general_callbacks.append(callback) + return + attrib = self._get_attribute_data(prop) + attrib.get('callbacks', []).append(callback)
+ + +
+[docs] + def update_animation(self, time=None): + """Update the animation. + + Update the animation at a certain time. This will make sure all + attributes are calculated and set to the actors at that given time. + + Parameters + ---------- + time: float or int, optional, default: None + The time to update animation at. If None, the animation will play + without adding it to a Timeline. + + """ + has_handler = True + if time is None: + time = perf_counter() - self._start_time + has_handler = False + + # handling in/out of scene events + in_scene = self.is_inside_scene_at(time) + self._handle_scene_event(time) + + if self.duration: + if self._loop and time > self.duration: + time = time % self.duration + elif time > self.duration: + time = self.duration + if isinstance(self._parent_animation, Animation): + self._transform.DeepCopy(self._parent_animation._transform) + else: + self._transform.Identity() + + self._current_timestamp = time + + # actors properties + if in_scene: + if self.is_interpolatable('position'): + position = self.get_position(time) + self._transform.Translate(*position) + + if self.is_interpolatable('opacity'): + opacity = self.get_opacity(time) + [act.GetProperty().SetOpacity(opacity) for act in self.actors] + + if self.is_interpolatable('rotation'): + x, y, z = self.get_rotation(time) + # Rotate in the same order as VTK defaults. + self._transform.RotateZ(z) + self._transform.RotateX(x) + self._transform.RotateY(y) + + if self.is_interpolatable('scale'): + scale = self.get_scale(time) + self._transform.Scale(*scale) + + if self.is_interpolatable('color'): + color = self.get_color(time) + for act in self.actors: + act.vcolors[:] = color * 255 + utils.update_actor(act) + + # update actors' transformation matrix + [act.SetUserTransform(self._transform) for act in self.actors] + + for attrib in self._data: + callbacks = self._data.get(attrib, {}).get('callbacks', []) + if callbacks != [] and self.is_interpolatable(attrib): + value = self.get_value(attrib, time) + [cbk(value) for cbk in callbacks] + + # Executing general callbacks that's not related to any attribute + [callback(time) for callback in self._general_callbacks] + + # Also update all child Animations. + [animation.update_animation(time) for animation in self._animations] + + if self._scene and not has_handler: + self._scene.reset_clipping_range()
+ + +
+[docs] + def add_to_scene(self, scene): + """Add this Animation, its actors and sub Animations to the scene""" + [scene.add(actor) for actor in self._actors] + [scene.add(static_act) for static_act in self._static_actors] + [scene.add(animation) for animation in self._animations] + + if self._motion_path_actor: + scene.add(self._motion_path_actor) + self._scene = scene + self._added_to_scene = True + self._start_time = perf_counter() + self.update_animation(0)
+ + +
+[docs] + def remove_from_scene(self, scene): + """Remove Animation, its actors and sub Animations from the scene""" + [scene.rm(act) for act in self.actors] + [scene.rm(static_act) for static_act in self._static_actors] + for anim in self.child_animations: + anim.remove_from_scene(scene) + if self._motion_path_actor: + scene.rm(self._motion_path_actor) + self._added_to_scene = False
+
+ + + +
+[docs] +class CameraAnimation(Animation): + """Camera keyframe animation class. + + This is used for animating a single camera using a set of keyframes. + + Attributes + ---------- + camera : Camera, optional, default: None + Camera to be animated. If None, active camera will be animated. + length : float or int, default: None, optional + the fixed length of the animation. If set to None, the animation will + get its duration from the keyframes being set. + loop : bool, optional, default: True + Whether to loop the animation (True) of play once (False). + motion_path_res : int, default: None + the number of line segments used to visualizer the animation's motion + path (visualizing position). + + """ + +
+[docs] + def __init__(self, camera=None, length=None, loop=True, motion_path_res=None): + super(CameraAnimation, self).__init__( + length=length, loop=loop, motion_path_res=motion_path_res + ) + self._camera = camera
+ + + @property + def camera(self) -> Camera: + """Return the camera assigned to this animation. + + Returns + ------- + Camera: + The camera that is being animated by this CameraAnimation. + + """ + return self._camera + + @camera.setter + def camera(self, camera: Camera): + """Set a camera to be animated. + + Parameters + ---------- + camera: Camera + The camera to be animated + + """ + self._camera = camera + +
+[docs] + def set_focal(self, timestamp, position, **kwargs): + """Set camera's focal position keyframe. + + Parameters + ---------- + timestamp: float + The time to interpolate opacity at. + position: ndarray, shape(1, 3) + The camera position + + """ + self.set_keyframe('focal', timestamp, position, **kwargs)
+ + +
+[docs] + def set_view_up(self, timestamp, direction, **kwargs): + """Set the camera view-up direction keyframe. + + Parameters + ---------- + timestamp: float + The time to interpolate at. + direction: ndarray, shape(1, 3) + The camera view-up direction + + """ + self.set_keyframe('view_up', timestamp, direction, **kwargs)
+ + +
+[docs] + def set_focal_keyframes(self, keyframes): + """Set multiple camera focal position keyframes at once. + Should be in the following form: + {timestamp_1: focal_1, timestamp_2: focal_1, ...} + + Parameters + ---------- + keyframes: dict + A dict with timestamps as keys and camera focal positions as + values. + + Examples + -------- + >>> focal_pos = {0, np.array([1, 1, 1]), 3, np.array([20, 0, 0])} + >>> CameraAnimation.set_focal_keyframes(focal_pos) + + """ + self.set_keyframes('focal', keyframes)
+ + +
+[docs] + def set_view_up_keyframes(self, keyframes): + """Set multiple camera view up direction keyframes. + Should be in the following form: + {timestamp_1: view_up_1, timestamp_2: view_up_2, ...} + + Parameters + ---------- + keyframes: dict + A dict with timestamps as keys and camera view up vectors as + values. + + Examples + -------- + >>> view_ups = {0, np.array([1, 0, 0]), 3, np.array([0, 1, 0])} + >>> CameraAnimation.set_view_up_keyframes(view_ups) + + """ + self.set_keyframes('view_up', keyframes)
+ + +
+[docs] + def get_focal(self, t): + """Return the interpolated camera's focal position. + + Parameters + ---------- + t: float + The time to interpolate at. + + Returns + ------- + ndarray(1, 3): + The interpolated camera's focal position. + + Notes + ----- + The returned focal position does not necessarily reflect the current + camera's focal position, but the expected one. + + """ + return self.get_value('focal', t)
+ + +
+[docs] + def get_view_up(self, t): + """Return the interpolated camera's view-up directional vector. + + Parameters + ---------- + t: float + The time to interpolate at. + + Returns + ------- + ndarray(1, 3): + The interpolated camera view-up directional vector. + + Notes + ----- + The returned focal position does not necessarily reflect the actual + camera view up directional vector, but the expected one. + + """ + return self.get_value('view_up', t)
+ + +
+[docs] + def set_focal_interpolator(self, interpolator, is_evaluator=False): + """Set the camera focal position interpolator. + + Parameters + ---------- + interpolator: callable + The generator function of the interpolator that would handle the + interpolation of the camera focal position keyframes. + is_evaluator: bool, optional + Specifies whether the `interpolator` is time-only based evaluation + function that does not depend on keyframes. + + """ + self.set_interpolator('focal', interpolator, is_evaluator=is_evaluator)
+ + +
+[docs] + def set_view_up_interpolator(self, interpolator, is_evaluator=False): + """Set the camera up-view vector animation interpolator. + + Parameters + ---------- + interpolator: callable + The generator function of the interpolator that would handle the + interpolation of the camera view-up keyframes. + is_evaluator: bool, optional + Specifies whether the `interpolator` is time-only based evaluation + function that does not depend on keyframes. + + """ + self.set_interpolator('view_up', interpolator, is_evaluator=is_evaluator)
+ + +
+[docs] + def update_animation(self, time=None): + """Update the camera animation. + + Parameters + ---------- + time: float or int, optional, default: None + The time to update the camera animation at. If None, the animation + will play. + + """ + if self._camera is None: + if self._scene: + self._camera = self._scene.camera() + self.update_animation(time) + return + else: + if self.is_interpolatable('rotation'): + pos = self._camera.GetPosition() + translation = np.identity(4) + translation[:3, 3] = pos + # camera axis is reverted + rot = -self.get_rotation(time, as_quat=True) + rot = transform.Rotation.from_quat(rot).as_matrix() + rot = np.array([[*rot[0], 0], [*rot[1], 0], [*rot[2], 0], [0, 0, 0, 1]]) + rot = translation @ rot @ np.linalg.inv(translation) + self._camera.SetModelTransformMatrix(rot.flatten()) + + if self.is_interpolatable('position'): + cam_pos = self.get_position(time) + self._camera.SetPosition(cam_pos) + + if self.is_interpolatable('focal'): + cam_foc = self.get_focal(time) + self._camera.SetFocalPoint(cam_foc) + + if self.is_interpolatable('view_up'): + cam_up = self.get_view_up(time) + self._camera.SetViewUp(cam_up) + elif not self.is_interpolatable('view_up'): + # to preserve up-view as default after user interaction + self._camera.SetViewUp(0, 1, 0) + if self._scene: + self._scene.reset_clipping_range()
+
+ +
+
+ + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/_modules/fury/animation/helpers.html b/v0.10.x/_modules/fury/animation/helpers.html new file mode 100644 index 000000000..461b31533 --- /dev/null +++ b/v0.10.x/_modules/fury/animation/helpers.html @@ -0,0 +1,634 @@ + + + + + + + fury.animation.helpers — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +

Source code for fury.animation.helpers

+import numpy as np
+
+
+
+[docs] +def get_previous_timestamp(timestamps, current_time, include_last=False): + """Return the maximum previous timestamp of a given time. + + Parameters + ---------- + timestamps : ndarray + Sorted list of timestamps. + current_time : float or int + The time to get previous timestamp for. + include_last: bool, optional, default: False + If `True`, even the last timestamp will be considered a valid previous + timestamp. + + Returns + ------- + float or int + The previous timestamp + + """ + for timestamp in timestamps[::-1] if include_last else timestamps[-2::-1]: + if timestamp <= current_time: + return timestamp + return timestamps[0]
+ + + +
+[docs] +def get_next_timestamp(timestamps, current_time, include_first=False): + """Return the minimum next timestamp of a given time. + + Parameters + ---------- + timestamps : ndarray + Sorted list of timestamps. + current_time : float or int + The time to get previous timestamp for. + include_first: bool, optional, default: False + If `True`, even the first timestamp will be considered a valid next + timestamp. + + Returns + ------- + float or int + The next timestamp + + """ + for timestamp in timestamps[:] if include_first else timestamps[1:]: + if timestamp > current_time: + return timestamp + return timestamps[-1]
+ + + +
+[docs] +def get_timestamps_from_keyframes(keyframes): + """Return a sorted array of timestamps given dict of keyframes. + + Parameters + ---------- + keyframes : dict + keyframes dict that contains timestamps as keys. + + Returns + ------- + ndarray + Array of sorted timestamps extracted from the keyframes. + + """ + return np.sort(np.array(list(keyframes)), axis=None)
+ + + +
+[docs] +def get_values_from_keyframes(keyframes): + """Return an array of keyframes values sorted using timestamps. + + Parameters + ---------- + keyframes : dict + keyframes dict that contains timestamps as keys and data as values. + + Returns + ------- + ndarray + Array of sorted values extracted from the keyframes. + + """ + return np.asarray( + [keyframes.get(t, {}).get('value', None) for t in sorted(keyframes.keys())] + )
+ + + +
+[docs] +def get_time_tau(t, t0, t1): + """Return a capped time tau between 0 and 1. + + Parameters + ---------- + t : float or int + Current time to calculate tau for. + t0 : float or int + Lower timestamp of the time period. + t1 : float or int + Higher timestamp of the time period. + + Returns + ------- + float + The time tau + + """ + return 0 if t <= t0 else 1 if t >= t1 else (t - t0) / (t1 - t0)
+ + + +
+[docs] +def lerp(v0, v1, t0, t1, t): + """Return a linearly interpolated value. + + Parameters + ---------- + v0: ndarray or float or int. + The first value + v1: ndarray or float or int. + The second value + t : float or int + Current time to interpolate at. + t0 : float or int + Timestamp associated with v0. + t1 : float or int + Timestamp associated with v1. + + Returns + ------- + ndarray or float + The interpolated value + + """ + if t0 == t1: + return v0 + v = v1 - v0 + dt = get_time_tau(t, t0, t1) + return dt * v + v0
+ + + +
+[docs] +def euclidean_distances(points): + """Return a list of euclidean distances of a list of points or values. + + Parameters + ---------- + points: ndarray + Array of points or valued to calculate euclidean distances between. + + Returns + ------- + list + A List of euclidean distance between each consecutive points or values. + + """ + return [np.linalg.norm(x - y) for x, y in zip(points, points[1:])]
+ +
+
+ + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/_modules/fury/animation/interpolator.html b/v0.10.x/_modules/fury/animation/interpolator.html new file mode 100644 index 000000000..8026fad99 --- /dev/null +++ b/v0.10.x/_modules/fury/animation/interpolator.html @@ -0,0 +1,865 @@ + + + + + + + fury.animation.interpolator — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +

Source code for fury.animation.interpolator

+import numpy as np
+from scipy.interpolate import splev, splprep
+from scipy.spatial import transform
+
+from fury.animation.helpers import (
+    euclidean_distances,
+    get_next_timestamp,
+    get_previous_timestamp,
+    get_time_tau,
+    get_timestamps_from_keyframes,
+    get_values_from_keyframes,
+    lerp,
+)
+from fury.colormap import hsv2rgb, lab2rgb, rgb2hsv, rgb2lab, rgb2xyz, xyz2rgb
+
+
+
+[docs] +def spline_interpolator(keyframes, degree): + """N-th degree spline interpolator for keyframes. + + This is a general n-th degree spline interpolator to be used for any shape + of keyframes data. + + Parameters + ---------- + keyframes: dict + Keyframe data containing timestamps and values to form the spline + curve. Data should be on the following format: + >>> {1: {'value': np.array([...])}, 2: {'value': np.array([...])}} + + Returns + ------- + function + The interpolation function that take time and return interpolated + value at that time. + + """ + if len(keyframes) < (degree + 1): + raise ValueError( + f'Minimum {degree + 1} ' + f'keyframes must be set in order to use ' + f'{degree}-degree spline' + ) + timestamps = get_timestamps_from_keyframes(keyframes) + + values = get_values_from_keyframes(keyframes) + distances = euclidean_distances(values) + distances_sum = sum(distances) + cumulative_dist_sum = np.cumsum([0] + distances) + tck = splprep(values.T, k=degree, full_output=1, s=0)[0][0] + + def interpolate(t): + t0 = get_previous_timestamp(timestamps, t) + t1 = get_next_timestamp(timestamps, t) + mi_index = np.where(timestamps == t0)[0][0] + dt = get_time_tau(t, t0, t1) + section = cumulative_dist_sum[mi_index] + ts = (section + dt * distances[mi_index]) / distances_sum + return np.array(splev(ts, tck)) + + return interpolate
+ + + +
+[docs] +def cubic_spline_interpolator(keyframes): + """Cubic spline interpolator for keyframes. + + This is a general cubic spline interpolator to be used for any shape of + keyframes data. + + Parameters + ---------- + keyframes: dict + Keyframe data containing timestamps and values to form the cubic spline + curve. + + Returns + ------- + function + The interpolation function that take time and return interpolated + value at that time. + + See Also + -------- + spline_interpolator + + """ + return spline_interpolator(keyframes, degree=3)
+ + + +
+[docs] +def step_interpolator(keyframes): + """Step interpolator for keyframes. + + This is a simple step interpolator to be used for any shape of + keyframes data. + + Parameters + ---------- + keyframes: dict + Keyframe data containing timestamps and values to form the spline + + Returns + ------- + function + The interpolation function that take time and return interpolated + value at that time. + + """ + timestamps = get_timestamps_from_keyframes(keyframes) + + def interpolate(t): + previous_t = get_previous_timestamp(timestamps, t, include_last=True) + return keyframes.get(previous_t).get('value') + + return interpolate
+ + + +
+[docs] +def linear_interpolator(keyframes): + """Linear interpolator for keyframes. + + This is a general linear interpolator to be used for any shape of + keyframes data. + + Parameters + ---------- + keyframes: dict + Keyframe data to be linearly interpolated. + + Returns + ------- + function + The interpolation function that take time and return interpolated + value at that time. + + """ + timestamps = get_timestamps_from_keyframes(keyframes) + is_single = len(keyframes) == 1 + + def interpolate(t): + if is_single: + t = timestamps[0] + return keyframes.get(t).get('value') + t0 = get_previous_timestamp(timestamps, t) + t1 = get_next_timestamp(timestamps, t) + p0 = keyframes.get(t0).get('value') + p1 = keyframes.get(t1).get('value') + return lerp(p0, p1, t0, t1, t) + + return interpolate
+ + + +
+[docs] +def cubic_bezier_interpolator(keyframes): + """Cubic Bézier interpolator for keyframes. + + This is a general cubic Bézier interpolator to be used for any shape of + keyframes data. + + Parameters + ---------- + keyframes : dict + Keyframes to be interpolated at any time. + + Returns + ------- + function + The interpolation function that take time and return interpolated + value at that time. + + Notes + ----- + If no control points are set in the keyframes, The cubic + Bézier interpolator will almost behave as a linear interpolator. + + """ + timestamps = get_timestamps_from_keyframes(keyframes) + + for ts in timestamps: + # keyframe at timestamp + kf_ts = keyframes.get(ts) + if kf_ts.get('in_cp') is None: + kf_ts['in_cp'] = kf_ts.get('value') + + if kf_ts.get('out_cp') is None: + kf_ts['out_cp'] = kf_ts.get('value') + + def interpolate(t): + t0 = get_previous_timestamp(timestamps, t) + t1 = get_next_timestamp(timestamps, t) + k0 = keyframes.get(t0) + k1 = keyframes.get(t1) + p0 = k0.get('value') + p1 = k0.get('out_cp') + p2 = k1.get('in_cp') + p3 = k1.get('value') + dt = get_time_tau(t, t0, t1) + val = ( + (1 - dt) ** 3 * p0 + + 3 * (1 - dt) ** 2 * dt * p1 + + 3 * (1 - dt) * dt**2 * p2 + + dt**3 * p3 + ) + return val + + return interpolate
+ + + +
+[docs] +def slerp(keyframes): + """Spherical based rotation keyframes interpolator. + + A rotation interpolator to be used for rotation keyframes. + + Parameters + ---------- + keyframes : dict + Rotation keyframes to be interpolated at any time. + + Returns + ------- + function + The interpolation function that take time and return interpolated + value at that time. + + Notes + ----- + Rotation keyframes must be in the form of quaternions. + + """ + timestamps = get_timestamps_from_keyframes(keyframes) + + quat_rots = [] + for ts in timestamps: + quat_rots.append(keyframes.get(ts).get('value')) + rotations = transform.Rotation.from_quat(quat_rots) + # if only one keyframe specified, linear interpolator is used. + if len(timestamps) == 1: + return linear_interpolator(keyframes) + slerp_interp = transform.Slerp(timestamps, rotations) + min_t = timestamps[0] + max_t = timestamps[-1] + + def interpolate(t): + t = min_t if t < min_t else max_t if t > max_t else t + v = slerp_interp(t) + q = v.as_quat() + return q + + return interpolate
+ + + +
+[docs] +def color_interpolator(keyframes, rgb2space, space2rgb): + """Custom-space color interpolator. + + Interpolate values linearly inside a custom color space. + + Parameters + ---------- + keyframes : dict + Rotation keyframes to be interpolated at any time. + rgb2space: function + A functions that take color value in rgb and return that color + converted to the targeted space. + space2rgb: function + A functions that take color value in the targeted space and returns + that color in rgb space. + + Returns + ------- + function + The interpolation function that take time and return interpolated + value at that time. + + """ + timestamps = get_timestamps_from_keyframes(keyframes) + space_keyframes = {} + is_single = len(keyframes) == 1 + for ts, keyframe in keyframes.items(): + space_keyframes[ts] = rgb2space(keyframe.get('value')) + + def interpolate(t): + if is_single: + t = timestamps[0] + return keyframes.get(t).get('value') + t0 = get_previous_timestamp(timestamps, t) + t1 = get_next_timestamp(timestamps, t) + c0 = space_keyframes.get(t0) + c1 = space_keyframes.get(t1) + space_color_val = lerp(c0, c1, t0, t1, t) + return space2rgb(space_color_val) + + return interpolate
+ + + +
+[docs] +def hsv_color_interpolator(keyframes): + """HSV interpolator for color keyframes + + See Also + -------- + color_interpolator + + """ + return color_interpolator(keyframes, rgb2hsv, hsv2rgb)
+ + + +
+[docs] +def lab_color_interpolator(keyframes): + """LAB interpolator for color keyframes + + See Also + -------- + color_interpolator + + """ + return color_interpolator(keyframes, rgb2lab, lab2rgb)
+ + + +
+[docs] +def xyz_color_interpolator(keyframes): + """XYZ interpolator for color keyframes + + See Also + -------- + color_interpolator + + """ + return color_interpolator(keyframes, rgb2xyz, xyz2rgb)
+ + + +
+[docs] +def tan_cubic_spline_interpolator(keyframes): + """Cubic spline interpolator for keyframes using tangents. + glTF contains additional tangent information for the cubic spline + interpolator. + + Parameters + ---------- + keyframes: dict + Keyframe data containing timestamps and values to form the cubic spline + curve. + + Returns + ------- + function + The interpolation function that take time and return interpolated + value at that time. + + """ + timestamps = get_timestamps_from_keyframes(keyframes) + for time in keyframes: + data = keyframes.get(time) + value = data.get('value') + if data.get('in_tangent') is None: + data['in_tangent'] = np.zeros_like(value) + if data.get('in_tangent') is None: + data['in_tangent'] = np.zeros_like(value) + + def interpolate(t): + t0 = get_previous_timestamp(timestamps, t) + t1 = get_next_timestamp(timestamps, t) + + dt = get_time_tau(t, t0, t1) + + time_delta = t1 - t0 + + p0 = keyframes.get(t0).get('value') + tan_0 = keyframes.get(t0).get('out_tangent') * time_delta + p1 = keyframes.get(t1).get('value') + tan_1 = keyframes.get(t1).get('in_tangent') * time_delta + # cubic spline equation using tangents + t2 = dt * dt + t3 = t2 * dt + return ( + (2 * t3 - 3 * t2 + 1) * p0 + + (t3 - 2 * t2 + dt) * tan_0 + + (-2 * t3 + 3 * t2) * p1 + + (t3 - t2) * tan_1 + ) + + return interpolate
+ +
+
+ + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/_modules/fury/animation/timeline.html b/v0.10.x/_modules/fury/animation/timeline.html new file mode 100644 index 000000000..caad715eb --- /dev/null +++ b/v0.10.x/_modules/fury/animation/timeline.html @@ -0,0 +1,984 @@ + + + + + + + fury.animation.timeline — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +

Source code for fury.animation.timeline

+import os
+from time import perf_counter
+
+import numpy as np
+from PIL import Image
+
+from fury import window
+from fury.animation.animation import Animation
+from fury.lib import RenderWindow, WindowToImageFilter, numpy_support
+from fury.ui.elements import PlaybackPanel
+
+
+
+[docs] +class Timeline: + """Keyframe animation Timeline. + + Timeline is responsible for handling the playback of keyframes animations. + It has multiple playback options which makes it easy + to control the playback, speed, state of the animation with/without a GUI + playback panel. + + Attributes + ---------- + animations : Animation or list[Animation], optional, default: None + Actor/s to be animated directly by the Timeline (main Animation). + playback_panel : bool, optional + If True, the timeline will have a playback panel set, which can be used + to control the playback of the timeline. + length : float or int, default: None, optional + the fixed length of the timeline. If set to None, the timeline will get + its length from the animations that it controls automatically. + loop : bool, optional + Whether loop playing the timeline or play once. + + """ + +
+[docs] + def __init__(self, animations=None, playback_panel=False, loop=True, length=None): + + self._scene = None + self.playback_panel = None + self._current_timestamp = 0 + self._speed = 1.0 + self._last_started_time = 0 + self._playing = False + self._animations = [] + self._loop = loop + self._length = length + self._duration = length if length is not None else 0.0 + + if playback_panel: + + def set_loop(is_loop): + self._loop = is_loop + + def set_speed(speed): + self.speed = speed + + self.playback_panel = PlaybackPanel(loop=self._loop) + self.playback_panel.on_play = self.play + self.playback_panel.on_stop = self.stop + self.playback_panel.on_pause = self.pause + self.playback_panel.on_loop_toggle = set_loop + self.playback_panel.on_progress_bar_changed = self.seek + self.playback_panel.on_speed_changed = set_speed + + if animations is not None: + self.add_animation(animations)
+ + +
+[docs] + def update_duration(self): + """Update and return the duration of the Timeline. + + Returns + ------- + float + The duration of the Timeline. + + """ + if self._length is not None: + self._duration = self._length + else: + self._duration = max( + [0.0] + [anim.update_duration() for anim in self._animations] + ) + if self.has_playback_panel: + self.playback_panel.final_time = self.duration + return self.duration
+ + + @property + def duration(self): + """Return the duration of the Timeline. + + Returns + ------- + float + The duration of the Timeline. + + """ + return self._duration + +
+[docs] + def play(self): + """Play the animation""" + if not self.playing: + if self.current_timestamp >= self.duration: + self.current_timestamp = 0 + self._last_started_time = ( + perf_counter() - self._current_timestamp / self.speed + ) + self._playing = True
+ + +
+[docs] + def pause(self): + """Pause the animation""" + self._current_timestamp = self.current_timestamp + self._playing = False
+ + +
+[docs] + def stop(self): + """Stop the animation""" + self._current_timestamp = 0 + self._playing = False + self.update(force=True)
+ + +
+[docs] + def restart(self): + """Restart the animation""" + self._current_timestamp = 0 + self._playing = True + self.update(force=True)
+ + + @property + def current_timestamp(self): + """Get current timestamp of the Timeline. + + Returns + ------- + float + The current time of the Timeline. + + """ + if self.playing: + self._current_timestamp = ( + perf_counter() - self._last_started_time + ) * self.speed + return self._current_timestamp + + @current_timestamp.setter + def current_timestamp(self, timestamp): + """Set the current timestamp of the Timeline. + + Parameters + ---------- + timestamp: float + The time to set as current time of the Timeline. + + """ + self.seek(timestamp) + +
+[docs] + def seek(self, timestamp): + """Set the current timestamp of the Timeline. + + Parameters + ---------- + timestamp: float + The time to seek. + + """ + # assuring timestamp value is in the timeline range + if timestamp < 0: + timestamp = 0 + elif timestamp > self.duration: + timestamp = self.duration + if self.playing: + self._last_started_time = perf_counter() - timestamp / self.speed + else: + self._current_timestamp = timestamp + self.update(force=True)
+ + +
+[docs] + def seek_percent(self, percent): + """Seek a percentage of the Timeline's final timestamp. + + Parameters + ---------- + percent: float + Value from 1 to 100. + + """ + t = percent * self.duration / 100 + self.seek(t)
+ + + @property + def playing(self): + """Return whether the Timeline is playing. + + Returns + ------- + bool + True if the Timeline is playing. + + """ + return self._playing + + @property + def stopped(self): + """Return whether the Timeline is stopped. + + Returns + ------- + bool + True if Timeline is stopped. + + """ + return not self.playing and not self._current_timestamp + + @property + def paused(self): + """Return whether the Timeline is paused. + + Returns + ------- + bool + True if the Timeline is paused. + + """ + return not self.playing and self._current_timestamp is not None + + @property + def speed(self): + """Return the speed of the timeline's playback. + + Returns + ------- + float + The speed of the timeline's playback. + + """ + return self._speed + + @speed.setter + def speed(self, speed): + """Set the speed of the timeline's playback. + + Parameters + ---------- + speed: float + The speed of the timeline's playback. + + """ + current = self.current_timestamp + if speed <= 0: + return + self._speed = speed + self._last_started_time = perf_counter() + self.current_timestamp = current + + @property + def loop(self): + """Get loop condition of the timeline. + + Returns + ------- + bool + Whether the playback is in loop mode (True) or play one mode + (False). + + """ + return self._loop + + @loop.setter + def loop(self, loop): + """Set the timeline's playback to loop or play once. + + Parameters + ---------- + loop: bool + The loop condition to be set. (True) to loop the playback, and + (False) to play only once. + + """ + self._loop = loop + + @property + def has_playback_panel(self): + """Return whether the `Timeline` has a playback panel. + + Returns + ------- + bool: 'True' if the `Timeline` has a playback panel. otherwise, 'False' + + """ + return self.playback_panel is not None + +
+[docs] + def record(self, fname=None, fps=30, speed=1.0, size=(900, 768), + order_transparent=True, multi_samples=8, + max_peels=4, show_panel=False): + """Record the animation + + Parameters + ---------- + fname : str, optional + The file name. Save a GIF file if name ends with '.gif', or mp4 + video if name ends with'.mp4'. + If None, this method will only return an array of frames. + fps : int, optional + The number of frames per second of the record. + size : (int, int) + ``(width, height)`` of the window. Default is (900, 768). + speed : float, optional, default 1.0 + The speed of the animation. + order_transparent : bool, optional + Default False. Use depth peeling to sort transparent objects. + If True also enables anti-aliasing. + multi_samples : int, optional + Number of samples for anti-aliasing (Default 8). + For no anti-aliasing use 0. + max_peels : int, optional + Maximum number of peels for depth peeling (Default 4). + show_panel : bool, optional, default False + Controls whether to show the playback (if True) panel of hide it + (if False) + + Returns + ------- + ndarray: + The recorded frames. + + Notes + ----- + It's recommended to use 50 or 30 FPS while recording to a GIF file. + + """ + ext = os.path.splitext(fname)[-1] + + mp4 = ext == '.mp4' + + if mp4: + try: + import cv2 + except ImportError: + raise ImportError('OpenCV must be installed in order to ' + 'save as MP4 video.') + fourcc = cv2.VideoWriter.fourcc(*'mp4v') + out = cv2.VideoWriter(fname, fourcc, fps, size) + + duration = self.duration + step = speed / fps + frames = [] + t = 0 + scene = self._scene + if not scene: + scene = window.Scene() + scene.add(self) + + _hide_panel = False + if self.has_playback_panel and not show_panel: + self.playback_panel.hide() + _hide_panel = True + render_window = RenderWindow() + render_window.SetOffScreenRendering(1) + render_window.AddRenderer(scene) + render_window.SetSize(*size) + + if order_transparent: + window.antialiasing(scene, render_window, multi_samples, max_peels, + 0) + + render_window = RenderWindow() + render_window.SetOffScreenRendering(1) + render_window.AddRenderer(scene) + render_window.SetSize(*size) + + if order_transparent: + window.antialiasing(scene, render_window, multi_samples, max_peels, 0) + + window_to_image_filter = WindowToImageFilter() + + print('Recording...') + while t < duration: + self.seek(t) + render_window.Render() + window_to_image_filter.SetInput(render_window) + window_to_image_filter.Update() + window_to_image_filter.Modified() + vtk_image = window_to_image_filter.GetOutput() + h, w, _ = vtk_image.GetDimensions() + vtk_array = vtk_image.GetPointData().GetScalars() + components = vtk_array.GetNumberOfComponents() + snap = numpy_support.vtk_to_numpy(vtk_array).reshape(w, h, + components) + corrected_snap = np.flipud(snap) + + if mp4: + cv_img = cv2.cvtColor(corrected_snap, cv2.COLOR_RGB2BGR) + out.write(cv_img) + else: + pillow_snap = Image.fromarray(corrected_snap) + frames.append(pillow_snap) + + t += step + + print('Saving...') + + if fname is None: + return frames + + if mp4: + out.release() + else: + frames[0].save(fname, append_images=frames[1:], loop=0, + duration=1000 / fps, save_all=True) + + if _hide_panel: + self.playback_panel.show() + + return frames
+ + +
+[docs] + def add_animation(self, animation): + """Add Animation or list of Animations. + + Parameters + ---------- + animation: Animation or list[Animation] or tuple[Animation] + Animation/s to be added. + + """ + if isinstance(animation, (list, tuple)): + [self.add_animation(anim) for anim in animation] + elif isinstance(animation, Animation): + animation._timeline = self + self._animations.append(animation) + self.update_duration() + else: + raise TypeError('Expected an Animation, a list or a tuple.')
+ + + @property + def animations(self) -> 'list[Animation]': + """Return a list of Animations. + + Returns + ------- + list: + List of Animations controlled by the timeline. + + """ + return self._animations + +
+[docs] + def update(self, force=False): + """Update the timeline. + + Update the Timeline and all the animations that it controls. As well as + the playback of the Timeline (if exists). + + Parameters + ---------- + force: bool, optional, default: False + If True, the timeline will update even when the timeline is paused + or stopped and hence, more resources will be used. + + """ + time = self.current_timestamp + if self.has_playback_panel: + self.playback_panel.current_time = time + if time > self.duration: + if self._loop: + self.seek(0) + else: + self.seek(self.duration) + # Doing this will pause both the timeline and the panel. + if self.has_playback_panel: + self.playback_panel.pause() + else: + self.pause() + if self.playing or force: + [anim.update_animation(time) for anim in self._animations]
+ + +
+[docs] + def add_to_scene(self, scene): + """Add Timeline and all of its Animations to the scene""" + self._scene = scene + if self.has_playback_panel: + self.playback_panel.add_to_scene(scene) + [animation.add_to_scene(scene) for animation in self._animations]
+ + +
+[docs] + def remove_from_scene(self, scene): + """Remove Timeline and all of its Animations to the scene""" + self._scene = None + if self.has_playback_panel: + scene.rm(*tuple(self.playback_panel.actors)) + [animation.remove_from_scene(scene) for animation in self._animations]
+
+ +
+
+ + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/_modules/fury/colormap.html b/v0.10.x/_modules/fury/colormap.html new file mode 100644 index 000000000..a8e3471cf --- /dev/null +++ b/v0.10.x/_modules/fury/colormap.html @@ -0,0 +1,1574 @@ + + + + + + + fury.colormap — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +

Source code for fury.colormap

+import json
+from os.path import join as pjoin
+from warnings import warn
+
+import numpy as np
+from scipy import linalg
+
+from fury.data import DATA_DIR
+from fury.lib import LookupTable
+
+# Allow import, but disable doctests if we don't have matplotlib
+from fury.optpkg import optional_package
+
+cm, have_matplotlib, _ = optional_package('matplotlib.cm')
+
+
+
+[docs] +def colormap_lookup_table( + scale_range=(0, 1), + hue_range=(0.8, 0), + saturation_range=(1, 1), + value_range=(0.8, 0.8), +): + """Lookup table for the colormap. + + Parameters + ---------- + scale_range : tuple + It can be anything e.g. (0, 1) or (0, 255). Usually it is the minimum + and maximum value of your data. Default is (0, 1). + hue_range : tuple of floats + HSV values (min 0 and max 1). Default is (0.8, 0). + saturation_range : tuple of floats + HSV values (min 0 and max 1). Default is (1, 1). + value_range : tuple of floats + HSV value (min 0 and max 1). Default is (0.8, 0.8). + + Returns + ------- + lookup_table : LookupTable + + """ + lookup_table = LookupTable() + lookup_table.SetRange(scale_range) + lookup_table.SetTableRange(scale_range) + + lookup_table.SetHueRange(hue_range) + lookup_table.SetSaturationRange(saturation_range) + lookup_table.SetValueRange(value_range) + + lookup_table.Build() + return lookup_table
+ + + +
+[docs] +def cc(na, nd): + return na * np.cos(nd * np.pi / 180.0)
+ + + +
+[docs] +def ss(na, nd): + return na * np.sin(nd * np.pi / 180.0)
+ + + +
+[docs] +def boys2rgb(v): + """Boys 2 rgb cool colormap + + Maps a given field of undirected lines (line field) to rgb + colors using Boy's Surface immersion of the real projective + plane. + Boy's Surface is one of the three possible surfaces + obtained by gluing a Mobius strip to the edge of a disk. + The other two are the crosscap and Roman surface, + Steiner surfaces that are homeomorphic to the real + projective plane (Pinkall 1986). The Boy's surface + is the only 3D immersion of the projective plane without + singularities. + Visit http://www.cs.brown.edu/~cad/rp2coloring for further details. + Cagatay Demiralp, 9/7/2008. + + Code was initially in matlab and was rewritten in Python for fury by + the FURY Team. Thank you Cagatay for putting this online. + + Parameters + ---------- + v : array, shape (N, 3) of unit vectors (e.g., principal eigenvectors of + tensor data) representing one of the two directions of the + undirected lines in a line field. + + Returns + ------- + c : array, shape (N, 3) matrix of rgb colors corresponding to the vectors + given in V. + + Examples + -------- + >>> from fury import colormap + >>> v = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]]) + >>> c = colormap.boys2rgb(v) + + """ + if v.ndim == 1: + x = v[0] + y = v[1] + z = v[2] + + if v.ndim == 2: + x = v[:, 0] + y = v[:, 1] + z = v[:, 2] + + x2 = x**2 + y2 = y**2 + z2 = z**2 + + x3 = x * x2 + y3 = y * y2 + z3 = z * z2 + + z4 = z * z2 + + xy = x * y + xz = x * z + yz = y * z + + hh1 = 0.5 * (3 * z2 - 1) / 1.58 + hh2 = 3 * xz / 2.745 + hh3 = 3 * yz / 2.745 + hh4 = 1.5 * (x2 - y2) / 2.745 + hh5 = 6 * xy / 5.5 + hh6 = (1 / 1.176) * 0.125 * (35 * z4 - 30 * z2 + 3) + hh7 = 2.5 * x * (7 * z3 - 3 * z) / 3.737 + hh8 = 2.5 * y * (7 * z3 - 3 * z) / 3.737 + hh9 = ((x2 - y2) * 7.5 * (7 * z2 - 1)) / 15.85 + hh10 = ((2 * xy) * (7.5 * (7 * z2 - 1))) / 15.85 + hh11 = 105 * (4 * x3 * z - 3 * xz * (1 - z2)) / 59.32 + hh12 = 105 * (-4 * y3 * z + 3 * yz * (1 - z2)) / 59.32 + + s0 = -23.0 + s1 = 227.9 + s2 = 251.0 + s3 = 125.0 + + ss23 = ss(2.71, s0) + cc23 = cc(2.71, s0) + ss45 = ss(2.12, s1) + cc45 = cc(2.12, s1) + ss67 = ss(0.972, s2) + cc67 = cc(0.972, s2) + ss89 = ss(0.868, s3) + cc89 = cc(0.868, s3) + + X = 0.0 + + X = X + hh2 * cc23 + X = X + hh3 * ss23 + + X = X + hh5 * cc45 + X = X + hh4 * ss45 + + X = X + hh7 * cc67 + X = X + hh8 * ss67 + + X = X + hh10 * cc89 + X = X + hh9 * ss89 + + Y = 0.0 + + Y = Y + hh2 * -ss23 + Y = Y + hh3 * cc23 + + Y = Y + hh5 * -ss45 + Y = Y + hh4 * cc45 + + Y = Y + hh7 * -ss67 + Y = Y + hh8 * cc67 + + Y = Y + hh10 * -ss89 + Y = Y + hh9 * cc89 + + Z = 0.0 + + Z = Z + hh1 * -2.8 + Z = Z + hh6 * -0.5 + Z = Z + hh11 * 0.3 + Z = Z + hh12 * -2.5 + + # scale and normalize to fit + # in the rgb space + + w_x = 4.1925 + trl_x = -2.0425 + w_y = 4.0217 + trl_y = -1.8541 + w_z = 4.0694 + trl_z = -2.1899 + + if v.ndim == 2: + + N = len(x) + C = np.zeros((N, 3)) + + C[:, 0] = 0.9 * np.abs(((X - trl_x) / w_x)) + 0.05 + C[:, 1] = 0.9 * np.abs(((Y - trl_y) / w_y)) + 0.05 + C[:, 2] = 0.9 * np.abs(((Z - trl_z) / w_z)) + 0.05 + + if v.ndim == 1: + + C = np.zeros((3,)) + C[0] = 0.9 * np.abs(((X - trl_x) / w_x)) + 0.05 + C[1] = 0.9 * np.abs(((Y - trl_y) / w_y)) + 0.05 + C[2] = 0.9 * np.abs(((Z - trl_z) / w_z)) + 0.05 + + return C
+ + + +
+[docs] +def orient2rgb(v): + """Get Standard orientation 2 rgb colormap. + + v : array, shape (N, 3) of vectors not necessarily normalized + + Returns + ------- + c : array, shape (N, 3) matrix of rgb colors corresponding to the vectors + given in V. + + Examples + -------- + >>> from fury import colormap + >>> v = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]]) + >>> c = colormap.orient2rgb(v) + + """ + if v.ndim == 1: + r = np.linalg.norm(v) + orient = np.abs(np.divide(v, r, where=r != 0)) + + elif v.ndim == 2: + orientn = np.sqrt(v[:, 0] ** 2 + v[:, 1] ** 2 + v[:, 2] ** 2) + orientn.shape = orientn.shape + (1,) + orient = np.abs(np.divide(v, orientn, where=orientn != 0)) + else: + raise IOError( + 'Wrong vector dimension, It should be an array' ' with a shape (N, 3)' + ) + + return orient
+ + + +
+[docs] +def line_colors(streamlines, cmap='rgb_standard'): + """Create colors for streamlines to be used in actor.line. + + Parameters + ---------- + streamlines : sequence of ndarrays + cmap : ('rgb_standard', 'boys_standard') + + Returns + ------- + colors : ndarray + + """ + if cmap == 'rgb_standard': + col_list = [ + orient2rgb(streamline[-1] - streamline[0]) for streamline in streamlines + ] + + if cmap == 'boys_standard': + col_list = [ + boys2rgb(streamline[-1] - streamline[0]) for streamline in streamlines + ] + + return np.vstack(col_list)
+ + + +lowercase_cm_name = {'blues': 'Blues', 'accent': 'Accent'} +dipy_cmaps = None + + +
+[docs] +def get_cmap(name): + """Make a callable, similar to maptlotlib.pyplot.get_cmap.""" + if name.lower() == 'accent': + warn( + 'The `Accent` colormap is deprecated as of version' + + ' 0.2 of Fury and will be removed in a future ' + + 'version. Please use another colormap', + PendingDeprecationWarning, + ) + + global dipy_cmaps + if dipy_cmaps is None: + filename = pjoin(DATA_DIR, 'dipy_colormaps.json') + with open(filename) as f: + dipy_cmaps = json.load(f) + + desc = dipy_cmaps.get(name) + if desc is None: + return None + + def simple_cmap(v): + """Emulate matplotlib colormap callable.""" + rgba = np.ones((len(v), 4)) + for i, color in enumerate(('red', 'green', 'blue')): + x, y0, _ = zip(*desc[color]) + # Matplotlib allows more complex colormaps, but for users who do + # not have Matplotlib fury makes a few simple colormaps available. + # These colormaps are simple because y0 == y1, and therefore we + # ignore y1 here. + rgba[:, i] = np.interp(v, x, y0) + return rgba + + return simple_cmap
+ + + +
+[docs] +def create_colormap(v, name='plasma', auto=True): + """Create colors from a specific colormap and return it + as an array of shape (N,3) where every row gives the corresponding + r,g,b value. The colormaps we use are similar with those of matplotlib. + + Parameters + ---------- + v : (N,) array + vector of values to be mapped in RGB colors according to colormap + name : str. + Name of the colormap. Currently implemented: 'jet', 'blues', + 'accent', 'bone' and matplotlib colormaps if you have matplotlib + installed. For example, we suggest using 'plasma', 'viridis' or + 'inferno'. 'jet' is popular but can be often misleading and we will + deprecate it the future. + auto : bool, + if auto is True then v is interpolated to [0, 1] from v.min() + to v.max() + + Notes + ----- + FURY supports a few colormaps for those who do not use Matplotlib, for + more colormaps consider downloading Matplotlib (see matplotlib.org). + + """ + if not have_matplotlib: + msg = 'You do not have Matplotlib installed. Some colormaps' + msg += ' might not work for you. Consider downloading Matplotlib.' + warn(msg) + + if name.lower() == 'jet': + msg = 'Jet is a popular colormap but can often be misleading' + msg += 'Use instead plasma, viridis, hot or inferno.' + warn(msg, PendingDeprecationWarning) + + if v.ndim > 1: + msg = 'This function works only with 1d arrays. Use ravel()' + raise ValueError(msg) + + if auto: + v = np.interp(v, [v.min(), v.max()], [0, 1]) + else: + v = np.clip(v, 0, 1) + + # For backwards compatibility with lowercase names + newname = lowercase_cm_name.get(name) or name + + colormap = getattr(cm, newname) if have_matplotlib else get_cmap(newname) + if colormap is None: + e_s = 'Colormap {} is not yet implemented '.format(name) + raise ValueError(e_s) + + rgba = colormap(v) + rgb = rgba[:, :3].copy() + return rgb
+ + + +def _lab_delta(x, y): + dL = y[:, 0] - x[:, 0] # L + dA = y[:, 1] - x[:, 1] # A + dB = y[:, 2] - x[:, 2] # B + return np.sqrt(dL**2 + dA**2 + dB**2) + + +def _rgb_lab_delta(x, y): + labX = _rgb2lab(x) + labY = _rgb2lab(y) + return _lab_delta(labX, labY) + + +def _rgb2xyz(rgb): + var_R = rgb[:, 0] / 255 # R from 0 to 255 + var_G = rgb[:, 1] / 255 # G from 0 to 255 + var_B = rgb[:, 2] / 255 # B from 0 to 255 + + idx = var_R > 0.04045 + var_R[idx] = ((var_R[idx] + 0.055) / 1.055) ** 2.4 + idx = np.logical_not(idx) + var_R[idx] = var_R[idx] / 12.92 + + idx = var_G > 0.04045 + var_G[idx] = ((var_G[idx] + 0.055) / 1.055) ** 2.4 + idx = np.logical_not(idx) + var_G[idx] = var_G[idx] / 12.92 + + idx = var_B > 0.04045 + var_B[idx] = ((var_B[idx] + 0.055) / 1.055) ** 2.4 + idx = np.logical_not(idx) + var_B[idx] = var_B[idx] / 12.92 + + var_R = var_R * 100 + var_G = var_G * 100 + var_B = var_B * 100 + + # Observer. = Illuminant = D65 + X = var_R * 0.4124 + var_G * 0.3576 + var_B * 0.1805 + Y = var_R * 0.2126 + var_G * 0.7152 + var_B * 0.0722 + Z = var_R * 0.0193 + var_G * 0.1192 + var_B * 0.9505 + + return np.c_[X, Y, Z] + + +def _xyz2lab(xyz): + ref_X = 095.047 + ref_Y = 100.000 + ref_Z = 108.883 + var_X = xyz[:, 0] / ref_X + var_Y = xyz[:, 1] / ref_Y + var_Z = xyz[:, 2] / ref_Z + + idx = var_X > 0.008856 + var_X[idx] = var_X[idx] ** (1 / 3) + idx = np.logical_not(idx) + var_X[idx] = (7.787 * var_X[idx]) + (16.0 / 116.0) + + idx = var_Y > 0.008856 + var_Y[idx] = var_Y[idx] ** (1 / 3) + idx = np.logical_not(idx) + var_Y[idx] = (7.787 * var_Y[idx]) + (16.0 / 116.0) + + idx = var_Z > 0.008856 + var_Z[idx] = var_Z[idx] ** (1 / 3) + idx = np.logical_not(idx) + var_Z[idx] = (7.787 * var_Z[idx]) + (16.0 / 116.0) + + L = (116 * var_Y) - 16 + A = 500 * (var_X - var_Y) + B = 200 * (var_Y - var_Z) + + return np.c_[L, A, B] + + +def _lab2xyz(lab): + var_Y = (lab[:, 0] + 16) / 116.0 + var_X = lab[:, 1] / 500.0 + var_Y + var_Z = var_Y - lab[:, 2] / 200.0 + + if var_Y**3 > 0.008856: + var_Y = var_Y**3 + else: + var_Y = (var_Y - 16.0 / 116.0) / 7.787 + + if var_X**3 > 0.008856: + var_X = var_X**3 + else: + var_X = (var_X - 16.0 / 116.0) / 7.787 + + if var_Z**3 > 0.008856: + var_Z = var_Z**3 + else: + var_Z = (var_Z - 16.0 / 116.0) / 7.787 + + ref_X = 095.047 + ref_Y = 100.000 + ref_Z = 108.883 + X = ref_X * var_X + Y = ref_Y * var_Y + Z = ref_Z * var_Z + + return np.c_[X, Y, Z] + + +def _xyz2rgb(xyz): + var_X = xyz[:, 0] / 100 # X from 0 to 95.047 + var_Y = xyz[:, 1] / 100 # Y from 0 to 100.000 + var_Z = xyz[:, 2] / 100 # Z from 0 to 108.883 + + var_R = var_X * 03.2406 + var_Y * -1.5372 + var_Z * -0.4986 + var_G = var_X * -0.9689 + var_Y * 01.8758 + var_Z * 00.0415 + var_B = var_X * 00.0557 + var_Y * -0.2040 + var_Z * 01.0570 + + if var_R > 0.0031308: + var_R = 1.055 * (var_R ** (1 / 2.4)) - 0.055 + else: + var_R = 12.92 * var_R + + if var_G > 0.0031308: + var_G = 1.055 * (var_G ** (1 / 2.4)) - 0.055 + else: + var_G = 12.92 * var_G + + if var_B > 0.0031308: + var_B = 1.055 * (var_B ** (1 / 2.4)) - 0.055 + else: + var_B = 12.92 * var_B + + R = var_R * 255 + G = var_G * 255 + B = var_B * 255 + + return np.c_[R, G, B] + + +def _rgb2lab(rgb): + tmp = _rgb2xyz(rgb) + return _xyz2lab(tmp) + + +def _lab2rgb(lab): + tmp = _lab2xyz(lab) + return _xyz2rgb(tmp) + + +
+[docs] +def distinguishable_colormap(bg=(0, 0, 0), exclude=[], nb_colors=None): + """Generate colors that are maximally perceptually distinct. + + This function generates a set of colors which are distinguishable + by reference to the "Lab" color space, which more closely matches + human color perception than RGB. Given an initial large list of possible + colors, it iteratively chooses the entry in the list that is farthest (in + Lab space) from all previously-chosen entries. While this "greedy" + algorithm does not yield a global maximum, it is simple and efficient. + Moreover, the sequence of colors is consistent no matter how many you + request, which facilitates the users' ability to learn the color order + and avoids major changes in the appearance of plots when adding or + removing lines. + + Parameters + ---------- + bg : tuple (optional) + Background RGB color, to make sure that your colors are also + distinguishable from the background. Default: (0, 0, 0). + exclude : list of tuples (optional) + Additional RGB colors to be distinguishable from. + nb_colors : int (optional) + Number of colors desired. Default: generate as many colors as needed. + + Returns + ------- + iterable of ndarray + If `nb_colors` is provided, returns a list of RBG colors. + Otherwise, yields the next RBG color maximally perceptually + distinct from previous ones. + + Examples + -------- + >>> from dipy.viz.colormap import distinguishable_colormap + >>> # Generate 5 colors + >>> [c for i, c in zip(range(5), distinguishable_colormap())] + [array([ 0., 1., 0.]), + array([ 1., 0., 1.]), + array([ 1. , 0.75862069, 0.03448276]), + array([ 0. , 1. , 0.89655172]), + array([ 0. , 0.17241379, 1. ])] + + + Notes + ----- + Code was initially in matlab and was rewritten in Python for dipy by + the Dipy Team. Thank you Tim Holy for putting this online. Visit + http://www.mathworks.com/matlabcentral/fileexchange/29702 for the + original implementation (v1.2), 14 Dec 2010 (Updated 07 Feb 2011). + + """ + NB_DIVISIONS = 30 # This constant come from the original code. + + # Generate a sizable number of RGB triples. This represents our space of + # possible choices. By starting in RGB space, we ensure that all of the + # colors can be generated by the monitor. + + colors_to_exclude = np.array([bg] + exclude) + # Divisions along each axis in RGB space. + x = np.linspace(0, 1, NB_DIVISIONS) + R, G, B = np.meshgrid(x, x, x) + rgb = np.c_[R.flatten(), G.flatten(), B.flatten()] + + lab = _rgb2lab(rgb) + bglab = _rgb2lab(colors_to_exclude) + + def _generate_next_color(): + lastlab = bglab[0] + mindist2 = np.ones(len(rgb)) * np.inf + for bglab_i in bglab[1:]: + dist2 = np.sum((lab - bglab_i) ** 2, axis=1) + # Dist2 to closest previously-chosen color. + mindist2 = np.minimum(dist2, mindist2) + + while True: + dX = lab - lastlab # Displacement of last from all colors on list. + dist2 = np.sum(dX**2, axis=1) # Square distance. + # Dist2 to closest previously-chosen color. + mindist2 = np.minimum(dist2, mindist2) + # Find the entry farthest from all previously-chosen colors. + idx = np.argmax(mindist2) + yield rgb[idx] + + lastlab = lab[idx] + + if nb_colors is not None: + return [c for i, c in zip(range(nb_colors), _generate_next_color())] + + return _generate_next_color()
+ + + +
+[docs] +def hex_to_rgb(color): + """Converts Hexadecimal color code to rgb() + + color : string containing hexcode of color (can also start with a hash) + + Returns + ------- + c : array, shape(1, 3) matrix of rbg colors corresponding to the + hexcode string given in color. + + Examples + -------- + >>> from fury import colormap + >>> color = "#FFFFFF" + >>> c = colormap.hex_to_rgb(color) + + + >>> from fury import colormap + >>> color = "FFFFFF" + >>> c = colormap.hex_to_rgb(color) + + """ + if color[0] == '#': + color = color[1:] + + r = int('0x' + color[0:2], 0) / 255 + g = int('0x' + color[2:4], 0) / 255 + b = int('0x' + color[4:6], 0) / 255 + + return np.array([r, g, b])
+ + + +
+[docs] +def rgb2hsv(rgb): + """RGB to HSV color space conversion. + + Parameters + ---------- + rgb : (..., 3, ...) array_like + The image in RGB format. By default, the final dimension denotes + channels. + + Returns + ------- + out : (..., 3, ...) ndarray + The image in HSV format. Same dimensions as input. + + Notes + ----- + Original Implementation from scikit-image package. + it can be found at: + https://github.com/scikit-image/scikit-image/blob/main/skimage/color/colorconv.py + This implementation might have been modified. + + """ + input_is_one_pixel = rgb.ndim == 1 + if input_is_one_pixel: + rgb = rgb[np.newaxis, ...] + + out = np.empty_like(rgb) + + # -- V channel + out_v = rgb.max(-1) + + # -- S channel + delta = rgb.ptp(-1) + # Ignore warning for zero divided by zero + old_settings = np.seterr(invalid='ignore') + out_s = delta / out_v + out_s[delta == 0.0] = 0.0 + + # -- H channel + # red is max + idx = rgb[..., 0] == out_v + out[idx, 0] = (rgb[idx, 1] - rgb[idx, 2]) / delta[idx] + + # green is max + idx = rgb[..., 1] == out_v + out[idx, 0] = 2.0 + (rgb[idx, 2] - rgb[idx, 0]) / delta[idx] + + # blue is max + idx = rgb[..., 2] == out_v + out[idx, 0] = 4.0 + (rgb[idx, 0] - rgb[idx, 1]) / delta[idx] + out_h = (out[..., 0] / 6.0) % 1.0 + out_h[delta == 0.0] = 0.0 + + np.seterr(**old_settings) + + # -- output + out[..., 0] = out_h + out[..., 1] = out_s + out[..., 2] = out_v + + # # remove NaN + out[np.isnan(out)] = 0 + + if input_is_one_pixel: + out = np.squeeze(out, axis=0) + + return out
+ + + +
+[docs] +def hsv2rgb(hsv): + """HSV to RGB color space conversion. + + Parameters + ---------- + hsv : (..., 3, ...) array_like + The image in HSV format. By default, the final dimension denotes + channels. + + Returns + ------- + out : (..., 3, ...) ndarray + The image in RGB format. Same dimensions as input. + + Notes + ----- + Original Implementation from scikit-image package. + it can be found at: + https://github.com/scikit-image/scikit-image/blob/main/skimage/color/colorconv.py + This implementation might have been modified. + + """ + hi = np.floor(hsv[..., 0] * 6) + f = hsv[..., 0] * 6 - hi + p = hsv[..., 2] * (1 - hsv[..., 1]) + q = hsv[..., 2] * (1 - f * hsv[..., 1]) + t = hsv[..., 2] * (1 - (1 - f) * hsv[..., 1]) + v = hsv[..., 2] + + hi = np.stack([hi, hi, hi], axis=-1).astype(np.uint8) % 6 + out = np.choose( + hi, + np.stack( + [ + np.stack((v, t, p), axis=-1), + np.stack((q, v, p), axis=-1), + np.stack((p, v, t), axis=-1), + np.stack((p, q, v), axis=-1), + np.stack((t, p, v), axis=-1), + np.stack((v, p, q), axis=-1), + ] + ), + ) + return out
+ + + +# From sRGB specification +xyz_from_rgb = np.array( + [ + [0.412453, 0.357580, 0.180423], + [0.212671, 0.715160, 0.072169], + [0.019334, 0.119193, 0.950227], + ] +) + +rgb_from_xyz = linalg.inv(xyz_from_rgb) + + +
+[docs] +def xyz2rgb(xyz): + """XYZ to RGB color space conversion. + + Parameters + ---------- + xyz : (..., 3, ...) array_like + The image in XYZ format. By default, the final dimension denotes + channels. + + Returns + ------- + out : (..., 3, ...) ndarray + The image in RGB format. Same dimensions as input. + + Notes + ----- + Original Implementation from scikit-image package. + it can be found at: + https://github.com/scikit-image/scikit-image/blob/main/skimage/color/colorconv.py + This implementation might have been modified. + + """ + arr = xyz @ rgb_from_xyz.T.astype(xyz.dtype) + mask = arr > 0.0031308 + arr[mask] = 1.055 * np.power(arr[mask], 1 / 2.4) - 0.055 + arr[~mask] *= 12.92 + np.clip(arr, 0, 1, out=arr) + return arr
+ + + +
+[docs] +def rgb2xyz(rgb): + """RGB to XYZ color space conversion. + + Parameters + ---------- + rgb : (..., 3, ...) array_like + The image in RGB format. By default, the final dimension denotes + channels. + + Returns + ------- + out : (..., 3, ...) ndarray + The image in XYZ format. Same dimensions as input. + + Notes + ----- + Original Implementation from scikit-image package. + it can be found at: + https://github.com/scikit-image/scikit-image/blob/main/skimage/color/colorconv.py + This implementation might have been modified. + + """ + rgb = rgb.astype(float) + mask = rgb > 0.04045 + rgb[mask] = np.power((rgb[mask] + 0.055) / 1.055, 2.4) + rgb[~mask] /= 12.92 + return rgb @ xyz_from_rgb.T.astype(rgb.dtype)
+ + + +# XYZ coordinates of the illuminants, scaled to [0, 1]. For each illuminant I. +# Original Implementation of this object is from scikit-image package. +# it can be found at: +# https://github.com/scikit-image/scikit-image/blob/main/skimage/color/colorconv.py +illuminants = { + 'A': { + '2': (1.098466069456375, 1, 0.3558228003436005), + '10': (1.111420406956693, 1, 0.3519978321919493), + 'R': (1.098466069456375, 1, 0.3558228003436005), + }, + 'B': { + '2': (0.9909274480248003, 1, 0.8531327322886154), + '10': (0.9917777147717607, 1, 0.8434930535866175), + 'R': (0.9909274480248003, 1, 0.8531327322886154), + }, + 'C': { + '2': (0.980705971659919, 1, 1.1822494939271255), + '10': (0.9728569189782166, 1, 1.1614480488951577), + 'R': (0.980705971659919, 1, 1.1822494939271255), + }, + 'D50': { + '2': (0.9642119944211994, 1, 0.8251882845188288), + '10': (0.9672062750333777, 1, 0.8142801513128616), + 'R': (0.9639501491621826, 1, 0.8241280285499208), + }, + 'D55': { + '2': (0.956797052643698, 1, 0.9214805860173273), + '10': (0.9579665682254781, 1, 0.9092525159847462), + 'R': (0.9565317453467969, 1, 0.9202554587037198), + }, + 'D65': { + '2': (0.95047, 1.0, 1.08883), + '10': (0.94809667673716, 1, 1.0730513595166162), + 'R': (0.9532057125493769, 1, 1.0853843816469158), + }, + 'D75': { + '2': (0.9497220898840717, 1, 1.226393520724154), + '10': (0.9441713925645873, 1, 1.2064272211720228), + 'R': (0.9497220898840717, 1, 1.226393520724154), + }, + 'E': {'2': (1.0, 1.0, 1.0), '10': (1.0, 1.0, 1.0), 'R': (1.0, 1.0, 1.0)}, +} + + +
+[docs] +def get_xyz_coords(illuminant, observer): + """Get the XYZ coordinates of the given illuminant and observer [1]_. + + Parameters + ---------- + illuminant : {"A", "B", "C", "D50", "D55", "D65", "D75", "E"}, optional + The name of the illuminant (the function is NOT case sensitive). + observer : {"2", "10", "R"}, optional + One of: 2-degree observer, 10-degree observer, or 'R' observer as in + R function grDevices::convertColor. + + Returns + ------- + out : array + Array with 3 elements containing the XYZ coordinates of the given + illuminant. + + Notes + ----- + Original Implementation from scikit-image package. + it can be found at: + https://github.com/scikit-image/scikit-image/blob/main/skimage/color/colorconv.py + This implementation might have been modified. + + """ + illuminant = illuminant.upper() + observer = observer.upper() + try: + return np.asarray(illuminants[illuminant][observer], dtype=float) + except KeyError: + raise ValueError( + f'Unknown illuminant/observer combination ' + f'(`{illuminant}`, `{observer}`)' + )
+ + + +
+[docs] +def xyz2lab(xyz, illuminant='D65', observer='2'): + """XYZ to CIE-LAB color space conversion. + + Parameters + ---------- + xyz : (..., 3, ...) array_like + The image in XYZ format. By default, the final dimension denotes + channels. + illuminant : {"A", "B", "C", "D50", "D55", "D65", "D75", "E"}, optional + The name of the illuminant (the function is NOT case sensitive). + observer : {"2", "10", "R"}, optional + One of: 2-degree observer, 10-degree observer, or 'R' observer as in + R function grDevices::convertColor. + + Returns + ------- + out : (..., 3, ...) ndarray + The image in CIE-LAB format. Same dimensions as input. + + Notes + ----- + Original Implementation from scikit-image package. + it can be found at: + https://github.com/scikit-image/scikit-image/blob/main/skimage/color/colorconv.py + This implementation might have been modified. + + """ + xyz_ref_white = get_xyz_coords(illuminant, observer) + + # scale by CIE XYZ tristimulus values of the reference white point + arr = xyz / xyz_ref_white + + # Nonlinear distortion and linear transformation + mask = arr > 0.008856 + arr[mask] = np.cbrt(arr[mask]) + arr[~mask] = 7.787 * arr[~mask] + 16.0 / 116.0 + + x, y, z = arr[..., 0], arr[..., 1], arr[..., 2] + + # Vector scaling + L = (116.0 * y) - 16.0 + a = 500.0 * (x - y) + b = 200.0 * (y - z) + + return np.concatenate([x[..., np.newaxis] for x in [L, a, b]], axis=-1)
+ + + +
+[docs] +def lab2xyz(lab, illuminant='D65', observer='2'): + """CIE-LAB to XYZcolor space conversion. + + Parameters + ---------- + lab : (..., 3, ...) array_like + The image in Lab format. By default, the final dimension denotes + channels. + illuminant : {"A", "B", "C", "D50", "D55", "D65", "D75", "E"}, optional + The name of the illuminant (the function is NOT case-sensitive). + observer : {"2", "10", "R"}, optional + The aperture angle of the observer. + + Returns + ------- + out : (..., 3, ...) ndarray + The image in XYZ format. Same dimensions as input. + + Notes + ----- + Original Implementation from scikit-image package. + it can be found at: + https://github.com/scikit-image/scikit-image/blob/main/skimage/color/colorconv.py + This implementation might have been modified. + + """ + L, a, b = lab[..., 0], lab[..., 1], lab[..., 2] + y = (L + 16.0) / 116.0 + x = (a / 500.0) + y + z = y - (b / 200.0) + + if np.any(z < 0): + invalid = np.nonzero(z < 0) + warn( + 'Color data out of range: Z < 0 in %s pixels' % invalid[0].size, + stacklevel=2, + ) + z[invalid] = 0 + + out = np.stack([x, y, z], axis=-1) + + mask = out > 0.2068966 + out[mask] = np.power(out[mask], 3.0) + out[~mask] = (out[~mask] - 16.0 / 116.0) / 7.787 + + # rescale to the reference white (illuminant) + xyz_ref_white = get_xyz_coords(illuminant, observer) + out *= xyz_ref_white + return out
+ + + +
+[docs] +def rgb2lab(rgb, illuminant='D65', observer='2'): + """Conversion from the sRGB color space (IEC 61966-2-1:1999) + to the CIE Lab colorspace under the given illuminant and observer. + + Parameters + ---------- + rgb : (..., 3, ...) array_like + The image in RGB format. By default, the final dimension denotes + channels. + illuminant : {"A", "B", "C", "D50", "D55", "D65", "D75", "E"}, optional + The name of the illuminant (the function is NOT case sensitive). + observer : {"2", "10", "R"}, optional + The aperture angle of the observer. + + Returns + ------- + out : (..., 3, ...) ndarray + The image in Lab format. Same dimensions as input. + + Notes + ----- + Original Implementation from scikit-image package. + it can be found at: + https://github.com/scikit-image/scikit-image/blob/main/skimage/color/colorconv.py + This implementation might have been modified. + + """ + return xyz2lab(rgb2xyz(rgb), illuminant, observer)
+ + + +
+[docs] +def lab2rgb(lab, illuminant='D65', observer='2'): + """Lab to RGB color space conversion. + + Parameters + ---------- + lab : (..., 3, ...) array_like + The image in Lab format. By default, the final dimension denotes + channels. + illuminant : {"A", "B", "C", "D50", "D55", "D65", "D75", "E"}, optional + The name of the illuminant (the function is NOT case sensitive). + observer : {"2", "10", "R"}, optional + The aperture angle of the observer. + + Returns + ------- + out : (..., 3, ...) ndarray + The image in RGB format. Same dimensions as input. + + Notes + ----- + Original Implementation from scikit-image package. + it can be found at: + https://github.com/scikit-image/scikit-image/blob/main/skimage/color/colorconv.py + This implementation might have been modified. + + """ + return xyz2rgb(lab2xyz(lab, illuminant, observer))
+ +
+
+ + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/_modules/fury/convert.html b/v0.10.x/_modules/fury/convert.html new file mode 100644 index 000000000..566115feb --- /dev/null +++ b/v0.10.x/_modules/fury/convert.html @@ -0,0 +1,525 @@ + + + + + + + fury.convert — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +

Source code for fury.convert

+import os
+from tempfile import TemporaryDirectory
+
+import numpy as np
+
+from fury.io import load_image
+
+
+
+[docs] +def matplotlib_figure_to_numpy( + fig, dpi=100, fname=None, flip_up_down=True, transparent=False +): + """Convert a Matplotlib figure to a 3D numpy array with RGBA channels. + + Parameters + ---------- + fig : obj + A matplotlib figure object + dpi : int, optional + Dots per inch + fname : str, optional + If ``fname`` is given then the array will be saved as a png to this + position. + flip_up_down : bool, optional + The origin is different from matlplotlib default and VTK's default + behaviour (default True). + transparent : bool, optional + Make background transparent (default False). + + Returns + ------- + arr : ndarray + a numpy 3D array of RGBA values + + Notes + ----- + The safest way to read the pixel values from the figure was to save them + using savefig as a png and then read again the png. There is a cleaner + way found here http://www.icare.univ-lille1.fr/drupal/node/1141 where + you can actually use fig.canvas.tostring_argb() to get the values directly + without saving to the disk. However, this was not stable across different + machines and needed more investigation from what time permitted. + + """ + if fname is None: + with TemporaryDirectory() as tmpdir: + fname = os.path.join(tmpdir, 'tmp.png') + fig.savefig( + fname, + dpi=dpi, + transparent=transparent, + bbox_inches='tight', + pad_inches=0, + ) + arr = load_image(fname) + else: + fig.savefig( + fname, dpi=dpi, transparent=transparent, bbox_inches='tight', pad_inches=0 + ) + arr = load_image(fname) + + if flip_up_down: + arr = np.flipud(arr) + return arr
+ +
+
+ + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/_modules/fury/data/fetcher.html b/v0.10.x/_modules/fury/data/fetcher.html new file mode 100644 index 000000000..4bb37c4b6 --- /dev/null +++ b/v0.10.x/_modules/fury/data/fetcher.html @@ -0,0 +1,1264 @@ + + + + + + + fury.data.fetcher — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +

Source code for fury.data.fetcher

+"""Fetcher based on dipy."""
+
+import os
+import sys
+import contextlib
+import warnings
+import json
+
+from os.path import join as pjoin, dirname
+from hashlib import sha256
+from shutil import copyfileobj
+
+import tarfile
+import zipfile
+
+from urllib.request import urlopen
+import asyncio
+import aiohttp
+import platform
+
+# Set a user-writeable file-system location to put files:
+if 'FURY_HOME' in os.environ:
+    fury_home = os.environ['FURY_HOME']
+else:
+    fury_home = pjoin(os.path.expanduser('~'), '.fury')
+
+# The URL to the University of Washington Researchworks repository:
+UW_RW_URL = \
+    "https://digital.lib.washington.edu/researchworks/bitstream/handle/"
+
+NEW_ICONS_DATA_URL = \
+    "https://raw.githubusercontent.com/fury-gl/fury-data/master/icons/new_icons/"
+
+CUBEMAP_DATA_URL = \
+    "https://raw.githubusercontent.com/fury-gl/fury-data/master/cubemaps/"
+
+FURY_DATA_URL = \
+    "https://raw.githubusercontent.com/fury-gl/fury-data/master/examples/"
+
+MODEL_DATA_URL = \
+    "https://raw.githubusercontent.com/fury-gl/fury-data/master/models/"
+
+TEXTURE_DATA_URL = \
+    "https://raw.githubusercontent.com/fury-gl/fury-data/master/textures/"
+
+DMRI_DATA_URL = \
+    "https://raw.githubusercontent.com/fury-gl/fury-data/master/dmri/"
+
+GLTF_DATA_URL = \
+    "https://api.github.com/repos/KhronosGroup/glTF-Sample-Models/contents/2.0/"  # noqa
+
+
+class FetcherError(Exception):
+    pass
+
+
+
+[docs] +def update_progressbar(progress, total_length): + """Show progressbar. + + Takes a number between 0 and 1 to indicate progress from 0 to 100%. + """ + # Try to set the bar_length according to the console size + try: + if os.name == 'nt': + bar_length = 20 + else: + columns = os.popen('tput cols', 'r').read() + bar_length = int(columns) - 46 + if bar_length < 1: + bar_length = 20 + except Exception: + # Default value if determination of console size fails + bar_length = 20 + block = int(round(bar_length * progress)) + size_string = "{0:.2f} MB".format(float(total_length) / (1024 * 1024)) + text = "\rDownload Progress: [{0}] {1:.2f}% of {2}\n".format( + "#" * block + "-" * (bar_length - block), progress * 100, size_string) + sys.stdout.write(text) + sys.stdout.flush()
+ + + +
+[docs] +def copyfileobj_withprogress(fsrc, fdst, total_length, length=16 * 1024): + copied = 0 + while True: + buf = fsrc.read(length) + if not buf: + break + fdst.write(buf) + copied += len(buf) + progress = float(copied) / float(total_length) + update_progressbar(progress, total_length)
+ + + +def _already_there_msg(folder): + """Print a message indicating that dataset is already in place.""" + msg = 'Dataset is already in place. If you want to fetch it again ' + msg += 'please first remove the folder %s ' % folder + print(msg) + + +def _get_file_sha(filename): + """Generate SHA checksum for the entire file in blocks of 256. + + Parameters + ---------- + filename : str + The path to the file whose sha checksum is to be generated + + Returns + ------- + sha256_data : str + The computed sha hash from the input file + + """ + sha256_data = sha256() + with open(filename, 'rb') as f: + for chunk in iter(lambda: f.read(256*sha256_data.block_size), b''): + sha256_data.update(chunk) + return sha256_data.hexdigest() + + +
+[docs] +def check_sha(filename, stored_sha256=None): + """Check the generated sha checksum. + + Parameters + ---------- + filename : str + The path to the file whose checksum is to be compared + stored_sha256 : str, optional + Used to verify the generated SHA checksum. + Default: None, checking is skipped + + """ + if stored_sha256 is not None: + computed_sha256 = _get_file_sha(filename) + if stored_sha256.lower() != computed_sha256: + msg = """The downloaded file, %s, + does not have the expected sha + checksum of "%s". + Instead, the sha checksum was: "%s". + This could mean that + something is wrong with the file + or that the upstream file has been updated. + You can try downloading the file again + or updating to the newest version of + Fury.""" % (filename, stored_sha256, computed_sha256) + raise FetcherError(msg)
+ + + +def _get_file_data(fname, url): + with contextlib.closing(urlopen(url)) as opener: + try: + response_size = opener.headers['content-length'] + except KeyError: + response_size = None + + with open(fname, 'wb') as data: + if response_size is None: + copyfileobj(opener, data) + else: + copyfileobj_withprogress(opener, data, response_size) + + +
+[docs] +def fetch_data(files, folder, data_size=None): + """Download files to folder and checks their sha checksums. + + Parameters + ---------- + files : dictionary + For each file in `files` the value should be (url, sha). The file will + be downloaded from url if the file does not already exist or if the + file exists but the sha checksum does not match. + folder : str + The directory where to save the file, the directory will be created if + it does not already exist. + data_size : str, optional + A string describing the size of the data (e.g. "91 MB") to be logged to + the screen. Default does not produce any information about data size. + + Raises + ------ + FetcherError + + Raises if the sha checksum of the file does not match the expected + value. The downloaded file is not deleted when this error is raised. + + """ + if not os.path.exists(folder): + print("Creating new folder %s" % (folder)) + os.makedirs(folder) + + if data_size is not None: + print('Data size is approximately %s' % data_size) + + all_skip = True + for f in files: + url, sha = files[f] + fullpath = pjoin(folder, f) + if os.path.exists(fullpath) and \ + (_get_file_sha(fullpath) == sha.lower()): + continue + all_skip = False + print('Downloading "%s" to %s' % (f, folder)) + _get_file_data(fullpath, url) + check_sha(fullpath, sha) + if all_skip: + _already_there_msg(folder) + else: + print("Files successfully downloaded to %s" % (folder))
+ + + +def _make_fetcher(name, folder, baseurl, remote_fnames, local_fnames, + sha_list=None, doc="", data_size=None, msg=None, + unzip=False): + """Create a new fetcher. + + Parameters + ---------- + name : str + The name of the fetcher function. + folder : str + The full path to the folder in which the files would be placed locally. + Typically, this is something like 'pjoin(fury_home, 'foo')' + baseurl : str + The URL from which this fetcher reads files + remote_fnames : list of strings + The names of the files in the baseurl location + local_fnames : list of strings + The names of the files to be saved on the local filesystem + sha_list : list of strings, optional + The sha checksums of the files. Used to verify the content of the + files. Default: None, skipping checking sha. + doc : str, optional. + Documentation of the fetcher. + data_size : str, optional. + If provided, is sent as a message to the user before downloading + starts. + msg : str, optional. + A message to print to screen when fetching takes place. Default (None) + is to print nothing + unzip : bool, optional + Whether to unzip the file(s) after downloading them. Supports zip, gz, + and tar.gz files. + + Returns + ------- + fetcher : function + A function that, when called, fetches data according to the designated + inputs + + """ + def fetcher(): + files = {} + for i, (f, n), in enumerate(zip(remote_fnames, local_fnames)): + files[n] = (baseurl + f, sha_list[i] if + sha_list is not None else None) + fetch_data(files, folder, data_size) + + if msg is not None: + print(msg) + if unzip: + for f in local_fnames: + split_ext = os.path.splitext(f) + if split_ext[-1] == '.gz' or split_ext[-1] == '.bz2': + if os.path.splitext(split_ext[0])[-1] == '.tar': + ar = tarfile.open(pjoin(folder, f)) + ar.extractall(path=folder) + ar.close() + else: + raise ValueError('File extension is not recognized') + elif split_ext[-1] == '.zip': + z = zipfile.ZipFile(pjoin(folder, f), 'r') + z.extractall(folder) + z.close() + else: + raise ValueError('File extension is not recognized') + + return files, folder + + fetcher.__name__ = name + fetcher.__doc__ = doc + return fetcher + + +async def _request(session, url): + """Get the request data as json. + + Parameters + ---------- + session : ClientSession + Aiohttp client session. + url : string + The URL from which _request gets the response + + Returns + ------- + response : dictionary + The response of url request. + + """ + async with session.get(url) as response: + if not response.status == 200: + raise aiohttp.InvalidURL(url) + + return await response.json() + + +async def _download(session, url, filename, size=None): + """Download file from url. + + Parameters + ---------- + session : ClientSession + Aiohttp client session + url : string + The URL of the downloadable file + filename : string + Name of the downloaded file (e.g. BoxTextured.gltf) + size : int, optional + Length of the content in bytes + + """ + if not os.path.exists(filename): + print(f'Downloading: {filename}') + async with session.get(url) as response: + size = response.content_length if not size else size + block = size + copied = 0 + with open(filename, mode='wb') as f: + async for chunk in response.content.iter_chunked(block): + f.write(chunk) + copied += len(chunk) + progress = float(copied)/float(size) + update_progressbar(progress, size) + + +async def _fetch_gltf(name, mode): + """Fetch glTF samples. + + Parameters + ---------- + name: str, list + Name of the glTF model (for e.g. Box, BoxTextured, FlightHelmet, etc) + + mode: str + Type of the glTF format. + (e.g. glTF, glTF-Embedded, glTF-Binary, glTF-Draco) + + Returns + ------- + f_names : list + list of fetched all file names. + folder : str + Path to the fetched files. + + """ + if name is None: + name = ['BoxTextured', 'Duck', 'CesiumMilkTruck', 'CesiumMan'] + + if isinstance(name, list): + f_names = await asyncio.gather( + *[_fetch_gltf(element, mode) for element in name] + ) + return f_names + else: + path = f'{name}/{mode}' + DATA_DIR = pjoin(dirname(__file__), 'files') + with open(pjoin(DATA_DIR, 'KhronosGltfSamples.json'), 'r') as f: + models = json.loads(f.read()) + + urls = models.get(path, None) + + if urls is None: + raise ValueError( + "Model name and mode combination doesn't exist") + + path = pjoin(name, mode) + path = pjoin('glTF', path) + folder = pjoin(fury_home, path) + if not os.path.exists(folder): + os.makedirs(folder) + + d_urls = [file['download_url'] for file in urls] + sizes = [file['size'] for file in urls] + f_names = [url.split('/')[-1] for url in d_urls] + f_paths = [pjoin(folder, name) for name in f_names] + zip_url = zip(d_urls, f_paths, sizes) + + async with aiohttp.ClientSession() as session: + await asyncio.gather( + *[_download(session, url, name, s) for url, name, s in zip_url] + ) + + return f_names, folder + + +
+[docs] +def fetch_gltf(name=None, mode='glTF'): + """Download glTF samples from Khronos Group Github. + + Parameters + ---------- + name: str, list, optional + Name of the glTF model (for e.g. Box, BoxTextured, FlightHelmet, etc) + https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0 + Default: None, Downloads essential glTF samples for tests. + + mode: str, optional + Type of glTF format. + You can choose from different options + (e.g. glTF, glTF-Embedded, glTF-Binary, glTF-Draco) + Default: glTF, `.bin` and texture files are stored separately. + + Returns + ------- + filenames : tuple + tuple of feteched filenames (list) and folder (str) path. + + """ + if platform.system().lower() == "windows": + asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy()) + filenames = asyncio.run(_fetch_gltf(name, mode)) + return filenames
+ + + +fetch_viz_cubemaps = _make_fetcher( + "fetch_viz_cubemaps", + pjoin(fury_home, "cubemaps"), + CUBEMAP_DATA_URL, + ['skybox-nx.jpg', 'skybox-ny.jpg', 'skybox-nz.jpg', 'skybox-px.jpg', + 'skybox-py.jpg', 'skybox-pz.jpg'], + ['skybox-nx.jpg', 'skybox-ny.jpg', 'skybox-nz.jpg', 'skybox-px.jpg', + 'skybox-py.jpg', 'skybox-pz.jpg'], + ['12B1CE6C91AA3AAF258A8A5944DF739A6C1CC76E89D4D7119D1F795A30FC1BF2', + 'E18FE2206B63D3DF2C879F5E0B9937A61D99734B6C43AC288226C58D2418D23E', + '00DDDD1B715D5877AF2A74C014FF6E47891F07435B471D213CD0673A8C47F2B2', + 'BF20ACD6817C9E7073E485BBE2D2CE56DACFF73C021C2B613BA072BA2DF2B754', + '16F0D692AF0B80E46929D8D8A7E596123C76729CC5EB7DFD1C9184B115DD143A', + 'B850B5E882889DF26BE9289D7C25BA30524B37E56BC2075B968A83197AD977F3'], + doc="Download cube map textures for fury" +) + +fetch_viz_icons = _make_fetcher( + "fetch_viz_icons", + pjoin(fury_home, "icons"), + UW_RW_URL + "1773/38478/", + ['icomoon.tar.gz'], + ['icomoon.tar.gz'], + ['BC1FEEA6F58BA3601D6A0B029EB8DFC5F352E21F2A16BA41099A96AA3F5A4735'], + data_size="12KB", + doc="Download icons for fury", + unzip=True + ) + +fetch_viz_new_icons = _make_fetcher( + "fetch_viz_new_icons", + pjoin(fury_home, "icons", "new_icons"), + NEW_ICONS_DATA_URL, + ["circle-pressed.png", "circle.png", "delete-pressed.png", "delete.png", + "drawing-pressed.png", "drawing.png", "line-pressed.png", "line.png", + "polyline-pressed.png", "polyline.png", "quad-pressed.png", "quad.png", + "resize-pressed.png", "resize.png", "selection-pressed.png", "selection.png"], + ["circle-pressed.png", "circle.png", "delete-pressed.png", "delete.png", + "drawing-pressed.png", "drawing.png", "line-pressed.png", "line.png", + "polyline-pressed.png", "polyline.png", "quad-pressed.png", "quad.png", + "resize-pressed.png", "resize.png", "selection-pressed.png", "selection.png"], + ["CD859F244DF1BA719C65C869C3FAF6B8563ABF82F457730ADBFBD7CA72DDB7BC", + "5896BDC9FF9B3D1054134D7D9A854677CE9FA4E64F494F156BB2E3F0E863F207", + "937C46C25BC38B62021B01C97A4EE3CDE5F7C8C4A6D0DB75BF4E4CACE2AF1226", + "476E00A0A5373E1CCDA4AF8E7C9158E0AC9B46B540CE410C6EA47D97F364A0CD", + "08A914C5DC7997CB944B8C5FBB958951F80B715CFE04FF4F47A73F9D08C4B14B", + "FB2210B0393ECA8A5DD2B8F034DAE386BBB47EB95BB1CAC2A97DE807EE195ADF", + "8D1AC2BB7C5BAA34E68578DAAD85F64EF824BE7BCB828CAC18E52833D4CBF4C9", + "E6D833B6D958129E12FF0F6087282CE92CD43C6DAFCE03F185746ECCA89E42A9", + "CFF12B8DE48FC19DA5D5F0EA7FF2D23DD942D05468E19522E7C7BEB72F0FF66E", + "7AFE65EBAE0C0D0556393B979148AE15FC3E037D126CD1DA4A296F4E25F5B4AA", + "5FD43F1C2D37BF9AF05D9FC591172684AC51BA236980CD1B0795B0225B9247E2", + "A2DA0CB963401C174919E1D8028AA6F0CB260A736FD26421DB5AB08E9F3C4FDF", + "FF49DDF9DF24729F4F6345C30C88DE0A11E5B12B2F2FF28375EF9762FE5F8995", + "A2D850CDBA8F332DA9CD7B7C9459CBDA587C18AF0D3C12CA68D6E6A864EF54BB", + "54618FDC4589F0A039D531C07A110ED9BC57A256BB15A3B5429CF60E950887C3", + "CD573F5E4BF4A91A3B21F6124A95FFB3C036F926F8FEC1FD0180F5D27D8F48C0"], + doc="Download the new icons for DrawPanel" + ) + + +fetch_viz_wiki_nw = _make_fetcher( + "fetch_viz_wiki_nw", + pjoin(fury_home, "examples", "wiki_nw"), + FURY_DATA_URL, + ['wiki_categories.txt', 'wiki_edges.txt', + 'wiki_positions.txt'], + ['wiki_categories.txt', 'wiki_edges.txt', + 'wiki_positions.txt'], + ['1679241B13D2FD01209160F0C186E14AB55855478300B713D5369C12854CFF82', + '702EE8713994243C8619A29C9ECE32F95305737F583B747C307500F3EC4A6B56', + '044917A8FBD0EB980D93B6C406A577BEA416FA934E897C26C87E91C218EF4432'], + doc="Download the following wiki information" + "Interdisciplinary map of the journals", + msg=("More information about complex " + "networks can be found in this papers:" + " https://arxiv.org/abs/0711.3199") + ) + +fetch_viz_models = _make_fetcher( + "fetch_viz_models", + pjoin(fury_home, "models"), + MODEL_DATA_URL, + ['utah.obj', 'suzanne.obj', 'satellite_obj.obj', 'dragon.obj'], + ['utah.obj', 'suzanne.obj', 'satellite_obj.obj', 'dragon.obj'], + ['0B50F12CEDCDC27377AC702B1EE331223BECEC59593B3F00A9E06B57A9C1B7C3', + 'BB4FF4E65D65D71D53000E06D2DC7BF89B702223657C1F64748811A3A6C8D621', + '90213FAC81D89BBB59FA541643304E0D95C2D446157ACE044D46F259454C0E74', + 'A775D6160D04EAB9A4E90180104F148927CEFCCAF9F0BCD748265CB8EE86F41B'], + doc=" Download the models for shader tutorial" + ) + +fetch_viz_dmri = _make_fetcher( + "fetch_viz_dmri", + pjoin(fury_home, "dmri"), + DMRI_DATA_URL, + ['fodf.nii.gz', 'slice_evecs.nii.gz', 'slice_evals.nii.gz', + 'roi_evecs.nii.gz', 'roi_evals.nii.gz', 'whole_brain_evecs.nii.gz', + 'whole_brain_evals.nii.gz'], + ['fodf.nii.gz', 'slice_evecs.nii.gz', 'slice_evals.nii.gz', + 'roi_evecs.nii.gz', 'roi_evals.nii.gz', 'whole_brain_evecs.nii.gz', + 'whole_brain_evals.nii.gz'], + ['767ca3e4cd296e78421d83c32201b30be2d859c332210812140caac1b93d492b', + '8843ECF3224CB8E3315B7251D1E303409A17D7137D3498A8833853C4603C6CC2', + '3096B190B1146DD0EADDFECC0B4FBBD901F4933692ADD46A83F637F28B22122D', + '89E569858A897E72C852A8F05BBCE0B21C1CA726E55508087A2DA5A38C212A17', + 'F53C68CCCABF97F1326E93840A8B5CE2E767D66D692FFD955CA747FFF14EC781', + '8A894F6AB404240E65451FA6D10FB5D74E2D0BDCB2A56AD6BEA38215BF787248', + '47A73BBE68196381ED790F80F48E46AC07B699B506973FFA45A95A33023C7A77'] +) + +fetch_viz_textures = _make_fetcher( + "fetch_viz_textures", + pjoin(fury_home, "textures"), + TEXTURE_DATA_URL, + ['1_earth_8k.jpg', '2_no_clouds_8k.jpg', + '5_night_8k.jpg', 'earth.ppm', + 'jupiter.jpg', 'masonry.bmp', + 'moon_8k.jpg', + '8k_mercury.jpg', '8k_venus_surface.jpg', + '8k_mars.jpg', '8k_saturn.jpg', + '8k_saturn_ring_alpha.png', + '2k_uranus.jpg', '2k_neptune.jpg', + '8k_sun.jpg', '1_earth_16k.jpg', + 'clouds.jpg'], + ['1_earth_8k.jpg', '2_no_clouds_8k.jpg', + '5_night_8k.jpg', 'earth.ppm', + 'jupiter.jpg', 'masonry.bmp', + 'moon-8k.jpg', + '8k_mercury.jpg', '8k_venus_surface.jpg', + '8k_mars.jpg', '8k_saturn.jpg', + '8k_saturn_ring_alpha.png', + '2k_uranus.jpg', '2k_neptune.jpg', + '8k_sun.jpg', '1_earth_16k.jpg', + 'clouds.jpg'], + ['0D66DC62768C43D763D3288CE67128AAED27715B11B0529162DC4117F710E26F', + '5CF740C72287AF7B3ACCF080C3951944ADCB1617083B918537D08CBD9F2C5465', + 'DF443F3E20C7724803690A350D9F6FDB36AD8EBC011B0345FB519A8B321F680A', + '34CE9AD183D7C7B11E2F682D7EBB84C803E661BE09E01ADB887175AE60C58156', + '5DF6A384E407BD0D5F18176B7DB96AAE1EEA3CFCFE570DDCE0D34B4F0E493668', + '045E30B2ABFEAE6318C2CF955040C4A37E6DE595ACE809CE6766D397C0EE205D', + '7397A6C2CE0348E148C66EBEFE078467DDB9D0370FF5E63434D0451477624839', + '5C8BD885AE3571C6BA2CD34B3446B9C6D767E314BF0EE8C1D5C147CADD388FC3', + '9BC21A50577ED8AC734CDA91058724C7A741C19427AA276224CE349351432C5B', + '4CC52149924ABC6AE507D63032F994E1D42A55CB82C09E002D1A567FF66C23EE', + '0D39A4A490C87C3EDABE00A3881A29BB3418364178C79C534FE0986E97E09853', + 'F1F826933C9FF87D64ECF0518D6256B8ED990B003722794F67E96E3D2B876AE4', + 'D15239D46F82D3EA13D2B260B5B29B2A382F42F2916DAE0694D0387B1204A09D', + 'CB42EA82709741D28B0AF44D8B283CBC6DBD0C521A7F0E1E1E010ADE00977DF6', + 'F22B1CFB306DDCE72A7E3B628668A0175B745038CE6268557CB2F7F1BDF98B9D', + '7DD1DAC926101B5D7B7F2E952E53ACF209421B5CCE57C03168BCE0AAD675998A', + '85043336E023C4C9394CFD6D48D257A5564B4F895BFCEC01C70E4898CC77F003'], + doc="Download textures for fury" + ) + + +
+[docs] +def read_viz_cubemap(name, suffix_type=1, ext='.jpg'): + """Read specific cube map with specific suffix type and extension. + + Parameters + ---------- + name : str + suffix_type : int, optional + 0 for numeric suffix (e.g., skybox_0.jpg, skybox_1.jpg, etc.), 1 for + -p/nC encoding where C is either x, y or z (e.g., skybox-px.jpeg, + skybox-ny.jpeg, etc.), 2 for pos/negC where C is either x, y, z (e.g., + skybox_posx.png, skybox_negy.png, etc.), and 3 for position in the cube + map (e.g., skybox_right.jpg, skybox_front.jpg, etc). + ext : str, optional + Image type extension. (.jpg, .jpeg, .png, etc.). + + Returns + ------- + list of paths : list + List with the complete paths of the skybox textures. + + """ + # Set of commonly used cube map naming conventions and its associated + # indexing number. For a correct creation and display of the skybox, + # textures must be read in this order. + suffix_types = { + 0: ['0', '1', '2', '3', '4', '5'], + 1: ['-px', '-nx', '-py', '-ny', '-pz', '-nz'], + 2: ['posx', 'negx', 'posy', 'negy', 'posz', 'negz'], + 3: ['right', 'left', 'top', 'bottom', 'front', 'back'] + } + if suffix_type in suffix_types: + conv = suffix_types[suffix_type] + else: + warnings.warn('read_viz_cubemap(): Invalid suffix_type.') + return None + cubemap_fnames = [] + folder = pjoin(fury_home, 'cubemaps') + for dir_conv in conv: + cubemap_fnames.append(pjoin(folder, name + dir_conv + ext)) + return cubemap_fnames
+ + + +
+[docs] +def read_viz_icons(style='icomoon', fname='infinity.png'): + """Read specific icon from specific style. + + Parameters + ---------- + style : str + Current icon style. Default is icomoon. + fname : str + Filename of icon. This should be found in folder HOME/.fury/style/. + Default is infinity.png. + + Returns + ------- + path : str + Complete path of icon. + + """ + if not os.path.isdir(pjoin(fury_home, 'icons', style)): + if style == "icomoon": + fetch_viz_icons() + elif style == "new_icons": + fetch_viz_new_icons() + folder = pjoin(fury_home, 'icons', style) + return pjoin(folder, fname)
+ + + +
+[docs] +def read_viz_models(fname): + """Read specific model. + + Parameters + ---------- + fname : str + Filename of the model. + This should be found in folder HOME/.fury/models/. + + Returns + ------- + path : str + Complete path of models. + + """ + folder = pjoin(fury_home, 'models') + return pjoin(folder, fname)
+ + + +
+[docs] +def read_viz_textures(fname): + """Read specific texture. + + Parameters + ---------- + fname: str + Filename of the texture. + This should be found in folder HOME/.fury/textures/. + + Returns + ------- + path : str + Complete path of textures. + + """ + folder = pjoin(fury_home, 'textures') + return pjoin(folder, fname)
+ + + +
+[docs] +def read_viz_dmri(fname): + """Read specific dMRI image. + + Parameters + ---------- + fname: str + Filename of the texture. + This should be found in folder HOME/.fury/dmri/. + + Returns + ------- + path : str + Complete path of dMRI image. + + """ + folder = pjoin(fury_home, 'dmri') + return pjoin(folder, fname)
+ + + +
+[docs] +def read_viz_gltf(fname, mode='glTF'): + """Read specific gltf sample. + + Parameters + ---------- + fname : str + Name of the model. + This should be found in folder HOME/.fury/models/glTF/. + + mode : str, optional + Model type (e.g. glTF-Binary, glTF-Embedded, etc) + Default : glTF + + Returns + ------- + path : str + Complete path of models. + + """ + folder = pjoin(fury_home, 'glTF') + model = pjoin(folder, fname) + + sample = pjoin(model, mode) + + if not os.path.exists(sample): + raise ValueError(f'Model {sample} does not exists.') + + for filename in os.listdir(sample): + if filename.endswith('.gltf') or filename.endswith('.glb'): + return pjoin(sample, filename)
+ + + +
+[docs] +def list_gltf_sample_models(): + """Return all model name from the glTF-samples repository. + + Returns + ------- + model_names : list + Lists the name of glTF sample from + https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0 + + """ + DATA_DIR = pjoin(dirname(__file__), 'files') + with open(pjoin(DATA_DIR, 'KhronosGltfSamples.json'), 'r') as f: + models = json.loads(f.read()) + models = models.keys() + model_modes = [model.split('/')[0] for model in models] + + model_names = [] + for name in model_modes: + if name not in model_names: + model_names.append(name) + model_names = model_names[1:] # removing __comments__ + + default_models = ['BoxTextured', 'Duck', 'CesiumMilkTruck', 'CesiumMan'] + + if not model_names: + print('Failed to get models list') + return None + result = [model in model_names for model in default_models] + for i, exist in enumerate(result): + if not exist: + print(f'Default Model: {default_models[i]} not found!') + return model_names
+ +
+
+ + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/_modules/fury/decorators.html b/v0.10.x/_modules/fury/decorators.html new file mode 100644 index 000000000..8ca467c86 --- /dev/null +++ b/v0.10.x/_modules/fury/decorators.html @@ -0,0 +1,506 @@ + + + + + + + fury.decorators — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +

Source code for fury.decorators

+"""Decorators for FURY tests."""
+import platform
+import re
+import sys
+
+skip_linux = is_linux = platform.system().lower() == 'linux'
+skip_osx = is_osx = platform.system().lower() == 'darwin'
+skip_win = is_win = platform.system().lower() == 'windows'
+is_py35 = sys.version_info.major == 3 and sys.version_info.minor == 5
+SKIP_RE = re.compile(r'(\s*>>>.*?)(\s*)#\s*skip\s+if\s+(.*)$')
+
+
+
+[docs] +def doctest_skip_parser(func): + """Decorator replaces custom skip test markup in doctests. + + Say a function has a docstring:: + >>> something # skip if not HAVE_AMODULE + >>> something + else + >>> something # skip if HAVE_BMODULE + This decorator will evaluate the expression after ``skip if``. If this + evaluates to True, then the comment is replaced by ``# doctest: +SKIP``. + If False, then the comment is just removed. The expression is evaluated in + the ``globals`` scope of `func`. + For example, if the module global ``HAVE_AMODULE`` is False, and module + global ``HAVE_BMODULE`` is False, the returned function will have + docstring:: + >>> something # doctest: +SKIP + >>> something + else + >>> something + + """ + lines = func.__doc__.split('\n') + new_lines = [] + for line in lines: + match = SKIP_RE.match(line) + if match is None: + new_lines.append(line) + continue + code, space, expr = match.groups() + if eval(expr, func.__globals__): + code = code + space + '# doctest: +SKIP' + new_lines.append(code) + func.__doc__ = '\n'.join(new_lines) + return func
+ +
+
+ + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/_modules/fury/deprecator.html b/v0.10.x/_modules/fury/deprecator.html new file mode 100644 index 000000000..dd251c085 --- /dev/null +++ b/v0.10.x/_modules/fury/deprecator.html @@ -0,0 +1,918 @@ + + + + + + + fury.deprecator — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +

Source code for fury.deprecator

+"""Function for recording and reporting deprecations.
+
+Notes
+-----
+this file is copied (with minor modifications) from the Nibabel.
+https://github.com/nipy/nibabel. See COPYING file distributed along with
+the Nibabel package for the copyright and license terms.
+
+"""
+
+import functools
+import re
+import warnings
+from inspect import signature
+
+from fury import __version__
+from fury.optpkg import optional_package
+
+# packaging.version.parse is a third-party utility but is used by setuptools
+# (so probably already installed) and is conformant to the current PEP 440.
+# But just if it is not the case, we use distutils
+packaging, have_pkg, _ = optional_package('setuptools.extern.packaging')
+
+_LEADING_WHITE = re.compile(r'^(\s*)')
+
+
+
+[docs] +class ExpiredDeprecationError(RuntimeError): + """Error for expired deprecation. + + Error raised when a called function or method has passed out of its + deprecation period. + + """ + + pass
+ + + +
+[docs] +class ArgsDeprecationWarning(DeprecationWarning): + """Warning for args deprecation. + + Warning raised when a function or method argument has changed or removed. + + """ + + pass
+ + + +def _ensure_cr(text): + """Remove trailing whitespace and add carriage return. + + Ensures that ``text`` always ends with a carriage return + """ + return text.rstrip() + '\n' + + +def _add_dep_doc(old_doc, dep_doc): + """Add deprecation message ``dep_doc`` to docstring in ``old_doc``. + + Parameters + ---------- + old_doc : str + Docstring from some object. + dep_doc : str + Deprecation warning to add to top of docstring, after initial line. + + Returns + ------- + new_doc : str + ``old_doc`` with ``dep_doc`` inserted after any first lines of + docstring. + + """ + dep_doc = _ensure_cr(dep_doc) + if not old_doc: + return dep_doc + old_doc = _ensure_cr(old_doc) + old_lines = old_doc.splitlines() + new_lines = [] + for line_no, line in enumerate(old_lines): + if line.strip(): + new_lines.append(line) + else: + break + next_line = line_no + 1 + if next_line >= len(old_lines): + # nothing following first paragraph, just append message + return old_doc + '\n' + dep_doc + indent = _LEADING_WHITE.match(old_lines[next_line]).group() + dep_lines = [indent + L for L in [''] + dep_doc.splitlines() + ['']] + return '\n'.join(new_lines + dep_lines + old_lines[next_line:]) + '\n' + + +
+[docs] +def cmp_pkg_version(version_str, pkg_version_str=__version__): + """Compare ``version_str`` to current package version. + + Parameters + ---------- + version_str : str + Version string to compare to current package version + pkg_version_str : str, optional + Version of our package. Optional, set from ``__version__`` by default. + + Returns + ------- + version_cmp : int + 1 if ``version_str`` is a later version than ``pkg_version_str``, 0 if + same, -1 if earlier. + + Examples + -------- + >>> cmp_pkg_version('1.2.1', '1.2.0') + 1 + >>> cmp_pkg_version('1.2.0dev', '1.2.0') + -1 + + """ + version_cmp = packaging.version.parse if have_pkg else None + + if any([re.match(r'^[a-z, A-Z]', v) for v in [version_str, pkg_version_str]]): + msg = 'Invalid version {0} or {1}'.format(version_str, pkg_version_str) + raise ValueError(msg) + elif version_cmp(version_str) > version_cmp(pkg_version_str): + return 1 + elif version_cmp(version_str) == version_cmp(pkg_version_str): + return 0 + else: + return -1
+ + + +
+[docs] +def is_bad_version(version_str, version_comparator=cmp_pkg_version): + """Return True if `version_str` is too high.""" + return version_comparator(version_str) == -1
+ + + +
+[docs] +def deprecate_with_version( + message, + since='', + until='', + version_comparator=cmp_pkg_version, + warn_class=DeprecationWarning, + error_class=ExpiredDeprecationError, +): + """Return decorator function for deprecation warning / error. + + The decorated function / method will: + + * Raise the given ``warning_class`` warning when the function / method gets + called, up to (and including) version `until` (if specified); + * Raise the given ``error_class`` error when the function / method gets + called, when the package version is greater than version ``until`` (if + specified). + + Parameters + ---------- + message : str + Message explaining deprecation, giving possible alternatives. + since : str, optional + Released version at which object was first deprecated. + until : str, optional + Last released version at which this function will still raise a + deprecation warning. Versions higher than this will raise an + error. + version_comparator : callable + Callable accepting string as argument, and return 1 if string + represents a higher version than encoded in the version_comparator`, 0 + if the version is equal, and -1 if the version is lower. For example, + the ``version_comparator`` may compare the input version string to the + current package version string. + warn_class : class, optional + Class of warning to generate for deprecation. + error_class : class, optional + Class of error to generate when ``version_comparator`` returns 1 for a + given argument of ``until``. + + Returns + ------- + deprecator : func + Function returning a decorator. + + """ + messages = [message] + if (since, until) != ('', ''): + messages.append('') + if since: + messages.append('* deprecated from version: ' + since) + if until: + messages.append( + '* {0} {1} as of version: {2}'.format( + 'Raises' if is_bad_version(until) else 'Will raise', error_class, until + ) + ) + message = '\n'.join(messages) + + def deprecator(func): + @functools.wraps(func) + def deprecated_func(*args, **kwargs): + if until and is_bad_version(until, version_comparator): + raise error_class(message) + warnings.warn(message, warn_class, stacklevel=2) + return func(*args, **kwargs) + + deprecated_func.__doc__ = _add_dep_doc(deprecated_func.__doc__, message) + return deprecated_func + + return deprecator
+ + + +
+[docs] +def deprecated_params( + old_name, + new_name=None, + since='', + until='', + version_comparator=cmp_pkg_version, + arg_in_kwargs=False, + warn_class=ArgsDeprecationWarning, + error_class=ExpiredDeprecationError, + alternative='', +): + """Deprecate a *renamed* or *removed* function argument. + + The decorator assumes that the argument with the ``old_name`` was removed + from the function signature and the ``new_name`` replaced it at the + **same position** in the signature. If the ``old_name`` argument is + given when calling the decorated function the decorator will catch it and + issue a deprecation warning and pass it on as ``new_name`` argument. + + Parameters + ---------- + old_name : str or list/tuple thereof + The old name of the argument. + new_name : str or list/tuple thereof or ``None``, optional + The new name of the argument. Set this to `None` to remove the + argument ``old_name`` instead of renaming it. + since : str or number or list/tuple thereof, optional + The release at which the old argument became deprecated. + until : str or number or list/tuple thereof, optional + Last released version at which this function will still raise a + deprecation warning. Versions higher than this will raise an + error. + version_comparator : callable + Callable accepting string as argument, and return 1 if string + represents a higher version than encoded in the ``version_comparator``, + 0 if the version is equal, and -1 if the version is lower. For example, + the ``version_comparator`` may compare the input version string to the + current package version string. + arg_in_kwargs : bool or list/tuple thereof, optional + If the argument is not a named argument (for example it + was meant to be consumed by ``**kwargs``) set this to + ``True``. Otherwise the decorator will throw an Exception + if the ``new_name`` cannot be found in the signature of + the decorated function. + Default is ``False``. + warn_class : warning, optional + Warning to be issued. + error_class : Exception, optional + Error to be issued + alternative : str, optional + An alternative function or class name that the user may use in + place of the deprecated object if ``new_name`` is None. The deprecation + warning will tell the user about this alternative if provided. + + Raises + ------ + TypeError + If the new argument name cannot be found in the function + signature and arg_in_kwargs was False or if it is used to + deprecate the name of the ``*args``-, ``**kwargs``-like arguments. + At runtime such an Error is raised if both the new_name + and old_name were specified when calling the function and + "relax=False". + + Notes + ----- + This function is based on the Astropy (major modification). + https://github.com/astropy/astropy. See COPYING file distributed along with + the astropy package for the copyright and license terms. + + Examples + -------- + The deprecation warnings are not shown in the following examples. + To deprecate a positional or keyword argument:: + >>> from fury.deprecator import deprecated_params + >>> @deprecated_params('sig', 'sigma', '0.3') + ... def test(sigma): + ... return sigma + >>> test(2) + 2 + >>> test(sigma=2) + 2 + >>> test(sig=2) # doctest: +SKIP + 2 + + It is also possible to replace multiple arguments. The ``old_name``, + ``new_name`` and ``since`` have to be `tuple` or `list` and contain the + same number of entries:: + >>> @deprecated_params(['a', 'b'], ['alpha', 'beta'], + ... ['0.2', 0.4]) + ... def test(alpha, beta): + ... return alpha, beta + >>> test(a=2, b=3) # doctest: +SKIP + (2, 3) + + """ + if isinstance(old_name, (list, tuple)): + # Normalize input parameters + if not isinstance(arg_in_kwargs, (list, tuple)): + arg_in_kwargs = [arg_in_kwargs] * len(old_name) + if not isinstance(since, (list, tuple)): + since = [since] * len(old_name) + if not isinstance(until, (list, tuple)): + until = [until] * len(old_name) + if not isinstance(new_name, (list, tuple)): + new_name = [new_name] * len(old_name) + + if ( + len( + set( + [ + len(old_name), + len(new_name), + len(since), + len(until), + len(arg_in_kwargs), + ] + ) + ) + != 1 + ): + raise ValueError('All parameters should have the same length') + else: + # To allow a uniform approach later on, wrap all arguments in lists. + old_name = [old_name] + new_name = [new_name] + since = [since] + until = [until] + arg_in_kwargs = [arg_in_kwargs] + + def deprecator(function): + # The named arguments of the function. + arguments = signature(function).parameters + positions = [None] * len(old_name) + + for i, (o_name, n_name, in_keywords) in enumerate( + zip(old_name, new_name, arg_in_kwargs) + ): + # Determine the position of the argument. + if in_keywords: + continue + + if n_name is not None and n_name not in arguments: + # In case the argument is not found in the list of arguments + # the only remaining possibility is that it should be caught + # by some kind of **kwargs argument. + msg = '"{}" was not specified in the function '.format(n_name) + msg += 'signature. If it was meant to be part of ' + msg += '"**kwargs" then set "arg_in_kwargs" to "True"' + raise TypeError(msg) + + key = o_name if n_name is None else n_name + param = arguments[key] + + if param.kind == param.POSITIONAL_OR_KEYWORD: + key = o_name if n_name is None else n_name + positions[i] = list(arguments.keys()).index(key) + elif param.kind == param.KEYWORD_ONLY: + # These cannot be specified by position. + positions[i] = None + else: + # positional-only argument, varargs, varkwargs or some + # unknown type: + msg = 'cannot replace argument "{}" '.format(n_name) + msg += 'of kind {}.'.format(repr(param.kind)) + raise TypeError(msg) + + @functools.wraps(function) + def wrapper(*args, **kwargs): + for i, (o_name, n_name) in enumerate(zip(old_name, new_name)): + messages = [ + '"{}" was deprecated'.format(o_name), + ] + if (since[i], until[i]) != ('', ''): + messages.append('') + if since[i]: + messages.append('* deprecated from version: ' + str(since[i])) + if until[i]: + messages.append( + '* {0} {1} as of version: {2}'.format( + 'Raises' if is_bad_version(until[i]) else 'Will raise', + error_class, + until[i], + ) + ) + messages.append('') + message = '\n'.join(messages) + + # The only way to have oldkeyword inside the function is + # that it is passed as kwarg because the oldkeyword + # parameter was renamed to newkeyword. + if o_name in kwargs: + value = kwargs.pop(o_name) + # Check if the newkeyword was given as well. + newarg_in_args = ( + positions[i] is not None and len(args) > positions[i] + ) + newarg_in_kwargs = n_name in kwargs + + if newarg_in_args or newarg_in_kwargs: + msg = 'cannot specify both "{}"'.format(o_name) + msg += ' (deprecated parameter) and ' + msg += '"{}" (new parameter name).'.format(n_name) + raise TypeError(msg) + + # Pass the value of the old argument with the + # name of the new argument to the function + key = n_name or o_name + kwargs[key] = value + + if n_name is not None: + message += '* Use argument "{}" instead.'.format(n_name) + elif alternative: + message += '* Use {} instead.'.format(alternative) + + if until[i] and is_bad_version(until[i], version_comparator): + raise error_class(message) + warnings.warn(message, warn_class, stacklevel=2) + + # Deprecated keyword without replacement is given as + # positional argument. + elif not n_name and positions[i] and len(args) > positions[i]: + if alternative: + message += '* Use {} instead.'.format(alternative) + if until[i] and is_bad_version(until[i], version_comparator): + raise error_class(message) + + warnings.warn(message, warn_class, stacklevel=2) + + return function(*args, **kwargs) + + return wrapper + + return deprecator
+ +
+
+ + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/_modules/fury/gltf.html b/v0.10.x/_modules/fury/gltf.html new file mode 100644 index 000000000..77d6343ef --- /dev/null +++ b/v0.10.x/_modules/fury/gltf.html @@ -0,0 +1,2066 @@ + + + + + + + fury.gltf — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +

Source code for fury.gltf

+# TODO: Materials, Lights
+import base64
+import copy
+import os
+from typing import Dict  # noqa
+
+import numpy as np
+import pygltflib as gltflib
+from PIL import Image
+from pygltflib.utils import glb2gltf, gltf2glb
+
+from fury import actor, io, transform, utils
+from fury.animation import Animation
+from fury.animation.interpolator import (
+    linear_interpolator,
+    slerp,
+    step_interpolator,
+    tan_cubic_spline_interpolator,
+)
+from fury.lib import Camera, Matrix4x4, Texture, Transform, numpy_support
+
+comp_type = {
+    5120: {'size': 1, 'dtype': np.byte},
+    5121: {'size': 1, 'dtype': np.ubyte},
+    5122: {'size': 2, 'dtype': np.short},
+    5123: {'size': 2, 'dtype': np.ushort},
+    5125: {'size': 4, 'dtype': np.uint},
+    5126: {'size': 4, 'dtype': np.float32},
+}
+
+acc_type = {'SCALAR': 1, 'VEC2': 2, 'VEC3': 3, 'VEC4': 4, 'MAT4': 16}
+
+
+
+[docs] +class glTF: +
+[docs] + def __init__(self, filename, apply_normals=False): + """Read and generate actors from glTF files. + + Parameters + ---------- + filename : str + Path of the gltf file + apply_normals : bool, optional + If `True` applies normals to the mesh. + + """ + if filename in ['', None]: + raise IOError('Filename cannot be empty or None!') + + name, extension = os.path.splitext(filename) + + if extension == '.glb': + fname_gltf = f'{name}.gltf' + if not os.path.exists(fname_gltf): + glb2gltf(filename) + filename = fname_gltf + + self.gltf = gltflib.GLTF2().load(filename) + + self.pwd = os.path.dirname(filename) + self.apply_normals = apply_normals + + self.cameras = {} + self.materials = [] + self.nodes = [] + self.transformations = [] + self.polydatas = [] + self.init_transform = np.identity(4) + self.node_transform = [] + self.animation_channels = {} + self.sampler_matrices = {} + + # Skinning Information + self.bone_tranforms = {} + self.keyframe_transforms = [] + self.joints_0 = [] + self.weights_0 = [] + self.bones = [] + self.ibms = {} + + self._vertices = None + self._vcopy = None + self._bvertices = {} + self._bvert_copy = {} + self.show_bones = False + + # morphing inofrmations + self.morph_vertices = [] + self.morph_weights = [] + + self.inspect_scene(0) + self._actors = [] + self._bactors = {}
+ + +
+[docs] + def actors(self): + """Generate actors from glTF file. + + Returns + ------- + actors : list + List of vtkActors with texture. + + """ + for i, polydata in enumerate(self.polydatas): + actor = utils.get_actor_from_polydata(polydata) + transform_mat = self.transformations[i] + + _transform = Transform() + _matrix = Matrix4x4() + _matrix.DeepCopy(transform_mat.ravel()) + + _transform.SetMatrix(_matrix) + actor.SetUserTransform(_transform) + + if self.materials[i] is not None: + base_col_tex = self.materials[i]['baseColorTexture'] + actor.SetTexture(base_col_tex) + base_color = self.materials[i]['baseColor'] + actor.GetProperty().SetColor(tuple(base_color[:3])) + + self._actors.append(actor) + + return self._actors
+ + +
+[docs] + def inspect_scene(self, scene_id=0): + """Loop over nodes in a scene. + + Parameters + ---------- + scene_id : int, optional + scene index of the glTF. + + """ + scene = self.gltf.scenes[scene_id] + nodes = scene.nodes + + for node_id in nodes: + self.transverse_node(node_id, self.init_transform) + for i, animation in enumerate(self.gltf.animations): + self.transverse_channels(animation, i)
+ + +
+[docs] + def transverse_node(self, nextnode_id, matrix, parent=None, is_joint=False): + """Load mesh and generates transformation matrix. + + Parameters + ---------- + nextnode_id : int + Index of the node + matrix : ndarray (4, 4) + Transformation matrix + parent : list, optional + List of indices of parent nodes + Default: None. + is_joint : Bool + To determine if the current node is a joint/bone of skins. + Default: False + + """ + node = self.gltf.nodes[nextnode_id] + if parent is None: + parent = [nextnode_id] + else: + parent.append(nextnode_id) + matnode = np.identity(4) + + if node.matrix is not None: + matnode = np.array(node.matrix) + matnode = matnode.reshape(-1, 4).T + else: + if node.translation is not None: + trans = node.translation + translate = transform.translate(trans) + matnode = np.dot(matnode, translate) + + if node.rotation is not None: + rot = node.rotation + rotate = transform.rotate(rot) + matnode = np.dot(matnode, rotate) + + if node.scale is not None: + scales = node.scale + scale = transform.scale(scales) + matnode = np.dot(matnode, scale) + + next_matrix = np.dot(matrix, matnode) + + if node.skin is not None: + if ( + nextnode_id in self.gltf.skins[0].joints + and nextnode_id not in self.bone_tranforms + ): + self.bone_tranforms[nextnode_id] = next_matrix[:] + + if is_joint: + if not (nextnode_id in self.bone_tranforms): + self.bone_tranforms[nextnode_id] = next_matrix[:] + + if node.mesh is not None: + mesh_id = node.mesh + self.load_mesh(mesh_id, next_matrix, parent) + + if node.skin is not None: + skin_id = node.skin + joints, ibms = self.get_skin_data(skin_id) + for bone, ibm in zip(joints, ibms): + self.bones.append(bone) + self.ibms[bone] = ibm + self.transverse_node(joints[0], np.identity(4), parent, is_joint=True) + + if node.camera is not None: + camera_id = node.camera + self.load_camera(camera_id, next_matrix) + + if node.children: + for child_id in node.children: + self.transverse_node(child_id, next_matrix, parent, is_joint)
+ + +
+[docs] + def load_mesh(self, mesh_id, transform_mat, parent): + """Load the mesh data from accessor and applies the transformation. + + Parameters + ---------- + mesh_id : int + Mesh index to be loaded + transform_mat : ndarray (4, 4) + Transformation matrix. + + """ + primitives = self.gltf.meshes[mesh_id].primitives + + for primitive in primitives: + + attributes = primitive.attributes + + vertices = self.get_acc_data(attributes.POSITION) + self.transformations.append(transform_mat) + + polydata = utils.PolyData() + utils.set_polydata_vertices(polydata, vertices) + + if attributes.NORMAL is not None and self.apply_normals: + normals = self.get_acc_data(attributes.NORMAL) + normals = transform.apply_transformation(normals, transform_mat) + utils.set_polydata_normals(polydata, normals) + + if attributes.TEXCOORD_0 is not None: + tcoords = self.get_acc_data(attributes.TEXCOORD_0) + utils.set_polydata_tcoords(polydata, tcoords) + + if attributes.COLOR_0 is not None: + color = self.get_acc_data(attributes.COLOR_0) + color = color[:, :-1] * 255 + utils.set_polydata_colors(polydata, color) + + if primitive.indices is not None: + indices = self.get_acc_data(primitive.indices).reshape(-1, 3) + else: + indices = np.arange(0, len(vertices)).reshape((-1, 3)) + utils.set_polydata_triangles(polydata, indices) + + if attributes.JOINTS_0 is not None: + vertex_joints = self.get_acc_data(attributes.JOINTS_0) + self.joints_0.append(vertex_joints) + vertex_weight = self.get_acc_data(attributes.WEIGHTS_0) + self.weights_0.append(vertex_weight) + + material = None + if primitive.material is not None: + material = self.get_materials(primitive.material) + + self.polydatas.append(polydata) + self.nodes.append(parent[:]) + self.materials.append(material) + + if primitive.targets is not None: + prim_morphdata = [] + for target in primitive.targets: + prim_morphdata.append(self.get_morph_data(target, mesh_id)) + self.morph_vertices.append(prim_morphdata)
+ + +
+[docs] + def get_acc_data(self, acc_id): + """Get the correct data from buffer using accessors and bufferviews. + + Parameters + ---------- + acc_id : int + Accessor index + + Returns + ------- + buffer_array : ndarray + Numpy array extracted from the buffer. + + """ + accessor = self.gltf.accessors[acc_id] + + buffview_id = accessor.bufferView + acc_byte_offset = accessor.byteOffset + count = accessor.count + d_type = comp_type.get(accessor.componentType) + d_size = d_type['size'] + a_type = acc_type.get(accessor.type) + + buffview = self.gltf.bufferViews[buffview_id] + + buff_id = buffview.buffer + byte_offset = buffview.byteOffset + byte_stride = buffview.byteStride + byte_stride = byte_stride if byte_stride else (a_type * d_size) + byte_length = count * byte_stride + + total_byte_offset = byte_offset + acc_byte_offset + + buff_array = self.get_buff_array( + buff_id, d_type['dtype'], byte_length, total_byte_offset, byte_stride + ) + return buff_array[:, :a_type]
+ + +
+[docs] + def get_buff_array(self, buff_id, d_type, byte_length, byte_offset, byte_stride): + """Extract the mesh data from buffer. + + Parameters + ---------- + buff_id : int + Buffer Index + d_type : type + Element data type + byte_length : int + The length of the buffer data + byte_offset : int + The offset into the buffer in bytes + byte_stride : int + The stride, in bytes + + Returns + ------- + out_arr : ndarray + Numpy array of size byte_length from buffer. + + """ + buffer = self.gltf.buffers[buff_id] + uri = buffer.uri + + if d_type == np.short or d_type == np.ushort or d_type == np.uint16: + byte_length = int(byte_length / 2) + byte_stride = int(byte_stride / 2) + + elif d_type == np.float32: + byte_length = int(byte_length / 4) + byte_stride = int(byte_stride / 4) + + try: + if uri.startswith('data:application/octet-stream;base64') or uri.startswith( + 'data:application/gltf-buffer;base64' + ): + buff_data = uri.split(',')[1] + buff_data = base64.b64decode(buff_data) + + elif uri.endswith('.bin'): + with open(os.path.join(self.pwd, uri), 'rb') as f: + buff_data = f.read(-1) + + out_arr = np.frombuffer( + buff_data, dtype=d_type, count=byte_length, offset=byte_offset + ) + + out_arr = out_arr.reshape(-1, byte_stride) + return out_arr + + except IOError: + print('Failed to read ! Error in opening file:')
+ + +
+[docs] + def get_materials(self, mat_id): + """Get the material data. + + Parameters + ---------- + mat_id : int + Material index + + Returns + ------- + materials : dict + Dictionary of all textures. + + """ + material = self.gltf.materials[mat_id] + bct = None + + pbr = material.pbrMetallicRoughness + + if pbr.baseColorTexture is not None: + bct = pbr.baseColorTexture.index + bct = self.get_texture(bct) + colors = pbr.baseColorFactor + return {'baseColorTexture': bct, 'baseColor': colors}
+ + +
+[docs] + def get_texture(self, tex_id): + """Read and convert image into vtk texture. + + Parameters + ---------- + tex_id : int + Texture index + + Returns + ------- + atexture : Texture + Returns flipped vtk texture from image. + + """ + texture = self.gltf.textures[tex_id].source + image = self.gltf.images[texture] + + file = image.uri + bv_index = image.bufferView + if file is None: + mimetype = image.mimeType + + if file is not None and file.startswith('data:image'): + buff_data = file.split(',')[1] + buff_data = base64.b64decode(buff_data) + + extension = '.png' if file.startswith('data:image/png') else '.jpg' + image_path = os.path.join(self.pwd, str('b64texture' + extension)) + with open(image_path, 'wb') as image_file: + image_file.write(buff_data) + + elif bv_index is not None: + bv = self.gltf.bufferViews[bv_index] + buffer = bv.buffer + bo = bv.byteOffset + bl = bv.byteLength + uri = self.gltf.buffers[buffer].uri + with open(os.path.join(self.pwd, uri), 'rb') as f: + f.seek(bo) + img_binary = f.read(bl) + extension = '.png' if mimetype == 'images/png' else '.jpg' + image_path = os.path.join(self.pwd, str('bvtexture' + extension)) + with open(image_path, 'wb') as image_file: + image_file.write(img_binary) + + else: + image_path = os.path.join(self.pwd, file) + + rgb = io.load_image(image_path) + grid = utils.rgb_to_vtk(np.flipud(rgb)) + atexture = Texture() + atexture.InterpolateOn() + atexture.EdgeClampOn() + atexture.SetInputDataObject(grid) + + return atexture
+ + +
+[docs] + def load_camera(self, camera_id, transform_mat): + """Load the camera data of a node. + + Parameters + ---------- + camera_id : int + Camera index of a node. + transform_mat : ndarray (4, 4) + Transformation matrix of the camera. + + """ + camera = self.gltf.cameras[camera_id] + vtk_cam = Camera() + position = vtk_cam.GetPosition() + position = np.asarray([position]) + + new_position = transform.apply_transformation(position, transform_mat) + vtk_cam.SetPosition(tuple(new_position[0])) + + if camera.type == 'orthographic': + orthographic = camera.orthographic + vtk_cam.ParallelProjectionOn() + zfar = orthographic.zfar + znear = orthographic.znear + vtk_cam.SetClippingRange(znear, zfar) + else: + perspective = camera.perspective + vtk_cam.ParallelProjectionOff() + zfar = perspective.zfar if perspective.zfar else 1000.0 + znear = perspective.znear + vtk_cam.SetClippingRange(znear, zfar) + angle = perspective.yfov * 180 / np.pi if perspective.yfov else 30.0 + vtk_cam.SetViewAngle(angle) + if perspective.aspectRatio: + vtk_cam.SetExplicitAspectRatio(perspective.aspectRatio) + + self.cameras[camera_id] = vtk_cam
+ + +
+[docs] + def transverse_channels(self, animation: gltflib.Animation, count: int): + """Loop over animation channels and sets animation data. + + Parameters + ---------- + animation : glTflib.Animation + pygltflib animation object. + count : int + Animation count. + + """ + name = animation.name + if name is None: + name = str(f'anim_{count}') + anim_channel = dict() # type: Dict[int, np.ndarray] + + for channel in animation.channels: + sampler = animation.samplers[channel.sampler] + node_id = channel.target.node + path = channel.target.path + anim_data = self.get_sampler_data(sampler, node_id, path) + self.node_transform.append(anim_data) + sampler_data = self.get_matrix_from_sampler( + path, node_id, anim_channel, sampler + ) + anim_channel[node_id] = sampler_data + self.animation_channels[name] = anim_channel
+ + +
+[docs] + def get_sampler_data(self, sampler: gltflib.Sampler, node_id: int, transform_type): + """Get the animation and transformation data from sampler. + + Parameters + ---------- + sampler : glTFlib.Sampler + pygltflib sampler object. + node_id : int + Node index of the current animation channel. + transform_type : str + Property of the node to be transformed. + + Returns + ------- + sampler_data : dict + dictionary of data containing timestamps, node transformations and + interpolation type. + + """ + time_array = self.get_acc_data(sampler.input) + transform_array = self.get_acc_data(sampler.output) + interpolation = sampler.interpolation + + return { + 'node': node_id, + 'input': time_array, + 'output': transform_array, + 'interpolation': interpolation, + 'property': transform_type, + }
+ + +
+[docs] + def get_matrix_from_sampler( + self, prop, node, anim_channel, sampler: gltflib.Sampler + ): + """Return transformation matrix for a given timestamp from Sampler + data. Combine matrices for a given common timestamp. + + Parameters + ---------- + prop : str + Property of the array ('translation', 'rotation' or 'scale') + node : int + Node index of the sampler data. + anim_channel : dict + Containing previous animations with node as keys. + sampler : gltflib.Sampler + Sampler object for an animation channel. + + """ + time_array = self.get_acc_data(sampler.input) + tran_array = self.get_acc_data(sampler.output) + + if prop == 'weights': + tran_array = tran_array.reshape( + -1, + ) + + tran_matrix = [] + if node in anim_channel: + prev_arr = anim_channel[node]['matrix'] + else: + prev_arr = [np.identity(4) for i in range(len(tran_array))] + + for i, arr in enumerate(tran_array): + temp = self.generate_tmatrix(arr, prop) + if temp.shape == (4, 4): + tran_matrix.append(np.dot(prev_arr[i], temp)) + else: + tran_matrix.append(temp) + data = {'timestamps': time_array, 'matrix': tran_matrix} + self.sampler_matrices[node] = data + return data
+ + +
+[docs] + def get_morph_data(self, target, mesh_id): + weights_array = self.gltf.meshes[mesh_id].weights + if target.get('POSITION') is not None: + morphed_data = self.get_acc_data(target.get('POSITION')) + self.morph_weights.append(weights_array) + return morphed_data
+ + +
+[docs] + def get_skin_data(self, skin_id): + """Get the inverse bind matrix for each bone in the skin. + + Parameters + ---------- + skin_id : int + Index of the skin. + + Returns + ------- + joint_nodes : list + List of bones in the skin. + inv_bind_matrix : ndarray + Numpy array containing inverse bind pose for each bone. + + """ + skin = self.gltf.skins[skin_id] + inv_bind_matrix = self.get_acc_data(skin.inverseBindMatrices) + inv_bind_matrix = inv_bind_matrix.reshape((-1, 4, 4)) + joint_nodes = skin.joints + return joint_nodes, inv_bind_matrix
+ + +
+[docs] + def generate_tmatrix(self, transf, prop): + """Create transformation matrix from TRS array. + + Parameters + ---------- + transf : ndarray + Array containing translation, rotation or scale values. + prop : str + String that defines the type of array + (values: translation, rotation or scale). + + Returns + ------- + matrix : ndarray (4, 4) + ransformation matrix of shape (4, 4) with respective transforms. + + """ + if prop == 'translation': + matrix = transform.translate(transf) + elif prop == 'rotation': + matrix = transform.rotate(transf) + elif prop == 'scale': + matrix = transform.scale(transf) + else: + matrix = transf + return matrix
+ + +
+[docs] + def transverse_animations( + self, + animation, + bone_id, + timestamp, + joint_matrices, + parent_bone_deform=np.identity(4), + ): + """Calculate skinning matrix (Joint Matrices) and transform bone for + each animation. + + Parameters + ---------- + animation : Animation + Animation object. + bone_id : int + Bone index of the current transform. + timestamp : float + Current timestamp of the animation. + joint_matrices : dict + Empty dictionary that will contain joint matrices. + parent_bone_transform : ndarray (4, 4) + Transformation matrix of the parent bone. + (default=np.identity(4)) + + """ + deform = animation.get_value('transform', timestamp) + new_deform = np.dot(parent_bone_deform, deform) + + ibm = self.ibms[bone_id].T + skin_matrix = np.dot(new_deform, ibm) + joint_matrices[bone_id] = skin_matrix + + node = self.gltf.nodes[bone_id] + + if self.show_bones: + actor_transform = self.transformations[0] + bone_transform = np.dot(actor_transform, new_deform) + self._bvertices[bone_id][:] = transform.apply_transformation( + self._bvert_copy[bone_id], bone_transform + ) + utils.update_actor(self._bactors[bone_id]) + + if node.children: + c_animations = animation.child_animations + c_bones = node.children + for c_anim, c_bone in zip(c_animations, c_bones): + self.transverse_animations( + c_anim, c_bone, timestamp, joint_matrices, new_deform + )
+ + +
+[docs] + def update_skin(self, animation): + """Update the animation and actors with skinning data. + + Parameters + ---------- + animation : Animation + Animation object. + + """ + animation.update_animation() + timestamp = animation.current_timestamp + joint_matrices = {} + root_bone = self.gltf.skins[0].skeleton + root_bone = root_bone if root_bone else self.bones[0] + + if not root_bone == self.bones[0]: + _animation = animation.child_animations[0] + parent_transform = self.transformations[root_bone].T + else: + _animation = animation + parent_transform = np.identity(4) + for child in _animation.child_animations: + self.transverse_animations( + child, self.bones[0], timestamp, joint_matrices, parent_transform + ) + for i, vertex in enumerate(self._vertices): + vertex[:] = self.apply_skin_matrix(self._vcopy[i], joint_matrices, i) + actor_transf = self.transformations[i] + vertex[:] = transform.apply_transformation(vertex, actor_transf) + utils.update_actor(self._actors[i]) + utils.compute_bounds(self._actors[i])
+ + +
+[docs] + def initialize_skin(self, animation, bones=False, length=0.2): + """Create bones and add to the animation and initialise `update_skin` + + Parameters + ---------- + animation : Animation + Skin animation object. + bones : bool + Switches the visibility of bones in scene. + (default=False) + length : float + Length of the bones. + (default=0.2) + + """ + self.show_bones = bones + if bones: + self.get_joint_actors(length, False) + animation.add_actor(list(self._bactors.values())) + self.update_skin(animation)
+ + +
+[docs] + def apply_skin_matrix(self, vertices, joint_matrices, actor_index=0): + """Apply the skinnig matrix, that transform the vertices. + + Parameters + ---------- + vertices : ndarray + Vertices of an actor. + join_matrices : list + List of skinning matrix to calculate the weighted transformation. + + Returns + ------- + vertices : ndarray + Modified vertices. + + """ + clone = np.copy(vertices) + weights = self.weights_0[actor_index] + joints = self.joints_0[actor_index] + + for i, xyz in enumerate(clone): + a_joint = joints[i] + a_joint = [self.bones[i] for i in a_joint] + a_weight = weights[i] + + skin_mat = ( + np.multiply(a_weight[0], joint_matrices[a_joint[0]]) + + np.multiply(a_weight[1], joint_matrices[a_joint[1]]) + + np.multiply(a_weight[2], joint_matrices[a_joint[2]]) + + np.multiply(a_weight[3], joint_matrices[a_joint[3]]) + ) + + xyz = np.dot(skin_mat, np.append(xyz, [1.0])) + clone[i] = xyz[:3] + + return clone
+ + +
+[docs] + def transverse_bones(self, bone_id, channel_name, parent_animation: Animation): + """Loop over the bones and add child bone animation to their parent + animation. + + Parameters + ---------- + bone_id : int + Index of the bone. + channel_name : str + Animation name. + parent_animation : Animation + The animation of the parent bone. Should be `root_animation` by + default. + + """ + node = self.gltf.nodes[bone_id] + animation = Animation() + if bone_id in self.bone_tranforms.keys(): + orig_transform = self.bone_tranforms[bone_id] + else: + orig_transform = np.identity(4) + if bone_id in self.animation_channels[channel_name]: + transforms = self.animation_channels[channel_name][bone_id] + timestamps = transforms['timestamps'] + metrices = transforms['matrix'] + for time, matrix in zip(timestamps, metrices): + animation.set_keyframe('transform', time[0], matrix) + else: + animation.set_keyframe('transform', 0.0, orig_transform) + + parent_animation.add(animation) + if node.children: + for child_bone in node.children: + self.transverse_bones(child_bone, channel_name, animation)
+ + +
+[docs] + def skin_animation(self): + """One animation for each bone, contains parent transforms. + + Returns + ------- + root_animations : Dict + An animation containing all the child animations for bones. + + """ + root_animations = {} + self._vertices = [utils.vertices_from_actor(act) for act in self.actors()] + self._vcopy = [np.copy(vert) for vert in self._vertices] + for name in self.animation_channels.keys(): + root_animation = Animation() + root_bone = self.gltf.skins[0].skeleton + root_bone = root_bone if root_bone else self.bones[0] + self.transverse_bones(root_bone, name, root_animation) + root_animations[name] = root_animation + root_animation.add_actor(self._actors) + return root_animations
+ + +
+[docs] + def get_joint_actors(self, length=0.5, with_transforms=False): + """Create an arrow actor for each bone in a skinned model. + + Parameters + ---------- + length : float (default = 0.5) + Length of the arrow actor + with_transforms : bool (default = False) + Applies respective transformations to bone. Bones will be at origin + if set to `False`. + + """ + origin = np.zeros((3, 3)) + parent_transforms = self.bone_tranforms + + for bone in self.bones: + arrow = actor.arrow(origin, [0, 1, 0], [1, 1, 1], scales=length) + verts = utils.vertices_from_actor(arrow) + if with_transforms: + verts[:] = transform.apply_transformation( + verts, parent_transforms[bone] + ) + utils.update_actor(arrow) + self._bactors[bone] = arrow + self._bvertices[bone] = verts + self._bvert_copy = copy.deepcopy(self._bvertices)
+ + +
+[docs] + def update_morph(self, animation): + """Update the animation and actors with morphing. + + Parameters + ---------- + animation : Animation + Animation object. + + """ + animation.update_animation() + timestamp = animation.current_timestamp + for i, vertex in enumerate(self._vertices): + weights = animation.child_animations[0].get_value('morph', timestamp) + vertex[:] = self.apply_morph_vertices(self._vcopy[i], weights, i) + vertex[:] = transform.apply_transformation(vertex, self.transformations[i]) + utils.update_actor(self._actors[i]) + utils.compute_bounds(self._actors[i])
+ + +
+[docs] + def apply_morph_vertices(self, vertices, weights, cnt): + """Calculate weighted vertex from the morph data. + + Parameters + ---------- + vertices : ndarray + Vertices of a actor. + weights : ndarray + Morphing weights used to calculate the weighted average of new + vertex. + cnt : int + Count of the actor. + + """ + clone = np.copy(vertices) + target_vertices = np.copy(self.morph_vertices[cnt]) + for i, weight in enumerate(weights): + target_vertices[i][:] = np.multiply(weight, target_vertices[i]) + new_verts = sum(target_vertices) + for i, vertex in enumerate(clone): + clone[i][:] = vertex + new_verts[i] + return clone
+ + +
+[docs] + def morph_animation(self): + """Create animation for each channel in animations. + + Returns + ------- + root_animations : Dict + A dictionary containing animations as values and animation name as + keys. + + """ + animations = {} + self._vertices = [utils.vertices_from_actor(act) for act in self.actors()] + self._vcopy = [np.copy(vert) for vert in self._vertices] + + for name, data in self.animation_channels.items(): + root_animation = Animation() + + for i, transforms in enumerate(data.values()): + weights = self.morph_weights[i] + animation = Animation() + timestamps = transforms['timestamps'] + metrices = transforms['matrix'] + metrices = np.array(metrices).reshape(-1, len(weights)) + + for time, weights in zip(timestamps, metrices): + animation.set_keyframe('morph', time[0], weights) + root_animation.add(animation) + + root_animation.add_actor(self._actors) + animations[name] = root_animation + return animations
+ + +
+[docs] + def get_animations(self): + """Return list of animations. + + Returns + ------- + animations: List + List of animations containing actors. + + """ + actors = self.actors() + interpolators = { + 'LINEAR': linear_interpolator, + 'STEP': step_interpolator, + 'CUBICSPLINE': tan_cubic_spline_interpolator, + } + + rotation_interpolators = { + 'LINEAR': slerp, + 'STEP': step_interpolator, + 'CUBICSPLINE': tan_cubic_spline_interpolator, + } + + animations = [] + for transforms in self.node_transform: + target_node = transforms['node'] + + for i, nodes in enumerate(self.nodes): + animation = Animation() + transform_mat = self.transformations[i] + position, rot, scale = transform.transform_from_matrix(transform_mat) + animation.set_keyframe('position', 0.0, position) + + if target_node in nodes: + animation.add_actor(actors[i]) + timestamp = transforms['input'] + node_transform = transforms['output'] + prop = transforms['property'] + + interpolation_type = transforms['interpolation'] + + interpolator = interpolators.get(interpolation_type) + rot_interp = rotation_interpolators.get(interpolation_type) + timeshape = timestamp.shape + transhape = node_transform.shape + if transforms['interpolation'] == 'CUBICSPLINE': + node_transform = node_transform.reshape( + (timeshape[0], -1, transhape[1]) + ) + + for time, trs in zip(timestamp, node_transform): + in_tan, out_tan = None, None + if trs.ndim == 2: + cubicspline = trs + in_tan = cubicspline[0] + trs = cubicspline[1] + out_tan = cubicspline[2] + + if prop == 'rotation': + animation.set_rotation( + time[0], trs, in_tangent=in_tan, out_tangent=out_tan + ) + animation.set_rotation_interpolator(rot_interp) + if prop == 'translation': + animation.set_position( + time[0], trs, in_tangent=in_tan, out_tangent=out_tan + ) + animation.set_position_interpolator(interpolator) + if prop == 'scale': + animation.set_scale( + time[0], trs, in_tangent=in_tan, out_tangent=out_tan + ) + animation.set_scale_interpolator(interpolator) + else: + animation.add_static_actor(actors[i]) + animations.append(animation) + return animations
+ + +
+[docs] + def main_animation(self): + """Return main animation with all glTF animations. + + Returns + ------- + main_animation : Animation + A parent animation containing all child animations for simple + animation. + + """ + main_animation = Animation() + animations = self.get_animations() + for animation in animations: + main_animation.add(animation) + return main_animation
+
+ + + +
+[docs] +def export_scene(scene, filename='default.gltf'): + """Generate gltf from FURY scene. + + Parameters + ---------- + scene: Scene + FURY scene object. + filename: str, optional + Name of the model to be saved + + """ + gltf_obj = gltflib.GLTF2() + name, extension = os.path.splitext(filename) + + if extension not in ['.gltf', '.glb']: + raise IOError('Filename should be .gltf or .glb') + + buffer_file = open(f'{name}.bin', 'wb') + primitives = [] + buffer_size = 0 + bview_count = 0 + + for act in scene.GetActors(): + prim, size, count = _connect_primitives( + gltf_obj, act, buffer_file, buffer_size, bview_count, name + ) + primitives.append(prim) + buffer_size = size + bview_count = count + + buffer_file.close() + write_mesh(gltf_obj, primitives) + write_buffer(gltf_obj, size, f'{name}.bin') + camera = scene.camera() + cam_id = None + if camera: + write_camera(gltf_obj, camera) + cam_id = 0 + write_node(gltf_obj, mesh_id=0, camera_id=cam_id) + write_scene(gltf_obj, [0]) + + gltf_obj.save(f'{name}.gltf') + if extension == '.glb': + gltf2glb(f'{name}.gltf', destination=filename)
+ + + +def _connect_primitives(gltf, actor, buff_file, byteoffset, count, name): + """Create Accessor, BufferViews and writes primitive data to a binary file + + Parameters + ---------- + gltf: Pygltflib.GLTF2 + actor: Actor + the fury actor + buff_file: file + filename.bin opened in `wb` mode + byteoffset: int + offset of the bufferview + count: int + BufferView count + name: str + Prefix of the gltf filename + + Returns + ------- + prim: Pygltflib.Primitive + byteoffset: int + Offset size of a primitive + count: int + BufferView count after adding the primitive. + + """ + polydata = actor.GetMapper().GetInput() + colors = utils.colors_from_actor(actor) + if colors is not None: + polydata = utils.set_polydata_colors(polydata, colors) + + vertices = utils.get_polydata_vertices(polydata) + colors = utils.get_polydata_colors(polydata) + normals = utils.get_polydata_normals(polydata) + tcoords = utils.get_polydata_tcoord(polydata) + try: + indices = utils.get_polydata_triangles(polydata) + except AssertionError as error: + indices = None + print(error) + + ispoints = polydata.GetNumberOfVerts() + islines = polydata.GetNumberOfLines() + istraingles = polydata.GetNumberOfPolys() + + if ispoints: + mode = 0 + elif islines: + mode = 3 + elif istraingles: + mode = 4 + + vertex, index, normal, tcoord, color = (None, None, None, None, None) + if indices is not None and len(indices) != 0: + indices = indices.reshape((-1,)) + amax = [np.max(indices)] + amin = [np.min(indices)] + + ctype = comp_type.get(gltflib.UNSIGNED_SHORT) + atype = acc_type.get(gltflib.SCALAR) + + indices = indices.astype(np.ushort) + blength = len(indices) * ctype['size'] + buff_file.write(indices.tobytes()) + write_bufferview(gltf, 0, byteoffset, blength) + write_accessor( + gltf, count, 0, gltflib.UNSIGNED_SHORT, len(indices), gltflib.SCALAR + ) + byteoffset += blength + index = count + count += 1 + + if vertices is not None: + amax = np.max(vertices, 0).tolist() + amin = np.min(vertices, 0).tolist() + + ctype = comp_type.get(gltflib.FLOAT) + atype = acc_type.get(gltflib.VEC3) + + vertices = vertices.reshape((-1,)).astype(ctype['dtype']) + blength = len(vertices) * ctype['size'] + buff_file.write(vertices.tobytes()) + write_bufferview(gltf, 0, byteoffset, blength) + write_accessor( + gltf, + count, + 0, + gltflib.FLOAT, + len(vertices) // atype, + gltflib.VEC3, + amax, + amin, + ) + byteoffset += blength + vertex = count + count += 1 + + if normals is not None: + amax = np.max(normals, 0).tolist() + amin = np.min(normals, 0).tolist() + + ctype = comp_type.get(gltflib.FLOAT) + atype = acc_type.get(gltflib.VEC3) + + normals = normals.reshape((-1,)) + blength = len(normals) * ctype['size'] + buff_file.write(normals.tobytes()) + write_bufferview(gltf, 0, byteoffset, blength) + write_accessor( + gltf, + count, + 0, + gltflib.FLOAT, + len(normals) // atype, + gltflib.VEC3, + amax, + amin, + ) + byteoffset += blength + normal = count + count += 1 + + if tcoords is not None: + amax = np.max(tcoords, 0).tolist() + amin = np.min(tcoords, 0).tolist() + + ctype = comp_type.get(gltflib.FLOAT) + atype = acc_type.get(gltflib.VEC2) + + tcoords = tcoords.reshape((-1,)).astype(ctype['dtype']) + blength = len(tcoords) * ctype['size'] + buff_file.write(tcoords.tobytes()) + write_bufferview(gltf, 0, byteoffset, blength) + write_accessor( + gltf, count, 0, gltflib.FLOAT, len(tcoords) // atype, gltflib.VEC2 + ) + byteoffset += blength + tcoord = count + count += 1 + vtk_image = actor.GetTexture().GetInput() + rows, cols, _ = vtk_image.GetDimensions() + scalars = vtk_image.GetPointData().GetScalars() + np_im = numpy_support.vtk_to_numpy(scalars) + np_im = np.reshape(np_im, (rows, cols, -1)) + + img = Image.fromarray(np_im) + image_path = f'{name}BaseColorTexture.png' + img.save(image_path) + write_material(gltf, 0, image_path) + + if colors is not None: + ctype = comp_type.get(gltflib.FLOAT) + atype = acc_type.get(gltflib.VEC3) + + shape = colors.shape[0] + colors = np.concatenate((colors, np.full((shape, 1), 255.0)), axis=1) + colors = colors / 255 + colors = colors.reshape((-1,)).astype(ctype['dtype']) + blength = len(colors) * ctype['size'] + buff_file.write(colors.tobytes()) + write_bufferview(gltf, 0, byteoffset, blength) + write_accessor(gltf, count, 0, gltflib.FLOAT, shape, gltflib.VEC4) + byteoffset += blength + color = count + count += 1 + material = None if tcoords is None else 0 + prim = get_prim(vertex, index, color, tcoord, normal, material, mode) + return prim, byteoffset, count + + +
+[docs] +def write_scene(gltf, nodes): + """Create scene + + Parameters + ---------- + gltf: GLTF2 + Pygltflib GLTF2 object + nodes: list + List of node indices. + + """ + scene = gltflib.Scene() + scene.nodes = nodes + gltf.scenes.append(scene)
+ + + +
+[docs] +def write_node(gltf, mesh_id=None, camera_id=None): + """Create node + + Parameters + ---------- + gltf: GLTF2 + Pygltflib GLTF2 object + mesh_id: int, optional + Mesh index + camera_id: int, optional + Camera index. + + """ + node = gltflib.Node() + if mesh_id is not None: + node.mesh = mesh_id + if camera_id is not None: + node.camera = camera_id + gltf.nodes.append(node)
+ + + +
+[docs] +def write_mesh(gltf, primitives): + """Create mesh and add primitive. + + Parameters + ---------- + gltf: GLTF2 + Pygltflib GLTF2 object. + primitives: list + List of Primitive object. + + """ + mesh = gltflib.Mesh() + for prim in primitives: + mesh.primitives.append(prim) + + gltf.meshes.append(mesh)
+ + + +
+[docs] +def write_camera(gltf, camera): + """Create and add camera. + + Parameters + ---------- + gltf: GLTF2 + Pygltflib GLTF2 object. + camera: vtkCamera + scene camera. + + """ + orthographic = camera.GetParallelProjection() + cam = gltflib.Camera() + if orthographic: + cam.type = 'orthographic' + else: + clip_range = camera.GetClippingRange() + angle = camera.GetViewAngle() + ratio = camera.GetExplicitAspectRatio() + aspect_ratio = ratio if ratio else 1.0 + pers = gltflib.Perspective() + pers.aspectRatio = aspect_ratio + pers.znear, pers.zfar = clip_range + pers.yfov = angle * np.pi / 180 + cam.type = 'perspective' + cam.perspective = pers + gltf.cameras.append(cam)
+ + + +
+[docs] +def get_prim(vertex, index, color, tcoord, normal, material, mode=4): + """Return a Primitive object. + + Parameters + ---------- + vertex: int + Accessor index for the vertices data. + index: int + Accessor index for the triangles data. + color: int + Accessor index for the colors data. + tcoord: int + Accessor index for the texture coordinates data. + normal: int + Accessor index for the normals data. + material: int + Materials index. + mode: int, optional + The topology type of primitives to render. + Default: 4 + + Returns + ------- + prim: Primitive + pygltflib primitive object. + + """ + prim = gltflib.Primitive() + attr = gltflib.Attributes() + attr.POSITION = vertex + attr.NORMAL = normal + attr.TEXCOORD_0 = tcoord + attr.COLOR_0 = color + prim.attributes = attr + prim.indices = index + if material is not None: + prim.material = material + prim.mode = mode + return prim
+ + + +
+[docs] +def write_material(gltf, basecolortexture: int, uri: str): + """Write Material, Images and Textures + + Parameters + ---------- + gltf: GLTF2 + Pygltflib GLTF2 object. + basecolortexture: int + BaseColorTexture index. + uri: str + BaseColorTexture uri. + + """ + material = gltflib.Material() + texture = gltflib.Texture() + image = gltflib.Image() + pbr = gltflib.PbrMetallicRoughness() + tinfo = gltflib.TextureInfo() + tinfo.index = basecolortexture + pbr.baseColorTexture = tinfo + pbr.metallicFactor = 0.0 + material.pbrMetallicRoughness = pbr + texture.source = basecolortexture + image.uri = uri + gltf.materials.append(material) + gltf.textures.append(texture) + gltf.images.append(image)
+ + + +
+[docs] +def write_accessor( + gltf, bufferview, byte_offset, comp_type, count, accssor_type, max=None, min=None +): + """Write accessor in the gltf. + + Parameters + ---------- + gltf: GLTF2 + Pygltflib GLTF2 objecomp_type + + bufferview: int + BufferView Index + byte_offset: int + ByteOffset of the accessor + comp_type: type + Type of a single component + count: int + Elements count of the accessor + accssor_type: type + Type of the accessor(SCALAR, VEC2, VEC3, VEC4) + max: ndarray, optional + Maximum elements of an array + min: ndarray, optional + Minimum elements of an array + + """ + accessor = gltflib.Accessor() + accessor.bufferView = bufferview + accessor.byteOffset = byte_offset + accessor.componentType = comp_type + accessor.count = count + accessor.type = accssor_type + if (max is not None) and (min is not None): + accessor.max = max + accessor.min = min + gltf.accessors.append(accessor)
+ + + +
+[docs] +def write_bufferview(gltf, buffer, byte_offset, byte_length, byte_stride=None): + """Write bufferview in the gltf. + + Parameters + ---------- + gltf: GLTF2 + Pygltflib GLTF2 object + buffer: int + Buffer index + byte_offset: int + Byte offset of the bufferview + byte_length: int + Byte length ie, Length of the data we want to get from + the buffer + byte_stride: int, optional + Byte stride of the bufferview. + + """ + buffer_view = gltflib.BufferView() + buffer_view.buffer = buffer + buffer_view.byteOffset = byte_offset + buffer_view.byteLength = byte_length + buffer_view.byteStride = byte_stride + gltf.bufferViews.append(buffer_view)
+ + + +
+[docs] +def write_buffer(gltf, byte_length, uri): + """Write buffer int the gltf + + Parameters + ---------- + gltf: GLTF2 + Pygltflib GLTF2 object + byte_length: int + Length of the buffer + uri: str + Path to the external `.bin` file. + + """ + buffer = gltflib.Buffer() + buffer.uri = uri + buffer.byteLength = byte_length + gltf.buffers.append(buffer)
+ +
+
+ + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/_modules/fury/io.html b/v0.10.x/_modules/fury/io.html new file mode 100644 index 000000000..3fc08a771 --- /dev/null +++ b/v0.10.x/_modules/fury/io.html @@ -0,0 +1,938 @@ + + + + + + + fury.io — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +

Source code for fury.io

+import os
+import warnings
+from tempfile import TemporaryDirectory as InTemporaryDirectory
+from urllib.request import urlretrieve
+
+import numpy as np
+from PIL import Image
+
+from fury.lib import (
+    BMPReader,
+    BMPWriter,
+    ImageData,
+    ImageFlip,
+    JPEGReader,
+    JPEGWriter,
+    MNIObjectReader,
+    MNIObjectWriter,
+    OBJReader,
+    PLYReader,
+    PLYWriter,
+    PNGReader,
+    PNGWriter,
+    PolyDataReader,
+    PolyDataWriter,
+    STLReader,
+    STLWriter,
+    Texture,
+    TIFFReader,
+    TIFFWriter,
+    XMLPolyDataReader,
+    XMLPolyDataWriter,
+    numpy_support,
+)
+from fury.utils import set_input
+
+
+
+[docs] +def load_cubemap_texture(fnames, interpolate_on=True, mipmap_on=True): + """Load a cube map texture from a list of 6 images. + + Parameters + ---------- + fnames : list of strings + List of 6 filenames with bmp, jpg, jpeg, png, tif or tiff extensions. + interpolate_on : bool, optional + mipmap_on : bool, optional + + Returns + ------- + output : vtkTexture + Cube map texture. + + """ + if len(fnames) != 6: + raise IOError('Expected 6 filenames, got {}'.format(len(fnames))) + texture = Texture() + texture.CubeMapOn() + for idx, fn in enumerate(fnames): + if not os.path.isfile(fn): + raise FileNotFoundError(fn) + else: + # Read the images + vtk_img = load_image(fn, as_vtktype=True) + # Flip the image horizontally + img_flip = ImageFlip() + img_flip.SetInputData(vtk_img) + img_flip.SetFilteredAxis(1) # flip y axis + img_flip.Update() + # Add the image to the cube map + texture.SetInputDataObject(idx, img_flip.GetOutput()) + if interpolate_on: + texture.InterpolateOn() + if mipmap_on: + texture.MipmapOn() + return texture
+ + + +
+[docs] +def load_image(filename, as_vtktype=False, use_pillow=True): + """Load an image. + + Parameters + ---------- + filename: str + should be png, bmp, jpeg or jpg files + as_vtktype: bool, optional + if True, return vtk output otherwise an ndarray. Default False. + use_pillow: bool, optional + Use pillow python library to load the files. Default True + + Returns + ------- + image: ndarray or vtk output + desired image array + + """ + is_url = filename.lower().startswith('http://') or filename.lower().startswith( + 'https://' + ) + + if is_url: + image_name = os.path.basename(filename) + + if len(image_name.split('.')) < 2: + raise IOError(f'{filename} is not a valid image URL') + + urlretrieve(filename, image_name) + filename = image_name + + if use_pillow: + with Image.open(filename) as pil_image: + if pil_image.mode in ['P']: + pil_image = pil_image.convert('RGB') + + if pil_image.mode in ['RGBA', 'RGB', 'L']: + image = np.asarray(pil_image) + elif pil_image.mode.startswith('I;16'): + raw = pil_image.tobytes('raw', pil_image.mode) + dtype = '>u2' if pil_image.mode.endswith('B') else '<u2' + image = np.frombuffer(raw, dtype=dtype) + image.reshape(pil_image.size[::-1]).astype('=u2') + else: + try: + image = pil_image.convert('RGBA') + except ValueError: + raise RuntimeError('Unknown image mode {}'.format(pil_image.mode)) + image = np.asarray(pil_image) + + if as_vtktype: + if image.ndim not in [2, 3]: + raise IOError('only 2D (L, RGB, RGBA) or 3D image available') + + vtk_image = ImageData() + depth = 1 if image.ndim == 2 else image.shape[2] + + # width, height + vtk_image.SetDimensions(image.shape[1], image.shape[0], depth) + vtk_image.SetExtent(0, image.shape[1] - 1, 0, image.shape[0] - 1, 0, 0) + vtk_image.SetSpacing(1.0, 1.0, 1.0) + vtk_image.SetOrigin(0.0, 0.0, 0.0) + + image = np.flipud(image) + image = image.reshape(image.shape[1] * image.shape[0], depth) + image = np.ascontiguousarray(image, dtype=image.dtype) + vtk_array_type = numpy_support.get_vtk_array_type(image.dtype) + uchar_array = numpy_support.numpy_to_vtk( + image, deep=True, array_type=vtk_array_type + ) + vtk_image.GetPointData().SetScalars(uchar_array) + image = vtk_image + + if is_url: + os.remove(filename) + return image + + d_reader = { + '.png': PNGReader, + '.bmp': BMPReader, + '.jpeg': JPEGReader, + '.jpg': JPEGReader, + '.tiff': TIFFReader, + '.tif': TIFFReader, + } + + extension = os.path.splitext(os.path.basename(filename).lower())[1] + + if extension.lower() not in d_reader.keys(): + raise IOError( + 'Impossible to read the file {0}: Unknown extension {1}'.format( + filename, extension + ) + ) + + reader = d_reader.get(extension)() + reader.SetFileName(filename) + reader.Update() + reader.GetOutput().GetPointData().GetArray(0).SetName('original') + + if not as_vtktype: + w, h, _ = reader.GetOutput().GetDimensions() + vtk_array = reader.GetOutput().GetPointData().GetScalars() + + components = vtk_array.GetNumberOfComponents() + image = numpy_support.vtk_to_numpy(vtk_array).reshape(h, w, components) + image = np.flipud(image) + + if is_url: + os.remove(filename) + return reader.GetOutput() if as_vtktype else image
+ + + +
+[docs] +def load_text(file): + """Load a text file. + + Parameters + ---------- + file: str + Path to the text file. + + Returns + ------- + text: str + Text contained in the file. + + """ + if not os.path.isfile(file): + raise IOError('File {} does not exist.'.format(file)) + with open(file) as f: + text = f.read() + return text
+ + + +
+[docs] +def save_image( + arr, + filename, + compression_quality=75, + compression_type='deflation', + use_pillow=True, + dpi=(72, 72), +): + """Save a 2d or 3d image. + + Expect an image with the following shape: (H, W) or (H, W, 1) or + (H, W, 3) or (H, W, 4). + + Parameters + ---------- + arr : ndarray + array to save + filename : string + should be png, bmp, jpeg or jpg files + compression_quality : int, optional + compression_quality for jpeg data. + 0 = Low quality, 100 = High quality + compression_type : str, optional + compression type for tiff file + select between: None, lzw, deflation (default) + use_pillow : bool, optional + Use imageio python library to save the files. + dpi : float or (float, float) + Dots per inch (dpi) for saved image. + Single values are applied as dpi for both dimensions. + + """ + if arr.ndim > 3: + raise IOError('Image Dimensions should be <=3') + + if isinstance(dpi, (float, int)): + dpi = (dpi, dpi) + + d_writer = { + '.png': PNGWriter, + '.bmp': BMPWriter, + '.jpeg': JPEGWriter, + '.jpg': JPEGWriter, + '.tiff': TIFFWriter, + '.tif': TIFFWriter, + } + + extension = os.path.splitext(os.path.basename(filename).lower())[1] + + if extension.lower() not in d_writer.keys(): + raise IOError( + 'Impossible to save the file {0}: Unknown extension {1}'.format( + filename, extension + ) + ) + + if use_pillow: + im = Image.fromarray(arr) + im.save(filename, quality=compression_quality, dpi=dpi) + else: + warnings.warn(UserWarning('DPI value is ignored while saving images via vtk.')) + if arr.ndim == 2: + arr = arr[..., None] + + shape = arr.shape + arr = np.flipud(arr) + if extension.lower() in [ + '.png', + ]: + arr = arr.astype(np.uint8) + arr = arr.reshape((shape[1] * shape[0], shape[2])) + arr = np.ascontiguousarray(arr, dtype=arr.dtype) + vtk_array_type = numpy_support.get_vtk_array_type(arr.dtype) + vtk_array = numpy_support.numpy_to_vtk( + num_array=arr, deep=True, array_type=vtk_array_type + ) + + # Todo, look the following link for managing png 16bit + # https://stackoverflow.com/questions/15667947/vtkpngwriter-printing-out-black-images + vtk_data = ImageData() + vtk_data.SetDimensions(shape[1], shape[0], shape[2]) + vtk_data.SetExtent(0, shape[1] - 1, 0, shape[0] - 1, 0, 0) + vtk_data.SetSpacing(1.0, 1.0, 1.0) + vtk_data.SetOrigin(0.0, 0.0, 0.0) + vtk_data.GetPointData().SetScalars(vtk_array) + + writer = d_writer.get(extension)() + writer.SetFileName(filename) + writer.SetInputData(vtk_data) + if extension.lower() in ['.jpg', '.jpeg']: + writer.ProgressiveOn() + writer.SetQuality(compression_quality) + if extension.lower() in ['.tif', '.tiff']: + compression_type = compression_type or 'nocompression' + l_compression = ['nocompression', 'packbits', 'jpeg', 'deflate', 'lzw'] + + if compression_type.lower() in l_compression: + comp_id = l_compression.index(compression_type.lower()) + writer.SetCompression(comp_id) + else: + writer.SetCompressionToDeflate() + writer.Write()
+ + + +
+[docs] +def load_polydata(file_name): + """Load a vtk polydata to a supported format file. + + Supported file formats are VTK, VTP, FIB, PLY, STL XML and OBJ + + Parameters + ---------- + file_name : string + + Returns + ------- + output : vtkPolyData + + """ + # Check if file actually exists + if not os.path.isfile(file_name): + raise FileNotFoundError(file_name) + + file_extension = file_name.split('.')[-1].lower() + + poly_reader = { + 'vtk': PolyDataReader, + 'vtp': XMLPolyDataReader, + 'fib': PolyDataReader, + 'ply': PLYReader, + 'stl': STLReader, + 'xml': XMLPolyDataReader, + } + + if file_extension in poly_reader.keys(): + reader = poly_reader.get(file_extension)() + elif file_extension == 'obj': + # Special case, since there is two obj format + reader = OBJReader() + reader.SetFileName(file_name) + reader.Update() + if reader.GetOutput().GetNumberOfCells() == 0: + reader = MNIObjectReader() + else: + raise IOError('.' + file_extension + ' is not supported by FURY') + + reader.SetFileName(file_name) + reader.Update() + return reader.GetOutput()
+ + + +
+[docs] +def save_polydata(polydata, file_name, binary=False, color_array_name=None): + """Save a vtk polydata to a supported format file. + + Save formats can be VTK, FIB, PLY, STL and XML. + + Parameters + ---------- + polydata : vtkPolyData + file_name : string + binary : bool + color_array_name: ndarray + + """ + # get file extension (type) + file_extension = file_name.split('.')[-1].lower() + poly_writer = { + 'vtk': PolyDataWriter, + 'vtp': XMLPolyDataWriter, + 'fib': PolyDataWriter, + 'ply': PLYWriter, + 'stl': STLWriter, + 'xml': XMLPolyDataWriter, + } + + if file_extension in poly_writer.keys(): + writer = poly_writer.get(file_extension)() + elif file_extension == 'obj': + # Special case, since there is two obj format + find_keyword = file_name.lower().split('.') + if 'mni' in find_keyword or 'mnc' in find_keyword: + writer = MNIObjectWriter() + else: + raise IOError( + 'Wavefront obj requires a scene \n' + " for MNI obj, use '.mni.obj' extension" + ) + else: + raise IOError('.' + file_extension + ' is not supported by FURY') + + writer.SetFileName(file_name) + writer = set_input(writer, polydata) + if color_array_name is not None and file_extension == 'ply': + writer.SetArrayName(color_array_name) + + if binary: + writer.SetFileTypeToBinary() + writer.Update() + writer.Write()
+ + + +
+[docs] +def load_sprite_sheet(sheet_path, nb_rows, nb_cols, as_vtktype=False): + """Process and load sprites from a sprite sheet. + + Parameters + ---------- + sheet_path: str + Path to the sprite sheet + nb_rows: int + Number of rows in the sprite sheet + nb_cols: int + Number of columns in the sprite sheet + as_vtktype: bool, optional + If True, the output is a vtkImageData + + Returns + ------- + Dict containing the processed sprites. + + """ + sprite_dicts = {} + sprite_sheet = load_image(sheet_path) + width, height = sprite_sheet.shape[:2] + + sprite_size_x = int(np.ceil(width / nb_rows)) + sprite_size_y = int(np.ceil(height / nb_cols)) + + for row, col in np.ndindex((nb_rows, nb_cols)): + nxt_row = row + 1 + nxt_col = col + 1 + + box = ( + row * sprite_size_x, + col * sprite_size_y, + nxt_row * sprite_size_x, + nxt_col * sprite_size_y, + ) + + sprite_arr = sprite_sheet[box[0] : box[2], box[1] : box[3]] + if as_vtktype: + with InTemporaryDirectory() as tdir: + tmp_img_path = os.path.join(tdir, f'{row}{col}.png') + save_image(sprite_arr, tmp_img_path, compression_quality=100) + + sprite_dicts[(row, col)] = load_image(tmp_img_path, as_vtktype=True) + else: + sprite_dicts[(row, col)] = sprite_arr + + return sprite_dicts
+ +
+
+ + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/_modules/fury/layout.html b/v0.10.x/_modules/fury/layout.html new file mode 100644 index 000000000..ff4a022d2 --- /dev/null +++ b/v0.10.x/_modules/fury/layout.html @@ -0,0 +1,1080 @@ + + + + + + + fury.layout — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +

Source code for fury.layout

+import math
+
+import numpy as np
+
+from fury.utils import get_bounding_box_sizes, get_grid_cells_position, is_ui
+
+
+
+[docs] +class Layout: + """Provide functionalities for laying out actors in a 3D scene.""" + +
+[docs] + def apply(self, actors): + """Position the actors according to a certain layout.""" + positions = self.compute_positions(actors) + + for a, pos in zip(actors, positions): + + if is_ui(a): + a.position = (pos[0], pos[1]) + else: + anchor = np.array(getattr(a, 'anchor', (0, 0, 0))) + a.AddPosition(pos - (np.array(a.GetCenter()) + anchor))
+ + +
+[docs] + def compute_positions(self, _actors): + """Compute the 3D coordinates of some actors.""" + return []
+
+ + + +
+[docs] +class GridLayout(Layout): + """Provide functionalities for laying out actors in a 2D grid fashion. + + The `GridLayout` class lays the actors in a 2D structured grid aligned + with the xy-plane. + + """ + +
+[docs] + def __init__( + self, + cell_padding=0, + cell_shape='rect', + aspect_ratio=16 / 9.0, + dim=None, + position_offset=(0, 0, 0), + ): + """Initialize the grid layout. + Parameters + ---------- + cell_padding : 2-tuple of float or float (optional) + Each grid cell will be padded according to (pad_x, pad_y) i.e. + horizontally and vertically. Padding is evenly distributed on each + side of the cell. If a single float is provided then both pad_x and + pad_y will have the same value. + cell_shape : {'rect', 'square', 'diagonal'} (optional) + Specifies the desired shape of every grid cell. + 'rect' ensures the cells are the tightest. + 'square' ensures the cells are as wide as high. + 'diagonal' ensures the content of the cells can be rotated without + colliding with content of the neighboring cells. + aspect_ratio : float (optional) + Aspect ratio of the grid (width/height). Default: 16:9. + dim : tuple of int (optional) + Dimension (nb_rows, nb_cols) of the grid. If provided, + `aspect_ratio` will be ignored. + position_offset: tuple (optional) + Offset the grid by some factor + + """ + self.cell_shape = cell_shape + self.aspect_ratio = aspect_ratio + self.dim = dim + self.position_offset = position_offset + if isinstance(cell_padding, int): + self.cell_padding = (cell_padding, cell_padding) + else: + self.cell_padding = cell_padding
+ + +
+[docs] + def get_cells_shape(self, actors): + """Get the 2D shape (on the xy-plane) of some actors according to + `self.cell_shape`. + + Parameters + ---------- + actors : list of `vtkProp3D` objects + Actors from which to calculate the 2D shape. + + Returns + ------- + list of 2-tuple + The 2D shape (on the xy-plane) of every actors. + + """ + if self.cell_shape == 'rect': + bounding_box_sizes = np.asarray(list(map(self.compute_sizes, actors))) + cell_shape = np.max(bounding_box_sizes, axis=0)[:2] + shapes = [cell_shape] * len(actors) + elif self.cell_shape == 'square': + bounding_box_sizes = np.asarray(list(map(self.compute_sizes, actors))) + cell_shape = np.max(bounding_box_sizes, axis=0)[:2] + shapes = [(max(cell_shape),) * 2] * len(actors) + elif self.cell_shape == 'diagonal': + # Size of every cell corresponds to the diagonal + # of the largest bounding box. + diagonals = [] + for a in actors: + if is_ui(a): + width, height = a.size + diagonal = math.sqrt(width**2 + height**2) + diagonals.append(diagonal) + else: + diagonals.append(a.GetLength()) + + longest_diagonal = np.max(diagonals) + shapes = [(longest_diagonal, longest_diagonal)] * len(actors) + else: + raise ValueError("Unknown cell shape: '{0}'".format(self.cell_shape)) + + return shapes
+ + +
+[docs] + def compute_positions(self, actors): + """Compute the 3D coordinates of some actors. + The coordinates will lie on the xy-plane and form a 2D grid. + + Parameters + ---------- + actors : list of `vtkProp3D` objects + Actors to be layout in a grid manner. + + Returns + ------- + list of 3-tuple + The computed 3D coordinates of every actors. + + """ + shapes = self.get_cells_shape(actors) + + # Add padding, if any, around every cell. + shapes = [np.array(self.cell_padding) / 2.0 + s for s in shapes] + positions = get_grid_cells_position(shapes, self.aspect_ratio, self.dim) + + positions += self.position_offset + return positions
+ + +
+[docs] + def compute_sizes(self, actor): + """Compute the bounding box size of the actor/UI element + + Parameters + ---------- + actor: `vtkProp3D` or `UI` element + Actor/UI element whose size is to be calculated + + Returns + ------- + bounding box sizes: tuple + + """ + if is_ui(actor): + width, height = actor.size + return (width, height, 0) + + return get_bounding_box_sizes(actor)
+
+ + + +
+[docs] +class HorizontalLayout(GridLayout): + """Provide functionalities for laying out actors in a horizontal layout.""" + +
+[docs] + def __init__(self, cell_padding=0, cell_shape='rect'): + """Initialize the Horizontal layout. + + Parameters + ---------- + cell_padding : 2-tuple of float or float (optional) + Each grid cell will be padded according to (pad_x, pad_y) i.e. + horizontally and vertically. Padding is evenly distributed on each + side of the cell. If a single float is provided then both pad_x and + pad_y will have the same value. + cell_shape : {'rect', 'square', 'diagonal'} (optional) + Specifies the desired shape of every grid cell. + 'rect' ensures the cells are the tightest. + 'square' ensures the cells are as wide as high. + 'diagonal' ensures the content of the cells can be rotated without + colliding with content of the neighboring cells. + + """ + super(HorizontalLayout, self).__init__( + cell_padding=cell_padding, cell_shape=cell_shape + )
+ + +
+[docs] + def compute_positions(self, actors): + """Compute the 3D coordinates of some actors. + The coordinates will lie on the xy-plane and form a horizontal stack. + + Parameters + ---------- + actors : list of `vtkProp3D` objects + Actors to be layout in a horizontal fashion. + + Returns + ------- + list of 3-tuple + The computed 3D coordinates of every actors. + + """ + positions = [ + np.asarray([0, 0, 0]), + ] + shapes = self.get_cells_shape(actors[1:]) + + # Add padding, if any, around every cell. + shapes = [np.array(self.cell_padding) / 2.0 + s for s in shapes] + + for shape in shapes: + actor_position = positions[-1] + np.asarray([shape[0], 0, 0]) + positions.append(actor_position) + + return positions
+
+ + + +
+[docs] +class VerticalLayout(GridLayout): + """Provide functionalities for laying out actors in a vertical stack.""" + +
+[docs] + def __init__(self, cell_padding=0, cell_shape='rect'): + """Initialize the Vertical layout. + + Parameters + ---------- + cell_padding : 2-tuple of float or float (optional) + Each cell will be padded according to (pad_x, pad_y) i.e. + horizontally and vertically. Padding is evenly distributed on each + side of the cell. If a single float is provided then both pad_x and + pad_y will have the same value. + cell_shape : {'rect', 'square', 'diagonal'} (optional) + Specifies the desired shape of every cell. + 'rect' ensures the cells are the tightest. + 'square' ensures the cells are as wide as high. + 'diagonal' ensures the content of the cells can be rotated without + colliding with content of the neighboring cells. + + """ + super(VerticalLayout, self).__init__( + cell_padding=cell_padding, cell_shape=cell_shape + )
+ + +
+[docs] + def compute_positions(self, actors): + """Compute the 3D coordinates of some actors. + + Parameters + ---------- + actors : list of `vtkProp3D` objects + Actors to be layout in a vertical stack. + + Returns + ------- + list of 3-tuple + The computed 3D coordinates of every actors. + + """ + positions = [ + np.asarray([0, 0, 0]), + ] + shapes = self.get_cells_shape(actors[1:]) + + # Add padding, if any, around every cell. + shapes = [np.array(self.cell_padding) / 2.0 + s for s in shapes] + + for shape in shapes: + actor_position = positions[-1] + np.asarray([0, shape[1], 0]) + positions.append(actor_position) + + return positions
+
+ + + +
+[docs] +class XLayout(HorizontalLayout): + """Provide functionalities for laying out actors along x-axis.""" + +
+[docs] + def __init__(self, direction='x+', cell_padding=0, cell_shape='rect'): + """Initialize the X layout. + + Parameters + ---------- + direction: str, optional + The direction of layout. + 'x+' means actors will be placed along positive x-axis. + 'x-' means actors will be placed along negative x-axis. + cell_padding : 2-tuple of float or float (optional) + Each cell will be padded according to (pad_x, pad_y) i.e. + horizontally and vertically. Padding is evenly distributed on each + side of the cell. If a single float is provided then both pad_x and + pad_y will have the same value. + cell_shape : {'rect', 'square', 'diagonal'} (optional) + Specifies the desired shape of every cell. + 'rect' ensures the cells are the tightest. + 'square' ensures the cells are as wide as high. + 'diagonal' ensures the content of the cells can be rotated without + colliding with content of the neighboring cells. + + """ + self.direction = direction.lower() + + if self.direction not in ['x+', 'x-']: + raise ValueError(f'{direction} is not a valid direction') + + super(XLayout, self).__init__(cell_padding=cell_padding, cell_shape=cell_shape)
+ + +
+[docs] + def get_cells_shape(self, actors): + """Get the 2D shape (on the xy-plane) of some actors according to + `self.cell_shape`. + + Parameters + ---------- + actors : list of `vtkProp3D` objects + Actors from which to calculate the 2D shape. + + Returns + ------- + list of 2-tuple + The 2D shape (on the xy-plane) of every actors. + + """ + if self.direction == 'x-': + actors = actors[::-1] + + return super().get_cells_shape(actors)
+ + +
+[docs] + def compute_positions(self, actors): + """Compute the 3D coordinates of some actors. + + The coordinates will lie on the xy-plane and + will be placed along x-axis. + + Parameters + ---------- + actors : list of `vtkProp3D` objects + Actors to be layout along the x-axis. + + Returns + ------- + list of 3-tuple + The computed 3D coordinates of every actors. + + """ + if self.direction == 'x-': + actors = actors[::-1] + + return super().compute_positions(actors)
+ + +
+[docs] + def apply(self, actors): + """Position the actors according to a certain layout.""" + if self.direction == 'x-': + actors = actors[::-1] + + return super().apply(actors)
+
+ + + +
+[docs] +class YLayout(VerticalLayout): + """Provide functionalities for laying out actors along y-axis.""" + +
+[docs] + def __init__(self, direction='y+', cell_padding=0, cell_shape='rect'): + """Initialize the Y layout. + + Parameters + ---------- + direction: str, optional + The direction of layout. + 'y+' means actors will be placed along positive y-axis. + 'y-' means actors will be placed along negative y-axis. + cell_padding : 2-tuple of float or float (optional) + Each cell will be padded according to (pad_x, pad_y) i.e. + horizontally and vertically. Padding is evenly distributed on each + side of the cell. If a single float is provided then both pad_x and + pad_y will have the same value. + cell_shape : {'rect', 'square', 'diagonal'} (optional) + Specifies the desired shape of every cell. + 'rect' ensures the cells are the tightest. + 'square' ensures the cells are as wide as high. + 'diagonal' ensures the content of the cells can be rotated without + colliding with content of the neighboring cells. + + """ + self.direction = direction.lower() + + if self.direction not in ['y+', 'y-']: + raise ValueError(f'{direction} is not a valid direction') + + super(YLayout, self).__init__(cell_padding=cell_padding, cell_shape=cell_shape)
+ + +
+[docs] + def get_cells_shape(self, actors): + """Get the 2D shape (on the xy-plane) of some actors according to + `self.cell_shape`. + + Parameters + ---------- + actors : list of `vtkProp3D` objects + Actors from which to calculate the 2D shape. + + Returns + ------- + list of 2-tuple + The 2D shape (on the xy-plane) of every actors. + + """ + if self.direction == 'y-': + actors = actors[::-1] + + return super().get_cells_shape(actors)
+ + +
+[docs] + def compute_positions(self, actors): + """Compute the 3D coordinates of some actors. + + The coordinates will lie on the xy-plane and + will be placed along y-axis. + + Parameters + ---------- + actors : list of `vtkProp3D` objects + Actors to be layout along the y-axis. + + Returns + ------- + list of 3-tuple + The computed 3D coordinates of every actors. + + """ + if self.direction == 'y-': + actors = actors[::-1] + + return super().compute_positions(actors)
+ + +
+[docs] + def apply(self, actors): + """Position the actors according to a certain layout.""" + if self.direction == 'y-': + actors = actors[::-1] + + return super().apply(actors)
+
+ + + +
+[docs] +class ZLayout(GridLayout): + """Provide functionalities for laying out actors along z-axis.""" + +
+[docs] + def __init__(self, direction='z+', cell_padding=0, cell_shape='rect'): + """Initialize the Z layout. + + Parameters + ---------- + direction: str, optional + The direction of layout. + 'z+' means actors will be placed along positive z-axis. + 'z-' means actors will be placed along negative z-axis. + cell_padding : 2-tuple of float or float (optional) + Each cell will be padded according to (pad_x, pad_y) i.e. + horizontally and vertically. Padding is evenly distributed on each + side of the cell. If a single float is provided then both pad_x and + pad_y will have the same value. + cell_shape : {'rect', 'square', 'diagonal'} (optional) + Specifies the desired shape of every cell. + 'rect' ensures the cells are the tightest. + 'square' ensures the cells are as wide as high. + 'diagonal' ensures the content of the cells can be rotated without + colliding with content of the neighboring cells. + + """ + self.direction = direction.lower() + + if self.direction not in ['z+', 'z-']: + raise ValueError(f'{direction} is not a valid direction') + + super(ZLayout, self).__init__(cell_padding=cell_padding, cell_shape=cell_shape)
+ + +
+[docs] + def get_cells_shape(self, actors): + """Get the shape (on the z-plane) of some actors according to + `self.cell_shape`. + + Parameters + ---------- + actors : list of `vtkProp3D` objects + Actors from which to calculate the shape. + + Returns + ------- + list of floats + The shape (on the z-plane) of every actors. + + """ + if self.direction == 'z-': + actors = actors[::-1] + + if self.cell_shape == 'rect' or self.cell_shape == 'square': + bounding_box_sizes = np.asarray(list(map(get_bounding_box_sizes, actors))) + cell_shape = np.max(bounding_box_sizes, axis=0)[2] + shapes = [cell_shape] * len(actors) + elif self.cell_shape == 'diagonal': + # Size of every cell corresponds to the diagonal + # of the largest bounding box. + longest_diagonal = np.max([a.GetLength() for a in actors]) + shapes = [longest_diagonal] * len(actors) + else: + raise ValueError("Unknown cell shape: '{0}'".format(self.cell_shape)) + + return shapes
+ + +
+[docs] + def compute_positions(self, actors): + """Compute the 3D coordinates of some actors. + + Parameters + ---------- + actors : list of `vtkProp3D` objects + Actors to be layout along the z-axis. + + Returns + ------- + list of 3-tuple + The computed 3D coordinates of every actors. + + """ + if self.direction == 'z-': + actors = actors[::-1] + + positions = [ + np.asarray([0, 0, 0]), + ] + shapes = self.get_cells_shape(actors[1:]) + # Add padding, if any, around every cell. + shapes = [np.array(self.cell_padding) / 2.0 + s for s in shapes] + + for shape in shapes: + actor_position = positions[-1] + np.asarray([0, 0, shape[0]]) + positions.append(actor_position) + + return positions
+ + +
+[docs] + def apply(self, actors): + """Position the actors according to a certain layout.""" + if self.direction == 'z-': + actors = actors[::-1] + + return super().apply(actors)
+
+ +
+
+ + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/_modules/fury/material.html b/v0.10.x/_modules/fury/material.html new file mode 100644 index 000000000..ed481c44a --- /dev/null +++ b/v0.10.x/_modules/fury/material.html @@ -0,0 +1,1026 @@ + + + + + + + fury.material — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +

Source code for fury.material

+import os
+import warnings
+
+from fury.lib import VTK_OBJECT, calldata_type
+from fury.shaders import (
+    add_shader_callback,
+    compose_shader,
+    import_fury_shader,
+    shader_to_actor,
+)
+
+
+class __PBRParams:
+    """Helper class to manage PBR parameters.
+
+    Attributes
+    ----------
+    actor_properties : vtkProperty
+        The actor properties.
+
+    Parameters
+    ----------
+    metallic : float
+        Metallic or non-metallic (dielectric) shading computation value. Values
+        must be between 0.0 and 1.0.
+    roughness : float
+        Parameter used to specify how glossy the actor should be. Values must
+        be between 0.0 and 1.0.
+    anisotropy : float
+        Isotropic or anisotropic material parameter. Values must be between
+        0.0 and 1.0.
+    anisotropy_rotation : float
+        Rotation of the anisotropy around the normal in a counter-clockwise
+        fashion. Values must be between 0.0 and 1.0. A value of 1.0 means a
+        rotation of 2 * pi.
+    coat_strength : float
+        Strength of the coat layer. Values must be between 0.0 and 1.0 (0.0
+        means no clear coat will be modeled).
+    coat_roughness : float
+        Roughness of the coat layer. Values must be between 0.0 and 1.0.
+    base_ior : float
+        Index of refraction of the base material. Default is 1.5. Values must
+        be between 1.0 and 2.3.
+    coat_ior : float
+        Index of refraction of the coat material. Default is 1.5. Values must
+        be between 1.0 and 2.3.
+
+    """
+
+    def __init__(self, actor_properties, metallic, roughness,
+                 anisotropy, anisotropy_rotation, coat_strength,
+                 coat_roughness, base_ior, coat_ior):
+        self.__actor_properties = actor_properties
+        self.__actor_properties.SetMetallic(metallic)
+        self.__actor_properties.SetRoughness(roughness)
+        self.__actor_properties.SetAnisotropy(anisotropy)
+        self.__actor_properties.SetAnisotropyRotation(
+            anisotropy_rotation)
+        self.__actor_properties.SetCoatStrength(coat_strength)
+        self.__actor_properties.SetCoatRoughness(coat_roughness)
+        self.__actor_properties.SetBaseIOR(base_ior)
+        self.__actor_properties.SetCoatIOR(coat_ior)
+
+    @property
+    def metallic(self):
+        return self.__actor_properties.GetMetallic()
+
+    @metallic.setter
+    def metallic(self, metallic):
+        self.__actor_properties.SetMetallic(metallic)
+
+    @property
+    def roughness(self):
+        return self.__actor_properties.GetRoughness()
+
+    @roughness.setter
+    def roughness(self, roughness):
+        self.__actor_properties.SetRoughness(roughness)
+
+    @property
+    def anisotropy(self):
+        return self.__actor_properties.GetAnisotropy()
+
+    @anisotropy.setter
+    def anisotropy(self, anisotropy):
+        self.__actor_properties.SetAnisotropy(anisotropy)
+
+    @property
+    def anisotropy_rotation(self):
+        return self.__actor_properties.GetAnisotropyRotation()
+
+    @anisotropy_rotation.setter
+    def anisotropy_rotation(self, anisotropy_rotation):
+        self.__actor_properties.SetAnisotropyRotation(anisotropy_rotation)
+
+    @property
+    def coat_strength(self):
+        return self.__actor_properties.GetCoatStrength()
+
+    @coat_strength.setter
+    def coat_strength(self, coat_strength):
+        self.__actor_properties.SetCoatStrength(coat_strength)
+
+    @property
+    def coat_roughness(self):
+        return self.__actor_properties.GetCoatRoughness()
+
+    @coat_roughness.setter
+    def coat_roughness(self, coat_roughness):
+        self.__actor_properties.SetCoatRoughness(coat_roughness)
+
+    @property
+    def base_ior(self):
+        return self.__actor_properties.GetBaseIOR()
+
+    @base_ior.setter
+    def base_ior(self, base_ior):
+        self.__actor_properties.SetBaseIOR(base_ior)
+
+    @property
+    def coat_ior(self):
+        return self.__actor_properties.GetCoatIOR()
+
+    @coat_ior.setter
+    def coat_ior(self, coat_ior):
+        self.__actor_properties.SetCoatIOR(coat_ior)
+
+
+
+[docs] +def manifest_pbr(actor, metallic=0, roughness=.5, anisotropy=0, + anisotropy_rotation=0, coat_strength=0, coat_roughness=0, + base_ior=1.5, coat_ior=2): + """Apply VTK's Physically Based Rendering properties to the selected actor. + + Parameters + ---------- + actor : actor + metallic : float, optional + Metallic or non-metallic (dielectric) shading computation value. Values + must be between 0.0 and 1.0. + roughness : float, optional + Parameter used to specify how glossy the actor should be. Values must + be between 0.0 and 1.0. + anisotropy : float, optional + Isotropic or anisotropic material parameter. Values must be between + 0.0 and 1.0. + anisotropy_rotation : float, optional + Rotation of the anisotropy around the normal in a counter-clockwise + fashion. Values must be between 0.0 and 1.0. A value of 1.0 means a + rotation of 2 * pi. + coat_strength : float, optional + Strength of the coat layer. Values must be between 0.0 and 1.0 (0.0 + means no clear coat will be modeled). + coat_roughness : float, optional + Roughness of the coat layer. Values must be between 0.0 and 1.0. + base_ior : float, optional + Index of refraction of the base material. Default is 1.5. Values must + be between 1.0 and 2.3. + coat_ior : float, optional + Index of refraction of the coat material. Default is 1.5. Values must + be between 1.0 and 2.3. + + """ + try: + prop = actor.GetProperty() + try: + prop.SetInterpolationToPBR() + pbr_params = __PBRParams(prop, metallic, roughness, anisotropy, + anisotropy_rotation, coat_strength, + coat_roughness, base_ior, coat_ior) + return pbr_params + except AttributeError: + warnings.warn( + 'PBR interpolation cannot be applied to this actor. The ' + 'material will not be applied.') + return None + except AttributeError: + warnings.warn('Actor does not have the attribute property. This ' + 'material will not be applied.') + return None
+ + + +
+[docs] +def manifest_principled(actor, subsurface=0, metallic=0, specular=0, + specular_tint=0, roughness=0, anisotropic=0, + anisotropic_direction=[0, 1, .5], sheen=0, + sheen_tint=0, clearcoat=0, clearcoat_gloss=0): + """Apply the Principled Shading properties to the selected actor. + + Parameters + ---------- + actor : actor + subsurface : float, optional + Subsurface scattering computation value. Values must be between 0.0 and + 1.0. + metallic : float, optional + Metallic or non-metallic (dielectric) shading computation value. Values + must be between 0.0 and 1.0. + specular : float, optional + Specular lighting coefficient. Value must be between 0.0 and 1.0. + specular_tint : float, optional + Specular tint coefficient value. Values must be between 0.0 and 1.0. + roughness : float, optional + Parameter used to specify how glossy the actor should be. Values must + be between 0.0 and 1.0. + anisotropic : float, optional + Anisotropy coefficient. Values must be between 0.0 and 1.0. + anisotropic_direction : list, optional + Anisotropy direction where X, Y and Z should be in the range [-1, 1]. + sheen : float, optional + Sheen coefficient. Values must be between 0.0 and 1.0. + sheen_tint : float, optional + Sheen tint coefficient value. Values must be between 0.0 and 1.0. + clearcoat : float, optional + Clearcoat coefficient. Values must be between 0.0 and 1.0. + clearcoat_gloss : float, optional + Clearcoat gloss coefficient value. Values must be between 0.0 and 1.0. + + Returns + ------- + principled_params : dict + Dictionary containing the Principled Shading parameters. + + """ + try: + prop = actor.GetProperty() + + principled_params = { + 'subsurface': subsurface, 'metallic': metallic, + 'specular': specular, 'specular_tint': specular_tint, + 'roughness': roughness, 'anisotropic': anisotropic, + 'anisotropic_direction': anisotropic_direction, 'sheen': sheen, + 'sheen_tint': sheen_tint, 'clearcoat': clearcoat, + 'clearcoat_gloss': clearcoat_gloss + } + + prop.SetSpecular(specular) + + @calldata_type(VTK_OBJECT) + def uniforms_callback(_caller, _event, calldata=None): + if calldata is not None: + calldata.SetUniformf( + 'subsurface', principled_params['subsurface']) + calldata.SetUniformf( + 'metallic', principled_params['metallic']) + calldata.SetUniformf( + 'specularTint', principled_params['specular_tint']) + calldata.SetUniformf( + 'roughness', principled_params['roughness']) + calldata.SetUniformf( + 'anisotropic', principled_params['anisotropic']) + calldata.SetUniformf('sheen', principled_params['sheen']) + calldata.SetUniformf( + 'sheenTint', principled_params['sheen_tint']) + calldata.SetUniformf( + 'clearcoat', principled_params['clearcoat']) + calldata.SetUniformf( + 'clearcoatGloss', principled_params['clearcoat_gloss']) + + calldata.SetUniform3f( + 'anisotropicDirection', principled_params[ + 'anisotropic_direction']) + + add_shader_callback(actor, uniforms_callback) + + # Start of shader implementation + + # Adding required constants + pi = '#define PI 3.14159265359' + + # Adding uniforms + uniforms = """ + uniform float subsurface; + uniform float metallic; + uniform float specularTint; + uniform float roughness; + uniform float anisotropic; + uniform float sheen; + uniform float sheenTint; + uniform float clearcoat; + uniform float clearcoatGloss; + + uniform vec3 anisotropicDirection; + """ + + # Importing functions in order + + # Importing utility functions + square = import_fury_shader(os.path.join('utils', 'square.glsl')) + pow5 = import_fury_shader(os.path.join('utils', 'pow5.glsl')) + + # Importing utility function to update the tangent and bitangent + # vectors given a direction of anisotropy + update_tan_bitan = import_fury_shader( + os.path.join('utils', 'update_tan_bitan.glsl') + ) + + # Importing color conversion gamma to linear space function + gamma_to_linear = import_fury_shader( + os.path.join('lighting', 'gamma_to_linear.frag') + ) + + # Importing color conversion linear to gamma space function + linear_to_gamma = import_fury_shader( + os.path.join('lighting', 'linear_to_gamma.frag') + ) + + # Importing linear-space CIE luminance tint approximation function + cie_color_tint = import_fury_shader( + os.path.join('lighting', 'cie_color_tint.frag') + ) + + # Importing Schlick's weight approximation of the Fresnel equation + schlick_weight = import_fury_shader( + os.path.join('lighting', 'schlick_weight.frag') + ) + + # Importing Normal Distribution Function (NDF): Generalized + # Trowbridge-Reitz with param gamma=1 (D_{GTR_1}) needed for the Clear + # Coat lobe + gtr1 = import_fury_shader( + os.path.join('lighting', 'ndf', 'gtr1.frag') + ) + + # Importing Normal Distribution Function (NDF): Generalized + # Trowbridge-Reitz with param gamma=2 (D_{GTR_2}) needed for the + # Isotropic Specular lobe + gtr2 = import_fury_shader( + os.path.join('lighting', 'ndf', 'gtr2.frag') + ) + + # Importing Normal Distribution Function (NDF): Anisotropic form of the + # Generalized Trowbridge-Reitz with param gamma=2 + # (D_{GTR_2anisotropic}) needed for the respective Specular lobe + gtr2_anisotropic = import_fury_shader( + os.path.join('lighting', 'ndf', 'gtr2_anisotropic.frag') + ) + + # Importing Geometry Shadowing and Masking Function (GF): Smith Ground + # Glass Unknown (G_{GGX}) needed for the Isotropic Specular and Clear + # Coat lobes + smith_ggx = import_fury_shader( + os.path.join('lighting', 'gf', 'smith_ggx.frag') + ) + + # Importing Geometry Shadowing and Masking Function (GF): Anisotropic + # form of the Smith Ground Glass Unknown (G_{GGXanisotropic}) needed + # for the respective Specular lobe + smith_ggx_anisotropic = import_fury_shader( + os.path.join('lighting', 'gf', 'smith_ggx_anisotropic.frag') + ) + + # Importing Principled components functions + diffuse = import_fury_shader( + os.path.join('lighting', 'principled', 'diffuse.frag') + ) + subsurface = import_fury_shader( + os.path.join('lighting', 'principled', 'subsurface.frag') + ) + sheen = import_fury_shader( + os.path.join('lighting', 'principled', 'sheen.frag') + ) + specular_isotropic = import_fury_shader( + os.path.join('lighting', 'principled', 'specular_isotropic.frag') + ) + specular_anisotropic = import_fury_shader( + os.path.join('lighting', 'principled', 'specular_anisotropic.frag') + ) + clearcoat = import_fury_shader( + os.path.join('lighting', 'principled', 'clearcoat.frag') + ) + + # Putting all the functions together before passing them to the actor + fs_dec = compose_shader([ + pi, uniforms, square, pow5, update_tan_bitan, gamma_to_linear, + linear_to_gamma, cie_color_tint, schlick_weight, gtr1, gtr2, + gtr2_anisotropic, smith_ggx, smith_ggx_anisotropic, diffuse, + subsurface, sheen, specular_isotropic, specular_anisotropic, + clearcoat + ]) + + # Adding shader functions to actor + shader_to_actor(actor, 'fragment', decl_code=fs_dec) + + # Start of the implementation code + start_comment = "//Disney's Principled BRDF" + + # Preparing vectors and values + normal = 'vec3 normal = normalVCVSOutput;' + # VTK's default system is retroreflective, which means view = light + view = 'vec3 view = normalize(-vertexVC.xyz);' + # Since VTK's default setup is retroreflective we only need to + # calculate one single dot product + dot_n_v = 'float dotNV = clamp(dot(normal, view), 1e-5, 1);' + + dot_n_v_validation = """ + if(dotNV < 0) + fragOutput0 = vec4(vec3(0), opacity); + """ + + # To work with anisotropic distributions is necessary to have a tangent + # and bitangent vector per point on the surface + tangent = 'vec3 tangent = vec3(.0);' + bitangent = 'vec3 bitangent = vec3(.0);' + # The shader function updateTanBitan aligns tangents and bitangents + # according to a direction of anisotropy + update_aniso_vecs = """ + updateTanBitan(normal, anisotropicDirection, tangent, bitangent); + """ + + # Calculating dot products with tangent and bitangent + dot_t_v = 'float dotTV = dot(tangent, view);' + dot_b_v = 'float dotBV = dot(bitangent, view);' + + # Converting color to linear space + linear_color = 'vec3 linColor = gamma2Linear(diffuseColor);' + + # Calculating linear-space CIE luminance tint approximation + tint = 'vec3 tint = calculateTint(linColor);' + + # Since VTK's default setup is retroreflective we only need to + # calculate one single Schlick's weight + fsw = 'float fsw = schlickWeight(dotNV);' + + # Calculating the diffuse coefficient + diff_coeff = """ + float diffCoeff = evaluateDiffuse(roughness, fsw, fsw, dotNV); + """ + + # Calculating the subsurface coefficient + subsurf_coeff = """ + float subsurfCoeff = evaluateSubsurface(roughness, fsw, fsw, dotNV, + dotNV, dotNV); + """ + + # Calculating the sheen irradiance + sheen_rad = """ + vec3 sheenRad = evaluateSheen(sheen, sheenTint, tint, fsw); + """ + + # Calculating the specular irradiance + spec_rad = """ + vec3 specRad = evaluateSpecularAnisotropic(specularIntensity, + specularTint, metallic, anisotropic, roughness, tint, linColor, + fsw, dotNV, dotTV, dotBV, dotNV, dotTV, dotBV, dotNV, dotTV, + dotBV); + """ + + # Calculating the clear coat coefficient + clear_coat_coef = """ + float coatCoeff = evaluateClearcoat(clearcoat, clearcoatGloss, fsw, + dotNV, dotNV, dotNV); + """ + + # Starting to put all together + # Initializing the radiance vector + radiance = 'vec3 rad = (1 / PI) * linColor;' + # Adding mix between the diffuse and the subsurface coefficients + # controlled by the subsurface parameter + diff_subsurf_mix = 'rad *= mix(diffCoeff, subsurfCoeff, subsurface);' + # Adding sheen radiance + sheen_add = 'rad += sheenRad;' + # Balancing energy using metallic + metallic_balance = 'rad *= (1 - metallic);' + # Adding specular radiance + specular_add = 'rad += specRad;' + # Adding clear coat coefficient + clearcoat_add = 'rad += coatCoeff;' + + # Initializing the color vector using the final radiance and VTK's + # additional information + color = 'vec3 color = rad * lightColor0;' + # Converting color back to gamma space + gamma_color = 'color = linear2Gamma(color);' + # Clamping color values + color_clamp = 'color = clamp(color, vec3(0), vec3(1));' + + # Fragment shader output + frag_output = 'fragOutput0 = vec4(color, opacity);' + + # Putting all the implementation together before passing it to the + # actor + fs_impl = compose_shader([ + start_comment, normal, view, dot_n_v, dot_n_v_validation, tangent, + bitangent, update_aniso_vecs, dot_t_v, dot_b_v, linear_color, tint, + fsw, diff_coeff, subsurf_coeff, sheen_rad, spec_rad, + clear_coat_coef, radiance, diff_subsurf_mix, sheen_add, + metallic_balance, specular_add, clearcoat_add, color, gamma_color, + color_clamp, frag_output + ]) + + # Adding shader implementation to actor + shader_to_actor(actor, 'fragment', impl_code=fs_impl, block='light') + + return principled_params + except AttributeError: + warnings.warn('Actor does not have the attribute property. This ' + 'material will not be applied.') + return None
+ + + +
+[docs] +def manifest_standard(actor, ambient_level=0, ambient_color=(1, 1, 1), + diffuse_level=1, diffuse_color=(1, 1, 1), + specular_level=0, specular_color=(1, 1, 1), + specular_power=1, interpolation='gouraud'): + """Apply the standard material to the selected actor. + + Parameters + ---------- + actor : actor + ambient_level : float, optional + Ambient lighting coefficient. Value must be between 0.0 and 1.0. + ambient_color : tuple (3,), optional + Ambient RGB color where R, G and B should be in the range [0, 1]. + diffuse_level : float, optional + Diffuse lighting coefficient. Value must be between 0.0 and 1.0. + diffuse_color : tuple (3,), optional + Diffuse RGB color where R, G and B should be in the range [0, 1]. + specular_level : float, optional + Specular lighting coefficient. Value must be between 0.0 and 1.0. + specular_color : tuple (3,), optional + Specular RGB color where R, G and B should be in the range [0, 1]. + specular_power : float, optional + Parameter used to specify the intensity of the specular reflection. + Value must be between 0.0 and 128.0. + interpolation : string, optional + If 'flat', the actor will be shaded using flat interpolation. If + 'gouraud' (default), then the shading will be calculated at the + vertex level. If 'phong', then the shading will be calculated at the + fragment level. + + """ + try: + prop = actor.GetProperty() + + interpolation = interpolation.lower() + + if interpolation == 'flat': + prop.SetInterpolationToFlat() + elif interpolation == 'gouraud': + prop.SetInterpolationToGouraud() + elif interpolation == 'phong': + prop.SetInterpolationToPhong() + else: + message = 'Unknown interpolation. Ignoring "{}" interpolation ' \ + 'option and using the default ("{}") option.' + message = message.format(interpolation, 'gouraud') + warnings.warn(message) + + prop.SetAmbient(ambient_level) + prop.SetAmbientColor(ambient_color) + prop.SetDiffuse(diffuse_level) + prop.SetDiffuseColor(diffuse_color) + prop.SetSpecular(specular_level) + prop.SetSpecularColor(specular_color) + prop.SetSpecularPower(specular_power) + except AttributeError: + warnings.warn('Actor does not have the attribute property. This ' + 'material will not be applied.') + return
+ +
+
+ + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/_modules/fury/molecular.html b/v0.10.x/_modules/fury/molecular.html new file mode 100644 index 000000000..da8c77891 --- /dev/null +++ b/v0.10.x/_modules/fury/molecular.html @@ -0,0 +1,1372 @@ + + + + + + + fury.molecular — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +

Source code for fury.molecular

+"""Module that provides molecular visualization tools."""
+
+import warnings
+
+import numpy as np
+
+from fury.actor import streamtube
+from fury.lib import (
+    VTK_FLOAT,
+    VTK_ID_TYPE,
+    VTK_UNSIGNED_CHAR,
+    VTK_UNSIGNED_INT,
+    VTK_UNSIGNED_SHORT,
+    Actor,
+    DataSetAttributes,
+)
+from fury.lib import Molecule as Mol
+from fury.lib import (
+    OpenGLMoleculeMapper,
+    PeriodicTable,
+    PolyData,
+    PolyDataMapper,
+    ProteinRibbonFilter,
+    SimpleBondPerceiver,
+    StringArray,
+)
+from fury.lib import numpy_support as nps
+from fury.utils import numpy_to_vtk_points
+
+
+
+[docs] +class Molecule(Mol): + """Your molecule class. + + An object that is used to create molecules and store molecular data (e.g. + coordinate and bonding data). + This is a more pythonic version of ``Molecule``. + """ + +
+[docs] + def __init__( + self, + atomic_numbers=None, + coords=None, + atom_names=None, + model=None, + residue_seq=None, + chain=None, + sheet=None, + helix=None, + is_hetatm=None, + ): + """Send the atomic data to the molecule. + + Parameters + ---------- + atomic_numbers : ndarray of integers, optional + The shape of the array must be (N, ) where N is the total number of + atoms present in the molecule. + Array having atomic number corresponding to each atom of the + molecule. + coords : ndarray of floats, optional + The shape of the array must be (N, 3) where N is the total number + of atoms present in the molecule. + Array having coordinates corresponding to each atom of the + molecule. + atom_names : ndarray of strings, optional + The shape of the array must be (N, ) where N is the total number of + atoms present in the molecule. + Array having the names of atoms. + model : ndarray of integers, optional + The shape of the array must be (N, ) where N is the total number of + atoms present in the molecule. + Array having the model number corresponding to each atom. + residue_seq : ndarray of integers, optional + The shape of the array must be (N, ) where N is the total number of + atoms present in the molecule. + Array having the residue sequence number corresponding to each atom + of the molecule. + chain : ndarray of integers, optional + The shape of the array must be (N, ) where N is the total number of + atoms present in the molecule. + Array having the chain number corresponding to each atom. + sheet : ndarray of integers, optional + The shape of the array must be (S, 4) where S is the total number + of sheets present in the molecule. + Array containing information about sheets present in the molecule. + helix : ndarray of integers, optional + The shape of the array must be (H, 4) where H is the total number + of helices present in the molecule. + Array containing information about helices present in the molecule. + is_hetatm : ndarray of bools, optional + The shape of the array must be (N, ) where N is the total number of + atoms present in the molecule. + Array containing a bool value to indicate if an atom is a + heteroatom. + + """ + if atomic_numbers is None and coords is None: + self.Initialize() + elif not isinstance(atomic_numbers, np.ndarray) or not isinstance( + coords, np.ndarray + ): + raise ValueError('atom_types and coords must be numpy arrays.') + elif len(atomic_numbers) == len(coords): + self.atom_names = atom_names + self.model = model + self.residue_seq = residue_seq + self.chain = chain + self.sheet = sheet + self.helix = helix + self.is_hetatm = is_hetatm + coords = numpy_to_vtk_points(coords) + atom_nums = nps.numpy_to_vtk(atomic_numbers, array_type=VTK_UNSIGNED_SHORT) + atom_nums.SetName('Atomic Numbers') + fieldData = DataSetAttributes() + fieldData.AddArray(atom_nums) + self.Initialize(coords, fieldData) + else: + n1 = len(coords) + n2 = len(atomic_numbers) + raise ValueError( + 'Mismatch in length of atomic_numbers({0}) and ' + 'length of atomic_coords({1}).'.format(n1, n2) + )
+ + + @property + def total_num_atoms(self): + """Return the total number of atoms in a given molecule.""" + return self.GetNumberOfAtoms() + + @property + def total_num_bonds(self): + """Return the total number of bonds in a given molecule.""" + return self.GetNumberOfBonds()
+ + + +
+[docs] +def add_atom(molecule, atomic_num, x_coord, y_coord, z_coord): + """Add atomic data to our molecule. + + Parameters + ---------- + molecule : Molecule + The molecule to which the atom is to be added. + atomic_num : int + Atomic number of the atom. + x_coord : float + x-coordinate of the atom. + y_coord : float + y-coordinate of the atom. + z_coord : float + z-coordinate of the atom. + + """ + molecule.AppendAtom(atomic_num, x_coord, y_coord, z_coord)
+ + + +
+[docs] +def add_bond(molecule, atom1_index, atom2_index, bond_order=1): + """Add bonding data to our molecule. Establish a bond of type bond_order + between the atom at atom1_index and the atom at atom2_index. + + Parameters + ---------- + molecule : Molecule + The molecule to which the bond is to be added. + atom1_index : int + Index of the first atom. + atom2_index : int + Index of the second atom. + bond_order : int (optional) + Bond order (whether it's a single/double/triple bond). Default: 1 + + Notes + ----- + Ensure that the total number of bonds between two atoms doesn't exceed 3. + Calling ``add_bond`` to add bonds between atoms that already have a triple + bond between them leads to erratic behavior and must be avoided. + + """ + molecule.AppendBond(atom1_index, atom2_index, bond_order)
+ + + +
+[docs] +def get_atomic_number(molecule, atom_index): + """Get the atomic number of an atom for a specified index. + + Returns the atomic number of the atom present at index atom_index. + + Parameters + ---------- + molecule : Molecule + The molecule to which the atom belongs. + atom_index : int + Index of the atom whose atomic number is to be obtained. + + """ + return molecule.GetAtomAtomicNumber(atom_index)
+ + + +
+[docs] +def set_atomic_number(molecule, atom_index, atomic_num): + """Set the atomic number of an atom for a specified index. + + Assign atomic_num as the atomic number of the atom present at + atom_index. + + Parameters + ---------- + molecule : Molecule + The molecule to which the atom belongs. + atom_index : int + Index of the atom to whom the atomic number is to be assigned. + atom_num : int + Atomic number to be assigned to the atom. + + """ + molecule.SetAtomAtomicNumber(atom_index, atomic_num)
+ + + +
+[docs] +def get_atomic_position(molecule, atom_index): + """Get the atomic coordinates of an atom for a specified index. + + Returns the atomic coordinates of the atom present at index atom_index. + + Parameters + ---------- + molecule : Molecule + The molecule to which the atom belongs. + atom_index : int + Index of the atom whose atomic coordinates are to be obtained. + + """ + return molecule.GetAtomPosition(atom_index)
+ + + +
+[docs] +def set_atomic_position(molecule, atom_index, x_coord, y_coord, z_coord): + """Set the atomic coordinates of an atom for a specified index. + + Assign atom_coordinate to the coordinates of the atom present at + atom_index. + + Parameters + ---------- + molecule : Molecule + The molecule to which the atom belongs. + atom_index : int + Index of the atom to which the coordinates are to be assigned. + x_coord : float + x-coordinate of the atom. + y_coord : float + y-coordinate of the atom. + z_coord : float + z-coordinate of the atom. + + """ + molecule.SetAtomPosition(atom_index, x_coord, y_coord, z_coord)
+ + + +
+[docs] +def get_bond_order(molecule, bond_index): + """Get the order of bond for a specified index. + + Returns the order of bond (whether it's a single/double/triple bond) + present at bond_index. + + Parameters + ---------- + molecule : Molecule + The molecule to which the bond belongs. + bond_index : int + Index of the bond whose order is to be obtained. + + """ + return molecule.GetBondOrder(bond_index)
+ + + +
+[docs] +def set_bond_order(molecule, bond_index, bond_order): + """Set the bond order of a bond for a specified index. + + Assign bond_order (whether it's a single/double/triple bond) to the bond + present at the bond_index. + + Parameters + ---------- + molecule : Molecule + The molecule to which the bond belongs. + bond_index : int + Index of the bond whose order is to be assigned. + bond_order : int + Bond order (whether it's a single/double/triple bond). + + """ + return molecule.SetBondOrder(bond_index, bond_order)
+ + + +
+[docs] +def get_all_atomic_numbers(molecule): + """Return an array of atomic numbers corresponding to the atoms + present in a given molecule. + + Parameters + ---------- + molecule : Molecule + The molecule whose atomic number array is to be obtained. + + """ + return nps.vtk_to_numpy(molecule.GetAtomicNumberArray())
+ + + +
+[docs] +def get_all_bond_orders(molecule): + """Return an array of integers containing the bond orders (single/double/ + triple) corresponding to the bonds present in the molecule. + + Parameters + ---------- + molecule : Molecule + The molecule whose bond types array is to be obtained. + + """ + return nps.vtk_to_numpy(molecule.GetBondOrdersArray())
+ + + +
+[docs] +def get_all_atomic_positions(molecule): + """Return an array of atomic coordinates corresponding to the atoms + present in the molecule. + + Parameters + ---------- + molecule : Molecule + The molecule whose atomic position array is to be obtained. + + """ + return nps.vtk_to_numpy(molecule.GetAtomicPositionArray().GetData())
+ + + +
+[docs] +def deep_copy_molecule(molecule1, molecule2): + """Deep copies the atomic information (atoms and bonds) from molecule2 into + molecule1. + + Parameters + ---------- + molecule1 : Molecule + The molecule to which the atomic information is copied. + molecule2 : Molecule + The molecule from which the atomic information is copied. + + """ + molecule1.DeepCopyStructure(molecule2)
+ + + +
+[docs] +def compute_bonding(molecule): + """Uses `vtkSimpleBondPerceiver` to generate bonding information for a + molecule. + `vtkSimpleBondPerceiver` performs a simple check of all interatomic + distances and adds a single bond between atoms that are reasonably + close. If the interatomic distance is less than the sum of the two + atom's covalent radii plus a tolerance, a single bond is added. + + Parameters + ---------- + molecule : Molecule + The molecule for which bonding information is to be generated. + + Notes + ----- + This algorithm does not consider valences, hybridization, aromaticity, + or anything other than atomic separations. It will not produce anything + other than single bonds. + + """ + bonder = SimpleBondPerceiver() + bonder.SetInputData(molecule) + bonder.SetTolerance(0.1) + bonder.Update() + deep_copy_molecule(molecule, bonder.GetOutput())
+ + + +
+[docs] +class PTable(PeriodicTable): + """A class to obtain properties of elements (eg: Covalent Radius, + Van Der Waals Radius, Symbol etc.). + + This is a more pythonic version of ``vtkPeriodicTable`` providing simple + methods to access atomic properties. It provides access to essential + functionality available in ``vtkPeriodicTable``. An object of this class + provides access to atomic information sourced from Blue Obelisk Data + Repository. + """ + +
+[docs] + def atomic_symbol(self, atomic_number): + """Given an atomic number, returns the symbol associated with the + element. + + Parameters + ---------- + atomic_number : int + Atomic number of the element whose symbol is to be obtained. + + """ + return self.GetSymbol(atomic_number)
+ + +
+[docs] + def element_name(self, atomic_number): + """Given an atomic number, returns the name of the element. + + Parameters + ---------- + atomic_number : int + Atomic number of the element whose name is to be obtained. + + """ + return self.GetElementName(atomic_number)
+ + +
+[docs] + def atomic_number(self, element_name): + """Given a case-insensitive string that contains the symbol or name of + an element, return the corresponding atomic number. + + Parameters + ---------- + element_name : string + Name of the element whose atomic number is to be obtained. + + """ + return self.GetAtomicNumber(element_name)
+ + +
+[docs] + def atomic_radius(self, atomic_number, radius_type='VDW'): + """Given an atomic number, return either the covalent radius of the + atom (in Å) or return the Van Der Waals radius (in Å) of the atom + depending on radius_type. + + Parameters + ---------- + atomic_number : int + Atomic number of the element whose atomic radius is to be obtained. + radius_type : string + Type of atomic radius to be obtained. Two valid choices: + + * 'VDW' : for Van der Waals radius of the atom + * 'Covalent' : for covalent radius of the atom + + Default: 'VDW' + + """ + radius_type = radius_type.lower() + if radius_type == 'vdw': + return self.GetVDWRadius(atomic_number) + elif radius_type == 'covalent': + return self.GetCovalentRadius(atomic_number) + else: + raise ValueError( + 'Incorrect radius_type specified. Please choose' + ' from "VDW" or "Covalent".' + )
+ + +
+[docs] + def atom_color(self, atomic_number): + """Given an atomic number, return the RGB tuple associated with that + element (CPK coloring convention) provided by the Blue Obelisk Data + Repository. + + Parameters + ---------- + atomicNumber : int + Atomic number of the element whose RGB tuple is to be obtained. + + """ + rgb = np.array(self.GetDefaultRGBTuple(atomic_number)) + return rgb
+
+ + + +
+[docs] +def sphere_cpk(molecule, colormode='discrete'): + """Create an actor for sphere molecular representation. It's also referred + to as CPK model and space-filling model. + + Parameters + ---------- + molecule : Molecule + The molecule to be rendered. + colormode : string, optional + Set the colormode for coloring the atoms. Two valid color modes: + + * 'discrete': Atoms are colored using CPK coloring convention. + * 'single': All atoms are colored with same color (grey). RGB tuple + used for coloring the atoms when 'single' colormode is selected: + (150, 150, 150). + + Default: 'discrete' + + Returns + ------- + molecule_actor : vtkActor + Actor created to render the space filling representation of the + molecule to be visualized. + + References + ---------- + Corey R.B.; Pauling L. Molecular Models of Amino Acids, + Peptides, and Proteins + `Review of Scientific Instruments 1953, 24 (8), 621-627. + <https://doi.org/10.1063/1.1770803>`_ + + """ + colormode = colormode.lower() + msp_mapper = OpenGLMoleculeMapper() + msp_mapper.SetInputData(molecule) + msp_mapper.SetRenderAtoms(True) + msp_mapper.SetRenderBonds(False) + msp_mapper.SetAtomicRadiusTypeToVDWRadius() + msp_mapper.SetAtomicRadiusScaleFactor(1) + if colormode == 'discrete': + msp_mapper.SetAtomColorMode(1) + elif colormode == 'single': + msp_mapper.SetAtomColorMode(0) + else: + msp_mapper.SetAtomColorMode(1) + warnings.warn('Incorrect colormode specified! Using discrete.') + + # To-Do manipulate shading properties to make it look aesthetic + molecule_actor = Actor() + molecule_actor.SetMapper(msp_mapper) + return molecule_actor
+ + + +
+[docs] +def ball_stick( + molecule, + colormode='discrete', + atom_scale_factor=0.3, + bond_thickness=0.1, + multiple_bonds=True, +): + """Create an actor for ball and stick molecular representation. + + Parameters + ---------- + molecule : Molecule + The molecule to be rendered. + colormode : string, optional + Set the colormode for coloring the atoms. Two valid color modes: + + * 'discrete': Atoms and bonds are colored using CPK coloring + convention. + * 'single': All atoms are colored with same color (grey) and all bonds + are colored with same color (dark grey). RGB tuple used for coloring + the atoms when 'single' colormode is selected: (150, 150, 150). RGB + tuple used for coloring the bonds when 'single' colormode is + selected: (50, 50, 50) + + Default: 'discrete' + atom_scale_factor : float, optional + Scaling factor. Default: 0.3 + bond_thickness : float, optional + Used to manipulate the thickness of bonds (i.e. thickness of tubes + which are used to render bonds) + Default: 0.1 (Optimal range: 0.1 - 0.5). + multiple_bonds : bool, optional + Set whether multiple tubes will be used to represent multiple + bonds. If True, multiple bonds (double, triple) will be shown by using + multiple tubes. If False, all bonds (single, double, triple) will be + shown as single bonds (i.e. shown using one tube each). + Default is True. + + Returns + ------- + molecule_actor : vtkActor + Actor created to render the ball and stick representation of the + molecule to be visualized. + + References + ---------- + Turner, M. Ball and stick models for organic chemistry + `J. Chem. Educ. 1971, 48, 6, 407. + <https://doi.org/10.1021/ed048p407>`_ + + """ + if molecule.total_num_bonds == 0: + raise ValueError( + 'No bonding data available for the molecule! Ball ' + 'and stick model cannot be made!' + ) + colormode = colormode.lower() + bs_mapper = OpenGLMoleculeMapper() + bs_mapper.SetInputData(molecule) + bs_mapper.SetRenderAtoms(True) + bs_mapper.SetRenderBonds(True) + bs_mapper.SetBondRadius(bond_thickness) + bs_mapper.SetAtomicRadiusTypeToVDWRadius() + bs_mapper.SetAtomicRadiusScaleFactor(atom_scale_factor) + if multiple_bonds: + bs_mapper.SetUseMultiCylindersForBonds(1) + else: + bs_mapper.SetUseMultiCylindersForBonds(0) + if colormode == 'discrete': + bs_mapper.SetAtomColorMode(1) + bs_mapper.SetBondColorMode(1) + elif colormode == 'single': + bs_mapper.SetAtomColorMode(0) + bs_mapper.SetBondColorMode(0) + else: + bs_mapper.SetAtomColorMode(1) + warnings.warn('Incorrect colormode specified! Using discrete.') + molecule_actor = Actor() + molecule_actor.SetMapper(bs_mapper) + return molecule_actor
+ + + +
+[docs] +def stick(molecule, colormode='discrete', bond_thickness=0.1): + """Create an actor for stick molecular representation. + + Parameters + ---------- + molecule : Molecule + The molecule to be rendered. + colormode : string, optional + Set the colormode for coloring the bonds. Two valid color modes: + + * 'discrete': Bonds are colored using CPK coloring convention. + * 'single': All bonds are colored with the same color (dark grey) + RGB tuple used for coloring the bonds when 'single' colormode is + selected: (50, 50, 50) + + Default: 'discrete' + + bond_thickness : float, optional + Used to manipulate the thickness of bonds (i.e. thickness of tubes + which are used to render bonds). + Default: 0.1 (Optimal range: 0.1 - 0.5). + + Returns + ------- + molecule_actor : vtkActor + Actor created to render the stick representation of the molecule to be + visualized. + + """ + if molecule.total_num_bonds == 0: + raise ValueError( + 'No bonding data available for the molecule! Stick ' 'model cannot be made!' + ) + colormode = colormode.lower() + mst_mapper = OpenGLMoleculeMapper() + mst_mapper.SetInputData(molecule) + mst_mapper.SetRenderAtoms(True) + mst_mapper.SetRenderBonds(True) + mst_mapper.SetBondRadius(bond_thickness) + mst_mapper.SetAtomicRadiusTypeToUnitRadius() + mst_mapper.SetAtomicRadiusScaleFactor(bond_thickness) + if colormode == 'discrete': + mst_mapper.SetAtomColorMode(1) + mst_mapper.SetBondColorMode(1) + elif colormode == 'single': + mst_mapper.SetAtomColorMode(0) + mst_mapper.SetBondColorMode(0) + else: + mst_mapper.SetAtomColorMode(1) + warnings.warn('Incorrect colormode specified! Using discrete.') + molecule_actor = Actor() + molecule_actor.SetMapper(mst_mapper) + return molecule_actor
+ + + +
+[docs] +def ribbon(molecule): + """Create an actor for ribbon molecular representation. + + Parameters + ---------- + molecule : Molecule + The molecule to be rendered. + + Returns + ------- + molecule_actor : vtkActor + Actor created to render the rubbon representation of the molecule to be + visualized. + + References + ---------- + Richardson, J.S. The anatomy and taxonomy of protein structure + `Advances in Protein Chemistry, 1981, 34, 167-339. + <https://doi.org/10.1016/S0065-3233(08)60520-3>`_ + + """ + coords = get_all_atomic_positions(molecule) + all_atomic_numbers = get_all_atomic_numbers(molecule) + num_total_atoms = molecule.total_num_atoms + secondary_structures = np.ones(num_total_atoms) + for i in range(num_total_atoms): + secondary_structures[i] = ord('c') + resi = molecule.residue_seq[i] + for j, _ in enumerate(molecule.sheet): + sheet = molecule.sheet[j] + if molecule.chain[i] != sheet[0] or resi < sheet[1] or resi > sheet[3]: + continue + secondary_structures[i] = ord('s') + + for j, _ in enumerate(molecule.helix): + helix = molecule.helix[j] + if molecule.chain[i] != helix[0] or resi < helix[1] or resi > helix[3]: + continue + secondary_structures[i] = ord('h') + + output = PolyData() + + # for atomic numbers + atomic_num_arr = nps.numpy_to_vtk( + num_array=all_atomic_numbers, deep=True, array_type=VTK_ID_TYPE + ) + + # setting the array name to atom_type as vtkProteinRibbonFilter requires + # the array to be named atom_type + atomic_num_arr.SetName('atom_type') + + output.GetPointData().AddArray(atomic_num_arr) + + # for atom names + atom_names = StringArray() + + # setting the array name to atom_types as vtkProteinRibbonFilter requires + # the array to be named atom_types + atom_names.SetName('atom_types') + atom_names.SetNumberOfTuples(num_total_atoms) + for i in range(num_total_atoms): + atom_names.SetValue(i, molecule.atom_names[i]) + + output.GetPointData().AddArray(atom_names) + + # for residue sequences + residue_seq = nps.numpy_to_vtk( + num_array=molecule.residue_seq, deep=True, array_type=VTK_ID_TYPE + ) + residue_seq.SetName('residue') + output.GetPointData().AddArray(residue_seq) + + # for chain + chain = nps.numpy_to_vtk( + num_array=molecule.chain, deep=True, array_type=VTK_UNSIGNED_CHAR + ) + chain.SetName('chain') + output.GetPointData().AddArray(chain) + + # for secondary structures + s_s = nps.numpy_to_vtk( + num_array=secondary_structures, deep=True, array_type=VTK_UNSIGNED_CHAR + ) + s_s.SetName('secondary_structures') + output.GetPointData().AddArray(s_s) + + # for secondary structures begin + newarr = np.ones(num_total_atoms) + s_sb = nps.numpy_to_vtk(num_array=newarr, deep=True, array_type=VTK_UNSIGNED_CHAR) + s_sb.SetName('secondary_structures_begin') + output.GetPointData().AddArray(s_sb) + + # for secondary structures end + newarr = np.ones(num_total_atoms) + s_se = nps.numpy_to_vtk(num_array=newarr, deep=True, array_type=VTK_UNSIGNED_CHAR) + s_se.SetName('secondary_structures_end') + output.GetPointData().AddArray(s_se) + + # for is_hetatm + is_hetatm = nps.numpy_to_vtk( + num_array=molecule.is_hetatm, deep=True, array_type=VTK_UNSIGNED_CHAR + ) + is_hetatm.SetName('ishetatm') + output.GetPointData().AddArray(is_hetatm) + + # for model + model = nps.numpy_to_vtk( + num_array=molecule.model, deep=True, array_type=VTK_UNSIGNED_INT + ) + model.SetName('model') + output.GetPointData().AddArray(model) + + table = PTable() + + # for colors and radii of hetero-atoms + radii = np.ones((num_total_atoms, 3)) + rgb = np.ones((num_total_atoms, 3)) + + for i in range(num_total_atoms): + radii[i] = np.repeat(table.atomic_radius(all_atomic_numbers[i], 'VDW'), 3) + rgb[i] = table.atom_color(all_atomic_numbers[i]) + + Rgb = nps.numpy_to_vtk(num_array=rgb, deep=True, array_type=VTK_UNSIGNED_CHAR) + Rgb.SetName('rgb_colors') + output.GetPointData().SetScalars(Rgb) + + Radii = nps.numpy_to_vtk(num_array=radii, deep=True, array_type=VTK_FLOAT) + Radii.SetName('radius') + output.GetPointData().SetVectors(Radii) + + # setting the coordinates + points = numpy_to_vtk_points(coords) + output.SetPoints(points) + + ribbonFilter = ProteinRibbonFilter() + ribbonFilter.SetInputData(output) + ribbonFilter.SetCoilWidth(0.2) + ribbonFilter.SetDrawSmallMoleculesAsSpheres(0) + mapper = PolyDataMapper() + mapper.SetInputConnection(ribbonFilter.GetOutputPort()) + molecule_actor = Actor() + molecule_actor.SetMapper(mapper) + return molecule_actor
+ + + +
+[docs] +def bounding_box(molecule, colors=(1, 1, 1), linewidth=0.3): + """Create a bounding box for a molecule. + + Parameters + ---------- + molecule : Molecule + The molecule around which the bounding box is to be created. + colors : tuple (3,) or ndarray of shape (3,), optional + Color of the bounding box. Default: (1, 1, 1) + linewidth: float, optional + Thickness of tubes used to compose bounding box. Default: 0.3 + + Returns + ------- + bbox_actor : vtkActor + Actor created to serve as a bounding box for a given molecule. + + """ + pts = numpy_to_vtk_points(get_all_atomic_positions(molecule)) + min_x, max_x, min_y, max_y, min_z, max_z = pts.GetBounds() + + lines = np.array( + [ + [[min_x, min_y, min_z], [min_x, min_y, max_z]], + [[min_x, max_y, min_z], [min_x, max_y, max_z]], + [[max_x, min_y, min_z], [max_x, min_y, max_z]], + [[max_x, max_y, min_z], [max_x, max_y, max_z]], + [[min_x, min_y, min_z], [max_x, min_y, min_z]], + [[min_x, max_y, min_z], [max_x, max_y, min_z]], + [[min_x, max_y, max_z], [max_x, max_y, max_z]], + [[min_x, min_y, max_z], [max_x, min_y, max_z]], + [[min_x, min_y, min_z], [min_x, max_y, min_z]], + [[max_x, min_y, min_z], [max_x, max_y, min_z]], + [[min_x, min_y, max_z], [min_x, max_y, max_z]], + [[max_x, min_y, max_z], [max_x, max_y, max_z]], + ] + ) + + return streamtube(lines, colors=colors, linewidth=linewidth)
+ +
+
+ + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/_modules/fury/pick.html b/v0.10.x/_modules/fury/pick.html new file mode 100644 index 000000000..5d684e3ba --- /dev/null +++ b/v0.10.x/_modules/fury/pick.html @@ -0,0 +1,774 @@ + + + + + + + fury.pick — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +

Source code for fury.pick

+from collections.abc import Sequence
+
+import numpy as np
+
+from fury.lib import (
+    CellPicker,
+    DataObject,
+    HardwareSelector,
+    PointPicker,
+    PropPicker,
+    WorldPointPicker,
+    numpy_support,
+)
+
+
+
+[docs] +class PickingManager: + """Picking Manager helps with picking 3D objects.""" + +
+[docs] + def __init__(self, vertices=True, faces=True, actors=True, world_coords=True): + """Initialize Picking Manager. + + Parameters + ---------- + vertices : bool + If True allows to pick vertex indices. + faces : bool + If True allows to pick face indices. + actors : bool + If True allows to pick actor indices. + world_coords : bool + If True allows to pick xyz position in world coordinates. + + """ + self.pickers = {} + if vertices: + self.pickers['vertices'] = PointPicker() + if faces: + self.pickers['faces'] = CellPicker() + if actors: + self.pickers['actors'] = PropPicker() + if world_coords: + self.pickers['world_coords'] = WorldPointPicker()
+ + +
+[docs] + def pick(self, disp_xy, sc): + """Pick on display coordinates. + + Parameters + ---------- + disp_xy : tuple + Display coordinates x, y. + + sc : Scene + + """ + x, y = disp_xy + z = 0 + info = {'vertex': None, 'face': None, 'actor': None, 'xyz': None} + keys = self.pickers.keys() + + if 'vertices' in keys: + self.pickers['vertices'].Pick(x, y, z, sc) + info['vertex'] = self.pickers['vertices'].GetPointId() + + if 'faces' in keys: + self.pickers['faces'].Pick(x, y, z, sc) + info['vertex'] = self.pickers['faces'].GetPointId() + info['face'] = self.pickers['faces'].GetCellId() + + if 'actors' in keys: + self.pickers['actors'].Pick(x, y, z, sc) + info['actor'] = self.pickers['actors'].GetViewProp() + + if 'world_coords' in keys: + self.pickers['world_coords'].Pick(x, y, z, sc) + info['xyz'] = self.pickers['world_coords'].GetPickPosition() + + return info
+ + +
+[docs] + def event_position(self, iren): + """Return event display position from interactor. + + Parameters + ---------- + iren : interactor + The interactor object can be retrieved for example + using providing ShowManager's iren attribute. + + """ + return iren.GetEventPosition()
+ + +
+[docs] + def pickable_on(self, actors): + """Choose which actors can be picked. + + Parameters + ---------- + actors : actor or sequence of actors + + """ + if isinstance(actors, Sequence): + for a in actors: + a.PickableOn() + else: + actors.PickableOn()
+ + +
+[docs] + def pickable_off(self, actors): + """Choose which actors cannot be picked. + + Parameters + ---------- + actors : actor or sequence of actors + + """ + if isinstance(actors, Sequence): + for a in actors: + a.PickableOff() + else: + actors.PickableOff()
+
+ + + +
+[docs] +class SelectionManager: + """Selection Manager helps with picking many objects simultaneously.""" + +
+[docs] + def __init__(self, select='faces'): + """Initialize Selection Manager. + + Parameters + ---------- + select : 'faces' + Options are 'faces', 'vertices' or 'actors'. + Default 'faces'. + + Methods + ------- + select() + pick() + + """ + self.hsel = HardwareSelector() + self.update_selection_type(select)
+ + +
+[docs] + def update_selection_type(self, select): + """Update selection type. + + Parameters + ---------- + select : 'faces' + Options are 'faces', 'vertices' or 'actors'. + Default 'faces'. + + """ + self.selected_type = select.lower() + if select == 'faces' or select == 'edges': + self.hsel.SetFieldAssociation(DataObject.FIELD_ASSOCIATION_CELLS) + elif select == 'points' or select == 'vertices': + self.hsel.SetFieldAssociation(DataObject.FIELD_ASSOCIATION_POINTS) + elif select == 'actors': + self.hsel.SetActorPassOnly(True) + else: + raise ValueError('Unkown parameter select')
+ + +
+[docs] + def pick(self, disp_xy, sc): + """Pick on display coordinates returns a single object. + + Parameters + ---------- + disp_xy : tuple + Display coordinates x, y. + + sc : Scene + + """ + return self.select(disp_xy, sc, area=0)[0]
+ + +
+[docs] + def select(self, disp_xy, sc, area=0): + """Select multiple objects using display coordinates. + + Parameters + ---------- + disp_xy : tuple + Display coordinates x, y. + + sc : Scene + + area : int or 2d tuple of ints + Selection area around x, y coords. + + """ + info_plus = {} + self.hsel.SetRenderer(sc) + if isinstance(area, int): + picking_area = area, area + else: + picking_area = area + + try: + self.hsel.SetArea( + disp_xy[0] - picking_area[0], + disp_xy[1] - picking_area[1], + disp_xy[0] + picking_area[0], + disp_xy[1] + picking_area[1], + ) + res = self.hsel.Select() + + except OverflowError: + return {0: {'node': None, 'vertex': None, 'face': None, 'actor': None}} + + num_nodes = res.GetNumberOfNodes() + if num_nodes < 1: + sel_node = None + return {0: {'node': None, 'vertex': None, 'face': None, 'actor': None}} + else: + + for i in range(num_nodes): + + sel_node = res.GetNode(i) + info = {'node': None, 'vertex': None, 'face': None, 'actor': None} + + if sel_node is not None: + selected_nodes = set( + np.floor( + numpy_support.vtk_to_numpy(sel_node.GetSelectionList()) + ).astype(int) + ) + + info['node'] = sel_node + info['actor'] = sel_node.GetProperties().Get(sel_node.PROP()) + if self.selected_type == 'faces': + info['face'] = list(selected_nodes) + if self.selected_type == 'vertex': + info['vertex'] = list(selected_nodes) + info_plus[i] = info + + return info_plus
+ + +
+[docs] + def event_position(self, iren): + """Return event display position from interactor. + + Parameters + ---------- + iren : interactor + The interactor object can be retrieved for example + using ShowManager's iren attribute. + + """ + return iren.GetEventPosition()
+ + +
+[docs] + def selectable_on(self, actors): + """Choose which actors can be selected. + + Parameters + ---------- + actors : actor or sequence of actors + + """ + if isinstance(actors, Sequence): + for a in actors: + a.PickableOn() + else: + actors.PickableOn()
+ + +
+[docs] + def selectable_off(self, actors): + """Choose which actors cannot be selected. + + Parameters + ---------- + actors : actor or sequence of actors + + """ + if isinstance(actors, Sequence): + for a in actors: + a.PickableOff() + else: + actors.PickableOff()
+
+ +
+
+ + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/_modules/fury/pkg_info.html b/v0.10.x/_modules/fury/pkg_info.html new file mode 100644 index 000000000..7b222da4f --- /dev/null +++ b/v0.10.x/_modules/fury/pkg_info.html @@ -0,0 +1,518 @@ + + + + + + + fury.pkg_info — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +

Source code for fury.pkg_info

+from __future__ import annotations
+
+from subprocess import run
+
+from packaging.version import Version
+
+try:
+    from ._version import __version__
+except ImportError:
+    __version__ = '0+unknown'
+
+COMMIT_HASH = '$Format:%h$'
+
+
+
+[docs] +def pkg_commit_hash(pkg_path: str | None = None) -> tuple[str, str]: + """Get short form of commit hash + + In this file is a variable called COMMIT_HASH. This contains a substitution + pattern that may have been filled by the execution of ``git archive``. + + We get the commit hash from (in order of preference): + + * A substituted value in ``archive_subst_hash`` + * A truncated commit hash value that is part of the local portion of the + version + * git's output, if we are in a git repository + + If all these fail, we return a not-found placeholder tuple + + Parameters + ---------- + pkg_path : str + directory containing package + + Returns + ------- + hash_from : str + Where we got the hash from - description + hash_str : str + short form of hash + + """ + if not COMMIT_HASH.startswith('$Format'): # it has been substituted + return 'archive substitution', COMMIT_HASH + ver = Version(__version__) + if ver.local is not None and ver.local.startswith('g'): + return 'installation', ver.local[1:8] + # maybe we are in a repository + proc = run( + ('git', 'rev-parse', '--short', 'HEAD'), + capture_output=True, + cwd=pkg_path, + ) + if proc.stdout: + return 'repository', proc.stdout.decode().strip() + return '(none found)', '<not found>'
+ +
+
+ + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/_modules/fury/primitive.html b/v0.10.x/_modules/fury/primitive.html new file mode 100644 index 000000000..2be3574e1 --- /dev/null +++ b/v0.10.x/_modules/fury/primitive.html @@ -0,0 +1,1708 @@ + + + + + + + fury.primitive — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +

Source code for fury.primitive

+"""Module dedicated for basic primitive."""
+import math
+from os.path import join as pjoin
+
+import numpy as np
+from packaging.version import parse
+from scipy.spatial import ConvexHull
+from scipy.version import short_version
+
+from fury.data import DATA_DIR
+from fury.transform import cart2sphere, sphere2cart
+from fury.utils import fix_winding_order
+
+SCIPY_1_4_PLUS = parse(short_version) >= parse('1.4.0')
+
+SPHERE_FILES = {
+    'symmetric362': pjoin(DATA_DIR, 'evenly_distributed_sphere_362.npz'),
+    'symmetric642': pjoin(DATA_DIR, 'evenly_distributed_sphere_642.npz'),
+    'symmetric724': pjoin(DATA_DIR, 'evenly_distributed_sphere_724.npz'),
+    'repulsion724': pjoin(DATA_DIR, 'repulsion724.npz'),
+    'repulsion100': pjoin(DATA_DIR, 'repulsion100.npz'),
+    'repulsion200': pjoin(DATA_DIR, 'repulsion200.npz'),
+}
+
+
+
+[docs] +def faces_from_sphere_vertices(vertices): + """Triangulate a set of vertices on the sphere. + + Parameters + ---------- + vertices : (M, 3) ndarray + XYZ coordinates of vertices on the sphere. + + Returns + ------- + faces : (N, 3) ndarray + Indices into vertices; forms triangular faces. + + """ + hull = ConvexHull(vertices, qhull_options='Qbb Qc') + faces = np.ascontiguousarray(hull.simplices) + if len(vertices) < 2**16: + return np.asarray(faces, np.uint16) + else: + return faces
+ + + +
+[docs] +def repeat_primitive_function( + func, centers, func_args=[], directions=(1, 0, 0), colors=(1, 0, 0), scales=1 +): + """Repeat Vertices and triangles of a specific primitive function. + + It could be seen as a glyph. The primitive function should generate and + return vertices and faces + + Parameters + ---------- + func : callable + primitive functions + centers : ndarray, shape (N, 3) + Superquadrics positions + func_args : args + primitive functions arguments/parameters + directions : ndarray, shape (N, 3) or tuple (3,), optional + The orientation vector of the cone. + colors : ndarray (N,3) or (N, 4) or tuple (3,) or tuple (4,) + RGB or RGBA (for opacity) R, G, B and A should be at the range [0, 1] + scales : ndarray, shape (N) or (N,3) or float or int, optional + The height of the cone. + + Returns + ------- + big_vertices: ndarray + Expanded vertices at the centers positions + big_triangles: ndarray + Expanded triangles that composed our shape to duplicate + big_colors : ndarray + Expanded colors applied to all vertices/faces + + """ + # Get faces + _, faces = func() + if len(func_args) == 1: + func_args = np.squeeze(np.array([func_args] * centers.shape[0])) + elif len(func_args) != centers.shape[0]: + raise IOError( + 'sq_params should 1 or equal to the numbers \ + of centers' + ) + + vertices = np.concatenate([func(i)[0] for i in func_args]) + return repeat_primitive( + vertices=vertices, + faces=faces, + centers=centers, + directions=directions, + colors=colors, + scales=scales, + have_tiled_verts=True, + )
+ + + +
+[docs] +def repeat_primitive( + vertices, + faces, + centers, + directions=None, + colors=(1, 0, 0), + scales=1, + have_tiled_verts=False, +): + """Repeat Vertices and triangles of a specific primitive shape. + + It could be seen as a glyph. + + Parameters + ---------- + vertices: ndarray + vertices coords to duplicate at the centers positions + triangles: ndarray + triangles that composed our shape to duplicate + centers : ndarray, shape (N, 3) + Superquadrics positions + directions : ndarray, shape (N, 3) or tuple (3,), optional + The orientation vector of the cone. + colors : ndarray (N,3) or (N, 4) or tuple (3,) or tuple (4,) + RGB or RGBA (for opacity) R, G, B and A should be at the range [0, 1] + scales : ndarray, shape (N) or (N,3) or float or int, optional + The height of the cone. + have_tiled_verts : bool + option to control if we need to duplicate vertices of a shape or not + + Returns + ------- + big_vertices: ndarray + Expanded vertices at the centers positions + big_triangles: ndarray + Expanded triangles that composed our shape to duplicate + big_colors : ndarray + Expanded colors applied to all vertices/faces + big_centers : ndarray + Expanded centers for all vertices/faces + + """ + # duplicated vertices if needed + if not have_tiled_verts: + vertices = np.tile(vertices, (centers.shape[0], 1)) + big_vertices = vertices + # Get unit shape + unit_verts_size = vertices.shape[0] // centers.shape[0] + unit_triangles_size = faces.shape[0] + + # scale them + if not isinstance(scales, np.ndarray): + scales = np.array(scales) + if scales.ndim == 1: + if scales.size == centers.shape[0]: + scales = np.repeat(scales, unit_verts_size, axis=0) + scales = scales.reshape((big_vertices.shape[0], 1)) + elif scales.ndim == 2: + scales = np.repeat(scales, unit_verts_size, axis=0) + big_vertices *= scales + + # update triangles + big_triangles = np.array(np.tile(faces, (centers.shape[0], 1)), dtype=np.int32) + big_triangles += np.repeat( + np.arange(0, centers.shape[0] * unit_verts_size, step=unit_verts_size), + unit_triangles_size, + axis=0, + ).reshape((big_triangles.shape[0], 1)) + + def normalize_input(arr, arr_name=''): + if ( + isinstance(arr, (tuple, list, np.ndarray)) + and len(arr) in [3, 4] + and not all(isinstance(i, (list, tuple, np.ndarray)) for i in arr) + ): + return np.array([arr] * centers.shape[0]) + elif isinstance(arr, np.ndarray) and len(arr) == 1: + return np.repeat(arr, centers.shape[0], axis=0) + elif arr is None: + return np.array([]) + elif len(arr) != len(centers): + msg = '{} size should be 1 or '.format(arr_name) + msg += 'equal to the numbers of centers' + raise IOError(msg) + else: + return np.array(arr) + + # update colors + colors = normalize_input(colors, 'colors') + big_colors = np.repeat(colors, unit_verts_size, axis=0) + big_colors *= 255 + + # update orientations + directions = normalize_input(directions, 'directions') + for pts, dirs in enumerate(directions): + # Normal vector of the object. + dir_abs = np.linalg.norm(dirs) + if dir_abs: + normal = np.array([1.0, 0.0, 0.0]) + dirs = dirs / dir_abs + v = np.cross(normal, dirs) + c = np.dot(normal, dirs) + + v1, v2, v3 = v + + Vmat = np.array([[0, -v3, v2], [v3, 0, -v1], [-v2, v1, 0]]) + + if c == -1.0: + rotation_matrix = -np.eye(3, dtype=np.float64) + else: + h = 1 / (1 + c) + rotation_matrix = np.eye(3, dtype=np.float64) + \ + Vmat + (Vmat.dot(Vmat) * h) + + else: + rotation_matrix = np.identity(3) + + big_vertices[pts * unit_verts_size : (pts + 1) * unit_verts_size] = np.dot( + rotation_matrix[:3, :3], + big_vertices[pts * unit_verts_size : (pts + 1) * unit_verts_size].T, + ).T + + # apply centers position + big_centers = np.repeat(centers, unit_verts_size, axis=0) + big_vertices += big_centers + + return big_vertices, big_triangles, big_colors, big_centers
+ + + +
+[docs] +def prim_square(): + """Return vertices and triangles for a square geometry. + + Returns + ------- + vertices: ndarray + 4 vertices coords that composed our square + triangles: ndarray + 2 triangles that composed our square + + """ + vertices = np.array( + [[-0.5, -0.5, 0.0], [-0.5, 0.5, 0.0], [0.5, 0.5, 0.0], [0.5, -0.5, 0.0]] + ) + triangles = np.array([[0, 1, 2], [2, 3, 0]], dtype='i8') + return vertices, triangles
+ + + +
+[docs] +def prim_box(): + """Return vertices and triangle for a box geometry. + + Returns + ------- + vertices: ndarray + 8 vertices coords that composed our box + triangles: ndarray + 12 triangles that composed our box + + """ + vertices = np.array( + [ + [-0.5, -0.5, -0.5], + [-0.5, -0.5, 0.5], + [-0.5, 0.5, -0.5], + [-0.5, 0.5, 0.5], + [0.5, -0.5, -0.5], + [0.5, -0.5, 0.5], + [0.5, 0.5, -0.5], + [0.5, 0.5, 0.5], + ] + ) + triangles = np.array( + [ + [0, 6, 4], + [0, 2, 6], + [0, 3, 2], + [0, 1, 3], + [2, 7, 6], + [2, 3, 7], + [4, 6, 7], + [4, 7, 5], + [0, 4, 5], + [0, 5, 1], + [1, 5, 7], + [1, 7, 3], + ], + dtype='i8', + ) + return vertices, triangles
+ + + +
+[docs] +def prim_sphere(name='symmetric362', gen_faces=False, phi=None, theta=None): + """Provide vertices and triangles of the spheres. + + Parameters + ---------- + name : str, optional + which sphere - one of: + * 'symmetric362' + * 'symmetric642' + * 'symmetric724' + * 'repulsion724' + * 'repulsion100' + * 'repulsion200' + gen_faces : bool, optional + If True, triangulate a set of vertices on the sphere to get the faces. + Otherwise, we load the saved faces from a file. Default: False + phi : int, optional + Set the number of points in the latitude direction + theta : int, optional + Set the number of points in the longitude direction + + Returns + ------- + vertices: ndarray + vertices coords that composed our sphere + triangles: ndarray + triangles that composed our sphere + + Examples + -------- + >>> import numpy as np + >>> from fury.primitive import prim_sphere + >>> verts, faces = prim_sphere('symmetric362') + >>> verts.shape == (362, 3) + True + >>> faces.shape == (720, 3) + True + + """ + if phi is None or theta is None: + fname = SPHERE_FILES.get(name) + if fname is None: + raise ValueError('No sphere called "%s"' % name) + res = np.load(fname) + + verts = res['vertices'].copy() + faces = faces_from_sphere_vertices(verts) if gen_faces else res['faces'] + faces = fix_winding_order(res['vertices'], faces, clockwise=True) + return verts, faces + else: + phi = phi if phi >= 3 else 3 + theta = theta if theta >= 3 else 3 + + phi_indices, theta_indices = np.arange(0, phi), np.arange(1, theta - 1) + + # phi and theta angles are same as standard physics convention + phi_angles = 2 * np.pi * phi_indices / phi + theta_angles = np.pi * theta_indices / (theta - 1) + + # combinations of all phi and theta angles + mesh = np.array(np.meshgrid(phi_angles, theta_angles)) + combs = mesh.T.reshape(-1, 2) + + _angles = np.array([[1, 1], [0, np.pi], [np.pi / 2, -np.pi / 2]]) + _points = np.array(sphere2cart(_angles[0], _angles[1], _angles[2])).T + + x, y, z = sphere2cart(1, combs[:, 1:], combs[:, :1]) + + x = np.reshape(np.append(x, _points[:, :1]), (-1,)) + y = np.reshape(np.append(y, _points[:, 1:2]), (-1,)) + z = np.reshape(np.append(z, _points[:, -1:]), (-1,)) + + verts = np.vstack([x, y, z]).T + faces = faces_from_sphere_vertices(verts) + faces = fix_winding_order(verts, faces, clockwise=True) + return verts, faces
+ + + +
+[docs] +def prim_superquadric(roundness=(1, 1), sphere_name='symmetric362'): + """Provide vertices and triangles of a superquadrics. + + Parameters + ---------- + roundness : tuple, optional + parameters (Phi and Theta) that control the shape of the superquadric + + sphere_name : str, optional + which sphere - one of: + * 'symmetric362' + * 'symmetric642' + * 'symmetric724' + * 'repulsion724' + * 'repulsion100' + * 'repulsion200' + + Returns + ------- + vertices: ndarray + vertices coords that composed our sphere + triangles: ndarray + triangles that composed our sphere + + Examples + -------- + >>> import numpy as np + >>> from fury.primitive import prim_superquadric + >>> verts, faces = prim_superquadric(roundness=(1, 1)) + >>> verts.shape == (362, 3) + True + >>> faces.shape == (720, 3) + True + + """ + + def _fexp(x, p): + """Return a different kind of exponentiation.""" + return np.sign(x) * (np.abs(x) ** p) + + sphere_verts, sphere_triangles = prim_sphere(sphere_name) + _, sphere_phi, sphere_theta = cart2sphere(*sphere_verts.T) + + phi, theta = roundness + x = _fexp(np.sin(sphere_phi), phi) * _fexp(np.cos(sphere_theta), theta) + y = _fexp(np.sin(sphere_phi), phi) * _fexp(np.sin(sphere_theta), theta) + z = _fexp(np.cos(sphere_phi), phi) + xyz = np.vstack([x, y, z]).T + + vertices = np.ascontiguousarray(xyz) + + return vertices, sphere_triangles
+ + + +
+[docs] +def prim_tetrahedron(): + """Return vertices and triangles for a tetrahedron. + + This shape has a side length of two units. + + Returns + ------- + pyramid_vert: numpy.ndarray + 4 vertices coordinates + triangles: numpy.ndarray + 4 triangles representing the tetrahedron + + """ + pyramid_vert = np.array( + [[0.5, 0.5, 0.5], [0.5, -0.5, -0.5], [-0.5, 0.5, -0.5], [-0.5, -0.5, 0.5]] + ) + + pyramid_triag = np.array([[2, 0, 1], [0, 2, 3], [0, 3, 1], [1, 3, 2]], dtype='i8') + + return pyramid_vert, pyramid_triag
+ + + +
+[docs] +def prim_icosahedron(): + """Return vertices and triangles for icosahedron. + + Returns + ------- + icosahedron_vertices: numpy.ndarray + 12 vertices coordinates to the icosahedron + icosahedron_mesh: numpy.ndarray + 20 triangles representing the tetrahedron + + """ + phi = (1 + math.sqrt(5)) / 2.0 + + icosahedron_vertices = np.array( + [ + [-1.0, 0.0, phi], + [0.0, phi, 1.0], + [1.0, 0.0, phi], + [-phi, 1.0, 0.0], + [0.0, phi, -1.0], + [phi, 1.0, 0.0], + [-phi, -1.0, 0.0], + [0.0, -phi, 1.0], + [phi, -1.0, 0.0], + [-1.0, 0.0, -phi], + [0.0, -phi, -1.0], + [1.0, 0.0, -phi], + ] + ) + + icosahedron_mesh = np.array( + [ + [1, 0, 2], + [2, 5, 1], + [5, 4, 1], + [3, 1, 4], + [0, 1, 3], + [0, 6, 3], + [9, 3, 6], + [8, 2, 7], + [2, 0, 7], + [0, 7, 6], + [5, 2, 8], + [11, 5, 8], + [11, 4, 5], + [9, 11, 4], + [4, 3, 9], + [11, 10, 8], + [8, 10, 7], + [6, 7, 10], + [10, 9, 6], + [9, 10, 11], + ], + dtype='i8', + ) + + return icosahedron_vertices, icosahedron_mesh
+ + + +
+[docs] +def prim_rhombicuboctahedron(): + """Return vertices and triangles for rhombicuboctahedron. + + Returns + ------- + vertices: numpy.ndarray + 24 vertices coordinates to the rhombicuboctahedron + triangles: numpy.ndarray + 44 triangles representing the rhombicuboctahedron + + """ + phi = (math.sqrt(2) - 1) / 2.0 + + vertices = np.array( + [ + [0.5, phi, phi], + [0.5, phi, -phi], + [0.5, -phi, phi], + [0.5, -phi, -phi], + [phi, 0.5, phi], + [phi, 0.5, -phi], + [-phi, 0.5, phi], + [-phi, 0.5, -phi], + [phi, phi, 0.5], + [phi, -phi, 0.5], + [-phi, phi, 0.5], + [-phi, -phi, 0.5], + [-0.5, phi, phi], + [-0.5, phi, -phi], + [-0.5, -phi, phi], + [-0.5, -phi, -phi], + [phi, -0.5, phi], + [phi, -0.5, -phi], + [-phi, -0.5, phi], + [-phi, -0.5, -phi], + [phi, phi, -0.5], + [phi, -phi, -0.5], + [-phi, phi, -0.5], + [-phi, -phi, -0.5], + ] + ) + + triangles = np.array( + [ + [0, 1, 2], + [1, 3, 2], + [0, 4, 5], + [0, 5, 1], + [6, 4, 7], + [4, 5, 7], + [0, 8, 4], + [0, 2, 8], + [2, 9, 8], + [8, 9, 10], + [9, 11, 10], + [6, 8, 10], + [6, 8, 4], + [6, 10, 12], + [6, 12, 7], + [7, 12, 13], + [10, 11, 14], + [10, 14, 12], + [12, 14, 15], + [12, 15, 13], + [2, 3, 16], + [3, 17, 16], + [2, 16, 9], + [9, 16, 11], + [11, 16, 18], + [18, 16, 19], + [16, 17, 19], + [11, 18, 14], + [14, 18, 19], + [14, 19, 15], + [1, 21, 3], + [1, 20, 21], + [3, 21, 17], + [17, 21, 23], + [17, 23, 19], + [21, 20, 23], + [23, 20, 22], + [19, 23, 15], + [15, 23, 13], + [13, 23, 22], + [13, 22, 7], + [22, 7, 5], + [22, 20, 5], + [20, 1, 5], + ], + dtype='i8', + ) + + triangles = fix_winding_order(vertices, triangles, clockwise=True) + + return vertices, triangles
+ + + +
+[docs] +def prim_star(dim=2): + """Return vertices and triangle for star geometry. + + Parameters + ---------- + dim: int + Represents the dimension of the wanted star + + Returns + ------- + vertices: ndarray + vertices coords that composed our star + triangles: ndarray + Triangles that composed our star + + """ + if dim == 2: + vert = np.array( + [ + [-2.0, -3.0, 0.0], + [0.0, -2.0, 0.0], + [3.0, -3.0, 0.0], + [2.0, -1.0, 0.0], + [3.0, 1.0, 0.0], + [1.0, 1.0, 0.0], + [0.0, 3.0, 0.0], + [-1.0, 1.0, 0.0], + [-3.0, 1.0, 0.0], + [-2.0, -1.0, 0.0], + ] + ) + + triangles = np.array( + [ + [1, 9, 0], + [1, 2, 3], + [3, 4, 5], + [5, 6, 7], + [7, 8, 9], + [1, 9, 3], + [3, 7, 9], + [3, 5, 7], + ], + dtype='i8', + ) + + if dim == 3: + vert = np.array( + [ + [-2.0, -3.0, 0.0], + [0.0, -2, 0.0], + [3.0, -3.0, 0.0], + [2.0, -1.0, 0.0], + [3.0, 0.5, 0.0], + [1.0, 0.5, 0.0], + [0, 3.0, 0.0], + [-1.0, 0.5, 0.0], + [-3.0, 0.5, 0.0], + [-2.0, -1.0, 0.0], + [0.0, 0.0, 0.5], + [0.0, 0.0, -0.5], + ] + ) + triangles = np.array( + [ + [1, 9, 0], + [1, 2, 3], + [3, 4, 5], + [5, 6, 7], + [7, 8, 9], + [1, 9, 3], + [3, 7, 9], + [3, 5, 7], + [1, 0, 10], + [0, 9, 10], + [10, 9, 8], + [7, 8, 10], + [6, 7, 10], + [5, 6, 10], + [5, 10, 4], + [10, 3, 4], + [3, 10, 2], + [10, 1, 2], + [1, 0, 11], + [0, 9, 11], + [11, 9, 8], + [7, 8, 10], + [6, 7, 11], + [5, 6, 11], + [5, 10, 4], + [11, 3, 4], + [3, 11, 2], + [11, 1, 2], + ], + dtype='i8', + ) + return vert, triangles
+ + + +
+[docs] +def prim_triangularprism(): + """Return vertices and triangle for a regular triangular prism. + + Returns + ------- + vertices: ndarray + vertices coords that compose our prism + triangles: ndarray + triangles that compose our prism + + """ + # Local variable to represent the square root of three rounded + # to 7 decimal places + three = float('{:.7f}'.format(math.sqrt(3))) + vertices = np.array( + [ + [0, -1 / three, 1 / 2], + [-1 / 2, 1 / 2 / three, 1 / 2], + [1 / 2, 1 / 2 / three, 1 / 2], + [-1 / 2, 1 / 2 / three, -1 / 2], + [1 / 2, 1 / 2 / three, -1 / 2], + [0, -1 / three, -1 / 2], + ] + ) + triangles = np.array( + [ + [0, 1, 2], + [2, 1, 3], + [2, 3, 4], + [1, 0, 5], + [1, 5, 3], + [0, 2, 4], + [0, 4, 5], + [5, 4, 3], + ] + ) + triangles = fix_winding_order(vertices, triangles, clockwise=True) + return vertices, triangles
+ + + +
+[docs] +def prim_pentagonalprism(): + """Return vertices and triangles for a pentagonal prism. + + Returns + ------- + vertices: ndarray + vertices coords that compose our prism + triangles: ndarray + triangles that compose our prism + + """ + # Local variable to represent the square root of five + five = math.sqrt(5) + onec = (five - 1) / 4.0 + twoc = (five + 1) / 4.0 + sone = (math.sqrt(10 + (2 * five))) / 4.0 + stwo = (math.sqrt(10 - (2 * five))) / 4.0 + + vertices = np.array( + [ + [stwo / 2, twoc / 2, -0.5], + [sone / 2, -onec / 2, -0.5], + [0, -1 / 2, -0.5], + [-sone / 2, -onec / 2, -0.5], + [-stwo / 2, twoc / 2, -0.5], + [stwo / 2, twoc / 2, 0.5], + [sone / 2, -onec / 2, 0.5], + [0, -1 / 2, 0.5], + [-sone / 2, -onec / 2, 0.5], + [-stwo / 2, twoc / 2, 0.5], + ] + ) + triangles = np.array( + [ + [9, 5, 4], + [4, 5, 0], + [5, 6, 0], + [0, 6, 1], + [6, 7, 1], + [1, 7, 2], + [7, 8, 2], + [2, 8, 3], + [8, 9, 3], + [3, 9, 4], + [0, 1, 4], + [1, 4, 3], + [1, 3, 2], + [5, 6, 9], + [6, 8, 9], + [6, 7, 8], + ] + ) + triangles = fix_winding_order(vertices, triangles, clockwise=True) + return vertices, triangles
+ + + +
+[docs] +def prim_octagonalprism(): + """Return vertices and triangle for an octagonal prism. + + Returns + ------- + vertices: ndarray + vertices coords that compose our prism + triangles: ndarray + triangles that compose our prism + + """ + # Local variable to represent the square root of two rounded + # to 7 decimal places + two = float('{:.7f}'.format(math.sqrt(2))) + + vertices = np.array( + [ + [-1, -(1 + two), -1], + [1, -(1 + two), -1], + [1, (1 + two), -1], + [-1, (1 + two), -1], + [-(1 + two), -1, -1], + [(1 + two), -1, -1], + [(1 + two), 1, -1], + [-(1 + two), 1, -1], + [-1, -(1 + two), 1], + [1, -(1 + two), 1], + [1, (1 + two), 1], + [-1, (1 + two), 1], + [-(1 + two), -1, 1], + [(1 + two), -1, 1], + [(1 + two), 1, 1], + [-(1 + two), 1, 1], + ] + ) + triangles = np.array( + [ + [0, 8, 9], + [9, 1, 0], + [5, 13, 9], + [9, 1, 5], + [3, 11, 10], + [10, 2, 3], + [2, 10, 14], + [14, 6, 2], + [5, 13, 14], + [14, 6, 5], + [7, 15, 11], + [11, 3, 7], + [7, 15, 12], + [12, 4, 7], + [0, 8, 12], + [12, 4, 0], + [0, 3, 4], + [3, 4, 7], + [0, 3, 1], + [1, 2, 3], + [2, 5, 6], + [5, 2, 1], + [8, 11, 12], + [11, 12, 15], + [8, 11, 9], + [9, 10, 11], + [10, 13, 14], + [13, 10, 9], + ], + dtype='u8', + ) + vertices /= 4 + triangles = fix_winding_order(vertices, triangles, clockwise=True) + return vertices, triangles
+ + + +
+[docs] +def prim_frustum(): + """Return vertices and triangle for a square frustum prism. + + Returns + ------- + vertices: ndarray + vertices coords that compose our prism + triangles: ndarray + triangles that compose our prism + + """ + vertices = np.array( + [ + [-0.5, -0.5, 0.5], + [0.5, -0.5, 0.5], + [0.5, 0.5, 0.5], + [-0.5, 0.5, 0.5], + [-1, -1, -0.5], + [1, -1, -0.5], + [1, 1, -0.5], + [-1, 1, -0.5], + ] + ) + triangles = np.array( + [ + [4, 6, 5], + [6, 4, 7], + [0, 2, 1], + [2, 0, 3], + [4, 3, 0], + [3, 4, 7], + [7, 2, 3], + [2, 7, 6], + [6, 1, 2], + [1, 6, 5], + [5, 0, 1], + [0, 5, 4], + ], + dtype='u8', + ) + vertices /= 2 + triangles = fix_winding_order(vertices, triangles, clockwise=True) + return vertices, triangles
+ + + +
+[docs] +def prim_cylinder(radius=0.5, height=1, sectors=36, capped=True): + """Return vertices and triangles for a cylinder. + + Parameters + ---------- + radius: float + Radius of the cylinder + height: float + Height of the cylinder + sectors: int + Sectors in the cylinder + capped: bool + Whether the cylinder is capped at both ends or open + + Returns + ------- + vertices: ndarray + vertices coords that compose our cylinder + triangles: ndarray + triangles that compose our cylinder + + """ + if not isinstance(sectors, int): + raise TypeError('Only integers are allowed for sectors parameter') + if not sectors > 7: + raise ValueError('Sectors parameter should be greater than 7') + sector_step = 2 * math.pi / sectors + unit_circle_vertices = [] + + # generate a unit circle on YZ plane + for i in range(sectors + 1): + sector_angle = i * sector_step + unit_circle_vertices.append(0) + unit_circle_vertices.append(math.cos(sector_angle)) + unit_circle_vertices.append(math.sin(sector_angle)) + + vertices = [] + # generate vertices for a cylinder + for i in range(2): + h = -height / 2 + i * height + k = 0 + for _ in range(sectors + 1): + uy = unit_circle_vertices[k + 1] + uz = unit_circle_vertices[k + 2] + # position vector + vertices.append(h) + vertices.append(uy * radius) + vertices.append(uz * radius) + k += 3 + + # base and top circle vertices + base_center_index = None + top_center_index = None + + if capped: + base_center_index = int(len(vertices) / 3) + top_center_index = base_center_index + sectors + 1 + + for i in range(2): + h = -height / 2 + i * height + vertices.append(h) + vertices.append(0) + vertices.append(0) + k = 0 + for _ in range(sectors): + uy = unit_circle_vertices[k + 1] + uz = unit_circle_vertices[k + 2] + # position vector + vertices.append(h) + vertices.append(uy * radius) + vertices.append(uz * radius) + k += 3 + + if capped: + vertices = np.array(vertices).reshape(2 * (sectors + 1) + 2 * sectors + 2, 3) + else: + vertices = np.array(vertices).reshape(2 * (sectors + 1), 3) + + triangles = [] + k1 = 0 + k2 = sectors + 1 + + # triangles for the side surface + for i in range(sectors): + triangles.append(k1) + triangles.append(k2) + triangles.append(k1 + 1) + + triangles.append(k2) + triangles.append(k2 + 1) + triangles.append(k1 + 1) + k1 += 1 + k2 += 1 + + if capped: + k = base_center_index + 1 + for i in range(sectors): + if i < sectors - 1: + triangles.append(base_center_index) + triangles.append(k) + triangles.append(k + 1) + else: + triangles.append(base_center_index) + triangles.append(k) + triangles.append(base_center_index + 1) + k += 1 + + k = top_center_index + 1 + for i in range(sectors): + if i < sectors - 1: + triangles.append(top_center_index) + triangles.append(k + 1) + triangles.append(k) + else: + triangles.append(top_center_index) + triangles.append(top_center_index + 1) + triangles.append(k) + k += 1 + + if capped: + triangles = np.array(triangles).reshape(4 * sectors, 3) + else: + triangles = np.array(triangles).reshape(2 * sectors, 3) + + return vertices, triangles
+ + + +
+[docs] +def prim_arrow( + height=1.0, resolution=10, tip_length=0.35, tip_radius=0.1, shaft_radius=0.03 +): + """Return vertices and triangle for arrow geometry. + + Parameters + ---------- + height : float + The height of the arrow (default: 1.0). + resolution : int + The resolution of the arrow. + tip_length : float + The tip size of the arrow (default: 0.35) + tip_radius : float + the tip radius of the arrow (default: 0.1) + shaft_radius : float + The shaft radius of the arrow (default: 0.03) + + Returns + ------- + vertices: ndarray + vertices of the Arrow + triangles: ndarray + Triangles of the Arrow + + """ + shaft_height = height - tip_length + + all_faces = [] + shaft_outer_circle_down = [] + shaft_outer_circle_up = [] + tip_outer_circle = [] + + # calculating vertices + for i in range(resolution + 1): + x = math.cos((i * 2) * math.pi / resolution) + y = math.sin((i * 2) * math.pi / resolution) + + shaft_x = x * shaft_radius + shaft_y = y * shaft_radius + + tip_x = x * tip_radius + tip_y = y * tip_radius + + # lower shaft circle (d) + shaft_outer_circle_down.append((0.0, shaft_x, shaft_y)) + # upper shaft circle (u) + shaft_outer_circle_up.append((shaft_height, shaft_x, shaft_y)) + # tip outer circle + tip_outer_circle.append((shaft_height, tip_x, tip_y)) + + # center, center at shaft height, center at overall height + v1, v2, v3 = (0.0, 0.0, 0.0), (shaft_height, 0.0, 0.0), (height, 0.0, 0.0) + + all_verts = ( + [v1, v2, v3] + + shaft_outer_circle_down + + shaft_outer_circle_up + + tip_outer_circle + ) + + offset = len(shaft_outer_circle_down) + + off_1 = 3 + off_2 = off_1 + offset + off_3 = off_2 + offset + + # calculating triangles + for i in range(resolution): + # down circle d[i] , 0, d[i + 1] + all_faces.append((i + off_1 + 1, i + off_1, 0)) + + # cylinder triangles 1 d[i], d[i + 1], u[i + 1] + all_faces.append((i + off_2 + 1, i + off_1, i + off_1 + 1)) + + # cylinder triangles 2 u[i + 1], u[i], d[i] + all_faces.append((i + off_1, i + off_2 + 1, i + off_2)) + + # tip circle u[i] , 1, d[i + 1] + all_faces.append((i + off_3 + 1, i + off_3, 1)) + + # tip cone t[i], t[i + 1], 2 + all_faces.append((2, i + off_3, i + off_3 + 1)) + + vertices = np.asarray(all_verts) + triangles = np.asarray(all_faces, dtype=int) + + return vertices, triangles
+ + + +
+[docs] +def prim_cone(radius=0.5, height=1, sectors=10): + """Return vertices and triangle of a Cone. + + Parameters + ---------- + radius: float, optional + Radius of the cone + height: float, optional + Height of the cone + sectors: int, optional + Sectors in the cone + + Returns + ------- + vertices: ndarray + vertices coords that compose our cone + triangles: ndarray + triangles that compose our cone + + """ + if sectors < 3: + raise ValueError('Sectors parameter should be greater than 2') + + sector_angles = 2 * np.pi / sectors * np.arange(sectors) + + # Circle in YZ plane + h = height / 2.0 + x = np.full((sectors,), -h) + y, z = radius * np.cos(sector_angles), radius * np.sin(sector_angles) + + x = np.concatenate((x, np.array([h, -h]))) + y = np.concatenate((y, np.array([0, 0]))) + z = np.concatenate((z, np.array([0, 0]))) + + vertices = np.vstack(np.array([x, y, z])).T + + # index of base and top centers + base_center_index = int(len(vertices) - 1) + top_center_index = base_center_index - 1 + + triangles = [] + + for i in range(sectors): + if not i + 1 == top_center_index: + triangles.append(top_center_index) + triangles.append(i) + triangles.append(i + 1) + + triangles.append(base_center_index) + triangles.append(i + 1) + triangles.append(i) + else: + triangles.append(top_center_index) + triangles.append(i) + triangles.append(0) + + triangles.append(base_center_index) + triangles.append(0) + triangles.append(i) + + triangles = np.array(triangles).reshape(-1, 3) + + return vertices, triangles
+ +
+
+ + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/_modules/fury/shaders/base.html b/v0.10.x/_modules/fury/shaders/base.html new file mode 100644 index 000000000..1e1e8db70 --- /dev/null +++ b/v0.10.x/_modules/fury/shaders/base.html @@ -0,0 +1,901 @@ + + + + + + + fury.shaders.base — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +

Source code for fury.shaders.base

+import os
+from functools import partial
+
+from fury import enable_warnings
+from fury.deprecator import deprecate_with_version
+from fury.io import load_text
+from fury.lib import (
+    VTK_OBJECT,
+    Command,
+    DataObject,
+    Shader,
+    calldata_type,
+    numpy_support,
+)
+
+SHADERS_DIR = os.path.join(os.path.dirname(__file__))
+
+SHADERS_EXTS = ['.glsl', '.vert', '.tesc', '.tese', '.geom', '.frag', '.comp']
+
+SHADERS_TYPE = {
+    'vertex': Shader.Vertex,
+    'geometry': Shader.Geometry,
+    'fragment': Shader.Fragment,
+}
+
+REPLACEMENT_SHADERS_TYPES = {'vertex': Shader.Vertex, 'fragment': Shader.Fragment}
+
+SHADERS_BLOCK = {
+    'position': '//VTK::PositionVC',  # frag position in VC
+    'normal': '//VTK::Normal',  # optional normal declaration
+    'light': '//VTK::Light',  # extra lighting parameters
+    'tcoord': '//VTK::TCoord',  # Texture coordinates
+    'color': '//VTK::Color',  # material property values
+    'clip': '//VTK::Clip',  # clipping plane vars
+    'camera': '//VTK::Camera',  # camera and actor matrix values
+    'prim_id': '//VTK::PrimID',  # Apple Bug
+    'valuepass': '//VTK::ValuePass',  # Value raster
+    'output': '//VTK::Output',  # only for geometry shader
+    'coincident': '//VTK::Coincident',  # handle coincident offsets
+    'zbufer': '//VTK::ZBuffer',
+    'depth_peeling': '//VTK::DepthPeeling',  # Depth Peeling Support
+    'picking': '//VTK::Picking',  # picking support
+}
+
+# See [1] for a more extensive list of OpenGL constants
+# [1] https://docs.factorcode.org/content/vocab-opengl.gl.html
+GL_NUMBERS = {
+    'GL_ONE': 1,
+    'GL_ZERO': 0,
+    'GL_BLEND': 3042,
+    'GL_ONE_MINUS_SRC_ALPHA': 771,
+    'GL_SRC_ALPHA': 770,
+    'GL_DEPTH_TEST': 2929,
+    'GL_DST_COLOR': 774,
+    'GL_FUNC_SUBTRACT': 3277,
+    'GL_CULL_FACE': 2884,
+    'GL_ALPHA_TEST': 3008,
+    'GL_CW': 2304,
+    'GL_CCW': 2305,
+    'GL_ONE_MINUS_SRC_COLOR': 769,
+    'GL_SRC_COLOR': 768,
+}
+
+
+
+[docs] +def compose_shader(glsl_code): + """Merge GLSL shader code from a list of strings. + + Parameters + ---------- + glsl_code : list of str (code or filenames). + + Returns + ------- + code : str + GLSL shader code. + + """ + if not glsl_code: + return '' + + if not all(isinstance(i, str) for i in glsl_code): + raise IOError('The only supported format are string.') + + if isinstance(glsl_code, str): + return glsl_code + + code = '' + for content in glsl_code: + code += '\n' + code += content + return code
+ + + +
+[docs] +def import_fury_shader(shader_file): + """Import a Fury shader. + + Parameters + ---------- + shader_file : str + Filename of shader. The file must be in the fury/shaders directory and + must have the one of the supported extensions specified by the Khronos + Group + (https://github.com/KhronosGroup/glslang#execution-of-standalone-wrapper). + + Returns + ------- + code : str + GLSL shader code. + + """ + shader_fname = os.path.join(SHADERS_DIR, shader_file) + return load_shader(shader_fname)
+ + + +
+[docs] +def load_shader(shader_file): + """Load a shader from a file. + + Parameters + ---------- + shader_file : str + Full path to a shader file ending with one of the file extensions + defined by the Khronos Group + (https://github.com/KhronosGroup/glslang#execution-of-standalone-wrapper). + + Returns + ------- + code : str + GLSL shader code. + + """ + file_ext = os.path.splitext(os.path.basename(shader_file))[1] + if file_ext not in SHADERS_EXTS: + raise IOError( + 'Shader file "{}" does not have one of the supported ' + 'extensions: {}.'.format(shader_file, SHADERS_EXTS) + ) + return load_text(shader_file)
+ + + +
+[docs] +@deprecate_with_version( + message='Load function has been reimplemented as import_fury_shader.', + since='0.8.1', + until='0.9.0', +) +def load(filename): + """Load a Fury shader file. + + Parameters + ---------- + filename : str + Filename of the shader file. + + Returns + ------- + code: str + Shader code. + + """ + with open(os.path.join(SHADERS_DIR, filename)) as shader_file: + return shader_file.read()
+ + + +
+[docs] +def shader_to_actor( + actor, + shader_type, + impl_code='', + decl_code='', + block='valuepass', + keep_default=True, + replace_first=True, + replace_all=False, + debug=False, +): + """Apply your own substitutions to the shader creation process. + + A set of string replacements is applied to a shader template. This + function let's apply custom string replacements. + + Parameters + ---------- + actor : vtkActor + Fury actor you want to set the shader code to. + shader_type : str + Shader type: vertex, fragment + impl_code : str, optional + Shader implementation code, should be a string or filename. Default + None. + decl_code : str, optional + Shader declaration code, should be a string or filename. Default None. + block : str, optional + Section name to be replaced. VTK use of heavy string replacements to + insert shader and make it flexible. Each section of the shader + template have a specific name. For more information: + https://vtk.org/Wiki/Shaders_In_VTK. The possible values are: + position, normal, light, tcoord, color, clip, camera, prim_id, + valuepass. by default valuepass + keep_default : bool, optional + Keep the default block tag to let VTK replace it with its default + behavior. Default True. + replace_first : bool, optional + If True, apply this change before the standard VTK replacements. + Default True. + replace_all : bool, optional + [description], by default False + debug : bool, optional + Introduce a small error to debug shader code. Default False. + + """ + shader_type = shader_type.lower() + shader_type = REPLACEMENT_SHADERS_TYPES.get(shader_type, None) + if shader_type is None: + msg = 'Invalid Shader Type. Please choose between ' + msg += ', '.join(REPLACEMENT_SHADERS_TYPES.keys()) + raise ValueError(msg) + + block = block.lower() + block = SHADERS_BLOCK.get(block, None) + if block is None: + msg = 'Invalid Shader Type. Please choose between ' + msg += ', '.join(SHADERS_BLOCK.keys()) + raise ValueError(msg) + + block_dec = block + '::Dec' + block_impl = block + '::Impl' + + if keep_default: + decl_code = block_dec + '\n' + decl_code + impl_code = block_impl + '\n' + impl_code + + if debug: + enable_warnings() + error_msg = '\n\n--- DEBUG: THIS LINE GENERATES AN ERROR ---\n\n' + impl_code += error_msg + + sp = actor.GetShaderProperty() + + sp.AddShaderReplacement( + shader_type, block_dec, replace_first, decl_code, replace_all + ) + sp.AddShaderReplacement( + shader_type, block_impl, replace_first, impl_code, replace_all + )
+ + + +
+[docs] +def replace_shader_in_actor(actor, shader_type, code): + """Set and replace the shader template with a new one. + + Parameters + ---------- + actor : vtkActor + Fury actor you want to set the shader code to. + shader_type : str + Shader type: vertex, geometry, fragment. + code : str + New shader template code. + + """ + function_name = { + 'vertex': 'SetVertexShaderCode', + 'fragment': 'SetFragmentShaderCode', + 'geometry': 'SetGeometryShaderCode', + } + shader_type = shader_type.lower() + function = function_name.get(shader_type, None) + if function is None: + msg = 'Invalid Shader Type. Please choose between ' + msg += ', '.join(function_name.keys()) + raise ValueError(msg) + + sp = actor.GetShaderProperty() + getattr(sp, function)(code)
+ + + +
+[docs] +def add_shader_callback(actor, callback, priority=0.0): + """Add a shader callback to the actor. + + Parameters + ---------- + actor : vtkActor + Fury actor you want to add the callback to. + callback : callable + Function or class that contains 3 parameters: caller, event, calldata. + This callback will be trigger at each `UpdateShaderEvent` event. + priority : float, optional + Commands with a higher priority are called first. + + Returns + ------- + id_observer : int + An unsigned Int tag which can be used later to remove the event + or retrieve the vtkCommand used in the observer. + See more at: https://vtk.org/doc/nightly/html/classvtkObject.html + + Examples + -------- + .. code-block:: python + + add_shader_callback(actor, func_call1) + id_observer = add_shader_callback(actor, func_call2) + actor.GetMapper().RemoveObserver(id_observer) + + Priority calls + + .. code-block:: python + + test_values = [] + def callbackLow(_caller, _event, calldata=None): + program = calldata + if program is not None: + test_values.append(0) + + def callbackHigh(_caller, _event, calldata=None): + program = calldata + if program is not None: + test_values.append(999) + + def callbackMean(_caller, _event, calldata=None): + program = calldata + if program is not None: + test_values.append(500) + + fs.add_shader_callback( + actor, callbackHigh, 999) + fs.add_shader_callback( + actor, callbackLow, 0) + id_mean = fs.add_shader_callback( + actor, callbackMean, 500) + + showm.start() + # test_values = [999, 500, 0, 999, 500, 0, ...] + + """ + + @calldata_type(VTK_OBJECT) + def cbk(caller, event, calldata=None): + callback(caller, event, calldata) + + if not isinstance(priority, (float, int)): + raise TypeError( + """ + add_shader_callback priority argument should be a float/int""" + ) + + mapper = actor.GetMapper() + id_observer = mapper.AddObserver(Command.UpdateShaderEvent, cbk, priority) + + return id_observer
+ + + +
+[docs] +def shader_apply_effects(window, actor, effects, priority=0): + """This applies a specific opengl state (effect) or a list of effects just + before the actor's shader is executed. + + Parameters + ---------- + window : RenderWindow + For example, this is provided by the ShowManager.window attribute. + actor : actor + effects : a function or a list of functions + priority : float, optional + Related with the shader callback command. + Effects with a higher priority are applied first and + can be override by the others. + + Returns + ------- + id_observer : int + An unsigned Int tag which can be used later to remove the event + or retrieve the vtkCommand used in the observer. + See more at: https://vtk.org/doc/nightly/html/classvtkObject.html + + """ + if not isinstance(effects, list): + effects = [effects] + + def callback(_caller, _event, calldata=None, effects=None, window=None): + program = calldata + glState = window.GetState() + if program is not None: + for func in effects: + func(glState) + + id_observer = add_shader_callback( + actor, partial(callback, effects=effects, window=window), priority + ) + + return id_observer
+ + + +
+[docs] +def attribute_to_actor(actor, arr, attr_name, deep=True): + """Link a numpy array with vertex attribute. + + Parameters + ---------- + actor : vtkActor + Fury actor you want to add the vertex attribute to. + arr : ndarray + Array to link to vertices. + attr_name : str + Vertex attribute name. The vtk array will take the same name as the + attribute. + deep : bool, optional + If True a deep copy is applied, otherwise a shallow copy is applied. + Default True. + + """ + nb_components = arr.shape[1] if arr.ndim > 1 else arr.ndim + vtk_array = numpy_support.numpy_to_vtk(arr, deep=deep) + vtk_array.SetNumberOfComponents(nb_components) + vtk_array.SetName(attr_name) + actor.GetMapper().GetInput().GetPointData().AddArray(vtk_array) + mapper = actor.GetMapper() + mapper.MapDataArrayToVertexAttribute( + attr_name, attr_name, DataObject.FIELD_ASSOCIATION_POINTS, -1 + )
+ +
+
+ + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/_modules/fury/stream/client.html b/v0.10.x/_modules/fury/stream/client.html new file mode 100644 index 000000000..7febb2440 --- /dev/null +++ b/v0.10.x/_modules/fury/stream/client.html @@ -0,0 +1,861 @@ + + + + + + + fury.stream.client — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +

Source code for fury.stream.client

+import logging
+import platform
+import time
+from functools import partial
+
+import numpy as np
+import vtk
+
+from fury.stream.constants import _CQUEUE, PY_VERSION_8
+from fury.stream.tools import (
+    ArrayCircularQueue,
+    IntervalTimer,
+    IntervalTimerThreading,
+    RawArrayImageBufferManager,
+    SharedMemCircularQueue,
+    SharedMemImageBufferManager,
+)
+
+
+
+[docs] +def callback_stream_client(stream_client): + """This callback is used to update the image inside of + the ImageManager instance + + Parameters + ---------- + stream_client : StreamClient + + """ + if stream_client.in_request: + return + stream_client.in_request = True + stream_client.window2image_filter.Update() + stream_client.window2image_filter.Modified() + vtk_image = stream_client.window2image_filter.GetOutput() + vtk_array = vtk_image.GetPointData().GetScalars() + + w, h, _ = vtk_image.GetDimensions() + np_arr = np.frombuffer(vtk_array, dtype='uint8') + if np_arr is None: + stream_client.in_request = False + return + + stream_client.img_manager.write_into(w, h, np_arr) + stream_client.in_request = False
+ + + +
+[docs] +class FuryStreamClient: + """This obj is responsible to create a StreamClient.""" + +
+[docs] + def __init__( + self, + showm, + max_window_size=None, + use_raw_array=True, + whithout_iren_start=False, + num_buffers=2, + ): + """A StreamClient extracts a framebuffer from the OpenGL context + and writes into a shared memory resource. + + Parameters + ---------- + showm : ShowManager + max_window_size : tuple of ints, optional + This allows resize events inside of the FURY window instance. + Should be greater than the window size. + use_raw_array : bool, optional + If False then FuryStreamClient will use SharedMemory + instead of RawArrays. Notice that Python >=3.8 it's a + requirement + to use SharedMemory) + whithout_iren_start : bool, optional + Sometimes you can't initiate the vtkInteractor instance. + num_buffers : int, optional + Number of buffers to be used in the n-buffering + technique. + + """ + self._whithout_iren_start = whithout_iren_start + self.showm = showm + self.window2image_filter = vtk.vtkWindowToImageFilter() + self.window2image_filter.SetInput(self.showm.window) + self.image_buffers = [] + self.image_buffer_names = [] + self.info_buffer_name = None + self.image_reprs = [] + self.num_buffers = num_buffers + if max_window_size is None: + max_window_size = ( + int(self.showm.size[0] * (1 + 0.1)), + int(self.showm.size[1] * (1 + 0.1)), + ) + + self.max_size = max_window_size[0] * max_window_size[1] + self.max_window_size = max_window_size + if self.max_size < self.showm.size[0] * self.showm.size[1]: + raise ValueError('max_window_size must be greater than window_size') + + if not PY_VERSION_8 and not use_raw_array: + raise ValueError( + """ + SharedMemory works only in python 3.8 or higher""" + ) + + if use_raw_array: + self.img_manager = RawArrayImageBufferManager( + max_window_size=max_window_size, num_buffers=num_buffers + ) + else: + self.img_manager = SharedMemImageBufferManager( + max_window_size=max_window_size, num_buffers=num_buffers + ) + + self._id_timer = None + self._id_observer = None + self._interval_timer = None + self.in_request = False + self.update = True + self.use_raw_array = use_raw_array + self._started = False
+ + +
+[docs] + def start(self, ms=0, use_asyncio=False): + """Start the stream client. + + Parameters + ---------- + ms : float, optional + positive number. This update the image buffer using a interval + of ms milliseconds. If ms is 0 then the stream client + will update the buffer after every Render event. + use_asyncio : bool, optional + If False then the stream client will update the image + using a threading technique. + + """ + + def callback_for_vtk(caller, event, *args, **kwargs): + callback_stream_client(**{'stream_client': kwargs['stream_client']}) + + use_asyncio = platform.system() == 'Windows' or use_asyncio + if self._started: + self.stop() + if ms > 0: + if self._whithout_iren_start: + + Interval = IntervalTimer if use_asyncio else IntervalTimerThreading + self._interval_timer = Interval( + ms / 1000, callback_stream_client, **{'stream_client': self} + ) + else: + self._id_observer = self.showm.iren.AddObserver( + 'TimerEvent', partial(callback_for_vtk, **{'stream_client': self}) + ) + self._id_timer = self.showm.iren.CreateRepeatingTimer(ms) + else: + self._id_observer = self.showm.iren.AddObserver( + 'RenderEvent', partial(callback_for_vtk, **{'stream_client': self}) + ) + self.showm.window.Render() + self.showm.iren.Render() + self._started = True + callback_stream_client(**{'stream_client': self})
+ + +
+[docs] + def stop(self): + """Stop the stream client.""" + if not self._started: + return False + + if self._interval_timer is not None: + self._interval_timer.stop() + if self._id_timer is not None: + # self.showm.destroy_timer(self._id_timer) + self.showm.iren.DestroyTimer(self._id_timer) + self._id_timer = None + + if self._id_observer is not None: + self.showm.iren.RemoveObserver(self._id_observer) + self._id_observer = None + + self._started = False
+ + +
+[docs] + def cleanup(self): + """Release the shared memory resources if necessary.""" + if self.use_raw_array: + return + + self.img_manager.info_buffer.close() + # this it's due the python core issues + # https://bugs.python.org/issue38119 + # https://bugs.python.org/issue39959 + # https://github.com/luizalabs/shared-memory-dict/issues/13 + try: + self.img_manager.info_buffer.unlink() + except FileNotFoundError: + print( + f'Shared Memory {self.img_manager.info_buffer_name}\ + (info_buffer) File not found' + ) + for buffer, name in zip( + self.img_manager.image_buffers, self.img_manager.image_buffer_names + ): + buffer.close() + try: + buffer.unlink() + except FileNotFoundError: + print(f'Shared Memory {name}(buffer image) File not found')
+
+ + + +
+[docs] +def interaction_callback(circular_queue, showm, iren, render_after): + """This callback is used to invoke vtk interaction events + reading those events from the provided circular_queue instance + + Parameters + ---------- + circular_queue : CircularQueue + showm : ShowmManager + iren : vtkInteractor + render_after : bool, optional + If the render method should be called after an + dequeue + + """ + ts = time.time() * 1000 + data = circular_queue.dequeue() + if data is None: + return + + user_event_id = data[0] + user_timestamp = data[_CQUEUE.index_info.user_timestamp] + + ts = time.time() * 1000 + newX = int(showm.size[0] * data[_CQUEUE.index_info.x]) + newY = int(showm.size[1] * data[_CQUEUE.index_info.y]) + ctrl_key = int(data[_CQUEUE.index_info.ctrl]) + shift_key = int(data[_CQUEUE.index_info.shift]) + newY = showm.size[1] - newY + event_ids = _CQUEUE.event_ids + if user_event_id == event_ids.mouse_weel: + zoomFactor = 1.0 - data[_CQUEUE.index_info.weel] / 1000.0 + camera = showm.scene.GetActiveCamera() + fp = camera.GetFocalPoint() + pos = camera.GetPosition() + delta = [fp[i] - pos[i] for i in range(3)] + + pos2 = camera.GetPosition() + camera.SetFocalPoint([pos2[i] + delta[i] for i in range(3)]) + camera.Zoom(zoomFactor) + elif user_event_id == event_ids.mouse_move: + iren.SetEventInformation(newX, newY, ctrl_key, shift_key, chr(0), 0, None) + + iren.MouseMoveEvent() + + elif event_ids.mouse_ids: + iren.SetEventInformation(newX, newY, ctrl_key, shift_key, chr(0), 0, None) + mouse_actions = { + event_ids.left_btn_press: iren.LeftButtonPressEvent, + event_ids.left_btn_release: iren.LeftButtonReleaseEvent, + event_ids.middle_btn_press: iren.MiddleButtonPressEvent, + event_ids.middle_btn_release: iren.MiddleButtonReleaseEvent, + event_ids.right_btn_press: iren.RightButtonPressEvent, + event_ids.right_btn_release: iren.RightButtonReleaseEvent, + } + mouse_actions[user_event_id]() + logging.info('Interaction: time to perform event ' + f'{ts-user_timestamp:.2f} ms') + if render_after: + showm.window.Render() + showm.iren.Render()
+ + + +
+[docs] +class FuryStreamInteraction: + """This obj. is responsible to manage the user interaction""" + +
+[docs] + def __init__( + self, showm, max_queue_size=50, use_raw_array=True, whithout_iren_start=False + ): + """Initialize the StreamInteraction obj. + + Parameters + ---------- + showm : ShowmManager + max_queue_size : int, optional + maximum number of events to be stored. + use_raw_array : bool, optional + If False then a CircularQueue will be created using + SharedMemory instead of RawArrays. Notice that + Python >=3.8 it's requirement to use SharedMemory. + whithout_iren_start : bool, optional + Set that to True if you can't initiate the vtkInteractor + instance. + + """ + self.showm = showm + self.iren = self.showm.iren + if use_raw_array: + self.circular_queue = ArrayCircularQueue( + max_size=max_queue_size, dimension=_CQUEUE.dimension + ) + else: + self.circular_queue = SharedMemCircularQueue( + max_size=max_queue_size, dimension=_CQUEUE.dimension + ) + + self._id_timer = None + self._id_observer = None + self._interval_timer = None + self._whithout_iren_start = whithout_iren_start + self._started = False
+ + +
+[docs] + def start(self, ms=3, use_asyncio=False): + """Start the stream interaction client. + + Parameters + ---------- + ms : float, optional + positive number greater than zero. + use_asyncio : bool, optional + If False then the interaction will be performed in a + separate thread. + + """ + use_asyncio = platform.system() == 'Windows' or use_asyncio + if ms <= 0: + raise ValueError('ms must be greater than zero') + + if self._started: + self.stop() + if self._whithout_iren_start: + Interval = IntervalTimer if use_asyncio else IntervalTimerThreading + self._interval_timer = Interval( + ms / 1000, + interaction_callback, + *[self.circular_queue, self.showm, self.iren, True], + ) + else: + + def callback(caller, event, *args, **kwargs): + interaction_callback(self.circular_queue, self.showm, self.iren, True) + + self._id_observer = self.showm.iren.AddObserver('TimerEvent', callback) + self._id_timer = self.showm.iren.CreateRepeatingTimer(ms) + + self._started = True
+ + +
+[docs] + def stop(self): + """Stop the stream interaction client.""" + if not self._started: + return False + + if self._id_timer is not None: + # self.showm.destroy_timer(self._id_timer) + self.showm.iren.DestroyTimer(self._id_timer) + self._id_timer = None + + if self._id_observer is not None: + self.showm.iren.RemoveObserver(self._id_observer) + self._id_observer = None + + if self._interval_timer is not None: + self._interval_timer.stop() + self._interval_timer = None + + self._started = False
+ + +
+[docs] + def cleanup(self): + """Release the shared memory resources if necessary.""" + self.circular_queue.cleanup()
+
+ +
+
+ + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/_modules/fury/stream/server/async_app.html b/v0.10.x/_modules/fury/stream/server/async_app.html new file mode 100644 index 000000000..0de932f2c --- /dev/null +++ b/v0.10.x/_modules/fury/stream/server/async_app.html @@ -0,0 +1,741 @@ + + + + + + + fury.stream.server.async_app — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +

Source code for fury.stream.server.async_app

+import asyncio
+import json
+import os
+import weakref
+from functools import partial
+
+import aiohttp
+import numpy as np
+from aiohttp import MultipartWriter, WSCloseCode, web
+
+try:
+    from aiortc import RTCPeerConnection, RTCSessionDescription
+    from aiortc.contrib.media import MediaRelay
+
+    WEBRTC_AVAILABLE = True
+except ImportError:
+    WEBRTC_AVAILABLE = False
+    print('webrtc not available')
+
+import logging
+import time
+
+from fury.stream.constants import _CQUEUE_EVENT_IDs as EVENT_IDs
+
+logging.basicConfig(level=logging.ERROR)
+pcs = set()
+
+
+async def index(request, **kwargs):
+    folder = kwargs['folder']
+    just_mjpeg = kwargs['just_mjpeg']
+    index_file = 'index.html'
+    if just_mjpeg:
+        index_file = 'index_mjpeg.html'
+    content = open(os.path.join(folder, index_file), 'r').read()
+    return web.Response(content_type='text/html', text=content)
+
+
+async def javascript(request, **kwargs):
+    folder = kwargs['folder']
+    js = kwargs['js']
+    content = open(os.path.join(folder, 'js/%s' % js), 'r').read()
+    return web.Response(content_type='application/javascript', text=content)
+
+
+async def mjpeg_handler(request):
+    """This async function it's responsible
+    to create the MJPEG streaming.
+
+    Notes
+    -----
+    endpoint : /video/mjpeg
+
+    """
+    my_boundary = 'image-boundary'
+    response = web.StreamResponse(
+        status=200,
+        reason='OK',
+        headers={
+            'Content-Type': 'multipart/x-mixed-replace;boundary={}'.format(my_boundary)
+        },
+    )
+    await response.prepare(request)
+    image_buffer_manager = request.app['image_buffer_manager']
+    while True:
+        jpeg_bytes = await image_buffer_manager.async_get_jpeg()
+        with MultipartWriter('image/jpeg', boundary=my_boundary) as mpwriter:
+            mpwriter.append(jpeg_bytes, {'Content-Type': 'image/jpeg'})
+            try:
+                await mpwriter.write(response, close_boundary=False)
+            except ConnectionResetError:
+                logging.info('Client connection closed')
+                break
+        await response.write(b'\r\n')
+
+
+async def offer(request, **kwargs):
+    video = kwargs['video']
+    if 'broadcast' in kwargs and kwargs['broadcast']:
+        video = MediaRelay().subscribe(video)
+
+    params = await request.json()
+
+    offer = RTCSessionDescription(sdp=params['sdp'], type=params['type'])
+
+    pc = RTCPeerConnection()
+    pcs.add(pc)
+
+    @pc.on('connectionstatechange')
+    async def on_connectionstatechange():
+        print('Connection state is %s' % pc.connectionState)
+        if pc.connectionState == 'failed':
+            await pc.close()
+            pcs.discard(pc)
+
+    # open media source
+    audio = None
+
+    await pc.setRemoteDescription(offer)
+    for t in pc.getTransceivers():
+        if t.kind == 'audio' and audio:
+            pc.addTrack(audio)
+        elif t.kind == 'video' and video:
+            pc.addTrack(video)
+
+    answer = await pc.createAnswer()
+    await pc.setLocalDescription(answer)
+
+    return web.Response(
+        content_type='application/json',
+        text=json.dumps(
+            {'sdp': pc.localDescription.sdp, 'type': pc.localDescription.type}
+        ),
+    )
+
+
+
+[docs] +def set_weel(data, circular_queue): + deltaY = float(data['deltaY']) + user_envent_ms = float(data['timestampInMs']) + ok = circular_queue.enqueue( + np.array( + [EVENT_IDs.mouse_weel, deltaY, 0, 0, 0, 0, user_envent_ms, 0], + dtype='float64', + ) + ) + ts = time.time() * 1000 + logging.info(f'WEEL Time until enqueue {ts-user_envent_ms:.2f} ms') + return ok
+ + + +
+[docs] +def set_mouse(data, circular_queue): + x = float(data['x']) + y = float(data['y']) + ctrl_key = int(data['ctrlKey']) + shift_key = int(data['shiftKey']) + + user_envent_ms = float(data['timestampInMs']) + circular_queue = circular_queue + ok = circular_queue.enqueue( + np.array( + [EVENT_IDs.mouse_move, 0, x, y, ctrl_key, shift_key, user_envent_ms, 0], + dtype='float64', + ) + ) + + return ok
+ + + +
+[docs] +def set_mouse_click(data, circular_queue): + """3 | LeftButtonPressEvent + 4 | LeftButtonReleaseEvent + 5 | MiddleButtonPressEvent + 6 | MiddleButtonReleaseEvent + 7 | RightButtonPressEvent + 8 | RightButtonReleaseEvent + """ + on = 0 if data['on'] == 1 else 1 + ctrl = int(data['ctrlKey']) + shift = int(data['shiftKey']) + user_envent_ms = float(data['timestampInMs']) + x = float(data['x']) + y = float(data['y']) + mouse_button = int(data['mouseButton']) + if mouse_button not in [0, 1, 2]: + return False + if ctrl not in [0, 1] or shift not in [0, 1]: + return False + + event_id = (mouse_button + 1) * 2 + on + 1 + ok = circular_queue.enqueue( + np.array([event_id, 0, x, y, ctrl, shift, user_envent_ms, 0], dtype='float64') + ) + + return ok
+ + + +async def on_shutdown(app): + # close peer connections + coros = [pc.close() for pc in pcs] + await asyncio.gather(*coros) + pcs.clear() + for ws in set(app['websockets']): + await ws.close(code=WSCloseCode.GOING_AWAY, message='Server shutdown') + + +async def websocket_handler(request, **kwargs): + + circular_queue = kwargs['circular_queue'] + ws = web.WebSocketResponse() + await ws.prepare(request) + request.app['websockets'].add(ws) + try: + async for msg in ws: + if msg.type == aiohttp.WSMsgType.TEXT: + if msg.data == 'close': + await ws.close() + else: + data = json.loads(msg.data) + logging.info(f'\nuser event time {data["timestampInMs"]}') + if data['type'] == 'weel': + ts = time.time() * 1000 + interval = ts - data['timestampInMs'] + logging.info('WEEL request time approx ' + f'{interval:.2f} ms') + set_weel(data, circular_queue) + elif data['type'] == 'mouseMove': + set_mouse(data, circular_queue) + elif data['type'] == 'mouseLeftClick': + set_mouse_click(data, circular_queue) + # await ws.send_str(msg.data + '/answer') + + elif msg.type == aiohttp.WSMsgType.ERROR: + print('ws connection closed with exception %s' % ws.exception()) + finally: + request.app['websockets'].discard(ws) + + return ws + + +
+[docs] +def get_app( + rtc_server=None, + folder=None, + circular_queue=None, + image_buffer_manager=None, + provides_mjpeg=False, + broadcast=True, +): + + if folder is None: + folder = f'{os.path.dirname(__file__)}/www/' + + app = web.Application() + app['websockets'] = weakref.WeakSet() + + app.on_shutdown.append(on_shutdown) + + # app.router.add_get("/shutdown", + # partial( + # shutdown, + # app=app, + # rtc_server=rtc_server, + # ) + # ) + app.router.add_get( + '/', partial(index, folder=folder, just_mjpeg=rtc_server is None) + ) + js_files = [ + 'main.js', + 'main_just_mjpeg.js', + 'webrtc.js', + 'constants.js', + 'interaction.js', + ] + for js in js_files: + app.router.add_get('/js/%s' % js, partial(javascript, folder=folder, js=js)) + + app['image_buffer_manager'] = image_buffer_manager + if provides_mjpeg: + app.router.add_get('/video/mjpeg', mjpeg_handler) + + if rtc_server is not None: + app.router.add_post( + '/offer', partial(offer, video=rtc_server, broadcast=broadcast) + ) + + if circular_queue is not None: + app.add_routes( + [web.get('/ws', partial(websocket_handler, circular_queue=circular_queue))] + ) + + return app
+ +
+
+ + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/_modules/fury/stream/server/main.html b/v0.10.x/_modules/fury/stream/server/main.html new file mode 100644 index 000000000..c6f4dbe63 --- /dev/null +++ b/v0.10.x/_modules/fury/stream/server/main.html @@ -0,0 +1,775 @@ + + + + + + + fury.stream.server.main — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +

Source code for fury.stream.server.main

+# import os
+# os.environ['PYTHONASYNCIODEBUG'] = '1'
+# import logging
+import numpy as np
+from aiohttp import web
+
+from fury.stream.constants import _CQUEUE, PY_VERSION_8
+from fury.stream.server.async_app import get_app
+from fury.stream.tools import (
+    ArrayCircularQueue,
+    RawArrayImageBufferManager,
+    SharedMemCircularQueue,
+    SharedMemImageBufferManager,
+)
+
+if PY_VERSION_8:
+    from fury.stream.tools import remove_shm_from_resource_tracker
+
+
+try:
+    from aiortc import VideoStreamTrack
+    from av import VideoFrame
+
+    WEBRTC_AVAILABLE = True
+except ImportError:
+    WEBRTC_AVAILABLE = False
+    VideoStreamTrack = object
+
+CYTHON_AVAILABLE = False
+if WEBRTC_AVAILABLE:
+    try:
+        import pyximport
+
+        pyximport.install()
+        from fury.stream.server.FuryVideoFrame import FuryVideoFrame
+
+        CYTHON_AVAILABLE = True
+    except ImportError:
+        pass
+
+
+
+[docs] +class RTCServer(VideoStreamTrack): + """This Obj it's responsible to create the VideoStream for + the WebRTCServer + """ + +
+[docs] + def __init__( + self, + image_buffer_manager, + ): + """Initialize the RTCServer + + Parameters + ---------- + image_buffer_manager : ImageBufferManager + + """ + super().__init__() + + self.frame = None + self.buffer_manager = image_buffer_manager
+ + +
+[docs] + async def recv(self): + """Return a VideoFrame to be used in the WebRTC Server + + The frame will be created using the image stored in the + shared memory + + Returns + ------- + frame : VideoFrame + + """ + pts, time_base = await self.next_timestamp() + + width, height, image = self.buffer_manager.get_current_frame() + + if ( + self.frame is None + or self.frame.planes[0].width != width + or self.frame.planes[0].height != height + ): + if CYTHON_AVAILABLE: + self.frame = FuryVideoFrame(width, height, 'rgb24') + self.image = image + + if not CYTHON_AVAILABLE: + # if the buffer it's already flipped + # self.frame.planes[0].update(self.image) + self.image = np.frombuffer(self.image, 'uint8')[ + 0 : width * height * 3 + ].reshape((height, width, 3)) + self.image = np.flipud(self.image) + self.frame = VideoFrame.from_ndarray(self.image) + else: + self.frame.update_from_buffer(self.image) + + self.frame.pts = pts + self.frame.time_base = time_base + + return self.frame
+ + +
+[docs] + def release(self): + """Release the RTCServer""" + try: + if self.stream is None: + return + self.stream.release() + self.stream = None + except AttributeError: + pass
+
+ + + +
+[docs] +def web_server_raw_array( + image_buffers=None, + info_buffer=None, + queue_head_tail_buffer=None, + queue_buffer=None, + port=8000, + host='localhost', + provides_mjpeg=True, + provides_webrtc=True, + ms_jpeg=16, + run_app=True, +): + """This will create a streaming webserver running on the + given port and host using RawArrays. + + Parameters + ---------- + image_buffers : list of buffers + A list of buffers with each one containing a frame. + info_buffer : buffer + A buffer with the information about the current + frame to be streamed and the respective sizes + queue_head_tail_buffer : buffer + If buffer is passed than this Obj will read a + a already created RawArray. + queue_buffer : buffer + If queue_buffer is passed than this Obj will read a + a already created RawArray containing the user interactions + events stored in the queue_buffer. + port : int, optional + Port to be used by the aiohttp server + host : str, optional, default localhost + host to be used by the aiohttp server + provides_mjpeg : bool, default True + If a MJPEG streaming should be available. + If True you can consume that through + host:port/video/mjpeg + or if you want to interact you can consume that + through your browser + http://host:port?encoding=mjpeg + provides_webrtc : bool, default True + If a WebRTC streaming should be available. + http://host:port + ms_jpeg : float, optional + This it's used only if the MJPEG will be used. The + ms_jpeg represents the amount of milliseconds between to + consecutive calls of the jpeg encoding. + run_app : bool, default True + This will run the aiohttp application. The False condition + is used just to be able to test the server. + + """ + image_buffer_manager = RawArrayImageBufferManager( + image_buffers=image_buffers, info_buffer=info_buffer + ) + + rtc_server = None + create_webrtc = provides_webrtc and WEBRTC_AVAILABLE + if create_webrtc: + rtc_server = RTCServer(image_buffer_manager) + else: + provides_mjpeg = True + + circular_queue = None + if queue_buffer is not None: + circular_queue = ArrayCircularQueue( + dimension=_CQUEUE.dimension, + head_tail_buffer=queue_head_tail_buffer, + buffer=queue_buffer, + ) + + app_fury = get_app( + rtc_server, + circular_queue=circular_queue, + image_buffer_manager=image_buffer_manager, + provides_mjpeg=provides_mjpeg, + ) + + if run_app: + web.run_app(app_fury, host=host, port=port, ssl_context=None) + + if rtc_server is not None: + rtc_server.release() + + if circular_queue is not None: + circular_queue.cleanup() + + image_buffer_manager.cleanup()
+ + + +
+[docs] +def web_server( + image_buffer_names=None, + info_buffer_name=None, + queue_head_tail_buffer_name=None, + queue_buffer_name=None, + port=8000, + host='localhost', + provides_mjpeg=True, + provides_webrtc=True, + avoid_unlink_shared_mem=True, + ms_jpeg=16, + run_app=True, +): + """This will create a streaming webserver running on the given port + and host using SharedMemory. + + Parameters + ---------- + image_buffers_name : list of str + A list of buffers with each one containing a frame. + info_buffer_name : str + A buffer with the information about the current + frame to be streamed and the respective sizes + queue_head_tail_buffer_name : str, optional + If buffer is passed than this Obj will read a + a already created RawArray. + buffer_name : str, optional + If queue_buffer is passed than this Obj will read a + a already created RawArray containing the user interactions + events stored in the queue_buffer. + port : int, optional + Port to be used by the aiohttp server + host : str, optional, default localhost + host to be used by the aiohttp server + provides_mjpeg : bool, default True + If a MJPEG streaming should be available. + If True you can consume that through + host:port/video/mjpeg + or if you want to interact you can consume that + through your browser + http://host:port?encoding=mjpeg + provides_webrtc : bool, default True + If a WebRTC streaming should be available. + http://host:port + avoid_unlink_shared_mem : bool, default False + If True, then this will apply a monkey-patch solution to + a python>=3.8 core bug + ms_jpeg : float, optional + This it's used only if the MJPEG will be used. The + ms_jpeg represents the amount of milliseconds between to + consecutive calls of the jpeg encoding. + run_app : bool, default True + This will run the aiohttp application. The False condition + is used just to be able to test the server. + + """ + if avoid_unlink_shared_mem and PY_VERSION_8: + remove_shm_from_resource_tracker() + + image_buffer_manager = SharedMemImageBufferManager( + image_buffer_names=image_buffer_names, info_buffer_name=info_buffer_name + ) + + rtc_server = None + create_webrtc = provides_webrtc and WEBRTC_AVAILABLE + if create_webrtc: + rtc_server = RTCServer(image_buffer_manager) + else: + provides_mjpeg = True + + circular_queue = None + if queue_buffer_name is not None: + circular_queue = SharedMemCircularQueue( + dimension=_CQUEUE.dimension, + buffer_name=queue_buffer_name, + head_tail_buffer_name=queue_head_tail_buffer_name, + ) + + app_fury = get_app( + rtc_server, + circular_queue=circular_queue, + image_buffer_manager=image_buffer_manager, + provides_mjpeg=provides_mjpeg, + ) + + if run_app: + web.run_app(app_fury, host=host, port=port, ssl_context=None) + + if rtc_server is not None: + rtc_server.release() + + if circular_queue is not None: + circular_queue.cleanup() + + image_buffer_manager.cleanup()
+ +
+
+ + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/_modules/fury/stream/tools.html b/v0.10.x/_modules/fury/stream/tools.html new file mode 100644 index 000000000..9e01efe4c --- /dev/null +++ b/v0.10.x/_modules/fury/stream/tools.html @@ -0,0 +1,1684 @@ + + + + + + + fury.stream.tools — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +

Source code for fury.stream.tools

+import asyncio
+import io
+import logging
+import multiprocessing
+import time
+from abc import ABC, abstractmethod
+from threading import Timer
+
+import numpy as np
+from PIL import Image, ImageDraw
+
+from fury.stream.constants import PY_VERSION_8
+
+if PY_VERSION_8:
+    from multiprocessing import resource_tracker, shared_memory
+else:
+    shared_memory = None   # type: ignore
+
+
+_FLOAT_ShM_TYPE = 'd'
+_INT_ShM_TYPE = 'i'
+_UINT_ShM_TYPE = 'I'
+_BYTE_ShM_TYPE = 'B'
+
+_FLOAT_SIZE = np.dtype(_FLOAT_ShM_TYPE).itemsize
+_INT_SIZE = np.dtype(_INT_ShM_TYPE).itemsize
+_UINT_SIZE = np.dtype(_UINT_ShM_TYPE).itemsize
+_BYTE_SIZE = np.dtype(_BYTE_ShM_TYPE).itemsize
+
+
+
+[docs] +def remove_shm_from_resource_tracker(): + """Monkey-patch multiprocessing.resource_tracker so SharedMemory won't + be tracked + + Notes + ----- + More details at: https://bugs.python.org/issue38119 + + """ + + def fix_register(name, rtype): + if rtype == 'shared_memory': + return + try: + return resource_tracker._resource_tracker.register(self, name, rtype) + except NameError: + return None + + resource_tracker.register = fix_register + + def fix_unregister(name, rtype): + if rtype == 'shared_memory': + return + try: + return resource_tracker._resource_tracker.unregister(self, name, rtype) + except NameError: + return None + + resource_tracker.unregister = fix_unregister + + if 'shared_memory' in resource_tracker._CLEANUP_FUNCS: + del resource_tracker._CLEANUP_FUNCS['shared_memory']
+ + + +
+[docs] +class GenericMultiDimensionalBuffer(ABC): + """This implements a abstract (generic) multidimensional buffer.""" + +
+[docs] + def __init__(self, max_size=None, dimension=8): + """Initialize the multidimensional buffer. + + Parameters + ---------- + max_size : int, optional + If buffer_name or buffer was not passed then max_size + it's mandatory + dimension : int, default 8 + + """ + self.max_size = max_size + self.dimension = dimension + self.buffer_name = None + self._buffer = None + self._buffer_repr = None + self._created = False
+ + + @property + def buffer(self): + return self._buffer + + @buffer.setter + def buffer(self, data): + if isinstance(data, (np.ndarray, np.generic)): + if data.dtype == _FLOAT_ShM_TYPE: + self._buffer_repr[:] = data + +
+[docs] + def get_start_end(self, idx): + dim = self.dimension + start = idx * dim + end = dim * (idx + 1) + return start, end
+ + + def __getitem__(self, idx): + start, end = self.get_start_end(idx) + logging.info(f'dequeue start {int(time.time()*1000)}') + ts = time.time() * 1000 + + items = self._buffer_repr[start:end] + te = time.time() * 1000 + logging.info(f'dequeue frombuffer cost {te-ts:.2f}') + return items + + def __setitem__(self, idx, data): + start, end = self.get_start_end(idx) + if isinstance(data, (np.ndarray, np.generic)): + if data.dtype == _FLOAT_ShM_TYPE: + # if end - start == self.dimension and start >= 0 and end >= 0: + self._buffer_repr[start:end] = data + +
+[docs] + @abstractmethod + def load_mem_resource(self): + ... # pragma: no cover
+ + +
+[docs] + @abstractmethod + def create_mem_resource(self): + ... # pragma: no cover
+ + +
+[docs] + @abstractmethod + def cleanup(self): + ... # pragma: no cover
+
+ + + +
+[docs] +class RawArrayMultiDimensionalBuffer(GenericMultiDimensionalBuffer): + """This implements a multidimensional buffer with RawArray.""" + +
+[docs] + def __init__(self, max_size, dimension=4, buffer=None): + """Stream system uses that to implement the CircularQueue + with shared memory resources. + + Parameters + ---------- + max_size : int, optional + If buffer_name or buffer was not passed then max_size + it's mandatory + dimension : int, default 8 + buffer : buffer, optional + If buffer is not passed to __init__ + then the multidimensional buffer obj will create a new + RawArray object to store the data + If buffer is passed than this Obj will read a + a already created RawArray + + """ + super().__init__(max_size, dimension) + if buffer is None: + self.create_mem_resource() + else: + self._buffer = buffer + self.load_mem_resource()
+ + +
+[docs] + def create_mem_resource(self): + buffer_arr = np.zeros( + self.dimension * (self.max_size + 1), dtype=_FLOAT_ShM_TYPE + ) + buffer = multiprocessing.RawArray( + _FLOAT_ShM_TYPE, np.ctypeslib.as_ctypes(buffer_arr) + ) + self._buffer = buffer + self._buffer_repr = np.ctypeslib.as_array(self._buffer)
+ + +
+[docs] + def load_mem_resource(self): + self.max_size = int(len(self._buffer) // self.dimension) + self.max_size -= 1 + self._buffer_repr = np.ctypeslib.as_array(self._buffer)
+ + +
+[docs] + def cleanup(self): + pass
+
+ + + +
+[docs] +class SharedMemMultiDimensionalBuffer(GenericMultiDimensionalBuffer): + """This implements a generic multidimensional buffer + with SharedMemory. + """ + +
+[docs] + def __init__(self, max_size, dimension=4, buffer_name=None): + """Stream system uses that to implement the + CircularQueue with shared memory resources. + + Parameters + ---------- + max_size : int, optional + If buffer_name or buffer was not passed then max_size + it's mandatory + dimension : int, default 8 + buffer_name : str, optional + if buffer_name is passed than this Obj will read a + a already created SharedMemory + + """ + super().__init__(max_size, dimension) + if buffer_name is None: + self.create_mem_resource() + self._created = True + else: + self.buffer_name = buffer_name + self.load_mem_resource() + self._created = False + + self._create_repr()
+ + +
+[docs] + def create_mem_resource(self): + self._num_el = self.dimension * (self.max_size + 1) + buffer_arr = np.zeros(self._num_el + 2, dtype=_FLOAT_ShM_TYPE) + self._buffer = shared_memory.SharedMemory(create=True, size=buffer_arr.nbytes) + sizes = np.ndarray( + 2, dtype=_FLOAT_ShM_TYPE, buffer=self._buffer.buf[0 : _FLOAT_SIZE * 2] + ) + sizes[0] = self.max_size + sizes[1] = self.dimension + self.buffer_name = self._buffer.name + logging.info( + [ + 'create repr multidimensional buffer ', + ] + )
+ + +
+[docs] + def load_mem_resource(self): + self._buffer = shared_memory.SharedMemory(self.buffer_name) + sizes = np.ndarray(2, dtype='d', buffer=self._buffer.buf[0 : _FLOAT_SIZE * 2]) + self.max_size = int(sizes[0]) + self.dimension = int(sizes[1]) + num_el = int((sizes[0] + 1) * sizes[1]) + self._num_el = num_el + logging.info( + [ + 'load repr multidimensional buffer', + ] + )
+ + + def _create_repr(self): + start = _FLOAT_SIZE * 2 + end = (self._num_el + 2) * _FLOAT_SIZE + self._buffer_repr = np.ndarray( + self._num_el, dtype=_FLOAT_ShM_TYPE, buffer=self._buffer.buf[start:end] + ) + logging.info( + [ + 'create repr multidimensional buffer', + self._buffer_repr.shape, + 'max size', + self.max_size, + 'dimension', + self.dimension, + ] + ) + +
+[docs] + def cleanup(self): + self._buffer.close() + if self._created: + # this it's due the python core issues + # https://bugs.python.org/issue38119 + # https://bugs.python.org/issue39959 + # https://github.com/luizalabs/shared-memory-dict/issues/13 + try: + self._buffer.unlink() + except FileNotFoundError: + print( + f'Shared Memory {self.buffer_name}(queue_event_buffer)\ + File not found' + )
+
+ + + +
+[docs] +class GenericCircularQueue(ABC): + """This implements a generic circular queue which works with + shared memory resources. + """ + +
+[docs] + def __init__( + self, + max_size=None, + dimension=8, + use_shared_mem=False, + buffer=None, + buffer_name=None, + ): + """Initialize the circular queue. + + Parameters + ---------- + max_size : int, optional + If buffer_name or buffer was not passed then max_size + it's mandatory. This will be used to construct the + multidimensional buffer + dimension : int, default 8 + This will be used to construct the multidimensional buffer + use_shared_mem : bool, default False + If the multidimensional memory resource should create or read + using SharedMemory or RawArrays + buffer : RawArray, optional + buffer_name: str, optional + + """ + self._created = False + self.head_tail_buffer_name = None + self.head_tail_buffer_repr = None + self.head_tail_buffer = None + self._use_shared_mem = use_shared_mem + if use_shared_mem: + self.buffer = SharedMemMultiDimensionalBuffer( + max_size=max_size, dimension=dimension, buffer_name=buffer_name + ) + else: + self.buffer = RawArrayMultiDimensionalBuffer( + max_size=max_size, dimension=dimension, buffer=buffer + )
+ + + @property + def head(self): + if self._use_shared_mem: + return self.head_tail_buffer_repr[0] + else: + return np.frombuffer(self.head_tail_buffer.get_obj(), _INT_ShM_TYPE)[0] + + @head.setter + def head(self, value): + self.head_tail_buffer_repr[0] = value + + @property + def tail(self): + if self._use_shared_mem: + return self.head_tail_buffer_repr[1] + else: + return np.frombuffer(self.head_tail_buffer.get_obj(), _INT_ShM_TYPE)[1] + + @tail.setter + def tail(self, value): + self.head_tail_buffer_repr[1] = value + +
+[docs] + def set_head_tail(self, head, tail, lock=1): + self.head_tail_buffer_repr[0:3] = np.array([head, tail, lock]).astype( + _INT_ShM_TYPE + )
+ + + def _enqueue(self, data): + ok = False + if (self.tail + 1) % self.buffer.max_size == self.head: + ok = False + else: + if self.head == -1: + self.set_head_tail(0, 0, 1) + else: + self.tail = (self.tail + 1) % self.buffer.max_size + self.buffer[self.tail] = data + + ok = True + return ok + + def _dequeue(self): + if self.head == -1: + interactions = None + else: + if self.head != self.tail: + interactions = self.buffer[self.head] + self.head = (self.head + 1) % self.buffer.max_size + else: + interactions = self.buffer[self.head] + self.set_head_tail(-1, -1, 1) + return interactions + +
+[docs] + @abstractmethod + def enqueue(self, data): + pass # pragma: no cover
+ + +
+[docs] + @abstractmethod + def dequeue(self): + pass # pragma: no cover
+ + +
+[docs] + @abstractmethod + def load_mem_resource(self): + pass # pragma: no cover
+ + +
+[docs] + @abstractmethod + def create_mem_resource(self): + pass # pragma: no cover
+ + +
+[docs] + @abstractmethod + def cleanup(self): + pass # pragma: no cover
+
+ + + +
+[docs] +class ArrayCircularQueue(GenericCircularQueue): + """This implements a MultiDimensional Queue which works with + Arrays and RawArrays. + """ + +
+[docs] + def __init__(self, max_size=10, dimension=6, head_tail_buffer=None, buffer=None): + """Stream system uses that to implement user interactions + + Parameters + ---------- + max_size : int, optional + If buffer_name or buffer was not passed then max_size + it's mandatory. This will be used to construct the + multidimensional buffer + dimension : int, default 8 + This will be used to construct the multidimensional buffer + head_tail_buffer : buffer, optional + If buffer is not passed to __init__ + then this obj will create a new + RawArray to store head and tail position. + buffer : buffer, optional + If buffer is not passed to __init__ + then the multidimensional buffer obj will create a new + RawArray to store the data + + """ + super().__init__(max_size, dimension, use_shared_mem=False, buffer=buffer) + + if head_tail_buffer is None: + self.create_mem_resource() + self._created = True + else: + self.head_tail_buffer = head_tail_buffer + self._created = False + + self.head_tail_buffer_name = None + self.head_tail_buffer_repr = self.head_tail_buffer + if self._created: + self.set_head_tail(-1, -1, 0)
+ + +
+[docs] + def load_mem_resource(self): + pass # pragma: no cover
+ + +
+[docs] + def create_mem_resource(self): + # head_tail_arr[0] int; head position + # head_tail_arr[1] int; tail position + head_tail_arr = np.array([-1, -1, 0], dtype=_INT_ShM_TYPE) + self.head_tail_buffer = multiprocessing.Array( + _INT_ShM_TYPE, + head_tail_arr, + )
+ + +
+[docs] + def enqueue(self, data): + ok = False + with self.head_tail_buffer.get_lock(): + ok = self._enqueue(data) + return ok
+ + +
+[docs] + def dequeue(self): + with self.head_tail_buffer.get_lock(): + interactions = self._dequeue() + return interactions
+ + +
+[docs] + def cleanup(self): + pass
+
+ + + +
+[docs] +class SharedMemCircularQueue(GenericCircularQueue): + """This implements a MultiDimensional Queue which works with + SharedMemory. + """ + +
+[docs] + def __init__( + self, max_size=10, dimension=6, head_tail_buffer_name=None, buffer_name=None + ): + """Stream system uses that to implement user interactions + + Parameters + ---------- + max_size : int, optional + If buffer_name or buffer was not passed then max_size + it's mandatory. This will be used to construct the + multidimensional buffer + dimension : int, default 8 + This will be used to construct the multidimensional buffer + head_tail_buffer_name : str, optional + if buffer_name is passed than this Obj will read a + a already created SharedMemory with the head and tail + information + buffer_name : str, optional + if buffer_name is passed than this Obj will read a + a already created SharedMemory to create the MultiDimensionalBuffer + + """ + super().__init__( + max_size, dimension, use_shared_mem=True, buffer_name=buffer_name + ) + + if head_tail_buffer_name is None: + self.create_mem_resource() + self._created = True + else: + self.head_tail_buffer_name = head_tail_buffer_name + self.load_mem_resource() + self._created = False + + self.head_tail_buffer_repr = np.ndarray( + 3, dtype=_INT_ShM_TYPE, buffer=self.head_tail_buffer.buf[0 : 3 * _INT_SIZE] + ) + logging.info( + [ + 'create shared mem', + 'size repr', + self.head_tail_buffer_repr.shape, + 'size buffer', + self.head_tail_buffer.size / _INT_SIZE, + ] + ) + if self._created: + self.set_head_tail(-1, -1, 0)
+ + +
+[docs] + def load_mem_resource(self): + self.head_tail_buffer = shared_memory.SharedMemory(self.head_tail_buffer_name)
+ + +
+[docs] + def create_mem_resource(self): + # head_tail_arr[0] int; head position + # head_tail_arr[1] int; tail position + head_tail_arr = np.array([-1, -1, 0], dtype=_INT_ShM_TYPE) + self.head_tail_buffer = shared_memory.SharedMemory( + create=True, size=head_tail_arr.nbytes + ) + self.head_tail_buffer_name = self.head_tail_buffer.name
+ + +
+[docs] + def is_unlocked(self): + return self.head_tail_buffer_repr[2] == 0
+ + +
+[docs] + def lock(self): + self.head_tail_buffer_repr[2] = 1
+ + +
+[docs] + def unlock(self): + self.head_tail_buffer_repr[2] = 0
+ + +
+[docs] + def enqueue(self, data): + ok = False + if self.is_unlocked(): + self.lock() + ok = self._enqueue(data) + self.unlock() + return ok
+ + +
+[docs] + def dequeue(self): + interactions = None + if self.is_unlocked(): + self.lock() + interactions = self._dequeue() + self.unlock() + return interactions
+ + +
+[docs] + def cleanup(self): + self.buffer.cleanup() + self.head_tail_buffer.close() + if self._created: + # this it's due the python core issues + # https://bugs.python.org/issue38119 + # https://bugs.python.org/issue39959 + # https://github.com/luizalabs/shared-memory-dict/issues/13 + try: + self.head_tail_buffer.unlink() + except FileNotFoundError: + print( + f'Shared Memory {self.head_tail_buffer_name}(head_tail)\ + File not found' + )
+
+ + + +
+[docs] +class GenericImageBufferManager(ABC): + """This implements a abstract (generic) ImageBufferManager with + the n-buffer technique. + """ + +
+[docs] + def __init__(self, max_window_size=None, num_buffers=2, use_shared_mem=False): + """Initialize the ImageBufferManager. + + Parameters + ---------- + max_window_size : tuple of ints, optional + This allows resize events inside of the FURY window instance. + Should be greater than the window size. + num_buffers : int, optional + Number of buffers to be used in the n-buffering + technique. + use_shared_mem: bool, default False + + """ + self.max_window_size = np.array(max_window_size) + self.num_buffers = num_buffers + self.info_buffer_size = num_buffers * 2 + 2 + self._use_shared_mem = use_shared_mem + self.max_size = None # int + self.num_components = 3 + self.image_reprs = [] + self.image_buffers = [] + self.image_buffer_names = [] + self.info_buffer_name = None + self.info_buffer = None + self.info_buffer_repr = None + self._created = False + + size = (self.max_window_size[0], self.max_window_size[1]) + img = Image.new('RGB', size, color=(0, 0, 0)) + + d = ImageDraw.Draw(img) + pos_text = (12, size[1] // 2) + d.text( + pos_text, 'Image size have exceed the Buffer Max Size', fill=(255, 255, 0) + ) + img = np.flipud(img) + self.img_exceed = np.asarray(img).flatten()
+ + + @property + def next_buffer_index(self): + index = int((self.info_buffer_repr[1] + 1) % self.num_buffers) + return index + + @property + def buffer_index(self): + index = self.info_buffer_repr[1] + return index + +
+[docs] + def write_into(self, w, h, np_arr): + buffer_size = buffer_size = int(h * w * 3) + next_buffer_index = self.next_buffer_index + + if buffer_size == self.max_size: + self.image_reprs[next_buffer_index][:] = np_arr + elif buffer_size < self.max_size: + self.image_reprs[next_buffer_index][0:buffer_size] = np_arr + else: + self.image_reprs[next_buffer_index][0 : self.max_size] = self.img_exceed + w = self.max_window_size[0] + h = self.max_window_size[1] + + self.info_buffer_repr[2 + next_buffer_index * 2] = w + self.info_buffer_repr[2 + next_buffer_index * 2 + 1] = h + self.info_buffer_repr[1] = next_buffer_index
+ + +
+[docs] + def get_current_frame(self): + """Get the current frame from the buffer.""" + if not self._use_shared_mem: + image_info = np.frombuffer(self.info_buffer, _UINT_ShM_TYPE) + else: + image_info = self.info_buffer_repr + + buffer_index = int(image_info[1]) + + self.width = int(image_info[2 + buffer_index * 2]) + self.height = int(image_info[2 + buffer_index * 2 + 1]) + + image = self.image_reprs[buffer_index] + self.image_buffer_repr = image + + return self.width, self.height, image
+ + +
+[docs] + def get_jpeg(self): + """Returns a jpeg image from the buffer. + + Returns + ------- + bytes: jpeg image. + + """ + width, height, image = self.get_current_frame() + + if self._use_shared_mem: + image = np.frombuffer(image, _BYTE_ShM_TYPE) + + image = image[0 : width * height * 3].reshape((height, width, 3)) + image = np.flipud(image) + image_encoded = Image.fromarray(image, mode='RGB') + bytes_img_data = io.BytesIO() + image_encoded.save(bytes_img_data, format='jpeg') + bytes_img = bytes_img_data.getvalue() + + return bytes_img
+ + +
+[docs] + async def async_get_jpeg(self, ms=33): + jpeg = self.get_jpeg() + await asyncio.sleep(ms / 1000) + return jpeg
+ + +
+[docs] + @abstractmethod + def load_mem_resource(self): + pass # pragma: no cover
+ + +
+[docs] + @abstractmethod + def create_mem_resource(self): + pass # pragma: no cover
+ + +
+[docs] + @abstractmethod + def cleanup(self): + pass # pragma: no cover
+
+ + + +
+[docs] +class RawArrayImageBufferManager(GenericImageBufferManager): + """This implements an ImageBufferManager using RawArrays.""" + +
+[docs] + def __init__( + self, + max_window_size=(100, 100), + num_buffers=2, + image_buffers=None, + info_buffer=None, + ): + """Initialize the ImageBufferManager. + + Parameters + ---------- + max_window_size : tuple of ints, optional + This allows resize events inside of the FURY window instance. + Should be greater than the window size. + num_buffers : int, optional + Number of buffers to be used in the n-buffering + technique. + info_buffer : buffer, optional + A buffer with the information about the current + frame to be streamed and the respective sizes + image_buffers : list of buffers, optional + A list of buffers with each one containing a frame. + + """ + super().__init__(max_window_size, num_buffers, use_shared_mem=False) + if image_buffers is None or info_buffer is None: + self.create_mem_resource() + else: + self.image_buffers = image_buffers + self.info_buffer = info_buffer + self.load_mem_resource()
+ + +
+[docs] + def create_mem_resource(self): + self.max_size = self.max_window_size[0] * self.max_window_size[1] + self.max_size *= self.num_components + + for _ in range(self.num_buffers): + buffer = multiprocessing.RawArray( + _BYTE_ShM_TYPE, + np.ctypeslib.as_ctypes( + np.random.randint(0, 255, size=self.max_size, dtype=_BYTE_ShM_TYPE) + ), + ) + self.image_buffers.append(buffer) + self.image_reprs.append(np.ctypeslib.as_array(buffer)) + + # info_list stores the information about the n frame buffers + # as well the respectives sizes. + # 0 number of components + # 1 id buffer + # 2, 3, width first buffer, height first buffer + # 4, 5, width second buffer , height second buffer + info_list = [3, 0] + for _ in range(self.num_buffers): + info_list += [self.max_window_size[0]] + info_list += [self.max_window_size[1]] + info_list = np.array(info_list, dtype=_UINT_ShM_TYPE) + self.info_buffer = multiprocessing.RawArray( + _UINT_ShM_TYPE, np.ctypeslib.as_ctypes(np.array(info_list)) + ) + self.info_buffer_repr = np.ctypeslib.as_array(self.info_buffer)
+ + +
+[docs] + def load_mem_resource(self): + self.info_buffer = np.frombuffer(self.info_buffer, _UINT_ShM_TYPE) + self.info_buffer_repr = np.ctypeslib.as_array(self.info_buffer) + for img_buffer in self.image_buffers: + self.image_reprs.append(np.ctypeslib.as_array(img_buffer))
+ + +
+[docs] + def cleanup(self): + pass
+
+ + + +
+[docs] +class SharedMemImageBufferManager(GenericImageBufferManager): + """This implements an ImageBufferManager using the + SharedMemory approach. + """ + +
+[docs] + def __init__( + self, + max_window_size=(100, 100), + num_buffers=2, + image_buffer_names=None, + info_buffer_name=None, + ): + """Initialize the ImageBufferManager. + + Parameters + ---------- + max_window_size : tuple of ints, optional + This allows resize events inside of the FURY window instance. + Should be greater than the window size. + num_buffers : int, optional + Number of buffers to be used in the n-buffering + technique. + info_buffer_name : str + The name of a buffer with the information about the current + frame to be streamed and the respective sizes + image_buffer_names : list of str, optional + a list of buffer names. Each buffer contains a frame + + Notes + ----- + Python >=3.8 is a requirement to use this object. + + """ + super().__init__(max_window_size, num_buffers, use_shared_mem=True) + if image_buffer_names is None or info_buffer_name is None: + self.create_mem_resource() + self._created = True + else: + self.image_buffer_names = image_buffer_names + self.info_buffer_name = info_buffer_name + self._created = False + self.load_mem_resource()
+ + +
+[docs] + def create_mem_resource(self): + self.max_size = self.max_window_size[0] * self.max_window_size[1] + self.max_size *= self.num_components + self.max_size = int(self.max_size) + for _ in range(self.num_buffers): + buffer = shared_memory.SharedMemory(create=True, size=self.max_size) + self.image_buffers.append(buffer) + self.image_reprs.append( + np.ndarray(self.max_size, dtype=_BYTE_ShM_TYPE, buffer=buffer.buf) + ) + self.image_buffer_names.append(buffer.name) + + info_list = [2 + self.num_buffers * 2, 1, 3, 0] + for _ in range(self.num_buffers): + info_list += [self.max_window_size[0]] + info_list += [self.max_window_size[1]] + info_list = np.array(info_list, dtype=_UINT_ShM_TYPE) + + self.info_buffer = shared_memory.SharedMemory( + create=True, size=info_list.nbytes + ) + sizes = np.ndarray( + 2, dtype=_UINT_ShM_TYPE, buffer=self.info_buffer.buf[0 : _UINT_SIZE * 2] + ) + sizes[0] = info_list[0] + sizes[1] = 1 + self.info_buffer_repr = np.ndarray( + sizes[0], + dtype=_UINT_ShM_TYPE, + buffer=self.info_buffer.buf[2 * _UINT_SIZE :], + ) + logging.info( + [ + 'info buffer create', + 'buffer size', + sizes[0], + 'repr size', + self.info_buffer_repr.shape, + ] + ) + self.info_buffer_name = self.info_buffer.name
+ + +
+[docs] + def load_mem_resource(self): + self.info_buffer = shared_memory.SharedMemory(self.info_buffer_name) + sizes = np.ndarray( + 2, dtype=_UINT_ShM_TYPE, buffer=self.info_buffer.buf[0 : _UINT_SIZE * 2] + ) + self.info_buffer_repr = np.ndarray( + sizes[0], + dtype=_UINT_ShM_TYPE, + buffer=self.info_buffer.buf[2 * _UINT_SIZE :], + ) + logging.info( + [ + 'info buffer load', + 'buffer size', + sizes[0], + 'repr size', + self.info_buffer_repr.shape, + ] + ) + for buffer_name in self.image_buffer_names: + buffer = shared_memory.SharedMemory(buffer_name) + self.image_buffers.append(buffer) + self.image_reprs.append( + np.ndarray( + buffer.size // _BYTE_SIZE, dtype=_BYTE_ShM_TYPE, buffer=buffer.buf + ) + )
+ + +
+[docs] + def cleanup(self): + """Release the resources used by the Shared Memory Manager""" + self.info_buffer.close() + # this it's due the python core issues + # https://bugs.python.org/issue38119 + # https://bugs.python.org/issue39959 + # https://github.com/luizalabs/shared-memory-dict/issues/13 + if self._created: + try: + self.info_buffer.unlink() + except FileNotFoundError: + print( + f'Shared Memory {self.info_buffer_name}\ + (info_buffer) File not found' + ) + for buffer, name in zip(self.image_buffers, self.image_buffer_names): + buffer.close() + if self._created: + try: + buffer.unlink() + except FileNotFoundError: + print(f'Shared Memory {name}(buffer image) File not found')
+
+ + + +
+[docs] +class IntervalTimerThreading: + """Implements a object with the same behavior of setInterval from Js""" + +
+[docs] + def __init__(self, seconds, callback, *args, **kwargs): + """ + + Parameters + ---------- + seconds : float + A positive float number. Represents the total amount of + seconds between each call + callback : function + The function to be called + *args : args + args to be passed to callback + **kwargs : kwargs + kwargs to be passed to callback + + Examples + -------- + + .. code-block:: python + + def callback(arr): + arr += [len(arr)] + arr = [] + interval_timer = tools.IntervalTimer(1, callback, arr) + interval_timer.start() + time.sleep(5) + interval_timer.stop() + # len(arr) == 5 + + References + ----------- + [1] https://stackoverflow.com/questions/3393612/run-certain-code-every-n-seconds + + """ # noqa + self._timer = None + self.seconds = seconds + self.callback = callback + self.args = args + self.kwargs = kwargs + self.is_running = False + self.start()
+ + + def _run(self): + self.is_running = False + self.start() + self.callback(*self.args, **self.kwargs) + +
+[docs] + def start(self): + """Start the timer""" + if self.is_running: + return + + self._timer = Timer(self.seconds, self._run) + self._timer.daemon = True + self._timer.start() + self.is_running = True
+ + +
+[docs] + def stop(self): + """Stop the timer""" + if self._timer is None: + return + + self._timer.cancel() + if self._timer.is_alive(): + self._timer.join() + self.is_running = False + self._timer = None
+
+ + + +
+[docs] +class IntervalTimer: + """A object that creates a timer that calls a function periodically.""" + +
+[docs] + def __init__(self, seconds, callback, *args, **kwargs): + """Parameters + ---------- + seconds : float + A positive float number. Represents the total amount of + seconds between each call + callback : function + The function to be called + *args : args + args to be passed to callback + **kwargs : kwargs + kwargs to be passed to callback + + """ + self._seconds = seconds + self._callback = callback + self.args = args + self.kwargs = kwargs + self._is_running = False + self.start()
+ + + async def _run(self): + self._is_running = True + while True: + await asyncio.sleep(self._seconds) + if self._is_running: + self._callback(*self.args, **self.kwargs) + +
+[docs] + def start(self): + """Start the timer""" + if self._is_running: + return + self._loop = asyncio.get_event_loop() + self._task = self._loop.create_task(self._run())
+ + +
+[docs] + def stop(self): + """Stop the timer""" + self._task.cancel() + self._is_running = False
+
+ +
+
+ + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/_modules/fury/stream/widget.html b/v0.10.x/_modules/fury/stream/widget.html new file mode 100644 index 000000000..c7226cbad --- /dev/null +++ b/v0.10.x/_modules/fury/stream/widget.html @@ -0,0 +1,740 @@ + + + + + + + fury.stream.widget — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +

Source code for fury.stream.widget

+import errno
+import socket
+import subprocess
+import sys
+import time
+
+import numpy as np
+
+try:
+    from IPython.display import IFrame, display
+
+    IPYTHON_AVAILABLE = True
+except ImportError:
+    IPYTHON_AVAILABLE = False
+
+from fury.stream.client import FuryStreamClient, FuryStreamInteraction
+from fury.stream.constants import PY_VERSION_8
+
+
+
+[docs] +def check_port_is_available(host, port): + """Check if a given port it's available + + Parameters + ---------- + host : str + port : int + + Returns + ------- + available : bool + + """ + available = True + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + try: + s.bind((host, port)) + except socket.error as error: + if error.errno == errno.EADDRINUSE: + available = False + s.close() + return available
+ + + +
+[docs] +class Widget: + """This Obj it's able execute the fury streaming system + using the SharedMemory object from Python multiprocessing. + """ + +
+[docs] + def __init__( + self, + showm, + ms_stream=33, + ms_interaction=33, + host='localhost', + port=None, + encoding='mjpeg', + ms_jpeg=33, + queue_size=20, + ): + """Initialize the widget. + + Parameters + ---------- + showm : ShowmManager + ms_stream : float, optional + time in mileseconds between each frame buffer update. + ms_interaction : float, optional + time in mileseconds between each user interaction update. + host : str, optional + port : int, optional + encoding : str, optional + If should use MJPEG streaming or WebRTC. + ms_jpeg : float, optional + This it's used only if the MJPEG will be used. The + ms_jpeg represents the amount of milliseconds between to + consecutive calls of the jpeg encoding. + queue_size : int, optional + maximum number of user interactions to be stored + + """ + if not PY_VERSION_8: + raise ImportError( + 'Python 3.8 or greater is required to use the\ + widget class' + ) + self.showm = showm + self.window_size = self.showm.size + max_window_size = ( + int(self.window_size[0] * (1 + 0.1)), + int(self.window_size[1] * (1 + 0.1)), + ) + self.max_window_size = max_window_size + self.ms_stream = ms_stream + self.ms_interaction = ms_interaction + self.ms_jpeg = ms_jpeg + self._host = host + if port is None: + port = np.random.randint(7000, 8888) + self._port = port + self.queue_size = queue_size + self._server_started = False + self.pserver = None + self.encoding = encoding + self.showm.window.SetOffScreenRendering(1) + self.showm.iren.EnableRenderOff()
+ + + @property + def command_string(self): + """Return the command string to start the server + + Returns + ------- + command_string : str + + """ + s = 'from fury.stream.server import web_server;' + s += 'web_server(image_buffer_names=' + s += f'{self.stream.img_manager.image_buffer_names}' + s += f",info_buffer_name='{self.stream.img_manager.info_buffer_name}'," + s += "queue_head_tail_buffer_name='" + s += f"{self.stream_interaction.circular_queue.head_tail_buffer_name}'" + s += ",queue_buffer_name='" + s += f"{self.stream_interaction.circular_queue.buffer.buffer_name}'" + if self.encoding == 'mjpeg': + s += ',provides_mjpeg=True' + s += f',ms_jpeg={self.ms_jpeg}' + s += ',provides_webrtc=False' + s += f",port={self._port},host='{self._host}'," + s += 'avoid_unlink_shared_mem=True' + s += ')' + return s + + def _start_fury_client(self, use_asyncio=False): + """Start the fury image buffer client and the interaction client + + Parameters + ---------- + use_asyncio : bool, optional + If should use asyncio to start the server. + Default is False. + + """ + if self._server_started: + self.stop() + + self.stream = FuryStreamClient( + self.showm, + max_window_size=self.max_window_size, + use_raw_array=False, + whithout_iren_start=True, + ) + self.stream_interaction = FuryStreamInteraction( + self.showm, + max_queue_size=self.queue_size, + whithout_iren_start=True, + use_raw_array=False, + ) + + self.stream_interaction.start(ms=self.ms_interaction, use_asyncio=use_asyncio) + self.stream.start(self.ms_stream, use_asyncio=use_asyncio) + self._server_started = True + self.pserver = None + +
+[docs] + def run_command(self): + """Evaluate the command string to start the server""" + if self.pserver is not None: + self._kill_server() + + i = 0 + available = check_port_is_available(self._host, self._port) + while not available and i < 50: + self._port = np.random.randint(7000, 8888) + available = check_port_is_available(self._host, self._port) + i += 1 + if not available: + return False + + if self._server_started: + args = [sys.executable, '-c', self.command_string] + self.pserver = subprocess.Popen( + args, + # f'python -c "{self.command_string}"', + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + shell=False, + ) + return True
+ + + @property + def url(self): + """Return the url to access the server""" + url = f'http://{self._host}:{self._port}' + url += f'?iframe=1&encoding={self.encoding}' + return url + +
+[docs] + def return_iframe(self, height=200): + """Return the jupyter div iframe used to show the stream""" + if IPYTHON_AVAILABLE: + display(IFrame(self.url, '100%', f'{int(height)}px'))
+ + +
+[docs] + def start(self, use_asyncio=False): + """Start the fury client and the interaction client and return the url + + Parameters + ---------- + use_asyncio : bool, optional + If should use the asyncio version of the server. + Default is False. + + """ + self._start_fury_client(use_asyncio) + ok = self.run_command() + if not ok: + self.stop() + return False + print(f'url: {self.url}')
+ + +
+[docs] + def display(self, height=150): + """Start the server and display the url in an iframe""" + self._start_fury_client() + ok = self.run_command() + if not ok: + self.stop() + return False + time.sleep(2) + self.return_iframe(height)
+ + +
+[docs] + def stop(self): + """Stop the streaming server and release the shared memory""" + if self._server_started: + self.stream.stop() + self.stream_interaction.stop() + + if self.pserver is not None: + self._kill_server() + self.cleanup() + self._server_started = False
+ + + def _kill_server(self): + """Kill the server process""" + self.pserver.kill() + self.pserver.wait() + self.pserver = None + +
+[docs] + def cleanup(self): + """Release the shared memory""" + if self.stream is not None: + self.stream.cleanup() + + if self.stream_interaction is not None: + self.stream_interaction.cleanup()
+ + + def __del__(self): + self.stop()
+ +
+
+ + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/_modules/fury/transform.html b/v0.10.x/_modules/fury/transform.html new file mode 100644 index 000000000..50972a8fb --- /dev/null +++ b/v0.10.x/_modules/fury/transform.html @@ -0,0 +1,877 @@ + + + + + + + fury.transform — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +

Source code for fury.transform

+import math
+
+import numpy as np
+from scipy.spatial.transform import Rotation as Rot  # type: ignore
+
+# axis sequences for Euler angles
+_NEXT_AXIS = [1, 2, 0, 1]
+
+# map axes strings to/from tuples of inner axis, parity, repetition, frame
+_AXES2TUPLE = {
+    'sxyz': (0, 0, 0, 0),
+    'sxyx': (0, 0, 1, 0),
+    'sxzy': (0, 1, 0, 0),
+    'sxzx': (0, 1, 1, 0),
+    'syzx': (1, 0, 0, 0),
+    'syzy': (1, 0, 1, 0),
+    'syxz': (1, 1, 0, 0),
+    'syxy': (1, 1, 1, 0),
+    'szxy': (2, 0, 0, 0),
+    'szxz': (2, 0, 1, 0),
+    'szyx': (2, 1, 0, 0),
+    'szyz': (2, 1, 1, 0),
+    'rzyx': (0, 0, 0, 1),
+    'rxyx': (0, 0, 1, 1),
+    'ryzx': (0, 1, 0, 1),
+    'rxzx': (0, 1, 1, 1),
+    'rxzy': (1, 0, 0, 1),
+    'ryzy': (1, 0, 1, 1),
+    'rzxy': (1, 1, 0, 1),
+    'ryxy': (1, 1, 1, 1),
+    'ryxz': (2, 0, 0, 1),
+    'rzxz': (2, 0, 1, 1),
+    'rxyz': (2, 1, 0, 1),
+    'rzyz': (2, 1, 1, 1),
+}
+
+_TUPLE2AXES = dict((v, k) for k, v in _AXES2TUPLE.items())
+
+
+
+[docs] +def euler_matrix(ai, aj, ak, axes='sxyz'): + """Return homogeneous rotation matrix from Euler angles and axis sequence. + + Code modified from the work of Christoph Gohlke link provided here + http://www.lfd.uci.edu/~gohlke/code/transformations.py.html + + Parameters + ---------- + ai, aj, ak : Euler's roll, pitch and yaw angles + axes : One of 24 axis sequences as string or encoded tuple + + Returns + ------- + matrix : ndarray (4, 4) + + Code modified from the work of Christoph Gohlke link provided here + http://www.lfd.uci.edu/~gohlke/code/transformations.py.html + + Examples + -------- + >>> import numpy + >>> R = euler_matrix(1, 2, 3, 'syxz') + >>> numpy.allclose(numpy.sum(R[0]), -1.34786452) + True + >>> R = euler_matrix(1, 2, 3, (0, 1, 0, 1)) + >>> numpy.allclose(numpy.sum(R[0]), -0.383436184) + True + >>> ai, aj, ak = (4.0*math.pi) * (numpy.random.random(3) - 0.5) + >>> for axes in _AXES2TUPLE.keys(): + ... _ = euler_matrix(ai, aj, ak, axes) + >>> for axes in _TUPLE2AXES.keys(): + ... _ = euler_matrix(ai, aj, ak, axes) + + """ + try: + firstaxis, parity, repetition, frame = _AXES2TUPLE[axes] + except (AttributeError, KeyError): + firstaxis, parity, repetition, frame = axes + + i = firstaxis + j = _NEXT_AXIS[i + parity] + k = _NEXT_AXIS[i - parity + 1] + + if frame: + ai, ak = ak, ai + if parity: + ai, aj, ak = -ai, -aj, -ak + + si, sj, sk = math.sin(ai), math.sin(aj), math.sin(ak) + ci, cj, ck = math.cos(ai), math.cos(aj), math.cos(ak) + cc, cs = ci * ck, ci * sk + sc, ss = si * ck, si * sk + + M = np.identity(4) + if repetition: + M[i, i] = cj + M[i, j] = sj * si + M[i, k] = sj * ci + M[j, i] = sj * sk + M[j, j] = -cj * ss + cc + M[j, k] = -cj * cs - sc + M[k, i] = -sj * ck + M[k, j] = cj * sc + cs + M[k, k] = cj * cc - ss + else: + M[i, i] = cj * ck + M[i, j] = sj * sc - cs + M[i, k] = sj * cc + ss + M[j, i] = cj * sk + M[j, j] = sj * ss + cc + M[j, k] = sj * cs - sc + M[k, i] = -sj + M[k, j] = cj * si + M[k, k] = cj * ci + return M
+ + + +
+[docs] +def sphere2cart(r, theta, phi): + """Spherical to Cartesian coordinates. + + This is the standard physics convention where `theta` is the + inclination (polar) angle, and `phi` is the azimuth angle. + + Imagine a sphere with center (0,0,0). Orient it with the z axis + running south-north, the y axis running west-east and the x axis + from posterior to anterior. `theta` (the inclination angle) is the + angle to rotate from the z-axis (the zenith) around the y-axis, + towards the x axis. Thus the rotation is counter-clockwise from the + point of view of positive y. `phi` (azimuth) gives the angle of + rotation around the z-axis towards the y axis. The rotation is + counter-clockwise from the point of view of positive z. + + Equivalently, given a point P on the sphere, with coordinates x, y, + z, `theta` is the angle between P and the z-axis, and `phi` is + the angle between the projection of P onto the XY plane, and the X + axis. + + Geographical nomenclature designates theta as 'co-latitude', and phi + as 'longitude' + + Parameters + ---------- + r : array_like + radius + theta : array_like + inclination or polar angle + phi : array_like + azimuth angle + + Returns + ------- + x : array + x coordinate(s) in Cartesian space + y : array + y coordinate(s) in Cartesian space + z : array + z coordinate + + Notes + ----- + See these pages: + + * http://en.wikipedia.org/wiki/Spherical_coordinate_system + * http://mathworld.wolfram.com/SphericalCoordinates.html + + for excellent discussion of the many different conventions + possible. Here we use the physics conventions, used in the + wikipedia page. + + Derivations of the formulae are simple. Consider a vector x, y, z of + length r (norm of x, y, z). The inclination angle (theta) can be + found from: cos(theta) == z / r -> z == r * cos(theta). This gives + the hypotenuse of the projection onto the XY plane, which we will + call Q. Q == r*sin(theta). Now x / Q == cos(phi) -> x == r * + sin(theta) * cos(phi) and so on. + + We have deliberately named this function ``sphere2cart`` rather than + ``sph2cart`` to distinguish it from the Matlab function of that + name, because the Matlab function uses an unusual convention for the + angles that we did not want to replicate. The Matlab function is + trivial to implement with the formulae given in the Matlab help. + + """ + sin_theta = np.sin(theta) + x = r * np.cos(phi) * sin_theta + y = r * np.sin(phi) * sin_theta + z = r * np.cos(theta) + x, y, z = np.broadcast_arrays(x, y, z) + return x, y, z
+ + + +
+[docs] +def cart2sphere(x, y, z): + r"""Return angles for Cartesian 3D coordinates `x`, `y`, and `z`. + + See doc for ``sphere2cart`` for angle conventions and derivation + of the formulae. + + $0\le\theta\mathrm{(theta)}\le\pi$ and $-\pi\le\phi\mathrm{(phi)}\le\pi$ + + Parameters + ---------- + x : array_like + x coordinate in Cartesian space + y : array_like + y coordinate in Cartesian space + z : array_like + z coordinate + + Returns + ------- + r : array + radius + theta : array + inclination (polar) angle + phi : array + azimuth angle + + """ + r = np.sqrt(x * x + y * y + z * z) + theta = np.arccos(np.divide(z, r, where=r > 0)) + theta = np.where(r > 0, theta, 0.0) + phi = np.arctan2(y, x) + r, theta, phi = np.broadcast_arrays(r, theta, phi) + return r, theta, phi
+ + + +
+[docs] +def translate(translation): + """Return transformation matrix for translation array. + + Parameters + ---------- + translation : ndarray + translation in x, y and z directions. + + Returns + ------- + translation : ndarray (4, 4) + Numpy array of shape 4,4 containing translation parameter in the last + column of the matrix. + + Examples + -------- + >>> import numpy as np + >>> tran = np.array([0.3, 0.2, 0.25]) + >>> transform = translate(tran) + >>> transform + >>> [[1. 0. 0. 0.3 ] + [0. 1. 0. 0.2 ] + [0. 0. 1. 0.25] + [0. 0. 0. 1. ]] + + """ + iden = np.identity(4) + translation = np.append(translation, 0).reshape(-1, 1) + + t = np.array([[0, 0, 0, 1], [0, 0, 0, 1], [0, 0, 0, 1], [0, 0, 0, 1]], np.float32) + translation = np.multiply(t, translation) + translation = np.add(iden, translation) + + return translation
+ + + +
+[docs] +def rotate(quat): + """Return transformation matrix for rotation quaternion. + + Parameters + ---------- + quat : ndarray (4, ) + rotation quaternion. + + Returns + ------- + rotation_mat : ndarray (4, 4) + Transformation matrix of shape (4, 4) to rotate a vector. + + Examples + -------- + >>> import numpy as np + >>> quat = np.array([0.259, 0.0, 0.0, 0.966]) + >>> rotation = rotate(quat) + >>> rotation + >>> [[1. 0. 0. 0.] + [0. 0.866 -0.5 0.] + [0. 0.5 0.866 0.] + [0. 0. 0. 1.]] + + """ + iden = np.identity(3) + rotation_mat = Rot.from_quat(quat).as_matrix() + + iden = np.append(iden, [[0, 0, 0]]).reshape(-1, 3) + + rotation_mat = np.dot(iden, rotation_mat) + iden = np.array([[0, 0, 0, 1]]).reshape(-1, 1) + + rotation_mat = np.concatenate((rotation_mat, iden), axis=1) + return rotation_mat
+ + + +
+[docs] +def scale(scales): + """Return transformation matrix for scales array. + + Parameters + ---------- + scales : ndarray + scales in x, y and z directions. + + Returns + ------- + scale_mat : ndarray (4, 4) + Numpy array of shape 4,4 containing elements of scale matrix along + the diagonal. + + Examples + -------- + >>> import numpy as np + >>> scales = np.array([2.0, 1.0, 0.5]) + >>> transform = scale(scales) + >>> transform + >>> [[2. 0. 0. 0.] + [0. 1. 0. 0.] + [0. 0. 0.5 0.] + [0. 0. 0. 1.]] + + """ + scale_mat = np.identity(4) + scales = np.append(scales, [1]) + + for i in range(len(scales)): + scale_mat[i][i] = scales[i] + + return scale_mat
+ + + +
+[docs] +def apply_transformation(vertices, transformation): + """Multiplying transformation matrix with vertices + + Parameters + ---------- + vertices : ndarray (n, 3) + vertices of the mesh + transformation : ndarray (4, 4) + transformation matrix + + Returns + ------- + vertices : ndarray (n, 3) + transformed vertices of the mesh + + """ + shape = vertices.shape + temp = np.full((shape[0], 1), 1) + vertices = np.concatenate((vertices, temp), axis=1) + + vertices = np.dot(transformation, vertices.T) + vertices = vertices.T + vertices = vertices[:, : shape[1]] + + return vertices
+ + + +
+[docs] +def transform_from_matrix(matrix): + """Returns translation, rotation and scale arrays from transformation + matrix. + + Parameters + ---------- + matrix : ndarray (4, 4) + the transformation matrix of shape 4*4 + + Returns + ------- + translate : ndarray (3, ) + translation component from the transformation matrix + rotate : ndarray (4, ) + rotation component from the transformation matrix + scale : ndarray (3, ) + scale component from the transformation matrix. + + """ + translate = matrix[:, -1:].reshape((-1,))[:-1] + + temp = matrix[:, :3][:3] + sx = np.linalg.norm(temp[:, :1]) + sy = np.linalg.norm(temp[:, 1:-1]) + sz = np.linalg.norm(temp[:, -1:]) + scale = np.array([sx, sy, sz]) + + rot_matrix = temp / scale[None, :] + rotation = Rot.from_matrix(rot_matrix) + rot_vec = rotation.as_rotvec() + angle = np.linalg.norm(rot_vec) + rotation = [np.rad2deg(angle), *rot_vec] + + return translate, rotation, scale
+ +
+
+ + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/_modules/fury/ui/containers.html b/v0.10.x/_modules/fury/ui/containers.html new file mode 100644 index 000000000..3e2c53106 --- /dev/null +++ b/v0.10.x/_modules/fury/ui/containers.html @@ -0,0 +1,1789 @@ + + + + + + + fury.ui.containers — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +

Source code for fury.ui.containers

+"""UI container module."""
+
+__all__ = ['Panel2D', 'TabPanel2D', 'TabUI', 'ImageContainer2D', 'GridUI']
+
+import numpy as np
+
+from fury.actor import grid
+from fury.io import load_image
+from fury.lib import (
+    CellArray,
+    FloatArray,
+    Points,
+    PolyData,
+    PolyDataMapper2D,
+    Property2D,
+    Texture,
+    TexturedActor2D,
+)
+from fury.ui.core import UI, Rectangle2D, TextBlock2D
+from fury.utils import rotate, set_input
+
+
+
+[docs] +class Panel2D(UI): + """A 2D UI Panel. + + Can contain one or more UI elements. + + Attributes + ---------- + alignment : [left, right] + Alignment of the panel with respect to the overall screen. + + """ + +
+[docs] + def __init__( + self, + size, + position=(0, 0), + color=(0.1, 0.1, 0.1), + opacity=0.7, + align='left', + border_color=(1, 1, 1), + border_width=0, + has_border=False, + ): + """Init class instance. + + Parameters + ---------- + size : (int, int) + Size (width, height) in pixels of the panel. + position : (float, float) + Absolute coordinates (x, y) of the lower-left corner of the panel. + color : (float, float, float) + Must take values in [0, 1]. + opacity : float + Must take values in [0, 1]. + align : [left, right] + Alignment of the panel with respect to the overall screen. + border_color: (float, float, float), optional + Must take values in [0, 1]. + border_width: float, optional + width of the border + has_border: bool, optional + If the panel should have borders. + + """ + self.has_border = has_border + self._border_color = border_color + self._border_width = border_width + super(Panel2D, self).__init__(position) + self.resize(size) + self.alignment = align + self.color = color + self.opacity = opacity + self.position = position + self._drag_offset = None
+ + + def _setup(self): + """Setup this UI component. + + Create the background (Rectangle2D) of the panel. + Create the borders (Rectangle2D) of the panel. + """ + self._elements = [] + self.element_offsets = [] + self.background = Rectangle2D() + + if self.has_border: + self.borders = { + 'left': Rectangle2D(), + 'right': Rectangle2D(), + 'top': Rectangle2D(), + 'bottom': Rectangle2D(), + } + + self.border_coords = { + 'left': (0.0, 0.0), + 'right': (1.0, 0.0), + 'top': (0.0, 1.0), + 'bottom': (0.0, 0.0), + } + + for key in self.borders.keys(): + self.borders[key].color = self._border_color + self.add_element(self.borders[key], self.border_coords[key]) + + for key in self.borders.keys(): + self.borders[ + key + ].on_left_mouse_button_pressed = self.left_button_pressed + + self.borders[ + key + ].on_left_mouse_button_dragged = self.left_button_dragged + + self.add_element(self.background, (0, 0)) + + # Add default events listener for this UI component. + self.background.on_left_mouse_button_pressed = self.left_button_pressed + self.background.on_left_mouse_button_dragged = self.left_button_dragged + + def _get_actors(self): + """Get the actors composing this UI component.""" + actors = [] + for element in self._elements: + actors += element.actors + + return actors + + def _add_to_scene(self, scene): + """Add all subcomponents or VTK props that compose this UI component. + + Parameters + ---------- + scene : scene + + """ + for element in self._elements: + element.add_to_scene(scene) + + def _get_size(self): + return self.background.size + +
+[docs] + def resize(self, size): + """Set the panel size. + + Parameters + ---------- + size : (float, float) + Panel size (width, height) in pixels. + + """ + self.background.resize(size) + + if self.has_border: + self.borders['left'].resize( + (self._border_width, size[1] + self._border_width) + ) + + self.borders['right'].resize( + (self._border_width, size[1] + self._border_width) + ) + + self.borders['top'].resize( + (self.size[0] + self._border_width, self._border_width) + ) + + self.borders['bottom'].resize( + (self.size[0] + self._border_width, self._border_width) + ) + + self.update_border_coords()
+ + + def _set_position(self, coords): + """Set the lower-left corner position of this UI component. + + Parameters + ---------- + coords: (float, float) + Absolute pixel coordinates (x, y). + + """ + coords = np.array(coords) + for element, offset in self.element_offsets: + element.position = coords + offset + +
+[docs] + def set_visibility(self, visibility): + for element in self._elements: + element.set_visibility(visibility)
+ + + @property + def color(self): + return self.background.color + + @color.setter + def color(self, color): + self.background.color = color + + @property + def opacity(self): + return self.background.opacity + + @opacity.setter + def opacity(self, opacity): + self.background.opacity = opacity + +
+[docs] + def add_element(self, element, coords, anchor='position'): + """Add a UI component to the panel. + + The coordinates represent an offset from the lower left corner of the + panel. + + Parameters + ---------- + element : UI + The UI item to be added. + coords : (float, float) or (int, int) + If float, normalized coordinates are assumed and they must be + between [0,1]. + If int, pixels coordinates are assumed and it must fit within the + panel's size. + + """ + coords = np.array(coords) + + if np.issubdtype(coords.dtype, np.floating): + if np.any(coords < 0) or np.any(coords > 1): + raise ValueError('Normalized coordinates must be in [0,1].') + + coords = coords * self.size + + if anchor == 'center': + element.center = self.position + coords + elif anchor == 'position': + element.position = self.position + coords + else: + msg = "Unknown anchor {}. Supported anchors are 'position'" " and 'center'." + raise ValueError(msg) + + self._elements.append(element) + offset = element.position - self.position + self.element_offsets.append((element, offset))
+ + +
+[docs] + def remove_element(self, element): + """Remove a UI component from the panel. + + Parameters + ---------- + element : UI + The UI item to be removed. + + """ + idx = self._elements.index(element) + del self._elements[idx] + del self.element_offsets[idx]
+ + +
+[docs] + def update_element(self, element, coords, anchor='position'): + """Update the position of a UI component in the panel. + + Parameters + ---------- + element : UI + The UI item to be updated. + coords : (float, float) or (int, int) + New coordinates. + If float, normalized coordinates are assumed and they must be + between [0,1]. + If int, pixels coordinates are assumed and it must fit within the + panel's size. + + """ + self.remove_element(element) + self.add_element(element, coords, anchor)
+ + +
+[docs] + def left_button_pressed(self, i_ren, _obj, panel2d_object): + click_pos = np.array(i_ren.event.position) + self._drag_offset = click_pos - self.position + i_ren.event.abort() # Stop propagating the event.
+ + +
+[docs] + def left_button_dragged(self, i_ren, _obj, _panel2d_object): + if self._drag_offset is not None: + click_position = np.array(i_ren.event.position) + new_position = click_position - self._drag_offset + self.position = new_position + i_ren.force_render()
+ + +
+[docs] + def re_align(self, window_size_change): + """Re-organise the elements in case the window size is changed. + + Parameters + ---------- + window_size_change : (int, int) + New window size (width, height) in pixels. + + """ + if self.alignment == 'left': + pass + elif self.alignment == 'right': + self.position += np.array(window_size_change) + else: + msg = 'You can only left-align or right-align objects in a panel.' + raise ValueError(msg)
+ + +
+[docs] + def update_border_coords(self): + """Update the coordinates of the borders""" + self.border_coords = { + 'left': (0.0, 0.0), + 'right': (1.0, 0.0), + 'top': (0.0, 1.0), + 'bottom': (0.0, 0.0), + } + + for key in self.borders.keys(): + self.update_element(self.borders[key], self.border_coords[key])
+ + + @property + def border_color(self): + sides = ['left', 'right', 'top', 'bottom'] + return [self.borders[side].color for side in sides] + + @border_color.setter + def border_color(self, side_color): + """Set the color of a specific border + + Parameters + ---------- + side_color: Iterable + Iterable to pack side, color values + + """ + side, color = side_color + + if side.lower() not in ['left', 'right', 'top', 'bottom']: + raise ValueError(f'{side} not a valid border side') + + self.borders[side].color = color + + @property + def border_width(self): + sides = ['left', 'right', 'top', 'bottom'] + widths = [] + + for side in sides: + if side in ['left', 'right']: + widths.append(self.borders[side].width) + elif side in ['top', 'bottom']: + widths.append(self.borders[side].height) + else: + raise ValueError(f'{side} not a valid border side') + return widths + + @border_width.setter + def border_width(self, side_width): + """Set the border width of a specific border + + Parameters + ---------- + side_width: Iterable + Iterable to pack side, width values + + """ + side, border_width = side_width + + if side.lower() in ['left', 'right']: + self.borders[side].width = border_width + elif side.lower() in ['top', 'bottom']: + self.borders[side].height = border_width + else: + raise ValueError(f'{side} not a valid border side')
+ + + +
+[docs] +class TabPanel2D(UI): + """Render content within a Tab. + + Attributes + ---------- + content_panel: :class: 'Panel2D' + Hold all the content UI components. + text_block: :class: 'TextBlock2D' + Renders the title of the tab. + + """ + +
+[docs] + def __init__( + self, + position=(0, 0), + size=(100, 100), + title='New Tab', + color=(0.5, 0.5, 0.5), + content_panel=None, + ): + """Init class instance. + + Parameters + ---------- + position : (float, float) + Absolute coordinates (x, y) of the lower-left corner of the + UI component + size : (int, int) + Width and height of the pixels of this UI component. + title : str + Renders the title for Tab panel. + color : list of 3 floats + Background color of tab panel. + content_panel : Panel2D + Panel consisting of the content UI elements. + + """ + self.content_panel = content_panel + self.panel_size = size + self._text_size = (int(1.0 * size[0]), size[1]) + + super(TabPanel2D, self).__init__() + self.title = title + self.panel.position = position + self.color = color
+ + + def _setup(self): + """Setup this UI component. + + Create parent panel. + Create Text to hold tab information. + Create Button to close tab. + + """ + self.panel = Panel2D(size=self.panel_size) + self.text_block = TextBlock2D(size=self._text_size, color=(0, 0, 0)) + self.panel.add_element(self.text_block, (0, 0)) + + def _get_actors(self): + """Get the actors composing this UI component.""" + return self.panel.actors + self.content_panel.actors + + def _add_to_scene(self, _scene): + """Add all subcomponents or VTK props that compose this UI component. + + Parameters + ---------- + scene : scene + + """ + self.panel.add_to_scene(_scene) + self.content_panel.add_to_scene(_scene) + + def _set_position(self, _coords): + """Set the lower-left corner position of this UI component. + + Parameters + ---------- + coords: (float, float) + Absolute pixel coordinates (x, y). + + """ + self.panel.position = _coords + + def _get_size(self): + self.panel.size + +
+[docs] + def resize(self, size): + """Resize Tab panel. + + Parameters + ---------- + size : (int, int) + New width and height in pixels. + + """ + self._text_size = (int(0.7 * size[0]), size[1]) + self._button_size = (int(0.3 * size[0]), size[1]) + self.panel.resize(size) + self.text_block.resize(self._text_size)
+ + + @property + def color(self): + """Return the background color of tab panel.""" + return self.panel.color + + @color.setter + def color(self, color): + """Set background color of tab panel. + + Parameters + ---------- + color : list of 3 floats. + + """ + self.panel.color = color + + @property + def title(self): + """Return the title of tab panel.""" + return self.text_block.message + + @title.setter + def title(self, text): + """Set the title of tab panel. + + Parameters + ---------- + text : str + New title for tab panel. + + """ + self.text_block.message = text + + @property + def title_bold(self): + """Is the title of a tab panel bold.""" + return self.text_block.bold + + @title_bold.setter + def title_bold(self, bold): + """Determine if the text title of a tab panel must be bold. + + Parameters + ---------- + bold : bool + Bold property for a text title in a tab panel. + + """ + self.text_block.bold = bold + + @property + def title_color(self): + """Return the title color of tab panel.""" + return self.text_block.color + + @title_color.setter + def title_color(self, color): + """Set the title color of tab panel. + + Parameters + ---------- + color : tuple + New title color for tab panel. + + """ + self.text_block.color = color + + @property + def title_font_size(self): + """Return the title font size of tab panel.""" + return self.text_block.font_size + + @title_font_size.setter + def title_font_size(self, font_size): + """Set the title font size of tab panel. + + Parameters + ---------- + font_size : int + New title font size for tab panel. + + """ + self.text_block.font_size = font_size + + @property + def title_italic(self): + """Is the title of a tab panel italic.""" + return self.text_block.italic + + @title_italic.setter + def title_italic(self, italic): + """Determine if the text title of a tab panel must be italic. + + Parameters + ---------- + italic : bool + Italic property for a text title in a tab panel. + + """ + self.text_block.italic = italic + +
+[docs] + def add_element(self, element, coords, anchor='position'): + """Add a UI component to the content panel. + + The coordinates represent an offset from the lower left corner of the + panel. + + Parameters + ---------- + element : UI + The UI item to be added. + coords : (float, float) or (int, int) + If float, normalized coordinates are assumed and they must be + between [0,1]. + If int, pixels coordinates are assumed and it must fit within the + panel's size. + + """ + element.set_visibility(False) + self.content_panel.add_element(element, coords, anchor)
+ + +
+[docs] + def remove_element(self, element): + """Remove a UI component from the content panel. + + Parameters + ---------- + element : UI + The UI item to be removed. + + """ + self.content_panel.remove_element(element)
+ + +
+[docs] + def update_element(self, element, coords, anchor='position'): + """Update the position of a UI component in the content panel. + + Parameters + ---------- + element : UI + The UI item to be updated. + coords : (float, float) or (int, int) + New coordinates. + If float, normalized coordinates are assumed and they must be + between [0,1]. + If int, pixels coordinates are assumed and it must fit within the + panel's size. + + """ + self.content_panel.update_element(element, coords, anchor='position')
+
+ + + +
+[docs] +class TabUI(UI): + """UI element to add multiple panels within a single window. + + Attributes + ---------- + tabs: :class: List of 'TabPanel2D' + Stores all the instances of 'TabPanel2D' that renders the contents. + + """ + +
+[docs] + def __init__( + self, + position=(0, 0), + size=(100, 100), + nb_tabs=1, + active_color=(1, 1, 1), + inactive_color=(0.5, 0.5, 0.5), + draggable=False, + startup_tab_id=None, + ): + """Init class instance. + + Parameters + ---------- + position : (float, float) + Absolute coordinates (x, y) of the lower-left corner of this + UI component. + size : (int, int) + Width and height in pixels of this UI component. + nb_tabs : int + Number of tabs to be renders. + active_color : tuple of 3 floats. + Background color of active tab panel. + inactive_color : tuple of 3 floats. + Background color of inactive tab panels. + draggable : bool + Whether the UI element is draggable or not. + startup_tab_id : int, optional + Tab to be activated and uncollapsed on startup. + by default None is activated/ all collapsed. + + """ + self.tabs = [] + self.nb_tabs = nb_tabs + self.parent_size = size + self.content_size = (size[0], int(0.9 * size[1])) + self.draggable = draggable + self.active_color = active_color + self.inactive_color = inactive_color + self.active_tab_idx = startup_tab_id + self.collapsed = True + + super(TabUI, self).__init__() + self.position = position
+ + + def _setup(self): + """Setup this UI component. + + Create parent panel. + Create tab panels. + """ + self.parent_panel = Panel2D(self.parent_size, opacity=0.0) + + # Offer some standard hooks to the user. + self.on_change = lambda ui: None + self.on_collapse = lambda ui: None + + for _ in range(self.nb_tabs): + content_panel = Panel2D(size=self.content_size) + content_panel.set_visibility(False) + tab_panel = TabPanel2D(content_panel=content_panel) + self.tabs.append(tab_panel) + self.update_tabs() + + if self.active_tab_idx is not None: + self.tabs[self.active_tab_idx].color = self.active_color + self.tabs[self.active_tab_idx].content_panel.set_visibility(True) + + def _get_actors(self): + """Get the actors composing this UI component.""" + actors = [] + actors += self.parent_panel.actors + for tab_panel in self.tabs: + actors += tab_panel.actors + + return actors + + def _add_to_scene(self, _scene): + """Add all subcomponents or VTK props that compose this UI component. + + Parameters + ---------- + scene : scene + + """ + self.parent_panel.add_to_scene(_scene) + for tab_panel in self.tabs: + tab_panel.add_to_scene(_scene) + + def _set_position(self, _coords): + """Set the lower-left corner position of this UI component. + + Parameters + ---------- + coords: (float, float) + Absolute pixel coordinates (x, y). + + """ + self.parent_panel.position = _coords + + def _get_size(self): + return self.parent_panel.size + +
+[docs] + def update_tabs(self): + """Update position, size and callbacks for tab panels.""" + self.tab_panel_size = (self.size[0] // self.nb_tabs, int(0.1 * self.size[1])) + + tab_panel_pos = [0.0, 0.9] + for tab_panel in self.tabs: + tab_panel.resize(self.tab_panel_size) + tab_panel.content_panel.position = self.position + + content_panel = tab_panel.content_panel + if self.draggable: + tab_panel.panel.background.on_left_mouse_button_pressed = \ + self.left_button_pressed + content_panel.background.on_left_mouse_button_pressed = \ + self.left_button_pressed + tab_panel.text_block.on_left_mouse_button_pressed = \ + self.left_button_pressed + + tab_panel.panel.background.on_left_mouse_button_dragged = \ + self.left_button_dragged + content_panel.background.on_left_mouse_button_dragged = \ + self.left_button_dragged + tab_panel.text_block.on_left_mouse_button_dragged = \ + self.left_button_dragged + else: + tab_panel.panel.background.on_left_mouse_button_dragged = \ + lambda i_ren, _obj, _comp: i_ren.force_render + content_panel.background.on_left_mouse_button_dragged = \ + lambda i_ren, _obj, _comp: i_ren.force_render + + tab_panel.text_block.on_left_mouse_button_clicked = self.select_tab_callback + tab_panel.panel.background.on_left_mouse_button_clicked = ( + self.select_tab_callback + ) + + tab_panel.text_block.on_right_mouse_button_clicked = self.collapse_tab_ui + tab_panel.panel.background.on_right_mouse_button_clicked = ( + self.collapse_tab_ui + ) + + tab_panel.content_panel.resize(self.content_size) + self.parent_panel.add_element(tab_panel, tab_panel_pos) + self.parent_panel.add_element(tab_panel.content_panel, (0.0, 0.0)) + tab_panel_pos[0] += 1 / self.nb_tabs
+ + +
+[docs] + def select_tab_callback(self, iren, _obj, _tab_comp): + """Handle events when a tab is selected.""" + for idx, tab_panel in enumerate(self.tabs): + if ( + tab_panel.text_block is not _tab_comp + and tab_panel.panel.background is not _tab_comp + ): + tab_panel.color = self.inactive_color + tab_panel.content_panel.set_visibility(False) + else: + current_visibility = tab_panel.content_panel.actors[0].GetVisibility() + if not current_visibility: + tab_panel.color = self.active_color + else: + tab_panel.color = self.inactive_color + tab_panel.content_panel.set_visibility(not current_visibility) + self.active_tab_idx = idx + + self.collapsed = False + self.on_change(self) + iren.force_render() + iren.event.abort()
+ + +
+[docs] + def collapse_tab_ui(self, iren, _obj, _tab_comp): + """Handle events when Tab UI is collapsed.""" + if self.active_tab_idx is not None: + active_tab_panel = self.tabs[self.active_tab_idx] + active_tab_panel.color = self.inactive_color + active_tab_panel.content_panel.set_visibility(False) + self.active_tab_idx = None + self.collapsed = True + self.on_collapse(self) + iren.force_render() + iren.event.abort()
+ + +
+[docs] + def add_element(self, tab_idx, element, coords, anchor='position'): + """Add element to content panel after checking its existence.""" + if tab_idx < self.nb_tabs and tab_idx >= 0: + self.tabs[tab_idx].add_element(element, coords, anchor) + if tab_idx == self.active_tab_idx: + element.set_visibility(True) + else: + raise IndexError('Tab with index ' '{} does not exist'.format(tab_idx))
+ + +
+[docs] + def remove_element(self, tab_idx, element): + """Remove element from content panel after checking its existence.""" + if tab_idx < self.nb_tabs and tab_idx >= 0: + self.tabs[tab_idx].remove_element(element) + else: + raise IndexError('Tab with index ' '{} does not exist'.format(tab_idx))
+ + +
+[docs] + def update_element(self, tab_idx, element, coords, anchor='position'): + """Update element on content panel after checking its existence.""" + if tab_idx < self.nb_tabs and tab_idx >= 0: + self.tabs[tab_idx].update_element(element, coords, anchor) + else: + raise IndexError('Tab with index ' '{} does not exist'.format(tab_idx))
+ + +
+[docs] + def left_button_pressed(self, i_ren, _obj, _sub_component): + click_pos = np.array(i_ren.event.position) + self._click_position = click_pos + i_ren.event.abort() # Stop propagating the event.
+ + +
+[docs] + def left_button_dragged(self, i_ren, _obj, _sub_component): + click_position = np.array(i_ren.event.position) + change = click_position - self._click_position + self.parent_panel.position += change + self._click_position = click_position + i_ren.force_render()
+
+ + + +
+[docs] +class ImageContainer2D(UI): + """A 2D container to hold an image. + + Currently Supports: + - png and jpg/jpeg images + + Attributes + ---------- + size: (float, float) + Image size (width, height) in pixels. + img : ImageData + The image loaded from the specified path. + + """ + +
+[docs] + def __init__(self, img_path, position=(0, 0), size=(100, 100)): + """Init class instance. + + Parameters + ---------- + img_path : string + URL or local path of the image + position : (float, float), optional + Absolute coordinates (x, y) of the lower-left corner of the image. + size : (int, int), optional + Width and height in pixels of the image. + + """ + super(ImageContainer2D, self).__init__(position) + self.img = load_image(img_path, as_vtktype=True) + self.set_img(self.img) + self.resize(size)
+ + + def _get_size(self): + lower_left_corner = self.texture_points.GetPoint(0) + upper_right_corner = self.texture_points.GetPoint(2) + size = np.array(upper_right_corner) - np.array(lower_left_corner) + return abs(size[:2]) + + def _setup(self): + """Setup this UI Component. + + Return an image as a 2D actor with a specific position. + + Returns + ------- + :class:`vtkTexturedActor2D` + + """ + self.texture_polydata = PolyData() + self.texture_points = Points() + self.texture_points.SetNumberOfPoints(4) + + polys = CellArray() + polys.InsertNextCell(4) + polys.InsertCellPoint(0) + polys.InsertCellPoint(1) + polys.InsertCellPoint(2) + polys.InsertCellPoint(3) + self.texture_polydata.SetPolys(polys) + + tc = FloatArray() + tc.SetNumberOfComponents(2) + tc.SetNumberOfTuples(4) + tc.InsertComponent(0, 0, 0.0) + tc.InsertComponent(0, 1, 0.0) + tc.InsertComponent(1, 0, 1.0) + tc.InsertComponent(1, 1, 0.0) + tc.InsertComponent(2, 0, 1.0) + tc.InsertComponent(2, 1, 1.0) + tc.InsertComponent(3, 0, 0.0) + tc.InsertComponent(3, 1, 1.0) + self.texture_polydata.GetPointData().SetTCoords(tc) + + texture_mapper = PolyDataMapper2D() + texture_mapper = set_input(texture_mapper, self.texture_polydata) + + image = TexturedActor2D() + image.SetMapper(texture_mapper) + + self.texture = Texture() + image.SetTexture(self.texture) + + image_property = Property2D() + image_property.SetOpacity(1.0) + image.SetProperty(image_property) + self.actor = image + + # Add default events listener to the VTK actor. + self.handle_events(self.actor) + + def _get_actors(self): + """Return the actors that compose this UI component.""" + return [self.actor] + + def _add_to_scene(self, scene): + """Add all subcomponents or VTK props that compose this UI component. + + Parameters + ---------- + scene : scene + + """ + scene.add(self.actor) + +
+[docs] + def resize(self, size): + """Resize the image. + + Parameters + ---------- + size : (float, float) + image size (width, height) in pixels. + + """ + # Update actor. + self.texture_points.SetPoint(0, 0, 0, 0.0) + self.texture_points.SetPoint(1, size[0], 0, 0.0) + self.texture_points.SetPoint(2, size[0], size[1], 0.0) + self.texture_points.SetPoint(3, 0, size[1], 0.0) + self.texture_polydata.SetPoints(self.texture_points)
+ + + def _set_position(self, coords): + """Set the lower-left corner position of this UI component. + + Parameters + ---------- + coords: (float, float) + Absolute pixel coordinates (x, y). + + """ + self.actor.SetPosition(*coords) + +
+[docs] + def scale(self, factor): + """Scale the image. + + Parameters + ---------- + factor : (float, float) + Scaling factor (width, height) in pixels. + + """ + self.resize(self.size * factor)
+ + +
+[docs] + def set_img(self, img): + """Modify the image used by the vtkTexturedActor2D. + + Parameters + ---------- + img : imageData + + """ + self.texture = set_input(self.texture, img)
+
+ + + +
+[docs] +class GridUI(UI): + """Add actors in a grid and interact with them individually.""" + +
+[docs] + def __init__( + self, + actors, + captions=None, + caption_offset=(0, -100, 0), + cell_padding=0, + cell_shape='rect', + aspect_ratio=16 / 9.0, + dim=None, + rotation_speed=1, + rotation_axis=(0, 1, 0), + ): + + # TODO: add rotation axis None by default + + self.container = grid( + actors, + captions=captions, + caption_offset=caption_offset, + cell_padding=cell_padding, + cell_shape=cell_shape, + aspect_ratio=aspect_ratio, + dim=dim, + ) + self._actors = [] + self._actors_dict = {} + self.rotation_speed = rotation_speed + self.rotation_axis = rotation_axis + + for item in self.container._items: + actor = item if captions is None else item._items[0] + self._actors.append(actor) + self._actors_dict[actor] = {'x': -np.inf, 'y': -np.inf} + + super(GridUI, self).__init__(position=(0, 0, 0))
+ + + def _get_size(self): + return + +
+[docs] + @staticmethod + def left_click_callback(istyle, _obj, _what): + istyle.trackball_actor.OnLeftButtonDown() + istyle.force_render() + istyle.event.abort()
+ + +
+[docs] + @staticmethod + def left_release_callback(istyle, _obj, _what): + + istyle.trackball_actor.OnLeftButtonUp() + istyle.force_render() + istyle.event.abort()
+ + +
+[docs] + @staticmethod + def mouse_move_callback(istyle, _obj, _what): + istyle.trackball_actor.OnMouseMove() + istyle.force_render() + istyle.event.abort()
+ + +
+[docs] + @staticmethod + def left_click_callback2(istyle, obj, self): + + rx, ry, rz = self.rotation_axis + clockwise_rotation = np.array([self.rotation_speed, rx, ry, rz]) + rotate(obj, clockwise_rotation) + + istyle.force_render() + istyle.event.abort()
+ + +
+[docs] + @staticmethod + def left_release_callback2(istyle, _obj, _what): + + istyle.force_render() + istyle.event.abort()
+ + +
+[docs] + @staticmethod + def mouse_move_callback2(istyle, obj, self): + + if self._actors_dict[obj]['y'] == -np.inf: + + iren = istyle.GetInteractor() + event_pos = iren.GetEventPosition() + self._actors_dict[obj]['y'] = event_pos[1] + + else: + + iren = istyle.GetInteractor() + event_pos = iren.GetEventPosition() + rx, ry, rz = self.rotation_axis + + if event_pos[1] >= self._actors_dict[obj]['y']: + clockwise_rotation = np.array([-self.rotation_speed, rx, ry, rz]) + rotate(obj, clockwise_rotation) + else: + anti_clockwise_rotation = np.array([self.rotation_speed, rx, ry, rz]) + rotate(obj, anti_clockwise_rotation) + + self._actors_dict[obj]['y'] = event_pos[1] + + istyle.force_render() + istyle.event.abort()
+ + + ANTICLOCKWISE_ROTATION_Y = np.array([-10, 0, 1, 0]) + CLOCKWISE_ROTATION_Y = np.array([10, 0, 1, 0]) + ANTICLOCKWISE_ROTATION_X = np.array([-10, 1, 0, 0]) + CLOCKWISE_ROTATION_X = np.array([10, 1, 0, 0]) + +
+[docs] + def key_press_callback(self, istyle, obj, _what): + has_changed = False + if istyle.event.key == 'Left': + has_changed = True + for a in self._actors: + rotate(a, self.ANTICLOCKWISE_ROTATION_Y) + elif istyle.event.key == 'Right': + has_changed = True + for a in self._actors: + rotate(a, self.CLOCKWISE_ROTATION_Y) + elif istyle.event.key == 'Up': + has_changed = True + for a in self._actors: + rotate(a, self.ANTICLOCKWISE_ROTATION_X) + elif istyle.event.key == 'Down': + has_changed = True + for a in self._actors: + rotate(a, self.CLOCKWISE_ROTATION_X) + + if has_changed: + istyle.force_render()
+ + + def _setup(self): + """Set up this UI component and the events of its actor.""" + # Add default events listener to the VTK actor. + for actor in self._actors: + # self.handle_events(actor) + + if self.rotation_axis is None: + self.add_callback( + actor, 'LeftButtonPressEvent', self.left_click_callback + ) + self.add_callback( + actor, 'LeftButtonReleaseEvent', self.left_release_callback + ) + self.add_callback(actor, 'MouseMoveEvent', self.mouse_move_callback) + else: + self.add_callback( + actor, 'LeftButtonPressEvent', self.left_click_callback2 + ) + # TODO: possibly add this too + self.add_callback( + actor, 'LeftButtonReleaseEvent', self.left_release_callback2 + ) + self.add_callback(actor, 'MouseMoveEvent', self.mouse_move_callback2) + + # TODO: this is currently not running + self.add_callback(actor, 'KeyPressEvent', self.key_press_callback) + # self.on_key_press = self.key_press_callback2 + + def _get_actors(self): + """Get the actors composing this UI component.""" + return self._actors + + def _add_to_scene(self, scene): + """Add all subcomponents or VTK props that compose this UI component. + + Parameters + ---------- + scene : scene + + """ + self.container.add_to_scene(scene) + +
+[docs] + def resize(self, size): + """Resize the button. + + Parameters + ---------- + size : (float, float) + Button size (width, height) in pixels. + + """ + # Update actor. + pass
+ + + def _set_position(self, coords): + """Set the lower-left corner position of this UI component. + + Parameters + ---------- + coords: (float, float) + Absolute pixel coordinates (x, y). + + """ + # coords = (0, 0, 0) + pass
+ + # self.actor.SetPosition(*coords) + # self.container.SetPosition(*coords) +
+
+ + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/_modules/fury/ui/core.html b/v0.10.x/_modules/fury/ui/core.html new file mode 100644 index 000000000..1da3051a9 --- /dev/null +++ b/v0.10.x/_modules/fury/ui/core.html @@ -0,0 +1,1987 @@ + + + + + + + fury.ui.core — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +

Source code for fury.ui.core

+"""UI core module that describe UI abstract class."""
+
+__all__ = ['Rectangle2D', 'Disk2D', 'TextBlock2D', 'Button2D']
+
+import abc
+
+import numpy as np
+
+from fury.interactor import CustomInteractorStyle
+from fury.io import load_image
+from fury.lib import (
+    Actor2D,
+    CellArray,
+    DiskSource,
+    FloatArray,
+    Points,
+    PolyData,
+    PolyDataMapper2D,
+    Polygon,
+    Property2D,
+    TextActor,
+    Texture,
+    TexturedActor2D,
+)
+from fury.utils import set_input
+
+
+
+[docs] +class UI(object, metaclass=abc.ABCMeta): + """An umbrella class for all UI elements. + + While adding UI elements to the scene, we go over all the sub-elements + that come with it and add those to the scene automatically. + + Attributes + ---------- + position : (float, float) + Absolute coordinates (x, y) of the lower-left corner of this + UI component. + center : (float, float) + Absolute coordinates (x, y) of the center of this UI component. + size : (int, int) + Width and height in pixels of this UI component. + on_left_mouse_button_pressed: function + Callback function for when the left mouse button is pressed. + on_left_mouse_button_released: function + Callback function for when the left mouse button is released. + on_left_mouse_button_clicked: function + Callback function for when clicked using the left mouse button + (i.e. pressed -> released). + on_left_mouse_double_clicked: function + Callback function for when left mouse button is double clicked + (i.e pressed -> released -> pressed -> released). + on_left_mouse_button_dragged: function + Callback function for when dragging using the left mouse button. + on_right_mouse_button_pressed: function + Callback function for when the right mouse button is pressed. + on_right_mouse_button_released: function + Callback function for when the right mouse button is released. + on_right_mouse_button_clicked: function + Callback function for when clicking using the right mouse button + (i.e. pressed -> released). + on_right_mouse_double_clicked: function + Callback function for when right mouse button is double clicked + (i.e pressed -> released -> pressed -> released). + on_right_mouse_button_dragged: function + Callback function for when dragging using the right mouse button. + on_middle_mouse_button_pressed: function + Callback function for when the middle mouse button is pressed. + on_middle_mouse_button_released: function + Callback function for when the middle mouse button is released. + on_middle_mouse_button_clicked: function + Callback function for when clicking using the middle mouse button + (i.e. pressed -> released). + on_middle_mouse_double_clicked: function + Callback function for when middle mouse button is double clicked + (i.e pressed -> released -> pressed -> released). + on_middle_mouse_button_dragged: function + Callback function for when dragging using the middle mouse button. + on_key_press: function + Callback function for when a keyboard key is pressed. + + """ + +
+[docs] + def __init__(self, position=(0, 0)): + """Init scene. + + Parameters + ---------- + position : (float, float) + Absolute coordinates (x, y) of the lower-left corner of this + UI component. + + """ + self._scene = object() + self._position = np.array([0, 0]) + self._callbacks = [] + + self._setup() # Setup needed actors and sub UI components. + self.position = position + + self.left_button_state = 'released' + self.right_button_state = 'released' + self.middle_button_state = 'released' + + self.on_left_mouse_button_pressed = lambda i_ren, obj, element: None + self.on_left_mouse_button_dragged = lambda i_ren, obj, element: None + self.on_left_mouse_button_released = lambda i_ren, obj, element: None + self.on_left_mouse_button_clicked = lambda i_ren, obj, element: None + self.on_left_mouse_double_clicked = lambda i_ren, obj, element: None + self.on_right_mouse_button_pressed = lambda i_ren, obj, element: None + self.on_right_mouse_button_released = lambda i_ren, obj, element: None + self.on_right_mouse_button_clicked = lambda i_ren, obj, element: None + self.on_right_mouse_double_clicked = lambda i_ren, obj, element: None + self.on_right_mouse_button_dragged = lambda i_ren, obj, element: None + self.on_middle_mouse_button_pressed = lambda i_ren, obj, element: None + self.on_middle_mouse_button_released = lambda i_ren, obj, element: None + self.on_middle_mouse_button_clicked = lambda i_ren, obj, element: None + self.on_middle_mouse_double_clicked = lambda i_ren, obj, element: None + self.on_middle_mouse_button_dragged = lambda i_ren, obj, element: None + self.on_key_press = lambda i_ren, obj, element: None
+ + + @abc.abstractmethod + def _setup(self): + """Set up this UI component. + + This is where you should create all your needed actors and sub UI + components. + + """ + msg = 'Subclasses of UI must implement `_setup(self)`.' + raise NotImplementedError(msg) + + @abc.abstractmethod + def _get_actors(self): + """Get the actors composing this UI component.""" + msg = 'Subclasses of UI must implement `_get_actors(self)`.' + raise NotImplementedError(msg) + + @property + def actors(self): + """Actors composing this UI component.""" + return self._get_actors() + + @abc.abstractmethod + def _add_to_scene(self, _scene): + """Add all subcomponents or VTK props that compose this UI component. + + Parameters + ---------- + _scene : Scene + + """ + msg = 'Subclasses of UI must implement `_add_to_scene(self, scene)`.' + raise NotImplementedError(msg) + +
+[docs] + def add_to_scene(self, scene): + """Allow UI objects to add their own props to the scene. + + Parameters + ---------- + scene : scene + + """ + self._add_to_scene(scene) + + # Get a hold on the current interactor style. + iren = scene.GetRenderWindow().GetInteractor().GetInteractorStyle() + + for callback in self._callbacks: + if not isinstance(iren, CustomInteractorStyle): + msg = ( + 'The ShowManager requires `CustomInteractorStyle` in' + ' order to use callbacks.' + ) + raise TypeError(msg) + + if callback[0] == self._scene: + + iren.add_callback(iren, callback[1], callback[2], args=[self]) + else: + iren.add_callback(*callback, args=[self])
+ + +
+[docs] + def add_callback(self, prop, event_type, callback, priority=0): + """Add a callback to a specific event for this UI component. + + Parameters + ---------- + prop : vtkProp + The prop on which is callback is to be added. + event_type : string + The event code. + callback : function + The callback function. + priority : int + Higher number is higher priority. + + """ + # Actually since we need an interactor style we will add the callback + # only when this UI component is added to the scene. + self._callbacks.append((prop, event_type, callback, priority))
+ + + @property + def position(self): + return self._position + + @position.setter + def position(self, coords): + coords = np.asarray(coords) + self._set_position(coords) + self._position = coords + + @abc.abstractmethod + def _set_position(self, _coords): + """Position the lower-left corner of this UI component. + + Parameters + ---------- + _coords: (float, float) + Absolute pixel coordinates (x, y). + + """ + msg = 'Subclasses of UI must implement `_set_position(self, coords)`.' + raise NotImplementedError(msg) + + @property + def size(self): + return np.asarray(self._get_size(), dtype=int) + + @abc.abstractmethod + def _get_size(self): + msg = 'Subclasses of UI must implement property `size`.' + raise NotImplementedError(msg) + + @property + def center(self): + return self.position + self.size / 2.0 + + @center.setter + def center(self, coords): + """Position the center of this UI component. + + Parameters + ---------- + coords: (float, float) + Absolute pixel coordinates (x, y). + + """ + if not hasattr(self, 'size'): + msg = 'Subclasses of UI must implement the `size` property.' + raise NotImplementedError(msg) + + new_center = np.array(coords) + size = np.array(self.size) + new_lower_left_corner = new_center - size / 2.0 + self.position = new_lower_left_corner + +
+[docs] + def set_visibility(self, visibility): + """Set visibility of this UI component.""" + for actor in self.actors: + actor.SetVisibility(visibility)
+ + +
+[docs] + def handle_events(self, actor): + self.add_callback( + actor, 'LeftButtonPressEvent', self.left_button_click_callback + ) + self.add_callback( + actor, 'LeftButtonReleaseEvent', self.left_button_release_callback + ) + self.add_callback( + actor, 'RightButtonPressEvent', self.right_button_click_callback + ) + self.add_callback( + actor, 'RightButtonReleaseEvent', self.right_button_release_callback + ) + self.add_callback( + actor, 'MiddleButtonPressEvent', self.middle_button_click_callback + ) + self.add_callback( + actor, 'MiddleButtonReleaseEvent', self.middle_button_release_callback + ) + self.add_callback(actor, 'MouseMoveEvent', self.mouse_move_callback) + self.add_callback(actor, 'KeyPressEvent', self.key_press_callback)
+ + +
+[docs] + @staticmethod + def left_button_click_callback(i_ren, obj, self): + self.left_button_state = 'pressing' + self.on_left_mouse_button_pressed(i_ren, obj, self) + i_ren.event.abort()
+ + +
+[docs] + @staticmethod + def left_button_release_callback(i_ren, obj, self): + if self.left_button_state == 'pressing': + self.on_left_mouse_button_clicked(i_ren, obj, self) + self.left_button_state = 'released' + self.on_left_mouse_button_released(i_ren, obj, self)
+ + +
+[docs] + @staticmethod + def right_button_click_callback(i_ren, obj, self): + self.right_button_state = 'pressing' + self.on_right_mouse_button_pressed(i_ren, obj, self) + i_ren.event.abort()
+ + +
+[docs] + @staticmethod + def right_button_release_callback(i_ren, obj, self): + if self.right_button_state == 'pressing': + self.on_right_mouse_button_clicked(i_ren, obj, self) + self.right_button_state = 'released' + self.on_right_mouse_button_released(i_ren, obj, self)
+ + +
+[docs] + @staticmethod + def middle_button_click_callback(i_ren, obj, self): + self.middle_button_state = 'pressing' + self.on_middle_mouse_button_pressed(i_ren, obj, self) + i_ren.event.abort()
+ + +
+[docs] + @staticmethod + def middle_button_release_callback(i_ren, obj, self): + if self.middle_button_state == 'pressing': + self.on_middle_mouse_button_clicked(i_ren, obj, self) + self.middle_button_state = 'released' + self.on_middle_mouse_button_released(i_ren, obj, self)
+ + +
+[docs] + @staticmethod + def mouse_move_callback(i_ren, obj, self): + left_pressing_or_dragging = ( + self.left_button_state == 'pressing' or self.left_button_state == 'dragging' + ) + + right_pressing_or_dragging = ( + self.right_button_state == 'pressing' + or self.right_button_state == 'dragging' + ) + + middle_pressing_or_dragging = ( + self.middle_button_state == 'pressing' + or self.middle_button_state == 'dragging' + ) + + if left_pressing_or_dragging: + self.left_button_state = 'dragging' + self.on_left_mouse_button_dragged(i_ren, obj, self) + elif right_pressing_or_dragging: + self.right_button_state = 'dragging' + self.on_right_mouse_button_dragged(i_ren, obj, self) + elif middle_pressing_or_dragging: + self.middle_button_state = 'dragging' + self.on_middle_mouse_button_dragged(i_ren, obj, self)
+ + +
+[docs] + @staticmethod + def key_press_callback(i_ren, obj, self): + self.on_key_press(i_ren, obj, self)
+
+ + + +
+[docs] +class Rectangle2D(UI): + """A 2D rectangle sub-classed from UI.""" + +
+[docs] + def __init__(self, size=(0, 0), position=(0, 0), color=(1, 1, 1), opacity=1.0): + """Initialize a rectangle. + + Parameters + ---------- + size : (int, int) + The size of the rectangle (width, height) in pixels. + position : (float, float) + Coordinates (x, y) of the lower-left corner of the rectangle. + color : (float, float, float) + Must take values in [0, 1]. + opacity : float + Must take values in [0, 1]. + + """ + super(Rectangle2D, self).__init__(position) + self.color = color + self.opacity = opacity + self.resize(size)
+ + + def _setup(self): + """Set up this UI component. + + Creating the polygon actor used internally. + """ + # Setup four points + size = (1, 1) + self._points = Points() + self._points.InsertNextPoint(0, 0, 0) + self._points.InsertNextPoint(size[0], 0, 0) + self._points.InsertNextPoint(size[0], size[1], 0) + self._points.InsertNextPoint(0, size[1], 0) + + # Create the polygon + polygon = Polygon() + polygon.GetPointIds().SetNumberOfIds(4) # make a quad + polygon.GetPointIds().SetId(0, 0) + polygon.GetPointIds().SetId(1, 1) + polygon.GetPointIds().SetId(2, 2) + polygon.GetPointIds().SetId(3, 3) + + # Add the polygon to a list of polygons + polygons = CellArray() + polygons.InsertNextCell(polygon) + + # Create a PolyData + self._polygonPolyData = PolyData() + self._polygonPolyData.SetPoints(self._points) + self._polygonPolyData.SetPolys(polygons) + + # Create a mapper and actor + mapper = PolyDataMapper2D() + mapper = set_input(mapper, self._polygonPolyData) + + self.actor = Actor2D() + self.actor.SetMapper(mapper) + + # Add default events listener to the VTK actor. + self.handle_events(self.actor) + + def _get_actors(self): + """Get the actors composing this UI component.""" + return [self.actor] + + def _add_to_scene(self, scene): + """Add all subcomponents or VTK props that compose this UI component. + + Parameters + ---------- + scene : scene + + """ + scene.add(self.actor) + + def _get_size(self): + # Get 2D coordinates of two opposed corners of the rectangle. + lower_left_corner = np.array(self._points.GetPoint(0)[:2]) + upper_right_corner = np.array(self._points.GetPoint(2)[:2]) + size = abs(upper_right_corner - lower_left_corner) + return size + + @property + def width(self): + return self._points.GetPoint(2)[0] + + @width.setter + def width(self, width): + self.resize((width, self.height)) + + @property + def height(self): + return self._points.GetPoint(2)[1] + + @height.setter + def height(self, height): + self.resize((self.width, height)) + +
+[docs] + def resize(self, size): + """Set the button size. + + Parameters + ---------- + size : (float, float) + Button size (width, height) in pixels. + + """ + self._points.SetPoint(0, 0, 0, 0.0) + self._points.SetPoint(1, size[0], 0, 0.0) + self._points.SetPoint(2, size[0], size[1], 0.0) + self._points.SetPoint(3, 0, size[1], 0.0) + self._polygonPolyData.SetPoints(self._points) + mapper = PolyDataMapper2D() + mapper = set_input(mapper, self._polygonPolyData) + + self.actor.SetMapper(mapper)
+ + + def _set_position(self, coords): + """Set the lower-left corner position of this UI component. + + Parameters + ---------- + coords: (float, float) + Absolute pixel coordinates (x, y). + + """ + self.actor.SetPosition(*coords) + + @property + def color(self): + """Get the rectangle's color.""" + color = self.actor.GetProperty().GetColor() + return np.asarray(color) + + @color.setter + def color(self, color): + """Set the rectangle's color. + + Parameters + ---------- + color : (float, float, float) + RGB. Must take values in [0, 1]. + + """ + self.actor.GetProperty().SetColor(*color) + + @property + def opacity(self): + """Get the rectangle's opacity.""" + return self.actor.GetProperty().GetOpacity() + + @opacity.setter + def opacity(self, opacity): + """Set the rectangle's opacity. + + Parameters + ---------- + opacity : float + Degree of transparency. Must be between [0, 1]. + + """ + self.actor.GetProperty().SetOpacity(opacity)
+ + + +
+[docs] +class Disk2D(UI): + """A 2D disk UI component.""" + +
+[docs] + def __init__( + self, outer_radius, inner_radius=0, center=(0, 0), color=(1, 1, 1), opacity=1.0 + ): + """Initialize a 2D Disk. + + Parameters + ---------- + outer_radius : int + Outer radius of the disk. + inner_radius : int, optional + Inner radius of the disk. A value > 0, makes a ring. + center : (float, float), optional + Coordinates (x, y) of the center of the disk. + color : (float, float, float), optional + Must take values in [0, 1]. + opacity : float, optional + Must take values in [0, 1]. + + """ + super(Disk2D, self).__init__() + self.outer_radius = outer_radius + self.inner_radius = inner_radius + self.color = color + self.opacity = opacity + self.center = center
+ + + def _setup(self): + """Setup this UI component. + + Creating the disk actor used internally. + + """ + # Setting up disk actor. + self._disk = DiskSource() + self._disk.SetRadialResolution(10) + self._disk.SetCircumferentialResolution(50) + self._disk.Update() + + # Mapper + mapper = PolyDataMapper2D() + mapper = set_input(mapper, self._disk.GetOutputPort()) + + # Actor + self.actor = Actor2D() + self.actor.SetMapper(mapper) + + # Add default events listener to the VTK actor. + self.handle_events(self.actor) + + def _get_actors(self): + """Get the actors composing this UI component.""" + return [self.actor] + + def _add_to_scene(self, scene): + """Add all subcomponents or VTK props that compose this UI component. + + Parameters + ---------- + scene : scene + + """ + scene.add(self.actor) + + def _get_size(self): + diameter = 2 * self.outer_radius + size = (diameter, diameter) + return size + + def _set_position(self, coords): + """Set the lower-left corner position of this UI bounding box. + + Parameters + ---------- + coords: (float, float) + Absolute pixel coordinates (x, y). + + """ + # Disk actor are positioned with respect to their center. + self.actor.SetPosition(*coords + self.outer_radius) + + @property + def color(self): + """Get the color of this UI component.""" + color = self.actor.GetProperty().GetColor() + return np.asarray(color) + + @color.setter + def color(self, color): + """Set the color of this UI component. + + Parameters + ---------- + color : (float, float, float) + RGB. Must take values in [0, 1]. + + """ + self.actor.GetProperty().SetColor(*color) + + @property + def opacity(self): + """Get the opacity of this UI component.""" + return self.actor.GetProperty().GetOpacity() + + @opacity.setter + def opacity(self, opacity): + """Set the opacity of this UI component. + + Parameters + ---------- + opacity : float + Degree of transparency. Must be between [0, 1]. + + """ + self.actor.GetProperty().SetOpacity(opacity) + + @property + def inner_radius(self): + return self._disk.GetInnerRadius() + + @inner_radius.setter + def inner_radius(self, radius): + self._disk.SetInnerRadius(radius) + self._disk.Update() + + @property + def outer_radius(self): + return self._disk.GetOuterRadius() + + @outer_radius.setter + def outer_radius(self, radius): + self._disk.SetOuterRadius(radius) + self._disk.Update()
+ + + +
+[docs] +class TextBlock2D(UI): + """Wrap over the default vtkTextActor and helps setting the text. + + Contains member functions for text formatting. + + Attributes + ---------- + actor : :class:`vtkTextActor` + The text actor. + message : str + The initial text while building the actor. + position : (float, float) + (x, y) in pixels. + color : (float, float, float) + RGB: Values must be between 0-1. + bg_color : (float, float, float) + RGB: Values must be between 0-1. + font_size : int + Size of the text font. + font_family : str + Currently only supports Arial. + justification : str + left, right or center. + vertical_justification : str + bottom, middle or top. + bold : bool + Makes text bold. + italic : bool + Makes text italicised. + shadow : bool + Adds text shadow. + size : (int, int) + Size (width, height) in pixels of the text bounding box. + auto_font_scale : bool + Automatically scale font according to the text bounding box. + dynamic_bbox : bool + Automatically resize the bounding box according to the content. + + """ + +
+[docs] + def __init__( + self, + text='Text Block', + font_size=18, + font_family='Arial', + justification='left', + vertical_justification='bottom', + bold=False, + italic=False, + shadow=False, + size=None, + color=(1, 1, 1), + bg_color=None, + position=(0, 0), + auto_font_scale=False, + dynamic_bbox=False + ): + """Init class instance. + + Parameters + ---------- + text : str + The initial text while building the actor. + position : (float, float) + (x, y) in pixels. + color : (float, float, float) + RGB: Values must be between 0-1. + bg_color : (float, float, float) + RGB: Values must be between 0-1. + font_size : int + Size of the text font. + font_family : str + Currently only supports Arial. + justification : str + left, right or center. + vertical_justification : str + bottom, middle or top. + bold : bool + Makes text bold. + italic : bool + Makes text italicised. + shadow : bool + Adds text shadow. + size : (int, int) + Size (width, height) in pixels of the text bounding box. + auto_font_scale : bool, optional + Automatically scale font according to the text bounding box. + dynamic_bbox : bool, optional + Automatically resize the bounding box according to the content. + + """ + self.boundingbox = [0, 0, 0, 0] + super(TextBlock2D, self).__init__(position=position) + self.scene = None + self.have_bg = bool(bg_color) + self.color = color + self.background_color = bg_color + self.font_family = font_family + self._justification = justification + self.bold = bold + self.italic = italic + self.shadow = shadow + self._vertical_justification = vertical_justification + self._dynamic_bbox = dynamic_bbox + self.auto_font_scale = auto_font_scale + self.message = text + self.font_size = font_size + if size is not None: + self.resize(size) + elif not self.dynamic_bbox: + # raise ValueError("TextBlock size is required as it is not dynamic.") + self.resize((0, 0))
+ + + def _setup(self): + self.actor = TextActor() + self.actor.GetPosition2Coordinate().SetCoordinateSystemToViewport() + self.background = Rectangle2D() + self.handle_events(self.actor) + +
+[docs] + def resize(self, size): + """Resize TextBlock2D. + + Parameters + ---------- + size : (int, int) + Text bounding box size(width, height) in pixels. + + """ + self.update_bounding_box(size)
+ + + def _get_actors(self): + """Get the actors composing this UI component.""" + return [self.actor] + self.background.actors + + def _add_to_scene(self, scene): + """Add all subcomponents or VTK props that compose this UI component. + + Parameters + ---------- + scene : scene + + """ + scene.add(self.background, self.actor) + + @property + def message(self): + """Get message from the text. + + Returns + ------- + str + The current text message. + + """ + return self.actor.GetInput() + + @message.setter + def message(self, text): + """Set the text message. + + Parameters + ---------- + text : str + The message to be set. + + """ + self.actor.SetInput(text) + if self.dynamic_bbox: + self.update_bounding_box() + + @property + def font_size(self): + """Get text font size. + + Returns + ------- + int + Text font size. + + """ + return self.actor.GetTextProperty().GetFontSize() + + @font_size.setter + def font_size(self, size): + """Set font size. + + Parameters + ---------- + size : int + Text font size. + + """ + if not self.auto_font_scale: + self.actor.SetTextScaleModeToNone() + self.actor.GetTextProperty().SetFontSize(size) + + if self.dynamic_bbox: + self.update_bounding_box() + + @property + def font_family(self): + """Get font family. + + Returns + ------- + str + Text font family. + + """ + return self.actor.GetTextProperty().GetFontFamilyAsString() + + @font_family.setter + def font_family(self, family='Arial'): + """Set font family. + + Currently Arial and Courier are supported. + + Parameters + ---------- + family : str + The font family. + + """ + if family == 'Arial': + self.actor.GetTextProperty().SetFontFamilyToArial() + elif family == 'Courier': + self.actor.GetTextProperty().SetFontFamilyToCourier() + else: + raise ValueError('Font not supported yet: {}.'.format(family)) + + @property + def justification(self): + """Get text justification. + + Returns + ------- + str + Text justification. + + """ + return self._justification + + @justification.setter + def justification(self, justification): + """Justify text. + + Parameters + ---------- + justification : str + Possible values are left, right, center. + + """ + self._justification = justification + self.update_alignment() + + @property + def vertical_justification(self): + """Get text vertical justification. + + Returns + ------- + str + Text vertical justification. + + """ + return self._vertical_justification + + @vertical_justification.setter + def vertical_justification(self, vertical_justification): + """Justify text vertically. + + Parameters + ---------- + vertical_justification : str + Possible values are bottom, middle, top. + + """ + self._vertical_justification = vertical_justification + self.update_alignment() + + @property + def bold(self): + """Return whether the text is bold. + + Returns + ------- + bool + Text is bold if True. + + """ + return self.actor.GetTextProperty().GetBold() + + @bold.setter + def bold(self, flag): + """Bold/un-bold text. + + Parameters + ---------- + flag : bool + Sets text bold if True. + + """ + self.actor.GetTextProperty().SetBold(flag) + + @property + def italic(self): + """Return whether the text is italicised. + + Returns + ------- + bool + Text is italicised if True. + + """ + return self.actor.GetTextProperty().GetItalic() + + @italic.setter + def italic(self, flag): + """Italicise/un-italicise text. + + Parameters + ---------- + flag : bool + Italicises text if True. + + """ + self.actor.GetTextProperty().SetItalic(flag) + + @property + def shadow(self): + """Return whether the text has shadow. + + Returns + ------- + bool + Text is shadowed if True. + + """ + return self.actor.GetTextProperty().GetShadow() + + @shadow.setter + def shadow(self, flag): + """Add/remove text shadow. + + Parameters + ---------- + flag : bool + Shadows text if True. + + """ + self.actor.GetTextProperty().SetShadow(flag) + + @property + def color(self): + """Get text color. + + Returns + ------- + (float, float, float) + Returns text color in RGB. + + """ + return self.actor.GetTextProperty().GetColor() + + @color.setter + def color(self, color=(1, 0, 0)): + """Set text color. + + Parameters + ---------- + color : (float, float, float) + RGB: Values must be between 0-1. + + """ + self.actor.GetTextProperty().SetColor(*color) + + @property + def background_color(self): + """Get background color. + + Returns + ------- + (float, float, float) or None + If None, there no background color. + Otherwise, background color in RGB. + + """ + if not self.have_bg: + return None + + return self.background.color + + @background_color.setter + def background_color(self, color): + """Set text color. + + Parameters + ---------- + color : (float, float, float) or None + If None, remove background. + Otherwise, RGB values (must be between 0-1). + + """ + if color is None: + # Remove background. + self.have_bg = False + self.background.set_visibility(False) + + else: + self.have_bg = True + self.background.set_visibility(True) + self.background.color = color + + @property + def auto_font_scale(self): + """Return whether text font is automatically scaled. + + Returns + ------- + bool + Text is auto_font_scaled if True. + + """ + return self._auto_font_scale + + @auto_font_scale.setter + def auto_font_scale(self, flag): + """Add/remove text auto_font_scale. + + Parameters + ---------- + flag : bool + Automatically scales the text font if True. + + """ + self._auto_font_scale = flag + if flag: + self.actor.SetTextScaleModeToProp() + self._justification = "left" + self.update_bounding_box(self.size) + else: + self.actor.SetTextScaleModeToNone() + + @property + def dynamic_bbox(self): + """Automatically resize the bounding box according to the content. + + Returns + ------- + bool + Bounding box is dynamic if True. + + """ + return self._dynamic_bbox + + @dynamic_bbox.setter + def dynamic_bbox(self, flag): + """Add/remove dynamic_bbox. + + Parameters + ---------- + flag : bool + The text bounding box is dynamic if True. + + """ + self._dynamic_bbox = flag + if flag: + self.update_bounding_box() + +
+[docs] + def update_alignment(self): + """Update Text Alignment. + """ + text_property = self.actor.GetTextProperty() + updated_text_position = [0, 0] + + if self.justification.lower() == 'left': + text_property.SetJustificationToLeft() + updated_text_position[0] = self.boundingbox[0] + elif self.justification.lower() == 'center': + text_property.SetJustificationToCentered() + updated_text_position[0] = self.boundingbox[0] + \ + (self.boundingbox[2]-self.boundingbox[0])//2 + elif self.justification.lower() == 'right': + text_property.SetJustificationToRight() + updated_text_position[0] = self.boundingbox[2] + else: + msg = 'Text can only be justified left, right and center.' + raise ValueError(msg) + + if self.vertical_justification.lower() == 'bottom': + text_property.SetVerticalJustificationToBottom() + updated_text_position[1] = self.boundingbox[1] + elif self.vertical_justification.lower() == 'middle': + text_property.SetVerticalJustificationToCentered() + updated_text_position[1] = self.boundingbox[1] + \ + (self.boundingbox[3]-self.boundingbox[1])//2 + elif self.vertical_justification.lower() == 'top': + text_property.SetVerticalJustificationToTop() + updated_text_position[1] = self.boundingbox[3] + else: + msg = 'Vertical justification must be: bottom, middle or top.' + raise ValueError(msg) + + self.actor.SetPosition(updated_text_position)
+ + +
+[docs] + def cal_size_from_message(self): + """Calculate size of background according to the message it contains.""" + lines = self.message.split("\n") + max_length = max(len(line) for line in lines) + return [max_length*self.font_size, len(lines)*self.font_size]
+ + +
+[docs] + def update_bounding_box(self, size=None): + """Update Text Bounding Box. + + Parameters + ---------- + size : (int, int) or None + If None, calculates bounding box. + Otherwise, uses the given size. + + """ + if size is None: + size = self.cal_size_from_message() + + self.boundingbox = [self.position[0], self.position[1], + self.position[0]+size[0], self.position[1]+size[1]] + self.background.resize(size) + + if self.auto_font_scale: + self.actor.SetPosition2( + self.boundingbox[2]-self.boundingbox[0], + self.boundingbox[3]-self.boundingbox[1]) + else: + self.update_alignment()
+ + + def _set_position(self, position): + """Set text actor position. + + Parameters + ---------- + position : (float, float) + The new position. (x, y) in pixels. + + """ + self.actor.SetPosition(*position) + self.background.position = position + + def _get_size(self): + bb_size = (self.boundingbox[2]-self.boundingbox[0], + self.boundingbox[3]-self.boundingbox[1]) + if self.dynamic_bbox or self.auto_font_scale or sum(bb_size): + return bb_size + return self.cal_size_from_message()
+ + + +
+[docs] +class Button2D(UI): + """A 2D overlay button and is of type vtkTexturedActor2D. + + Currently supports:: + + - Multiple icons. + - Switching between icons. + + """ + +
+[docs] + def __init__(self, icon_fnames, position=(0, 0), size=(30, 30)): + """Init class instance. + + Parameters + ---------- + icon_fnames : List(string, string) + ((iconname, filename), (iconname, filename), ....) + position : (float, float), optional + Absolute coordinates (x, y) of the lower-left corner of the button. + size : (int, int), optional + Width and height in pixels of the button. + + """ + super(Button2D, self).__init__(position) + + self.icon_extents = dict() + self.icons = self._build_icons(icon_fnames) + self.icon_names = [icon[0] for icon in self.icons] + self.current_icon_id = 0 + self.current_icon_name = self.icon_names[self.current_icon_id] + self.set_icon(self.icons[self.current_icon_id][1]) + self.resize(size)
+ + + def _get_size(self): + lower_left_corner = self.texture_points.GetPoint(0) + upper_right_corner = self.texture_points.GetPoint(2) + size = np.array(upper_right_corner) - np.array(lower_left_corner) + return abs(size[:2]) + + def _build_icons(self, icon_fnames): + """Convert file names to ImageData. + + A pre-processing step to prevent re-read of file names during every + state change. + + Parameters + ---------- + icon_fnames : List(string, string) + ((iconname, filename), (iconname, filename), ....) + + Returns + ------- + icons : List + A list of corresponding ImageData. + + """ + icons = [] + for icon_name, icon_fname in icon_fnames: + icons.append((icon_name, load_image(icon_fname, as_vtktype=True))) + + return icons + + def _setup(self): + """Set up this UI component. + + Creating the button actor used internally. + + """ + # This is highly inspired by + # https://github.com/Kitware/VTK/blob/c3ec2495b183e3327820e927af7f8f90d34c3474/Interaction/Widgets/vtkBalloonRepresentation.cxx#L47 + + self.texture_polydata = PolyData() + self.texture_points = Points() + self.texture_points.SetNumberOfPoints(4) + + polys = CellArray() + polys.InsertNextCell(4) + polys.InsertCellPoint(0) + polys.InsertCellPoint(1) + polys.InsertCellPoint(2) + polys.InsertCellPoint(3) + self.texture_polydata.SetPolys(polys) + + tc = FloatArray() + tc.SetNumberOfComponents(2) + tc.SetNumberOfTuples(4) + tc.InsertComponent(0, 0, 0.0) + tc.InsertComponent(0, 1, 0.0) + tc.InsertComponent(1, 0, 1.0) + tc.InsertComponent(1, 1, 0.0) + tc.InsertComponent(2, 0, 1.0) + tc.InsertComponent(2, 1, 1.0) + tc.InsertComponent(3, 0, 0.0) + tc.InsertComponent(3, 1, 1.0) + self.texture_polydata.GetPointData().SetTCoords(tc) + + texture_mapper = PolyDataMapper2D() + texture_mapper = set_input(texture_mapper, self.texture_polydata) + + button = TexturedActor2D() + button.SetMapper(texture_mapper) + + self.texture = Texture() + button.SetTexture(self.texture) + + button_property = Property2D() + button_property.SetOpacity(1.0) + button.SetProperty(button_property) + self.actor = button + + # Add default events listener to the VTK actor. + self.handle_events(self.actor) + + def _get_actors(self): + """Get the actors composing this UI component.""" + return [self.actor] + + def _add_to_scene(self, scene): + """Add all subcomponents or VTK props that compose this UI component. + + Parameters + ---------- + scene : scene + + """ + scene.add(self.actor) + +
+[docs] + def resize(self, size): + """Resize the button. + + Parameters + ---------- + size : (float, float) + Button size (width, height) in pixels. + + """ + # Update actor. + self.texture_points.SetPoint(0, 0, 0, 0.0) + self.texture_points.SetPoint(1, size[0], 0, 0.0) + self.texture_points.SetPoint(2, size[0], size[1], 0.0) + self.texture_points.SetPoint(3, 0, size[1], 0.0) + self.texture_polydata.SetPoints(self.texture_points)
+ + + def _set_position(self, coords): + """Set the lower-left corner position of this UI component. + + Parameters + ---------- + coords: (float, float) + Absolute pixel coordinates (x, y). + + """ + self.actor.SetPosition(*coords) + + @property + def color(self): + """Get the button's color.""" + color = self.actor.GetProperty().GetColor() + return np.asarray(color) + + @color.setter + def color(self, color): + """Set the button's color. + + Parameters + ---------- + color : (float, float, float) + RGB. Must take values in [0, 1]. + + """ + self.actor.GetProperty().SetColor(*color) + +
+[docs] + def scale(self, factor): + """Scale the button. + + Parameters + ---------- + factor : (float, float) + Scaling factor (width, height) in pixels. + + """ + self.resize(self.size * factor)
+ + +
+[docs] + def set_icon_by_name(self, icon_name): + """Set the button icon using its name. + + Parameters + ---------- + icon_name : str + + """ + icon_id = self.icon_names.index(icon_name) + self.set_icon(self.icons[icon_id][1])
+ + +
+[docs] + def set_icon(self, icon): + """Modify the icon used by the vtkTexturedActor2D. + + Parameters + ---------- + icon : imageData + + """ + self.texture = set_input(self.texture, icon)
+ + +
+[docs] + def next_icon_id(self): + """Set the next icon ID while cycling through icons.""" + self.current_icon_id += 1 + if self.current_icon_id == len(self.icons): + self.current_icon_id = 0 + self.current_icon_name = self.icon_names[self.current_icon_id]
+ + +
+[docs] + def next_icon(self): + """Increment the state of the Button. + + Also changes the icon. + """ + self.next_icon_id() + self.set_icon(self.icons[self.current_icon_id][1])
+
+ +
+
+ + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/_modules/fury/ui/elements.html b/v0.10.x/_modules/fury/ui/elements.html new file mode 100644 index 000000000..a001b1942 --- /dev/null +++ b/v0.10.x/_modules/fury/ui/elements.html @@ -0,0 +1,5511 @@ + + + + + + + fury.ui.elements — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +

Source code for fury.ui.elements

+"""UI components module."""
+
+__all__ = [
+    'TextBox2D',
+    'LineSlider2D',
+    'LineDoubleSlider2D',
+    'RingSlider2D',
+    'RangeSlider',
+    'Checkbox',
+    'Option',
+    'RadioButton',
+    'ComboBox2D',
+    'ListBox2D',
+    'ListBoxItem2D',
+    'FileMenu2D',
+    'DrawShape',
+    'DrawPanel',
+    'PlaybackPanel',
+    'Card2D',
+    'SpinBox'
+]
+
+import os
+from collections import OrderedDict
+from numbers import Number
+from string import printable
+from urllib.request import urlopen
+
+import numpy as np
+from PIL import Image, UnidentifiedImageError
+
+from fury.data import read_viz_icons
+from fury.lib import Command
+from fury.ui.containers import ImageContainer2D, Panel2D
+from fury.ui.core import UI, Button2D, Disk2D, Rectangle2D, TextBlock2D
+from fury.ui.helpers import (
+    TWO_PI,
+    cal_bounding_box_2d,
+    clip_overflow,
+    rotate_2d,
+    wrap_overflow,
+)
+from fury.utils import set_polydata_vertices, update_actor, vertices_from_actor
+
+
+
+[docs] +class TextBox2D(UI): + """An editable 2D text box that behaves as a UI component. + + Currently supports: + - Basic text editing. + - Cursor movements. + - Single and multi-line text boxes. + - Pre text formatting (text needs to be formatted beforehand). + + Attributes + ---------- + text : str + The current text state. + actor : :class:`vtkActor2d` + The text actor. + width : int + The number of characters in a single line of text. + height : int + The number of lines in the textbox. + window_left : int + Left limit of visible text in the textbox. + window_right : int + Right limit of visible text in the textbox. + caret_pos : int + Position of the caret in the text. + init : bool + Flag which says whether the textbox has just been initialized. + + """ + +
+[docs] + def __init__( + self, + width, + height, + text='Enter Text', + position=(100, 10), + color=(0, 0, 0), + font_size=18, + font_family='Arial', + justification='left', + bold=False, + italic=False, + shadow=False, + ): + """Init this UI element. + + Parameters + ---------- + width : int + The number of characters in a single line of text. + height : int + The number of lines in the textbox. + text : str + The initial text while building the actor. + position : (float, float) + (x, y) in pixels. + color : (float, float, float) + RGB: Values must be between 0-1. + font_size : int + Size of the text font. + font_family : str + Currently only supports Arial. + justification : str + left, right or center. + bold : bool + Makes text bold. + italic : bool + Makes text italicised. + shadow : bool + Adds text shadow. + + """ + super(TextBox2D, self).__init__(position=position) + + self.message = text + self.text.message = text + self.text.font_size = font_size + self.text.font_family = font_family + self.text.justification = justification + self.text.bold = bold + self.text.italic = italic + self.text.shadow = shadow + self.text.color = color + self.text.background_color = (1, 1, 1) + + self.width = width + self.height = height + self.window_left = 0 + self.window_right = 0 + self.caret_pos = 0 + self.init = True + + self.off_focus = lambda ui: None
+ + + def _setup(self): + """Setup this UI component. + + Create the TextBlock2D component used for the textbox. + """ + self.text = TextBlock2D(dynamic_bbox=True) + + # Add default events listener for this UI component. + self.text.on_left_mouse_button_pressed = self.left_button_press + self.text.on_key_press = self.key_press + + def _get_actors(self): + """Get the actors composing this UI component.""" + return self.text.actors + + def _add_to_scene(self, scene): + """Add all subcomponents or VTK props that compose this UI component. + + Parameters + ---------- + scene : scene + + """ + self.text.add_to_scene(scene) + + def _set_position(self, coords): + """Set the lower-left corner position of this UI component. + + Parameters + ---------- + coords: (float, float) + Absolute pixel coordinates (x, y). + + """ + self.text.position = coords + + def _get_size(self): + return self.text.size + +
+[docs] + def set_message(self, message): + """Set custom text to textbox. + + Parameters + ---------- + message: str + The custom message to be set. + + """ + self.message = message + self.text.message = message + self.init = False + self.window_right = len(self.message) + self.window_left = 0 + self.caret_pos = self.window_right
+ + +
+[docs] + def width_set_text(self, text): + """Add newlines to text where necessary. + + This is needed for multi-line text boxes. + + Parameters + ---------- + text : str + The final text to be formatted. + + Returns + ------- + str + A multi line formatted text. + + """ + multi_line_text = '' + for i, t in enumerate(text): + multi_line_text += t + if (i + 1) % self.width == 0: + multi_line_text += '\n' + return multi_line_text.rstrip('\n')
+ + +
+[docs] + def handle_character(self, key, key_char): + """Handle button events. + + # TODO: Need to handle all kinds of characters like !, +, etc. + + Parameters + ---------- + character : str + + """ + if key.lower() == 'return': + self.render_text(False) + self.off_focus(self) + return True + elif key_char != '' and key_char in printable: + self.add_character(key_char) + if key.lower() == 'backspace': + self.remove_character() + elif key.lower() == 'left': + self.move_left() + elif key.lower() == 'right': + self.move_right() + + self.render_text() + return False
+ + +
+[docs] + def move_caret_right(self): + """Move the caret towards right.""" + self.caret_pos = min(self.caret_pos + 1, len(self.message))
+ + +
+[docs] + def move_caret_left(self): + """Move the caret towards left.""" + self.caret_pos = max(self.caret_pos - 1, 0)
+ + +
+[docs] + def right_move_right(self): + """Move right boundary of the text window right-wards.""" + if self.window_right <= len(self.message): + self.window_right += 1
+ + +
+[docs] + def right_move_left(self): + """Move right boundary of the text window left-wards.""" + if self.window_right > 0: + self.window_right -= 1
+ + +
+[docs] + def left_move_right(self): + """Move left boundary of the text window right-wards.""" + if self.window_left <= len(self.message): + self.window_left += 1
+ + +
+[docs] + def left_move_left(self): + """Move left boundary of the text window left-wards.""" + if self.window_left > 0: + self.window_left -= 1
+ + +
+[docs] + def add_character(self, character): + """Insert a character into the text and moves window and caret. + + Parameters + ---------- + character : str + + """ + if len(character) > 1 and character.lower() != 'space': + return + if character.lower() == 'space': + character = ' ' + self.message = ( + self.message[: self.caret_pos] + character + self.message[self.caret_pos :] + ) + self.move_caret_right() + if self.window_right - self.window_left == self.height * self.width - 1: + self.left_move_right() + self.right_move_right()
+ + +
+[docs] + def remove_character(self): + """Remove a character and moves window and caret accordingly.""" + if self.caret_pos == 0: + return + self.message = ( + self.message[: self.caret_pos - 1] + self.message[self.caret_pos :] + ) + self.move_caret_left() + if len(self.message) < self.height * self.width - 1: + self.right_move_left() + if self.window_right - self.window_left == self.height * self.width - 1: + if self.window_left > 0: + self.left_move_left() + self.right_move_left()
+ + +
+[docs] + def move_left(self): + """Handle left button press.""" + self.move_caret_left() + if self.caret_pos == self.window_left - 1: + if self.window_right - self.window_left == self.height * self.width - 1: + self.left_move_left() + self.right_move_left()
+ + +
+[docs] + def move_right(self): + """Handle right button press.""" + self.move_caret_right() + if self.caret_pos == self.window_right + 1: + if self.window_right - self.window_left == self.height * self.width - 1: + self.left_move_right() + self.right_move_right()
+ + +
+[docs] + def showable_text(self, show_caret): + """Chop out text to be shown on the screen. + + Parameters + ---------- + show_caret : bool + Whether or not to show the caret. + + """ + if show_caret: + ret_text = ( + self.message[: self.caret_pos] + '_' + self.message[self.caret_pos :] + ) + else: + ret_text = self.message + ret_text = ret_text[self.window_left : self.window_right + 1] + return ret_text
+ + +
+[docs] + def render_text(self, show_caret=True): + """Render text after processing. + + Parameters + ---------- + show_caret : bool + Whether or not to show the caret. + + """ + text = self.showable_text(show_caret) + if text == '': + text = 'Enter Text' + self.text.message = self.width_set_text(text)
+ + +
+[docs] + def edit_mode(self): + """Turn on edit mode.""" + if self.init: + self.message = '' + self.init = False + self.caret_pos = 0 + self.render_text()
+ + +
+[docs] + def left_button_press(self, i_ren, _obj, _textbox_object): + """Handle left button press for textbox. + + Parameters + ---------- + i_ren: :class:`CustomInteractorStyle` + obj: :class:`vtkActor` + The picked actor + _textbox_object: :class:`TextBox2D` + + """ + i_ren.add_active_prop(self.text.actor) + self.edit_mode() + i_ren.force_render()
+ + +
+[docs] + def key_press(self, i_ren, _obj, _textbox_object): + """Handle Key press for textboxself. + + Parameters + ---------- + i_ren: :class:`CustomInteractorStyle` + obj: :class:`vtkActor` + The picked actor + _textbox_object: :class:`TextBox2D` + + """ + key = i_ren.event.key + key_char = i_ren.event.key_char + is_done = self.handle_character(key, key_char) + if is_done: + i_ren.remove_active_prop(self.text.actor) + + i_ren.force_render()
+
+ + + +
+[docs] +class LineSlider2D(UI): + """A 2D Line Slider. + + A sliding handle on a line with a percentage indicator. + + Attributes + ---------- + line_width : int + Width of the line on which the disk will slide. + length : int + Length of the slider. + track : :class:`Rectangle2D` + The line on which the slider's handle moves. + handle : :class:`Disk2D` + The moving part of the slider. + text : :class:`TextBlock2D` + The text that shows percentage. + shape : string + Describes the shape of the handle. + Currently supports 'disk' and 'square'. + default_color : (float, float, float) + Color of the handle when in unpressed state. + active_color : (float, float, float) + Color of the handle when it is pressed. + + """ + +
+[docs] + def __init__( + self, + center=(0, 0), + initial_value=50, + min_value=0, + max_value=100, + length=200, + line_width=5, + inner_radius=0, + outer_radius=10, + handle_side=20, + font_size=16, + orientation='horizontal', + text_alignment='', + text_template='{value:.1f} ({ratio:.0%})', + shape='disk', + ): + """Init this UI element. + + Parameters + ---------- + center : (float, float) + Center of the slider's center. + initial_value : float + Initial value of the slider. + min_value : float + Minimum value of the slider. + max_value : float + Maximum value of the slider. + length : int + Length of the slider. + line_width : int + Width of the line on which the disk will slide. + inner_radius : int + Inner radius of the handles (if disk). + outer_radius : int + Outer radius of the handles (if disk). + handle_side : int + Side length of the handles (if square). + font_size : int + Size of the text to display alongside the slider (pt). + orientation : str + horizontal or vertical + text_alignment : str + define text alignment on a slider. Left (default)/ right for the + vertical slider or top/bottom (default) for an horizontal slider. + text_template : str, callable + If str, text template can contain one or multiple of the + replacement fields: `{value:}`, `{ratio:}`. + If callable, this instance of `:class:LineSlider2D` will be + passed as argument to the text template function. + shape : string + Describes the shape of the handle. + Currently supports 'disk' and 'square'. + + """ + self.shape = shape + self.orientation = orientation.lower().strip() + self.align_dict = { + 'horizontal': ['top', 'bottom'], + 'vertical': ['left', 'right'], + } + self.default_color = (1, 1, 1) + self.active_color = (0, 0, 1) + self.alignment = text_alignment.lower() + super(LineSlider2D, self).__init__() + + if self.orientation == 'horizontal': + self.alignment = 'bottom' if not self.alignment else self.alignment + self.track.width = length + self.track.height = line_width + elif self.orientation == 'vertical': + self.alignment = 'left' if not self.alignment else self.alignment + self.track.width = line_width + self.track.height = length + else: + raise ValueError('Unknown orientation') + + if self.alignment not in self.align_dict[self.orientation]: + raise ValueError( + "Unknown alignment: choose from '{}' or '{}'".format( + *self.align_dict[self.orientation] + ) + ) + + if shape == 'disk': + self.handle.inner_radius = inner_radius + self.handle.outer_radius = outer_radius + elif shape == 'square': + self.handle.width = handle_side + self.handle.height = handle_side + self.center = center + + self.min_value = min_value + self.max_value = max_value + self.text.font_size = font_size + self.text_template = text_template + + # Offer some standard hooks to the user. + self.on_change = lambda ui: None + self.on_value_changed = lambda ui: None + self.on_moving_slider = lambda ui: None + + self.value = initial_value + self.update()
+ + + def _setup(self): + """Setup this UI component. + + Create the slider's track (Rectangle2D), the handle (Disk2D) and + the text (TextBlock2D). + """ + # Slider's track + self.track = Rectangle2D() + self.track.color = (1, 0, 0) + + # Slider's handle + if self.shape == 'disk': + self.handle = Disk2D(outer_radius=1) + elif self.shape == 'square': + self.handle = Rectangle2D(size=(1, 1)) + self.handle.color = self.default_color + + # Slider Text + self.text = TextBlock2D(justification='center', vertical_justification='top') + + # Add default events listener for this UI component. + self.track.on_left_mouse_button_pressed = self.track_click_callback + self.track.on_left_mouse_button_dragged = self.handle_move_callback + self.track.on_left_mouse_button_released = self.handle_release_callback + self.handle.on_left_mouse_button_dragged = self.handle_move_callback + self.handle.on_left_mouse_button_released = self.handle_release_callback + + def _get_actors(self): + """Get the actors composing this UI component.""" + return self.track.actors + self.handle.actors + self.text.actors + + def _add_to_scene(self, scene): + """Add all subcomponents or VTK props that compose this UI component. + + Parameters + ---------- + scene : scene + + """ + self.track.add_to_scene(scene) + self.handle.add_to_scene(scene) + self.text.add_to_scene(scene) + + def _get_size(self): + # Consider the handle's size when computing the slider's size. + width = None + height = None + if self.orientation == 'horizontal': + width = self.track.width + self.handle.size[0] + height = max(self.track.height, self.handle.size[1]) + else: + width = max(self.track.width, self.handle.size[0]) + height = self.track.height + self.handle.size[1] + + return np.array([width, height]) + + def _set_position(self, coords): + """Set the lower-left corner position of this UI component. + + Parameters + ---------- + coords: (float, float) + Absolute pixel coordinates (x, y). + + """ + # Offset the slider line by the handle's radius. + track_position = coords + self.handle.size / 2.0 + if self.orientation == 'horizontal': + # Offset the slider line height by half the slider line width. + track_position[1] -= self.track.size[1] / 2.0 + else: + # Offset the slider line width by half the slider line height. + track_position[0] += self.track.size[0] / 2.0 + + self.track.position = track_position + self.handle.position = self.handle.position.astype(float) + self.handle.position += coords - self.position + # Position the text below the handle. + if self.orientation == 'horizontal': + align = 35 if self.alignment == 'top' else -10 + self.text.position = ( + self.handle.center[0], + self.handle.position[1] + align, + ) + else: + align = 70 if self.alignment == 'right' else -35 + self.text.position = ( + self.handle.position[0] + align, + self.handle.center[1] + 2, + ) + + @property + def bottom_y_position(self): + return self.track.position[1] + + @property + def top_y_position(self): + return self.track.position[1] + self.track.size[1] + + @property + def left_x_position(self): + return self.track.position[0] + + @property + def right_x_position(self): + return self.track.position[0] + self.track.size[0] + +
+[docs] + def set_position(self, position): + """Set the disk's position. + + Parameters + ---------- + position : (float, float) + The absolute position of the disk (x, y). + + """ + # Move slider disk. + if self.orientation == 'horizontal': + x_position = position[0] + x_position = max(x_position, self.left_x_position) + x_position = min(x_position, self.right_x_position) + self.handle.center = (x_position, self.track.center[1]) + else: + y_position = position[1] + y_position = max(y_position, self.bottom_y_position) + y_position = min(y_position, self.top_y_position) + self.handle.center = (self.track.center[0], y_position) + self.update() # Update information.
+ + + @property + def value(self): + return self._value + + @value.setter + def value(self, value): + value_range = self.max_value - self.min_value + self.ratio = (value - self.min_value) / value_range if value_range else 0 + self.on_value_changed(self) + + @property + def ratio(self): + return self._ratio + + @ratio.setter + def ratio(self, ratio): + position_x = self.left_x_position + ratio * self.track.width + position_y = self.bottom_y_position + ratio * self.track.height + self.set_position((position_x, position_y)) + +
+[docs] + def format_text(self): + """Return formatted text to display along the slider.""" + if callable(self.text_template): + return self.text_template(self) + return self.text_template.format(ratio=self.ratio, value=self.value)
+ + +
+[docs] + def update(self): + """Update the slider.""" + # Compute the ratio determined by the position of the slider disk. + disk_position_x = None + disk_position_y = None + + if self.orientation == 'horizontal': + length = float(self.right_x_position - self.left_x_position) + length = np.round(length, decimals=6) + if length != self.track.width: + raise ValueError('Disk position outside the slider line') + disk_position_x = self.handle.center[0] + self._ratio = (disk_position_x - self.left_x_position) / length + else: + length = float(self.top_y_position - self.bottom_y_position) + if length != self.track.height: + raise ValueError('Disk position outside the slider line') + disk_position_y = self.handle.center[1] + self._ratio = (disk_position_y - self.bottom_y_position) / length + + # Compute the selected value considering min_value and max_value. + value_range = self.max_value - self.min_value + self._value = self.min_value + self.ratio * value_range + + # Update text. + text = self.format_text() + self.text.message = text + + # Move the text below the slider's handle. + if self.orientation == 'horizontal': + self.text.position = (disk_position_x, self.text.position[1]) + else: + self.text.position = (self.text.position[0], disk_position_y) + + self.on_change(self)
+ + +
+[docs] + def track_click_callback(self, i_ren, _vtkactor, _slider): + """Update disk position and grab the focus. + + Parameters + ---------- + i_ren : :class:`CustomInteractorStyle` + vtkactor : :class:`vtkActor` + The picked actor + _slider : :class:`LineSlider2D` + + """ + position = i_ren.event.position + self.set_position(position) + self.on_moving_slider(self) + i_ren.force_render() + i_ren.event.abort() # Stop propagating the event.
+ + +
+[docs] + def handle_move_callback(self, i_ren, _vtkactor, _slider): + """Handle movement. + + Parameters + ---------- + i_ren : :class:`CustomInteractorStyle` + vtkactor : :class:`vtkActor` + The picked actor + slider : :class:`LineSlider2D` + + """ + self.handle.color = self.active_color + position = i_ren.event.position + self.set_position(position) + self.on_moving_slider(self) + i_ren.force_render() + i_ren.event.abort() # Stop propagating the event.
+ + +
+[docs] + def handle_release_callback(self, i_ren, _vtkactor, _slider): + """Change color when handle is released. + + Parameters + ---------- + i_ren : :class:`CustomInteractorStyle` + vtkactor : :class:`vtkActor` + The picked actor + slider : :class:`LineSlider2D` + + """ + self.handle.color = self.default_color + i_ren.force_render()
+
+ + + +
+[docs] +class LineDoubleSlider2D(UI): + """A 2D Line Slider with two sliding rings. + + Useful for setting min and max values for something. + + Currently supports: + - Setting positions of both disks. + + Attributes + ---------- + line_width : int + Width of the line on which the disk will slide. + length : int + Length of the slider. + track : :class:`vtkActor` + The line on which the handles move. + handles : [:class:`vtkActor`, :class:`vtkActor`] + The moving slider disks. + text : [:class:`TextBlock2D`, :class:`TextBlock2D`] + The texts that show the values of the disks. + shape : string + Describes the shape of the handle. + Currently supports 'disk' and 'square'. + default_color : (float, float, float) + Color of the handles when in unpressed state. + active_color : (float, float, float) + Color of the handles when they are pressed. + + """ + +
+[docs] + def __init__( + self, + line_width=5, + inner_radius=0, + outer_radius=10, + handle_side=20, + center=(450, 300), + length=200, + initial_values=(0, 100), + min_value=0, + max_value=100, + font_size=16, + text_template='{value:.1f}', + orientation='horizontal', + shape='disk', + ): + """Init this UI element. + + Parameters + ---------- + line_width : int + Width of the line on which the disk will slide. + inner_radius : int + Inner radius of the handles (if disk). + outer_radius : int + Outer radius of the handles (if disk). + handle_side : int + Side length of the handles (if square). + center : (float, float) + Center of the slider. + length : int + Length of the slider. + initial_values : (float, float) + Initial values of the two handles. + min_value : float + Minimum value of the slider. + max_value : float + Maximum value of the slider. + font_size : int + Size of the text to display alongside the slider (pt). + text_template : str, callable + If str, text template can contain one or multiple of the + replacement fields: `{value:}`, `{ratio:}`. + If callable, this instance of `:class:LineDoubleSlider2D` will be + passed as argument to the text template function. + orientation : str + horizontal or vertical + shape : string + Describes the shape of the handle. + Currently supports 'disk' and 'square'. + + """ + self.shape = shape + self.default_color = (1, 1, 1) + self.active_color = (0, 0, 1) + self.orientation = orientation.lower() + super(LineDoubleSlider2D, self).__init__() + + if self.orientation == 'horizontal': + self.track.width = length + self.track.height = line_width + elif self.orientation == 'vertical': + self.track.width = line_width + self.track.height = length + else: + raise ValueError('Unknown orientation') + + self.center = center + if shape == 'disk': + self.handles[0].inner_radius = inner_radius + self.handles[0].outer_radius = outer_radius + self.handles[1].inner_radius = inner_radius + self.handles[1].outer_radius = outer_radius + elif shape == 'square': + self.handles[0].width = handle_side + self.handles[0].height = handle_side + self.handles[1].width = handle_side + self.handles[1].height = handle_side + + self.min_value = min_value + self.max_value = max_value + self.text[0].font_size = font_size + self.text[1].font_size = font_size + self.text_template = text_template + + # Offer some standard hooks to the user. + self.on_change = lambda ui: None + self.on_value_changed = lambda ui: None + self.on_moving_slider = lambda ui: None + + # Setting the handle positions will also update everything. + self._values = [initial_values[0], initial_values[1]] + self._ratio = [None, None] + self.left_disk_value = initial_values[0] + self.right_disk_value = initial_values[1] + self.bottom_disk_value = initial_values[0] + self.top_disk_value = initial_values[1]
+ + + def _setup(self): + """Setup this UI component. + + Create the slider's track (Rectangle2D), the handles (Disk2D) and + the text (TextBlock2D). + + """ + # Slider's track + self.track = Rectangle2D() + self.track.color = (1, 0, 0) + + # Handles + self.handles = [] + if self.shape == 'disk': + self.handles.append(Disk2D(outer_radius=1)) + self.handles.append(Disk2D(outer_radius=1)) + elif self.shape == 'square': + self.handles.append(Rectangle2D(size=(1, 1))) + self.handles.append(Rectangle2D(size=(1, 1))) + self.handles[0].color = self.default_color + self.handles[1].color = self.default_color + + # Slider Text + self.text = [ + TextBlock2D(justification='center', vertical_justification='top'), + TextBlock2D(justification='center', vertical_justification='top'), + ] + + # Add default events listener for this UI component. + self.track.on_left_mouse_button_dragged = self.handle_move_callback + self.handles[0].on_left_mouse_button_dragged = self.handle_move_callback + self.handles[1].on_left_mouse_button_dragged = self.handle_move_callback + self.handles[0].on_left_mouse_button_released = self.handle_release_callback + self.handles[1].on_left_mouse_button_released = self.handle_release_callback + + def _get_actors(self): + """Get the actors composing this UI component.""" + return ( + self.track.actors + + self.handles[0].actors + + self.handles[1].actors + + self.text[0].actors + + self.text[1].actors + ) + + def _add_to_scene(self, scene): + """Add all subcomponents or VTK props that compose this UI component. + + Parameters + ---------- + scene : scene + + """ + self.track.add_to_scene(scene) + self.handles[0].add_to_scene(scene) + self.handles[1].add_to_scene(scene) + self.text[0].add_to_scene(scene) + self.text[1].add_to_scene(scene) + + def _get_size(self): + # Consider the handle's size when computing the slider's size. + width = None + height = None + if self.orientation == 'horizontal': + width = self.track.width + self.handles[0].size[0] + height = max(self.track.height, self.handles[0].size[1]) + else: + width = max(self.track.width, self.handles[0].size[0]) + height = self.track.height + self.handles[0].size[1] + + return np.array([width, height]) + + def _set_position(self, coords): + """Set the lower-left corner position of this UI component. + + Parameters + ---------- + coords: (float, float) + Absolute pixel coordinates (x, y). + + """ + # Offset the slider line by the handle's radius. + track_position = coords + if self.orientation == 'horizontal': + # Offset the slider line height by half the slider line width. + track_position[1] -= self.track.size[1] / 2.0 + else: + # Offset the slider line width by half the slider line height. + track_position[0] -= self.track.size[0] / 2.0 + + self.track.position = track_position + + self.handles[0].position = self.handles[0].position.astype(float) + self.handles[1].position = self.handles[1].position.astype(float) + + self.handles[0].position += coords - self.position + self.handles[1].position += coords - self.position + + if self.orientation == 'horizontal': + # Position the text below the handles. + self.text[0].position = ( + self.handles[0].center[0], + self.handles[0].position[1] - 10, + ) + self.text[1].position = ( + self.handles[1].center[0], + self.handles[1].position[1] - 10, + ) + else: + # Position the text to the left of the handles. + self.text[0].position = ( + self.handles[0].center[0] - 35, + self.handles[0].position[1], + ) + self.text[1].position = ( + self.handles[1].center[0] - 35, + self.handles[1].position[1], + ) + + @property + def bottom_y_position(self): + return self.track.position[1] + + @property + def top_y_position(self): + return self.track.position[1] + self.track.size[1] + + @property + def left_x_position(self): + return self.track.position[0] + + @property + def right_x_position(self): + return self.track.position[0] + self.track.size[0] + +
+[docs] + def value_to_ratio(self, value): + """Convert the value of a disk to the ratio. + + Parameters + ---------- + value : float + + """ + value_range = self.max_value - self.min_value + return (value - self.min_value) / value_range if value_range else 0
+ + +
+[docs] + def ratio_to_coord(self, ratio): + """Convert the ratio to the absolute coordinate. + + Parameters + ---------- + ratio : float + + """ + if self.orientation == 'horizontal': + return self.left_x_position + ratio * self.track.width + return self.bottom_y_position + ratio * self.track.height
+ + +
+[docs] + def coord_to_ratio(self, coord): + """Convert the x coordinate of a disk to the ratio. + + Parameters + ---------- + coord : float + + """ + if self.orientation == 'horizontal': + return (coord - self.left_x_position) / float(self.track.width) + return (coord - self.bottom_y_position) / float(self.track.height)
+ + +
+[docs] + def ratio_to_value(self, ratio): + """Convert the ratio to the value of the disk. + + Parameters + ---------- + ratio : float + + """ + value_range = self.max_value - self.min_value + return self.min_value + ratio * value_range
+ + +
+[docs] + def set_position(self, position, disk_number): + """Set the disk's position. + + Parameters + ---------- + position : (float, float) + The absolute position of the disk (x, y). + disk_number : int + The index of disk being moved. + + """ + if self.orientation == 'horizontal': + x_position = position[0] + + if disk_number == 0 and x_position >= self.handles[1].center[0]: + x_position = self.ratio_to_coord( + self.value_to_ratio(self._values[1] - 1) + ) + + if disk_number == 1 and x_position <= self.handles[0].center[0]: + x_position = self.ratio_to_coord( + self.value_to_ratio(self._values[0] + 1) + ) + + x_position = max(x_position, self.left_x_position) + x_position = min(x_position, self.right_x_position) + + self.handles[disk_number].center = (x_position, self.track.center[1]) + else: + y_position = position[1] + + if disk_number == 0 and y_position >= self.handles[1].center[1]: + y_position = self.ratio_to_coord( + self.value_to_ratio(self._values[1] - 1) + ) + + if disk_number == 1 and y_position <= self.handles[0].center[1]: + y_position = self.ratio_to_coord( + self.value_to_ratio(self._values[0] + 1) + ) + + y_position = max(y_position, self.bottom_y_position) + y_position = min(y_position, self.top_y_position) + + self.handles[disk_number].center = (self.track.center[0], y_position) + self.update(disk_number)
+ + + @property + def bottom_disk_value(self): + """Return the value of the bottom disk.""" + return self._values[0] + + @bottom_disk_value.setter + def bottom_disk_value(self, bottom_disk_value): + """Set the value of the bottom disk. + + Parameters + ---------- + bottom_disk_value : float + New value for the bottom disk. + + """ + self.bottom_disk_ratio = self.value_to_ratio(bottom_disk_value) + + @property + def top_disk_value(self): + """Return the value of the top disk.""" + return self._values[1] + + @top_disk_value.setter + def top_disk_value(self, top_disk_value): + """Set the value of the top disk. + + Parameters + ---------- + top_disk_value : float + New value for the top disk. + + """ + self.top_disk_ratio = self.value_to_ratio(top_disk_value) + + @property + def left_disk_value(self): + """Return the value of the left disk.""" + return self._values[0] + + @left_disk_value.setter + def left_disk_value(self, left_disk_value): + """Set the value of the left disk. + + Parameters + ---------- + left_disk_value : float + New value for the left disk. + + """ + self.left_disk_ratio = self.value_to_ratio(left_disk_value) + self.on_value_changed(self) + + @property + def right_disk_value(self): + """Return the value of the right disk.""" + return self._values[1] + + @right_disk_value.setter + def right_disk_value(self, right_disk_value): + """Set the value of the right disk. + + Parameters + ---------- + right_disk_value : float + New value for the right disk. + + """ + self.right_disk_ratio = self.value_to_ratio(right_disk_value) + self.on_value_changed(self) + + @property + def bottom_disk_ratio(self): + """Return the ratio of the bottom disk.""" + return self._ratio[0] + + @bottom_disk_ratio.setter + def bottom_disk_ratio(self, bottom_disk_ratio): + """Set the ratio of the bottom disk. + + Parameters + ---------- + bottom_disk_ratio : float + New ratio for the bottom disk. + + """ + position_x = self.ratio_to_coord(bottom_disk_ratio) + position_y = self.ratio_to_coord(bottom_disk_ratio) + self.set_position((position_x, position_y), 0) + + @property + def top_disk_ratio(self): + """Return the ratio of the top disk.""" + return self._ratio[1] + + @top_disk_ratio.setter + def top_disk_ratio(self, top_disk_ratio): + """Set the ratio of the top disk. + + Parameters + ---------- + top_disk_ratio : float + New ratio for the top disk. + + """ + position_x = self.ratio_to_coord(top_disk_ratio) + position_y = self.ratio_to_coord(top_disk_ratio) + self.set_position((position_x, position_y), 1) + + @property + def left_disk_ratio(self): + """Return the ratio of the left disk.""" + return self._ratio[0] + + @left_disk_ratio.setter + def left_disk_ratio(self, left_disk_ratio): + """Set the ratio of the left disk. + + Parameters + ---------- + left_disk_ratio : float + New ratio for the left disk. + + """ + position_x = self.ratio_to_coord(left_disk_ratio) + position_y = self.ratio_to_coord(left_disk_ratio) + self.set_position((position_x, position_y), 0) + + @property + def right_disk_ratio(self): + """Return the ratio of the right disk.""" + return self._ratio[1] + + @right_disk_ratio.setter + def right_disk_ratio(self, right_disk_ratio): + """Set the ratio of the right disk. + + Parameters + ---------- + right_disk_ratio : float + New ratio for the right disk. + + """ + position_x = self.ratio_to_coord(right_disk_ratio) + position_y = self.ratio_to_coord(right_disk_ratio) + self.set_position((position_x, position_y), 1) + +
+[docs] + def format_text(self, disk_number): + """Return formatted text to display along the slider. + + Parameters + ---------- + disk_number : int + Index of the disk. + + """ + if callable(self.text_template): + return self.text_template(self) + + return self.text_template.format(value=self._values[disk_number])
+ + +
+[docs] + def update(self, disk_number): + """Update the slider. + + Parameters + ---------- + disk_number : int + Index of the disk to be updated. + + """ + # Compute the ratio determined by the position of the slider disk. + if self.orientation == 'horizontal': + self._ratio[disk_number] = self.coord_to_ratio( + self.handles[disk_number].center[0] + ) + else: + self._ratio[disk_number] = self.coord_to_ratio( + self.handles[disk_number].center[1] + ) + + # Compute the selected value considering min_value and max_value. + self._values[disk_number] = self.ratio_to_value(self._ratio[disk_number]) + + # Update text. + text = self.format_text(disk_number) + self.text[disk_number].message = text + + if self.orientation == 'horizontal': + self.text[disk_number].position = ( + self.handles[disk_number].center[0], + self.text[disk_number].position[1], + ) + else: + self.text[disk_number].position = ( + self.text[disk_number].position[0], + self.handles[disk_number].center[1], + ) + self.on_change(self)
+ + +
+[docs] + def handle_move_callback(self, i_ren, vtkactor, _slider): + """Handle movement. + + Parameters + ---------- + i_ren : :class:`CustomInteractorStyle` + vtkactor : :class:`vtkActor` + The picked actor + _slider : :class:`LineDoubleSlider2D` + + """ + position = i_ren.event.position + if vtkactor == self.handles[0].actors[0]: + self.set_position(position, 0) + self.handles[0].color = self.active_color + elif vtkactor == self.handles[1].actors[0]: + self.set_position(position, 1) + self.handles[1].color = self.active_color + self.on_moving_slider(self) + i_ren.force_render() + i_ren.event.abort() # Stop propagating the event.
+ + +
+[docs] + def handle_release_callback(self, i_ren, vtkactor, _slider): + """Change color when handle is released. + + Parameters + ---------- + i_ren : :class:`CustomInteractorStyle` + vtkactor : :class:`vtkActor` + The picked actor + _slider : :class:`LineDoubleSlider2D` + + """ + if vtkactor == self.handles[0].actors[0]: + self.handles[0].color = self.default_color + elif vtkactor == self.handles[1].actors[0]: + self.handles[1].color = self.default_color + i_ren.force_render()
+
+ + + +
+[docs] +class RingSlider2D(UI): + """A disk slider. + + A disk moves along the boundary of a ring. + Goes from 0-360 degrees. + + Attributes + ---------- + mid_track_radius: float + Distance from the center of the slider to the middle of the track. + previous_value: float + Value of Rotation of the actor before the current value. + track : :class:`Disk2D` + The circle on which the slider's handle moves. + handle : :class:`Disk2D` + The moving part of the slider. + text : :class:`TextBlock2D` + The text that shows percentage. + default_color : (float, float, float) + Color of the handle when in unpressed state. + active_color : (float, float, float) + Color of the handle when it is pressed. + + """ + +
+[docs] + def __init__( + self, + center=(0, 0), + initial_value=180, + min_value=0, + max_value=360, + slider_inner_radius=40, + slider_outer_radius=44, + handle_inner_radius=0, + handle_outer_radius=10, + font_size=16, + text_template='{ratio:.0%}', + ): + """Init this UI element. + + Parameters + ---------- + center : (float, float) + Position (x, y) of the slider's center. + initial_value : float + Initial value of the slider. + min_value : float + Minimum value of the slider. + max_value : float + Maximum value of the slider. + slider_inner_radius : int + Inner radius of the base disk. + slider_outer_radius : int + Outer radius of the base disk. + handle_outer_radius : int + Outer radius of the slider's handle. + handle_inner_radius : int + Inner radius of the slider's handle. + font_size : int + Size of the text to display alongside the slider (pt). + text_template : str, callable + If str, text template can contain one or multiple of the + replacement fields: `{value:}`, `{ratio:}`, `{angle:}`. + If callable, this instance of `:class:RingSlider2D` will be + passed as argument to the text template function. + + """ + self.default_color = (1, 1, 1) + self.active_color = (0, 0, 1) + super(RingSlider2D, self).__init__() + + self.track.inner_radius = slider_inner_radius + self.track.outer_radius = slider_outer_radius + self.handle.inner_radius = handle_inner_radius + self.handle.outer_radius = handle_outer_radius + self.center = center + + self.min_value = min_value + self.max_value = max_value + self.text.font_size = font_size + self.text_template = text_template + + # Offer some standard hooks to the user. + self.on_change = lambda ui: None + self.on_value_changed = lambda ui: None + self.on_moving_slider = lambda ui: None + + self._value = initial_value + self.value = initial_value + self._previous_value = initial_value + self._angle = 0 + self._ratio = self.angle / TWO_PI
+ + + def _setup(self): + """Setup this UI component. + + Create the slider's circle (Disk2D), the handle (Disk2D) and + the text (TextBlock2D). + + """ + # Slider's track. + self.track = Disk2D(outer_radius=1) + self.track.color = (1, 0, 0) + + # Slider's handle. + self.handle = Disk2D(outer_radius=1) + self.handle.color = self.default_color + + # Slider Text + self.text = TextBlock2D(justification='center', + vertical_justification='middle') + + # Add default events listener for this UI component. + self.track.on_left_mouse_button_pressed = self.track_click_callback + self.track.on_left_mouse_button_dragged = self.handle_move_callback + self.track.on_left_mouse_button_released = self.handle_release_callback + self.handle.on_left_mouse_button_dragged = self.handle_move_callback + self.handle.on_left_mouse_button_released = self.handle_release_callback + + def _get_actors(self): + """Get the actors composing this UI component.""" + return self.track.actors + self.handle.actors + self.text.actors + + def _add_to_scene(self, scene): + """Add all subcomponents or VTK props that compose this UI component. + + Parameters + ---------- + scene : scene + + """ + self.track.add_to_scene(scene) + self.handle.add_to_scene(scene) + self.text.add_to_scene(scene) + + def _get_size(self): + return self.track.size + self.handle.size + + def _set_position(self, coords): + """Set the lower-left corner position of this UI component. + + Parameters + ---------- + coords: (float, float) + Absolute pixel coordinates (x, y). + + """ + self.track.position = coords + self.handle.size / 2.0 + self.handle.position += coords - self.position + # Position the text in the center of the slider's track. + self.text.position = coords + self.size / 2.0 + + @property + def mid_track_radius(self): + return (self.track.inner_radius + self.track.outer_radius) / 2.0 + + @property + def value(self): + return self._value + + @value.setter + def value(self, value): + value_range = self.max_value - self.min_value + self.ratio = (value - self.min_value) / value_range if value_range else 0 + self.on_value_changed(self) + + @property + def previous_value(self): + return self._previous_value + + @property + def ratio(self): + return self._ratio + + @ratio.setter + def ratio(self, ratio): + self.angle = ratio * TWO_PI + + @property + def angle(self): + """Return Angle (in rad) the handle makes with x-axis.""" + return self._angle + + @angle.setter + def angle(self, angle): + self._angle = angle % TWO_PI # Wraparound + self.update() + +
+[docs] + def format_text(self): + """Return formatted text to display along the slider.""" + if callable(self.text_template): + return self.text_template(self) + + return self.text_template.format( + ratio=self.ratio, value=self.value, angle=np.rad2deg(self.angle) + )
+ + +
+[docs] + def update(self): + """Update the slider.""" + # Compute the ratio determined by the position of the slider disk. + self._ratio = self.angle / TWO_PI + + # Compute the selected value considering min_value and max_value. + value_range = self.max_value - self.min_value + self._previous_value = self.value + self._value = self.min_value + self.ratio * value_range + + # Update text disk actor. + x = self.mid_track_radius * np.cos(self.angle) + self.center[0] + y = self.mid_track_radius * np.sin(self.angle) + self.center[1] + self.handle.center = (x, y) + + # Update text. + text = self.format_text() + self.text.message = text + + self.on_change(self) # Call hook.
+ + +
+[docs] + def move_handle(self, click_position): + """Move the slider's handle. + + Parameters + ---------- + click_position: (float, float) + Position of the mouse click. + + """ + x, y = np.array(click_position) - self.center + angle = np.arctan2(y, x) + if angle < 0: + angle += TWO_PI + + self.angle = angle
+ + +
+[docs] + def track_click_callback(self, i_ren, _obj, _slider): + """Update disk position and grab the focus. + + Parameters + ---------- + i_ren : :class:`CustomInteractorStyle` + obj : :class:`vtkActor` + The picked actor + _slider : :class:`RingSlider2D` + + """ + click_position = i_ren.event.position + self.move_handle(click_position=click_position) + self.on_moving_slider(self) + i_ren.force_render() + i_ren.event.abort() # Stop propagating the event.
+ + +
+[docs] + def handle_move_callback(self, i_ren, _obj, _slider): + """Move the slider's handle. + + Parameters + ---------- + i_ren : :class:`CustomInteractorStyle` + obj : :class:`vtkActor` + The picked actor + _slider : :class:`RingSlider2D` + + """ + click_position = i_ren.event.position + self.handle.color = self.active_color + self.move_handle(click_position=click_position) + self.on_moving_slider(self) + i_ren.force_render() + i_ren.event.abort() # Stop propagating the event.
+ + +
+[docs] + def handle_release_callback(self, i_ren, _obj, _slider): + """Change color when handle is released. + + Parameters + ---------- + i_ren : :class:`CustomInteractorStyle` + vtkactor : :class:`vtkActor` + The picked actor + _slider : :class:`RingSlider2D` + + """ + self.handle.color = self.default_color + i_ren.force_render()
+
+ + + +
+[docs] +class RangeSlider(UI): + """A set of a LineSlider2D and a LineDoubleSlider2D. + The double slider is used to set the min and max value + for the LineSlider2D + + Attributes + ---------- + range_slider_center : (float, float) + Center of the LineDoubleSlider2D object. + value_slider_center : (float, float) + Center of the LineSlider2D object. + range_slider : :class:`LineDoubleSlider2D` + The line slider which sets the min and max values + value_slider : :class:`LineSlider2D` + The line slider which sets the value + + """ + +
+[docs] + def __init__( + self, + line_width=5, + inner_radius=0, + outer_radius=10, + handle_side=20, + range_slider_center=(450, 400), + value_slider_center=(450, 300), + length=200, + min_value=0, + max_value=100, + font_size=16, + range_precision=1, + orientation='horizontal', + value_precision=2, + shape='disk', + ): + """Init this class instance. + + Parameters + ---------- + line_width : int + Width of the slider tracks + inner_radius : int + Inner radius of the handles. + outer_radius : int + Outer radius of the handles. + handle_side : int + Side length of the handles (if square). + range_slider_center : (float, float) + Center of the LineDoubleSlider2D object. + value_slider_center : (float, float) + Center of the LineSlider2D object. + length : int + Length of the sliders. + min_value : float + Minimum value of the double slider. + max_value : float + Maximum value of the double slider. + font_size : int + Size of the text to display alongside the sliders (pt). + range_precision : int + Number of decimal places to show the min and max values set. + orientation : str + horizontal or vertical + value_precision : int + Number of decimal places to show the value set on slider. + shape : string + Describes the shape of the handle. + Currently supports 'disk' and 'square'. + + """ + self.min_value = min_value + self.max_value = max_value + self.inner_radius = inner_radius + self.outer_radius = outer_radius + self.handle_side = handle_side + self.length = length + self.line_width = line_width + self.font_size = font_size + self.shape = shape + self.orientation = orientation.lower() + + self.range_slider_text_template = '{value:.' + str(range_precision) + 'f}' + self.value_slider_text_template = '{value:.' + str(value_precision) + 'f}' + + self.range_slider_center = range_slider_center + self.value_slider_center = value_slider_center + super(RangeSlider, self).__init__()
+ + + def _setup(self): + """Setup this UI component.""" + self.range_slider = LineDoubleSlider2D( + line_width=self.line_width, + inner_radius=self.inner_radius, + outer_radius=self.outer_radius, + handle_side=self.handle_side, + center=self.range_slider_center, + length=self.length, + min_value=self.min_value, + max_value=self.max_value, + initial_values=(self.min_value, self.max_value), + font_size=self.font_size, + shape=self.shape, + orientation=self.orientation, + text_template=self.range_slider_text_template, + ) + + self.value_slider = LineSlider2D( + line_width=self.line_width, + length=self.length, + inner_radius=self.inner_radius, + outer_radius=self.outer_radius, + handle_side=self.handle_side, + center=self.value_slider_center, + min_value=self.min_value, + max_value=self.max_value, + initial_value=(self.min_value + self.max_value) / 2, + font_size=self.font_size, + shape=self.shape, + orientation=self.orientation, + text_template=self.value_slider_text_template, + ) + + # Add default events listener for this UI component. + self.range_slider.handles[ + 0 + ].on_left_mouse_button_dragged = self.range_slider_handle_move_callback + self.range_slider.handles[ + 1 + ].on_left_mouse_button_dragged = self.range_slider_handle_move_callback + + def _get_actors(self): + """Get the actors composing this UI component.""" + return self.range_slider.actors + self.value_slider.actors + + def _add_to_scene(self, scene): + """Add all subcomponents or VTK props that compose this UI component. + + Parameters + ---------- + scene : scene + + """ + self.range_slider.add_to_scene(scene) + self.value_slider.add_to_scene(scene) + + def _get_size(self): + return self.range_slider.size + self.value_slider.size + + def _set_position(self, coords): + pass + +
+[docs] + def range_slider_handle_move_callback(self, i_ren, obj, _slider): + """Update range_slider's handles. + + Parameters + ---------- + i_ren : :class:`CustomInteractorStyle` + obj : :class:`vtkActor` + The picked actor + _slider : :class:`RangeSlider` + + """ + position = i_ren.event.position + if obj == self.range_slider.handles[0].actors[0]: + self.range_slider.handles[0].color = self.range_slider.active_color + self.range_slider.set_position(position, 0) + self.value_slider.min_value = self.range_slider.left_disk_value + self.value_slider.update() + elif obj == self.range_slider.handles[1].actors[0]: + self.range_slider.handles[1].color = self.range_slider.active_color + self.range_slider.set_position(position, 1) + self.value_slider.max_value = self.range_slider.right_disk_value + self.value_slider.update() + i_ren.force_render() + i_ren.event.abort() # Stop propagating the event.
+
+ + + +
+[docs] +class Option(UI): + """A set of a Button2D and a TextBlock2D to act as a single option + for checkboxes and radio buttons. + Clicking the button toggles its checked/unchecked status. + + Attributes + ---------- + label : str + The label for the option. + font_size : int + Font Size of the label. + + """ + +
+[docs] + def __init__(self, label, position=(0, 0), font_size=18, checked=False): + """Init this class instance. + + Parameters + ---------- + label : str + Text to be displayed next to the option's button. + position : (float, float) + Absolute coordinates (x, y) of the lower-left corner of + the button of the option. + font_size : int + Font size of the label. + checked : bool, optional + Boolean value indicates the initial state of the option + + """ + self.label = label + self.font_size = font_size + self.checked = checked + self.button_size = (font_size * 1.2, font_size * 1.2) + self.button_label_gap = 10 + super(Option, self).__init__(position) + + # Offer some standard hooks to the user. + self.on_change = lambda obj: None
+ + + def _setup(self): + """Setup this UI component.""" + # Option's button + self.button_icons = [] + self.button_icons.append(('unchecked', read_viz_icons(fname='stop2.png'))) + self.button_icons.append(('checked', read_viz_icons(fname='checkmark.png'))) + self.button = Button2D(icon_fnames=self.button_icons, size=self.button_size) + + self.text = TextBlock2D(text=self.label, font_size=self.font_size) + + # Display initial state + if self.checked: + self.button.set_icon_by_name('checked') + + # Add callbacks + self.button.on_left_mouse_button_clicked = self.toggle + self.text.on_left_mouse_button_clicked = self.toggle + + def _get_actors(self): + """Get the actors composing this UI component.""" + return self.button.actors + self.text.actors + + def _add_to_scene(self, scene): + """Add all subcomponents or VTK props that compose this UI component. + + Parameters + ---------- + scene : scene + + """ + self.button.add_to_scene(scene) + self.text.add_to_scene(scene) + + def _get_size(self): + width = self.button.size[0] + self.button_label_gap + self.text.size[0] + height = max(self.button.size[1], self.text.size[1]) + return np.array([width, height]) + + def _set_position(self, coords): + """Set the lower-left corner position of this UI component. + + Parameters + ---------- + coords: (float, float) + Absolute pixel coordinates (x, y). + + """ + num_newlines = self.label.count('\n') + self.button.position = coords + (0, num_newlines * self.font_size * 0.5) + offset = (self.button.size[0] + self.button_label_gap, 0) + self.text.position = coords + offset + +
+[docs] + def toggle(self, i_ren, _obj, _element): + if self.checked: + self.deselect() + else: + self.select() + + self.on_change(self) + i_ren.force_render()
+ + +
+[docs] + def select(self): + self.checked = True + self.button.set_icon_by_name('checked')
+ + +
+[docs] + def deselect(self): + self.checked = False + self.button.set_icon_by_name('unchecked')
+
+ + + +
+[docs] +class Checkbox(UI): + """A 2D set of :class:'Option' objects. + Multiple options can be selected. + + Attributes + ---------- + labels : list(string) + List of labels of each option. + options : dict(Option) + Dictionary of all the options in the checkbox set. + padding : float + Distance between two adjacent options + + """ + +
+[docs] + def __init__( + self, + labels, + checked_labels=(), + padding=1, + font_size=18, + font_family='Arial', + position=(0, 0), + ): + """Init this class instance. + + Parameters + ---------- + labels : list(str) + List of labels of each option. + checked_labels: list(str), optional + List of labels that are checked on setting up. + padding : float, optional + The distance between two adjacent options + font_size : int, optional + Size of the text font. + font_family : str, optional + Currently only supports Arial. + position : (float, float), optional + Absolute coordinates (x, y) of the lower-left corner of + the button of the first option. + + """ + self.labels = list(reversed(list(labels))) + self._padding = padding + self._font_size = font_size + self.font_family = font_family + self.checked_labels = list(checked_labels) + super(Checkbox, self).__init__(position) + self.on_change = lambda checkbox: None
+ + + def _setup(self): + """Setup this UI component.""" + self.options = OrderedDict() + button_y = self.position[1] + for label in self.labels: + + option = Option( + label=label, + font_size=self.font_size, + position=(self.position[0], button_y), + checked=(label in self.checked_labels), + ) + + line_spacing = option.text.actor.GetTextProperty().GetLineSpacing() + button_y = ( + button_y + + self.font_size * (label.count('\n') + 1) * (line_spacing + 0.1) + + self.padding + ) + self.options[label] = option + + # Set callback + option.on_change = self._handle_option_change + + def _get_actors(self): + """Get the actors composing this UI component.""" + actors = [] + for option in self.options.values(): + actors = actors + option.actors + return actors + + def _add_to_scene(self, scene): + """Add all subcomponents or VTK props that compose this UI component. + + Parameters + ---------- + scene : scene + + """ + for option in self.options.values(): + option.add_to_scene(scene) + + def _get_size(self): + option_width, option_height = self.options.values()[0].get_size() + height = len(self.labels) * (option_height + self.padding) - self.padding + return np.asarray([option_width, height]) + + def _handle_option_change(self, option): + """Update whenever an option changes. + + Parameters + ---------- + option : :class:`Option` + + """ + if option.checked: + self.checked_labels.append(option.label) + else: + self.checked_labels.remove(option.label) + + self.on_change(self) + + def _set_position(self, coords): + """Set the lower-left corner position of this UI component. + + Parameters + ---------- + coords: (float, float) + Absolute pixel coordinates (x, y). + + """ + button_y = coords[1] + for option_no, option in enumerate(self.options.values()): + option.position = (coords[0], button_y) + line_spacing = option.text.actor.GetTextProperty().GetLineSpacing() + button_y = ( + button_y + + self.font_size + * (self.labels[option_no].count('\n') + 1) + * (line_spacing + 0.1) + + self.padding + ) + + @property + def font_size(self): + """Gets the font size of text.""" + return self._font_size + + @property + def padding(self): + """Get the padding between options.""" + return self._padding
+ + + +
+[docs] +class RadioButton(Checkbox): + """A 2D set of :class:'Option' objects. + Only one option can be selected. + + Attributes + ---------- + labels : list(string) + List of labels of each option. + options : dict(Option) + Dictionary of all the options in the checkbox set. + padding : float + Distance between two adjacent options + + """ + +
+[docs] + def __init__( + self, + labels, + checked_labels, + padding=1, + font_size=18, + font_family='Arial', + position=(0, 0), + ): + """Init class instance. + + Parameters + ---------- + labels : list(str) + List of labels of each option. + checked_labels: list(str), optional + List of labels that are checked on setting up. + padding : float, optional + The distance between two adjacent options + font_size : int, optional + Size of the text font. + font_family : str, optional + Currently only supports Arial. + position : (float, float), optional + Absolute coordinates (x, y) of the lower-left corner of + the button of the first option. + + """ + if len(checked_labels) > 1: + err_msg = 'Only one option can be pre-selected for radio buttons.' + raise ValueError(err_msg) + + super(RadioButton, self).__init__( + labels=labels, + position=position, + padding=padding, + font_size=font_size, + font_family=font_family, + checked_labels=checked_labels, + )
+ + + def _handle_option_change(self, option): + for option_ in self.options.values(): + option_.deselect() + + option.select() + self.checked_labels = [option.label] + self.on_change(self)
+ + + +
+[docs] +class ComboBox2D(UI): + """UI element to create drop-down menus. + + Attributes + ---------- + selection_box: :class: 'TextBox2D' + Display selection and placeholder text. + drop_down_button: :class: 'Button2D' + Button to show or hide menu. + drop_down_menu: :class: 'ListBox2D' + Container for item list. + + """ + +
+[docs] + def __init__( + self, + items=[], + position=(0, 0), + size=(300, 200), + placeholder='Choose selection...', + draggable=True, + selection_text_color=(0, 0, 0), + selection_bg_color=(1, 1, 1), + menu_text_color=(0.2, 0.2, 0.2), + selected_color=(0.9, 0.6, 0.6), + unselected_color=(0.6, 0.6, 0.6), + scroll_bar_active_color=(0.6, 0.2, 0.2), + scroll_bar_inactive_color=(0.9, 0.0, 0.0), + menu_opacity=1.0, + reverse_scrolling=False, + font_size=20, + line_spacing=1.4, + ): + """Init class Instance. + + Parameters + ---------- + items: list(string) + List of items to be displayed as choices. + position : (float, float) + Absolute coordinates (x, y) of the lower-left corner of this + UI component. + size : (int, int) + Width and height in pixels of this UI component. + placeholder : str + Holds the default text to be displayed. + draggable: {True, False} + Whether the UI element is draggable or not. + selection_text_color : tuple of 3 floats + Color of the selected text to be displayed. + selection_bg_color : tuple of 3 floats + Background color of the selection text. + menu_text_color : tuple of 3 floats. + Color of the options displayed in drop down menu. + selected_color : tuple of 3 floats. + Background color of the selected option in drop down menu. + unselected_color : tuple of 3 floats. + Background color of the unselected option in drop down menu. + scroll_bar_active_color : tuple of 3 floats. + Color of the scrollbar when in active use. + scroll_bar_inactive_color : tuple of 3 floats. + Color of the scrollbar when inactive. + reverse_scrolling: {True, False} + If True, scrolling up will move the list of files down. + font_size: int + The font size of selected text in pixels. + line_spacing: float + Distance between drop down menu's items in pixels. + + """ + self.items = items.copy() + self.font_size = font_size + self.reverse_scrolling = reverse_scrolling + self.line_spacing = line_spacing + self.panel_size = size + self._selection = placeholder + self._menu_visibility = False + self._selection_ID = None + self.draggable = draggable + self.sel_text_color = selection_text_color + self.sel_bg_color = selection_bg_color + self.menu_txt_color = menu_text_color + self.selected_color = selected_color + self.unselected_color = unselected_color + self.scroll_active_color = scroll_bar_active_color + self.scroll_inactive_color = scroll_bar_inactive_color + self.menu_opacity = menu_opacity + + # Define subcomponent sizes. + self.text_block_size = (int(0.9 * size[0]), int(0.1 * size[1])) + self.drop_menu_size = (int(0.9 * size[0]), int(0.7 * size[1])) + self.drop_button_size = (int(0.1 * size[0]), int(0.1 * size[1])) + + self._icon_files = [ + ('left', read_viz_icons(fname='circle-left.png')), + ('down', read_viz_icons(fname='circle-down.png')), + ] + + super(ComboBox2D, self).__init__() + self.position = position
+ + + def _setup(self): + """Setup this UI component. + + Create the ListBox filled with empty slots (ListBoxItem2D). + Create TextBox with placeholder text. + Create Button for toggling drop down menu. + """ + self.selection_box = TextBlock2D( + size=self.text_block_size, + color=self.sel_text_color, + bg_color=self.sel_bg_color, + text=self._selection, + ) + + self.drop_down_button = Button2D( + icon_fnames=self._icon_files, size=self.drop_button_size + ) + + self.drop_down_menu = ListBox2D( + values=self.items, + multiselection=False, + font_size=self.font_size, + line_spacing=self.line_spacing, + text_color=self.menu_txt_color, + selected_color=self.selected_color, + unselected_color=self.unselected_color, + scroll_bar_active_color=self.scroll_active_color, + scroll_bar_inactive_color=self.scroll_inactive_color, + background_opacity=self.menu_opacity, + reverse_scrolling=self.reverse_scrolling, + size=self.drop_menu_size, + ) + + self.drop_down_menu.set_visibility(False) + + self.panel = Panel2D(self.panel_size, opacity=0.0) + self.panel.add_element(self.selection_box, (0.001, 0.7)) + self.panel.add_element(self.drop_down_button, (0.8, 0.7)) + self.panel.add_element(self.drop_down_menu, (0, 0)) + + if self.draggable: + self.drop_down_button.on_left_mouse_button_dragged = ( + self.left_button_dragged + ) + self.drop_down_menu.panel.background.on_left_mouse_button_dragged = ( + self.left_button_dragged + ) + self.selection_box.on_left_mouse_button_dragged = self.left_button_dragged + self.selection_box.background.on_left_mouse_button_dragged = ( + self.left_button_dragged + ) + + self.drop_down_button.on_left_mouse_button_pressed = ( + self.left_button_pressed + ) + self.drop_down_menu.panel.background.on_left_mouse_button_pressed = ( + self.left_button_pressed + ) + self.selection_box.on_left_mouse_button_pressed = self.left_button_pressed + self.selection_box.background.on_left_mouse_button_pressed = ( + self.left_button_pressed + ) + else: + self.panel.background.on_left_mouse_button_dragged = ( + lambda i_ren, _obj, _comp: i_ren.force_render + ) + self.drop_down_menu.panel.background.on_left_mouse_button_dragged = ( + lambda i_ren, _obj, _comp: i_ren.force_render + ) + + # Handle mouse wheel events on the slots. + for slot in self.drop_down_menu.slots: + slot.add_callback( + slot.textblock.actor, + 'LeftButtonPressEvent', + self.select_option_callback, + ) + + slot.add_callback( + slot.background.actor, + 'LeftButtonPressEvent', + self.select_option_callback, + ) + + self.drop_down_button.on_left_mouse_button_clicked = ( + self.menu_toggle_callback + ) + + # Offer some standard hooks to the user. + self.on_change = lambda ui: None + + def _get_actors(self): + """Get the actors composing this UI component.""" + return self.panel.actors + +
+[docs] + def resize(self, size): + """Resize ComboBox2D. + + Parameters + ---------- + size : (int, int) + ComboBox size(width, height) in pixels. + + """ + self.panel.resize(size) + + self.text_block_size = (int(0.9 * size[0]), int(0.1 * size[1])) + self.drop_menu_size = (int(0.9 * size[0]), int(0.7 * size[1])) + self.drop_button_size = (int(0.1 * size[0]), int(0.1 * size[1])) + + self.panel.update_element(self.selection_box, (0.001, 0.7)) + self.panel.update_element(self.drop_down_button, (0.8, 0.7)) + self.panel.update_element(self.drop_down_menu, (0, 0)) + + self.drop_down_button.resize(self.drop_button_size) + self.drop_down_menu.resize(self.drop_menu_size) + self.selection_box.resize(self.text_block_size)
+ + + def _set_position(self, coords): + """Set the lower-left corner position of this UI component. + + Parameters + ---------- + coords: (float, float) + Absolute pixel coordinates (x, y). + + """ + self.panel.position = coords + self.panel.position = (self.panel.position[0], + self.panel.position[1] - self.drop_menu_size[1]) + + def _add_to_scene(self, scene): + """Add all subcomponents or VTK props that compose this UI component. + + Parameters + ---------- + scene : scene + + """ + self.panel.add_to_scene(scene) + self.selection_box.font_size = self.font_size + + def _get_size(self): + return self.panel.size + + @property + def selected_text(self): + return self._selection + + @property + def selected_text_index(self): + return self._selection_ID + +
+[docs] + def set_visibility(self, visibility): + super().set_visibility(visibility) + if not self._menu_visibility: + self.drop_down_menu.set_visibility(False)
+ + +
+[docs] + def append_item(self, *items): + """Append additional options to the menu. + + Parameters + ---------- + items : n-d list, n-d tuple, Number or str + Additional options. + + """ + for item in items: + if isinstance(item, (list, tuple)): + # Useful when n-d lists/tuples are used. + self.append_item(*item) + elif isinstance(item, (str, Number)): + self.items.append(str(item)) + else: + raise TypeError('Invalid item instance {}'.format(type(item))) + + self.drop_down_menu.update_scrollbar() + if not self._menu_visibility: + self.drop_down_menu.scroll_bar.set_visibility(False)
+ + +
+[docs] + def select_option_callback(self, i_ren, _obj, listboxitem): + """Select the appropriate option + + Parameters + ---------- + i_ren: :class:`CustomInteractorStyle` + obj: :class:`vtkActor` + The picked actor + listboxitem: :class:`ListBoxItem2D` + + """ + # Set the Text of TextBlock2D to the text of listboxitem + self._selection = listboxitem.element + self._selection_ID = self.items.index(self._selection) + + self.selection_box.message = self._selection + clip_overflow(self.selection_box, self.selection_box.background.size[0]) + self.drop_down_menu.set_visibility(False) + self._menu_visibility = False + + self.drop_down_button.next_icon() + + self.on_change(self) + + i_ren.force_render() + i_ren.event.abort()
+ + +
+[docs] + def menu_toggle_callback(self, i_ren, _vtkactor, _combobox): + """Toggle visibility of drop down menu list. + + Parameters + ---------- + i_ren : :class:`CustomInteractorStyle` + vtkactor : :class:`vtkActor` + The picked actor + combobox : :class:`ComboBox2D` + + """ + self._menu_visibility = not self._menu_visibility + self.drop_down_menu.set_visibility(self._menu_visibility) + + self.drop_down_button.next_icon() + + i_ren.force_render() + i_ren.event.abort() # Stop propagating the event.
+ + +
+[docs] + def left_button_pressed(self, i_ren, _obj, _sub_component): + click_pos = np.array(i_ren.event.position) + self._click_position = click_pos + i_ren.event.abort() # Stop propagating the event.
+ + +
+[docs] + def left_button_dragged(self, i_ren, _obj, _sub_component): + click_position = np.array(i_ren.event.position) + change = click_position - self._click_position + self.panel.position += change + self._click_position = click_position + i_ren.force_render()
+
+ + + +
+[docs] +class ListBox2D(UI): + """UI component that allows the user to select items from a list. + + Attributes + ---------- + on_change: function + Callback function for when the selected items have changed. + + """ + +
+[docs] + def __init__( + self, + values, + position=(0, 0), + size=(100, 300), + multiselection=True, + reverse_scrolling=False, + font_size=20, + line_spacing=1.4, + text_color=(0.2, 0.2, 0.2), + selected_color=(0.9, 0.6, 0.6), + unselected_color=(0.6, 0.6, 0.6), + scroll_bar_active_color=(0.6, 0.2, 0.2), + scroll_bar_inactive_color=(0.9, 0.0, 0.0), + background_opacity=1.0, + ): + """Init class instance. + + Parameters + ---------- + values: list of objects + Values used to populate this listbox. Objects must be castable + to string. + position : (float, float) + Absolute coordinates (x, y) of the lower-left corner of this + UI component. + size : (int, int) + Width and height in pixels of this UI component. + multiselection: {True, False} + Whether multiple values can be selected at once. + reverse_scrolling: {True, False} + If True, scrolling up will move the list of files down. + font_size: int + The font size in pixels. + line_spacing: float + Distance between listbox's items in pixels. + text_color : tuple of 3 floats + selected_color : tuple of 3 floats + unselected_color : tuple of 3 floats + scroll_bar_active_color : tuple of 3 floats + scroll_bar_inactive_color : tuple of 3 floats + background_opacity : float + + """ + self.view_offset = 0 + self.slots = [] + self.selected = [] + + self.panel_size = size + self.font_size = font_size + self.line_spacing = line_spacing + self.slot_height = int(self.font_size * self.line_spacing) + + self.text_color = text_color + self.selected_color = selected_color + self.unselected_color = unselected_color + self.background_opacity = background_opacity + + # self.panel.resize(size) + self.values = values + self.multiselection = multiselection + self.last_selection_idx = 0 + self.reverse_scrolling = reverse_scrolling + super(ListBox2D, self).__init__() + + denom = len(self.values) - self.nb_slots + if not denom: + denom += 1 + self.scroll_step_size = ( + self.slot_height * self.nb_slots - self.scroll_bar.height + ) / denom + + self.scroll_bar_active_color = scroll_bar_active_color + self.scroll_bar_inactive_color = scroll_bar_inactive_color + self.scroll_bar.color = self.scroll_bar_inactive_color + self.scroll_bar.opacity = self.background_opacity + + self.position = position + self.scroll_init_position = 0 + self.update() + + # Offer some standard hooks to the user. + self.on_change = lambda: None
+ + + def _setup(self): + """Setup this UI component. + + Create the ListBox (Panel2D) filled with empty slots (ListBoxItem2D). + """ + self.margin = 10 + size = self.panel_size + font_size = self.font_size + # Calculating the number of slots. + self.nb_slots = int((size[1] - 2 * self.margin) // self.slot_height) + + # This panel facilitates adding slots at the right position. + self.panel = Panel2D(size=size, color=(1, 1, 1)) + + # Add a scroll bar + scroll_bar_height = ( + self.nb_slots * (size[1] - 2 * self.margin) / len(self.values) + ) + self.scroll_bar = Rectangle2D(size=(int(size[0] / 20), scroll_bar_height)) + if len(self.values) <= self.nb_slots: + self.scroll_bar.set_visibility(False) + self.scroll_bar.height = 0 + self.panel.add_element( + self.scroll_bar, size - self.scroll_bar.size - self.margin + ) + + # Initialisation of empty text actors + self.slot_width = ( + size[0] - self.scroll_bar.size[0] - 2 * self.margin - self.margin + ) + x = self.margin + y = size[1] - self.margin + for _ in range(self.nb_slots): + y -= self.slot_height + item = ListBoxItem2D( + list_box=self, + size=(self.slot_width, self.slot_height), + text_color=self.text_color, + selected_color=self.selected_color, + unselected_color=self.unselected_color, + background_opacity=self.background_opacity, + ) + item.textblock.font_size = font_size + self.slots.append(item) + self.panel.add_element(item, (x, y + self.margin)) + + # Add default events listener for this UI component. + self.scroll_bar.on_left_mouse_button_pressed = self.scroll_click_callback + self.scroll_bar.on_left_mouse_button_released = self.scroll_release_callback + self.scroll_bar.on_left_mouse_button_dragged = self.scroll_drag_callback + + # Handle mouse wheel events on the panel. + up_event = 'MouseWheelForwardEvent' + down_event = 'MouseWheelBackwardEvent' + if self.reverse_scrolling: + up_event, down_event = down_event, up_event # Swap events + + self.add_callback( + self.panel.background.actor, up_event, self.up_button_callback + ) + self.add_callback( + self.panel.background.actor, down_event, self.down_button_callback + ) + + # Handle mouse wheel events on the slots. + for slot in self.slots: + self.add_callback(slot.background.actor, up_event, self.up_button_callback) + self.add_callback( + slot.background.actor, down_event, self.down_button_callback + ) + self.add_callback(slot.textblock.actor, up_event, self.up_button_callback) + self.add_callback( + slot.textblock.actor, down_event, self.down_button_callback + ) + +
+[docs] + def resize(self, size): + pass
+ + + def _get_actors(self): + """Get the actors composing this UI component.""" + return self.panel.actors + + def _add_to_scene(self, scene): + """Add all subcomponents or VTK props that compose this UI component. + + Parameters + ---------- + scene : scene + + """ + self.panel.add_to_scene(scene) + for slot in self.slots: + clip_overflow(slot.textblock, self.slot_width) + + def _get_size(self): + return self.panel.size + + def _set_position(self, coords): + """Position the lower-left corner of this UI component. + + Parameters + ---------- + coords: (float, float) + Absolute pixel coordinates (x, y). + + """ + self.panel.position = coords + +
+[docs] + def up_button_callback(self, i_ren, _obj, _list_box): + """Pressing up button scrolls up in the combo box. + + Parameters + ---------- + i_ren: :class:`CustomInteractorStyle` + obj: :class:`vtkActor` + The picked actor + _list_box: :class:`ListBox2D` + + """ + if self.view_offset > 0: + self.view_offset -= 1 + self.update() + scroll_bar_idx = self.panel._elements.index(self.scroll_bar) + self.scroll_bar.center = ( + self.scroll_bar.center[0], + self.scroll_bar.center[1] + self.scroll_step_size, + ) + self.panel.element_offsets[scroll_bar_idx] = ( + self.scroll_bar, + (self.scroll_bar.position - self.panel.position), + ) + + i_ren.force_render() + i_ren.event.abort() # Stop propagating the event.
+ + +
+[docs] + def down_button_callback(self, i_ren, _obj, _list_box): + """Pressing down button scrolls down in the combo box. + + Parameters + ---------- + i_ren: :class:`CustomInteractorStyle` + obj: :class:`vtkActor` + The picked actor + _list_box: :class:`ListBox2D` + + """ + view_end = self.view_offset + self.nb_slots + if view_end < len(self.values): + self.view_offset += 1 + self.update() + scroll_bar_idx = self.panel._elements.index(self.scroll_bar) + self.scroll_bar.center = ( + self.scroll_bar.center[0], + self.scroll_bar.center[1] - self.scroll_step_size, + ) + self.panel.element_offsets[scroll_bar_idx] = ( + self.scroll_bar, + (self.scroll_bar.position - self.panel.position), + ) + + i_ren.force_render() + i_ren.event.abort() # Stop propagating the event.
+ + +
+[docs] + def scroll_click_callback(self, i_ren, _obj, _rect_obj): + """Callback to change the color of the bar when it is clicked. + + Parameters + ---------- + i_ren: :class:`CustomInteractorStyle` + obj: :class:`vtkActor` + The picked actor + _rect_obj: :class:`Rectangle2D` + + """ + self.scroll_bar.color = self.scroll_bar_active_color + self.scroll_init_position = i_ren.event.position[1] + i_ren.force_render() + i_ren.event.abort()
+ + +
+[docs] + def scroll_release_callback(self, i_ren, _obj, _rect_obj): + """Callback to change the color of the bar when it is released. + + Parameters + ---------- + i_ren: :class:`CustomInteractorStyle` + obj: :class:`vtkActor` + The picked actor + rect_obj: :class:`Rectangle2D` + + """ + self.scroll_bar.color = self.scroll_bar_inactive_color + i_ren.force_render()
+ + +
+[docs] + def scroll_drag_callback(self, i_ren, _obj, _rect_obj): + """Drag scroll bar in the combo box. + + Parameters + ---------- + i_ren: :class:`CustomInteractorStyle` + obj: :class:`vtkActor` + The picked actor + rect_obj: :class:`Rectangle2D` + + """ + position = i_ren.event.position + offset = int((position[1] - self.scroll_init_position) / self.scroll_step_size) + if offset > 0 and self.view_offset > 0: + offset = min(offset, self.view_offset) + + elif offset < 0 and (self.view_offset + self.nb_slots < len(self.values)): + offset = min(-offset, len(self.values) - self.nb_slots - self.view_offset) + offset = -offset + else: + return + + self.view_offset -= offset + self.update() + scroll_bar_idx = self.panel._elements.index(self.scroll_bar) + self.scroll_bar.center = ( + self.scroll_bar.center[0], + self.scroll_bar.center[1] + offset * self.scroll_step_size, + ) + + self.scroll_init_position += offset * self.scroll_step_size + + self.panel.element_offsets[scroll_bar_idx] = ( + self.scroll_bar, + (self.scroll_bar.position - self.panel.position), + ) + i_ren.force_render() + i_ren.event.abort()
+ + +
+[docs] + def update(self): + """Refresh listbox's content.""" + view_start = self.view_offset + view_end = view_start + self.nb_slots + values_to_show = self.values[view_start:view_end] + + # Populate slots according to the view. + for i, choice in enumerate(values_to_show): + slot = self.slots[i] + slot.element = choice + if slot.textblock.scene is not None: + clip_overflow(slot.textblock, self.slot_width) + slot.set_visibility(True) + if slot.size[1] != self.slot_height: + slot.resize((self.slot_width, self.slot_height)) + if slot.element in self.selected: + slot.select() + else: + slot.deselect() + + # Flush remaining slots. + for slot in self.slots[len(values_to_show) :]: + slot.element = None + slot.set_visibility(False) + slot.resize((self.slot_width, 0)) + slot.deselect()
+ + +
+[docs] + def update_scrollbar(self): + """Change the scroll-bar height when the values + in the listbox change + """ + self.scroll_bar.set_visibility(True) + + self.scroll_bar.height = ( + self.nb_slots * (self.panel_size[1] - 2 * self.margin) / len(self.values) + ) + + self.scroll_step_size = ( + self.slot_height * self.nb_slots - self.scroll_bar.height + ) / (len(self.values) - self.nb_slots) + + self.panel.update_element( + self.scroll_bar, self.panel_size - self.scroll_bar.size - self.margin + ) + + if len(self.values) <= self.nb_slots: + self.scroll_bar.set_visibility(False) + self.scroll_bar.height = 0
+ + +
+[docs] + def clear_selection(self): + del self.selected[:]
+ + +
+[docs] + def select(self, item, multiselect=False, range_select=False): + """Select the item. + + Parameters + ---------- + item: ListBoxItem2D's object + Item to select. + multiselect: {True, False} + If True and multiselection is allowed, the item is added to the + selection. + Otherwise, the selection will only contain the provided item unless + range_select is True. + range_select: {True, False} + If True and multiselection is allowed, all items between the last + selected item and the current one will be added to the selection. + Otherwise, the selection will only contain the provided item unless + multi_select is True. + + """ + selection_idx = self.values.index(item.element) + if self.multiselection and range_select: + self.clear_selection() + step = 1 if selection_idx >= self.last_selection_idx else -1 + for i in range(self.last_selection_idx, selection_idx + step, step): + self.selected.append(self.values[i]) + + elif self.multiselection and multiselect: + if item.element in self.selected: + self.selected.remove(item.element) + else: + self.selected.append(item.element) + self.last_selection_idx = selection_idx + + else: + self.clear_selection() + self.selected.append(item.element) + self.last_selection_idx = selection_idx + + self.on_change() # Call hook. + self.update()
+
+ + + +
+[docs] +class ListBoxItem2D(UI): + """The text displayed in a listbox.""" + +
+[docs] + def __init__( + self, + list_box, + size, + text_color=(1.0, 0.0, 0.0), + selected_color=(0.4, 0.4, 0.4), + unselected_color=(0.9, 0.9, 0.9), + background_opacity=1.0, + ): + """Init ListBox Item instance. + + Parameters + ---------- + list_box : :class:`ListBox` + The ListBox reference this text belongs to. + size : tuple of 2 ints + The size of the listbox item. + text_color : tuple of 3 floats + unselected_color : tuple of 3 floats + selected_color : tuple of 3 floats + background_opacity : float + + """ + super(ListBoxItem2D, self).__init__() + self._element = None + self.list_box = list_box + self.background.resize(size) + self.background_opacity = background_opacity + self.selected = False + self.text_color = text_color + self.textblock.color = self.text_color + self.selected_color = selected_color + self.unselected_color = unselected_color + self.background.opacity = self.background_opacity + self.deselect()
+ + + def _setup(self): + """Setup this UI component. + + Create the ListBoxItem2D with its background (Rectangle2D) and its + label (TextBlock2D). + """ + self.background = Rectangle2D() + self.textblock = TextBlock2D( + justification='left', vertical_justification='middle' + ) + + # Add default events listener for this UI component. + self.add_callback( + self.textblock.actor, 'LeftButtonPressEvent', self.left_button_clicked + ) + self.add_callback( + self.background.actor, 'LeftButtonPressEvent', self.left_button_clicked + ) + + def _get_actors(self): + """Get the actors composing this UI component.""" + return self.background.actors + self.textblock.actors + + def _add_to_scene(self, scene): + """Add all subcomponents or VTK props that compose this UI component. + + Parameters + ---------- + scene : scene + + """ + self.background.add_to_scene(scene) + self.textblock.add_to_scene(scene) + + def _get_size(self): + return self.background.size + + def _set_position(self, coords): + """Set the lower-left corner position of this UI component. + + Parameters + ---------- + coords: (float, float) + Absolute pixel coordinates (x, y). + + """ + self.textblock.position = coords + # Center background underneath the text. + position = coords + self.background.position = ( + position[0], + position[1] - self.background.size[1] / 2.0, + ) + +
+[docs] + def deselect(self): + self.background.color = self.unselected_color + self.textblock.bold = False + self.selected = False
+ + +
+[docs] + def select(self): + self.textblock.bold = True + self.background.color = self.selected_color + self.selected = True
+ + + @property + def element(self): + return self._element + + @element.setter + def element(self, element): + self._element = element + self.textblock.message = '' if self._element is None else str(element) + +
+[docs] + def left_button_clicked(self, i_ren, _obj, _list_box_item): + """Handle left click for this UI element. + + Parameters + ---------- + i_ren: :class:`CustomInteractorStyle` + obj: :class:`vtkActor` + The picked actor + _list_box_item: :class:`ListBoxItem2D` + + """ + multiselect = i_ren.event.ctrl_key + range_select = i_ren.event.shift_key + self.list_box.select(self, multiselect, range_select) + i_ren.force_render()
+ + +
+[docs] + def resize(self, size): + self.background.resize(size)
+
+ + + +
+[docs] +class FileMenu2D(UI): + """A menu to select files in the current folder. + + Can go to new folder, previous folder and select multiple files. + + Attributes + ---------- + extensions: ['extension1', 'extension2', ....] + To show all files, extensions=["*"] or [""] + List of extensions to be shown as files. + listbox : :class: 'ListBox2D' + Container for the menu. + + """ + +
+[docs] + def __init__( + self, + directory_path, + extensions=None, + position=(0, 0), + size=(100, 300), + multiselection=True, + reverse_scrolling=False, + font_size=20, + line_spacing=1.4, + ): + """Init class instance. + + Parameters + ---------- + extensions: list(string) + List of extensions to be shown as files. + directory_path: string + Path of the directory where this dialog should open. + position : (float, float) + Absolute coordinates (x, y) of the lower-left corner of this + UI component. + size : (int, int) + Width and height in pixels of this UI component. + multiselection: {True, False} + Whether multiple values can be selected at once. + reverse_scrolling: {True, False} + If True, scrolling up will move the list of files down. + font_size: int + The font size in pixels. + line_spacing: float + Distance between listbox's items in pixels. + + """ + self.font_size = font_size + self.multiselection = multiselection + self.reverse_scrolling = reverse_scrolling + self.line_spacing = line_spacing + self.extensions = extensions or ['*'] + self.current_directory = directory_path + self.menu_size = size + self.directory_contents = [] + + super(FileMenu2D, self).__init__() + self.position = position + self.set_slot_colors()
+ + + def _setup(self): + """Setup this UI component. + + Create the ListBox (Panel2D) filled with empty slots (ListBoxItem2D). + + """ + self.directory_contents = self.get_all_file_names() + content_names = [x[0] for x in self.directory_contents] + self.listbox = ListBox2D( + values=content_names, + multiselection=self.multiselection, + font_size=self.font_size, + line_spacing=self.line_spacing, + reverse_scrolling=self.reverse_scrolling, + size=self.menu_size, + ) + + self.add_callback( + self.listbox.scroll_bar.actor, 'MouseMoveEvent', self.scroll_callback + ) + + # Handle mouse wheel events on the panel. + up_event = 'MouseWheelForwardEvent' + down_event = 'MouseWheelBackwardEvent' + if self.reverse_scrolling: + up_event, down_event = down_event, up_event # Swap events + + self.add_callback( + self.listbox.panel.background.actor, up_event, self.scroll_callback + ) + self.add_callback( + self.listbox.panel.background.actor, down_event, self.scroll_callback + ) + + # Handle mouse wheel events on the slots. + for slot in self.listbox.slots: + self.add_callback(slot.background.actor, up_event, self.scroll_callback) + self.add_callback(slot.background.actor, down_event, self.scroll_callback) + self.add_callback(slot.textblock.actor, up_event, self.scroll_callback) + self.add_callback(slot.textblock.actor, down_event, self.scroll_callback) + slot.add_callback( + slot.textblock.actor, + 'LeftButtonPressEvent', + self.directory_click_callback, + ) + slot.add_callback( + slot.background.actor, + 'LeftButtonPressEvent', + self.directory_click_callback, + ) + + def _get_actors(self): + """Get the actors composing this UI component.""" + return self.listbox.actors + +
+[docs] + def resize(self, size): + pass
+ + + def _set_position(self, coords): + """Set the lower-left corner position of this UI component. + + Parameters + ---------- + coords: (float, float) + Absolute pixel coordinates (x, y). + + """ + self.listbox.position = coords + + def _add_to_scene(self, scene): + """Add all subcomponents or VTK props that compose this UI component. + + Parameters + ---------- + scene : scene + + """ + self.listbox.add_to_scene(scene) + + def _get_size(self): + return self.listbox.size + +
+[docs] + def get_all_file_names(self): + """Get file and directory names. + + Returns + ------- + all_file_names: list((string, {"directory", "file"})) + List of all file and directory names as string. + + """ + all_file_names = [] + + directory_names = self.get_directory_names() + for directory_name in directory_names: + all_file_names.append((directory_name, 'directory')) + + file_names = self.get_file_names() + for file_name in file_names: + all_file_names.append((file_name, 'file')) + + return all_file_names
+ + +
+[docs] + def get_directory_names(self): + """Find names of all directories in the current_directory + + Returns + ------- + directory_names: list(string) + List of all directory names as string. + + """ + # A list of directory names in the current directory + directory_names = [] + for (_, dirnames, _) in os.walk(self.current_directory): + directory_names += dirnames + break + directory_names.sort(key=lambda s: s.lower()) + directory_names.insert(0, '../') + return directory_names
+ + +
+[docs] + def get_file_names(self): + """Find names of all files in the current_directory + + Returns + ------- + file_names: list(string) + List of all file names as string. + + """ + # A list of file names with extension in the current directory + for (_, _, files) in os.walk(self.current_directory): + break + + file_names = [] + if '*' in self.extensions or '' in self.extensions: + file_names = files + else: + for ext in self.extensions: + for file in files: + if file.endswith('.' + ext): + file_names.append(file) + file_names.sort(key=lambda s: s.lower()) + return file_names
+ + +
+[docs] + def set_slot_colors(self): + """Set the text color of the slots based on the type of element + they show. Blue for directories and green for files. + """ + for idx, slot in enumerate(self.listbox.slots): + list_idx = min( + self.listbox.view_offset + idx, len(self.directory_contents) - 1 + ) + if self.directory_contents[list_idx][1] == 'directory': + slot.textblock.color = (0, 0.6, 0) + elif self.directory_contents[list_idx][1] == 'file': + slot.textblock.color = (0, 0, 0.7)
+ + +
+[docs] + def scroll_callback(self, i_ren, _obj, _filemenu_item): + """Handle scroll and change the slot text colors. + + Parameters + ---------- + i_ren: :class:`CustomInteractorStyle` + obj: :class:`vtkActor` + The picked actor + _filemenu_item: :class:`FileMenu2D` + + """ + self.set_slot_colors() + i_ren.force_render() + i_ren.event.abort()
+ + +
+[docs] + def directory_click_callback(self, i_ren, _obj, listboxitem): + """Handle the move into a directory if it has been clicked. + + Parameters + ---------- + i_ren: :class:`CustomInteractorStyle` + obj: :class:`vtkActor` + The picked actor + listboxitem: :class:`ListBoxItem2D` + + """ + if (listboxitem.element, 'directory') in self.directory_contents: + new_directory_path = os.path.join( + self.current_directory, listboxitem.element + ) + if os.access(new_directory_path, os.R_OK): + self.current_directory = new_directory_path + self.directory_contents = self.get_all_file_names() + content_names = [x[0] for x in self.directory_contents] + self.listbox.clear_selection() + self.listbox.values = content_names + self.listbox.view_offset = 0 + self.listbox.update() + self.listbox.update_scrollbar() + self.set_slot_colors() + i_ren.force_render() + i_ren.event.abort()
+
+ + + +
+[docs] +class DrawShape(UI): + """Create and Manage 2D Shapes.""" + +
+[docs] + def __init__(self, shape_type, drawpanel=None, position=(0, 0)): + """Init this UI element. + + Parameters + ---------- + shape_type : string + Type of shape to be created. + drawpanel : DrawPanel, optional + Reference to the main canvas on which it is drawn. + position : (float, float), optional + (x, y) in pixels. + + """ + self.shape = None + self.shape_type = shape_type.lower() + self.drawpanel = drawpanel + self.max_size = None + self.rotation = 0 + super(DrawShape, self).__init__(position) + self.shape.color = np.random.random(3)
+ + + def _setup(self): + """Setup this UI component. + + Create a Shape. + """ + if self.shape_type == 'line': + self.shape = Rectangle2D(size=(3, 3)) + elif self.shape_type == 'quad': + self.shape = Rectangle2D(size=(3, 3)) + elif self.shape_type == 'circle': + self.shape = Disk2D(outer_radius=2) + else: + raise IOError('Unknown shape type: {}.'.format(self.shape_type)) + + self.shape.on_left_mouse_button_pressed = self.left_button_pressed + self.shape.on_left_mouse_button_dragged = self.left_button_dragged + self.shape.on_left_mouse_button_released = self.left_button_released + + def _get_actors(self): + """Get the actors composing this UI component.""" + return self.shape + + def _add_to_scene(self, scene): + """Add all subcomponents or VTK props that compose this UI component. + + Parameters + ---------- + scene : scene + + """ + self._scene = scene + self.shape.add_to_scene(scene) + + def _get_size(self): + return self.shape.size + + def _set_position(self, coords): + """Set the lower-left corner position of this UI component. + + Parameters + ---------- + coords: (float, float) + Absolute pixel coordinates (x, y). + + """ + if self.shape_type == 'circle': + self.shape.center = coords + else: + self.shape.position = coords + +
+[docs] + def update_shape_position(self, center_position): + """Update the center position on the canvas. + + Parameters + ---------- + center_position: (float, float) + Absolute pixel coordinates (x, y). + + """ + new_center = self.clamp_position(center=center_position) + self.drawpanel.canvas.update_element(self, new_center, 'center') + self.cal_bounding_box()
+ + + @property + def center(self): + return self._bounding_box_min + self._bounding_box_size // 2 + + @center.setter + def center(self, coords): + """Position the center of this UI component. + + Parameters + ---------- + coords: (float, float) + Absolute pixel coordinates (x, y). + + """ + new_center = np.array(coords) + new_lower_left_corner = new_center - self._bounding_box_size // 2 + self.position = new_lower_left_corner + self._bounding_box_offset + self.cal_bounding_box() + + @property + def is_selected(self): + return self._is_selected + + @is_selected.setter + def is_selected(self, value): + if self.drawpanel and value: + self.drawpanel.current_shape = self + self._is_selected = value + self.selection_change() + +
+[docs] + def selection_change(self): + if self.is_selected: + self.drawpanel.rotation_slider.value = self.rotation + else: + self.drawpanel.rotation_slider.set_visibility(False)
+ + +
+[docs] + def rotate(self, angle): + """Rotate the vertices of the UI component using specific angle. + + Parameters + ---------- + angle: float + Value by which the vertices are rotated in radian. + + """ + if self.shape_type == 'circle': + return + points_arr = vertices_from_actor(self.shape.actor) + new_points_arr = rotate_2d(points_arr, angle) + set_polydata_vertices(self.shape._polygonPolyData, new_points_arr) + update_actor(self.shape.actor) + + self.cal_bounding_box()
+ + +
+[docs] + def cal_bounding_box(self): + """Calculate the min, max position and the size of the bounding box.""" + vertices = self.position + vertices_from_actor(self.shape.actor)[:, :-1] + + ( + self._bounding_box_min, + self._bounding_box_max, + self._bounding_box_size, + ) = cal_bounding_box_2d(vertices) + + self._bounding_box_offset = self.position - self._bounding_box_min
+ + +
+[docs] + def clamp_position(self, center=None): + """Clamp the given center according to the DrawPanel canvas. + + Parameters + ---------- + center : (float, float) + (x, y) in pixels. + + Returns + ------- + new_center: ndarray(int) + New center for the shape. + + """ + center = self.center if center is None else center + new_center = np.clip( + center, + self._bounding_box_size // 2, + self.drawpanel.canvas.size - self._bounding_box_size // 2, + ) + return new_center.astype(int)
+ + +
+[docs] + def resize(self, size): + """Resize the UI.""" + if self.shape_type == 'line': + hyp = np.hypot(size[0], size[1]) + self.shape.resize((hyp, 3)) + self.rotate(angle=np.arctan2(size[1], size[0])) + + elif self.shape_type == 'quad': + self.shape.resize(size) + + elif self.shape_type == 'circle': + hyp = np.hypot(size[0], size[1]) + if self.max_size and hyp > self.max_size: + hyp = self.max_size + self.shape.outer_radius = hyp + + self.cal_bounding_box()
+ + +
+[docs] + def remove(self): + """Remove the Shape and all related actors.""" + self._scene.rm(self.shape.actor) + self.drawpanel.rotation_slider.set_visibility(False)
+ + +
+[docs] + def left_button_pressed(self, i_ren, _obj, shape): + mode = self.drawpanel.current_mode + if mode == 'selection': + self.drawpanel.update_shape_selection(self) + + click_pos = np.array(i_ren.event.position) + self._drag_offset = click_pos - self.center + self.drawpanel.show_rotation_slider() + i_ren.event.abort() + elif mode == 'delete': + self.remove() + else: + self.drawpanel.left_button_pressed(i_ren, _obj, self.drawpanel) + i_ren.force_render()
+ + +
+[docs] + def left_button_dragged(self, i_ren, _obj, shape): + if self.drawpanel.current_mode == "selection": + self.drawpanel.rotation_slider.set_visibility(False) + if self._drag_offset is not None: + click_position = i_ren.event.position + relative_center_position = ( + click_position - self._drag_offset - self.drawpanel.canvas.position + ) + self.update_shape_position(relative_center_position) + i_ren.force_render() + else: + self.drawpanel.left_button_dragged(i_ren, _obj, self.drawpanel)
+ + +
+[docs] + def left_button_released(self, i_ren, _obj, shape): + if self.drawpanel.current_mode == "selection": + self.drawpanel.show_rotation_slider() + i_ren.force_render()
+
+ + + +
+[docs] +class DrawPanel(UI): + """The main Canvas(Panel2D) on which everything would be drawn.""" + +
+[docs] + def __init__(self, size=(400, 400), position=(0, 0), is_draggable=False): + """Init this UI element. + + Parameters + ---------- + size : (int, int), optional + Width and height in pixels of this UI component. + position : (float, float), optional + (x, y) in pixels. + is_draggable : bool, optional + Whether the background canvas will be draggble or not. + + """ + self.panel_size = size + super(DrawPanel, self).__init__(position) + self.is_draggable = is_draggable + self.current_mode = None + + if is_draggable: + self.current_mode = 'selection' + + self.shape_list = [] + self.current_shape = None
+ + + def _setup(self): + """Setup this UI component. + + Create a Canvas(Panel2D). + """ + self.canvas = Panel2D(size=self.panel_size) + self.canvas.background.on_left_mouse_button_pressed = self.left_button_pressed + self.canvas.background.on_left_mouse_button_dragged = self.left_button_dragged + + # Todo + # Convert mode_data into a private variable and make it read-only + # Then add the ability to insert user-defined mode + mode_data = { + 'selection': ['selection.png', 'selection-pressed.png'], + 'line': ['line.png', 'line-pressed.png'], + 'quad': ['quad.png', 'quad-pressed.png'], + 'circle': ['circle.png', 'circle-pressed.png'], + 'delete': ['delete.png', 'delete-pressed.png'], + } + + padding = 5 + # Todo + # Add this size to __init__ + mode_panel_size = (len(mode_data) * 35 + 2 * padding, 40) + self.mode_panel = Panel2D(size=mode_panel_size, color=(0.5, 0.5, 0.5)) + btn_pos = np.array([0, 0]) + + for mode, fname in mode_data.items(): + icon_files = [] + icon_files.append((mode, read_viz_icons(style='new_icons', fname=fname[0]))) + icon_files.append( + (mode + '-pressed', read_viz_icons(style='new_icons', fname=fname[1])) + ) + btn = Button2D(icon_fnames=icon_files) + + def mode_selector(i_ren, _obj, btn): + self.current_mode = btn.icon_names[0] + i_ren.force_render() + + btn.on_left_mouse_button_pressed = mode_selector + + self.mode_panel.add_element(btn, btn_pos + padding) + btn_pos[0] += btn.size[0] + padding + + self.canvas.add_element(self.mode_panel, (0, -mode_panel_size[1])) + + self.mode_text = TextBlock2D( + text='Select appropriate drawing mode using below icon' + ) + self.canvas.add_element(self.mode_text, (0.0, 1.0)) + + self.rotation_slider = RingSlider2D(initial_value=0, + text_template="{angle:5.1f}°") + self.rotation_slider.set_visibility(False) + + def rotate_shape(slider): + angle = slider.value + previous_angle = slider.previous_value + rotation_angle = angle - previous_angle + + current_center = self.current_shape.center + self.current_shape.rotate(np.deg2rad(rotation_angle)) + self.current_shape.rotation = slider.value + self.current_shape.update_shape_position( + current_center - self.canvas.position) + + self.rotation_slider.on_moving_slider = rotate_shape + + def _get_actors(self): + """Get the actors composing this UI component.""" + return self.canvas.actors + + def _add_to_scene(self, scene): + """Add all subcomponents or VTK props that compose this UI component. + + Parameters + ---------- + scene : scene + + """ + self._scene = scene + self.canvas.add_to_scene(scene) + + def _get_size(self): + return self.canvas.size + + def _set_position(self, coords): + """Set the lower-left corner position of this UI component. + + Parameters + ---------- + coords: (float, float) + Absolute pixel coordinates (x, y). + + """ + self.canvas.position = coords + [0, self.mode_panel.size[1]] + slider_position = self.canvas.position + \ + [self.canvas.size[0] - self.rotation_slider.size[0]/2, + self.rotation_slider.size[1]/2] + self.rotation_slider.center = slider_position + +
+[docs] + def resize(self, size): + """Resize the UI.""" + pass
+ + + @property + def current_mode(self): + return self._current_mode + + @current_mode.setter + def current_mode(self, mode): + self.update_button_icons(mode) + self._current_mode = mode + if mode is not None: + self.mode_text.message = f'Mode: {mode}' + +
+[docs] + def cal_min_boundary_distance(self, position): + """Calculate minimum distance between the current position and canvas boundary. + + Parameters + ---------- + position: (float,float) + current position of the shape. + + Returns + ------- + float + Minimum distance from the boundary. + + """ + distance_list = [] + # calculate distance from element to left and lower boundary + distance_list.extend(position - self.canvas.position) + # calculate distance from element to upper and right boundary + distance_list.extend(self.canvas.position + self.canvas.size - position) + + return min(distance_list)
+ + +
+[docs] + def draw_shape(self, shape_type, current_position): + """Draw the required shape at the given position. + + Parameters + ---------- + shape_type: string + Type of shape - line, quad, circle. + current_position: (float,float) + Lower left corner position for the shape. + + """ + shape = DrawShape( + shape_type=shape_type, drawpanel=self, position=current_position + ) + if shape_type == 'circle': + shape.max_size = self.cal_min_boundary_distance(current_position) + self.shape_list.append(shape) + self._scene.add(shape) + self.canvas.add_element(shape, current_position - self.canvas.position) + self.update_shape_selection(shape)
+ + +
+[docs] + def resize_shape(self, current_position): + """Resize the shape. + + Parameters + ---------- + current_position: (float,float) + Lower left corner position for the shape. + + """ + self.current_shape = self.shape_list[-1] + size = current_position - self.current_shape.position + self.current_shape.resize(size)
+ + +
+[docs] + def update_shape_selection(self, selected_shape): + for shape in self.shape_list: + if selected_shape == shape: + shape.is_selected = True + else: + shape.is_selected = False
+ + +
+[docs] + def show_rotation_slider(self): + """Display the RingSlider2D to allow rotation of shape from the center. + """ + self._scene.rm(*self.rotation_slider.actors) + self.rotation_slider.add_to_scene(self._scene) + self.rotation_slider.set_visibility(True)
+ + +
+[docs] + def update_button_icons(self, current_mode): + """Update the button icon. + + Parameters + ---------- + current_mode: string + Current mode of the UI. + + """ + for btn in self.mode_panel._elements[1:]: + if btn.icon_names[0] == current_mode: + btn.next_icon() + elif btn.current_icon_id == 1: + btn.next_icon()
+ + +
+[docs] + def clamp_mouse_position(self, mouse_position): + """Restrict the mouse position to the canvas boundary. + + Parameters + ---------- + mouse_position: (float,float) + Current mouse position. + + Returns + ------- + list(float) + New clipped position. + + """ + return np.clip( + mouse_position, + self.canvas.position, + self.canvas.position + self.canvas.size, + )
+ + +
+[docs] + def handle_mouse_click(self, position): + if self.current_mode == 'selection': + if self.is_draggable: + self._drag_offset = position - self.position + self.current_shape.is_selected = False + if self.current_mode in ['line', 'quad', 'circle']: + self.draw_shape(self.current_mode, position)
+ + +
+[docs] + def left_button_pressed(self, i_ren, _obj, element): + self.handle_mouse_click(i_ren.event.position) + i_ren.force_render()
+ + +
+[docs] + def handle_mouse_drag(self, position): + if self.is_draggable and self.current_mode == 'selection': + if self._drag_offset is not None: + new_position = position - self._drag_offset + self.position = new_position + if self.current_mode in ['line', 'quad', 'circle']: + self.resize_shape(position)
+ + +
+[docs] + def left_button_dragged(self, i_ren, _obj, element): + mouse_position = self.clamp_mouse_position(i_ren.event.position) + self.handle_mouse_drag(mouse_position) + i_ren.force_render()
+
+ + + +
+[docs] +class PlaybackPanel(UI): + """A playback controller that can do essential functionalities. + such as play, pause, stop, and seek. + """ + +
+[docs] + def __init__(self, loop=False, position=(0, 0), width=None): + self._width = width if width is not None else 900 + self._auto_width = width is None + self._position = position + super(PlaybackPanel, self).__init__(position) + self._playing = False + self._loop = None + self.loop() if loop else self.play_once() + self._speed = 1 + # callback functions + self.on_play_pause_toggle = lambda state: None + self.on_play = lambda: None + self.on_pause = lambda: None + self.on_stop = lambda: None + self.on_loop_toggle = lambda is_looping: None + self.on_progress_bar_changed = lambda x: None + self.on_speed_up = lambda x: None + self.on_slow_down = lambda x: None + self.on_speed_changed = lambda x: None + self._set_position(position)
+ + + def _setup(self): + """Setup this Panel component.""" + self.time_text = TextBlock2D() + self.speed_text = TextBlock2D( + text='1', + font_size=21, + color=(0.2, 0.2, 0.2), + bold=True, + justification='center', + vertical_justification='middle', + ) + + self.panel = Panel2D( + size=(190, 30), + color=(1, 1, 1), + align='right', + has_border=True, + border_color=(0, 0.3, 0), + border_width=2, + ) + + play_pause_icons = [ + ('play', read_viz_icons(fname='play3.png')), + ('pause', read_viz_icons(fname='pause2.png')), + ] + + loop_icons = [ + ('once', read_viz_icons(fname='checkmark.png')), + ('loop', read_viz_icons(fname='infinite.png')), + ] + + self._play_pause_btn = Button2D(icon_fnames=play_pause_icons) + + self._loop_btn = Button2D(icon_fnames=loop_icons) + + self._stop_btn = Button2D( + icon_fnames=[('stop', read_viz_icons(fname='stop2.png'))] + ) + + self._speed_up_btn = Button2D( + icon_fnames=[('plus', read_viz_icons(fname='plus.png'))], size=(15, 15) + ) + + self._slow_down_btn = Button2D( + icon_fnames=[('minus', read_viz_icons(fname='minus.png'))], size=(15, 15) + ) + + self._progress_bar = LineSlider2D( + initial_value=0, + orientation='horizontal', + min_value=0, + max_value=100, + text_alignment='top', + length=590, + text_template='', + line_width=9, + ) + + start = 0.04 + w = 0.2 + self.panel.add_element(self._play_pause_btn, (start, 0.04)) + self.panel.add_element(self._stop_btn, (start + w, 0.04)) + self.panel.add_element(self._loop_btn, (start + 2 * w, 0.04)) + self.panel.add_element(self._slow_down_btn, (start + 0.63, 0.3)) + self.panel.add_element(self.speed_text, (start + 0.78, 0.45)) + self.panel.add_element(self._speed_up_btn, (start + 0.86, 0.3)) + + def play_pause_toggle(i_ren, _obj, _button): + self._playing = not self._playing + if self._playing: + self.play() + else: + self.pause() + self.on_play_pause_toggle(self._playing) + i_ren.force_render() + + def stop(i_ren, _obj, _button): + self.stop() + i_ren.force_render() + + def speed_up(i_ren, _obj, _button): + inc = 10 ** np.floor(np.log10(self.speed)) + self.speed = round(self.speed + inc, 13) + self.on_speed_up(self._speed) + self.on_speed_changed(self._speed) + i_ren.force_render() + + def slow_down(i_ren, _obj, _button): + dec = 10 ** np.floor(np.log10(self.speed - self.speed / 10)) + self.speed = round(self.speed - dec, 13) + self.on_slow_down(self._speed) + self.on_speed_changed(self._speed) + i_ren.force_render() + + def loop_toggle(i_ren, _obj, _button): + self._loop = not self._loop + if self._loop: + self.loop() + else: + self.play_once() + self.on_loop_toggle(self._loop) + i_ren.force_render() + + # using the adapters created above + self._play_pause_btn.on_left_mouse_button_pressed = play_pause_toggle + self._stop_btn.on_left_mouse_button_pressed = stop + self._loop_btn.on_left_mouse_button_pressed = loop_toggle + self._speed_up_btn.on_left_mouse_button_pressed = speed_up + self._slow_down_btn.on_left_mouse_button_pressed = slow_down + + def on_progress_change(slider): + t = slider.value + self.on_progress_bar_changed(t) + self.current_time = t + + self._progress_bar.on_moving_slider = on_progress_change + self.current_time = 0 + +
+[docs] + def play(self): + """Play the playback""" + self._playing = True + self._play_pause_btn.set_icon_by_name('pause') + self.on_play()
+ + +
+[docs] + def stop(self): + """Stop the playback""" + self._playing = False + self._play_pause_btn.set_icon_by_name('play') + self.on_stop()
+ + +
+[docs] + def pause(self): + """Pause the playback""" + self._playing = False + self._play_pause_btn.set_icon_by_name('play') + self.on_pause()
+ + +
+[docs] + def loop(self): + """Set repeating mode to loop.""" + self._loop = True + self._loop_btn.set_icon_by_name('loop')
+ + +
+[docs] + def play_once(self): + """Set repeating mode to repeat once.""" + self._loop = False + self._loop_btn.set_icon_by_name('once')
+ + + @property + def final_time(self): + """Set final progress slider time value. + + Returns + ------- + float + Final time for the progress slider. + + """ + return self._progress_bar.max_value + + @final_time.setter + def final_time(self, t): + """Set final progress slider time value. + + Parameters + ---------- + t: float + Final time for the progress slider. + + """ + self._progress_bar.max_value = t + + @property + def current_time(self): + """Get current time of the progress slider. + + Returns + ------- + float + Progress slider current value. + + """ + return self._progress_bar.value + + @current_time.setter + def current_time(self, t): + """Set progress slider value. + + Parameters + ---------- + t: float + Current time to be set. + + """ + self._progress_bar.value = t + self.current_time_str = t + + @property + def current_time_str(self): + """Returns current time as a string. + + Returns + ------- + str + Current time formatted as a string in the form:`HH:MM:SS`. + + """ + return self.time_text.message + + @current_time_str.setter + def current_time_str(self, t): + """Set time counter. + + Parameters + ---------- + t: float + Time to be set in the time_text counter. + + Notes + ----- + This should only be used when the `current_value` is not being set + since setting`current_value` automatically sets this property as well. + + """ + t = np.clip(t, 0, self.final_time) + if self.final_time < 3600: + m, s = divmod(t, 60) + t_str = r'%02d:%05.2f' % (m, s) + else: + m, s = divmod(t, 60) + h, m = divmod(m, 60) + t_str = r'%02d:%02d:%02d' % (h, m, s) + self.time_text.message = t_str + + @property + def speed(self): + """Returns current speed. + + Returns + ------- + str + Current time formatted as a string in the form:`HH:MM:SS`. + + """ + return self._speed + + @speed.setter + def speed(self, speed): + """Set time counter. + + Parameters + ---------- + speed: float + Speed value to be set in the speed_text counter. + + """ + if speed <= 0: + speed = 0.01 + self._speed = speed + speed_str = f'{speed}'.strip('0').rstrip('.') + self.speed_text.font_size = 21 if 0.01 <= speed < 100 else 14 + self.speed_text.message = speed_str + +
+[docs] + def show(self): + [act.SetVisibility(1) for act in self._get_actors()]
+ + +
+[docs] + def hide(self): + [act.SetVisibility(0) for act in self._get_actors()]
+ + + def _get_actors(self): + """Get the actors composing this UI component.""" + return self.panel.actors + self._progress_bar.actors + self.time_text.actors + + def _add_to_scene(self, _scene): + """Add all subcomponents or VTK props that compose this UI component. + + Parameters + ---------- + _scene : scene + + """ + + def resize_cbk(caller, ev): + if self._auto_width: + width = _scene.GetSize()[0] + if width == self.width: + return + self._width = width + self._set_position(self.position) + self._progress_bar.value = self._progress_bar.value + + _scene.AddObserver(Command.StartEvent, resize_cbk) + self.panel.add_to_scene(_scene) + self._progress_bar.add_to_scene(_scene) + self.time_text.add_to_scene(_scene) + + @property + def width(self): + """Return the width of the PlaybackPanel + + Returns + ------- + float + The width of the PlaybackPanel. + + """ + return self._width + + @width.setter + def width(self, width): + """Set width of the PlaybackPanel. + + Parameters + ---------- + width: float + The width of the whole panel. + If set to None, The width will be the same as the window's width. + + """ + self._width = width if width is not None else 900 + self._auto_width = width is None + self._set_position(self.position) + + def _set_position(self, _coords): + x, y = self.position + width = self.width + self.panel.position = (x + 5, y + 5) + progress_length = max(width - 310 - x, 1.0) + self._progress_bar.track.width = progress_length + self._progress_bar.center = (x + 215 + progress_length / 2, y + 20) + self.time_text.position = (x + 225 + progress_length, y + 10) + + def _get_size(self): + return self.panel.size + self._progress_bar.size + self.time_text.size
+ + + +
+[docs] +class Card2D(UI): + """Card element to show image and related text + + Attributes + ---------- + image: :class: 'ImageContainer2D' + Renders the image on the card. + title_box: :class: 'TextBlock2D' + Displays the title on card. + body_box: :class: 'TextBLock2D' + Displays the body text. + + """ + +
+[docs] + def __init__(self, image_path, body_text="", draggable=True, + title_text="", padding=10, position=(0, 0), + size=(400, 400), image_scale=0.5, bg_color=(0.5, 0.5, 0.5), + bg_opacity=1, title_color=(0., 0., 0.), + body_color=(0., 0., 0.), border_color=(1., 1., 1.), + border_width=0, maintain_aspect=False): + """Parameters + ---------- + image_path: str + Path of the image, supports png and jpg/jpeg images + body_text: str, optional + Card body text + draggable: Bool, optional + If the card should be draggable + title_text: str, optional + Card title text + padding: int, optional + Padding between image, title, body + position : (float, float), optional + Absolute coordinates (x, y) of the lower-left corner of the + UI component + size : (int, int), optional + Width and height of the pixels of this UI component. + image_scale: float, optional + fraction of size taken by the image (between 0 , 1) + bg_color: (float, float, float), optional + Background color of card + bg_opacity: float, optional + Background opacity + title_color: (float, float, float), optional + Title text color + body_color: (float, float, float), optional + Body text color + border_color: (float, float, float), optional + Border color + border_width: int, optional + Width of the border + maintain_aspect: bool, optional + If the image should be scaled to maintain aspect ratio + + """ + self.image_path = image_path + self._basename = os.path.basename(self.image_path) + self._extension = self._basename.split('.')[-1] + if self._extension not in ['jpg', 'jpeg', 'png']: + raise UnidentifiedImageError( + f'Image extension {self._extension} not supported') + + self.body_text = body_text + self.title_text = title_text + self.draggable = draggable + self.card_size = size + self.padding = padding + + self.title_color = [np.clip(value, 0, 1) for value in title_color] + self.body_color = [np.clip(value, 0, 1) for value in body_color] + self.bg_color = [np.clip(value, 0, 1) for value in bg_color] + self.border_color = [np.clip(value, 0, 1) for value in border_color] + self.bg_opacity = bg_opacity + + self.text_scale = np.clip(1 - image_scale, 0, 1) + self.image_scale = np.clip(image_scale, 0, 1) + + self.maintain_aspect = maintain_aspect + if self.maintain_aspect: + self._true_image_size = Image.open(urlopen(self.image_path)).size + + self._image_size = (self.card_size[0], self.card_size[1] * + self.image_scale) + + self.border_width = border_width + self.has_border = bool(border_width) + + super(Card2D, self).__init__() + self.position = position + + if self.maintain_aspect: + self._new_size = (self._true_image_size[0], + self._true_image_size[1] // self.image_scale) + self.resize(self._new_size) + else: + self.resize(size)
+ + + def _setup(self): + """Setup this UI component + Create the image. + Create the title and body. + Create a Panel2D widget to hold image, title, body. + """ + self.image = ImageContainer2D(img_path=self.image_path, + size=self._image_size) + + self.body_box = TextBlock2D(text=self.body_text, + color=self.body_color) + + self.title_box = TextBlock2D(text=self.title_text, bold=True, + color=self.title_color) + + self.panel = Panel2D(self.card_size, color=self.bg_color, + opacity=self.bg_opacity, + border_color=self.border_color, + border_width=self.border_width, + has_border=self.has_border) + + self.panel.add_element(self.image, (0., 0.)) + self.panel.add_element(self.title_box, (0., 0.)) + self.panel.add_element(self.body_box, (0., 0.)) + + if self.draggable: + self.panel.background.on_left_mouse_button_dragged =\ + self.left_button_dragged + self.panel.background.on_left_mouse_button_pressed\ + = self.left_button_pressed + self.image.on_left_mouse_button_dragged =\ + self.left_button_dragged + self.image.on_left_mouse_button_pressed =\ + self.left_button_pressed + else: + self.panel.background.on_left_mouse_button_dragged =\ + lambda i_ren, _obj, _comp: i_ren.force_render + + def _get_actors(self): + """Get the actors composing this UI component. + """ + return self.panel.actors + + def _add_to_scene(self, _scene): + """Add all subcomponents or VTK props that compose this UI component. + + Parameters + ---------- + scene : scene + + """ + self.panel.add_to_scene(_scene) + if self.size[0] <= 200: + clip_overflow(self.body_box, self.size[0]-2*self.padding) + else: + wrap_overflow(self.body_box, self.size[0]-2*self.padding) + + wrap_overflow(self.title_box, self.size[0]-2*self.padding) + + def _get_size(self): + return self.panel.size + +
+[docs] + def resize(self, size): + """Resize Card2D. + + Parameters + ---------- + size : (int, int) + Card2D size(width, height) in pixels. + + """ + _width, _height = size + self.panel.resize(size) + + self._image_size = (size[0]-int(self.border_width), + int(self.image_scale*size[1])) + + _title_box_size = (_width - 2 * self.padding, _height * + 0.34 * self.text_scale / 2) + + _body_box_size = (_width - 2 * self.padding, _height * + self.text_scale / 2) + + _img_coords = (int(self.border_width), + int(size[1] - self._image_size[1])) + + _title_coords = (self.padding, int(_img_coords[1] - + _title_box_size[1] - self.padding + + self.border_width)) + + _text_coords = (self.padding, int(_title_coords[1] - + _body_box_size[1] - self.padding + + self.border_width)) + + self.panel.update_element(self.image, _img_coords) + self.panel.update_element(self.body_box, _text_coords) + self.panel.update_element(self.title_box, _title_coords) + + self.image.resize(self._image_size) + self.title_box.resize(_title_box_size)
+ + + def _set_position(self, _coords): + """Position the lower-left corner of this UI component. + + Parameters + ---------- + coords: (float, float) + Absolute pixel coordinates (x, y). + + """ + self.panel.position = _coords + + @property + def color(self): + """Returns the background color of card. + """ + return self.panel.color + + @color.setter + def color(self, color): + """Sets background color of card. + + Parameters + ---------- + color : list of 3 floats. + + """ + self.panel.color = color + + @property + def body(self): + """Returns the body text of the card. + """ + return self.body_box.message + + @body.setter + def body(self, text): + self.body_box.message = text + + @property + def title(self): + """Returns the title text of the card + """ + return self.title_box.message + + @title.setter + def title(self, text): + self.title_box.message = text + +
+[docs] + def left_button_pressed(self, i_ren, _obj, _sub_component): + click_pos = np.array(i_ren.event.position) + self._click_position = click_pos + i_ren.event.abort()
+ + +
+[docs] + def left_button_dragged(self, i_ren, _obj, _sub_component): + click_position = np.array(i_ren.event.position) + change = click_position - self._click_position + self.panel.position += change + self._click_position = click_position + i_ren.force_render()
+
+ + + +
+[docs] +class SpinBox(UI): + """SpinBox UI. + """ + +
+[docs] + def __init__(self, position=(350, 400), size=(300, 100), padding=10, + panel_color=(1, 1, 1), min_val=0, max_val=100, + initial_val=50, step=1, max_column=10, max_line=2): + """Init this UI element. + + Parameters + ---------- + position : (int, int), optional + Absolute coordinates (x, y) of the lower-left corner of this + UI component. + size : (int, int), optional + Width and height in pixels of this UI component. + padding : int, optional + Distance between TextBox and Buttons. + panel_color : (float, float, float), optional + Panel color of SpinBoxUI. + min_val: int, optional + Minimum value of SpinBoxUI. + max_val: int, optional + Maximum value of SpinBoxUI. + initial_val: int, optional + Initial value of SpinBoxUI. + step: int, optional + Step value of SpinBoxUI. + max_column: int, optional + Max number of characters in a line. + max_line: int, optional + Max number of lines in the textbox. + + """ + self.panel_size = size + self.padding = padding + self.panel_color = panel_color + self.min_val = min_val + self.max_val = max_val + self.step = step + self.max_column = max_column + self.max_line = max_line + + super(SpinBox, self).__init__(position) + self.value = initial_val + self.resize(size) + + self.on_change = lambda ui: None
+ + + def _setup(self): + """Setup this UI component. + + Create the SpinBoxUI with Background (Panel2D) and InputBox (TextBox2D) + and Increment,Decrement Button (Button2D). + """ + self.panel = Panel2D(size=self.panel_size, color=self.panel_color) + + self.textbox = TextBox2D(width=self.max_column, + height=self.max_line) + self.textbox.text.dynamic_bbox = False + self.textbox.text.auto_font_scale = True + self.increment_button = Button2D( + icon_fnames=[("up", read_viz_icons(fname="circle-up.png"))]) + self.decrement_button = Button2D( + icon_fnames=[("down", read_viz_icons(fname="circle-down.png"))]) + + self.panel.add_element(self.textbox, (0, 0)) + self.panel.add_element(self.increment_button, (0, 0)) + self.panel.add_element(self.decrement_button, (0, 0)) + + # Adding button click callbacks + self.increment_button.on_left_mouse_button_pressed = \ + self.increment_callback + self.decrement_button.on_left_mouse_button_pressed = \ + self.decrement_callback + self.textbox.off_focus = self.textbox_update_value + +
+[docs] + def resize(self, size): + """Resize SpinBox. + + Parameters + ---------- + size : (float, float) + SpinBox size(width, height) in pixels. + + """ + self.panel_size = size + self.textbox_size = (int(0.7 * size[0]), int(0.8 * size[1])) + self.button_size = (int(0.2 * size[0]), int(0.3 * size[1])) + self.padding = int(0.03 * self.panel_size[0]) + + self.panel.resize(size) + self.textbox.text.resize(self.textbox_size) + self.increment_button.resize(self.button_size) + self.decrement_button.resize(self.button_size) + + textbox_pos = (self.padding, int((size[1] - self.textbox_size[1])/2)) + inc_btn_pos = (size[0] - self.padding - self.button_size[0], + int((1.5*size[1] - self.button_size[1])/2)) + dec_btn_pos = (size[0] - self.padding - self.button_size[0], + int((0.5*size[1] - self.button_size[1])/2)) + + self.panel.update_element(self.textbox, textbox_pos) + self.panel.update_element(self.increment_button, inc_btn_pos) + self.panel.update_element(self.decrement_button, dec_btn_pos)
+ + + def _get_actors(self): + """Get the actors composing this UI component.""" + return self.panel.actors + + def _add_to_scene(self, scene): + """Add all subcomponents or VTK props that compose this UI component. + + Parameters + ---------- + scene : Scene + + """ + self.panel.add_to_scene(scene) + + def _get_size(self): + return self.panel.size + + def _set_position(self, coords): + """Set the lower-left corner position of this UI component. + + Parameters + ---------- + coords: (float, float) + Absolute pixel coordinates (x, y). + + """ + self.panel.center = coords + +
+[docs] + def increment_callback(self, i_ren, _obj, _button): + self.increment() + i_ren.force_render() + i_ren.event.abort()
+ + +
+[docs] + def decrement_callback(self, i_ren, _obj, _button): + self.decrement() + i_ren.force_render() + i_ren.event.abort()
+ + + @property + def value(self): + return self._value + + @value.setter + def value(self, value): + if value >= self.max_val: + self._value = self.max_val + elif value <= self.min_val: + self._value = self.min_val + else: + self._value = value + + self.textbox.set_message(str(self._value)) + +
+[docs] + def validate_value(self, value): + """Validate and convert the given value into integer. + + Parameters + ---------- + value : str + Input value received from the textbox. + + Returns + ------- + int + If valid return converted integer else the previous value. + + """ + if value.isnumeric(): + return int(value) + + return self.value
+ + +
+[docs] + def increment(self): + """Increment the current value by the step.""" + current_val = self.validate_value(self.textbox.message) + self.value = current_val + self.step + self.on_change(self)
+ + +
+[docs] + def decrement(self): + """Decrement the current value by the step.""" + current_val = self.validate_value(self.textbox.message) + self.value = current_val - self.step + self.on_change(self)
+ + +
+[docs] + def textbox_update_value(self, textbox): + self.value = self.validate_value(textbox.message) + self.on_change(self)
+
+ +
+
+ + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/_modules/fury/ui/helpers.html b/v0.10.x/_modules/fury/ui/helpers.html new file mode 100644 index 000000000..31e0c93f0 --- /dev/null +++ b/v0.10.x/_modules/fury/ui/helpers.html @@ -0,0 +1,664 @@ + + + + + + + fury.ui.helpers — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +

Source code for fury.ui.helpers

+"""Helper variable or function for UI Elements."""
+
+import numpy as np
+
+TWO_PI = 2 * np.pi
+
+
+
+[docs] +def clip_overflow(textblock, width, side='right'): + """Clips overflowing text of TextBlock2D with respect to width. + + Parameters + ---------- + textblock : TextBlock2D + The textblock object whose text needs to be clipped. + width : int + Required width of the clipped text. + side : str, optional + Clips the overflowing text according to side. + It takes values "left" or "right". + + Returns + ------- + clipped text : str + Clipped version of the text. + + """ + original_str = textblock.message + prev_bg = textblock.have_bg + + clip_idx = check_overflow(textblock, width, '...', side) + + if clip_idx == 0: + return original_str + + textblock.have_bg = prev_bg + return textblock.message
+ + + +
+[docs] +def wrap_overflow(textblock, wrap_width, side='right'): + """Wraps overflowing text of TextBlock2D with respect to width. + + Parameters + ---------- + textblock : TextBlock2D + The textblock object whose text needs to be wrapped. + wrap_width : int + Required width of the wrapped text. + side : str, optional + Clips the overflowing text according to side. + It takes values "left" or "right". + + Returns + ------- + wrapped text : str + Wrapped version of the text. + + """ + original_str = textblock.message + str_copy = textblock.message + wrap_idxs = [] + + wrap_idx = check_overflow(textblock, wrap_width, '', side) + + if wrap_idx == 0: + return original_str + + wrap_idxs.append(wrap_idx) + + while wrap_idx != 0: + str_copy = str_copy[wrap_idx:] + textblock.message = str_copy + wrap_idx = check_overflow(textblock, wrap_width, '', side) + if wrap_idx != 0: + wrap_idxs.append(wrap_idxs[-1] + wrap_idx + 1) + + for idx in wrap_idxs: + original_str = original_str[:idx] + '\n' + original_str[idx:] + + textblock.message = original_str + return textblock.message
+ + + +
+[docs] +def check_overflow(textblock, width, overflow_postfix='', side='right'): + """Checks if the text is overflowing. + + Parameters + ---------- + textblock : TextBlock2D + The textblock object whose text is to be checked. + width: int + Required width of the text. + overflow_postfix: str, optional + Postfix to be added to the text if it is overflowing. + + Returns + ------- + mid_ptr: int + Overflow index of the text. + + """ + side = side.lower() + if side not in ['left', 'right']: + raise ValueError("side can only take values 'left' or 'right'") + + original_str = textblock.message + start_ptr = 0 + mid_ptr = 0 + end_ptr = len(original_str) + + if side == 'left': + original_str = original_str[::-1] + + if textblock.cal_size_from_message()[0] <= width: + return 0 + + while start_ptr < end_ptr: + mid_ptr = (start_ptr + end_ptr) // 2 + textblock.message = original_str[:mid_ptr] + overflow_postfix + + if textblock.cal_size_from_message()[0] < width: + start_ptr = mid_ptr + elif textblock.cal_size_from_message()[0] > width: + end_ptr = mid_ptr + + if (mid_ptr == (start_ptr + end_ptr) // 2 or + textblock.cal_size_from_message()[0] == width): + if side == 'left': + textblock.message = textblock.message[::-1] + return mid_ptr
+ + + +
+[docs] +def cal_bounding_box_2d(vertices): + """Calculate the min, max position and the size of the bounding box. + + Parameters + ---------- + vertices : ndarray + vertices of the actors. + + """ + if vertices.ndim != 2 or vertices.shape[1] not in [2, 3]: + raise IOError('vertices should be a 2D array with shape (n,2) or (n,3).') + + if vertices.shape[1] == 3: + vertices = vertices[:, :-1] + + min_x, min_y = vertices[0] + max_x, max_y = vertices[0] + + for x, y in vertices: + if x < min_x: + min_x = x + if y < min_y: + min_y = y + if x > max_x: + max_x = x + if y > max_y: + max_y = y + + bounding_box_min = np.asarray([min_x, min_y], dtype='int') + bounding_box_max = np.asarray([max_x, max_y], dtype='int') + bounding_box_size = np.asarray([max_x - min_x, max_y - min_y], dtype='int') + + return bounding_box_min, bounding_box_max, bounding_box_size
+ + + +
+[docs] +def rotate_2d(vertices, angle): + """Rotate the given vertices by an angle. + + Parameters + ---------- + vertices : ndarray + vertices of the actors. + angle: float + Value by which the vertices are rotated in radian. + + """ + if vertices.ndim != 2 or vertices.shape[1] != 3: + raise IOError('vertices should be a 2D array with shape (n,3).') + + rotation_matrix = np.array( + [ + [np.cos(angle), np.sin(angle), 0], + [-np.sin(angle), np.cos(angle), 0], + [0, 0, 1], + ] + ) + new_vertices = np.matmul(vertices, rotation_matrix) + + return new_vertices
+ +
+
+ + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/_modules/fury/utils.html b/v0.10.x/_modules/fury/utils.html new file mode 100644 index 000000000..e7c3c7f02 --- /dev/null +++ b/v0.10.x/_modules/fury/utils.html @@ -0,0 +1,2249 @@ + + + + + + + fury.utils — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +

Source code for fury.utils

+import numpy as np
+from scipy.ndimage import map_coordinates
+
+from fury.colormap import line_colors
+from fury.lib import (
+    VTK_DOUBLE,
+    VTK_FLOAT,
+    VTK_INT,
+    VTK_UNSIGNED_CHAR,
+    Actor,
+    AlgorithmOutput,
+    CellArray,
+    Glyph3D,
+    ImageData,
+    Matrix3x3,
+    Matrix4x4,
+    Points,
+    PolyData,
+    PolyDataMapper,
+    PolyDataNormals,
+    Transform,
+    TransformPolyDataFilter,
+    numpy_support,
+)
+
+
+
+[docs] +def remove_observer_from_actor(actor, id): + """Remove the observer with the given id from the actor. + + Parameters + ---------- + actor : vtkActor + id : int + id of the observer to remove + + """ + if not hasattr(actor, 'GetMapper'): + raise ValueError('Invalid actor') + + mapper = actor.GetMapper() + if not hasattr(mapper, 'RemoveObserver'): + raise ValueError('Invalid mapper') + mapper.RemoveObserver(id)
+ + + +
+[docs] +def set_input(vtk_object, inp): + """Set Generic input function which takes into account VTK 5 or 6. + + Parameters + ---------- + vtk_object: vtk object + inp: vtkPolyData or vtkImageData or vtkAlgorithmOutput + + Returns + ------- + vtk_object + + Notes + ----- + This can be used in the following way:: + from fury.utils import set_input + poly_mapper = set_input(PolyDataMapper(), poly_data) + + """ + if isinstance(inp, (PolyData, ImageData)): + vtk_object.SetInputData(inp) + elif isinstance(inp, AlgorithmOutput): + vtk_object.SetInputConnection(inp) + vtk_object.Update() + return vtk_object
+ + + +
+[docs] +def numpy_to_vtk_points(points): + """Convert Numpy points array to a vtk points array. + + Parameters + ---------- + points : ndarray + + Returns + ------- + vtk_points : vtkPoints() + + """ + vtk_points = Points() + vtk_points.SetData(numpy_support.numpy_to_vtk(np.asarray(points), deep=True)) + return vtk_points
+ + + +
+[docs] +def numpy_to_vtk_colors(colors): + """Convert Numpy color array to a vtk color array. + + Parameters + ---------- + colors: ndarray + + Returns + ------- + vtk_colors : vtkDataArray + + Notes + ----- + If colors are not already in UNSIGNED_CHAR you may need to multiply by 255. + + Examples + -------- + >>> import numpy as np + >>> from fury.utils import numpy_to_vtk_colors + >>> rgb_array = np.random.rand(100, 3) + >>> vtk_colors = numpy_to_vtk_colors(255 * rgb_array) + + """ + vtk_colors = numpy_support.numpy_to_vtk( + np.asarray(colors), deep=True, array_type=VTK_UNSIGNED_CHAR + ) + return vtk_colors
+ + + +
+[docs] +def numpy_to_vtk_cells(data, is_coords=True): + """Convert numpy array to a vtk cell array. + + Parameters + ---------- + data : ndarray + points coordinate or connectivity array (e.g triangles). + is_coords : ndarray + Select the type of array. default: True. + + Returns + ------- + vtk_cell : vtkCellArray + connectivity + offset information + + """ + if isinstance(data, (list, np.ndarray)): + offsets_dtype = np.int64 + else: + offsets_dtype = np.dtype(data._offsets.dtype) + if offsets_dtype.kind == 'u': + offsets_dtype = np.dtype(offsets_dtype.name[1:]) + data = np.array(data, dtype=object) + nb_cells = len(data) + + # Get lines_array in vtk input format + connectivity = data.flatten() if not is_coords else [] + offset = [ + 0, + ] + current_position = 0 + + cell_array = CellArray() + + for i in range(nb_cells): + current_len = len(data[i]) + offset.append(offset[-1] + current_len) + + if is_coords: + end_position = current_position + current_len + connectivity += list(range(current_position, end_position)) + current_position = end_position + + connectivity = np.array(connectivity, offsets_dtype) + offset = np.array(offset, dtype=offsets_dtype) + + vtk_array_type = numpy_support.get_vtk_array_type(offsets_dtype) + cell_array.SetData( + numpy_support.numpy_to_vtk(offset, deep=True, array_type=vtk_array_type), + numpy_support.numpy_to_vtk(connectivity, deep=True, array_type=vtk_array_type), + ) + + cell_array.SetNumberOfCells(nb_cells) + return cell_array
+ + + +
+[docs] +def numpy_to_vtk_image_data( + array, spacing=(1.0, 1.0, 1.0), origin=(0.0, 0.0, 0.0), deep=True +): + """Convert numpy array to a vtk image data. + + Parameters + ---------- + array : ndarray + pixel coordinate and colors values. + spacing : (float, float, float) (optional) + sets the size of voxel (unit of space in each direction x,y,z) + origin : (float, float, float) (optional) + sets the origin at the given point + deep : bool (optional) + decides the type of copy(ie. deep or shallow) + + Returns + ------- + vtk_image : vtkImageData + + """ + if array.ndim not in [2, 3]: + raise IOError('only 2D (L, RGB, RGBA) or 3D image available') + + vtk_image = ImageData() + depth = 1 if array.ndim == 2 else array.shape[2] + + vtk_image.SetDimensions(array.shape[1], array.shape[0], depth) + vtk_image.SetExtent(0, array.shape[1] - 1, 0, array.shape[0] - 1, 0, 0) + vtk_image.SetSpacing(spacing) + vtk_image.SetOrigin(origin) + temp_arr = np.flipud(array) + temp_arr = temp_arr.reshape(array.shape[1] * array.shape[0], depth) + temp_arr = np.ascontiguousarray(temp_arr, dtype=array.dtype) + vtk_array_type = numpy_support.get_vtk_array_type(array.dtype) + uchar_array = numpy_support.numpy_to_vtk( + temp_arr, deep=deep, array_type=vtk_array_type + ) + vtk_image.GetPointData().SetScalars(uchar_array) + return vtk_image
+ + + +
+[docs] +def map_coordinates_3d_4d(input_array, indices): + """Evaluate input_array at the given indices using trilinear interpolation. + + Parameters + ---------- + input_array : ndarray, + 3D or 4D array + indices : ndarray + + Returns + ------- + output : ndarray + 1D or 2D array + + """ + if input_array.ndim <= 2 or input_array.ndim >= 5: + raise ValueError('Input array can only be 3d or 4d') + + if input_array.ndim == 3: + return map_coordinates(input_array, indices.T, order=1) + + if input_array.ndim == 4: + values_4d = [] + for i in range(input_array.shape[-1]): + values_tmp = map_coordinates(input_array[..., i], indices.T, order=1) + values_4d.append(values_tmp) + return np.ascontiguousarray(np.array(values_4d).T)
+ + + +
+[docs] +def lines_to_vtk_polydata(lines, colors=None): + """Create a vtkPolyData with lines and colors. + + Parameters + ---------- + lines : list + list of N curves represented as 2D ndarrays + colors : array (N, 3), list of arrays, tuple (3,), array (K,) + If None or False, a standard orientation colormap is used for every + line. + If one tuple of color is used. Then all streamlines will have the same + colour. + If an array (N, 3) is given, where N is equal to the number of lines. + Then every line is coloured with a different RGB color. + If a list of RGB arrays is given then every point of every line takes + a different color. + If an array (K, 3) is given, where K is the number of points of all + lines then every point is colored with a different RGB color. + If an array (K,) is given, where K is the number of points of all + lines then these are considered as the values to be used by the + colormap. + If an array (L,) is given, where L is the number of streamlines then + these are considered as the values to be used by the colormap per + streamline. + If an array (X, Y, Z) or (X, Y, Z, 3) is given then the values for the + colormap are interpolated automatically using trilinear interpolation. + + Returns + ------- + poly_data : vtkPolyData + color_is_scalar : bool, true if the color array is a single scalar + Scalar array could be used with a colormap lut + None if no color was used + + """ + # Get the 3d points_array + if lines.__class__.__name__ == 'ArraySequence': + points_array = lines._data + else: + points_array = np.vstack(lines) + + if points_array.size == 0: + raise ValueError('Empty lines/streamlines data.') + + # Set Points to vtk array format + vtk_points = numpy_to_vtk_points(points_array) + + # Set Lines to vtk array format + vtk_cell_array = numpy_to_vtk_cells(lines) + + # Create the poly_data + poly_data = PolyData() + poly_data.SetPoints(vtk_points) + poly_data.SetLines(vtk_cell_array) + + # Get colors_array (reformat to have colors for each points) + # - if/else tested and work in normal simple case + nb_points = len(points_array) + nb_lines = len(lines) + lines_range = range(nb_lines) + points_per_line = [len(lines[i]) for i in lines_range] + points_per_line = np.array(points_per_line, np.intp) + + color_is_scalar = False + if points_array.size: + if colors is None or colors is False: + # set automatic rgb colors + cols_arr = line_colors(lines) + colors_mapper = np.repeat(lines_range, points_per_line, axis=0) + vtk_colors = numpy_to_vtk_colors(255 * cols_arr[colors_mapper]) + else: + cols_arr = np.asarray(colors) + if cols_arr.dtype == object: # colors is a list of colors + vtk_colors = numpy_to_vtk_colors(255 * np.vstack(colors)) + else: + if len(cols_arr) == nb_points: + if cols_arr.ndim == 1: # values for every point + vtk_colors = numpy_support.numpy_to_vtk(cols_arr, deep=True) + color_is_scalar = True + elif cols_arr.ndim == 2: # map color to each point + vtk_colors = numpy_to_vtk_colors(255 * cols_arr) + + elif cols_arr.ndim == 1: + if len(cols_arr) == nb_lines: # values for every streamline + cols_arrx = [] + for (i, value) in enumerate(colors): + cols_arrx += lines[i].shape[0] * [value] + cols_arrx = np.array(cols_arrx) + vtk_colors = numpy_support.numpy_to_vtk(cols_arrx, deep=True) + color_is_scalar = True + else: # the same colors for all points + vtk_colors = numpy_to_vtk_colors( + np.tile(255 * cols_arr, (nb_points, 1)) + ) + + elif cols_arr.ndim == 2: # map color to each line + colors_mapper = np.repeat(lines_range, points_per_line, axis=0) + vtk_colors = numpy_to_vtk_colors(255 * cols_arr[colors_mapper]) + else: # colormap + # get colors for each vertex + cols_arr = map_coordinates_3d_4d(cols_arr, points_array) + vtk_colors = numpy_support.numpy_to_vtk(cols_arr, deep=True) + color_is_scalar = True + + vtk_colors.SetName('colors') + poly_data.GetPointData().SetScalars(vtk_colors) + + return poly_data, color_is_scalar
+ + + +
+[docs] +def get_polydata_lines(line_polydata): + """Convert vtk polydata to a list of lines ndarrays. + + Parameters + ---------- + line_polydata : vtkPolyData + + Returns + ------- + lines : list + List of N curves represented as 2D ndarrays + + """ + lines_vertices = numpy_support.vtk_to_numpy(line_polydata.GetPoints().GetData()) + lines_idx = numpy_support.vtk_to_numpy(line_polydata.GetLines().GetData()) + + lines = [] + current_idx = 0 + while current_idx < len(lines_idx): + line_len = lines_idx[current_idx] + + next_idx = current_idx + line_len + 1 + line_range = lines_idx[current_idx + 1 : next_idx] + + lines += [lines_vertices[line_range]] + current_idx = next_idx + return lines
+ + + +
+[docs] +def get_polydata_triangles(polydata): + """Get triangles (ndarrays Nx3 int) from a vtk polydata. + + Parameters + ---------- + polydata : vtkPolyData + + Returns + ------- + output : array (N, 3) + triangles + + """ + vtk_polys = numpy_support.vtk_to_numpy(polydata.GetPolys().GetData()) + # test if its really triangles + if not (vtk_polys[::4] == 3).all(): + raise AssertionError('Shape error: this is not triangles') + return np.vstack([vtk_polys[1::4], vtk_polys[2::4], vtk_polys[3::4]]).T
+ + + +
+[docs] +def get_polydata_vertices(polydata): + """Get vertices (ndarrays Nx3 int) from a vtk polydata. + + Parameters + ---------- + polydata : vtkPolyData + + Returns + ------- + output : array (N, 3) + points, represented as 2D ndarrays + + """ + return numpy_support.vtk_to_numpy(polydata.GetPoints().GetData())
+ + + +
+[docs] +def get_polydata_tcoord(polydata): + """Get texture coordinates (ndarrays Nx2 float) from a vtk polydata. + + Parameters + ---------- + polydata : vtkPolyData + + Returns + ------- + output : array (N, 2) + Tcoords, represented as 2D ndarrays. None if there are no texture + in the vtk polydata. + + """ + vtk_tcoord = polydata.GetPointData().GetTCoords() + if vtk_tcoord is None: + return None + + return numpy_support.vtk_to_numpy(vtk_tcoord)
+ + + +
+[docs] +def get_polydata_normals(polydata): + """Get vertices normal (ndarrays Nx3 int) from a vtk polydata. + + Parameters + ---------- + polydata : vtkPolyData + + Returns + ------- + output : array (N, 3) + Normals, represented as 2D ndarrays (Nx3). None if there are no normals + in the vtk polydata. + + """ + vtk_normals = polydata.GetPointData().GetNormals() + if vtk_normals is None: + return None + + return numpy_support.vtk_to_numpy(vtk_normals)
+ + + +
+[docs] +def get_polydata_tangents(polydata): + """Get vertices tangent (ndarrays Nx3 int) from a vtk polydata. + + Parameters + ---------- + polydata : vtkPolyData + + Returns + ------- + output : array (N, 3) + Tangents, represented as 2D ndarrays (Nx3). None if there are no + tangents in the vtk polydata. + + """ + vtk_tangents = polydata.GetPointData().GetTangents() + if vtk_tangents is None: + return None + + return numpy_support.vtk_to_numpy(vtk_tangents)
+ + + +
+[docs] +def get_polydata_colors(polydata): + """Get points color (ndarrays Nx3 int) from a vtk polydata. + + Parameters + ---------- + polydata : vtkPolyData + + Returns + ------- + output : array (N, 3) + Colors. None if no normals in the vtk polydata. + + """ + vtk_colors = polydata.GetPointData().GetScalars() + if vtk_colors is None: + return None + + return numpy_support.vtk_to_numpy(vtk_colors)
+ + + +
+[docs] +def get_polydata_field(polydata, field_name, as_vtk=False): + """Get a field from a vtk polydata. + + Parameters + ---------- + polydata : vtkPolyData + field_name : str + as_vtk : optional + By default, ndarray is returned. + + Returns + ------- + output : ndarray or vtkDataArray + Field data. The return type depends on the value of the as_vtk + parameter. None if the field is not found. + + """ + vtk_field_data = polydata.GetFieldData().GetArray(field_name) + if vtk_field_data is None: + return None + if as_vtk: + return vtk_field_data + return numpy_support.vtk_to_numpy(vtk_field_data)
+ + + +
+[docs] +def add_polydata_numeric_field(polydata, field_name, field_data, array_type=VTK_INT): + """Add a field to a vtk polydata. + + Parameters + ---------- + polydata : vtkPolyData + field_name : str + field_data : bool, int, float, double, numeric array or ndarray + array_type : vtkArrayType + + """ + vtk_field_data = numpy_support.numpy_to_vtk( + field_data, deep=True, array_type=array_type + ) + vtk_field_data.SetName(field_name) + polydata.GetFieldData().AddArray(vtk_field_data) + return polydata
+ + + +
+[docs] +def set_polydata_primitives_count(polydata, primitives_count): + """Add primitives count to polydata. + + Parameters + ---------- + polydata: vtkPolyData + primitives_count : int + + """ + add_polydata_numeric_field( + polydata, 'prim_count', primitives_count, array_type=VTK_INT + )
+ + + +
+[docs] +def get_polydata_primitives_count(polydata): + """Get primitives count from actor's polydata. + + Parameters + ---------- + polydata: vtkPolyData + + Returns + ------- + primitives count : int + + """ + return get_polydata_field(polydata, 'prim_count')[0]
+ + + +
+[docs] +def primitives_count_to_actor(actor, primitives_count): + """Add primitives count to actor's polydata. + + Parameters + ---------- + actor: :class: `UI` or `vtkProp3D` actor + primitives_count : int + + """ + polydata = actor.GetMapper().GetInput() + set_polydata_primitives_count(polydata, primitives_count)
+ + + +
+[docs] +def primitives_count_from_actor(actor): + """Get primitives count from actor's polydata. + + Parameters + ---------- + actor: :class: `UI` or `vtkProp3D` actor + + Returns + ------- + primitives count : int + + """ + polydata = actor.GetMapper().GetInput() + return get_polydata_primitives_count(polydata)
+ + + +
+[docs] +def set_polydata_triangles(polydata, triangles): + """Set polydata triangles with a numpy array (ndarrays Nx3 int). + + Parameters + ---------- + polydata : vtkPolyData + triangles : array (N, 3) + triangles, represented as 2D ndarrays (Nx3) + + """ + vtk_cells = CellArray() + vtk_cells = numpy_to_vtk_cells(triangles, is_coords=False) + polydata.SetPolys(vtk_cells) + return polydata
+ + + +
+[docs] +def set_polydata_vertices(polydata, vertices): + """Set polydata vertices with a numpy array (ndarrays Nx3 int). + + Parameters + ---------- + polydata : vtkPolyData + vertices : vertices, represented as 2D ndarrays (Nx3) + + """ + vtk_points = Points() + vtk_points.SetData(numpy_support.numpy_to_vtk(vertices, deep=True)) + polydata.SetPoints(vtk_points) + return polydata
+ + + +
+[docs] +def set_polydata_normals(polydata, normals): + """Set polydata normals with a numpy array (ndarrays Nx3 int). + + Parameters + ---------- + polydata : vtkPolyData + normals : normals, represented as 2D ndarrays (Nx3) (one per vertex) + + """ + vtk_normals = numpy_support.numpy_to_vtk(normals, deep=True) + # VTK does not require a specific name for the normals array, however, for + # readability purposes, we set it to "Normals" + vtk_normals.SetName('Normals') + polydata.GetPointData().SetNormals(vtk_normals) + return polydata
+ + + +
+[docs] +def set_polydata_tangents(polydata, tangents): + """Set polydata tangents with a numpy array (ndarrays Nx3 int). + + Parameters + ---------- + polydata : vtkPolyData + tangents : tangents, represented as 2D ndarrays (Nx3) (one per vertex) + + """ + vtk_tangents = numpy_support.numpy_to_vtk(tangents, deep=True, array_type=VTK_FLOAT) + # VTK does not require a specific name for the tangents array, however, for + # readability purposes, we set it to "Tangents" + vtk_tangents.SetName('Tangents') + polydata.GetPointData().SetTangents(vtk_tangents) + return polydata
+ + + +
+[docs] +def set_polydata_colors(polydata, colors, array_name='colors'): + """Set polydata colors with a numpy array (ndarrays Nx3 int). + + Parameters + ---------- + polydata : vtkPolyData + colors : colors, represented as 2D ndarrays (Nx3) + colors are uint8 [0,255] RGB for each points + + """ + vtk_colors = numpy_support.numpy_to_vtk( + colors, deep=True, array_type=VTK_UNSIGNED_CHAR + ) + nb_components = colors.shape[1] + vtk_colors.SetNumberOfComponents(nb_components) + vtk_colors.SetName(array_name) + polydata.GetPointData().SetScalars(vtk_colors) + return polydata
+ + + +
+[docs] +def set_polydata_tcoords(polydata, tcoords): + """Set polydata texture coordinates with a numpy array (ndarrays Nx2 float). + + Parameters + ---------- + polydata : vtkPolyData + tcoords : texture coordinates, represented as 2D ndarrays (Nx2) + (one per vertex range (0, 1)) + + """ + vtk_tcoords = numpy_support.numpy_to_vtk(tcoords, deep=True, array_type=VTK_FLOAT) + polydata.GetPointData().SetTCoords(vtk_tcoords) + return polydata
+ + + +
+[docs] +def update_polydata_normals(polydata): + """Generate and update polydata normals. + + Parameters + ---------- + polydata : vtkPolyData + + """ + normals_gen = set_input(PolyDataNormals(), polydata) + normals_gen.ComputePointNormalsOn() + normals_gen.ComputeCellNormalsOn() + normals_gen.SplittingOff() + # normals_gen.FlipNormalsOn() + # normals_gen.ConsistencyOn() + # normals_gen.AutoOrientNormalsOn() + normals_gen.Update() + + vtk_normals = normals_gen.GetOutput().GetPointData().GetNormals() + polydata.GetPointData().SetNormals(vtk_normals)
+ + + +
+[docs] +def get_polymapper_from_polydata(polydata): + """Get vtkPolyDataMapper from a vtkPolyData. + + Parameters + ---------- + polydata : vtkPolyData + + Returns + ------- + poly_mapper : vtkPolyDataMapper + + """ + poly_mapper = set_input(PolyDataMapper(), polydata) + poly_mapper.ScalarVisibilityOn() + poly_mapper.InterpolateScalarsBeforeMappingOn() + poly_mapper.Update() + poly_mapper.StaticOn() + return poly_mapper
+ + + +
+[docs] +def get_actor_from_polymapper(poly_mapper): + """Get actor from a vtkPolyDataMapper. + + Parameters + ---------- + poly_mapper : vtkPolyDataMapper + + Returns + ------- + actor : actor + + """ + actor = Actor() + actor.SetMapper(poly_mapper) + actor.GetProperty().BackfaceCullingOn() + actor.GetProperty().SetInterpolationToPhong() + + return actor
+ + + +
+[docs] +def get_actor_from_polydata(polydata): + """Get actor from a vtkPolyData. + + Parameters + ---------- + polydata : vtkPolyData + + Returns + ------- + actor : actor + + """ + poly_mapper = get_polymapper_from_polydata(polydata) + return get_actor_from_polymapper(poly_mapper)
+ + + +
+[docs] +def get_actor_from_primitive( + vertices, triangles, colors=None, normals=None, backface_culling=True, prim_count=1 +): + """Get actor from a vtkPolyData. + + Parameters + ---------- + vertices : (Mx3) ndarray + XYZ coordinates of the object + triangles: (Nx3) ndarray + Indices into vertices; forms triangular faces. + colors: (Nx3) or (Nx4) ndarray + RGB or RGBA (for opacity) R, G, B and A should be at the range [0, 1] + N is equal to the number of vertices. + normals: (Nx3) ndarray + normals, represented as 2D ndarrays (Nx3) (one per vertex) + backface_culling: bool + culling of polygons based on orientation of normal with respect to + camera. If backface culling is True, polygons facing away from camera + are not drawn. Default: True + prim_count: int, optional + primitives count to be associated with the actor + + Returns + ------- + actor : actor + + """ + # Create a Polydata + pd = PolyData() + set_polydata_vertices(pd, vertices) + set_polydata_triangles(pd, triangles) + set_polydata_primitives_count(pd, prim_count) + if isinstance(colors, np.ndarray): + if len(colors) != len(vertices): + msg = 'Vertices and Colors should have the same size.' + msg += ' Please, update your color array or use the function ' + msg += '``fury.primitive.repeat_primitives`` to normalize your ' + msg += 'color array before calling this function. e.g.' + raise ValueError(msg) + + set_polydata_colors(pd, colors, array_name='colors') + if isinstance(normals, np.ndarray): + set_polydata_normals(pd, normals) + + current_actor = get_actor_from_polydata(pd) + current_actor.GetProperty().SetBackfaceCulling(backface_culling) + return current_actor
+ + + +
+[docs] +def repeat_sources( + centers, + colors, + active_scalars=1.0, + directions=None, + source=None, + vertices=None, + faces=None, + orientation=None, +): + """Transform a vtksource to glyph.""" + if source is None and faces is None: + raise IOError('A source or faces should be defined') + + if np.array(colors).ndim == 1: + colors = np.tile(colors, (len(centers), 1)) + + pts = numpy_to_vtk_points(np.ascontiguousarray(centers)) + cols = numpy_to_vtk_colors(255 * np.ascontiguousarray(colors)) + cols.SetName('colors') + if isinstance(active_scalars, (float, int)): + active_scalars = np.tile(active_scalars, (len(centers), 1)) + if isinstance(active_scalars, np.ndarray): + ascalars = numpy_support.numpy_to_vtk( + np.asarray(active_scalars), deep=True, array_type=VTK_DOUBLE + ) + ascalars.SetName('active_scalars') + + if directions is not None: + directions_fa = numpy_support.numpy_to_vtk( + np.asarray(directions), deep=True, array_type=VTK_DOUBLE + ) + directions_fa.SetName('directions') + + polydata_centers = PolyData() + polydata_geom = PolyData() + + if faces is not None: + set_polydata_vertices(polydata_geom, vertices) + set_polydata_triangles(polydata_geom, faces) + + polydata_centers.SetPoints(pts) + polydata_centers.GetPointData().AddArray(cols) + set_polydata_primitives_count(polydata_centers, len(centers)) + + if directions is not None: + polydata_centers.GetPointData().AddArray(directions_fa) + polydata_centers.GetPointData().SetActiveVectors('directions') + if isinstance(active_scalars, np.ndarray): + polydata_centers.GetPointData().AddArray(ascalars) + polydata_centers.GetPointData().SetActiveScalars('active_scalars') + + glyph = Glyph3D() + if faces is None: + if orientation is not None: + transform = Transform() + transform.SetMatrix(numpy_to_vtk_matrix(orientation)) + rtrans = TransformPolyDataFilter() + rtrans.SetInputConnection(source.GetOutputPort()) + rtrans.SetTransform(transform) + source = rtrans + glyph.SetSourceConnection(source.GetOutputPort()) + else: + glyph.SetSourceData(polydata_geom) + glyph.SetInputData(polydata_centers) + glyph.SetOrient(True) + glyph.SetScaleModeToScaleByScalar() + glyph.SetVectorModeToUseVector() + glyph.Update() + + mapper = PolyDataMapper() + mapper.SetInputData(glyph.GetOutput()) + mapper.SetScalarModeToUsePointFieldData() + mapper.SelectColorArray('colors') + + actor = Actor() + actor.SetMapper(mapper) + return actor
+ + + +
+[docs] +def apply_affine_to_actor(act, affine): + """Apply affine matrix `affine` to the actor `act`. + + Parameters + ---------- + act: Actor + + affine: (4, 4) array-like + Homogeneous affine, for 3D object. + + Returns + ------- + transformed_act: Actor + + """ + act.SetUserMatrix(numpy_to_vtk_matrix(affine)) + return act
+ + + +
+[docs] +def apply_affine(aff, pts): + """Apply affine matrix `aff` to points `pts`. + + Returns result of application of `aff` to the *right* of `pts`. The + coordinate dimension of `pts` should be the last. + For the 3D case, `aff` will be shape (4,4) and `pts` will have final axis + length 3 - maybe it will just be N by 3. The return value is the + transformed points, in this case:: + res = np.dot(aff[:3,:3], pts.T) + aff[:3,3:4] + transformed_pts = res.T + This routine is more general than 3D, in that `aff` can have any shape + (N,N), and `pts` can have any shape, as long as the last dimension is for + the coordinates, and is therefore length N-1. + + Parameters + ---------- + aff : (N, N) array-like + + Homogeneous affine, for 3D points, will be 4 by 4. Contrary to first + appearance, the affine will be applied on the left of `pts`. + pts : (..., N-1) array-like + Points, where the last dimension contains the coordinates of each + point. For 3D, the last dimension will be length 3. + + Returns + ------- + transformed_pts : (..., N-1) array + transformed points + + Notes + ----- + Copied from nibabel to remove dependency. + + Examples + -------- + >>> aff = np.array([[0,2,0,10],[3,0,0,11],[0,0,4,12],[0,0,0,1]]) + >>> pts = np.array([[1,2,3],[2,3,4],[4,5,6],[6,7,8]]) + >>> apply_affine(aff, pts) #doctest: +ELLIPSIS + array([[14, 14, 24], + [16, 17, 28], + [20, 23, 36], + [24, 29, 44]]...) + Just to show that in the simple 3D case, it is equivalent to: + >>> (np.dot(aff[:3,:3], pts.T) + aff[:3,3:4]).T #doctest: +ELLIPSIS + array([[14, 14, 24], + [16, 17, 28], + [20, 23, 36], + [24, 29, 44]]...) + But `pts` can be a more complicated shape: + >>> pts = pts.reshape((2,2,3)) + >>> apply_affine(aff, pts) #doctest: +ELLIPSIS + array([[[14, 14, 24], + [16, 17, 28]], + <BLANKLINE> + [[20, 23, 36], + [24, 29, 44]]]...) + + """ + aff = np.asarray(aff) + pts = np.asarray(pts) + shape = pts.shape + pts = pts.reshape((-1, shape[-1])) + # rzs == rotations, zooms, shears + rzs = aff[:-1, :-1] + trans = aff[:-1, -1] + res = np.dot(pts, rzs.T) + trans[None, :] + return res.reshape(shape)
+ + + +
+[docs] +def asbytes(s): + if isinstance(s, bytes): + return s + return s.encode('latin1')
+ + + +
+[docs] +def vtk_matrix_to_numpy(matrix): + """Convert VTK matrix to numpy array.""" + if matrix is None: + return None + + size = (4, 4) + if isinstance(matrix, Matrix3x3): + size = (3, 3) + + mat = np.zeros(size) + for i in range(mat.shape[0]): + for j in range(mat.shape[1]): + mat[i, j] = matrix.GetElement(i, j) + + return mat
+ + + +
+[docs] +def numpy_to_vtk_matrix(array): + """Convert a numpy array to a VTK matrix.""" + if array is None: + return None + + if array.shape == (4, 4): + matrix = Matrix4x4() + elif array.shape == (3, 3): + matrix = Matrix3x3() + else: + raise ValueError('Invalid matrix shape: {0}'.format(array.shape)) + + for i in range(array.shape[0]): + for j in range(array.shape[1]): + matrix.SetElement(i, j, array[i, j]) + + return matrix
+ + + +
+[docs] +def get_bounding_box_sizes(actor): + """Get the bounding box sizes of an actor.""" + X1, X2, Y1, Y2, Z1, Z2 = actor.GetBounds() + return (X2 - X1, Y2 - Y1, Z2 - Z1)
+ + + +
+[docs] +def get_grid_cells_position(shapes, aspect_ratio=16 / 9.0, dim=None): + """Construct a XY-grid based on the cells content shape. + + This function generates the coordinates of every grid cell. The width and + height of every cell correspond to the largest width and the largest height + respectively. The grid dimensions will automatically be adjusted to respect + the given aspect ratio unless they are explicitly specified. + + The grid follows a row-major order with the top left corner being at + coordinates (0,0,0) and the bottom right corner being at coordinates + (nb_cols*cell_width, -nb_rows*cell_height, 0). Note that the X increases + while the Y decreases. + + Parameters + ---------- + shapes : list of tuple of int + The shape (width, height) of every cell content. + aspect_ratio : float (optional) + Aspect ratio of the grid (width/height). Default: 16:9. + dim : tuple of int (optional) + Dimension (nb_rows, nb_cols) of the grid, if provided. + + Returns + ------- + ndarray + 3D coordinates of every grid cell. + + """ + cell_shape = np.r_[np.max(shapes, axis=0), 0] + cell_aspect_ratio = cell_shape[0] / cell_shape[1] + + count = len(shapes) + if dim is None: + # Compute the number of rows and columns. + n_cols = np.ceil(np.sqrt(count * aspect_ratio / cell_aspect_ratio)) + n_rows = np.ceil(count / n_cols) + else: + n_rows, n_cols = dim + + if n_cols * n_rows < count: + msg = 'Size is too small, it cannot contain at least {} elements.' + raise ValueError(msg.format(count)) + + # Use indexing="xy" so the cells are in row-major (C-order). Also, + # the Y coordinates are negative so the cells are order from top to bottom. + X, Y, Z = np.meshgrid(np.arange(n_cols), -np.arange(n_rows), [0], indexing='xy') + return cell_shape * np.array([X.flatten(), Y.flatten(), Z.flatten()]).T
+ + + +
+[docs] +def shallow_copy(vtk_object): + """Create a shallow copy of a given `vtkObject` object.""" + copy = vtk_object.NewInstance() + copy.ShallowCopy(vtk_object) + return copy
+ + + +
+[docs] +def rotate(actor, rotation=(90, 1, 0, 0)): + """Rotate actor around axis by angle. + + Parameters + ---------- + actor : actor or other prop + rotation : tuple + Rotate with angle w around axis x, y, z. Needs to be provided + in the form (w, x, y, z). + + """ + prop3D = actor + center = np.array(prop3D.GetCenter()) + + oldMatrix = prop3D.GetMatrix() + orig = np.array(prop3D.GetOrigin()) + + newTransform = Transform() + newTransform.PostMultiply() + if prop3D.GetUserMatrix() is not None: + newTransform.SetMatrix(prop3D.GetUserMatrix()) + else: + newTransform.SetMatrix(oldMatrix) + + newTransform.Translate(*(-center)) + newTransform.RotateWXYZ(*rotation) + newTransform.Translate(*center) + + # now try to get the composite of translate, rotate, and scale + newTransform.Translate(*(-orig)) + newTransform.PreMultiply() + newTransform.Translate(*orig) + + if prop3D.GetUserMatrix() is not None: + newTransform.GetMatrix(prop3D.GetUserMatrix()) + else: + prop3D.SetPosition(newTransform.GetPosition()) + prop3D.SetScale(newTransform.GetScale()) + prop3D.SetOrientation(newTransform.GetOrientation())
+ + + +
+[docs] +def rgb_to_vtk(data): + """RGB or RGBA images to VTK arrays. + + Parameters + ---------- + data : ndarray + Shape can be (X, Y, 3) or (X, Y, 4) + + Returns + ------- + vtkImageData + + """ + grid = ImageData() + grid.SetDimensions(data.shape[1], data.shape[0], 1) + nd = data.shape[-1] + vtkarr = numpy_support.numpy_to_vtk( + np.flip(data.swapaxes(0, 1), axis=1).reshape((-1, nd), order='F') + ) + vtkarr.SetName('Image') + grid.GetPointData().AddArray(vtkarr) + grid.GetPointData().SetActiveScalars('Image') + grid.GetPointData().Update() + return grid
+ + + +
+[docs] +def normalize_v3(arr): + """Normalize a numpy array of 3 component vectors shape=(N, 3). + + Parameters + ---------- + array : ndarray + Shape (N, 3) + + Returns + ------- + norm_array + + """ + lens = np.sqrt(arr[:, 0] ** 2 + arr[:, 1] ** 2 + arr[:, 2] ** 2) + arr[:, 0] /= lens + arr[:, 1] /= lens + arr[:, 2] /= lens + return arr
+ + + +
+[docs] +def normals_from_v_f(vertices, faces): + """Calculate normals from vertices and faces. + + Parameters + ---------- + verices : ndarray + faces : ndarray + + Returns + ------- + normals : ndarray + Shape same as vertices + + """ + norm = np.zeros(vertices.shape, dtype=vertices.dtype) + tris = vertices[faces] + n = np.cross(tris[::, 1] - tris[::, 0], tris[::, 2] - tris[::, 0]) + normalize_v3(n) + norm[faces[:, 0]] += n + norm[faces[:, 1]] += n + norm[faces[:, 2]] += n + normalize_v3(norm) + return norm
+ + + +
+[docs] +def tangents_from_direction_of_anisotropy(normals, direction): + """Calculate tangents from normals and a 3D vector representing the + direction of anisotropy. + + Parameters + ---------- + normals : normals, represented as 2D ndarrays (Nx3) (one per vertex) + direction : tuple (3,) or array (3,) + + Returns + ------- + output : array (N, 3) + Tangents, represented as 2D ndarrays (Nx3). + + """ + tangents = np.cross(normals, direction) + binormals = normalize_v3(np.cross(normals, tangents)) + return normalize_v3(np.cross(normals, binormals))
+ + + +
+[docs] +def triangle_order(vertices, faces): + """Determine the winding order of a given set of vertices and a triangle. + + Parameters + ---------- + vertices : ndarray + array of vertices making up a shape + faces : ndarray + array of triangles + + Returns + ------- + order : int + If the order is counter clockwise (CCW), returns True. + Otherwise, returns False. + + """ + v1 = vertices[faces[0]] + v2 = vertices[faces[1]] + v3 = vertices[faces[2]] + + # https://stackoverflow.com/questions/40454789/computing-face-normals-and-winding + m_orient = np.ones((4, 4)) + m_orient[0, :3] = v1 + m_orient[1, :3] = v2 + m_orient[2, :3] = v3 + m_orient[3, :3] = 0 + + val = np.linalg.det(m_orient) + + return bool(val > 0)
+ + + +
+[docs] +def change_vertices_order(triangle): + """Change the vertices order of a given triangle. + + Parameters + ---------- + triangle : ndarray, shape(1, 3) + array of 3 vertices making up a triangle + + Returns + ------- + new_triangle : ndarray, shape(1, 3) + new array of vertices making up a triangle in the opposite winding + order of the given parameter + + """ + return np.array([triangle[2], triangle[1], triangle[0]])
+ + + +
+[docs] +def fix_winding_order(vertices, triangles, clockwise=False): + """Return corrected triangles. + + Given an ordering of the triangle's three vertices, a triangle can appear + to have a clockwise winding or counter-clockwise winding. + Clockwise means that the three vertices, in order, rotate clockwise around + the triangle's center. + + Parameters + ---------- + vertices : ndarray + array of vertices corresponding to a shape + triangles : ndarray + array of triangles corresponding to a shape + clockwise : bool + triangle order type: clockwise (default) or counter-clockwise. + + Returns + ------- + corrected_triangles : ndarray + The corrected order of the vert parameter + + """ + corrected_triangles = triangles.copy() + desired_order = clockwise + for nb, face in enumerate(triangles): + current_order = triangle_order(vertices, face) + if desired_order != current_order: + corrected_triangles[nb] = change_vertices_order(face) + return corrected_triangles
+ + + +
+[docs] +def vertices_from_actor(actor, as_vtk=False): + """Access to vertices from actor. + + Parameters + ---------- + actor : actor + as_vtk: bool, optional + by default, ndarray is returned. + + Returns + ------- + vertices : ndarray + + """ + vtk_array = actor.GetMapper().GetInput().GetPoints().GetData() + if as_vtk: + return vtk_array + + return numpy_support.vtk_to_numpy(vtk_array)
+ + + +
+[docs] +def colors_from_actor(actor, array_name='colors', as_vtk=False): + """Access colors from actor which uses polydata. + + Parameters + ---------- + actor : actor + array_name: str + as_vtk: bool, optional + by default, numpy array is returned. + + Returns + ------- + output : array (N, 3) + Colors + + """ + return array_from_actor(actor, array_name=array_name, as_vtk=as_vtk)
+ + + +
+[docs] +def normals_from_actor(act): + """Access normals from actor which uses polydata. + + Parameters + ---------- + act : actor + + Returns + ------- + output : array (N, 3) + Normals + + """ + polydata = act.GetMapper().GetInput() + return get_polydata_normals(polydata)
+ + + +
+[docs] +def tangents_from_actor(act): + """Access tangents from actor which uses polydata. + + Parameters + ---------- + act : actor + + Returns + ------- + output : array (N, 3) + Tangents + + """ + polydata = act.GetMapper().GetInput() + return get_polydata_tangents(polydata)
+ + + +
+[docs] +def array_from_actor(actor, array_name, as_vtk=False): + """Access array from actor which uses polydata. + + Parameters + ---------- + actor : actor + array_name: str + as_vtk_type: bool, optional + by default, ndarray is returned. + + Returns + ------- + output : array (N, 3) + + """ + vtk_array = actor.GetMapper().GetInput().GetPointData().GetArray(array_name) + if vtk_array is None: + return None + if as_vtk: + return vtk_array + + return numpy_support.vtk_to_numpy(vtk_array)
+ + + +
+[docs] +def normals_to_actor(act, normals): + """Set normals to actor which uses polydata. + + Parameters + ---------- + act : actor + normals : normals, represented as 2D ndarrays (Nx3) (one per vertex) + + Returns + ------- + actor + + """ + polydata = act.GetMapper().GetInput() + set_polydata_normals(polydata, normals) + return act
+ + + +
+[docs] +def tangents_to_actor(act, tangents): + """Set tangents to actor which uses polydata. + + Parameters + ---------- + act : actor + tangents : tangents, represented as 2D ndarrays (Nx3) (one per vertex) + + """ + polydata = act.GetMapper().GetInput() + set_polydata_tangents(polydata, tangents) + return act
+ + + +
+[docs] +def compute_bounds(actor): + """Compute Bounds of actor. + + Parameters + ---------- + actor : actor + + """ + actor.GetMapper().GetInput().ComputeBounds()
+ + + +
+[docs] +def update_actor(actor, all_arrays=True): + """Update actor. + + Parameters + ---------- + actor : actor + all_arrays: bool, optional + if False, only vertices are updated + if True, all arrays associated to the actor are updated + Default: True + + """ + pd = actor.GetMapper().GetInput() + pd.GetPoints().GetData().Modified() + if all_arrays: + nb_array = pd.GetPointData().GetNumberOfArrays() + for i in range(nb_array): + pd.GetPointData().GetArray(i).Modified()
+ + + +
+[docs] +def get_bounds(actor): + """Return Bounds of actor. + + Parameters + ---------- + actor : actor + + Returns + ------- + vertices : ndarray + + """ + return actor.GetMapper().GetInput().GetBounds()
+ + + +
+[docs] +def represent_actor_as_wireframe(actor): + """Returns the actor wireframe. + + Parameters + ---------- + actor : actor + + Returns + ------- + actor : actor + + """ + return actor.GetProperty().SetRepresentationToWireframe()
+ + + +
+[docs] +def update_surface_actor_colors(actor, colors): + """Update colors of a surface actor. + + Parameters + ---------- + actor : surface actor + colors : ndarray of shape (N, 3) having colors. The colors should be in the + range [0, 1]. + + """ + actor.GetMapper().GetInput().GetPointData().SetScalars( + numpy_to_vtk_colors(255 * colors) + )
+ + + +
+[docs] +def color_check(pts_len, colors=None): + """Returns a VTK scalar array containing colors information for each one of + the points according to the policy defined by the parameter colors. + + Parameters + ---------- + pts_len : int + length of points ndarray + colors : None or tuple (3D or 4D) or array/ndarray (N, 3 or 4) + If None a predefined color is used for each point. + If a tuple of color is used. Then all points will have the same color. + If an array (N, 3 or 4) is given, where N is equal to the number of + points. Then every point is colored with a different RGB(A) color. + + Returns + ------- + color_array : vtkDataArray + vtk scalar array with name 'colors'. + global_opacity : float + returns 1 if the colors array doesn't contain opacity otherwise -1. + If colors array has 4 dimensions, it checks values of the fourth + dimension. If the value is the same, then assign it to global_opacity. + + """ + global_opacity = 1 + if colors is None: + # Automatic RGB colors + colors = np.asarray((1, 1, 1)) + color_array = numpy_to_vtk_colors(np.tile(255 * colors, (pts_len, 1))) + elif type(colors) is tuple: + global_opacity = 1 if len(colors) == 3 else colors[3] + colors = np.asarray(colors) + color_array = numpy_to_vtk_colors(np.tile(255 * colors, (pts_len, 1))) + elif isinstance(colors, np.ndarray): + colors = np.asarray(colors) + if colors.shape[1] == 4: + opacities = np.unique(colors[:, 3]) + global_opacity = opacities[0] if len(opacities) == 1 else -1 + color_array = numpy_to_vtk_colors(255 * colors) + color_array.SetName('colors') + + return color_array, global_opacity
+ + + +
+[docs] +def is_ui(actor): + """Method to check if the passed actor is `UI` or `vtkProp3D` + + Parameters + ---------- + actor: :class: `UI` or `vtkProp3D` + actor that is to be checked + + """ + return all([hasattr(actor, attr) for attr in ['add_to_scene', '_setup']])
+ + + +
+[docs] +def set_actor_origin(actor, center=None): + """Change the origin of an actor to a custom position. + + Parameters + ---------- + actor: Actor + The actor object to change origin for. + center: ndarray, optional, default: None + The new center position. If `None`, the origin will be set to the mean + of the actor's vertices. + + """ + vertices = vertices_from_actor(actor) + if center is None: + center = np.mean(vertices) + vertices[:] -= center + update_actor(actor)
+ +
+
+ + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/_modules/fury/window.html b/v0.10.x/_modules/fury/window.html new file mode 100644 index 000000000..0197ad1ad --- /dev/null +++ b/v0.10.x/_modules/fury/window.html @@ -0,0 +1,2190 @@ + + + + + + + fury.window — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +

Source code for fury.window

+# -*- coding: utf-8 -*-
+import gzip
+import time
+from tempfile import TemporaryDirectory as InTemporaryDirectory
+from threading import Lock
+from warnings import warn
+
+import numpy as np
+from scipy import ndimage
+
+import fury.animation as anim
+from fury import __version__ as fury_version
+from fury.interactor import CustomInteractorStyle
+from fury.io import load_image, save_image
+from fury.lib import (
+    Actor2D,
+    Command,
+    InteractorEventRecorder,
+    InteractorStyleImage,
+    InteractorStyleTrackballCamera,
+    OpenGLRenderer,
+    RenderLargeImage,
+    RenderWindow,
+    RenderWindowInteractor,
+    Skybox,
+    Volume,
+    WindowToImageFilter,
+    colors,
+    numpy_support,
+)
+from fury.shaders.base import GL_NUMBERS as _GL
+from fury.utils import asbytes
+
+try:
+    basestring
+except NameError:
+    basestring = str
+
+
+
+[docs] +class Scene(OpenGLRenderer): + """Your scene class. + + This is an important object that is responsible for preparing objects + e.g. actors and volumes for rendering. This is a more pythonic version + of ``vtkRenderer`` providing simple methods for adding and removing actors + but also it provides access to all the functionality + available in ``vtkRenderer`` if necessary. + """ + +
+[docs] + def __init__(self, background=(0, 0, 0), skybox=None): + self.__skybox = skybox + self.__skybox_actor = None + if skybox: + self.AutomaticLightCreationOff() + self.UseImageBasedLightingOn() + self.UseSphericalHarmonicsOff() + self.SetEnvironmentTexture(self.__skybox) + self.skybox()
+ + +
+[docs] + def background(self, color): + """Set a background color.""" + self.SetBackground(color)
+ + +
+[docs] + def skybox(self, visible=True, gamma_correct=True): + """Show or hide the skybox. + + Parameters + ---------- + visible : bool + Whether to show the skybox or not. + gamma_correct : bool + Whether to apply gamma correction to the skybox or not. + + """ + if self.__skybox: + if visible: + if self.__skybox_actor is None: + self.__skybox_actor = Skybox() + self.__skybox_actor.SetTexture(self.__skybox) + if gamma_correct: + self.__skybox_actor.GammaCorrectOn() + self.add(self.__skybox_actor) + else: + self.rm(self.__skybox_actor) + else: + warn('Scene created without a skybox. Nothing to show or hide.')
+ + +
+[docs] + def add(self, *actors): + """Add an actor to the scene.""" + for actor in actors: + if isinstance(actor, Volume): + self.AddVolume(actor) + elif isinstance(actor, Actor2D): + self.AddActor2D(actor) + elif hasattr(actor, 'add_to_scene'): + actor.add_to_scene(self) + else: + self.AddActor(actor)
+ + +
+[docs] + def rm(self, *actors): + """Remove more than once actors at once.""" + for actor in actors: + self.RemoveActor(actor)
+ + +
+[docs] + def clear(self): + """Remove all actors from the scene.""" + self.RemoveAllViewProps()
+ + +
+[docs] + def rm_all(self): + """Remove all actors from the scene.""" + self.RemoveAllViewProps()
+ + +
+[docs] + def projection(self, proj_type='perspective'): + """Decide between parallel or perspective projection. + + Parameters + ---------- + proj_type : str + Can be 'parallel' or 'perspective' (default). + + """ + if proj_type == 'parallel': + self.GetActiveCamera().ParallelProjectionOn() + else: + self.GetActiveCamera().ParallelProjectionOff()
+ + +
+[docs] + def reset_camera(self): + """Reset the camera to an automatic position given by the engine.""" + self.ResetCamera()
+ + +
+[docs] + def reset_camera_tight(self, margin_factor=1.02): + """Resets camera so the content fit tightly within the window. + + Parameters + ---------- + margin_factor : float (optional) + Margin added around the content. Default: 1.02. + + """ + self.ComputeAspect() + cam = self.GetActiveCamera() + aspect = self.GetAspect() + + X1, X2, Y1, Y2, Z1, Z2 = self.ComputeVisiblePropBounds() + width, height = X2 - X1, Y2 - Y1 + center = np.array((X1 + width / 2.0, Y1 + height / 2.0, 0)) + + angle = np.pi * cam.GetViewAngle() / 180.0 + dist = max(width / aspect[0], height) / np.sin(angle / 2.0) / 2.0 + position = center + np.array((0, 0, dist * margin_factor)) + + cam.SetViewUp(0, 1, 0) + cam.SetPosition(*position) + cam.SetFocalPoint(*center) + self.ResetCameraClippingRange(X1, X2, Y1, Y2, Z1, Z2) + + parallelScale = max(width / aspect[0], height) / 2.0 + cam.SetParallelScale(parallelScale * margin_factor)
+ + +
+[docs] + def reset_clipping_range(self): + """Reset the camera to an automatic position given by the engine.""" + self.ResetCameraClippingRange()
+ + +
+[docs] + def camera(self): + """Return the camera object.""" + return self.GetActiveCamera()
+ + +
+[docs] + def get_camera(self): + """Return Camera information: Position, Focal Point, View Up.""" + cam = self.GetActiveCamera() + return cam.GetPosition(), cam.GetFocalPoint(), cam.GetViewUp()
+ + +
+[docs] + def camera_info(self): + """Return Camera information.""" + cam = self.camera() + print('# Active Camera') + print(' Position (%.2f, %.2f, %.2f)' % cam.GetPosition()) + print(' Focal Point (%.2f, %.2f, %.2f)' % cam.GetFocalPoint()) + print(' View Up (%.2f, %.2f, %.2f)' % cam.GetViewUp())
+ + +
+[docs] + def set_camera(self, position=None, focal_point=None, view_up=None): + """Set up camera position / Focal Point / View Up.""" + if position is not None: + self.GetActiveCamera().SetPosition(*position) + if focal_point is not None: + self.GetActiveCamera().SetFocalPoint(*focal_point) + if view_up is not None: + self.GetActiveCamera().SetViewUp(*view_up) + self.ResetCameraClippingRange()
+ + +
+[docs] + def size(self): + """Scene size.""" + return self.GetSize()
+ + +
+[docs] + def zoom(self, value): + """Rescale scene's camera. + + In perspective mode, decrease the view angle by the specified + factor. In parallel mode, decrease the parallel scale by the specified + factor. A value greater than 1 is a zoom-in, a value less than 1 is a + zoom-out. + + """ + self.GetActiveCamera().Zoom(value)
+ + +
+[docs] + def azimuth(self, angle): + """Rotate scene's camera. + + Rotate the camera about the view up vector centered at the focal + point. Note that the view up vector is whatever was set via SetViewUp, + and is not necessarily perpendicular to the direction of projection. + The result is a horizontal rotation of the camera. + + """ + self.GetActiveCamera().Azimuth(angle)
+ + +
+[docs] + def yaw(self, angle): + """Yaw scene's camera. + + Rotate the focal point about the view up vector, using the camera's + position as the center of rotation. Note that the view up vector is + whatever was set via SetViewUp, and is not necessarily perpendicular + to the direction of projection. The result is a horizontal rotation of + the scene. + + """ + self.GetActiveCamera().Yaw(angle)
+ + +
+[docs] + def elevation(self, angle): + """Elevate scene's camera. + + Rotate the camera about the cross product of the negative of the + direction of projection and the view up vector, using the focal point + as the center of rotation. The result is a vertical rotation of the + scene. + """ + self.GetActiveCamera().Elevation(angle)
+ + +
+[docs] + def pitch(self, angle): + """Pitch scene's camera. + + Rotate the focal point about the cross product of the view up + vector and the direction of projection, using the camera's position as + the center of rotation. The result is a vertical rotation of the + camera. + """ + self.GetActiveCamera().Pitch(angle)
+ + +
+[docs] + def roll(self, angle): + """Roll scene's camera. + + Rotate the camera about the direction of projection. This will + spin the camera about its axis. + """ + self.GetActiveCamera().Roll(angle)
+ + +
+[docs] + def dolly(self, value): + """Dolly In/Out scene's camera. + + Divide the camera's distance from the focal point by the given + dolly value. Use a value greater than one to dolly-in toward the focal + point, and use a value less than one to dolly-out away from the focal + point. + """ + self.GetActiveCamera().Dolly(value)
+ + +
+[docs] + def camera_direction(self): + """Get camera direction. + + Get the vector in the direction from the camera position to the + focal point. This is usually the opposite of the ViewPlaneNormal, the + vector perpendicular to the screen, unless the view is oblique. + """ + return self.GetActiveCamera().GetDirectionOfProjection()
+ + + @property + def last_render_time(self): + """Returns the last render time in seconds.""" + return self.GetLastRenderTimeInSeconds() + +
+[docs] + def fxaa_on(self): + self.SetUseFXAA(True)
+ + +
+[docs] + def fxaa_off(self): + self.SetUseFXAA(False)
+
+ + + +
+[docs] +class ShowManager: + """Class interface between the scene, the window and the interactor.""" + +
+[docs] + def __init__( + self, + scene=None, + title='FURY', + size=(300, 300), + png_magnify=1, + reset_camera=True, + order_transparent=False, + interactor_style='custom', + stereo='off', + multi_samples=8, + max_peels=4, + occlusion_ratio=0.0, + ): + """Manage the visualization pipeline. + + Parameters + ---------- + scene : Scene() or vtkRenderer() + The scene that holds all the actors. + title : string + A string for the window title bar. + size : (int, int) + ``(width, height)`` of the window. Default is (300, 300). + png_magnify : int + Number of times to magnify the screenshot. This can be used to save + high resolution screenshots when pressing 's' inside the window. + reset_camera : bool + Default is True. You can change this option to False if you want to + keep the camera as set before calling this function. + order_transparent : bool + True is useful when you want to order transparent + actors according to their relative position to the camera. The + default option which is False will order the actors according to + the order of their addition to the Scene(). + interactor_style : str or vtkInteractorStyle + If str then if 'trackball' then vtkInteractorStyleTrackballCamera() + is used, if 'image' then vtkInteractorStyleImage() is used (no + rotation) or if 'custom' then CustomInteractorStyle is used. + Otherwise you can input your own interactor style. + stereo: string + Set the stereo type. Default is 'off'. Other types include: + + * 'opengl': OpenGL frame-sequential stereo. Referred to as + 'CrystalEyes' by VTK. + * 'anaglyph': For use with red/blue glasses. See VTK docs to + use different colors. + * 'interlaced': Line interlaced. + * 'checkerboard': Checkerboard interlaced. + * 'left': Left eye only. + * 'right': Right eye only. + * 'horizontal': Side-by-side. + + multi_samples : int + Number of samples for anti-aliazing (Default 8). + For no anti-aliasing use 0. + max_peels : int + Maximum number of peels for depth peeling (Default 4). + occlusion_ratio : float + Occlusion ration for depth peeling (Default 0 - exact image). + + Attributes + ---------- + scene : Scene() or vtkRenderer() + iren : vtkRenderWindowInteractor() + style : vtkInteractorStyle() + window : vtkRenderWindow() + + Examples + -------- + >>> from fury import actor, window + >>> scene = window.Scene() + >>> scene.add(actor.axes()) + >>> showm = window.ShowManager(scene) + >>> # showm.render() + >>> # showm.start() + + """ + if scene is None: + scene = Scene() + self.scene = scene + self.title = title + self.size = size + self.png_magnify = png_magnify + self.reset_camera = reset_camera + self.order_transparent = order_transparent + self.interactor_style = interactor_style + self.stereo = stereo + self.timers = [] + self.mutex = Lock() + self._fps = 0 + self._last_render_time = 0 + + if self.reset_camera: + self.scene.ResetCamera() + + self.window = RenderWindow() + + if self.stereo.lower() != 'off': + enable_stereo(self.window, self.stereo) + + self.window.AddRenderer(scene) + + self.window.SetSize(size[0], size[1]) + + if self.order_transparent: + occlusion_ratio = occlusion_ratio or 0.1 + antialiasing( + self.scene, + self.window, + multi_samples=multi_samples, + max_peels=max_peels, + occlusion_ratio=occlusion_ratio, + ) + + if self.interactor_style == 'image': + self.style = InteractorStyleImage() + elif self.interactor_style == 'trackball': + self.style = InteractorStyleTrackballCamera() + elif self.interactor_style == 'custom': + self.style = CustomInteractorStyle() + else: + self.style = interactor_style + + self.iren = RenderWindowInteractor() + self.style.SetCurrentRenderer(self.scene) + # Hack: below, we explicitly call the Python version of SetInteractor. + self.style.SetInteractor(self.iren) + self.iren.SetInteractorStyle(self.style) + self.iren.SetRenderWindow(self.window) + self._timelines = [] + self._animations = [] + self._animation_callback = None
+ + +
+[docs] + def initialize(self): + """Initialize interaction.""" + self.iren.Initialize()
+ + + @property + def timelines(self): + """Return a list of Timelines that were added to the ShowManager. + + Returns + ------- + list[Timeline]: + List of Timelines. + + """ + return self._timelines + + @property + def animations(self): + """Return a list of Animations that were added to the ShowManager. + + Returns + ------- + list[Animation]: + List of Animations. + + """ + return self._animations + +
+[docs] + def add_animation(self, animation): + """Add an Animation or a Timeline to the ShowManager. + + Adding an Animation or a Timeline to the ShowManager ensures that it + gets added to the scene, gets updated and rendered without any extra + code. + + Parameters + ---------- + animation : Animation or Timeline + The Animation or Timeline to be added to the ShowManager. + + """ + animation.add_to_scene(self.scene) + if isinstance(animation, anim.Animation): + if animation in self._animations: + return + self._animations.append(animation) + elif isinstance(animation, anim.Timeline): + if animation in self._timelines: + return + self._timelines.append(animation) + + if self._animation_callback is not None: + return + + def animation_cbk(_obj, _event): + [tl.update() for tl in self._timelines] + [anim.update_animation() for anim in self._animations] + self.render() + + self._animation_callback = self.add_timer_callback(True, 10, animation_cbk)
+ + +
+[docs] + def remove_animation(self, animation): + """Remove an Animation or a Timeline from the ShowManager. + + Animation will be removed from the Scene as well as from the + ShowManager. + + Parameters + ---------- + animation : Animation or Timeline + The Timeline to be removed. + + """ + if animation in self.timelines or animation in self.animations: + animation.remove_from_scene(self.scene) + if isinstance(animation, anim.Animation): + self._animations.remove(animation) + elif isinstance(animation, anim.Timeline): + self._timelines.remove(animation) + if not (len(self.timelines) or len(self.animations)): + self.iren.DestroyTimer(self._animation_callback) + self._animation_callback = None
+ + +
+[docs] + def render(self): + """Render only once.""" + self.window.Render() + # calculate the FPS + self._fps = 1.0 / (time.perf_counter() - self._last_render_time) + self._last_render_time = time.perf_counter()
+ + +
+[docs] + def is_done(self): + """Check if show manager is done.""" + try: + return self.iren.GetDone() + except AttributeError: + return True
+ + +
+[docs] + def start(self, multithreaded=False, desired_fps=60): + """Start interaction. + + Parameters + ---------- + multithreaded : bool + Whether to use multithreading. (Default False) + desired_fps : int + Desired frames per second when using multithreading is enabled. + (Default 60) + + """ + try: + if self.title.upper() == 'FURY': + self.window.SetWindowName(self.title + ' ' + fury_version) + else: + self.window.SetWindowName(self.title) + if multithreaded: + while self.iren.GetDone() is False: + start_time = time.perf_counter() + self.lock() + self.window.MakeCurrent() + self.iren.ProcessEvents() # Check if we can really do that + self.window.Render() + release_context(self.window) + self.release_lock() + end_time = time.perf_counter() + # throttle to 60fps to avoid busy wait + time_per_frame = 1.0 / desired_fps + if end_time - start_time < time_per_frame: + time.sleep(time_per_frame - (end_time - start_time)) + else: + self.render() + self.iren.Start() + + except AttributeError: + self.__init__( + self.scene, + self.title, + size=self.size, + png_magnify=self.png_magnify, + reset_camera=self.reset_camera, + order_transparent=self.order_transparent, + interactor_style=self.interactor_style, + ) + self.render() + if self.title.upper() == 'FURY': + self.window.SetWindowName(self.title + ' ' + fury_version) + else: + self.window.SetWindowName(self.title) + self.iren.Start() + + self.window.RemoveRenderer(self.scene) + self.scene.SetRenderWindow(None) + self.window.Finalize() + del self.iren + del self.window
+ + +
+[docs] + def lock(self): + """Lock the render window.""" + self.mutex.acquire()
+ + +
+[docs] + def release_lock(self): + """Release the lock of the render window.""" + self.mutex.release()
+ + +
+[docs] + def lock_current(self): + """Lock the render window and acquire the current context and + check if the lock was successfully acquired. + + Returns + ------- + successful : bool + Returns if the lock was acquired. + + """ + if self.is_done(): + return False + if not hasattr(self, 'window'): + return False + try: + self.lock() + self.window.MakeCurrent() + return True + except AttributeError: + return False
+ + +
+[docs] + def release_current(self): + """Release the window context and lock of the render window.""" + release_context(self.window) + self.release_lock()
+ + +
+[docs] + def wait(self): + """Wait for thread to finish.""" + if self.thread: + self.thread.join()
+ + + @property + def frame_rate(self): + """Returns number of frames per second.""" + return self._fps + +
+[docs] + def record_events(self): + """Record events during the interaction. + + The recording is represented as a list of VTK events that happened + during the interaction. The recorded events are then returned. + + Returns + ------- + events : str + Recorded events (one per line). + + Notes + ----- + Since VTK only allows recording events to a file, we use a + temporary file from which we then read the events. + + """ + with InTemporaryDirectory(): + filename = 'recorded_events.log' + recorder = InteractorEventRecorder() + recorder.SetInteractor(self.iren) + recorder.SetFileName(filename) + + def _stop_recording_and_close(_obj, _evt): + if recorder: + recorder.Stop() + self.iren.TerminateApp() + + self.iren.AddObserver('ExitEvent', _stop_recording_and_close) + + recorder.EnabledOn() + recorder.Record() + + self.render() + self.iren.Start() + # Deleting this object is the unique way + # to close the file. + recorder = None + # Retrieved recorded events. + with open(filename, 'r') as f: + events = f.read() + return events
+ + +
+[docs] + def record_events_to_file(self, filename='record.log'): + """Record events during the interaction. + + The recording is represented as a list of VTK events + that happened during the interaction. The recording is + going to be saved into `filename`. + + Parameters + ---------- + filename : str + Name of the file that will contain the recording (.log|.log.gz). + + """ + events = self.record_events() + + # Compress file if needed + if filename.endswith('.gz'): + with gzip.open(filename, 'wb') as fgz: + fgz.write(asbytes(events)) + else: + with open(filename, 'w') as f: + f.write(events)
+ + +
+[docs] + def play_events(self, events): + """Play recorded events of a past interaction. + + The VTK events that happened during the recorded interaction will be + played back. + + Parameters + ---------- + events : str + Recorded events (one per line). + + """ + recorder = InteractorEventRecorder() + recorder.SetInteractor(self.iren) + + recorder.SetInputString(events) + recorder.ReadFromInputStringOn() + self.initialize() + # self.render() + recorder.Play() + + # Finalize seems very important otherwise + # the recording window will not close. + self.window.RemoveRenderer(self.scene) + self.scene.SetRenderWindow(None) + self.window.Finalize() + self.exit()
+ + + # print('After Finalize and Exit') + + # del self.iren + # del self.window + +
+[docs] + def play_events_from_file(self, filename): + """Play recorded events of a past interaction. + + The VTK events that happened during the recorded interaction will be + played back from `filename`. + + Parameters + ---------- + filename : str + Name of the file containing the recorded events (.log|.log.gz). + + """ + # Uncompress file if needed. + if filename.endswith('.gz'): + with gzip.open(filename, 'r') as f: + events = f.read() + else: + with open(filename) as f: + events = f.read() + + self.play_events(events)
+ + +
+[docs] + def add_window_callback(self, win_callback, event=Command.ModifiedEvent): + """Add window callbacks.""" + self.window.AddObserver(event, win_callback) + self.window.Render()
+ + +
+[docs] + def add_timer_callback(self, repeat, duration, timer_callback): + if not self.iren.GetInitialized(): + self.initialize() + self.iren.AddObserver('TimerEvent', timer_callback) + + if repeat: + timer_id = self.iren.CreateRepeatingTimer(duration) + else: + timer_id = self.iren.CreateOneShotTimer(duration) + self.timers.append(timer_id) + return timer_id
+ + +
+[docs] + def add_iren_callback(self, iren_callback, event='MouseMoveEvent'): + if not self.iren.GetInitialized(): + self.initialize() + self.iren.AddObserver(event, iren_callback)
+ + +
+[docs] + def destroy_timer(self, timer_id): + self.iren.DestroyTimer(timer_id) + del self.timers[self.timers.index(timer_id)]
+ + +
+[docs] + def destroy_timers(self): + for timer_id in self.timers: + self.destroy_timer(timer_id)
+ + +
+[docs] + def exit(self): + """Close window and terminate interactor.""" + # if is_osx and self.timers: + # OSX seems to not destroy correctly timers + # segfault 11 appears sometimes if we do not do it manually. + # self.iren.GetRenderWindow().Finalize() + self.iren.TerminateApp() + self.destroy_timers() + self.timers.clear()
+ + +
+[docs] + def save_screenshot(self, fname, magnification=1, size=None, stereo=None): + """Save a screenshot of the current window in the specified filename. + + Parameters + ---------- + fname : str or None + File name where to save the screenshot. + magnification : int, optional + Applies a magnification factor to the scene before taking the + screenshot which improves the quality. A value greater than 1 + increases the quality of the image. However, the output size will + be larger. For example, 200x200 image with magnification of 2 will + result in a 400x400 image. Default is 1. + size : tuple of 2 ints, optional + Size of the output image in pixels. If None, the size of the scene + will be used. If magnification > 1, then the size will be + determined by the magnification factor. Default is None. + stereo : str, optional + Set the type of stereo for the screenshot. Supported values are: + + * 'opengl': OpenGL frame-sequential stereo. Referred to as + 'CrystalEyes' by VTK. + * 'anaglyph': For use with red/blue glasses. See VTK docs to + use different colors. + * 'interlaced': Line interlaced. + * 'checkerboard': Checkerboard interlaced. + * 'left': Left eye only. + * 'right': Right eye only. + * 'horizontal': Side-by-side. + + """ + if size is None: + size = self.size + if stereo is None: + stereo = self.stereo.lower() + + record( + scene=self.scene, + out_path=fname, + magnification=magnification, + size=size, + stereo=stereo, + )
+
+ + + +
+[docs] +def show( + scene, + title='FURY', + size=(300, 300), + png_magnify=1, + reset_camera=True, + order_transparent=False, + stereo='off', + multi_samples=8, + max_peels=4, + occlusion_ratio=0.0, +): + """Show window with current scene. + + Parameters + ---------- + scene : Scene() or vtkRenderer() + The scene that holds all the actors. + title : string + A string for the window title bar. Default is FURY and current version. + size : (int, int) + ``(width, height)`` of the window. Default is (300, 300). + png_magnify : int + Number of times to magnify the screenshot. Default is 1. This can be + used to save high resolution screenshots when pressing 's' inside the + window. + reset_camera : bool + Default is True. You can change this option to False if you want to + keep the camera as set before calling this function. + order_transparent : bool + True is useful when you want to order transparent + actors according to their relative position to the camera. The default + option which is False will order the actors according to the order of + their addition to the Scene(). + stereo : string + Set the stereo type. Default is 'off'. Other types include: + + * 'opengl': OpenGL frame-sequential stereo. Referred to as + 'CrystalEyes' by VTK. + * 'anaglyph': For use with red/blue glasses. See VTK docs to + use different colors. + * 'interlaced': Line interlaced. + * 'checkerboard': Checkerboard interlaced. + * 'left': Left eye only. + * 'right': Right eye only. + * 'horizontal': Side-by-side. + + multi_samples : int + Number of samples for anti-aliazing (Default 8). + For no anti-aliasing use 0. + max_peels : int + Maximum number of peels for depth peeling (Default 4). + occlusion_ratio : float + Occlusion ration for depth peeling (Default 0 - exact image). + + Examples + -------- + >>> import numpy as np + >>> from fury import window, actor + >>> r = window.Scene() + >>> lines=[np.random.rand(10,3),np.random.rand(20,3)] + >>> colors=np.array([[0.2,0.2,0.2],[0.8,0.8,0.8]]) + >>> c=actor.line(lines,colors) + >>> r.add(c) + >>> l=actor.label(text="Hello") + >>> r.add(l) + >>> #window.show(r) + + See Also + -------- + fury.window.record + fury.window.snapshot + + """ + show_manager = ShowManager( + scene, + title, + size, + png_magnify, + reset_camera, + order_transparent, + stereo=stereo, + multi_samples=multi_samples, + max_peels=max_peels, + occlusion_ratio=occlusion_ratio, + ) + show_manager.render() + show_manager.start()
+ + + +
+[docs] +def record( + scene=None, + cam_pos=None, + cam_focal=None, + cam_view=None, + out_path=None, + path_numbering=False, + n_frames=1, + az_ang=10, + magnification=1, + size=(300, 300), + reset_camera=True, + screen_clip=False, + stereo='off', + verbose=False, +): + """Record a video of your scene. + + Records a video as a series of ``.png`` files of your scene by rotating the + azimuth angle az_angle in every frame. + + Parameters + ---------- + scene : Scene() or vtkRenderer() object + Scene instance + cam_pos : None or sequence (3,), optional + Camera's position. If None then default camera's position is used. + cam_focal : None or sequence (3,), optional + Camera's focal point. If None then default camera's focal point is + used. + cam_view : None or sequence (3,), optional + Camera's view up direction. If None then default camera's view up + vector is used. + out_path : str, optional + Output path for the frames. If None a default fury.png is created. + path_numbering : bool + When recording it changes out_path to out_path + str(frame number) + n_frames : int, optional + Number of frames to save, default 1 + az_ang : float, optional + Azimuthal angle of camera rotation. + magnification : int, optional + How much to magnify the saved frame. Default is 1. A value greater + than 1 increases the quality of the image. However, the output + size will be larger. For example, 200x200 image with magnification + of 2 will be a 400x400 image. + size : (int, int) + ``(width, height)`` of the window. Default is (300, 300). + screen_clip: bool + Clip the png based on screen resolution. Default is False. + reset_camera : bool + If True Call ``scene.reset_camera()``. Otherwise you need to set the + camera before calling this function. + stereo: string + Set the stereo type. Default is 'off'. Other types include: + + * 'opengl': OpenGL frame-sequential stereo. Referred to as + 'CrystalEyes' by VTK. + * 'anaglyph': For use with red/blue glasses. See VTK docs to + use different colors. + * 'interlaced': Line interlaced. + * 'checkerboard': Checkerboard interlaced. + * 'left': Left eye only. + * 'right': Right eye only. + * 'horizontal': Side-by-side. + + verbose : bool + print information about the camera. Default is False. + + Examples + -------- + >>> from fury import window, actor + >>> scene = window.Scene() + >>> a = actor.axes() + >>> scene.add(a) + >>> # uncomment below to record + >>> # window.record(scene) + >>> # check for new images in current directory + + """ + if scene is None: + scene = Scene() + + renWin = RenderWindow() + + renWin.SetOffScreenRendering(1) + renWin.SetBorders(screen_clip) + renWin.AddRenderer(scene) + renWin.SetSize(size[0], size[1]) + + # scene.GetActiveCamera().Azimuth(180) + + if reset_camera: + scene.ResetCamera() + + if stereo.lower() != 'off': + enable_stereo(renWin, stereo) + + renderLarge = RenderLargeImage() + renderLarge.SetInput(scene) + renderLarge.SetMagnification(magnification) + renderLarge.Update() + + ang = 0 + + if cam_pos is not None: + cx, cy, cz = cam_pos + scene.GetActiveCamera().SetPosition(cx, cy, cz) + if cam_focal is not None: + fx, fy, fz = cam_focal + scene.GetActiveCamera().SetFocalPoint(fx, fy, fz) + if cam_view is not None: + ux, uy, uz = cam_view + scene.GetActiveCamera().SetViewUp(ux, uy, uz) + + cam = scene.GetActiveCamera() + if verbose: + print('Camera Position (%.2f, %.2f, %.2f)' % cam.GetPosition()) + print('Camera Focal Point (%.2f, %.2f, %.2f)' % cam.GetFocalPoint()) + print('Camera View Up (%.2f, %.2f, %.2f)' % cam.GetViewUp()) + + for i in range(n_frames): + scene.GetActiveCamera().Azimuth(ang) + renderLarge = RenderLargeImage() + renderLarge.SetInput(scene) + renderLarge.SetMagnification(magnification) + renderLarge.Update() + + if path_numbering: + if out_path is None: + filename = str(i).zfill(6) + '.png' + else: + filename = out_path + str(i).zfill(6) + '.png' + else: + if out_path is None: + filename = 'fury.png' + else: + filename = out_path + + arr = numpy_support.vtk_to_numpy( + renderLarge.GetOutput().GetPointData().GetScalars() + ) + w, h, _ = renderLarge.GetOutput().GetDimensions() + components = renderLarge.GetOutput().GetNumberOfScalarComponents() + arr = arr.reshape((h, w, components)) + arr = np.flipud(arr) + save_image(arr, filename) + + ang = +az_ang + + renWin.RemoveRenderer(scene) + renWin.Finalize()
+ + + +
+[docs] +def antialiasing(scene, win, multi_samples=8, max_peels=4, occlusion_ratio=0.0): + """Enable anti-aliasing and ordered transparency. + + Parameters + ---------- + scene : Scene + win : Window + Provided by ShowManager.window attribute. + multi_samples : int + Number of samples for anti-aliasing (Default 8). + For no anti-aliasing use 0. + max_peels : int + Maximum number of peels for depth peeling (Default 4). + occlusion_ratio : float + Occlusion ratio for depth peeling (Default 0 - exact image). + + """ + # Use a render window with alpha bits + # as default is 0 (false)) + win.SetAlphaBitPlanes(True) + + # Force to not pick a framebuffer with a multisample buffer + # (default is 8) + win.SetMultiSamples(multi_samples) + + # TODO: enable these but test + # win.SetBorders(True) + # win.LineSmoothingOn(True) + # win.PointSmoothingOn(True) + # win.PolygonSmoothingOn(True) + + # Choose to use depth peeling (if supported) + # (default is 0 (false)): + scene.UseDepthPeelingOn() + + # Set depth peeling parameters + # Set the maximum number of rendering passes (default is 4) + scene.SetMaximumNumberOfPeels(max_peels) + + # Set the occlusion ratio (initial value is 0.0, exact image): + scene.SetOcclusionRatio(occlusion_ratio)
+ + + +
+[docs] +def snapshot( + scene, + fname=None, + size=(300, 300), + offscreen=True, + order_transparent=False, + stereo='off', + multi_samples=8, + max_peels=4, + occlusion_ratio=0.0, + dpi=(72, 72), + render_window=None, +): + """Save a snapshot of the scene in a file or in memory. + + Parameters + ---------- + scene : Scene() or vtkRenderer + Scene instance + fname : str or None + Save PNG file. If None return only an array without saving PNG. + size : (int, int) + ``(width, height)`` of the window. Default is (300, 300). + offscreen : bool + Default True. Go stealth mode no window should appear. + order_transparent : bool + Default False. Use depth peeling to sort transparent objects. + If True also enables anti-aliasing. + + stereo: string + Set the stereo type. Default is 'off'. Other types include: + + * 'opengl': OpenGL frame-sequential stereo. Referred to as + 'CrystalEyes' by VTK. + * 'anaglyph': For use with red/blue glasses. See VTK docs to + use different colors. + * 'interlaced': Line interlaced. + * 'checkerboard': Checkerboard interlaced. + * 'left': Left eye only. + * 'right': Right eye only. + * 'horizontal': Side-by-side. + + multi_samples : int + Number of samples for anti-aliazing (Default 8). + For no anti-aliasing use 0. + max_peels : int + Maximum number of peels for depth peeling (Default 4). + occlusion_ratio : float + Occlusion ration for depth peeling (Default 0 - exact image). + dpi : float or (float, float) + Dots per inch (dpi) for saved image. + Single values are applied as dpi for both dimensions. + render_window : RenderWindow + If provided, use this window instead of creating a new one. + + Returns + ------- + arr : ndarray + Color array of size (width, height, 3) where the last dimension + holds the RGB values. + + """ + width, height = size + if render_window is None: + render_window = RenderWindow() + if offscreen: + render_window.SetOffScreenRendering(1) + if stereo.lower() != 'off': + enable_stereo(render_window, stereo) + render_window.AddRenderer(scene) + render_window.SetSize(width, height) + + if order_transparent: + antialiasing( + scene, render_window, multi_samples, max_peels, occlusion_ratio + ) + render_window.Render() + + window_to_image_filter = WindowToImageFilter() + window_to_image_filter.SetInput(render_window) + window_to_image_filter.Update() + + vtk_image = window_to_image_filter.GetOutput() + h, w, _ = vtk_image.GetDimensions() + vtk_array = vtk_image.GetPointData().GetScalars() + components = vtk_array.GetNumberOfComponents() + arr = numpy_support.vtk_to_numpy(vtk_array).reshape(w, h, components).copy() + arr = np.flipud(arr) + + if fname is None: + return arr + + save_image(arr, fname, dpi=dpi) + + render_window.RemoveRenderer(scene) + render_window.Finalize() + + return arr
+ + + +
+[docs] +def analyze_scene(scene): + class ReportScene: + bg_color = None + collection = None + actors = None + actors_classnames = None + + report = ReportScene() + + report.bg_color = scene.GetBackground() + report.collection = scene.GetActors() + report.actors = report.collection.GetNumberOfItems() + + report.collection.InitTraversal() + report.actors_classnames = [] + for _ in range(report.actors): + class_name = report.collection.GetNextActor().GetClassName() + report.actors_classnames.append(class_name) + + return report
+ + + +
+[docs] +def analyze_snapshot( + im, bg_color=colors.black, colors=None, find_objects=True, strel=None +): + """Analyze snapshot from memory or file. + + Parameters + ---------- + im: str or array + If string then the image is read from a file otherwise the image is + read from a numpy array. The array is expected to be of shape (X, Y, 3) + or (X, Y, 4) where the last dimensions are the RGB or RGBA values. + colors: tuple (3,) or list of tuples (3,) + List of colors to search in the image + find_objects: bool + If True it will calculate the number of objects that are different + from the background and return their position in a new image. + strel: 2d array + Structure element to use for finding the objects. + + Returns + ------- + report : ReportSnapshot + This is an object with attributes like ``colors_found`` that give + information about what was found in the current snapshot array ``im``. + + """ + if isinstance(im, basestring): + im = load_image(im) + + class ReportSnapshot: + objects = None + labels = None + colors_found = False + + def __str__(self): + msg = 'Report:\n-------\n' + msg += 'objects: {}\n'.format(self.objects) + msg += 'labels: \n{}\n'.format(self.labels) + msg += 'colors_found: {}\n'.format(self.colors_found) + return msg + + report = ReportSnapshot() + + if colors is not None: + if isinstance(colors, tuple): + colors = [colors] + flags = [False] * len(colors) + for (i, col) in enumerate(colors): + # find if the current color exist in the array + flags[i] = np.any(np.any(np.all(np.equal(im[..., :3], col[:3]), axis=-1))) + + report.colors_found = flags + + if find_objects is True: + weights = [0.299, 0.587, 0.144] + gray = np.dot(im[..., :3], weights) + bg_color2 = im[0, 0] + background = np.dot(bg_color2, weights) + + if strel is None: + strel = np.array([[1, 1, 1], [1, 1, 1], [1, 1, 1]]) + + labels, objects = ndimage.label(gray != background, strel) + report.labels = labels + report.objects = objects + + return report
+ + + +
+[docs] +def enable_stereo(renwin, stereo_type): + """Enable the given stereo type on the RenderWindow. + + Parameters + ---------- + renwin: vtkRenderWindow + stereo_type: string + * 'opengl': OpenGL frame-sequential stereo. Referred to as + 'CrystalEyes' by VTK. + * 'anaglyph': For use with red/blue glasses. See VTK docs to + use different colors. + * 'interlaced': Line interlaced. + * 'checkerboard': Checkerboard interlaced. + * 'left': Left eye only. + * 'right': Right eye only. + * 'horizontal': Side-by-side. + + """ + renwin.GetStereoCapableWindow() + renwin.StereoCapableWindowOn() + renwin.StereoRenderOn() + + stereo_type = stereo_type.lower() + + # stereo type ints from + # https://gitlab.kitware.com/vtk/vtk/blob/master/Rendering/Core/vtkRenderWindow.h#L57 + stereo_type_dictionary = { + 'opengl': 1, + 'interlaced': 3, + 'anaglyph': 7, + 'checkerboard': 8, + 'horizontal': 9, + } + + # default to horizontal since it is easy to see if it is working + if stereo_type not in stereo_type_dictionary: + warn('Unknown stereo type provided. ' "Setting stereo type to 'horizontal'.") + stereo_type = 'horizontal' + + renwin.SetStereoType(stereo_type_dictionary[stereo_type])
+ + + +
+[docs] +def gl_get_current_state(gl_state): + """Returns a dict which describes the current state of the opengl + context + + Parameters + ---------- + gl_state : vtkOpenGLState + + """ + state_description = { + glName: gl_state.GetEnumState(glNumber) for glName, glNumber in _GL.items() + } + return state_description
+ + + +
+[docs] +def gl_reset_blend(gl_state): + """Redefines the state of the OpenGL context related with how the RGBA + channels will be combined. + + Parameters + ---------- + gl_state : vtkOpenGLState + + See more + --------- + [1] https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glBlendEquation.xhtml + [2] https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glBlendFunc.xhtml + vtk specification: + [3] https://gitlab.kitware.com/vtk/vtk/-/blob/master/Rendering/OpenGL2/vtkOpenGLState.cxx#L1705 + + """ # noqa + gl_state.ResetGLBlendEquationState() + gl_state.ResetGLBlendFuncState()
+ + + +
+[docs] +def gl_enable_depth(gl_state): + """Enable OpenGl depth test + + Parameters + ---------- + gl_state : vtkOpenGLState + + """ + gl_state.vtkglEnable(_GL['GL_DEPTH_TEST'])
+ + + +
+[docs] +def gl_disable_depth(gl_state): + """Disable OpenGl depth test + + Parameters + ---------- + gl_state : vtkOpenGLState + + """ + gl_state.vtkglDisable(_GL['GL_DEPTH_TEST'])
+ + + +
+[docs] +def gl_enable_blend(gl_state): + """Enable OpenGl blending + + Parameters + ---------- + gl_state : vtkOpenGLState + + """ + gl_state.vtkglEnable(_GL['GL_BLEND'])
+ + + +
+[docs] +def gl_disable_blend(gl_state): + """This it will disable any gl behavior which has no + function for opaque objects. This has the benefit of + speeding up the rendering of the image. + + Parameters + ---------- + gl_state : vtkOpenGLState + + See more + -------- + [1] https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glFrontFace.xhtml + + """ # noqa + + gl_state.vtkglDisable(_GL['GL_CULL_FACE']) + gl_state.vtkglDisable(_GL['GL_BLEND'])
+ + + +
+[docs] +def gl_set_additive_blending(gl_state): + """Enable additive blending + + Parameters + ---------- + gl_state : vtkOpenGLState + + """ + gl_reset_blend(gl_state) + gl_state.vtkglEnable(_GL['GL_BLEND']) + gl_state.vtkglDisable(_GL['GL_DEPTH_TEST']) + gl_state.vtkglBlendFunc(_GL['GL_SRC_ALPHA'], _GL['GL_ONE'])
+ + + +
+[docs] +def gl_set_additive_blending_white_background(gl_state): + """Enable additive blending for a white background + + Parameters + ---------- + gl_state : vtkOpenGLState + + """ + gl_reset_blend(gl_state) + gl_state.vtkglEnable(_GL['GL_BLEND']) + gl_state.vtkglDisable(_GL['GL_DEPTH_TEST']) + gl_state.vtkglBlendFuncSeparate( + _GL['GL_SRC_ALPHA'], + _GL['GL_ONE_MINUS_SRC_ALPHA'], + _GL['GL_ONE'], + _GL['GL_ZERO'], + )
+ + + +
+[docs] +def gl_set_normal_blending(gl_state): + """Enable normal blending + + Parameters + ---------- + gl_state : vtkOpenGLState + + """ + gl_state.vtkglEnable(_GL['GL_BLEND']) + gl_state.vtkglEnable(_GL['GL_DEPTH_TEST']) + gl_state.vtkglBlendFunc(_GL['GL_ONE'], _GL['GL_ONE']) + gl_state.vtkglBlendFuncSeparate( + _GL['GL_SRC_ALPHA'], + _GL['GL_ONE_MINUS_SRC_ALPHA'], + _GL['GL_ONE'], + _GL['GL_ONE_MINUS_SRC_ALPHA'], + )
+ + + +
+[docs] +def gl_set_multiplicative_blending(gl_state): + """Enable multiplicative blending + + Parameters + ---------- + gl_state : vtkOpenGLState + + """ + gl_reset_blend(gl_state) + gl_state.vtkglBlendFunc(_GL['GL_ZERO'], _GL['GL_SRC_COLOR'])
+ + + +
+[docs] +def gl_set_subtractive_blending(gl_state): + """Enable subtractive blending + + Parameters + ---------- + gl_state : vtkOpenGLState + + """ + gl_reset_blend(gl_state) + gl_state.vtkglBlendFunc(_GL['GL_ZERO'], _GL['GL_ONE_MINUS_SRC_COLOR'])
+ + + +
+[docs] +def release_context(window): + """Release the context of the window + + Parameters + ---------- + window : vtkRenderWindow + + """ + window.ReleaseCurrent()
+ +
+
+ + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/_modules/index.html b/v0.10.x/_modules/index.html new file mode 100644 index 000000000..a874101d6 --- /dev/null +++ b/v0.10.x/_modules/index.html @@ -0,0 +1,520 @@ + + + + + + + Overview: module code — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +

All modules for which code is available

+ +
+ + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/_sources/auto_examples/01_introductory/index.rst.txt b/v0.10.x/_sources/auto_examples/01_introductory/index.rst.txt new file mode 100644 index 000000000..2ca7d6bba --- /dev/null +++ b/v0.10.x/_sources/auto_examples/01_introductory/index.rst.txt @@ -0,0 +1,371 @@ + + +.. _sphx_glr_auto_examples_01_introductory: + +Introductory +------------ + +These tutorials show: + +- How to combine a timer with an actor +- How to slice data with the slicer actor +- How to use the normals of your data. + + + +.. raw:: html + +
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/01_introductory/images/thumb/sphx_glr_viz_texture_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_01_introductory_viz_texture.py` + +.. raw:: html + +
Sphere Texture
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/01_introductory/images/thumb/sphx_glr_viz_gltf_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_01_introductory_viz_gltf.py` + +.. raw:: html + +
Visualizing a glTF file
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/01_introductory/images/thumb/sphx_glr_viz_sphere_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_01_introductory_viz_sphere.py` + +.. raw:: html + +
FURY sphere Actor
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/01_introductory/images/thumb/sphx_glr_viz_cone_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_01_introductory_viz_cone.py` + +.. raw:: html + +
Fury Cone Actor
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/01_introductory/images/thumb/sphx_glr_viz_arrow_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_01_introductory_viz_arrow.py` + +.. raw:: html + +
Fury Arrow Actor
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/01_introductory/images/thumb/sphx_glr_viz_gltf_animated_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_01_introductory_viz_gltf_animated.py` + +.. raw:: html + +
Visualizing a glTF file
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/01_introductory/images/thumb/sphx_glr_viz_morphing_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_01_introductory_viz_morphing.py` + +.. raw:: html + +
Morphing Animation in a glTF
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/01_introductory/images/thumb/sphx_glr_viz_gltf_export_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_01_introductory_viz_gltf_export.py` + +.. raw:: html + +
Exporting scene as a glTF file
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/01_introductory/images/thumb/sphx_glr_viz_skinning_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_01_introductory_viz_skinning.py` + +.. raw:: html + +
Skeletal Animation in a glTF file
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/01_introductory/images/thumb/sphx_glr_viz_timers_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_01_introductory_viz_timers.py` + +.. raw:: html + +
Using a timer
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/01_introductory/images/thumb/sphx_glr_viz_spiky_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_01_introductory_viz_spiky.py` + +.. raw:: html + +
Spiky Sphere
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/01_introductory/images/thumb/sphx_glr_viz_surfaces_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_01_introductory_viz_surfaces.py` + +.. raw:: html + +
Visualize surfaces
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/01_introductory/images/thumb/sphx_glr_viz_selection_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_01_introductory_viz_selection.py` + +.. raw:: html + +
Selecting multiple objects
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/01_introductory/images/thumb/sphx_glr_viz_multithread_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_01_introductory_viz_multithread.py` + +.. raw:: html + +
Multithreading Example
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/01_introductory/images/thumb/sphx_glr_viz_picking_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_01_introductory_viz_picking.py` + +.. raw:: html + +
Simple picking
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/01_introductory/images/thumb/sphx_glr_viz_earth_animation_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_01_introductory_viz_earth_animation.py` + +.. raw:: html + +
Texture Sphere Animation
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/01_introductory/images/thumb/sphx_glr_viz_earth_coordinates_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_01_introductory_viz_earth_coordinates.py` + +.. raw:: html + +
Earth Coordinate Conversion
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/01_introductory/images/thumb/sphx_glr_viz_slice_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_01_introductory_viz_slice.py` + +.. raw:: html + +
Simple volume slicing
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/01_introductory/images/thumb/sphx_glr_viz_solar_system_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_01_introductory_viz_solar_system.py` + +.. raw:: html + +
Solar System Animation
+
+ + +.. raw:: html + +
+ + +.. toctree:: + :hidden: + + /auto_examples/01_introductory/viz_texture + /auto_examples/01_introductory/viz_gltf + /auto_examples/01_introductory/viz_sphere + /auto_examples/01_introductory/viz_cone + /auto_examples/01_introductory/viz_arrow + /auto_examples/01_introductory/viz_gltf_animated + /auto_examples/01_introductory/viz_morphing + /auto_examples/01_introductory/viz_gltf_export + /auto_examples/01_introductory/viz_skinning + /auto_examples/01_introductory/viz_timers + /auto_examples/01_introductory/viz_spiky + /auto_examples/01_introductory/viz_surfaces + /auto_examples/01_introductory/viz_selection + /auto_examples/01_introductory/viz_multithread + /auto_examples/01_introductory/viz_picking + /auto_examples/01_introductory/viz_earth_animation + /auto_examples/01_introductory/viz_earth_coordinates + /auto_examples/01_introductory/viz_slice + /auto_examples/01_introductory/viz_solar_system + diff --git a/v0.10.x/_sources/auto_examples/01_introductory/sg_execution_times.rst.txt b/v0.10.x/_sources/auto_examples/01_introductory/sg_execution_times.rst.txt new file mode 100644 index 000000000..59654c703 --- /dev/null +++ b/v0.10.x/_sources/auto_examples/01_introductory/sg_execution_times.rst.txt @@ -0,0 +1,91 @@ + +:orphan: + +.. _sphx_glr_auto_examples_01_introductory_sg_execution_times: + + +Computation times +================= +**01:59.821** total execution time for 19 files **from auto_examples/01_introductory**: + +.. container:: + + .. raw:: html + + + + + + + + .. list-table:: + :header-rows: 1 + :class: table table-striped sg-datatable + + * - Example + - Time + - Mem (MB) + * - :ref:`sphx_glr_auto_examples_01_introductory_viz_earth_animation.py` (``viz_earth_animation.py``) + - 00:39.436 + - 0.0 + * - :ref:`sphx_glr_auto_examples_01_introductory_viz_solar_system.py` (``viz_solar_system.py``) + - 00:31.865 + - 0.0 + * - :ref:`sphx_glr_auto_examples_01_introductory_viz_earth_coordinates.py` (``viz_earth_coordinates.py``) + - 00:27.806 + - 0.0 + * - :ref:`sphx_glr_auto_examples_01_introductory_viz_timers.py` (``viz_timers.py``) + - 00:05.984 + - 0.0 + * - :ref:`sphx_glr_auto_examples_01_introductory_viz_multithread.py` (``viz_multithread.py``) + - 00:05.510 + - 0.0 + * - :ref:`sphx_glr_auto_examples_01_introductory_viz_spiky.py` (``viz_spiky.py``) + - 00:04.349 + - 0.0 + * - :ref:`sphx_glr_auto_examples_01_introductory_viz_slice.py` (``viz_slice.py``) + - 00:02.768 + - 0.0 + * - :ref:`sphx_glr_auto_examples_01_introductory_viz_selection.py` (``viz_selection.py``) + - 00:01.308 + - 0.0 + * - :ref:`sphx_glr_auto_examples_01_introductory_viz_skinning.py` (``viz_skinning.py``) + - 00:00.644 + - 0.0 + * - :ref:`sphx_glr_auto_examples_01_introductory_viz_picking.py` (``viz_picking.py``) + - 00:00.085 + - 0.0 + * - :ref:`sphx_glr_auto_examples_01_introductory_viz_surfaces.py` (``viz_surfaces.py``) + - 00:00.064 + - 0.0 + * - :ref:`sphx_glr_auto_examples_01_introductory_viz_arrow.py` (``viz_arrow.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_01_introductory_viz_cone.py` (``viz_cone.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_01_introductory_viz_gltf.py` (``viz_gltf.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_01_introductory_viz_gltf_animated.py` (``viz_gltf_animated.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_01_introductory_viz_gltf_export.py` (``viz_gltf_export.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_01_introductory_viz_morphing.py` (``viz_morphing.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_01_introductory_viz_sphere.py` (``viz_sphere.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_01_introductory_viz_texture.py` (``viz_texture.py``) + - 00:00.000 + - 0.0 diff --git a/v0.10.x/_sources/auto_examples/01_introductory/viz_arrow.rst.txt b/v0.10.x/_sources/auto_examples/01_introductory/viz_arrow.rst.txt new file mode 100644 index 000000000..17f690d22 --- /dev/null +++ b/v0.10.x/_sources/auto_examples/01_introductory/viz_arrow.rst.txt @@ -0,0 +1,179 @@ + +.. DO NOT EDIT. +.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. +.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: +.. "auto_examples/01_introductory/viz_arrow.py" +.. LINE NUMBERS ARE GIVEN BELOW. + +.. only:: html + + .. note:: + :class: sphx-glr-download-link-note + + :ref:`Go to the end ` + to download the full example code + +.. rst-class:: sphx-glr-example-title + +.. _sphx_glr_auto_examples_01_introductory_viz_arrow.py: + + +====================================================================== +Fury Arrow Actor +====================================================================== + +This example shows how to use the arrow actor. + +.. GENERATED FROM PYTHON SOURCE LINES 8-13 + +.. code-block:: Python + + + import numpy as np + + from fury import actor, window + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 14-16 + +First thing, you have to specify centers, directions, and colors of the +arrow(s) + +.. GENERATED FROM PYTHON SOURCE LINES 16-19 + +.. code-block:: Python + + + centers = np.zeros([3, 3]) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 20-21 + +np.identity is the same as specifying x, y, and z directions. + +.. GENERATED FROM PYTHON SOURCE LINES 21-25 + +.. code-block:: Python + + dirs = np.identity(3) + colors = np.identity(3) + scales = np.array([2.1, 2.6, 2.5]) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 26-27 + +The below arrow actor is generated by repeating the arrow primitive. + +.. GENERATED FROM PYTHON SOURCE LINES 27-30 + +.. code-block:: Python + + + arrow_actor = actor.arrow(centers, dirs, colors=colors, scales=1.5) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 31-33 + +repeating what we did but this time with random centers, directions, and +colors. + +.. GENERATED FROM PYTHON SOURCE LINES 33-42 + +.. code-block:: Python + + + cen2 = np.random.rand(5, 3) + dir2 = np.random.rand(5, 3) + cols2 = np.random.rand(5, 3) + + arrow_actor2 = actor.arrow(cen2, dir2, colors=cols2, scales=1.5) + + scene = window.Scene() + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 43-44 + +Adding our Arrow actors to scene. + +.. GENERATED FROM PYTHON SOURCE LINES 44-54 + +.. code-block:: Python + + + scene.add(arrow_actor) + scene.add(arrow_actor2) + + interactive = False + + if interactive: + window.show(scene, size=(600, 600)) + + window.record(scene, out_path='viz_arrow.png', size=(600, 600)) + + + +.. image-sg:: /auto_examples/01_introductory/images/sphx_glr_viz_arrow_001.png + :alt: viz arrow + :srcset: /auto_examples/01_introductory/images/sphx_glr_viz_arrow_001.png + :class: sphx-glr-single-img + + + + + + +.. rst-class:: sphx-glr-timing + + **Total running time of the script:** (0 minutes 0.052 seconds) + + +.. _sphx_glr_download_auto_examples_01_introductory_viz_arrow.py: + +.. only:: html + + .. container:: sphx-glr-footer sphx-glr-footer-example + + .. container:: sphx-glr-download sphx-glr-download-jupyter + + :download:`Download Jupyter notebook: viz_arrow.ipynb ` + + .. container:: sphx-glr-download sphx-glr-download-python + + :download:`Download Python source code: viz_arrow.py ` + + +.. only:: html + + .. rst-class:: sphx-glr-signature + + `Gallery generated by Sphinx-Gallery `_ diff --git a/v0.10.x/_sources/auto_examples/01_introductory/viz_cone.rst.txt b/v0.10.x/_sources/auto_examples/01_introductory/viz_cone.rst.txt new file mode 100644 index 000000000..09c734058 --- /dev/null +++ b/v0.10.x/_sources/auto_examples/01_introductory/viz_cone.rst.txt @@ -0,0 +1,160 @@ + +.. DO NOT EDIT. +.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. +.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: +.. "auto_examples/01_introductory/viz_cone.py" +.. LINE NUMBERS ARE GIVEN BELOW. + +.. only:: html + + .. note:: + :class: sphx-glr-download-link-note + + :ref:`Go to the end ` + to download the full example code + +.. rst-class:: sphx-glr-example-title + +.. _sphx_glr_auto_examples_01_introductory_viz_cone.py: + + +====================================================================== +Fury Cone Actor +====================================================================== +This example shows how to use the cone actor. + +.. GENERATED FROM PYTHON SOURCE LINES 7-12 + +.. code-block:: Python + + + import numpy as np + + from fury import actor, window + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 13-14 + +First thing, you have to specify centers, directions, and colors of the cone + +.. GENERATED FROM PYTHON SOURCE LINES 14-19 + +.. code-block:: Python + + + centers = np.zeros([3, 3]) + dirs = np.identity(3) + colors = np.identity(3) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 20-21 + +The below cone actor is generated by repeating the cone primitive. + +.. GENERATED FROM PYTHON SOURCE LINES 21-24 + +.. code-block:: Python + + + cone_actor1 = actor.cone(centers, dirs, colors=colors, heights=1.5) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 25-27 + +repeating what we did but this time with random directions, and colors +Here, we're using vtkConeSource to generate the cone actor + +.. GENERATED FROM PYTHON SOURCE LINES 27-36 + +.. code-block:: Python + + + cen2 = np.add(centers, np.array([3, 0, 0])) + dir2 = np.random.rand(5, 3) + cols2 = np.random.rand(5, 3) + + cone_actor2 = actor.cone(cen2, dir2, colors=cols2, heights=1.5, use_primitive=False) + + scene = window.Scene() + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 37-38 + +Adding our cone actors to scene. + +.. GENERATED FROM PYTHON SOURCE LINES 38-48 + +.. code-block:: Python + + + scene.add(cone_actor1) + scene.add(cone_actor2) + + interactive = False + + if interactive: + window.show(scene, size=(600, 600)) + + window.record(scene, out_path='viz_cone.png', size=(600, 600)) + + + +.. image-sg:: /auto_examples/01_introductory/images/sphx_glr_viz_cone_001.png + :alt: viz cone + :srcset: /auto_examples/01_introductory/images/sphx_glr_viz_cone_001.png + :class: sphx-glr-single-img + + + + + + +.. rst-class:: sphx-glr-timing + + **Total running time of the script:** (0 minutes 0.055 seconds) + + +.. _sphx_glr_download_auto_examples_01_introductory_viz_cone.py: + +.. only:: html + + .. container:: sphx-glr-footer sphx-glr-footer-example + + .. container:: sphx-glr-download sphx-glr-download-jupyter + + :download:`Download Jupyter notebook: viz_cone.ipynb ` + + .. container:: sphx-glr-download sphx-glr-download-python + + :download:`Download Python source code: viz_cone.py ` + + +.. only:: html + + .. rst-class:: sphx-glr-signature + + `Gallery generated by Sphinx-Gallery `_ diff --git a/v0.10.x/_sources/auto_examples/01_introductory/viz_earth_animation.rst.txt b/v0.10.x/_sources/auto_examples/01_introductory/viz_earth_animation.rst.txt new file mode 100644 index 000000000..4dde07bf2 --- /dev/null +++ b/v0.10.x/_sources/auto_examples/01_introductory/viz_earth_animation.rst.txt @@ -0,0 +1,430 @@ + +.. DO NOT EDIT. +.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. +.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: +.. "auto_examples/01_introductory/viz_earth_animation.py" +.. LINE NUMBERS ARE GIVEN BELOW. + +.. only:: html + + .. note:: + :class: sphx-glr-download-link-note + + :ref:`Go to the end ` + to download the full example code + +.. rst-class:: sphx-glr-example-title + +.. _sphx_glr_auto_examples_01_introductory_viz_earth_animation.py: + + +========================= +Texture Sphere Animation +========================= +In this tutorial, we will show how to animate a textured sphere. + +.. GENERATED FROM PYTHON SOURCE LINES 7-20 + +.. code-block:: Python + + + import itertools + + import numpy as np + + from fury import actor, io, utils, window + from fury.data import ( + fetch_viz_models, + fetch_viz_textures, + read_viz_models, + read_viz_textures, + ) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 21-22 + +Create a scene to start. + +.. GENERATED FROM PYTHON SOURCE LINES 22-25 + +.. code-block:: Python + + + scene = window.Scene() + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 26-31 + +Next, load in a texture for each of the actors. For this tutorial, we will +be creating one textured sphere for the Earth, and another for the moon. +Collect the Earth texture from the FURY github using ``fetch_viz_textures`` +and ``read_viz_textures``, then use ``io.load_image`` to load in the +image. + +.. GENERATED FROM PYTHON SOURCE LINES 31-36 + +.. code-block:: Python + + + fetch_viz_textures() + earth_filename = read_viz_textures('1_earth_8k.jpg') + earth_image = io.load_image(earth_filename) + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + Dataset is already in place. If you want to fetch it again please first remove the folder /Users/skoudoro/.fury/textures + + + + +.. GENERATED FROM PYTHON SOURCE LINES 37-39 + +Using ``actor.texture_on_sphere()``, create an earth_actor with your newly +loaded texture. + +.. GENERATED FROM PYTHON SOURCE LINES 39-42 + +.. code-block:: Python + + + earth_actor = actor.texture_on_sphere(earth_image) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 43-44 + +Then, do the same for the moon. + +.. GENERATED FROM PYTHON SOURCE LINES 44-50 + +.. code-block:: Python + + + moon_filename = read_viz_textures('moon-8k.jpg') + moon_image = io.load_image(moon_filename) + + moon_actor = actor.texture_on_sphere(moon_image) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 51-52 + +Add both actors to the already existing scene. + +.. GENERATED FROM PYTHON SOURCE LINES 52-56 + +.. code-block:: Python + + + scene.add(earth_actor) + scene.add(moon_actor) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 57-61 + +Next, alter the position and scale of the moon to correctly size it in +comparison to the Earth using ``actor.SetPosition()`` and +``actor.SetScale()``, and rotate the Earth using ``utils.rotate`` to +correctly align the texture. + +.. GENERATED FROM PYTHON SOURCE LINES 61-66 + +.. code-block:: Python + + + moon_actor.SetPosition(1, 0.1, 0.5) + moon_actor.SetScale(0.25, 0.25, 0.25) + utils.rotate(earth_actor, (-90, 1, 0, 0)) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 67-69 + +The ShowManager class is the interface between the scene, the window and the +interactor. + +.. GENERATED FROM PYTHON SOURCE LINES 69-74 + +.. code-block:: Python + + + showm = window.ShowManager( + scene, size=(900, 768), reset_camera=False, order_transparent=True + ) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 75-78 + +Next, let's focus on creating the animation. +We can determine the duration of animation with using the ``counter``. +Use itertools to avoid global variables. + +.. GENERATED FROM PYTHON SOURCE LINES 78-81 + +.. code-block:: Python + + + counter = itertools.count() + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 82-84 + +Use ``set_camera`` to ensure the camera is in the optimal position for the +scene. + +.. GENERATED FROM PYTHON SOURCE LINES 84-91 + +.. code-block:: Python + + + scene.set_camera( + position=(0.24, 0.00, 4.34), + focal_point=(0.00, 0.00, 0.00), + view_up=(0.00, 1.00, 0.00), + ) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 92-94 + +Let's create a sphere actor to add to the Earth. We will place this sphere +on the Earth's surface on Bloomington, IN, home of FURY's headquarters! + +.. GENERATED FROM PYTHON SOURCE LINES 94-99 + +.. code-block:: Python + + + center = np.array([[-0.39, 0.3175, 0.025]]) + radius = 0.002 + sphere_actor = actor.sphere(center, window.colors.blue_medium, radius) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 100-101 + +Also creating a text actor to add below the sphere. + +.. GENERATED FROM PYTHON SOURCE LINES 101-107 + +.. code-block:: Python + + + text_actor = actor.text_3d( + 'Bloomington, Indiana', (-0.42, 0.31, 0.03), window.colors.white, 0.004 + ) + utils.rotate(text_actor, (-90, 0, 1, 0)) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 108-109 + +Let's also import a model of a satellite to visualize circling the moon. + +.. GENERATED FROM PYTHON SOURCE LINES 109-119 + +.. code-block:: Python + + + fetch_viz_models() + satellite_filename = read_viz_models('satellite_obj.obj') + satellite = io.load_polydata(satellite_filename) + satellite_actor = utils.get_actor_from_polydata(satellite) + + satellite_actor.SetPosition(-0.75, 0.1, 0.4) + satellite_actor.SetScale(0.005, 0.005, 0.005) + + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + Dataset is already in place. If you want to fetch it again please first remove the folder /Users/skoudoro/.fury/models + + + + +.. GENERATED FROM PYTHON SOURCE LINES 120-124 + +In the ``timer_callback`` function, use if statements to specify when +certain events will happen in the animation, based on the position that +the counter is at. So, for example, the earth actor will continue to +rotate while the count is less than 450. + +.. GENERATED FROM PYTHON SOURCE LINES 124-169 + +.. code-block:: Python + + + + def timer_callback(_obj, _event): + cnt = next(counter) + showm.render() + if cnt < 450: + utils.rotate(earth_actor, (1, 0, 1, 0)) + if cnt % 5 == 0 and cnt < 450: + showm.scene.azimuth(-1) + if cnt == 300: + scene.set_camera( + position=(-3.679, 0.00, 2.314), + focal_point=(0.0, 0.35, 0.00), + view_up=(0.00, 1.00, 0.00), + ) + if cnt > 300 and cnt < 450: + scene.zoom(1.01) + if cnt >= 450 and cnt < 1500: + scene.add(sphere_actor) + scene.add(text_actor) + if cnt >= 450 and cnt < 550: + scene.zoom(1.01) + if cnt == 575: + moon_actor.SetPosition(-1, 0.1, 0.5) + scene.set_camera( + position=(-0.5, 0.1, 0.00), + focal_point=(-1, 0.1, 0.5), + view_up=(0.00, 1.00, 0.00), + ) + scene.zoom(0.03) + scene.add(satellite_actor) + utils.rotate(satellite_actor, (180, 0, 1, 0)) + scene.rm(earth_actor) + if cnt > 575 and cnt < 750: + showm.scene.azimuth(-2) + utils.rotate(moon_actor, (-2, 0, 1, 0)) + satellite_actor.SetPosition(-0.8, 0.1 - cnt / 10000, 0.4) + if cnt >= 750 and cnt < 1100: + showm.scene.azimuth(-2) + utils.rotate(moon_actor, (-2, 0, 1, 0)) + satellite_actor.SetPosition(-0.8, -0.07 + cnt / 10000, 0.4) + if cnt == 1100: + showm.exit() + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 170-171 + +Watch your new animation take place! + +.. GENERATED FROM PYTHON SOURCE LINES 171-176 + +.. code-block:: Python + + + + showm.add_timer_callback(True, 35, timer_callback) + showm.start() + window.record(showm.scene, size=(900, 768), out_path='viz_earth_animation.png') + + + +.. image-sg:: /auto_examples/01_introductory/images/sphx_glr_viz_earth_animation_001.png + :alt: viz earth animation + :srcset: /auto_examples/01_introductory/images/sphx_glr_viz_earth_animation_001.png + :class: sphx-glr-single-img + + + + + + +.. rst-class:: sphx-glr-timing + + **Total running time of the script:** (0 minutes 39.436 seconds) + + +.. _sphx_glr_download_auto_examples_01_introductory_viz_earth_animation.py: + +.. only:: html + + .. container:: sphx-glr-footer sphx-glr-footer-example + + .. container:: sphx-glr-download sphx-glr-download-jupyter + + :download:`Download Jupyter notebook: viz_earth_animation.ipynb ` + + .. container:: sphx-glr-download sphx-glr-download-python + + :download:`Download Python source code: viz_earth_animation.py ` + + +.. only:: html + + .. rst-class:: sphx-glr-signature + + `Gallery generated by Sphinx-Gallery `_ diff --git a/v0.10.x/_sources/auto_examples/01_introductory/viz_earth_coordinates.rst.txt b/v0.10.x/_sources/auto_examples/01_introductory/viz_earth_coordinates.rst.txt new file mode 100644 index 000000000..68f931d5a --- /dev/null +++ b/v0.10.x/_sources/auto_examples/01_introductory/viz_earth_coordinates.rst.txt @@ -0,0 +1,346 @@ + +.. DO NOT EDIT. +.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. +.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: +.. "auto_examples/01_introductory/viz_earth_coordinates.py" +.. LINE NUMBERS ARE GIVEN BELOW. + +.. only:: html + + .. note:: + :class: sphx-glr-download-link-note + + :ref:`Go to the end ` + to download the full example code + +.. rst-class:: sphx-glr-example-title + +.. _sphx_glr_auto_examples_01_introductory_viz_earth_coordinates.py: + + +============================ +Earth Coordinate Conversion +============================ + +In this tutorial, we will show how to place actors on specific locations +on the surface of the Earth using a new function. + +.. GENERATED FROM PYTHON SOURCE LINES 9-18 + +.. code-block:: Python + + + import itertools + import math + + import numpy as np + + from fury import actor, io, utils, window + from fury.data import fetch_viz_textures, read_viz_textures + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 19-22 + +Create a new scene, and load in the image of the Earth using +``fetch_viz_textures`` and ``read_viz_textures``. We will use a 16k +resolution texture for maximum detail. + +.. GENERATED FROM PYTHON SOURCE LINES 22-31 + +.. code-block:: Python + + + scene = window.Scene() + + fetch_viz_textures() + earth_file = read_viz_textures('1_earth_16k.jpg') + earth_image = io.load_image(earth_file) + earth_actor = actor.texture_on_sphere(earth_image) + scene.add(earth_actor) + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + Dataset is already in place. If you want to fetch it again please first remove the folder /Users/skoudoro/.fury/textures + /opt/homebrew/Caskroom/miniforge/base/envs/py311-fury/lib/python3.11/site-packages/PIL/Image.py:3186: DecompressionBombWarning: Image size (131220000 pixels) exceeds limit of 89478485 pixels, could be decompression bomb DOS attack. + warnings.warn( + + + + +.. GENERATED FROM PYTHON SOURCE LINES 32-34 + +Rotate the Earth to make sure the texture is correctly oriented. Change it's +scale using ``actor.SetScale()``. + +.. GENERATED FROM PYTHON SOURCE LINES 34-39 + +.. code-block:: Python + + + utils.rotate(earth_actor, (-90, 1, 0, 0)) + utils.rotate(earth_actor, (180, 0, 1, 0)) + earth_actor.SetScale(2, 2, 2) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 40-44 + +Define the function to convert geographical coordinates of a location in +latitude and longitude degrees to coordinates on the ``earth_actor`` surface. +In this function, convert to radians, then to spherical coordinates, and +lastly, to cartesian coordinates. + +.. GENERATED FROM PYTHON SOURCE LINES 44-61 + +.. code-block:: Python + + + + def latlong_coordinates(lat, lon): + # Convert latitude and longitude to spherical coordinates + degrees_to_radians = math.pi / 180.0 + # phi = 90 - latitude + phi = (90 - lat) * degrees_to_radians + # theta = longitude + theta = lon * degrees_to_radians * -1 + # now convert to cartesian + x = np.sin(phi) * np.cos(theta) + y = np.sin(phi) * np.sin(theta) + z = np.cos(phi) + # flipping z to y for FURY coordinates + return (x, z, y) + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 62-64 + +Use this new function to place some sphere actors on several big cities +around the Earth. + +.. GENERATED FROM PYTHON SOURCE LINES 64-69 + +.. code-block:: Python + + + locationone = latlong_coordinates(40.730610, -73.935242) # new york city, us + locationtwo = latlong_coordinates(39.916668, 116.383331) # beijing, china + locationthree = latlong_coordinates(48.864716, 2.349014) # paris, france + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 70-72 + +Set the centers, radii, and colors of these spheres, and create a new +``sphere_actor`` for each location to add to the scene. + +.. GENERATED FROM PYTHON SOURCE LINES 72-79 + +.. code-block:: Python + + + centers = np.array([[*locationone], [*locationtwo], [*locationthree]]) + colors = np.random.rand(3, 3) + radii = np.array([0.005, 0.005, 0.005]) + sphere_actor = actor.sphere(centers, colors, radii) + scene.add(sphere_actor) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 80-82 + +Create some text actors to add to the scene indicating each location and its +geographical coordinates. + +.. GENERATED FROM PYTHON SOURCE LINES 82-105 + +.. code-block:: Python + + + nyc_actor = actor.text_3d( + 'New York City, New York\n40.7128° N, 74.0060° W', + (locationone[0] - 0.04, locationone[1], locationone[2] + 0.07), + window.colors.white, + 0.01, + ) + paris_actor = actor.text_3d( + 'Paris, France\n48.8566° N, 2.3522° E', + (locationthree[0] - 0.04, locationthree[1], locationthree[2] - 0.07), + window.colors.white, + 0.01, + ) + beijing_actor = actor.text_3d( + 'Beijing, China\n39.9042° N, 116.4074° E', + (locationtwo[0] - 0.06, locationtwo[1], locationtwo[2] - 0.07), + window.colors.white, + 0.01, + ) + utils.rotate(paris_actor, (85, 0, 1, 0)) + utils.rotate(beijing_actor, (180, 0, 1, 0)) + utils.rotate(nyc_actor, (5, 1, 0, 0)) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 106-108 + +Create a ShowManager object, which acts as the interface between the scene, +the window and the interactor. + +.. GENERATED FROM PYTHON SOURCE LINES 108-113 + +.. code-block:: Python + + + showm = window.ShowManager( + scene, size=(900, 768), reset_camera=False, order_transparent=True + ) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 114-117 + +Let's create a ``timer_callback`` function to add some animation to the +Earth. Change the camera position and angle to fly over and zoom in on each +new location. + +.. GENERATED FROM PYTHON SOURCE LINES 117-152 + +.. code-block:: Python + + + counter = itertools.count() + + + def timer_callback(_obj, _event): + cnt = next(counter) + showm.render() + if cnt == 0: + scene.set_camera(position=(1.5, 3.5, 7.0)) + if cnt < 200 and cnt > 25: + scene.zoom(1.015) + scene.pitch(0.01) + if cnt == 200: + scene.add(nyc_actor) + if cnt > 250 and cnt < 350: + scene.zoom(0.985) + if cnt > 350 and cnt < 425: + scene.azimuth(1) + if cnt > 425 and cnt < 525: + scene.zoom(1.015) + scene.pitch(0.011) + if cnt == 525: + scene.add(paris_actor) + if cnt > 575 and cnt < 700: + scene.zoom(0.985) + if cnt > 700 and cnt < 820: + scene.azimuth(1) + if cnt > 820 and cnt < 930: + scene.zoom(1.015) + if cnt == 930: + scene.add(beijing_actor) + if cnt == 1000: + showm.exit() + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 153-155 + +Initialize the ShowManager object, add the timer_callback, and watch the +new animation take place! + +.. GENERATED FROM PYTHON SOURCE LINES 155-161 + +.. code-block:: Python + + + + showm.add_timer_callback(True, 25, timer_callback) + showm.start() + + window.record(showm.scene, size=(900, 768), out_path='viz_earth_coordinates.png') + + + +.. image-sg:: /auto_examples/01_introductory/images/sphx_glr_viz_earth_coordinates_001.png + :alt: viz earth coordinates + :srcset: /auto_examples/01_introductory/images/sphx_glr_viz_earth_coordinates_001.png + :class: sphx-glr-single-img + + + + + + +.. rst-class:: sphx-glr-timing + + **Total running time of the script:** (0 minutes 27.806 seconds) + + +.. _sphx_glr_download_auto_examples_01_introductory_viz_earth_coordinates.py: + +.. only:: html + + .. container:: sphx-glr-footer sphx-glr-footer-example + + .. container:: sphx-glr-download sphx-glr-download-jupyter + + :download:`Download Jupyter notebook: viz_earth_coordinates.ipynb ` + + .. container:: sphx-glr-download sphx-glr-download-python + + :download:`Download Python source code: viz_earth_coordinates.py ` + + +.. only:: html + + .. rst-class:: sphx-glr-signature + + `Gallery generated by Sphinx-Gallery `_ diff --git a/v0.10.x/_sources/auto_examples/01_introductory/viz_gltf.rst.txt b/v0.10.x/_sources/auto_examples/01_introductory/viz_gltf.rst.txt new file mode 100644 index 000000000..d06fa07d9 --- /dev/null +++ b/v0.10.x/_sources/auto_examples/01_introductory/viz_gltf.rst.txt @@ -0,0 +1,175 @@ + +.. DO NOT EDIT. +.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. +.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: +.. "auto_examples/01_introductory/viz_gltf.py" +.. LINE NUMBERS ARE GIVEN BELOW. + +.. only:: html + + .. note:: + :class: sphx-glr-download-link-note + + :ref:`Go to the end ` + to download the full example code + +.. rst-class:: sphx-glr-example-title + +.. _sphx_glr_auto_examples_01_introductory_viz_gltf.py: + + +======================= +Visualizing a glTF file +======================= +In this tutorial, we will show how to display a glTF file in a scene. + +.. GENERATED FROM PYTHON SOURCE LINES 7-12 + +.. code-block:: Python + + + from fury import window + from fury.data import fetch_gltf, read_viz_gltf + from fury.gltf import glTF + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 13-14 + +Create a scene. + +.. GENERATED FROM PYTHON SOURCE LINES 14-18 + +.. code-block:: Python + + + scene = window.Scene() + scene.SetBackground(0.1, 0.1, 0.4) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 19-20 + +Retrieving the gltf model. + +.. GENERATED FROM PYTHON SOURCE LINES 20-23 + +.. code-block:: Python + + fetch_gltf('Duck', 'glTF') + filename = read_viz_gltf('Duck') + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 24-28 + +Initialize the glTF object and get actors using `actors` method. +Note: You can always manually create actor from polydata, and apply texture +or materials manually afterwards. +Experimental: For smooth mesh/actor you can set `apply_normals=True`. + +.. GENERATED FROM PYTHON SOURCE LINES 28-32 + +.. code-block:: Python + + + gltf_obj = glTF(filename, apply_normals=False) + actors = gltf_obj.actors() + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 33-34 + +Add all the actor from list of actors to the scene. + +.. GENERATED FROM PYTHON SOURCE LINES 34-37 + +.. code-block:: Python + + + scene.add(*actors) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 38-39 + +Applying camera + +.. GENERATED FROM PYTHON SOURCE LINES 39-50 + +.. code-block:: Python + + + cameras = gltf_obj.cameras + if cameras: + scene.SetActiveCamera(cameras[0]) + + interactive = False + + if interactive: + window.show(scene, size=(1280, 720)) + + window.record(scene, out_path='viz_gltf.png', size=(1280, 720)) + + + +.. image-sg:: /auto_examples/01_introductory/images/sphx_glr_viz_gltf_001.png + :alt: viz gltf + :srcset: /auto_examples/01_introductory/images/sphx_glr_viz_gltf_001.png + :class: sphx-glr-single-img + + + + + + +.. rst-class:: sphx-glr-timing + + **Total running time of the script:** (0 minutes 0.135 seconds) + + +.. _sphx_glr_download_auto_examples_01_introductory_viz_gltf.py: + +.. only:: html + + .. container:: sphx-glr-footer sphx-glr-footer-example + + .. container:: sphx-glr-download sphx-glr-download-jupyter + + :download:`Download Jupyter notebook: viz_gltf.ipynb ` + + .. container:: sphx-glr-download sphx-glr-download-python + + :download:`Download Python source code: viz_gltf.py ` + + +.. only:: html + + .. rst-class:: sphx-glr-signature + + `Gallery generated by Sphinx-Gallery `_ diff --git a/v0.10.x/_sources/auto_examples/01_introductory/viz_gltf_animated.rst.txt b/v0.10.x/_sources/auto_examples/01_introductory/viz_gltf_animated.rst.txt new file mode 100644 index 000000000..61be9123b --- /dev/null +++ b/v0.10.x/_sources/auto_examples/01_introductory/viz_gltf_animated.rst.txt @@ -0,0 +1,183 @@ + +.. DO NOT EDIT. +.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. +.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: +.. "auto_examples/01_introductory/viz_gltf_animated.py" +.. LINE NUMBERS ARE GIVEN BELOW. + +.. only:: html + + .. note:: + :class: sphx-glr-download-link-note + + :ref:`Go to the end ` + to download the full example code + +.. rst-class:: sphx-glr-example-title + +.. _sphx_glr_auto_examples_01_introductory_viz_gltf_animated.py: + + +======================= +Visualizing a glTF file +======================= +In this tutorial, we will show how to display a simple animated glTF in a +scene. + +.. GENERATED FROM PYTHON SOURCE LINES 8-13 + +.. code-block:: Python + + + from fury import window + from fury.data import fetch_gltf, read_viz_gltf + from fury.gltf import glTF + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 14-15 + +Create a scene. + +.. GENERATED FROM PYTHON SOURCE LINES 15-24 + +.. code-block:: Python + + + scene = window.Scene() + + showm = window.ShowManager( + scene, size=(900, 768), reset_camera=False, order_transparent=True + ) + showm.initialize() + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 25-26 + +Retrieving the gltf model. + +.. GENERATED FROM PYTHON SOURCE LINES 26-29 + +.. code-block:: Python + + fetch_gltf('InterpolationTest', 'glTF') + filename = read_viz_gltf('InterpolationTest') + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 30-32 + +Initialize the glTF object and get actors using `actors` method. +Get the main_timeline (which contains multiple Timeline objects). + +.. GENERATED FROM PYTHON SOURCE LINES 32-36 + +.. code-block:: Python + + + gltf_obj = glTF(filename) + timeline = gltf_obj.main_animation() + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 37-38 + +Add the timeline to the scene (No need to add actors separately). + +.. GENERATED FROM PYTHON SOURCE LINES 38-41 + +.. code-block:: Python + + + scene.add(timeline) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 42-43 + +define a timer_callback that updates the timeline. + +.. GENERATED FROM PYTHON SOURCE LINES 43-58 + +.. code-block:: Python + + + interactive = False + + + def timer_callback(_obj, _event): + timeline.update_animation() + showm.render() + + + showm.add_timer_callback(True, 10, timer_callback) + + if interactive: + showm.start() + + window.record(scene, out_path='viz_gltf_animated.png', size=(900, 768)) + + + +.. image-sg:: /auto_examples/01_introductory/images/sphx_glr_viz_gltf_animated_001.png + :alt: viz gltf animated + :srcset: /auto_examples/01_introductory/images/sphx_glr_viz_gltf_animated_001.png + :class: sphx-glr-single-img + + + + + + +.. rst-class:: sphx-glr-timing + + **Total running time of the script:** (0 minutes 0.156 seconds) + + +.. _sphx_glr_download_auto_examples_01_introductory_viz_gltf_animated.py: + +.. only:: html + + .. container:: sphx-glr-footer sphx-glr-footer-example + + .. container:: sphx-glr-download sphx-glr-download-jupyter + + :download:`Download Jupyter notebook: viz_gltf_animated.ipynb ` + + .. container:: sphx-glr-download sphx-glr-download-python + + :download:`Download Python source code: viz_gltf_animated.py ` + + +.. only:: html + + .. rst-class:: sphx-glr-signature + + `Gallery generated by Sphinx-Gallery `_ diff --git a/v0.10.x/_sources/auto_examples/01_introductory/viz_gltf_export.rst.txt b/v0.10.x/_sources/auto_examples/01_introductory/viz_gltf_export.rst.txt new file mode 100644 index 000000000..6166c4bc1 --- /dev/null +++ b/v0.10.x/_sources/auto_examples/01_introductory/viz_gltf_export.rst.txt @@ -0,0 +1,224 @@ + +.. DO NOT EDIT. +.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. +.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: +.. "auto_examples/01_introductory/viz_gltf_export.py" +.. LINE NUMBERS ARE GIVEN BELOW. + +.. only:: html + + .. note:: + :class: sphx-glr-download-link-note + + :ref:`Go to the end ` + to download the full example code + +.. rst-class:: sphx-glr-example-title + +.. _sphx_glr_auto_examples_01_introductory_viz_gltf_export.py: + + +============================== +Exporting scene as a glTF file +============================== +In this tutorial, we will show how to create a glTF file for a scene. + +.. GENERATED FROM PYTHON SOURCE LINES 7-12 + +.. code-block:: Python + + import numpy as np + + from fury import actor, gltf, window + from fury.data import fetch_gltf, read_viz_gltf + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 13-15 + +Specifying centers and colors for actors. We will use these parameters +later. + +.. GENERATED FROM PYTHON SOURCE LINES 15-19 + +.. code-block:: Python + + + centers = np.zeros((3, 3)) + colors = np.array([1, 1, 1]) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 20-21 + +Create a scene. + +.. GENERATED FROM PYTHON SOURCE LINES 21-24 + +.. code-block:: Python + + + scene = window.Scene() + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 25-26 + +Creating actors and adding to scene. + +.. GENERATED FROM PYTHON SOURCE LINES 26-39 + +.. code-block:: Python + + + cube = actor.cube(np.add(centers, np.array([2, 0, 0])), colors=colors / 2) + scene.add(cube) + + sphere = actor.sphere(np.add(centers, np.array([0, 2, 0])), colors=colors) + scene.add(sphere) + + fetch_gltf('BoxTextured', 'glTF') + filename = read_viz_gltf('BoxTextured') + gltf_obj = gltf.glTF(filename) + box_actor = gltf_obj.actors() + scene.add(box_actor[0]) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 40-41 + +Setting camera to the scene. + +.. GENERATED FROM PYTHON SOURCE LINES 41-46 + +.. code-block:: Python + + + scene.set_camera( + position=(4.45, -21, 12), focal_point=(4.45, 0.0, 0.0), view_up=(0.0, 0.0, 1.0) + ) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 47-48 + +Exporting scene as a glTF file + +.. GENERATED FROM PYTHON SOURCE LINES 48-51 + +.. code-block:: Python + + + gltf.export_scene(scene, filename='viz_gltf_export.gltf') + + + + +.. image-sg:: /auto_examples/01_introductory/images/sphx_glr_viz_gltf_export_001.png + :alt: viz gltf export + :srcset: /auto_examples/01_introductory/images/sphx_glr_viz_gltf_export_001.png + :class: sphx-glr-single-img + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 52-53 + +Reading the newly created glTF file and get actors. + +.. GENERATED FROM PYTHON SOURCE LINES 53-57 + +.. code-block:: Python + + + gltf_obj = gltf.glTF('viz_gltf_export.gltf') + actors = gltf_obj.actors() + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 58-59 + +Add all the actor from list of actors to the scene. + +.. GENERATED FROM PYTHON SOURCE LINES 59-68 + +.. code-block:: Python + + + scene.add(*actors) + + interactive = False + + if interactive: + window.show(scene, size=(1280, 720)) + + window.record(scene, out_path='viz_gltf_export.png', size=(1280, 720)) + + + +.. image-sg:: /auto_examples/01_introductory/images/sphx_glr_viz_gltf_export_002.png + :alt: viz gltf export + :srcset: /auto_examples/01_introductory/images/sphx_glr_viz_gltf_export_002.png + :class: sphx-glr-single-img + + + + + + +.. rst-class:: sphx-glr-timing + + **Total running time of the script:** (0 minutes 0.120 seconds) + + +.. _sphx_glr_download_auto_examples_01_introductory_viz_gltf_export.py: + +.. only:: html + + .. container:: sphx-glr-footer sphx-glr-footer-example + + .. container:: sphx-glr-download sphx-glr-download-jupyter + + :download:`Download Jupyter notebook: viz_gltf_export.ipynb ` + + .. container:: sphx-glr-download sphx-glr-download-python + + :download:`Download Python source code: viz_gltf_export.py ` + + +.. only:: html + + .. rst-class:: sphx-glr-signature + + `Gallery generated by Sphinx-Gallery `_ diff --git a/v0.10.x/_sources/auto_examples/01_introductory/viz_morphing.rst.txt b/v0.10.x/_sources/auto_examples/01_introductory/viz_morphing.rst.txt new file mode 100644 index 000000000..da021a833 --- /dev/null +++ b/v0.10.x/_sources/auto_examples/01_introductory/viz_morphing.rst.txt @@ -0,0 +1,226 @@ + +.. DO NOT EDIT. +.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. +.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: +.. "auto_examples/01_introductory/viz_morphing.py" +.. LINE NUMBERS ARE GIVEN BELOW. + +.. only:: html + + .. note:: + :class: sphx-glr-download-link-note + + :ref:`Go to the end ` + to download the full example code + +.. rst-class:: sphx-glr-example-title + +.. _sphx_glr_auto_examples_01_introductory_viz_morphing.py: + + +============================ +Morphing Animation in a glTF +============================ +In this tutorial, we will show how to use morphing in a glTF model in FURY. + +.. GENERATED FROM PYTHON SOURCE LINES 7-12 + +.. code-block:: Python + + + from fury import window + from fury.data import fetch_gltf, read_viz_gltf + from fury.gltf import glTF + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 13-15 + +Retrieving the model with morphing in it (look at Khronoos samples). +We're choosing the `MorphStressTest` model here. + +.. GENERATED FROM PYTHON SOURCE LINES 15-19 + +.. code-block:: Python + + + fetch_gltf('MorphStressTest', 'glTF') + filename = read_viz_gltf('MorphStressTest') + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 20-22 + +Initializing the glTF object, You can additionally set `apply_normals=True`. +Note: Normals might not work as intended with morphing. + +.. GENERATED FROM PYTHON SOURCE LINES 22-25 + +.. code-block:: Python + + + gltf_obj = glTF(filename, apply_normals=True) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 26-29 + +Get the morph timeline using `morph_timeline` method, Choose the animation +name you want to visualize. +Note: If there's no name for animation, It's stored as `anim_0`, `anim_1` etc + +.. GENERATED FROM PYTHON SOURCE LINES 29-32 + +.. code-block:: Python + + + animation = gltf_obj.morph_animation()['TheWave'] + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 33-35 + +Call the `update_morph` method once, This moves initialise the morphing at +timestamp 0.0 seconds and ensures that camera fits all the actors perfectly. + +.. GENERATED FROM PYTHON SOURCE LINES 35-38 + +.. code-block:: Python + + + gltf_obj.update_morph(animation) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 39-42 + +Create a scene, and show manager. +Initialize the show manager and add timeline to the scene (No need to add +actors to the scene separately). + +.. GENERATED FROM PYTHON SOURCE LINES 42-51 + +.. code-block:: Python + + + scene = window.Scene() + showm = window.ShowManager( + scene, size=(900, 768), reset_camera=True, order_transparent=True + ) + + showm.initialize() + scene.add(animation) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 52-55 + +define a timer_callback. +Use the `update_morph` method again, It updates the timeline and applies +morphing). + +.. GENERATED FROM PYTHON SOURCE LINES 55-62 + +.. code-block:: Python + + + + def timer_callback(_obj, _event): + gltf_obj.update_morph(animation) + showm.render() + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 63-64 + +Optional: `timeline.play()` auto plays the animations. + +.. GENERATED FROM PYTHON SOURCE LINES 64-75 + +.. code-block:: Python + + + + showm.add_timer_callback(True, 20, timer_callback) + scene.reset_camera() + + interactive = False + + if interactive: + showm.start() + + window.record(scene, out_path='viz_morphing.png', size=(900, 768)) + + + +.. image-sg:: /auto_examples/01_introductory/images/sphx_glr_viz_morphing_001.png + :alt: viz morphing + :srcset: /auto_examples/01_introductory/images/sphx_glr_viz_morphing_001.png + :class: sphx-glr-single-img + + + + + + +.. rst-class:: sphx-glr-timing + + **Total running time of the script:** (0 minutes 0.165 seconds) + + +.. _sphx_glr_download_auto_examples_01_introductory_viz_morphing.py: + +.. only:: html + + .. container:: sphx-glr-footer sphx-glr-footer-example + + .. container:: sphx-glr-download sphx-glr-download-jupyter + + :download:`Download Jupyter notebook: viz_morphing.ipynb ` + + .. container:: sphx-glr-download sphx-glr-download-python + + :download:`Download Python source code: viz_morphing.py ` + + +.. only:: html + + .. rst-class:: sphx-glr-signature + + `Gallery generated by Sphinx-Gallery `_ diff --git a/v0.10.x/_sources/auto_examples/01_introductory/viz_multithread.rst.txt b/v0.10.x/_sources/auto_examples/01_introductory/viz_multithread.rst.txt new file mode 100644 index 000000000..980d6edc6 --- /dev/null +++ b/v0.10.x/_sources/auto_examples/01_introductory/viz_multithread.rst.txt @@ -0,0 +1,180 @@ + +.. DO NOT EDIT. +.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. +.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: +.. "auto_examples/01_introductory/viz_multithread.py" +.. LINE NUMBERS ARE GIVEN BELOW. + +.. only:: html + + .. note:: + :class: sphx-glr-download-link-note + + :ref:`Go to the end ` + to download the full example code + +.. rst-class:: sphx-glr-example-title + +.. _sphx_glr_auto_examples_01_introductory_viz_multithread.py: + + +======================================================= +Multithreading Example +======================================================= + +The goal of this demo is to show how to use different threads +to interact with FURY. In particular, the main thread is used +to update interactions and render the scene, while thread A +rotates the camera, thread B prints a counter, and thread C +adds and removes elements from the scene. + +.. GENERATED FROM PYTHON SOURCE LINES 12-114 + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + + Counter: 0 Counter: 1 Counter: 2 Counter: 3 Counter: 4 Counter: 5 Counter: 6 Counter: 7 Counter: 8 Counter: 9 Counter: 10 Counter: 11 Counter: 12 Counter: 13 Counter: 14 Counter: 15 Counter: 16 Counter: 17 Counter: 18 Counter: 19 Counter: 20 Counter: 21 Counter: 22 Counter: 23 Counter: 24 Counter: 25 Counter: 26 Counter: 27 Counter: 28 Counter: 29 Counter: 30 Counter: 31 Counter: 32 Counter: 33 Counter: 34 Counter: 35 Counter: 36 Counter: 37 Counter: 38 Counter: 39 Counter: 40 Counter: 41 Counter: 42 Counter: 43 Counter: 44 Counter: 45 Counter: 46 Counter: 47 Counter: 48 Counter: 49 Counter: 50 Counter: 51 Counter: 52 Counter: 53 Counter: 54 Counter: 55 Counter: 56 Counter: 57 Counter: 58 Counter: 59 Counter: 60 Counter: 61 Counter: 62 Counter: 63 Counter: 64 Counter: 65 Counter: 66 Counter: 67 Counter: 68 Counter: 69 Counter: 70 Counter: 71 Counter: 72 Counter: 73 Counter: 74 Counter: 75 Counter: 76 Counter: 77 Counter: 78 Counter: 79 Counter: 80 Counter: 81 Counter: 82 Counter: 83 Counter: 84 Counter: 85 Counter: 86 Counter: 87 Counter: 88 Counter: 89 Counter: 90 Counter: 91 Counter: 92 Counter: 93 Counter: 94 Counter: 95 Counter: 96 Counter: 97 Counter: 98 Counter: 99 + + + + + + +| + +.. code-block:: Python + + + import time + from threading import Thread + + import numpy as np + + from fury import actor, ui, window + + # Preparing to draw some spheres + xyz = 10 * (np.random.random((100, 3)) - 0.5) + colors = np.random.random((100, 4)) + radii = np.random.random(100) + 0.5 + + scene = window.Scene() + sphere_actor = actor.sphere( + centers=xyz, colors=colors, radii=radii, use_primitive=False + ) + scene.add(sphere_actor) + + + # Preparing the show manager as usual + showm = window.ShowManager( + scene, size=(900, 768), reset_camera=False, order_transparent=True + ) + + # showm.initialize() + + # Creating a text block to show a message and reset the camera + tb = ui.TextBlock2D(bold=True) + scene.add(tb) + scene.ResetCamera() + + + # Create a function to print a counter to the console + def print_counter(): + print('') + for i in range(100): + print('\rCounter: %d' % i, end='') + message = "Let's count up to 100 and exit :" + str(i + 1) + tb.message = message + time.sleep(0.05) + if showm.is_done(): + break + showm.exit() + print('') + + + # Create a function to rotate the camera + + + def rotate_camera(): + for i in range(100): + if showm.lock_current(): + scene.azimuth(0.01 * i) + showm.release_current() + time.sleep(0.05) + else: + break + + + # Create a function to add or remove the axes and increase its scale + + + def add_remove_axes(): + current_axes = None + for i in range(100): + if showm.lock_current(): + if current_axes is None: + current_axes = actor.axes(scale=(0.20 * i, 0.20 * i, 0.20 * i)) + scene.add(current_axes) + pass + else: + scene.rm(current_axes) + current_axes = None + pass + showm.release_current() + time.sleep(0.1) + else: + break + + + # Start the threads + # Multiple threads can be started here + # First, one to rotate the camera + thread_a = Thread(target=rotate_camera) + thread_a.start() + + # Now let's start a thread that will print a counter + thread_b = Thread(target=print_counter) + thread_b.start() + + # Now let's start a thread that will add or remove axes + thread_c = Thread(target=add_remove_axes) + thread_c.start() + + # Let's start the show manager loop with multithreading option + showm.start(multithreaded=True) + + # Wait for the threads to finish + thread_a.join() + thread_b.join() + thread_c.join() + + +.. rst-class:: sphx-glr-timing + + **Total running time of the script:** (0 minutes 5.510 seconds) + + +.. _sphx_glr_download_auto_examples_01_introductory_viz_multithread.py: + +.. only:: html + + .. container:: sphx-glr-footer sphx-glr-footer-example + + .. container:: sphx-glr-download sphx-glr-download-jupyter + + :download:`Download Jupyter notebook: viz_multithread.ipynb ` + + .. container:: sphx-glr-download sphx-glr-download-python + + :download:`Download Python source code: viz_multithread.py ` + + +.. only:: html + + .. rst-class:: sphx-glr-signature + + `Gallery generated by Sphinx-Gallery `_ diff --git a/v0.10.x/_sources/auto_examples/01_introductory/viz_picking.rst.txt b/v0.10.x/_sources/auto_examples/01_introductory/viz_picking.rst.txt new file mode 100644 index 000000000..67c529357 --- /dev/null +++ b/v0.10.x/_sources/auto_examples/01_introductory/viz_picking.rst.txt @@ -0,0 +1,383 @@ + +.. DO NOT EDIT. +.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. +.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: +.. "auto_examples/01_introductory/viz_picking.py" +.. LINE NUMBERS ARE GIVEN BELOW. + +.. only:: html + + .. note:: + :class: sphx-glr-download-link-note + + :ref:`Go to the end ` + to download the full example code + +.. rst-class:: sphx-glr-example-title + +.. _sphx_glr_auto_examples_01_introductory_viz_picking.py: + + +===================== +Simple picking +===================== + +Here we present a tutorial showing how to interact with objects in the +3D world. All objects to be picked are part of a single actor. +FURY likes to bundle objects in a few actors to reduce code and +increase speed. + +When the objects are picked they will change size and color. + +.. GENERATED FROM PYTHON SOURCE LINES 13-24 + +.. code-block:: Python + + + import numpy as np + + from fury import actor, pick, ui, utils, window + + centers = 0.5 * np.array([[0, 0, 0], [100, 0, 0], [200, 0, 0.0]]) + colors = np.array([[0.8, 0, 0], [0, 0.8, 0], [0, 0, 0.8]]) + radii = 0.1 * np.array([50, 100, 150.0]) + + selected = np.zeros(3, dtype=bool) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 25-26 + +Let's create a panel to show what is picked + +.. GENERATED FROM PYTHON SOURCE LINES 26-33 + +.. code-block:: Python + + + panel = ui.Panel2D(size=(400, 200), color=(1, 0.5, 0.0), align='right') + panel.center = (150, 200) + + text_block = ui.TextBlock2D(text='Left click on object \n') + panel.add_element(text_block, (0.3, 0.3)) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 34-35 + +Build scene and add an actor with many objects. + +.. GENERATED FROM PYTHON SOURCE LINES 35-40 + +.. code-block:: Python + + + scene = window.Scene() + + label_actor = actor.vector_text(text='Test') + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 41-42 + +This actor is made with 3 cubes of different orientation + +.. GENERATED FROM PYTHON SOURCE LINES 42-52 + +.. code-block:: Python + + + directions = np.array( + [ + [np.sqrt(2) / 2, 0, np.sqrt(2) / 2], + [np.sqrt(2) / 2, np.sqrt(2) / 2, 0], + [0, np.sqrt(2) / 2, np.sqrt(2) / 2], + ] + ) + fury_actor = actor.cube(centers, directions, colors, scales=radii) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 53-54 + +Access the memory of the vertices of all the cubes + +.. GENERATED FROM PYTHON SOURCE LINES 54-59 + +.. code-block:: Python + + + vertices = utils.vertices_from_actor(fury_actor) + num_vertices = vertices.shape[0] + num_objects = centers.shape[0] + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 60-61 + +Access the memory of the colors of all the cubes + +.. GENERATED FROM PYTHON SOURCE LINES 61-64 + +.. code-block:: Python + + + vcolors = utils.colors_from_actor(fury_actor, 'colors') + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 65-66 + +Adding an actor showing the axes of the world coordinates + +.. GENERATED FROM PYTHON SOURCE LINES 66-73 + +.. code-block:: Python + + ax = actor.axes(scale=(10, 10, 10)) + + scene.add(fury_actor) + scene.add(label_actor) + scene.add(ax) + scene.reset_camera() + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 74-75 + +Create the Picking manager + +.. GENERATED FROM PYTHON SOURCE LINES 75-78 + +.. code-block:: Python + + + pickm = pick.PickingManager() + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 79-80 + +Time to make the callback which will be called when we pick an object + +.. GENERATED FROM PYTHON SOURCE LINES 80-135 + +.. code-block:: Python + + + + def left_click_callback(obj, event): + + # Get the event position on display and pick + + event_pos = pickm.event_position(showm.iren) + picked_info = pickm.pick(event_pos, showm.scene) + + vertex_index = picked_info['vertex'] + + # Calculate the objects index + + object_index = int(np.floor((vertex_index / num_vertices) * num_objects)) + + # Find how many vertices correspond to each object + sec = int(num_vertices / num_objects) + + if not selected[object_index]: + scale = 6 / 5 + color_add = np.array([30, 30, 30], dtype='uint8') + selected[object_index] = True + else: + scale = 5 / 6 + color_add = np.array([-30, -30, -30], dtype='uint8') + selected[object_index] = False + + # Update vertices positions + vertices[object_index * sec : object_index * sec + sec] = ( + scale + * ( + vertices[object_index * sec : object_index * sec + sec] + - centers[object_index] + ) + + centers[object_index] + ) + + # Update colors + vcolors[object_index * sec : object_index * sec + sec] += color_add + + # Tell actor that memory is modified + utils.update_actor(fury_actor) + + face_index = picked_info['face'] + + # Show some info + text = 'Object ' + str(object_index) + '\n' + text += 'Vertex ID ' + str(vertex_index) + '\n' + text += 'Face ID ' + str(face_index) + '\n' + text += 'World pos ' + str(np.round(picked_info['xyz'], 2)) + '\n' + text += 'Actor ID ' + str(id(picked_info['actor'])) + text_block.message = text + showm.render() + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 136-137 + +Bind the callback to the actor + +.. GENERATED FROM PYTHON SOURCE LINES 137-140 + +.. code-block:: Python + + + fury_actor.AddObserver('LeftButtonPressEvent', left_click_callback, 1) + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + + 1 + + + +.. GENERATED FROM PYTHON SOURCE LINES 141-142 + +Make the window appear + +.. GENERATED FROM PYTHON SOURCE LINES 142-147 + +.. code-block:: Python + + + showm = window.ShowManager(scene, size=(1024, 768), order_transparent=True) + + scene.add(panel) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 148-149 + +Change interactive to True to start interacting with the scene + +.. GENERATED FROM PYTHON SOURCE LINES 149-157 + +.. code-block:: Python + + + interactive = False + + if interactive: + + showm.start() + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 158-159 + +Save the current framebuffer in a PNG file + +.. GENERATED FROM PYTHON SOURCE LINES 159-161 + +.. code-block:: Python + + + window.record(showm.scene, size=(1024, 768), out_path='viz_picking.png') + + + +.. image-sg:: /auto_examples/01_introductory/images/sphx_glr_viz_picking_001.png + :alt: viz picking + :srcset: /auto_examples/01_introductory/images/sphx_glr_viz_picking_001.png + :class: sphx-glr-single-img + + + + + + +.. rst-class:: sphx-glr-timing + + **Total running time of the script:** (0 minutes 0.085 seconds) + + +.. _sphx_glr_download_auto_examples_01_introductory_viz_picking.py: + +.. only:: html + + .. container:: sphx-glr-footer sphx-glr-footer-example + + .. container:: sphx-glr-download sphx-glr-download-jupyter + + :download:`Download Jupyter notebook: viz_picking.ipynb ` + + .. container:: sphx-glr-download sphx-glr-download-python + + :download:`Download Python source code: viz_picking.py ` + + +.. only:: html + + .. rst-class:: sphx-glr-signature + + `Gallery generated by Sphinx-Gallery `_ diff --git a/v0.10.x/_sources/auto_examples/01_introductory/viz_selection.rst.txt b/v0.10.x/_sources/auto_examples/01_introductory/viz_selection.rst.txt new file mode 100644 index 000000000..9dec0639d --- /dev/null +++ b/v0.10.x/_sources/auto_examples/01_introductory/viz_selection.rst.txt @@ -0,0 +1,385 @@ + +.. DO NOT EDIT. +.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. +.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: +.. "auto_examples/01_introductory/viz_selection.py" +.. LINE NUMBERS ARE GIVEN BELOW. + +.. only:: html + + .. note:: + :class: sphx-glr-download-link-note + + :ref:`Go to the end ` + to download the full example code + +.. rst-class:: sphx-glr-example-title + +.. _sphx_glr_auto_examples_01_introductory_viz_selection.py: + + +========================== +Selecting multiple objects +========================== + +Here we show how to select objects in the +3D world. In this example all objects to be picked are part of +a single actor. + +FURY likes to bundle objects in a few actors to reduce code and +increase speed. Nonetheless the method works for multiple actors too. + +The difference with the picking tutorial is that here we will +be able to select more than one object. In addition we can +select interactively many vertices or faces. + +In summary, we will create an actor with thousands of cubes and +then interactively we will be moving a rectangular box by +hovering the mouse and making transparent everything that is +behind that box. + +.. GENERATED FROM PYTHON SOURCE LINES 22-27 + +.. code-block:: Python + + + import numpy as np + + from fury import actor, pick, utils, window + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 28-29 + +Adding many cubes of different sizes and colors + +.. GENERATED FROM PYTHON SOURCE LINES 29-37 + +.. code-block:: Python + + + num_cubes = 50000 + + centers = 10000 * (np.random.rand(num_cubes, 3) - 0.5) + colors = np.random.rand(num_cubes, 4) + colors[:, 3] = 1.0 + radii = 100 * np.random.rand(num_cubes) + 0.1 + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 38-41 + +Keep track of total number of triangle faces +Note that every quad of each cube has 2 triangles +and each cube has 6 quads in total. + +.. GENERATED FROM PYTHON SOURCE LINES 41-44 + +.. code-block:: Python + + + num_faces = num_cubes * 6 * 2 + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 45-46 + +Build scene and add an actor with many objects. + +.. GENERATED FROM PYTHON SOURCE LINES 46-49 + +.. code-block:: Python + + + scene = window.Scene() + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 50-51 + +Build the actor containing all the cubes + +.. GENERATED FROM PYTHON SOURCE LINES 51-54 + +.. code-block:: Python + + + cube_actor = actor.cube(centers, directions=(1, 0, 0), colors=colors, scales=radii) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 55-56 + +Access the memory of the vertices of all the cubes + +.. GENERATED FROM PYTHON SOURCE LINES 56-61 + +.. code-block:: Python + + + vertices = utils.vertices_from_actor(cube_actor) + num_vertices = vertices.shape[0] + num_objects = centers.shape[0] + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 62-63 + +Access the memory of the colors of all the cubes + +.. GENERATED FROM PYTHON SOURCE LINES 63-66 + +.. code-block:: Python + + + vcolors = utils.colors_from_actor(cube_actor, 'colors') + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 67-68 + +Create a rectangular 2d box as a texture + +.. GENERATED FROM PYTHON SOURCE LINES 68-78 + +.. code-block:: Python + + + rgba = 255 * np.ones((100, 200, 4)) + rgba[1:-1, 1:-1] = np.zeros((98, 198, 4)) + 100 + texa = actor.texture_2d(rgba.astype(np.uint8)) + + scene.add(cube_actor) + scene.add(texa) + scene.reset_camera() + scene.zoom(3.0) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 79-80 + +Create the Selection Manager + +.. GENERATED FROM PYTHON SOURCE LINES 80-83 + +.. code-block:: Python + + + selm = pick.SelectionManager(select='faces') + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 84-85 + +Tell Selection Manager to avoid selecting specific actors + +.. GENERATED FROM PYTHON SOURCE LINES 85-88 + +.. code-block:: Python + + + selm.selectable_off(texa) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 89-91 + +Let's make the callback which will be called +when we hover the mouse + +.. GENERATED FROM PYTHON SOURCE LINES 91-116 + +.. code-block:: Python + + + + def hover_callback(_obj, _event): + event_pos = selm.event_position(showm.iren) + # updates rectangular box around mouse + texa.SetPosition(event_pos[0] - 200 // 2, event_pos[1] - 100 // 2) + + # defines selection region and returns information from selected objects + info = selm.select(event_pos, showm.scene, (200 // 2, 100 // 2)) + for node in info.keys(): + if info[node]['face'] is not None: + if info[node]['actor'] is cube_actor: + for face_index in info[node]['face']: + # generates an object_index to help with coloring + # by dividing by the number of faces of each cube (6 * 2) + object_index = face_index // 12 + sec = int(num_vertices / num_objects) + color_change = np.array([150, 0, 0, 255], dtype='uint8') + vcolors[ + object_index * sec : object_index * sec + sec + ] = color_change + utils.update_actor(cube_actor) + showm.render() + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 117-118 + +Make the window appear + +.. GENERATED FROM PYTHON SOURCE LINES 118-124 + +.. code-block:: Python + + + showm = window.ShowManager( + scene, size=(1024, 768), order_transparent=True, reset_camera=False + ) + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 125-126 + +Bind the callback to the actor + +.. GENERATED FROM PYTHON SOURCE LINES 126-129 + +.. code-block:: Python + + + showm.add_iren_callback(hover_callback) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 130-131 + +Change interactive to True to start interacting with the scene + +.. GENERATED FROM PYTHON SOURCE LINES 131-139 + +.. code-block:: Python + + + interactive = False + + if interactive: + + showm.start() + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 140-141 + +Save the current framebuffer in a PNG file + +.. GENERATED FROM PYTHON SOURCE LINES 141-143 + +.. code-block:: Python + + + window.record(showm.scene, size=(1024, 768), out_path='viz_selection.png') + + + +.. image-sg:: /auto_examples/01_introductory/images/sphx_glr_viz_selection_001.png + :alt: viz selection + :srcset: /auto_examples/01_introductory/images/sphx_glr_viz_selection_001.png + :class: sphx-glr-single-img + + + + + + +.. rst-class:: sphx-glr-timing + + **Total running time of the script:** (0 minutes 1.308 seconds) + + +.. _sphx_glr_download_auto_examples_01_introductory_viz_selection.py: + +.. only:: html + + .. container:: sphx-glr-footer sphx-glr-footer-example + + .. container:: sphx-glr-download sphx-glr-download-jupyter + + :download:`Download Jupyter notebook: viz_selection.ipynb ` + + .. container:: sphx-glr-download sphx-glr-download-python + + :download:`Download Python source code: viz_selection.py ` + + +.. only:: html + + .. rst-class:: sphx-glr-signature + + `Gallery generated by Sphinx-Gallery `_ diff --git a/v0.10.x/_sources/auto_examples/01_introductory/viz_skinning.rst.txt b/v0.10.x/_sources/auto_examples/01_introductory/viz_skinning.rst.txt new file mode 100644 index 000000000..176545a34 --- /dev/null +++ b/v0.10.x/_sources/auto_examples/01_introductory/viz_skinning.rst.txt @@ -0,0 +1,215 @@ + +.. DO NOT EDIT. +.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. +.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: +.. "auto_examples/01_introductory/viz_skinning.py" +.. LINE NUMBERS ARE GIVEN BELOW. + +.. only:: html + + .. note:: + :class: sphx-glr-download-link-note + + :ref:`Go to the end ` + to download the full example code + +.. rst-class:: sphx-glr-example-title + +.. _sphx_glr_auto_examples_01_introductory_viz_skinning.py: + + +================================= +Skeletal Animation in a glTF file +================================= +In this tutorial, we will show how to use skeletal animations (skinning) in a +glTF model in FURY. + +.. GENERATED FROM PYTHON SOURCE LINES 8-13 + +.. code-block:: Python + + + from fury import window + from fury.data import fetch_gltf, read_viz_gltf + from fury.gltf import glTF + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 14-16 + +Retrieving the model with skeletal animations. +We're choosing the `RiggedFigure` model here. + +.. GENERATED FROM PYTHON SOURCE LINES 16-20 + +.. code-block:: Python + + + fetch_gltf('RiggedFigure', 'glTF') + filename = read_viz_gltf('RiggedFigure') + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 21-23 + +Initializing the glTF object, You can additionally set `apply_normals=True`. +Note: Normals might not work well as intended with skinning animations. + +.. GENERATED FROM PYTHON SOURCE LINES 23-26 + +.. code-block:: Python + + + gltf_obj = glTF(filename, apply_normals=False) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 27-30 + +Get the skinning timeline using `skin_timeline` method, Choose the animation +name you want to visualize. +Note: If there's no name for animation, It's stored as `anim_0`, `anim_1` etc + +.. GENERATED FROM PYTHON SOURCE LINES 30-41 + +.. code-block:: Python + + + animation = gltf_obj.skin_animation()['anim_0'] + + # After we get the timeline object, We want to initialise the skinning process. + # You can set `bones=true` to visualize each bone transformation. Additionally, + # you can set `length` of bones in the `initialise_skin` method. + # Note: Make sure to call this method before you initialize ShowManager, else + # bones won't be added to the scene. + + gltf_obj.initialize_skin(animation, bones=False) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 42-45 + +Create a scene, and show manager. +Initialize the show manager and add timeline to the scene (No need to add +actors to the scene separately). + +.. GENERATED FROM PYTHON SOURCE LINES 45-53 + +.. code-block:: Python + + + scene = window.Scene() + showm = window.ShowManager( + scene, size=(900, 768), reset_camera=True, order_transparent=True + ) + showm.initialize() + scene.add(animation) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 54-57 + +define a timer_callback. +Use the `update_skin` method, It updates the timeline and applies skinning to +actors (and bones). + +.. GENERATED FROM PYTHON SOURCE LINES 57-64 + +.. code-block:: Python + + + + def timer_callback(_obj, _event): + gltf_obj.update_skin(animation) + showm.render() + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 65-66 + +Optional: `timeline.play()` auto plays the animations. + +.. GENERATED FROM PYTHON SOURCE LINES 66-77 + +.. code-block:: Python + + + + showm.add_timer_callback(True, 20, timer_callback) + scene.reset_camera() + + interactive = False + + if interactive: + showm.start() + + window.record(scene, out_path='viz_skinning.png', size=(900, 768)) + + + +.. image-sg:: /auto_examples/01_introductory/images/sphx_glr_viz_skinning_001.png + :alt: viz skinning + :srcset: /auto_examples/01_introductory/images/sphx_glr_viz_skinning_001.png + :class: sphx-glr-single-img + + + + + + +.. rst-class:: sphx-glr-timing + + **Total running time of the script:** (0 minutes 0.644 seconds) + + +.. _sphx_glr_download_auto_examples_01_introductory_viz_skinning.py: + +.. only:: html + + .. container:: sphx-glr-footer sphx-glr-footer-example + + .. container:: sphx-glr-download sphx-glr-download-jupyter + + :download:`Download Jupyter notebook: viz_skinning.ipynb ` + + .. container:: sphx-glr-download sphx-glr-download-python + + :download:`Download Python source code: viz_skinning.py ` + + +.. only:: html + + .. rst-class:: sphx-glr-signature + + `Gallery generated by Sphinx-Gallery `_ diff --git a/v0.10.x/_sources/auto_examples/01_introductory/viz_slice.rst.txt b/v0.10.x/_sources/auto_examples/01_introductory/viz_slice.rst.txt new file mode 100644 index 000000000..9b0941c9e --- /dev/null +++ b/v0.10.x/_sources/auto_examples/01_introductory/viz_slice.rst.txt @@ -0,0 +1,574 @@ + +.. DO NOT EDIT. +.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. +.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: +.. "auto_examples/01_introductory/viz_slice.py" +.. LINE NUMBERS ARE GIVEN BELOW. + +.. only:: html + + .. note:: + :class: sphx-glr-download-link-note + + :ref:`Go to the end ` + to download the full example code + +.. rst-class:: sphx-glr-example-title + +.. _sphx_glr_auto_examples_01_introductory_viz_slice.py: + + +===================== +Simple volume slicing +===================== + +Here we present an example for visualizing slices from 3D images. + +.. GENERATED FROM PYTHON SOURCE LINES 8-16 + +.. code-block:: Python + + + import os + + import nibabel as nib + from dipy.data import fetch_bundles_2_subjects + + from fury import actor, ui, window + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 17-18 + +Let's download and load a T1. + +.. GENERATED FROM PYTHON SOURCE LINES 18-35 + +.. code-block:: Python + + + fetch_bundles_2_subjects() + + fname_t1 = os.path.join( + os.path.expanduser('~'), + '.dipy', + 'exp_bundles_and_maps', + 'bundles_2_subjects', + 'subj_1', + 't1_warped.nii.gz', + ) + + + img = nib.load(fname_t1) + data = img.get_fdata() + affine = img.affine + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 36-37 + +Create a Scene object which holds all the actors which we want to visualize. + +.. GENERATED FROM PYTHON SOURCE LINES 37-41 + +.. code-block:: Python + + + scene = window.Scene() + scene.background((0.5, 0.5, 0.5)) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 42-47 + +Render slices from T1 with a specific value range +================================================= + +The T1 has usually a higher range of values than what can be visualized in an +image. We can set the range that we would like to see. + +.. GENERATED FROM PYTHON SOURCE LINES 47-51 + +.. code-block:: Python + + + mean, std = data[data > 0].mean(), data[data > 0].std() + value_range = (mean - 0.5 * std, mean + 1.5 * std) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 52-55 + +The ``slice`` function will read data and resample the data using an affine +transformation matrix. The default behavior of this function is to show the +middle slice of the last dimension of the resampled data. + +.. GENERATED FROM PYTHON SOURCE LINES 55-58 + +.. code-block:: Python + + + slice_actor = actor.slicer(data, affine, value_range) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 59-60 + +The ``slice_actor`` contains an axial slice. + +.. GENERATED FROM PYTHON SOURCE LINES 60-63 + +.. code-block:: Python + + + scene.add(slice_actor) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 64-67 + +The same actor can show any different slice from the given data using its +``display`` function. However, if we want to show multiple slices we need to +copy the actor first. + +.. GENERATED FROM PYTHON SOURCE LINES 67-70 + +.. code-block:: Python + + + slice_actor2 = slice_actor.copy() + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 71-73 + +Now we have a new ``slice_actor`` which displays the middle slice of sagittal +plane. + +.. GENERATED FROM PYTHON SOURCE LINES 73-81 + +.. code-block:: Python + + + slice_actor2.display(slice_actor2.shape[0] // 2, None, None) + + scene.add(slice_actor2) + + scene.reset_camera() + scene.zoom(1.4) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 82-83 + +In order to interact with the data you will need to uncomment the line below. + +.. GENERATED FROM PYTHON SOURCE LINES 83-86 + +.. code-block:: Python + + + # window.show(scene, size=(600, 600), reset_camera=False) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 87-88 + +Otherwise, you can save a screenshot using the following command. + +.. GENERATED FROM PYTHON SOURCE LINES 88-91 + +.. code-block:: Python + + + window.record(scene, out_path='slices.png', size=(600, 600), reset_camera=False) + + + + +.. image-sg:: /auto_examples/01_introductory/images/sphx_glr_viz_slice_001.png + :alt: viz slice + :srcset: /auto_examples/01_introductory/images/sphx_glr_viz_slice_001.png + :class: sphx-glr-single-img + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 92-94 + +Render slices from FA with your colormap +======================================== + +.. GENERATED FROM PYTHON SOURCE LINES 94-111 + +.. code-block:: Python + + + # It is also possible to set the colormap of your preference. Here we are + # loading an FA image and showing it in a non-standard way using an HSV + # colormap. + + fname_fa = os.path.join( + os.path.expanduser('~'), + '.dipy', + 'exp_bundles_and_maps', + 'bundles_2_subjects', + 'subj_1', + 'fa_1x1x1.nii.gz', + ) + + img = nib.load(fname_fa) + fa = img.get_fdata() + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 112-113 + +Notice here how the scale range is. We use FA min and max values to set it up + +.. GENERATED FROM PYTHON SOURCE LINES 113-121 + +.. code-block:: Python + + + lut = actor.colormap_lookup_table( + scale_range=(fa.min(), fa.max()), + hue_range=(0.4, 1.0), + saturation_range=(1, 1.0), + value_range=(0.0, 1.0), + ) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 122-124 + +This is because the lookup table is applied in the slice after interpolating +to (0, 255). + +.. GENERATED FROM PYTHON SOURCE LINES 124-137 + +.. code-block:: Python + + + fa_actor = actor.slicer(fa, affine, lookup_colormap=lut) + + scene.clear() + scene.add(fa_actor) + + scene.reset_camera() + scene.zoom(1.4) + + # window.show(scene, size=(600, 600), reset_camera=False) + + window.record(scene, out_path='slices_lut.png', size=(600, 600), reset_camera=False) + + + + +.. image-sg:: /auto_examples/01_introductory/images/sphx_glr_viz_slice_002.png + :alt: viz slice + :srcset: /auto_examples/01_introductory/images/sphx_glr_viz_slice_002.png + :class: sphx-glr-single-img + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 138-144 + +Now we would like to add the ability to click on a voxel and show its value +on a panel in the window. The panel is a UI element which requires access to +different areas of the visualization pipeline and therefore we don't +recommend using it with ``window.show``. The more appropriate way is to use +the ``ShowManager`` object, which allows accessing the pipeline in different +areas. + +.. GENERATED FROM PYTHON SOURCE LINES 144-148 + +.. code-block:: Python + + + show_m = window.ShowManager(scene, size=(1200, 900)) + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 149-150 + +We'll start by creating the panel and adding it to the ``ShowManager`` + +.. GENERATED FROM PYTHON SOURCE LINES 150-169 + +.. code-block:: Python + + + label_position = ui.TextBlock2D(text='Position:') + label_value = ui.TextBlock2D(text='Value:') + + result_position = ui.TextBlock2D(text='') + result_value = ui.TextBlock2D(text='') + + panel_picking = ui.Panel2D( + size=(250, 125), position=(20, 20), color=(0, 0, 0), opacity=0.75, align='left' + ) + + panel_picking.add_element(label_position, (0.1, 0.55)) + panel_picking.add_element(label_value, (0.1, 0.25)) + + panel_picking.add_element(result_position, (0.45, 0.55)) + panel_picking.add_element(result_value, (0.45, 0.25)) + + show_m.scene.add(panel_picking) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 170-172 + +Add a left-click callback to the slicer. Also disable interpolation so you +can see what you are picking. + +.. GENERATED FROM PYTHON SOURCE LINES 172-190 + +.. code-block:: Python + + + + def left_click_callback(obj, _ev): + """Get the value of the clicked voxel and show it in the panel.""" + event_pos = show_m.iren.GetEventPosition() + + obj.picker.Pick(event_pos[0], event_pos[1], 0, show_m.scene) + + i, j, k = obj.picker.GetPointIJK() + result_position.message = '({}, {}, {})'.format(str(i), str(j), str(k)) + result_value.message = '%.8f' % data[i, j, k] + + + fa_actor.SetInterpolate(False) + fa_actor.AddObserver('LeftButtonPressEvent', left_click_callback, 1.0) + + # show_m.start() + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + + 1 + + + +.. GENERATED FROM PYTHON SOURCE LINES 191-199 + +Create a mosaic +================ + +By using the ``copy`` and ``display`` method of the ``slice_actor`` becomes +easy and efficient to create a mosaic of all the slices. + +So, let's clear the scene and change the projection from perspective to +parallel. We'll also need a new show manager and an associated callback. + +.. GENERATED FROM PYTHON SOURCE LINES 199-220 + +.. code-block:: Python + + + scene.clear() + scene.projection('parallel') + + result_position.message = '' + result_value.message = '' + + show_m_mosaic = window.ShowManager(scene, size=(1200, 900)) + + + def left_click_callback_mosaic(obj, _ev): + """Get the value of the clicked voxel and show it in the panel.""" + event_pos = show_m_mosaic.iren.GetEventPosition() + + obj.picker.Pick(event_pos[0], event_pos[1], 0, show_m_mosaic.scene) + + i, j, k = obj.picker.GetPointIJK() + result_position.message = '({}, {}, {})'.format(str(i), str(j), str(k)) + result_value.message = '%.8f' % data[i, j, k] + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 221-224 + +Now we need to create two nested for loops which will set the positions of +the grid of the mosaic and add the new actors to the scene. We are going +to use 15 columns and 10 rows but you can adjust those with your datasets. + +.. GENERATED FROM PYTHON SOURCE LINES 224-257 + +.. code-block:: Python + + + cnt = 0 + + X, Y, Z = slice_actor.shape[:3] + + rows = 10 + cols = 15 + border = 10 + + for j in range(rows): + for i in range(cols): + slice_mosaic = slice_actor.copy() + slice_mosaic.display(None, None, cnt) + slice_mosaic.SetPosition( + (X + border) * i, 0.5 * cols * (Y + border) - (Y + border) * j, 0 + ) + slice_mosaic.SetInterpolate(False) + slice_mosaic.AddObserver( + 'LeftButtonPressEvent', left_click_callback_mosaic, 1.0 + ) + scene.add(slice_mosaic) + cnt += 1 + if cnt > Z: + break + if cnt > Z: + break + + scene.reset_camera() + scene.zoom(1.0) + + # show_m_mosaic.scene.add(panel_picking) + # show_m_mosaic.start() + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 258-261 + +If you uncomment the two lines above, you will be able to move +the mosaic up/down and left/right using the middle mouse button drag, +zoom in/out using the scroll wheel, and pick voxels with left click. + +.. GENERATED FROM PYTHON SOURCE LINES 261-264 + +.. code-block:: Python + + + + window.record(scene, out_path='mosaic.png', size=(900, 600), reset_camera=False) + + + +.. image-sg:: /auto_examples/01_introductory/images/sphx_glr_viz_slice_003.png + :alt: viz slice + :srcset: /auto_examples/01_introductory/images/sphx_glr_viz_slice_003.png + :class: sphx-glr-single-img + + + + + + +.. rst-class:: sphx-glr-timing + + **Total running time of the script:** (0 minutes 2.768 seconds) + + +.. _sphx_glr_download_auto_examples_01_introductory_viz_slice.py: + +.. only:: html + + .. container:: sphx-glr-footer sphx-glr-footer-example + + .. container:: sphx-glr-download sphx-glr-download-jupyter + + :download:`Download Jupyter notebook: viz_slice.ipynb ` + + .. container:: sphx-glr-download sphx-glr-download-python + + :download:`Download Python source code: viz_slice.py ` + + +.. only:: html + + .. rst-class:: sphx-glr-signature + + `Gallery generated by Sphinx-Gallery `_ diff --git a/v0.10.x/_sources/auto_examples/01_introductory/viz_solar_system.rst.txt b/v0.10.x/_sources/auto_examples/01_introductory/viz_solar_system.rst.txt new file mode 100644 index 000000000..465492817 --- /dev/null +++ b/v0.10.x/_sources/auto_examples/01_introductory/viz_solar_system.rst.txt @@ -0,0 +1,636 @@ + +.. DO NOT EDIT. +.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. +.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: +.. "auto_examples/01_introductory/viz_solar_system.py" +.. LINE NUMBERS ARE GIVEN BELOW. + +.. only:: html + + .. note:: + :class: sphx-glr-download-link-note + + :ref:`Go to the end ` + to download the full example code + +.. rst-class:: sphx-glr-example-title + +.. _sphx_glr_auto_examples_01_introductory_viz_solar_system.py: + + +======================= +Solar System Animation +======================= + +In this tutorial, we will create an animation of the solar system +using textured spheres. We will also show how to manipulate the +position of these sphere actors in a timer_callback function +to simulate orbital motion. + +.. GENERATED FROM PYTHON SOURCE LINES 11-19 + +.. code-block:: Python + + + import itertools + + import numpy as np + + from fury import actor, io, ui, utils, window + from fury.data import fetch_viz_textures, read_viz_icons, read_viz_textures + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 20-21 + +Create a scene to start. + +.. GENERATED FROM PYTHON SOURCE LINES 21-38 + +.. code-block:: Python + + + scene = window.Scene() + + # Create a panel and the start/pause buttons + + panel = ui.Panel2D(size=(300, 100), color=(1, 1, 1), align='right') + panel.center = (400, 50) + + pause_button = ui.Button2D(icon_fnames=[('square', read_viz_icons(fname='pause2.png'))]) + start_button = ui.Button2D(icon_fnames=[('square', read_viz_icons(fname='play3.png'))]) + + # Add the buttons on the panel + + panel.add_element(pause_button, (0.25, 0.33)) + panel.add_element(start_button, (0.66, 0.33)) + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 39-41 + +Define information relevant for each planet actor including its +texture name, relative position, and scale. + +.. GENERATED FROM PYTHON SOURCE LINES 41-96 + +.. code-block:: Python + + + planets_data = [ + { + 'filename': '8k_mercury.jpg', + 'position': 7, + 'earth_days': 58, + 'scale': (0.4, 0.4, 0.4), + }, + { + 'filename': '8k_venus_surface.jpg', + 'position': 9, + 'earth_days': 243, + 'scale': (0.6, 0.6, 0.6), + }, + { + 'filename': '1_earth_8k.jpg', + 'position': 11, + 'earth_days': 1, + 'scale': (0.4, 0.4, 0.4), + }, + { + 'filename': '8k_mars.jpg', + 'position': 13, + 'earth_days': 1, + 'scale': (0.8, 0.8, 0.8), + }, + {'filename': 'jupiter.jpg', 'position': 16, 'earth_days': 0.41, 'scale': (2, 2, 2)}, + { + 'filename': '8k_saturn.jpg', + 'position': 19, + 'earth_days': 0.45, + 'scale': (2, 2, 2), + }, + { + 'filename': '8k_saturn_ring_alpha.png', + 'position': 19, + 'earth_days': 0.45, + 'scale': (3, 0.5, 3), + }, + { + 'filename': '2k_uranus.jpg', + 'position': 22, + 'earth_days': 0.70, + 'scale': (1, 1, 1), + }, + { + 'filename': '2k_neptune.jpg', + 'position': 25, + 'earth_days': 0.70, + 'scale': (1, 1, 1), + }, + {'filename': '8k_sun.jpg', 'position': 0, 'earth_days': 27, 'scale': (5, 5, 5)}, + ] + fetch_viz_textures() + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + Dataset is already in place. If you want to fetch it again please first remove the folder /Users/skoudoro/.fury/textures + + ({'1_earth_8k.jpg': ('https://raw.githubusercontent.com/fury-gl/fury-data/master/textures/1_earth_8k.jpg', '0D66DC62768C43D763D3288CE67128AAED27715B11B0529162DC4117F710E26F'), '2_no_clouds_8k.jpg': ('https://raw.githubusercontent.com/fury-gl/fury-data/master/textures/2_no_clouds_8k.jpg', '5CF740C72287AF7B3ACCF080C3951944ADCB1617083B918537D08CBD9F2C5465'), '5_night_8k.jpg': ('https://raw.githubusercontent.com/fury-gl/fury-data/master/textures/5_night_8k.jpg', 'DF443F3E20C7724803690A350D9F6FDB36AD8EBC011B0345FB519A8B321F680A'), 'earth.ppm': ('https://raw.githubusercontent.com/fury-gl/fury-data/master/textures/earth.ppm', '34CE9AD183D7C7B11E2F682D7EBB84C803E661BE09E01ADB887175AE60C58156'), 'jupiter.jpg': ('https://raw.githubusercontent.com/fury-gl/fury-data/master/textures/jupiter.jpg', '5DF6A384E407BD0D5F18176B7DB96AAE1EEA3CFCFE570DDCE0D34B4F0E493668'), 'masonry.bmp': ('https://raw.githubusercontent.com/fury-gl/fury-data/master/textures/masonry.bmp', '045E30B2ABFEAE6318C2CF955040C4A37E6DE595ACE809CE6766D397C0EE205D'), 'moon-8k.jpg': ('https://raw.githubusercontent.com/fury-gl/fury-data/master/textures/moon_8k.jpg', '7397A6C2CE0348E148C66EBEFE078467DDB9D0370FF5E63434D0451477624839'), '8k_mercury.jpg': ('https://raw.githubusercontent.com/fury-gl/fury-data/master/textures/8k_mercury.jpg', '5C8BD885AE3571C6BA2CD34B3446B9C6D767E314BF0EE8C1D5C147CADD388FC3'), '8k_venus_surface.jpg': ('https://raw.githubusercontent.com/fury-gl/fury-data/master/textures/8k_venus_surface.jpg', '9BC21A50577ED8AC734CDA91058724C7A741C19427AA276224CE349351432C5B'), '8k_mars.jpg': ('https://raw.githubusercontent.com/fury-gl/fury-data/master/textures/8k_mars.jpg', '4CC52149924ABC6AE507D63032F994E1D42A55CB82C09E002D1A567FF66C23EE'), '8k_saturn.jpg': ('https://raw.githubusercontent.com/fury-gl/fury-data/master/textures/8k_saturn.jpg', '0D39A4A490C87C3EDABE00A3881A29BB3418364178C79C534FE0986E97E09853'), '8k_saturn_ring_alpha.png': ('https://raw.githubusercontent.com/fury-gl/fury-data/master/textures/8k_saturn_ring_alpha.png', 'F1F826933C9FF87D64ECF0518D6256B8ED990B003722794F67E96E3D2B876AE4'), '2k_uranus.jpg': ('https://raw.githubusercontent.com/fury-gl/fury-data/master/textures/2k_uranus.jpg', 'D15239D46F82D3EA13D2B260B5B29B2A382F42F2916DAE0694D0387B1204A09D'), '2k_neptune.jpg': ('https://raw.githubusercontent.com/fury-gl/fury-data/master/textures/2k_neptune.jpg', 'CB42EA82709741D28B0AF44D8B283CBC6DBD0C521A7F0E1E1E010ADE00977DF6'), '8k_sun.jpg': ('https://raw.githubusercontent.com/fury-gl/fury-data/master/textures/8k_sun.jpg', 'F22B1CFB306DDCE72A7E3B628668A0175B745038CE6268557CB2F7F1BDF98B9D'), '1_earth_16k.jpg': ('https://raw.githubusercontent.com/fury-gl/fury-data/master/textures/1_earth_16k.jpg', '7DD1DAC926101B5D7B7F2E952E53ACF209421B5CCE57C03168BCE0AAD675998A'), 'clouds.jpg': ('https://raw.githubusercontent.com/fury-gl/fury-data/master/textures/clouds.jpg', '85043336E023C4C9394CFD6D48D257A5564B4F895BFCEC01C70E4898CC77F003')}, '/Users/skoudoro/.fury/textures') + + + +.. GENERATED FROM PYTHON SOURCE LINES 97-101 + +To take advantage of the previously defined data structure we are going to +create an auxiliary function that will load and apply the respective +texture, set its respective properties (relative position and scale), +and add the actor to a previously created scene. + +.. GENERATED FROM PYTHON SOURCE LINES 101-128 + +.. code-block:: Python + + + + def init_planet(planet_data): + """Initialize a planet actor. + + Parameters + ---------- + planet_data : dict + The planet_data is a dictionary, and the keys are filename(texture), + position and scale. + + Returns + ------- + planet_actor: actor + The corresponding sphere actor with texture applied. + """ + planet_file = read_viz_textures(planet_data['filename']) + planet_image = io.load_image(planet_file) + planet_actor = actor.texture_on_sphere(planet_image) + planet_actor.SetPosition(planet_data['position'], 0, 0) + if planet_data['filename'] != '8k_saturn_ring_alpha.png': + utils.rotate(planet_actor, (90, 1, 0, 0)) + planet_actor.SetScale(planet_data['scale']) + scene.add(planet_actor) + return planet_actor + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 129-132 + +Use the ``map`` function to create actors for each of the texture files +in the ``planet_files`` list. Then, assign each actor to its corresponding +actor in the list. + +.. GENERATED FROM PYTHON SOURCE LINES 132-147 + +.. code-block:: Python + + + planet_actor_list = list(map(init_planet, planets_data)) + + mercury_actor = planet_actor_list[0] + venus_actor = planet_actor_list[1] + earth_actor = planet_actor_list[2] + mars_actor = planet_actor_list[3] + jupiter_actor = planet_actor_list[4] + saturn_actor = planet_actor_list[5] + saturn_rings_actor = planet_actor_list[6] + uranus_actor = planet_actor_list[7] + neptune_actor = planet_actor_list[8] + sun_actor = planet_actor_list[9] + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 148-152 + +Define the gravitational constant G, the orbital radii of each of the +planets, and the central mass of the sun. The gravity and mass will be +used to calculate the orbital position, so multiply these two together to +create a new constant, which we will call miu. + +.. GENERATED FROM PYTHON SOURCE LINES 152-161 + +.. code-block:: Python + + + g_exponent = np.float_power(10, -11) + g_constant = 6.673 * g_exponent + + m_exponent = 1073741824 # np.power(10, 30) + m_constant = 1.989 * m_exponent + + miu = m_constant * g_constant + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 162-166 + +Let's define two functions that will help us calculate the position of each +planet as it orbits around the sun: ``get_orbit_period`` and +``get_orbital_position``, using the constant miu and the orbital radii +of each planet. + +.. GENERATED FROM PYTHON SOURCE LINES 166-179 + +.. code-block:: Python + + + + def get_orbit_period(radius): + return 2 * np.pi * np.sqrt(np.power(radius, 3) / miu) + + + def get_orbital_position(radius, time): + orbit_period = get_orbit_period(radius) + x = radius * np.cos((-2 * np.pi * time) / orbit_period) + y = radius * np.sin((-2 * np.pi * time) / orbit_period) + return x, y + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 180-183 + +Let's define a function to rotate the planet actor axially, we'll be defining +axis of each planet and angle by which it should be rotated using +``rotate_axial`` funtction + +.. GENERATED FROM PYTHON SOURCE LINES 183-192 + +.. code-block:: Python + + + + def rotate_axial(actor, time, radius): + axis = (0, radius, 0) + angle = 50 / time + utils.rotate(actor, (angle, axis[0], axis[1], axis[2])) + return angle + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 193-194 + +Let's change the camera position to visualize the planets better. + +.. GENERATED FROM PYTHON SOURCE LINES 194-197 + +.. code-block:: Python + + + scene.set_camera(position=(-20, 60, 100)) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 198-200 + +Next, create a ShowManager object. The ShowManager class is the interface +between the scene, the window and the interactor. + +.. GENERATED FROM PYTHON SOURCE LINES 200-206 + +.. code-block:: Python + + + showm = window.ShowManager( + scene, size=(900, 768), reset_camera=False, order_transparent=True + ) + scene.add(panel) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 207-210 + +Next, let's focus on creating the animation. +We can determine the duration of animation with using the ``counter``. +Use itertools to avoid global variables. + +.. GENERATED FROM PYTHON SOURCE LINES 210-213 + +.. code-block:: Python + + + counter = itertools.count() + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 214-216 + +Define one new function to use in ``timer_callback`` to update the planet +positions ``update_planet_position``. + +.. GENERATED FROM PYTHON SOURCE LINES 216-224 + +.. code-block:: Python + + + + def update_planet_position(r_planet, planet_actor, cnt): + pos_planet = get_orbital_position(r_planet, cnt) + planet_actor.SetPosition(pos_planet[0], 0, pos_planet[1]) + return pos_planet + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 225-227 + +``calculate_path`` function is for calculating the path/orbit +of every planet. + +.. GENERATED FROM PYTHON SOURCE LINES 227-237 + +.. code-block:: Python + + + + def calculate_path(r_planet, c): + planet_track = [ + [get_orbital_position(r_planet, i)[0], 0, get_orbital_position(r_planet, i)[1]] + for i in range(c) + ] + return planet_track + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 238-243 + +First we are making a list that will contain radius from `planets_data`. +Here we are not taking the radius of orbit/path for sun and saturn ring. +`planet_actors` will contain all the planet actors. +`r_times` will contain time taken (in days) by the planets to rotate +around itself. + +.. GENERATED FROM PYTHON SOURCE LINES 243-271 + +.. code-block:: Python + + + r_planets = [ + p_data['position'] + for p_data in planets_data + if 'sun' not in p_data['filename'] + if 'saturn_ring' not in p_data['filename'] + ] + + planet_actors = [ + mercury_actor, + venus_actor, + earth_actor, + mars_actor, + jupiter_actor, + saturn_actor, + uranus_actor, + neptune_actor, + ] + + + sun_data = { + 'actor': sun_actor, + 'position': planets_data[9]['position'], + 'earth_days': planets_data[9]['earth_days'], + } + + r_times = [p_data['earth_days'] for p_data in planets_data] + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 272-273 + +Here we are calculating and updating the path/orbit before animation starts. + +.. GENERATED FROM PYTHON SOURCE LINES 273-276 + +.. code-block:: Python + + + planet_tracks = [calculate_path(rplanet, rplanet * 85) for rplanet in r_planets] + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 277-279 + +This is for orbit visualization. We are using line actor for orbits. +After creating an actor we add it to the scene. + +.. GENERATED FROM PYTHON SOURCE LINES 279-283 + +.. code-block:: Python + + + orbit_actor = actor.line(planet_tracks, colors=(1, 1, 1), linewidth=0.1) + scene.add(orbit_actor) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 284-288 + +Define the ``timer_callback`` function, which controls what events happen +at certain times, using the counter. Update the position of each planet +actor using ``update_planet_position,`` assigning the x and y values of +each planet's position with the newly calculated ones. + +.. GENERATED FROM PYTHON SOURCE LINES 288-311 + +.. code-block:: Python + + + + def timer_callback(_obj, _event): + cnt = next(counter) + showm.render() + + # Rotating the sun actor + rotate_axial(sun_actor, sun_data['earth_days'], 1) + + for r_planet, p_actor, r_time in zip(r_planets, planet_actors, r_times): + # if the planet is saturn then we also need to update the position + # of its rings. + if p_actor == saturn_actor: + pos_saturn = update_planet_position(19, saturn_actor, cnt) + saturn_rings_actor.SetPosition(pos_saturn[0], 0, pos_saturn[1]) + else: + update_planet_position(r_planet, p_actor, cnt) + rotate_axial(p_actor, r_time, r_planet) + + if cnt == 2000: + showm.exit() + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 312-313 + +We add a callback to each button to perform some action. + +.. GENERATED FROM PYTHON SOURCE LINES 313-327 + +.. code-block:: Python + + + + def start_animation(i_ren, _obj, _button): + showm.add_timer_callback(True, 10, timer_callback) + + + def pause_animation(i_ren, _obj, _button): + showm.destroy_timers() + + + start_button.on_left_mouse_button_clicked = start_animation + pause_button.on_left_mouse_button_clicked = pause_animation + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 328-329 + +Watch the planets orbit the sun in your new animation! + +.. GENERATED FROM PYTHON SOURCE LINES 329-335 + +.. code-block:: Python + + + + showm.add_timer_callback(True, 10, timer_callback) + showm.start() + + window.record(showm.scene, size=(900, 768), out_path='viz_solar_system_animation.png') + + + +.. image-sg:: /auto_examples/01_introductory/images/sphx_glr_viz_solar_system_001.png + :alt: viz solar system + :srcset: /auto_examples/01_introductory/images/sphx_glr_viz_solar_system_001.png + :class: sphx-glr-single-img + + + + + + +.. rst-class:: sphx-glr-timing + + **Total running time of the script:** (0 minutes 31.865 seconds) + + +.. _sphx_glr_download_auto_examples_01_introductory_viz_solar_system.py: + +.. only:: html + + .. container:: sphx-glr-footer sphx-glr-footer-example + + .. container:: sphx-glr-download sphx-glr-download-jupyter + + :download:`Download Jupyter notebook: viz_solar_system.ipynb ` + + .. container:: sphx-glr-download sphx-glr-download-python + + :download:`Download Python source code: viz_solar_system.py ` + + +.. only:: html + + .. rst-class:: sphx-glr-signature + + `Gallery generated by Sphinx-Gallery `_ diff --git a/v0.10.x/_sources/auto_examples/01_introductory/viz_sphere.rst.txt b/v0.10.x/_sources/auto_examples/01_introductory/viz_sphere.rst.txt new file mode 100644 index 000000000..890d7ed59 --- /dev/null +++ b/v0.10.x/_sources/auto_examples/01_introductory/viz_sphere.rst.txt @@ -0,0 +1,157 @@ + +.. DO NOT EDIT. +.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. +.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: +.. "auto_examples/01_introductory/viz_sphere.py" +.. LINE NUMBERS ARE GIVEN BELOW. + +.. only:: html + + .. note:: + :class: sphx-glr-download-link-note + + :ref:`Go to the end ` + to download the full example code + +.. rst-class:: sphx-glr-example-title + +.. _sphx_glr_auto_examples_01_introductory_viz_sphere.py: + + +====================================================================== +FURY sphere Actor +====================================================================== +This example shows how to use both primitive and vtkSource sphere actor. + +.. GENERATED FROM PYTHON SOURCE LINES 7-12 + +.. code-block:: Python + + + import numpy as np + + from fury import actor, window + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 13-14 + +First thing, you have to specify centers and colors of the sphere + +.. GENERATED FROM PYTHON SOURCE LINES 14-18 + +.. code-block:: Python + + + centers = np.zeros([1, 3]) + colors = np.array([0, 0, 1]) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 19-20 + +The below sphere actor is generated by repeating the sphere primitive. + +.. GENERATED FROM PYTHON SOURCE LINES 20-23 + +.. code-block:: Python + + + prim_sphere_actor = actor.sphere(centers, colors=colors, radii=5) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 24-25 + +This time, we're using vtkSphereSource to generate the sphere actor + +.. GENERATED FROM PYTHON SOURCE LINES 25-33 + +.. code-block:: Python + + + cen2 = np.add(centers, np.array([12, 0, 0])) + cols2 = np.array([1, 0, 0]) + + vtk_sphere_actor = actor.sphere(cen2, colors=cols2, radii=5, use_primitive=False) + + scene = window.Scene() + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 34-35 + +Adding our sphere actors to scene. + +.. GENERATED FROM PYTHON SOURCE LINES 35-45 + +.. code-block:: Python + + + scene.add(prim_sphere_actor) + scene.add(vtk_sphere_actor) + + interactive = False + + if interactive: + window.show(scene, size=(600, 600)) + + window.record(scene, out_path='viz_sphere.png', size=(600, 600)) + + + +.. image-sg:: /auto_examples/01_introductory/images/sphx_glr_viz_sphere_001.png + :alt: viz sphere + :srcset: /auto_examples/01_introductory/images/sphx_glr_viz_sphere_001.png + :class: sphx-glr-single-img + + + + + + +.. rst-class:: sphx-glr-timing + + **Total running time of the script:** (0 minutes 0.067 seconds) + + +.. _sphx_glr_download_auto_examples_01_introductory_viz_sphere.py: + +.. only:: html + + .. container:: sphx-glr-footer sphx-glr-footer-example + + .. container:: sphx-glr-download sphx-glr-download-jupyter + + :download:`Download Jupyter notebook: viz_sphere.ipynb ` + + .. container:: sphx-glr-download sphx-glr-download-python + + :download:`Download Python source code: viz_sphere.py ` + + +.. only:: html + + .. rst-class:: sphx-glr-signature + + `Gallery generated by Sphinx-Gallery `_ diff --git a/v0.10.x/_sources/auto_examples/01_introductory/viz_spiky.rst.txt b/v0.10.x/_sources/auto_examples/01_introductory/viz_spiky.rst.txt new file mode 100644 index 000000000..d534d9a0f --- /dev/null +++ b/v0.10.x/_sources/auto_examples/01_introductory/viz_spiky.rst.txt @@ -0,0 +1,308 @@ + +.. DO NOT EDIT. +.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. +.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: +.. "auto_examples/01_introductory/viz_spiky.py" +.. LINE NUMBERS ARE GIVEN BELOW. + +.. only:: html + + .. note:: + :class: sphx-glr-download-link-note + + :ref:`Go to the end ` + to download the full example code + +.. rst-class:: sphx-glr-example-title + +.. _sphx_glr_auto_examples_01_introductory_viz_spiky.py: + + +=============== +Spiky Sphere +=============== +In this tutorial, we show how to create a sphere with spikes. + +.. GENERATED FROM PYTHON SOURCE LINES 7-14 + +.. code-block:: Python + + + import itertools + + import numpy as np + + from fury import actor, primitive, utils, window + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 15-19 + +Create a sphere actor. Define the center, radius and color of a sphere. +The sphere actor is made of points (vertices) evenly distributed on a +sphere. +Let's create a scene. + +.. GENERATED FROM PYTHON SOURCE LINES 19-22 + +.. code-block:: Python + + + scene = window.Scene() + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 23-26 + +The vertices are connected with triangles in order to specify the direction +of the surface normal. +``prim_sphere`` provides a sphere with evenly distributed points + +.. GENERATED FROM PYTHON SOURCE LINES 26-29 + +.. code-block:: Python + + + vertices, triangles = primitive.prim_sphere(name='symmetric362', gen_faces=False) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 30-32 + +To be able to visualize the vertices, let's define a point actor with +green color. + +.. GENERATED FROM PYTHON SOURCE LINES 32-35 + +.. code-block:: Python + + + point_actor = actor.point(vertices, point_radius=0.01, colors=(0, 1, 0)) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 36-39 + +Normals are the vectors that are perpendicular to the surface at each +vertex. We specify the normals at the vertices to tell the system +whether triangles represent curved surfaces. + +.. GENERATED FROM PYTHON SOURCE LINES 39-42 + +.. code-block:: Python + + + normals = utils.normals_from_v_f(vertices, triangles) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 43-47 + +The normals are usually used to calculate how the light will bounce on +the surface of an object. However, here we will use them to direct the +spikes (represented with arrows). +So, let's create an arrow actor at the center of each vertex. + +.. GENERATED FROM PYTHON SOURCE LINES 47-58 + +.. code-block:: Python + + + arrow_actor = actor.arrow( + centers=vertices, + directions=normals, + colors=(1, 0, 0), + heights=0.2, + resolution=10, + vertices=None, + faces=None, + ) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 59-61 + +To be able to visualize the surface of the primitive sphere, we use +``get_actor_from_primitive``. + +.. GENERATED FROM PYTHON SOURCE LINES 61-72 + +.. code-block:: Python + + + primitive_colors = np.zeros(vertices.shape) + primitive_colors[:, 2] = 180 + primitive_actor = utils.get_actor_from_primitive( + vertices=vertices, + triangles=triangles, + colors=primitive_colors, + normals=normals, + backface_culling=True, + ) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 73-74 + +We add all actors (visual objects) defined above to the scene. + +.. GENERATED FROM PYTHON SOURCE LINES 74-80 + +.. code-block:: Python + + + scene.add(point_actor) + scene.add(arrow_actor) + scene.add(primitive_actor) + scene.add(actor.axes()) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 81-83 + +The ShowManager class is the interface between the scene, the window and the +interactor. + +.. GENERATED FROM PYTHON SOURCE LINES 83-88 + +.. code-block:: Python + + + showm = window.ShowManager( + scene, size=(900, 768), reset_camera=False, order_transparent=True + ) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 89-92 + +We want to make a small animation for fun! +We can determine the duration of animation with using the ``counter``. +Use itertools to avoid global variables. + +.. GENERATED FROM PYTHON SOURCE LINES 92-95 + +.. code-block:: Python + + + counter = itertools.count() + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 96-98 + +The timer will call this user defined callback every 200 milliseconds. The +application will exit after the callback has been called 20 times. + +.. GENERATED FROM PYTHON SOURCE LINES 98-113 + +.. code-block:: Python + + + + def timer_callback(_obj, _event): + cnt = next(counter) + showm.scene.azimuth(0.05 * cnt) + primitive_actor.GetProperty().SetOpacity(cnt / 10.0) + showm.render() + if cnt == 20: + showm.exit() + + + showm.add_timer_callback(True, 200, timer_callback) + showm.start() + window.record(showm.scene, size=(900, 768), out_path='viz_spiky.png') + + + + +.. image-sg:: /auto_examples/01_introductory/images/sphx_glr_viz_spiky_001.png + :alt: viz spiky + :srcset: /auto_examples/01_introductory/images/sphx_glr_viz_spiky_001.png + :class: sphx-glr-single-img + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 114-116 + +Instead of arrows, you can choose other geometrical objects +such as cones, cubes or spheres. + + +.. rst-class:: sphx-glr-timing + + **Total running time of the script:** (0 minutes 4.349 seconds) + + +.. _sphx_glr_download_auto_examples_01_introductory_viz_spiky.py: + +.. only:: html + + .. container:: sphx-glr-footer sphx-glr-footer-example + + .. container:: sphx-glr-download sphx-glr-download-jupyter + + :download:`Download Jupyter notebook: viz_spiky.ipynb ` + + .. container:: sphx-glr-download sphx-glr-download-python + + :download:`Download Python source code: viz_spiky.py ` + + +.. only:: html + + .. rst-class:: sphx-glr-signature + + `Gallery generated by Sphinx-Gallery `_ diff --git a/v0.10.x/_sources/auto_examples/01_introductory/viz_surfaces.rst.txt b/v0.10.x/_sources/auto_examples/01_introductory/viz_surfaces.rst.txt new file mode 100644 index 000000000..7c18e1402 --- /dev/null +++ b/v0.10.x/_sources/auto_examples/01_introductory/viz_surfaces.rst.txt @@ -0,0 +1,285 @@ + +.. DO NOT EDIT. +.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. +.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: +.. "auto_examples/01_introductory/viz_surfaces.py" +.. LINE NUMBERS ARE GIVEN BELOW. + +.. only:: html + + .. note:: + :class: sphx-glr-download-link-note + + :ref:`Go to the end ` + to download the full example code + +.. rst-class:: sphx-glr-example-title + +.. _sphx_glr_auto_examples_01_introductory_viz_surfaces.py: + + +================== +Visualize surfaces +================== + +Here is a simple tutorial that shows how to visualize surfaces using DIPY. It +also shows how to load/save, get/set and update ``PolyData`` and show +surfaces. + +``PolyData`` is a structure used by VTK to represent surfaces and other data +structures. Here we show how to visualize a simple cube but the same idea +should apply for any surface. + +.. GENERATED FROM PYTHON SOURCE LINES 14-21 + +.. code-block:: Python + + + import numpy as np + + from fury import utils, window + from fury.io import load_polydata, save_polydata + from fury.lib import PolyData + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 22-23 + +Import useful functions + +.. GENERATED FROM PYTHON SOURCE LINES 26-27 + +Create an empty ``PolyData`` + +.. GENERATED FROM PYTHON SOURCE LINES 27-30 + +.. code-block:: Python + + + my_polydata = PolyData() + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 31-32 + +Create a cube with vertices and triangles as numpy arrays + +.. GENERATED FROM PYTHON SOURCE LINES 32-65 + +.. code-block:: Python + + + my_vertices = np.array( + [ + [0.0, 0.0, 0.0], + [0.0, 0.0, 1.0], + [0.0, 1.0, 0.0], + [0.0, 1.0, 1.0], + [1.0, 0.0, 0.0], + [1.0, 0.0, 1.0], + [1.0, 1.0, 0.0], + [1.0, 1.0, 1.0], + ] + ) + # the data type is needed to mention here, numpy.int64 + my_triangles = np.array( + [ + [0, 6, 4], + [0, 2, 6], + [0, 3, 2], + [0, 1, 3], + [2, 7, 6], + [2, 3, 7], + [4, 6, 7], + [4, 7, 5], + [0, 4, 5], + [0, 5, 1], + [1, 5, 7], + [1, 7, 3], + ], + dtype='i8', + ) + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 66-67 + +Set vertices and triangles in the ``PolyData`` + +.. GENERATED FROM PYTHON SOURCE LINES 67-71 + +.. code-block:: Python + + + utils.set_polydata_vertices(my_polydata, my_vertices) + utils.set_polydata_triangles(my_polydata, my_triangles) + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 72-73 + +Save the ``PolyData`` + +.. GENERATED FROM PYTHON SOURCE LINES 73-78 + +.. code-block:: Python + + + file_name = 'my_cube.vtk' + save_polydata(my_polydata, file_name) + print('Surface saved in ' + file_name) + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + Surface saved in my_cube.vtk + + + + +.. GENERATED FROM PYTHON SOURCE LINES 79-80 + +Load the ``PolyData`` + +.. GENERATED FROM PYTHON SOURCE LINES 80-83 + +.. code-block:: Python + + + cube_polydata = load_polydata(file_name) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 84-85 + +add color based on vertices position + +.. GENERATED FROM PYTHON SOURCE LINES 85-93 + +.. code-block:: Python + + + cube_vertices = utils.get_polydata_vertices(cube_polydata) + colors = cube_vertices * 255 + utils.set_polydata_colors(cube_polydata, colors) + + print('new surface colors') + print(utils.get_polydata_colors(cube_polydata)) + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + new surface colors + [[ 0 0 0] + [ 0 0 255] + [ 0 255 0] + [ 0 255 255] + [255 0 0] + [255 0 255] + [255 255 0] + [255 255 255]] + + + + +.. GENERATED FROM PYTHON SOURCE LINES 94-95 + +Visualize surfaces + +.. GENERATED FROM PYTHON SOURCE LINES 95-108 + +.. code-block:: Python + + + # get Actor + cube_actor = utils.get_actor_from_polydata(cube_polydata) + + # Create a scene + scene = window.Scene() + scene.add(cube_actor) + scene.set_camera(position=(10, 5, 7), focal_point=(0.5, 0.5, 0.5)) + scene.zoom(3) + + # display + # window.show(scene, size=(600, 600), reset_camera=False) + window.record(scene, out_path='cube.png', size=(600, 600)) + + + +.. image-sg:: /auto_examples/01_introductory/images/sphx_glr_viz_surfaces_001.png + :alt: viz surfaces + :srcset: /auto_examples/01_introductory/images/sphx_glr_viz_surfaces_001.png + :class: sphx-glr-single-img + + + + + + +.. rst-class:: sphx-glr-timing + + **Total running time of the script:** (0 minutes 0.064 seconds) + + +.. _sphx_glr_download_auto_examples_01_introductory_viz_surfaces.py: + +.. only:: html + + .. container:: sphx-glr-footer sphx-glr-footer-example + + .. container:: sphx-glr-download sphx-glr-download-jupyter + + :download:`Download Jupyter notebook: viz_surfaces.ipynb ` + + .. container:: sphx-glr-download sphx-glr-download-python + + :download:`Download Python source code: viz_surfaces.py ` + + +.. only:: html + + .. rst-class:: sphx-glr-signature + + `Gallery generated by Sphinx-Gallery `_ diff --git a/v0.10.x/_sources/auto_examples/01_introductory/viz_texture.rst.txt b/v0.10.x/_sources/auto_examples/01_introductory/viz_texture.rst.txt new file mode 100644 index 000000000..a947af285 --- /dev/null +++ b/v0.10.x/_sources/auto_examples/01_introductory/viz_texture.rst.txt @@ -0,0 +1,160 @@ + +.. DO NOT EDIT. +.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. +.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: +.. "auto_examples/01_introductory/viz_texture.py" +.. LINE NUMBERS ARE GIVEN BELOW. + +.. only:: html + + .. note:: + :class: sphx-glr-download-link-note + + :ref:`Go to the end ` + to download the full example code + +.. rst-class:: sphx-glr-example-title + +.. _sphx_glr_auto_examples_01_introductory_viz_texture.py: + + +=============== +Sphere Texture +=============== +In this tutorial, we will show how to create a sphere with a texture. + +.. GENERATED FROM PYTHON SOURCE LINES 7-11 + +.. code-block:: Python + + + from fury import actor, io, window + from fury.data import fetch_viz_textures, read_viz_textures + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 12-13 + +Create a scene to start. + +.. GENERATED FROM PYTHON SOURCE LINES 13-16 + +.. code-block:: Python + + + scene = window.Scene() + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 17-21 + +Load an image (png, bmp, jpeg or jpg) using ``io.load_image``. In this +example, we will use ``read_viz_textures`` to access an image of the +Earth's surface from the fury Github after using ''fetch_viz_textures()'' +to download the available textures. + +.. GENERATED FROM PYTHON SOURCE LINES 21-26 + +.. code-block:: Python + + + fetch_viz_textures() + filename = read_viz_textures('1_earth_8k.jpg') + image = io.load_image(filename) + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + Dataset is already in place. If you want to fetch it again please first remove the folder /Users/skoudoro/.fury/textures + + + + +.. GENERATED FROM PYTHON SOURCE LINES 27-31 + +Next, use ``actor.texture_on_sphere`` to add a sphere with the texture from +your loaded image to the already existing scene. +To add a texture to your scene as visualized on a plane, use +``actor.texture`` instead. + +.. GENERATED FROM PYTHON SOURCE LINES 31-34 + +.. code-block:: Python + + + scene.add(actor.texture_on_sphere(image)) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 35-37 + +Lastly, record the scene, or set interactive to True if you would like to +manipulate your new sphere. + +.. GENERATED FROM PYTHON SOURCE LINES 37-42 + +.. code-block:: Python + + + interactive = False + if interactive: + window.show(scene, size=(600, 600), reset_camera=False) + window.record(scene, size=(900, 768), out_path='viz_texture.png') + + + +.. image-sg:: /auto_examples/01_introductory/images/sphx_glr_viz_texture_001.png + :alt: viz texture + :srcset: /auto_examples/01_introductory/images/sphx_glr_viz_texture_001.png + :class: sphx-glr-single-img + + + + + + +.. rst-class:: sphx-glr-timing + + **Total running time of the script:** (0 minutes 1.470 seconds) + + +.. _sphx_glr_download_auto_examples_01_introductory_viz_texture.py: + +.. only:: html + + .. container:: sphx-glr-footer sphx-glr-footer-example + + .. container:: sphx-glr-download sphx-glr-download-jupyter + + :download:`Download Jupyter notebook: viz_texture.ipynb ` + + .. container:: sphx-glr-download sphx-glr-download-python + + :download:`Download Python source code: viz_texture.py ` + + +.. only:: html + + .. rst-class:: sphx-glr-signature + + `Gallery generated by Sphinx-Gallery `_ diff --git a/v0.10.x/_sources/auto_examples/01_introductory/viz_timers.rst.txt b/v0.10.x/_sources/auto_examples/01_introductory/viz_timers.rst.txt new file mode 100644 index 000000000..bce119d7c --- /dev/null +++ b/v0.10.x/_sources/auto_examples/01_introductory/viz_timers.rst.txt @@ -0,0 +1,131 @@ + +.. DO NOT EDIT. +.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. +.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: +.. "auto_examples/01_introductory/viz_timers.py" +.. LINE NUMBERS ARE GIVEN BELOW. + +.. only:: html + + .. note:: + :class: sphx-glr-download-link-note + + :ref:`Go to the end ` + to download the full example code + +.. rst-class:: sphx-glr-example-title + +.. _sphx_glr_auto_examples_01_introductory_viz_timers.py: + + +=============== +Using a timer +=============== + +This example shows how to create a simple animation using a timer callback. + +We will use a sphere actor that generates many spheres of different colors, +radii and opacity. Then we will animate this actor by rotating and changing +global opacity levels from inside a user defined callback. + +The timer will call this user defined callback every 200 milliseconds. The +application will exit after the callback has been called 100 times. + +.. GENERATED FROM PYTHON SOURCE LINES 15-71 + + + +.. image-sg:: /auto_examples/01_introductory/images/sphx_glr_viz_timers_001.png + :alt: viz timers + :srcset: /auto_examples/01_introductory/images/sphx_glr_viz_timers_001.png + :class: sphx-glr-single-img + + + + + +.. code-block:: Python + + + + import itertools + + import numpy as np + + from fury import actor, ui, window + + xyz = 10 * np.random.rand(100, 3) + colors = np.random.rand(100, 4) + radii = np.random.rand(100) + 0.5 + + scene = window.Scene() + + sphere_actor = actor.sphere(centers=xyz, colors=colors, radii=radii) + + scene.add(sphere_actor) + + showm = window.ShowManager( + scene, size=(900, 768), reset_camera=False, order_transparent=True + ) + + + tb = ui.TextBlock2D(bold=True) + + # use itertools to avoid global variables + counter = itertools.count() + + + def timer_callback(_obj, _event): + global timer_id + cnt = next(counter) + tb.message = "Let's count up to 300 and exit :" + str(cnt) + showm.scene.azimuth(0.05 * cnt) + sphere_actor.GetProperty().SetOpacity(cnt / 100.0) + showm.render() + + if cnt == 10: + # destroy the first timer and replace it with another faster timer + showm.destroy_timer(timer_id) + timer_id = showm.add_timer_callback(True, 10, timer_callback) + + if cnt == 300: + # destroy the second timer and exit + showm.destroy_timer(timer_id) + showm.exit() + + + scene.add(tb) + + # Run every 200 milliseconds + timer_id = showm.add_timer_callback(True, 200, timer_callback) + + showm.start() + + window.record(showm.scene, size=(900, 768), out_path='viz_timer.png') + + +.. rst-class:: sphx-glr-timing + + **Total running time of the script:** (0 minutes 5.984 seconds) + + +.. _sphx_glr_download_auto_examples_01_introductory_viz_timers.py: + +.. only:: html + + .. container:: sphx-glr-footer sphx-glr-footer-example + + .. container:: sphx-glr-download sphx-glr-download-jupyter + + :download:`Download Jupyter notebook: viz_timers.ipynb ` + + .. container:: sphx-glr-download sphx-glr-download-python + + :download:`Download Python source code: viz_timers.py ` + + +.. only:: html + + .. rst-class:: sphx-glr-signature + + `Gallery generated by Sphinx-Gallery `_ diff --git a/v0.10.x/_sources/auto_examples/04_demos/collision-particles.rst.txt b/v0.10.x/_sources/auto_examples/04_demos/collision-particles.rst.txt new file mode 100644 index 000000000..2f722c9fb --- /dev/null +++ b/v0.10.x/_sources/auto_examples/04_demos/collision-particles.rst.txt @@ -0,0 +1,294 @@ + +.. DO NOT EDIT. +.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. +.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: +.. "auto_examples/04_demos/collision-particles.py" +.. LINE NUMBERS ARE GIVEN BELOW. + +.. only:: html + + .. note:: + :class: sphx-glr-download-link-note + + :ref:`Go to the end ` + to download the full example code + +.. rst-class:: sphx-glr-example-title + +.. _sphx_glr_auto_examples_04_demos_collision-particles.py: + + +Collisions of particles in a box +================================ + +This is a simple demonstration of how you can simulate moving +particles in a box using FURY. + +.. GENERATED FROM PYTHON SOURCE LINES 10-15 + +In this example, the particles collide with each other and with the walls +of the container. When the collision happens between two particles, +the particle with less velocity changes its color and gets the same color +as the particle with higher velocity. For simplicity, in this demo we +do not apply forces. + +.. GENERATED FROM PYTHON SOURCE LINES 15-22 + +.. code-block:: Python + + + import itertools + + import numpy as np + + from fury import actor, ui, utils, window + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 23-24 + +Here, we define the edges of the box. + +.. GENERATED FROM PYTHON SOURCE LINES 24-45 + +.. code-block:: Python + + + + def box_edges(box_lx, box_ly, box_lz): + + edge1 = 0.5 * np.array( + [ + [box_lx, box_ly, box_lz], + [box_lx, box_ly, -box_lz], + [-box_lx, box_ly, -box_lz], + [-box_lx, box_ly, box_lz], + [box_lx, box_ly, box_lz], + ] + ) + edge2 = 0.5 * np.array([[box_lx, box_ly, box_lz], [box_lx, -box_ly, box_lz]]) + edge3 = 0.5 * np.array([[box_lx, box_ly, -box_lz], [box_lx, -box_ly, -box_lz]]) + edge4 = 0.5 * np.array([[-box_lx, box_ly, -box_lz], [-box_lx, -box_ly, -box_lz]]) + edge5 = 0.5 * np.array([[-box_lx, box_ly, box_lz], [-box_lx, -box_ly, box_lz]]) + lines = [edge1, -edge1, edge2, edge3, edge4, edge5] + return lines + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 46-49 + +Here we define collision between walls-particles and particle-particle. +When collision happens, the particle with lower velocity gets the +color of the particle with higher velocity + +.. GENERATED FROM PYTHON SOURCE LINES 49-101 + +.. code-block:: Python + + + + def collision(): + global xyz + num_vertices = vertices.shape[0] + sec = int(num_vertices / num_particles) + + for i, j in np.ndindex(num_particles, num_particles): + + if i == j: + continue + distance = np.linalg.norm(xyz[i] - xyz[j]) + vel_mag_i = np.linalg.norm(vel[i]) + vel_mag_j = np.linalg.norm(vel[j]) + # Collision happens if the distance between the centers of two + # particles is less or equal to the sum of their radii + if distance <= (radii[i] + radii[j]): + vel[i] = -vel[i] + vel[j] = -vel[j] + if vel_mag_j > vel_mag_i: + vcolors[i * sec : i * sec + sec] = vcolors[j * sec : j * sec + sec] + if vel_mag_i > vel_mag_j: + vcolors[j * sec : j * sec + sec] = vcolors[i * sec : i * sec + sec] + xyz[i] = xyz[i] + vel[i] * dt + xyz[j] = xyz[j] + vel[j] * dt + # Collision between particles-walls; + vel[:, 0] = np.where( + ( + (xyz[:, 0] <= -0.5 * box_lx + radii[:]) + | (xyz[:, 0] >= (0.5 * box_lx - radii[:])) + ), + -vel[:, 0], + vel[:, 0], + ) + vel[:, 1] = np.where( + ( + (xyz[:, 1] <= -0.5 * box_ly + radii[:]) + | (xyz[:, 1] >= (0.5 * box_ly - radii[:])) + ), + -vel[:, 1], + vel[:, 1], + ) + vel[:, 2] = np.where( + ( + (xyz[:, 2] <= -0.5 * box_lz + radii[:]) + | (xyz[:, 2] >= (0.5 * box_lz - radii[:])) + ), + -vel[:, 2], + vel[:, 2], + ) + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 102-104 + +We define position, velocity, color and radius randomly for 50 particles +inside the box. + +.. GENERATED FROM PYTHON SOURCE LINES 104-119 + +.. code-block:: Python + + + global xyz + num_particles = 50 + box_lx = 20 + box_ly = 20 + box_lz = 10 + steps = 1000 + dt = 0.05 + xyz = ( + np.array([box_lx, box_ly, box_lz]) * (np.random.rand(num_particles, 3) - 0.5) * 0.6 + ) + vel = 4 * (np.random.rand(num_particles, 3) - 0.5) + colors = np.random.rand(num_particles, 3) + radii = np.random.rand(num_particles) + 0.01 + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 120-122 + +With box, streamtube and sphere actors, we can create the box, the +edges of the box and the spheres respectively. + +.. GENERATED FROM PYTHON SOURCE LINES 122-181 + +.. code-block:: Python + + + scene = window.Scene() + box_centers = np.array([[0, 0, 0]]) + box_directions = np.array([[0, 1, 0]]) + box_colors = np.array([[1, 1, 1, 0.2]]) + box_actor = actor.box( + box_centers, box_directions, box_colors, scales=(box_lx, box_ly, box_lz) + ) + scene.add(box_actor) + + lines = box_edges(box_lx, box_ly, box_lz) + line_actor = actor.streamtube(lines, colors=(1, 0.5, 0), linewidth=0.1) + scene.add(line_actor) + + sphere_actor = actor.sphere(centers=xyz, colors=colors, radii=radii) + scene.add(sphere_actor) + + showm = window.ShowManager( + scene, size=(900, 768), reset_camera=True, order_transparent=True + ) + + tb = ui.TextBlock2D(bold=True) + scene.zoom(0.8) + scene.azimuth(30) + + # use itertools to avoid global variables + counter = itertools.count() + + vertices = utils.vertices_from_actor(sphere_actor) + vcolors = utils.colors_from_actor(sphere_actor, 'colors') + no_vertices_per_sphere = len(vertices) / num_particles + initial_vertices = vertices.copy() - np.repeat(xyz, no_vertices_per_sphere, axis=0) + + + def timer_callback(_obj, _event): + global xyz + cnt = next(counter) + tb.message = "Let's count up to 1000 and exit :" + str(cnt) + xyz = xyz + vel * dt + collision() + + vertices[:] = initial_vertices + np.repeat(xyz, no_vertices_per_sphere, axis=0) + utils.update_actor(sphere_actor) + + scene.reset_clipping_range() + showm.render() + + if cnt == steps: + showm.exit() + + + scene.add(tb) + showm.add_timer_callback(True, 50, timer_callback) + + interactive = False + if interactive: + showm.start() + + window.record(showm.scene, size=(900, 768), out_path='simple_collisions.png') + + + +.. image-sg:: /auto_examples/04_demos/images/sphx_glr_collision-particles_001.png + :alt: collision particles + :srcset: /auto_examples/04_demos/images/sphx_glr_collision-particles_001.png + :class: sphx-glr-single-img + + + + + + +.. rst-class:: sphx-glr-timing + + **Total running time of the script:** (0 minutes 0.128 seconds) + + +.. _sphx_glr_download_auto_examples_04_demos_collision-particles.py: + +.. only:: html + + .. container:: sphx-glr-footer sphx-glr-footer-example + + .. container:: sphx-glr-download sphx-glr-download-jupyter + + :download:`Download Jupyter notebook: collision-particles.ipynb ` + + .. container:: sphx-glr-download sphx-glr-download-python + + :download:`Download Python source code: collision-particles.py ` + + +.. only:: html + + .. rst-class:: sphx-glr-signature + + `Gallery generated by Sphinx-Gallery `_ diff --git a/v0.10.x/_sources/auto_examples/04_demos/index.rst.txt b/v0.10.x/_sources/auto_examples/04_demos/index.rst.txt new file mode 100644 index 000000000..c50734c8a --- /dev/null +++ b/v0.10.x/_sources/auto_examples/04_demos/index.rst.txt @@ -0,0 +1,349 @@ + + +.. _sphx_glr_auto_examples_04_demos: + +Demos +----- + +Below is a gallery of Demos. A bunch of apps powered by FURY. + + + +.. raw:: html + +
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/04_demos/images/thumb/sphx_glr_viz_markers_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_04_demos_viz_markers.py` + +.. raw:: html + +
Fury Markers
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/04_demos/images/thumb/sphx_glr_viz_network_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_04_demos_viz_network.py` + +.. raw:: html + +
Visualize Interdisciplinary map of the journals network
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/04_demos/images/thumb/sphx_glr_viz_roi_contour_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_04_demos_viz_roi_contour.py` + +.. raw:: html + +
Visualization of ROI Surface Rendered with Streamlines
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/04_demos/images/thumb/sphx_glr_viz_helical_motion_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_04_demos_viz_helical_motion.py` + +.. raw:: html + +
Motion of a charged particle in a combined magnetic and electric field
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/04_demos/images/thumb/sphx_glr_viz_brownian_motion_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_04_demos_viz_brownian_motion.py` + +.. raw:: html + +
Brownian motion
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/04_demos/images/thumb/sphx_glr_viz_play_video_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_04_demos_viz_play_video.py` + +.. raw:: html + +
Play a video in the 3D world
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/04_demos/images/thumb/sphx_glr_viz_fine_tuning_gl_context_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_04_demos_viz_fine_tuning_gl_context.py` + +.. raw:: html + +
Fine-tuning the OpenGL state using shader callbacks
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/04_demos/images/thumb/sphx_glr_viz_emwave_animation_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_04_demos_viz_emwave_animation.py` + +.. raw:: html + +
Electromagnetic Wave Propagation Animation
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/04_demos/images/thumb/sphx_glr_viz_animated_surfaces_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_04_demos_viz_animated_surfaces.py` + +.. raw:: html + +
Animated 2D functions
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/04_demos/images/thumb/sphx_glr_viz_bundles_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_04_demos_viz_bundles.py` + +.. raw:: html + +
Visualize bundles and metrics on bundles
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/04_demos/images/thumb/sphx_glr_viz_tesseract_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_04_demos_viz_tesseract.py` + +.. raw:: html + +
Tesseract (Hypercube)
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/04_demos/images/thumb/sphx_glr_collision-particles_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_04_demos_collision-particles.py` + +.. raw:: html + +
Collisions of particles in a box
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/04_demos/images/thumb/sphx_glr_viz_advanced_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_04_demos_viz_advanced.py` + +.. raw:: html + +
Advanced interactive visualization
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/04_demos/images/thumb/sphx_glr_viz_fiber_odf_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_04_demos_viz_fiber_odf.py` + +.. raw:: html + +
Brain Fiber ODF Visualisation
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/04_demos/images/thumb/sphx_glr_viz_fractals_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_04_demos_viz_fractals.py` + +.. raw:: html + +
Fractals
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/04_demos/images/thumb/sphx_glr_viz_network_animated_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_04_demos_viz_network_animated.py` + +.. raw:: html + +
Visualize Networks (Animated version)
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/04_demos/images/thumb/sphx_glr_viz_dt_ellipsoids_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_04_demos_viz_dt_ellipsoids.py` + +.. raw:: html + +
Display Tensor Ellipsoids for DTI using tensor_slicer vs ellipsoid actor
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/04_demos/images/thumb/sphx_glr_viz_pbr_interactive_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_04_demos_viz_pbr_interactive.py` + +.. raw:: html + +
Interactive PBR demo
+
+ + +.. raw:: html + +
+ + +.. toctree:: + :hidden: + + /auto_examples/04_demos/viz_markers + /auto_examples/04_demos/viz_network + /auto_examples/04_demos/viz_roi_contour + /auto_examples/04_demos/viz_helical_motion + /auto_examples/04_demos/viz_brownian_motion + /auto_examples/04_demos/viz_play_video + /auto_examples/04_demos/viz_fine_tuning_gl_context + /auto_examples/04_demos/viz_emwave_animation + /auto_examples/04_demos/viz_animated_surfaces + /auto_examples/04_demos/viz_bundles + /auto_examples/04_demos/viz_tesseract + /auto_examples/04_demos/collision-particles + /auto_examples/04_demos/viz_advanced + /auto_examples/04_demos/viz_fiber_odf + /auto_examples/04_demos/viz_fractals + /auto_examples/04_demos/viz_network_animated + /auto_examples/04_demos/viz_dt_ellipsoids + /auto_examples/04_demos/viz_pbr_interactive + diff --git a/v0.10.x/_sources/auto_examples/04_demos/sg_execution_times.rst.txt b/v0.10.x/_sources/auto_examples/04_demos/sg_execution_times.rst.txt new file mode 100644 index 000000000..0cc179993 --- /dev/null +++ b/v0.10.x/_sources/auto_examples/04_demos/sg_execution_times.rst.txt @@ -0,0 +1,88 @@ + +:orphan: + +.. _sphx_glr_auto_examples_04_demos_sg_execution_times: + + +Computation times +================= +**00:16.543** total execution time for 18 files **from auto_examples/04_demos**: + +.. container:: + + .. raw:: html + + + + + + + + .. list-table:: + :header-rows: 1 + :class: table table-striped sg-datatable + + * - Example + - Time + - Mem (MB) + * - :ref:`sphx_glr_auto_examples_04_demos_viz_dt_ellipsoids.py` (``viz_dt_ellipsoids.py``) + - 00:08.555 + - 0.0 + * - :ref:`sphx_glr_auto_examples_04_demos_viz_network_animated.py` (``viz_network_animated.py``) + - 00:07.015 + - 0.0 + * - :ref:`sphx_glr_auto_examples_04_demos_viz_pbr_interactive.py` (``viz_pbr_interactive.py``) + - 00:00.974 + - 0.0 + * - :ref:`sphx_glr_auto_examples_04_demos_collision-particles.py` (``collision-particles.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_04_demos_viz_advanced.py` (``viz_advanced.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_04_demos_viz_animated_surfaces.py` (``viz_animated_surfaces.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_04_demos_viz_brownian_motion.py` (``viz_brownian_motion.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_04_demos_viz_bundles.py` (``viz_bundles.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_04_demos_viz_emwave_animation.py` (``viz_emwave_animation.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_04_demos_viz_fiber_odf.py` (``viz_fiber_odf.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_04_demos_viz_fine_tuning_gl_context.py` (``viz_fine_tuning_gl_context.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_04_demos_viz_fractals.py` (``viz_fractals.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_04_demos_viz_helical_motion.py` (``viz_helical_motion.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_04_demos_viz_markers.py` (``viz_markers.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_04_demos_viz_network.py` (``viz_network.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_04_demos_viz_play_video.py` (``viz_play_video.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_04_demos_viz_roi_contour.py` (``viz_roi_contour.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_04_demos_viz_tesseract.py` (``viz_tesseract.py``) + - 00:00.000 + - 0.0 diff --git a/v0.10.x/_sources/auto_examples/04_demos/viz_advanced.rst.txt b/v0.10.x/_sources/auto_examples/04_demos/viz_advanced.rst.txt new file mode 100644 index 000000000..f371ea9a5 --- /dev/null +++ b/v0.10.x/_sources/auto_examples/04_demos/viz_advanced.rst.txt @@ -0,0 +1,551 @@ + +.. DO NOT EDIT. +.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. +.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: +.. "auto_examples/04_demos/viz_advanced.py" +.. LINE NUMBERS ARE GIVEN BELOW. + +.. only:: html + + .. note:: + :class: sphx-glr-download-link-note + + :ref:`Go to the end ` + to download the full example code + +.. rst-class:: sphx-glr-example-title + +.. _sphx_glr_auto_examples_04_demos_viz_advanced.py: + + +================================== +Advanced interactive visualization +================================== + +In DIPY we created a thin interface to access many of the capabilities +available in the Visualization Toolkit framework (VTK) but tailored to the +needs of structural and diffusion imaging. Initially the 3D visualization +module was named ``fvtk``, meaning functions using vtk. This is still available +for backwards compatibility but now there is a more comprehensive way to access +the main functions using the following modules. + +.. GENERATED FROM PYTHON SOURCE LINES 13-17 + +.. code-block:: Python + + + import numpy as np + from dipy.data.fetcher import fetch_bundles_2_subjects, read_bundles_2_subjects + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 18-38 + +In ``window`` we have all the objects that connect what needs to be rendered +to the display or the disk e.g., for saving screenshots. So, there you will +find key objects and functions like the ``Scene`` class which holds and +provides access to all the actors and the ``show`` function which displays +what is in the scene on a window. Also, this module provides access to +functions for opening/saving dialogs and printing screenshots +(see ``snapshot``). + +In the ``actor`` module we can find all the different primitives e.g., +streamtubes, lines, image slices, etc. + +In the ``ui`` module we have some other objects which allow to add buttons +and sliders and these interact both with windows and actors. Because of this +they need input from the operating system so they can process events. + +Let's get started. In this tutorial, we will visualize some bundles +together with FA or T1. We will be able to change the slices using +a ``LineSlider2D`` widget. + +First we need to fetch and load some datasets. + +.. GENERATED FROM PYTHON SOURCE LINES 38-44 + +.. code-block:: Python + + from dipy.tracking.streamline import Streamlines + + from fury import actor, ui, window + + fetch_bundles_2_subjects() + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + + ({'bundles_2_subjects.tar.gz': ('https://digital.lib.washington.edu/researchworks/bitstream/handle/1773/38477/bundles_2_subjects.tar.gz', '97756fbef11ce2df31f1bedf1fc7aac7')}, '/Users/skoudoro/.dipy/exp_bundles_and_maps') + + + +.. GENERATED FROM PYTHON SOURCE LINES 45-48 + +The following function outputs a dictionary with the required bundles e.g. +``af left`` (left arcuate fasciculus) and maps, e.g. FA for a specific +subject. + +.. GENERATED FROM PYTHON SOURCE LINES 48-51 + +.. code-block:: Python + + + res = read_bundles_2_subjects('subj_1', ['t1', 'fa'], ['af.left', 'cst.right', 'cc_1']) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 52-54 + +We will use 3 bundles, FA and the affine transformation that brings the voxel +coordinates to world coordinates (RAS 1mm). + +.. GENERATED FROM PYTHON SOURCE LINES 54-63 + +.. code-block:: Python + + + streamlines = Streamlines(res['af.left']) + streamlines.extend(res['cst.right']) + streamlines.extend(res['cc_1']) + + data = res['fa'] + shape = data.shape + affine = res['affine'] + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 64-67 + +With our current design it is easy to decide in which space you want the +streamlines and slices to appear. The default we have here is to appear in +world coordinates (RAS 1mm). + +.. GENERATED FROM PYTHON SOURCE LINES 67-70 + +.. code-block:: Python + + + world_coords = True + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 71-74 + +If we want to see the objects in native space we need to make sure that all +objects which are currently in world coordinates are transformed back to +native space using the inverse of the affine. + +.. GENERATED FROM PYTHON SOURCE LINES 74-81 + +.. code-block:: Python + + + + if not world_coords: + from dipy.tracking.streamline import transform_streamlines + + streamlines = transform_streamlines(streamlines, np.linalg.inv(affine)) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 82-84 + +Now we create, a ``Scene`` object and add the streamlines using the +``line`` function and an image plane using the ``slice`` function. + +.. GENERATED FROM PYTHON SOURCE LINES 84-93 + +.. code-block:: Python + + + scene = window.Scene() + stream_actor = actor.line(streamlines) + + if not world_coords: + image_actor_z = actor.slicer(data, affine=np.eye(4)) + else: + image_actor_z = actor.slicer(data, affine) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 94-95 + +We can also change also the opacity of the slicer. + +.. GENERATED FROM PYTHON SOURCE LINES 95-99 + +.. code-block:: Python + + + slicer_opacity = 0.6 + image_actor_z.opacity(slicer_opacity) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 100-102 + +We can add additional slicers by copying the original and adjusting the +``display_extent``. + +.. GENERATED FROM PYTHON SOURCE LINES 102-111 + +.. code-block:: Python + + + image_actor_x = image_actor_z.copy() + x_midpoint = int(np.round(shape[0] / 2)) + image_actor_x.display_extent(x_midpoint, x_midpoint, 0, shape[1] - 1, 0, shape[2] - 1) + + image_actor_y = image_actor_z.copy() + y_midpoint = int(np.round(shape[1] / 2)) + image_actor_y.display_extent(0, shape[0] - 1, y_midpoint, y_midpoint, 0, shape[2] - 1) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 112-113 + +Connect the actors with the Scene. + +.. GENERATED FROM PYTHON SOURCE LINES 113-119 + +.. code-block:: Python + + + scene.add(stream_actor) + scene.add(image_actor_z) + scene.add(image_actor_x) + scene.add(image_actor_y) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 120-125 + +Now we would like to change the position of each ``image_actor`` using a +slider. The sliders are widgets which require access to different areas of +the visualization pipeline and therefore we don't recommend using them with +``show``. The more appropriate way is to use them with the ``ShowManager`` +object which allows accessing the pipeline in different areas. Here is how: + +.. GENERATED FROM PYTHON SOURCE LINES 125-129 + +.. code-block:: Python + + + show_m = window.ShowManager(scene, size=(1200, 900)) + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 130-132 + +After we have initialized the ``ShowManager`` we can go ahead and create +sliders to move the slices and change their opacity. + +.. GENERATED FROM PYTHON SOURCE LINES 132-161 + +.. code-block:: Python + + + line_slider_z = ui.LineSlider2D( + min_value=0, + max_value=shape[2] - 1, + initial_value=shape[2] / 2, + text_template='{value:.0f}', + length=140, + ) + + line_slider_x = ui.LineSlider2D( + min_value=0, + max_value=shape[0] - 1, + initial_value=shape[0] / 2, + text_template='{value:.0f}', + length=140, + ) + + line_slider_y = ui.LineSlider2D( + min_value=0, + max_value=shape[1] - 1, + initial_value=shape[1] / 2, + text_template='{value:.0f}', + length=140, + ) + + opacity_slider = ui.LineSlider2D( + min_value=0.0, max_value=1.0, initial_value=slicer_opacity, length=140 + ) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 162-163 + +Now we will write callbacks for the sliders and register them. + +.. GENERATED FROM PYTHON SOURCE LINES 163-192 + +.. code-block:: Python + + + + def change_slice_z(slider): + z = int(np.round(slider.value)) + image_actor_z.display_extent(0, shape[0] - 1, 0, shape[1] - 1, z, z) + + + def change_slice_x(slider): + x = int(np.round(slider.value)) + image_actor_x.display_extent(x, x, 0, shape[1] - 1, 0, shape[2] - 1) + + + def change_slice_y(slider): + y = int(np.round(slider.value)) + image_actor_y.display_extent(0, shape[0] - 1, y, y, 0, shape[2] - 1) + + + def change_opacity(slider): + slicer_opacity = slider.value + image_actor_z.opacity(slicer_opacity) + image_actor_x.opacity(slicer_opacity) + image_actor_y.opacity(slicer_opacity) + + + line_slider_z.on_change = change_slice_z + line_slider_x.on_change = change_slice_x + line_slider_y.on_change = change_slice_y + opacity_slider.on_change = change_opacity + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 193-194 + +We'll also create text labels to identify the sliders. + +.. GENERATED FROM PYTHON SOURCE LINES 194-216 + +.. code-block:: Python + + + + def build_label(text): + label = ui.TextBlock2D() + label.message = text + label.font_size = 18 + label.font_family = 'Arial' + label.justification = 'left' + label.bold = False + label.italic = False + label.shadow = False + label.background_color = (0, 0, 0) + label.color = (1, 1, 1) + + return label + + + line_slider_label_z = build_label(text='Z Slice') + line_slider_label_x = build_label(text='X Slice') + line_slider_label_y = build_label(text='Y Slice') + opacity_slider_label = build_label(text='Opacity') + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 217-218 + +Now we will create a ``panel`` to contain the sliders and labels. + +.. GENERATED FROM PYTHON SOURCE LINES 218-233 + +.. code-block:: Python + + + panel = ui.Panel2D(size=(300, 200), color=(1, 1, 1), opacity=0.1, align='right') + panel.center = (1030, 120) + + panel.add_element(line_slider_label_x, (0.1, 0.75)) + panel.add_element(line_slider_x, (0.38, 0.75)) + panel.add_element(line_slider_label_y, (0.1, 0.55)) + panel.add_element(line_slider_y, (0.38, 0.55)) + panel.add_element(line_slider_label_z, (0.1, 0.35)) + panel.add_element(line_slider_z, (0.38, 0.35)) + panel.add_element(opacity_slider_label, (0.1, 0.15)) + panel.add_element(opacity_slider, (0.38, 0.15)) + + show_m.scene.add(panel) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 234-241 + +Then, we can render all the widgets and everything else in the screen and +start the interaction using ``show_m.start()``. + + +However, if you change the window size, the panel will not update its +position properly. The solution to this issue is to update the position of +the panel using its ``re_align`` method every time the window size changes. + +.. GENERATED FROM PYTHON SOURCE LINES 241-255 + +.. code-block:: Python + + + + size = scene.GetSize() + + + def win_callback(obj, _event): + global size + if size != obj.GetSize(): + size_old = size + size = obj.GetSize() + size_change = [size[0] - size_old[0], 0] + panel.re_align(size_change) + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 256-258 + +Finally, please set the following variable to ``True`` to interact with the +datasets in 3D. + +.. GENERATED FROM PYTHON SOURCE LINES 258-277 + +.. code-block:: Python + + + interactive = False + + scene.zoom(1.5) + scene.reset_clipping_range() + + if interactive: + + show_m.add_window_callback(win_callback) + show_m.render() + show_m.start() + + else: + + window.record( + scene, out_path='bundles_and_3_slices.png', size=(1200, 900), reset_camera=False + ) + + del show_m + + + +.. image-sg:: /auto_examples/04_demos/images/sphx_glr_viz_advanced_001.png + :alt: viz advanced + :srcset: /auto_examples/04_demos/images/sphx_glr_viz_advanced_001.png + :class: sphx-glr-single-img + + + + + + +.. rst-class:: sphx-glr-timing + + **Total running time of the script:** (0 minutes 2.302 seconds) + + +.. _sphx_glr_download_auto_examples_04_demos_viz_advanced.py: + +.. only:: html + + .. container:: sphx-glr-footer sphx-glr-footer-example + + .. container:: sphx-glr-download sphx-glr-download-jupyter + + :download:`Download Jupyter notebook: viz_advanced.ipynb ` + + .. container:: sphx-glr-download sphx-glr-download-python + + :download:`Download Python source code: viz_advanced.py ` + + +.. only:: html + + .. rst-class:: sphx-glr-signature + + `Gallery generated by Sphinx-Gallery `_ diff --git a/v0.10.x/_sources/auto_examples/04_demos/viz_animated_surfaces.rst.txt b/v0.10.x/_sources/auto_examples/04_demos/viz_animated_surfaces.rst.txt new file mode 100644 index 000000000..610ef5880 --- /dev/null +++ b/v0.10.x/_sources/auto_examples/04_demos/viz_animated_surfaces.rst.txt @@ -0,0 +1,454 @@ + +.. DO NOT EDIT. +.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. +.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: +.. "auto_examples/04_demos/viz_animated_surfaces.py" +.. LINE NUMBERS ARE GIVEN BELOW. + +.. only:: html + + .. note:: + :class: sphx-glr-download-link-note + + :ref:`Go to the end ` + to download the full example code + +.. rst-class:: sphx-glr-example-title + +.. _sphx_glr_auto_examples_04_demos_viz_animated_surfaces.py: + + +=============================================== +Animated 2D functions +=============================================== + +This is a simple demonstration of how one can +animate 2D functions using FURY. + +.. GENERATED FROM PYTHON SOURCE LINES 11-12 + +Importing necessary modules + +.. GENERATED FROM PYTHON SOURCE LINES 12-19 + +.. code-block:: Python + + + import itertools + + import numpy as np + + from fury import actor, colormap, ui, utils, window + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 20-25 + +The following function is used to create and update the coordinates of the +points which are being used to plot the surface. It's also used to create +and update the colormap being used to color the surface. +Kindly note that only the z coordinate is being modified with time as only +the z coordinate is a function of time. + +.. GENERATED FROM PYTHON SOURCE LINES 25-42 + +.. code-block:: Python + + + + def update_surface(x, y, equation, cmap_name='viridis'): + + # z is the function F i.e. F(x, y, t) + z = eval(equation) + xyz = np.vstack([x, y, z]).T + + # creating the colormap + v = np.copy(z) + m_v = np.max(np.abs(v), axis=0) + v /= m_v if m_v else 1 + colors = colormap.create_colormap(v, name=cmap_name) + + return xyz, colors + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 43-66 + +Variables and their usage: +:time - float: initial value of the time variable i.e. value of the time variable at + the beginning of the program; (default = 0) +dt: float + amount by which ``time`` variable is incremented for every iteration + of timer_callback function (default = 0.1) +lower_xbound: float + lower bound of the x values in which the function is plotted + (default = -1) +upper_xbound: float + Upper bound of the x values in which the function is plotted + (default = 1) +lower_ybound: float + lower bound of the y values in which the function is plotted + (default = -1) +upper_ybound: float + Upper bound of the y values in which the function is plotted + (default = 1) +npoints: int + For high quality rendering, keep the number high but kindly note + that higher values for npoints slows down the animation + (default = 128) + + +.. GENERATED FROM PYTHON SOURCE LINES 66-75 + +.. code-block:: Python + + + time = 0 + dt = 0.1 + lower_xbound = -1 + upper_xbound = 1 + lower_ybound = -1 + upper_ybound = 1 + npoints = 128 + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 76-78 + +creating the x, y points which will be used to fit the equation to get +elevation and generate the surface + +.. GENERATED FROM PYTHON SOURCE LINES 78-84 + +.. code-block:: Python + + x = np.linspace(lower_xbound, upper_xbound, npoints) + y = np.linspace(lower_ybound, upper_ybound, npoints) + x, y = np.meshgrid(x, y) + x = x.reshape(-1) + y = y.reshape(-1) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 85-86 + +Function used to create surface obtained from 2D equation. + +.. GENERATED FROM PYTHON SOURCE LINES 86-101 + +.. code-block:: Python + + + + def create_surface(x, y, equation, colormap_name): + xyz, colors = update_surface(x, y, equation=equation, cmap_name=colormap_name) + surf = actor.surface(xyz, colors=colors) + surf.equation = equation + surf.cmap_name = colormap_name + surf.vertices = utils.vertices_from_actor(surf) + surf.no_vertices_per_point = len(surf.vertices) / npoints**2 + surf.initial_vertices = surf.vertices.copy() - np.repeat( + xyz, surf.no_vertices_per_point, axis=0 + ) + return surf + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 102-103 + +Equations to be plotted + +.. GENERATED FROM PYTHON SOURCE LINES 103-111 + +.. code-block:: Python + + eq1 = 'np.abs(np.sin(x*2*np.pi*np.cos(time/2)))**1*np.cos(time/2)*\ + np.abs(np.cos(y*2*np.pi*np.sin(time/2)))**1*np.sin(time/2)*1.2' + eq2 = '((x**2 - y**2)/(x**2 + y**2))**(2)*np.cos(6*np.pi*x*y-1.8*time)*0.24' + eq3 = '(np.sin(np.pi*2*x-np.sin(1.8*time))*np.cos(np.pi*2*y+np.cos(1.8*time)))\ + *0.48' + eq4 = 'np.cos(24*np.sqrt(x**2 + y**2) - 2*time)*0.18' + equations = [eq1, eq2, eq3, eq4] + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 112-113 + +List of colormaps to be used for the various functions. + +.. GENERATED FROM PYTHON SOURCE LINES 113-115 + +.. code-block:: Python + + cmap_names = ['hot', 'plasma', 'viridis', 'ocean'] + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 116-117 + +Creating a list of surfaces. + +.. GENERATED FROM PYTHON SOURCE LINES 117-124 + +.. code-block:: Python + + surfaces = [] + for i in range(4): + surfaces.append( + create_surface(x, y, equation=equations[i], colormap_name=cmap_names[i]) + ) + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 125-126 + +Creating a scene object and configuring the camera's position + +.. GENERATED FROM PYTHON SOURCE LINES 126-133 + +.. code-block:: Python + + + scene = window.Scene() + scene.set_camera( + position=(4.45, -21, 12), focal_point=(4.45, 0.0, 0.0), view_up=(0.0, 0.0, 1.0) + ) + showm = window.ShowManager(scene, size=(600, 600)) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 134-135 + +Creating a grid to interact with surfaces individually. + +.. GENERATED FROM PYTHON SOURCE LINES 135-159 + +.. code-block:: Python + + + # To store the function names + text = [] + for i in range(4): + t_actor = actor.vector_text( + 'Function ' + str(i + 1), pos=(0, 0, 0), scale=(0.17, 0.2, 0.2) + ) + text.append(t_actor) + + grid_ui = ui.GridUI( + actors=surfaces, + captions=text, + caption_offset=(-0.7, -2.5, 0), + dim=(1, 4), + cell_padding=2, + aspect_ratio=1, + rotation_axis=(0, 1, 0), + ) + showm.scene.add(grid_ui) + + # Adding an axes actor to the first surface. + showm.scene.add(actor.axes()) + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 160-161 + +Initializing text box to print the title of the animation + +.. GENERATED FROM PYTHON SOURCE LINES 161-165 + +.. code-block:: Python + + tb = ui.TextBlock2D(bold=True, position=(200, 60)) + tb.message = 'Animated 2D functions' + scene.add(tb) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 166-167 + +Initializing showm and counter + +.. GENERATED FROM PYTHON SOURCE LINES 167-170 + +.. code-block:: Python + + + counter = itertools.count() + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 171-172 + +end is used to decide when to end the animation + +.. GENERATED FROM PYTHON SOURCE LINES 172-175 + +.. code-block:: Python + + end = 200 + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 176-177 + +The 2D functions are updated and rendered here. + +.. GENERATED FROM PYTHON SOURCE LINES 177-202 + +.. code-block:: Python + + + + def timer_callback(_obj, _event): + global xyz, time + time += dt + cnt = next(counter) + + # updating the colors and vertices of the triangles used to form the + # surfaces + for surf in surfaces: + xyz, colors = update_surface( + x, y, equation=surf.equation, cmap_name=surf.cmap_name + ) + utils.update_surface_actor_colors(surf, colors) + surf.vertices[:] = surf.initial_vertices + np.repeat( + xyz, surf.no_vertices_per_point, axis=0 + ) + utils.update_actor(surf) + + showm.render() + # to end the animation + if cnt == end: + showm.exit() + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 203-204 + +Run every 30 milliseconds + +.. GENERATED FROM PYTHON SOURCE LINES 204-211 + +.. code-block:: Python + + showm.add_timer_callback(True, 30, timer_callback) + + interactive = False + if interactive: + showm.start() + + window.record(showm.scene, size=(600, 600), out_path='viz_animated_surfaces.png') + + + +.. image-sg:: /auto_examples/04_demos/images/sphx_glr_viz_animated_surfaces_001.png + :alt: viz animated surfaces + :srcset: /auto_examples/04_demos/images/sphx_glr_viz_animated_surfaces_001.png + :class: sphx-glr-single-img + + + + + + +.. rst-class:: sphx-glr-timing + + **Total running time of the script:** (0 minutes 0.450 seconds) + + +.. _sphx_glr_download_auto_examples_04_demos_viz_animated_surfaces.py: + +.. only:: html + + .. container:: sphx-glr-footer sphx-glr-footer-example + + .. container:: sphx-glr-download sphx-glr-download-jupyter + + :download:`Download Jupyter notebook: viz_animated_surfaces.ipynb ` + + .. container:: sphx-glr-download sphx-glr-download-python + + :download:`Download Python source code: viz_animated_surfaces.py ` + + +.. only:: html + + .. rst-class:: sphx-glr-signature + + `Gallery generated by Sphinx-Gallery `_ diff --git a/v0.10.x/_sources/auto_examples/04_demos/viz_brownian_motion.rst.txt b/v0.10.x/_sources/auto_examples/04_demos/viz_brownian_motion.rst.txt new file mode 100644 index 000000000..5568b174d --- /dev/null +++ b/v0.10.x/_sources/auto_examples/04_demos/viz_brownian_motion.rst.txt @@ -0,0 +1,336 @@ + +.. DO NOT EDIT. +.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. +.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: +.. "auto_examples/04_demos/viz_brownian_motion.py" +.. LINE NUMBERS ARE GIVEN BELOW. + +.. only:: html + + .. note:: + :class: sphx-glr-download-link-note + + :ref:`Go to the end ` + to download the full example code + +.. rst-class:: sphx-glr-example-title + +.. _sphx_glr_auto_examples_04_demos_viz_brownian_motion.py: + + +====================================================================== +Brownian motion +====================================================================== +Brownian motion, or pedesis, is the random motion of particles +suspended in a medium. In this animation, path followed by 20 particles +exhibiting brownian motion in 3D is plotted. + +Importing necessary modules + +.. GENERATED FROM PYTHON SOURCE LINES 11-17 + +.. code-block:: Python + + + import numpy as np + from scipy.stats import norm + + from fury import actor, ui, utils, window + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 18-37 + +Let's define some variable and their description: + +* **total_time**: time to be discretized via time_steps (default: 5) +* **num_total_steps**: total number of steps each particle will take + (default: 300) +* **time_step**: By default, it is equal to total_time / num_total_steps +* **counter_step**: to keep track of number of steps taken + (initialised to 0) +* **delta**: delta determines the "speed" of the Brownian motion. + Increase delta to speed up the motion of the particle(s). The random + variable of the position has a normal distribution whose mean is the + position at counter_step = 0 and whose variance is equal to + delta**2*time_step. (default: 1.8) +* **num_particles**: number of particles whose path will be plotted + (default: 20) +* **path_thickness**: thickness of line(s) that will be used to plot the + path(s) of the particle(s) (default: 3) +* **origin**: coordinate from which the the particle(s) begin the motion + (default: [0, 0, 0]) + +.. GENERATED FROM PYTHON SOURCE LINES 37-46 + +.. code-block:: Python + + + total_time = 5 + num_total_steps = 300 + counter_step = 0 + delta = 1.8 + num_particles = 20 + path_thickness = 3 + origin = [0, 0, 0] + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 47-49 + +We define a particle function that will return an actor, store and update +coordinates of the particles (the path of the particles). + +.. GENERATED FROM PYTHON SOURCE LINES 49-74 + +.. code-block:: Python + + + + def particle( + colors, + origin=[0, 0, 0], + num_total_steps=300, + total_time=5, + delta=1.8, + path_thickness=3, + ): + origin = np.asarray(origin, dtype=float) + position = np.tile(origin, (num_total_steps, 1)) + path_actor = actor.line([position], colors, linewidth=path_thickness) + path_actor.position = position + path_actor.delta = delta + path_actor.num_total_steps = num_total_steps + path_actor.time_step = total_time / num_total_steps + path_actor.vertices = utils.vertices_from_actor(path_actor) + path_actor.no_vertices_per_point = len(path_actor.vertices) / num_total_steps + path_actor.initial_vertices = path_actor.vertices.copy() - np.repeat( + position, path_actor.no_vertices_per_point, axis=0 + ) + return path_actor + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 75-76 + +The function `update_path` will simulate the the brownian motion. + +.. GENERATED FROM PYTHON SOURCE LINES 76-91 + +.. code-block:: Python + + + + def update_path(act, counter_step): + if counter_step < act.num_total_steps: + x, y, z = act.position[counter_step - 1] + x += norm.rvs(scale=act.delta**2 * act.time_step) + y += norm.rvs(scale=act.delta**2 * act.time_step) + z += norm.rvs(scale=act.delta**2 * act.time_step) + act.position[counter_step:] = [x, y, z] + act.vertices[:] = act.initial_vertices + np.repeat( + act.position, act.no_vertices_per_point, axis=0 + ) + utils.update_actor(act) + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 92-93 + +Creating a scene object and configuring the camera's position + +.. GENERATED FROM PYTHON SOURCE LINES 93-105 + +.. code-block:: Python + + + scene = window.Scene() + scene.background((1.0, 1.0, 1.0)) + scene.zoom(1.7) + scene.set_camera( + position=(0, 0, 40), focal_point=(0.0, 0.0, 0.0), view_up=(0.0, 0.0, 0.0) + ) + showm = window.ShowManager( + scene, size=(600, 600), reset_camera=True, order_transparent=True + ) + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 106-107 + +Creating a list of particle objects + +.. GENERATED FROM PYTHON SOURCE LINES 107-121 + +.. code-block:: Python + + + l_particle = [ + particle( + colors=np.random.rand(1, 3), + origin=origin, + num_total_steps=num_total_steps, + total_time=total_time, + path_thickness=path_thickness, + ) + for _ in range(num_particles) + ] + + scene.add(*l_particle) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 122-123 + +Creating a container (cube actor) inside which the particle(s) move around + +.. GENERATED FROM PYTHON SOURCE LINES 123-129 + +.. code-block:: Python + + + container_actor = actor.box( + centers=np.array([[0, 0, 0]]), colors=(0.5, 0.9, 0.7, 0.4), scales=6 + ) + scene.add(container_actor) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 130-131 + +Initializing text box to display the name of the animation + +.. GENERATED FROM PYTHON SOURCE LINES 131-137 + +.. code-block:: Python + + + tb = ui.TextBlock2D(bold=True, position=(235, 40), color=(0, 0, 0)) + tb.message = 'Brownian Motion' + scene.add(tb) + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 138-139 + +The path of the particles exhibiting Brownian motion is plotted here + +.. GENERATED FROM PYTHON SOURCE LINES 139-152 + +.. code-block:: Python + + + + def timer_callback(_obj, _event): + global counter_step, list_particle + counter_step += 1 + for p in l_particle: + update_path(p, counter_step=counter_step) + showm.render() + scene.azimuth(2) + if counter_step == num_total_steps: + showm.exit() + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 153-154 + +Run every 30 milliseconds + +.. GENERATED FROM PYTHON SOURCE LINES 154-159 + +.. code-block:: Python + + + + showm.add_timer_callback(True, 30, timer_callback) + showm.start() + window.record(showm.scene, size=(600, 600), out_path='viz_brownian_motion.png') + + + +.. image-sg:: /auto_examples/04_demos/images/sphx_glr_viz_brownian_motion_001.png + :alt: viz brownian motion + :srcset: /auto_examples/04_demos/images/sphx_glr_viz_brownian_motion_001.png + :class: sphx-glr-single-img + + + + + + +.. rst-class:: sphx-glr-timing + + **Total running time of the script:** (0 minutes 9.253 seconds) + + +.. _sphx_glr_download_auto_examples_04_demos_viz_brownian_motion.py: + +.. only:: html + + .. container:: sphx-glr-footer sphx-glr-footer-example + + .. container:: sphx-glr-download sphx-glr-download-jupyter + + :download:`Download Jupyter notebook: viz_brownian_motion.ipynb ` + + .. container:: sphx-glr-download sphx-glr-download-python + + :download:`Download Python source code: viz_brownian_motion.py ` + + +.. only:: html + + .. rst-class:: sphx-glr-signature + + `Gallery generated by Sphinx-Gallery `_ diff --git a/v0.10.x/_sources/auto_examples/04_demos/viz_bundles.rst.txt b/v0.10.x/_sources/auto_examples/04_demos/viz_bundles.rst.txt new file mode 100644 index 000000000..da0579e66 --- /dev/null +++ b/v0.10.x/_sources/auto_examples/04_demos/viz_bundles.rst.txt @@ -0,0 +1,599 @@ + +.. DO NOT EDIT. +.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. +.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: +.. "auto_examples/04_demos/viz_bundles.py" +.. LINE NUMBERS ARE GIVEN BELOW. + +.. only:: html + + .. note:: + :class: sphx-glr-download-link-note + + :ref:`Go to the end ` + to download the full example code + +.. rst-class:: sphx-glr-example-title + +.. _sphx_glr_auto_examples_04_demos_viz_bundles.py: + + +======================================== +Visualize bundles and metrics on bundles +======================================== + +First, let's download some available datasets. Here we are using a dataset +which provides metrics and bundles. + +.. GENERATED FROM PYTHON SOURCE LINES 9-23 + +.. code-block:: Python + + + import numpy as np + from dipy.data import fetch_bundles_2_subjects, read_bundles_2_subjects + from dipy.tracking.streamline import length, transform_streamlines + + from fury import actor, window + + interactive = False # set to True to show the interactive display window + + fetch_bundles_2_subjects() + dix = read_bundles_2_subjects( + subj_id='subj_1', metrics=['fa'], bundles=['cg.left', 'cst.right'] + ) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 24-25 + +Store fractional anisotropy. + +.. GENERATED FROM PYTHON SOURCE LINES 25-28 + +.. code-block:: Python + + + fa = dix['fa'] + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 29-30 + +Store grid to world transformation matrix. + +.. GENERATED FROM PYTHON SOURCE LINES 30-33 + +.. code-block:: Python + + + affine = dix['affine'] + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 34-35 + +Store the cingulum bundle. A bundle is a list of streamlines. + +.. GENERATED FROM PYTHON SOURCE LINES 35-38 + +.. code-block:: Python + + + bundle = dix['cg.left'] + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 39-42 + +It happened that this bundle is in world coordinates and therefore we need to +transform it into native image coordinates so that it is in the same +coordinate space as the ``fa`` image. + +.. GENERATED FROM PYTHON SOURCE LINES 42-45 + +.. code-block:: Python + + + bundle_native = transform_streamlines(bundle, np.linalg.inv(affine)) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 46-50 + +Show every streamline with an orientation color +=============================================== + +This is the default option when you are using ``line`` or ``streamtube``. + +.. GENERATED FROM PYTHON SOURCE LINES 50-68 + +.. code-block:: Python + + + scene = window.Scene() + + stream_actor = actor.line(bundle_native) + + scene.set_camera( + position=(-176.42, 118.52, 128.20), + focal_point=(113.30, 128.31, 76.56), + view_up=(0.18, 0.00, 0.98), + ) + + scene.add(stream_actor) + + if interactive: + window.show(scene, size=(600, 600), reset_camera=False) + + window.record(scene, out_path='bundle1.png', size=(600, 600)) + + + + +.. image-sg:: /auto_examples/04_demos/images/sphx_glr_viz_bundles_001.png + :alt: viz bundles + :srcset: /auto_examples/04_demos/images/sphx_glr_viz_bundles_001.png + :class: sphx-glr-single-img + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 69-73 + +You may wonder how we knew how to set the camera. This is very easy. You just +need to run ``window.show`` once see how you want to see the object and then +close the window and call the ``camera_info`` method which prints the +position, focal point and view up vectors of the camera. + +.. GENERATED FROM PYTHON SOURCE LINES 73-76 + +.. code-block:: Python + + + scene.camera_info() + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + # Active Camera + Position (-237.76, 115.97, 138.55) + Focal Point (112.80, 127.81, 76.06) + View Up (0.18, 0.00, 0.98) + + + + +.. GENERATED FROM PYTHON SOURCE LINES 77-81 + +Show every point with a value from a volume with default colormap +================================================================= + +Here we will need to input the ``fa`` map in ``streamtube`` or ``line``. + +.. GENERATED FROM PYTHON SOURCE LINES 81-85 + +.. code-block:: Python + + + scene.clear() + stream_actor2 = actor.line(bundle_native, fa, linewidth=0.1) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 86-87 + +We can also show the scalar bar. + +.. GENERATED FROM PYTHON SOURCE LINES 87-98 + +.. code-block:: Python + + + bar = actor.scalar_bar() + + scene.add(stream_actor2) + scene.add(bar) + + if interactive: + window.show(scene, size=(600, 600), reset_camera=False) + + window.record(scene, out_path='bundle2.png', size=(600, 600)) + + + + +.. image-sg:: /auto_examples/04_demos/images/sphx_glr_viz_bundles_002.png + :alt: viz bundles + :srcset: /auto_examples/04_demos/images/sphx_glr_viz_bundles_002.png + :class: sphx-glr-single-img + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 99-103 + +Show every point with a value from a volume with your colormap +============================================================== + +Here we will need to input the ``fa`` map in ``streamtube`` + +.. GENERATED FROM PYTHON SOURCE LINES 103-122 + +.. code-block:: Python + + + scene.clear() + + hue = (0.0, 0.0) # red only + saturation = (0.0, 1.0) # white to red + + lut_cmap = actor.colormap_lookup_table(hue_range=hue, saturation_range=saturation) + + stream_actor3 = actor.line(bundle_native, fa, linewidth=0.1, lookup_colormap=lut_cmap) + bar2 = actor.scalar_bar(lut_cmap) + + scene.add(stream_actor3) + scene.add(bar2) + + if interactive: + window.show(scene, size=(600, 600), reset_camera=False) + + window.record(scene, out_path='bundle3.png', size=(600, 600)) + + + + +.. image-sg:: /auto_examples/04_demos/images/sphx_glr_viz_bundles_003.png + :alt: viz bundles + :srcset: /auto_examples/04_demos/images/sphx_glr_viz_bundles_003.png + :class: sphx-glr-single-img + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 123-128 + +Show every bundle with a specific color +======================================== + +You can have a bundle with a specific color. In this example, we are choosing +orange. + +.. GENERATED FROM PYTHON SOURCE LINES 128-139 + +.. code-block:: Python + + + scene.clear() + stream_actor4 = actor.line(bundle_native, (1.0, 0.5, 0), linewidth=0.1) + + scene.add(stream_actor4) + + if interactive: + window.show(scene, size=(600, 600), reset_camera=False) + + window.record(scene, out_path='bundle4.png', size=(600, 600)) + + + + +.. image-sg:: /auto_examples/04_demos/images/sphx_glr_viz_bundles_004.png + :alt: viz bundles + :srcset: /auto_examples/04_demos/images/sphx_glr_viz_bundles_004.png + :class: sphx-glr-single-img + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 140-145 + +Show every streamline of a bundle with a different color +======================================================== + +Let's make a colormap where every streamline of the bundle is colored by its +length. + +.. GENERATED FROM PYTHON SOURCE LINES 145-173 + +.. code-block:: Python + + + scene.clear() + + lengths = length(bundle_native) + + hue = (0.5, 0.5) # blue only + saturation = (0.0, 1.0) # black to white + + lut_cmap = actor.colormap_lookup_table( + scale_range=(lengths.min(), lengths.max()), + hue_range=hue, + saturation_range=saturation, + ) + + stream_actor5 = actor.line( + bundle_native, lengths, linewidth=0.1, lookup_colormap=lut_cmap + ) + + scene.add(stream_actor5) + bar3 = actor.scalar_bar(lut_cmap) + + scene.add(bar3) + + if interactive: + window.show(scene, size=(600, 600), reset_camera=False) + + window.record(scene, out_path='bundle5.png', size=(600, 600)) + + + + +.. image-sg:: /auto_examples/04_demos/images/sphx_glr_viz_bundles_005.png + :alt: viz bundles + :srcset: /auto_examples/04_demos/images/sphx_glr_viz_bundles_005.png + :class: sphx-glr-single-img + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 174-180 + +Show every point of every streamline with a different color +============================================================ + +In this case in which we want to have a color per point and per streamline, +we can create a list of the colors to correspond to the list of streamlines +(bundles). Here in ``colors`` we will insert some random RGB colors. + +.. GENERATED FROM PYTHON SOURCE LINES 180-194 + +.. code-block:: Python + + + scene.clear() + + colors = [np.random.rand(*streamline.shape) for streamline in bundle_native] + + stream_actor6 = actor.line(bundle_native, np.vstack(colors), linewidth=0.2) + + scene.add(stream_actor6) + + if interactive: + window.show(scene, size=(600, 600), reset_camera=False) + + window.record(scene, out_path='bundle6.png', size=(600, 600)) + + + + +.. image-sg:: /auto_examples/04_demos/images/sphx_glr_viz_bundles_006.png + :alt: viz bundles + :srcset: /auto_examples/04_demos/images/sphx_glr_viz_bundles_006.png + :class: sphx-glr-single-img + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 195-203 + +Add depth cues to streamline rendering +============================================================ + +By default, lines are drawn with the same width on the screen, regardless of +their distance from the camera. To increase realism, we can enable +``depth_cue`` to make the lines shrink with distance from the camera. We +will return to the default color scheme from the first example. Note that +``depth_cue`` works best for ``linewidth`` <= 1. + +.. GENERATED FROM PYTHON SOURCE LINES 203-215 + +.. code-block:: Python + + + scene.clear() + + stream_actor7 = actor.line(bundle_native, linewidth=0.5, depth_cue=True) + + scene.add(stream_actor7) + + if interactive: + window.show(scene, size=(600, 600), reset_camera=False) + + window.record(scene, out_path='bundle7.png', size=(600, 600)) + + + + +.. image-sg:: /auto_examples/04_demos/images/sphx_glr_viz_bundles_007.png + :alt: viz bundles + :srcset: /auto_examples/04_demos/images/sphx_glr_viz_bundles_007.png + :class: sphx-glr-single-img + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 216-221 + +Render streamlines as fake tubes +============================================================ + +We can simulate the look of streamtubes by adding shading to streamlines with +``fake_tube``. Note that ``fake_tube`` requires ``linewidth`` > 1. + +.. GENERATED FROM PYTHON SOURCE LINES 221-233 + +.. code-block:: Python + + + scene.clear() + + stream_actor8 = actor.line(bundle_native, linewidth=3, fake_tube=True) + + scene.add(stream_actor8) + + if interactive: + window.show(scene, size=(600, 600), reset_camera=False) + + window.record(scene, out_path='bundle8.png', size=(600, 600)) + + + + +.. image-sg:: /auto_examples/04_demos/images/sphx_glr_viz_bundles_008.png + :alt: viz bundles + :srcset: /auto_examples/04_demos/images/sphx_glr_viz_bundles_008.png + :class: sphx-glr-single-img + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 234-240 + +Combine depth cues with fake tubes +============================================================ + +It is possible to fully simulate streamtubes by enabling both ``depth_cue`` +and ``fake_tube``. However, it can be challenging to choose a ``linewidth`` +that demonstrates both techniques well. + +.. GENERATED FROM PYTHON SOURCE LINES 240-252 + +.. code-block:: Python + + + scene.clear() + + stream_actor9 = actor.line(bundle_native, linewidth=3, depth_cue=True, fake_tube=True) + + scene.add(stream_actor9) + + if interactive: + window.show(scene, size=(600, 600), reset_camera=False) + + window.record(scene, out_path='bundle9.png', size=(600, 600)) + + + + +.. image-sg:: /auto_examples/04_demos/images/sphx_glr_viz_bundles_009.png + :alt: viz bundles + :srcset: /auto_examples/04_demos/images/sphx_glr_viz_bundles_009.png + :class: sphx-glr-single-img + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 253-260 + +Render streamlines as tubes +============================================================ + +For yet more realism, we can use ``streamtube``. Note that this actor +generates much more geometry than ``line``, so it is more computationally +expensive. For large datasets, it may be better to approximate tubes using +the methods described above. + +.. GENERATED FROM PYTHON SOURCE LINES 260-272 + +.. code-block:: Python + + + scene.clear() + + stream_actor10 = actor.streamtube(bundle_native, linewidth=0.5) + + scene.add(stream_actor10) + + if interactive: + window.show(scene, size=(600, 600), reset_camera=False) + + window.record(scene, out_path='bundle10.png', size=(600, 600)) + + + + +.. image-sg:: /auto_examples/04_demos/images/sphx_glr_viz_bundles_010.png + :alt: viz bundles + :srcset: /auto_examples/04_demos/images/sphx_glr_viz_bundles_010.png + :class: sphx-glr-single-img + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 273-275 + +In summary, we showed that there are many useful ways for visualizing maps +on bundles. + + +.. rst-class:: sphx-glr-timing + + **Total running time of the script:** (0 minutes 4.691 seconds) + + +.. _sphx_glr_download_auto_examples_04_demos_viz_bundles.py: + +.. only:: html + + .. container:: sphx-glr-footer sphx-glr-footer-example + + .. container:: sphx-glr-download sphx-glr-download-jupyter + + :download:`Download Jupyter notebook: viz_bundles.ipynb ` + + .. container:: sphx-glr-download sphx-glr-download-python + + :download:`Download Python source code: viz_bundles.py ` + + +.. only:: html + + .. rst-class:: sphx-glr-signature + + `Gallery generated by Sphinx-Gallery `_ diff --git a/v0.10.x/_sources/auto_examples/04_demos/viz_dt_ellipsoids.rst.txt b/v0.10.x/_sources/auto_examples/04_demos/viz_dt_ellipsoids.rst.txt new file mode 100644 index 000000000..967fe70c2 --- /dev/null +++ b/v0.10.x/_sources/auto_examples/04_demos/viz_dt_ellipsoids.rst.txt @@ -0,0 +1,653 @@ + +.. DO NOT EDIT. +.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. +.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: +.. "auto_examples/04_demos/viz_dt_ellipsoids.py" +.. LINE NUMBERS ARE GIVEN BELOW. + +.. only:: html + + .. note:: + :class: sphx-glr-download-link-note + + :ref:`Go to the end ` + to download the full example code + +.. rst-class:: sphx-glr-example-title + +.. _sphx_glr_auto_examples_04_demos_viz_dt_ellipsoids.py: + + +=============================================================================== +Display Tensor Ellipsoids for DTI using tensor_slicer vs ellipsoid actor +=============================================================================== +This tutorial is intended to show two ways of displaying diffusion tensor +ellipsoids for DTI visualization. The first is using the usual +``tensor_slicer`` that allows us to slice many tensors as ellipsoids. The +second is the generic ``ellipsoid`` actor that can be used to display different +amount of ellipsoids. + +We start by importing the necessary modules: + +.. GENERATED FROM PYTHON SOURCE LINES 13-24 + +.. code-block:: Python + + import itertools + + import numpy as np + + from dipy.io.image import load_nifti + + from fury import window, actor, ui + from fury.actor import _fa, _color_fa + from fury.data import fetch_viz_dmri, read_viz_dmri + from fury.primitive import prim_sphere + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 25-27 + +Now, we fetch and load the data needed to display the Diffusion Tensor +Images. + +.. GENERATED FROM PYTHON SOURCE LINES 27-30 + +.. code-block:: Python + + + fetch_viz_dmri() + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + Dataset is already in place. If you want to fetch it again please first remove the folder /Users/skoudoro/.fury/dmri + + ({'fodf.nii.gz': ('https://raw.githubusercontent.com/fury-gl/fury-data/master/dmri/fodf.nii.gz', '767ca3e4cd296e78421d83c32201b30be2d859c332210812140caac1b93d492b'), 'slice_evecs.nii.gz': ('https://raw.githubusercontent.com/fury-gl/fury-data/master/dmri/slice_evecs.nii.gz', '8843ECF3224CB8E3315B7251D1E303409A17D7137D3498A8833853C4603C6CC2'), 'slice_evals.nii.gz': ('https://raw.githubusercontent.com/fury-gl/fury-data/master/dmri/slice_evals.nii.gz', '3096B190B1146DD0EADDFECC0B4FBBD901F4933692ADD46A83F637F28B22122D'), 'roi_evecs.nii.gz': ('https://raw.githubusercontent.com/fury-gl/fury-data/master/dmri/roi_evecs.nii.gz', '89E569858A897E72C852A8F05BBCE0B21C1CA726E55508087A2DA5A38C212A17'), 'roi_evals.nii.gz': ('https://raw.githubusercontent.com/fury-gl/fury-data/master/dmri/roi_evals.nii.gz', 'F53C68CCCABF97F1326E93840A8B5CE2E767D66D692FFD955CA747FFF14EC781'), 'whole_brain_evecs.nii.gz': ('https://raw.githubusercontent.com/fury-gl/fury-data/master/dmri/whole_brain_evecs.nii.gz', '8A894F6AB404240E65451FA6D10FB5D74E2D0BDCB2A56AD6BEA38215BF787248'), 'whole_brain_evals.nii.gz': ('https://raw.githubusercontent.com/fury-gl/fury-data/master/dmri/whole_brain_evals.nii.gz', '47A73BBE68196381ED790F80F48E46AC07B699B506973FFA45A95A33023C7A77')}, '/Users/skoudoro/.fury/dmri') + + + +.. GENERATED FROM PYTHON SOURCE LINES 31-34 + +The tensor ellipsoids are expressed as eigenvalues and eigenvectors which are +the decomposition of the diffusion tensor that describes the water diffusion +within a voxel. + +.. GENERATED FROM PYTHON SOURCE LINES 34-42 + +.. code-block:: Python + + + slice_evecs, _ = load_nifti(read_viz_dmri('slice_evecs.nii.gz')) + slice_evals, _ = load_nifti(read_viz_dmri('slice_evals.nii.gz')) + roi_evecs, _ = load_nifti(read_viz_dmri('roi_evecs.nii.gz')) + roi_evals, _ = load_nifti(read_viz_dmri('roi_evals.nii.gz')) + whole_brain_evecs, _ = load_nifti(read_viz_dmri('whole_brain_evecs.nii.gz')) + whole_brain_evals, _ = load_nifti(read_viz_dmri('whole_brain_evals.nii.gz')) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 43-51 + +Using tensor_slicer actor +========================= +First we must define the 3 parameters needed to use the ``tensor_slicer`` +actor, which correspond to the eigenvalues, the eigenvectors, and the sphere. +For the sphere we use ``prim_sphere`` which provide vertices and triangles of +the spheres. These are labeled as 'repulsionN' with N been the number of +vertices that made up the sphere, which have a standard number of 100, 200, +and 724 vertices. + +.. GENERATED FROM PYTHON SOURCE LINES 51-55 + +.. code-block:: Python + + + vertices, faces = prim_sphere('repulsion100', True) + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 56-58 + +As we need to provide a sphere object we create a class Sphere to which we +assign the values obtained from vertices and faces. + +.. GENERATED FROM PYTHON SOURCE LINES 58-67 + +.. code-block:: Python + + + class Sphere: + def __init__(self, vertices, faces): + self.vertices = vertices + self.faces = faces + + + sphere100 = Sphere(vertices, faces) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 68-71 + +Now we are ready to create the ``tensor_slicer`` actor with the values of a +brain slice. We also define the scale so that the tensors are not so large +and overlap each other. + +.. GENERATED FROM PYTHON SOURCE LINES 71-75 + +.. code-block:: Python + + + tensor_slice = actor.tensor_slicer(evals=slice_evals, evecs=slice_evecs, + sphere=sphere100, scale=.3) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 76-78 + +Next, we set up a new scene to add and visualize the tensor ellipsoids +created. + +.. GENERATED FROM PYTHON SOURCE LINES 78-94 + +.. code-block:: Python + + + scene = window.Scene() + scene.background([255, 255, 255]) + scene.add(tensor_slice) + + # Create show manager + showm = window.ShowManager(scene, size=(600, 600)) + + # Enables/disables interactive visualization + interactive = False + + if interactive: + showm.start() + + window.record(showm.scene, size=(600, 600), out_path='tensor_slice_100.png') + + + + +.. image-sg:: /auto_examples/04_demos/images/sphx_glr_viz_dt_ellipsoids_001.png + :alt: viz dt ellipsoids + :srcset: /auto_examples/04_demos/images/sphx_glr_viz_dt_ellipsoids_001.png + :class: sphx-glr-single-img + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 95-97 + +If we zoom in at the scene to see with detail the tensor ellipsoids displayed +with the different spheres, we get the following results. + +.. GENERATED FROM PYTHON SOURCE LINES 97-110 + +.. code-block:: Python + + + scene.roll(10) + scene.pitch(90) + showm = window.ShowManager(scene, size=(600, 600), order_transparent=True) + showm.scene.zoom(50) + + if interactive: + showm.render() + showm.start() + + window.record(showm.scene, out_path='tensor_slice_100_zoom.png', + size=(600, 300), reset_camera=False) + + + + +.. image-sg:: /auto_examples/04_demos/images/sphx_glr_viz_dt_ellipsoids_002.png + :alt: viz dt ellipsoids + :srcset: /auto_examples/04_demos/images/sphx_glr_viz_dt_ellipsoids_002.png + :class: sphx-glr-single-img + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 111-117 + +To render the same tensor slice using a different sphere we redefine the +vertices and faces of the sphere using prim_sphere with other sphere +specification, as 'repulsion200' or 'repulsion724'. + +Now we clear the scene for the next visualization, and revert the scene +rotations. + +.. GENERATED FROM PYTHON SOURCE LINES 117-123 + +.. code-block:: Python + + + showm.scene.clear() + showm.scene.pitch(-90) + showm.scene.roll(-10) + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 124-130 + +Using ellipsoid actor +===================== +In order to use the ``ellipsoid`` actor to display the same tensor slice we +need to set additional parameters. For this purpose, we define a helper +function to facilitate the correct setting of the parameters before passing +them to the actor. + +.. GENERATED FROM PYTHON SOURCE LINES 130-152 + +.. code-block:: Python + + + def get_params(evecs, evals): + # We define the centers which corresponds to the ellipsoids positions. + valid_mask = np.abs(evecs).max(axis=(-2, -1)) > 0 + indices = np.nonzero(valid_mask) + centers = np.asarray(indices).T + + # We need to pass the data of the axes and lengths of the ellipsoid as a + # ndarray, so it is necessary to rearrange the data of the eigenvectors and + # eigenvalues. + fevecs = evecs[indices] + fevals = evals[indices] + + # We need to define the colors of the ellipsoids following the default + # coloring in tensor_slicer that is uses _color_fa that is a way to map + # colors to each tensor based on the fractional anisotropy (FA) of each + # diffusion tensor. + colors = _color_fa(_fa(fevals), fevecs) + + return centers, fevecs, fevals, colors + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 153-155 + +With this we now have the values we need to define the centers, axes, +lengths, and colors of the ellipsoids. + +.. GENERATED FROM PYTHON SOURCE LINES 155-158 + +.. code-block:: Python + + + centers, evecs, evals, colors = get_params(slice_evecs, slice_evals) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 159-161 + +Now, we can use the ``ellipsoid`` actor to create the tensor ellipsoids as +follows. + +.. GENERATED FROM PYTHON SOURCE LINES 161-171 + +.. code-block:: Python + + + tensors = actor.ellipsoid(centers=centers, colors=colors, axes=evecs, + lengths=evals, scales=.6) + showm.scene.add(tensors) + + if interactive: + showm.start() + + window.record(scene, size=(600, 600), out_path='tensor_slice_sdf.png') + + + + +.. image-sg:: /auto_examples/04_demos/images/sphx_glr_viz_dt_ellipsoids_003.png + :alt: viz dt ellipsoids + :srcset: /auto_examples/04_demos/images/sphx_glr_viz_dt_ellipsoids_003.png + :class: sphx-glr-single-img + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 172-177 + +Thus, one can see that the same result is obtained, however there is a +difference in the visual quality and this is because the ``ellipsoid`` actor +uses raymarching technique, so the objects that are generated are smoother +since they are not made with polygons but defined by an SDF function. Next we +can see in more detail the tensor ellipsoids generated. + +.. GENERATED FROM PYTHON SOURCE LINES 177-194 + +.. code-block:: Python + + + scene.roll(10) + scene.pitch(90) + showm = window.ShowManager(scene, size=(600, 600), order_transparent=True) + showm.scene.zoom(50) + + if interactive: + showm.render() + showm.start() + + window.record(showm.scene, out_path='tensor_slice_sdf_zoom.png', + size=(600, 300), reset_camera=False) + + showm.scene.clear() + showm.scene.pitch(-90) + showm.scene.roll(-10) + + + + +.. image-sg:: /auto_examples/04_demos/images/sphx_glr_viz_dt_ellipsoids_004.png + :alt: viz dt ellipsoids + :srcset: /auto_examples/04_demos/images/sphx_glr_viz_dt_ellipsoids_004.png + :class: sphx-glr-single-img + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 195-203 + +Visual quality comparison +========================= +One can see that there is a different on the visual quality of both ways of +displaying tensors and this is because ``tensor_slicer`` uses polygons while +``ellipsoid`` uses raymarching. Let's display both implementations at the +same time, so we can see this in more detail. + +We first set up the required data and create the actors. + +.. GENERATED FROM PYTHON SOURCE LINES 203-229 + +.. code-block:: Python + + + mevals = np.array([1.4, 1.0, 0.35]) * 10 ** (-3) + mevecs = np.array([[2/3, -2/3, 1/3], [1/3, 2/3, 2/3], [2/3, 1/3, -2/3]]) + + evals = np.zeros((1, 1, 1, 3)) + evecs = np.zeros((1, 1, 1, 3, 3)) + + evals[..., :] = mevals + evecs[..., :, :] = mevecs + + vertices, faces = prim_sphere('repulsion200', True) + sphere200 = Sphere(vertices, faces) + vertices, faces = prim_sphere('repulsion724', True) + sphere724 = Sphere(vertices, faces) + + tensor_100 = actor.tensor_slicer(evals=evals, evecs=evecs, + sphere=sphere100, scale=1.0) + tensor_200 = actor.tensor_slicer(evals=evals, evecs=evecs, + sphere=sphere200, scale=1.0) + tensor_724 = actor.tensor_slicer(evals=evals, evecs=evecs, + sphere=sphere724, scale=1.0) + + centers, evecs, evals, colors = get_params(evecs=evecs, evals=evals) + tensor_sdf = actor.ellipsoid(centers=centers, axes=evecs, lengths=evals, + colors=colors, scales=2.0) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 230-232 + +Next, we made use of `GridUI` which allows us to add the actors in a grid and +interact with them individually. + +.. GENERATED FROM PYTHON SOURCE LINES 232-255 + +.. code-block:: Python + + + objects = [tensor_100, tensor_200, tensor_724, tensor_sdf] + text = [actor.vector_text('Tensor 100'), actor.vector_text('Tensor 200'), + actor.vector_text('Tensor 724'), actor.vector_text('Tensor SDF')] + + grid_ui = ui.GridUI(actors=objects, captions=text, cell_padding=.1, + caption_offset=(-0.7, -2.5, 0), dim=(1, 4)) + + scene = window.Scene() + scene.background([255, 255, 255]) + scene.zoom(3.5) + scene.set_camera(position=(3.2, -20, 12), focal_point=(3.2, 0.0, 0.0)) + showm = window.ShowManager(scene, size=(560, 200)) + showm.scene.add(grid_ui) + + if interactive: + showm.start() + + window.record(showm.scene, size=(560, 200), out_path='tensor_comparison.png', + reset_camera=False, magnification=2) + + showm.scene.clear() + + + + +.. image-sg:: /auto_examples/04_demos/images/sphx_glr_viz_dt_ellipsoids_005.png + :alt: viz dt ellipsoids + :srcset: /auto_examples/04_demos/images/sphx_glr_viz_dt_ellipsoids_005.png + :class: sphx-glr-single-img + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 256-261 + +Visualize a larger amount of data +================================= +With ``tensor_slicer`` is possible to visualize more than one slice using +``display_extent()``. Here we can see an example of a region of interest +(ROI) using a sphere of 100 vertices. + +.. GENERATED FROM PYTHON SOURCE LINES 261-281 + +.. code-block:: Python + + + tensor_roi = actor.tensor_slicer(evals=roi_evals, evecs=roi_evecs, + sphere=sphere100, scale=.3) + + data_shape = roi_evals.shape[:3] + tensor_roi.display_extent( + 0, data_shape[0], 0, data_shape[1], 0, data_shape[2]) + + showm.size = (600, 600) + showm.scene.background([0, 0, 0]) + showm.scene.add(tensor_roi) + showm.scene.azimuth(87) + + if interactive: + showm.start() + + window.record(showm.scene, size=(600, 600), out_path='tensor_roi_100.png') + + showm.scene.clear() + + + + +.. image-sg:: /auto_examples/04_demos/images/sphx_glr_viz_dt_ellipsoids_006.png + :alt: viz dt ellipsoids + :srcset: /auto_examples/04_demos/images/sphx_glr_viz_dt_ellipsoids_006.png + :class: sphx-glr-single-img + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 282-286 + +We can do it also with a sphere of 200 vertices, but if we try to do it with +one of 724 the visualization can no longer be rendered. In contrast, we can +visualize the ROI with the ``ellipsoid`` actor without compromising the +quality of the visualization. + +.. GENERATED FROM PYTHON SOURCE LINES 286-300 + +.. code-block:: Python + + + centers, evecs, evals, colors = get_params(roi_evecs, roi_evals) + + tensors = actor.ellipsoid(centers=centers, colors=colors, axes=evecs, + lengths=evals, scales=.6) + showm.scene.add(tensors) + + if interactive: + showm.start() + + window.record(showm.scene, size=(600, 600), out_path='tensor_roi_sdf.png') + + showm.scene.clear() + + + + +.. image-sg:: /auto_examples/04_demos/images/sphx_glr_viz_dt_ellipsoids_007.png + :alt: viz dt ellipsoids + :srcset: /auto_examples/04_demos/images/sphx_glr_viz_dt_ellipsoids_007.png + :class: sphx-glr-single-img + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 301-304 + +In fact, although with a low performance, this actor allows us to visualize +the whole brain, which contains a much larger amount of data, to be exact +184512 tensor ellipsoids are displayed at the same time. + +.. GENERATED FROM PYTHON SOURCE LINES 304-330 + +.. code-block:: Python + + + centers, evecs, evals, colors = get_params(whole_brain_evecs, + whole_brain_evals) + + # We remove all the noise around the brain to have a better visualization. + fil = [len(set(elem)) != 1 for elem in evals] + centers = np.array(list(itertools.compress(centers, fil))) + colors = np.array(list(itertools.compress(colors, fil))) + evecs = np.array(list(itertools.compress(evecs, fil))) + evals = np.array(list(itertools.compress(evals, fil))) + + tensors = actor.ellipsoid(centers=centers, colors=colors, axes=evecs, + lengths=evals, scales=.6) + + scene = window.Scene() + scene.add(tensors) + scene.pitch(180) + showm = window.ShowManager(scene, size=(600, 600)) + + if interactive: + showm.start() + + window.record(showm.scene, size=(600, 600), reset_camera=False, + out_path='tensor_whole_brain_sdf.png') + + showm.scene.clear() + + + +.. image-sg:: /auto_examples/04_demos/images/sphx_glr_viz_dt_ellipsoids_008.png + :alt: viz dt ellipsoids + :srcset: /auto_examples/04_demos/images/sphx_glr_viz_dt_ellipsoids_008.png + :class: sphx-glr-single-img + + + + + + +.. rst-class:: sphx-glr-timing + + **Total running time of the script:** (0 minutes 8.555 seconds) + + +.. _sphx_glr_download_auto_examples_04_demos_viz_dt_ellipsoids.py: + +.. only:: html + + .. container:: sphx-glr-footer sphx-glr-footer-example + + .. container:: sphx-glr-download sphx-glr-download-jupyter + + :download:`Download Jupyter notebook: viz_dt_ellipsoids.ipynb ` + + .. container:: sphx-glr-download sphx-glr-download-python + + :download:`Download Python source code: viz_dt_ellipsoids.py ` + + +.. only:: html + + .. rst-class:: sphx-glr-signature + + `Gallery generated by Sphinx-Gallery `_ diff --git a/v0.10.x/_sources/auto_examples/04_demos/viz_emwave_animation.rst.txt b/v0.10.x/_sources/auto_examples/04_demos/viz_emwave_animation.rst.txt new file mode 100644 index 000000000..d41ffc70f --- /dev/null +++ b/v0.10.x/_sources/auto_examples/04_demos/viz_emwave_animation.rst.txt @@ -0,0 +1,385 @@ + +.. DO NOT EDIT. +.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. +.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: +.. "auto_examples/04_demos/viz_emwave_animation.py" +.. LINE NUMBERS ARE GIVEN BELOW. + +.. only:: html + + .. note:: + :class: sphx-glr-download-link-note + + :ref:`Go to the end ` + to download the full example code + +.. rst-class:: sphx-glr-example-title + +.. _sphx_glr_auto_examples_04_demos_viz_emwave_animation.py: + + +=============================================== +Electromagnetic Wave Propagation Animation +=============================================== + +A linearly polarized sinusoidal electromagnetic wave, propagating in the +direction +x through a homogeneous, isotropic, dissipationless medium, +such as vacuum. The electric field (blue arrows) oscillates in the +±z-direction, and the orthogonal magnetic field (red arrows) oscillates in +phase with the electric field, but in the ±y-direction. + +Function of the sinusoid used in the animation = sin(k*x - w*t + d) +Where, k:wavenumber, x:abscissa, w:angular frequency, t:time, d:phase angle + +Importing necessary modules + +.. GENERATED FROM PYTHON SOURCE LINES 17-24 + +.. code-block:: Python + + + import itertools + + import numpy as np + + from fury import actor, ui, utils, window + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 25-27 + +function that updates and returns the coordinates of the waves which are +changing with time + +.. GENERATED FROM PYTHON SOURCE LINES 27-36 + +.. code-block:: Python + + + + def update_coordinates(wavenumber, ang_frq, time, phase_angle): + x = np.linspace(-3, 3, npoints) + y = np.sin(wavenumber * x - ang_frq * time + phase_angle) + z = np.array([0 for i in range(npoints)]) + return x, y, z + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 37-48 + +Variable(s) and their description- +npoints: For high quality rendering, keep the number of npoints high + but kindly note that higher values for npoints will slow down the + rendering process (default = 800) +wavelength : wavelength of the wave (default = 2) +wavenumber : 2*pi/wavelength +time: time (default time i.e. time at beginning of the animation = 0) +incre_time: value by which time is incremented for each call of + timer_callback (default = 0.1) +angular_frq: angular frequency (default = 0.1) +phase_angle: phase angle (default = 0.002) + +.. GENERATED FROM PYTHON SOURCE LINES 48-58 + +.. code-block:: Python + + + + npoints = 800 + wavelength = 2 + wavenumber = 2 * np.pi / wavelength + time = 0 + incre_time = 0.1 + angular_frq = 0.1 + phase_angle = 0.002 + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 59-60 + +Creating a scene object and configuring the camera's position + +.. GENERATED FROM PYTHON SOURCE LINES 60-70 + +.. code-block:: Python + + + scene = window.Scene() + scene.set_camera( + position=(-6, 5, -10), focal_point=(0.0, 0.0, 0.0), view_up=(0.0, 0.0, 0.0) + ) + showm = window.ShowManager( + scene, size=(800, 600), reset_camera=True, order_transparent=True + ) + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 71-73 + +Creating a yellow colored arrow to show the direction of propagation of +electromagnetic wave + +.. GENERATED FROM PYTHON SOURCE LINES 73-90 + +.. code-block:: Python + + + centers = np.array([[3, 0, 0]]) + directions = np.array([[-1, 0, 0]]) + heights = np.array([6.4]) + arrow_actor = actor.arrow( + centers, + directions, + window.colors.yellow, + heights, + resolution=20, + tip_length=0.06, + tip_radius=0.012, + shaft_radius=0.005, + ) + scene.add(arrow_actor) + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 91-92 + +Creating point actor that renders the magnetic field + +.. GENERATED FROM PYTHON SOURCE LINES 92-109 + +.. code-block:: Python + + + x = np.linspace(-3, 3, npoints) + y = np.sin(wavenumber * x - angular_frq * time + phase_angle) + z = np.array([0 for i in range(npoints)]) + + pts = np.array([(a, b, c) for (a, b, c) in zip(x, y, z)]) + pts = [pts] + colors = window.colors.red + wave_actor1 = actor.line(pts, colors, linewidth=3) + scene.add(wave_actor1) + + vertices = utils.vertices_from_actor(wave_actor1) + vcolors = utils.colors_from_actor(wave_actor1, 'colors') + no_vertices_per_point = len(vertices) / npoints + initial_vertices = vertices.copy() - np.repeat(pts, no_vertices_per_point, axis=0) + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 110-111 + +Creating point actor that renders the electric field + +.. GENERATED FROM PYTHON SOURCE LINES 111-128 + +.. code-block:: Python + + + xx = np.linspace(-3, 3, npoints) + yy = np.array([0 for i in range(npoints)]) + zz = np.sin(wavenumber * xx - angular_frq * time + phase_angle) + + pts2 = np.array([(a, b, c) for (a, b, c) in zip(xx, yy, zz)]) + pts2 = [pts2] + colors2 = window.colors.blue + wave_actor2 = actor.line(pts2, colors2, linewidth=3) + scene.add(wave_actor2) + + vertices2 = utils.vertices_from_actor(wave_actor2) + vcolors2 = utils.colors_from_actor(wave_actor2, 'colors') + no_vertices_per_point2 = len(vertices2) / npoints + initial_vertices2 = vertices2.copy() - np.repeat(pts2, no_vertices_per_point2, axis=0) + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 129-130 + +Initializing text box to display the title of the animation + +.. GENERATED FROM PYTHON SOURCE LINES 130-135 + +.. code-block:: Python + + + tb = ui.TextBlock2D(bold=True, position=(160, 90)) + tb.message = 'Electromagnetic Wave' + scene.add(tb) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 136-137 + +end is used to decide when to end the animation + +.. GENERATED FROM PYTHON SOURCE LINES 137-140 + +.. code-block:: Python + + + end = 300 + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 141-142 + +Initializing counter + +.. GENERATED FROM PYTHON SOURCE LINES 142-146 + +.. code-block:: Python + + + counter = itertools.count() + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 147-149 + +Coordinates to be plotted are changed every time timer_callback is called by +using the update_coordinates function. The wave is rendered here. + +.. GENERATED FROM PYTHON SOURCE LINES 149-173 + +.. code-block:: Python + + + + def timer_callback(_obj, _event): + global pts, pts2, time, time_incre, angular_frq, phase_angle, wavenumber + time += incre_time + cnt = next(counter) + + x, y, z = update_coordinates(wavenumber, angular_frq, phase_angle, time) + pts = np.array([(a, b, c) for (a, b, c) in zip(x, y, z)]) + vertices[:] = initial_vertices + np.repeat(pts, no_vertices_per_point, axis=0) + utils.update_actor(wave_actor1) + + xx, zz, yy = update_coordinates(wavenumber, angular_frq, phase_angle, time) + pts2 = np.array([(a, b, c) for (a, b, c) in zip(xx, yy, zz)]) + vertices2[:] = initial_vertices2 + np.repeat(pts2, no_vertices_per_point2, axis=0) + utils.update_actor(wave_actor2) + + showm.render() + + # to end the animation + if cnt == end: + showm.exit() + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 174-175 + +Run every 25 milliseconds + +.. GENERATED FROM PYTHON SOURCE LINES 175-182 + +.. code-block:: Python + + + showm.add_timer_callback(True, 25, timer_callback) + + interactive = False + if interactive: + showm.start() + window.record(showm.scene, size=(800, 600), out_path='viz_emwave.png') + + + +.. image-sg:: /auto_examples/04_demos/images/sphx_glr_viz_emwave_animation_001.png + :alt: viz emwave animation + :srcset: /auto_examples/04_demos/images/sphx_glr_viz_emwave_animation_001.png + :class: sphx-glr-single-img + + + + + + +.. rst-class:: sphx-glr-timing + + **Total running time of the script:** (0 minutes 0.524 seconds) + + +.. _sphx_glr_download_auto_examples_04_demos_viz_emwave_animation.py: + +.. only:: html + + .. container:: sphx-glr-footer sphx-glr-footer-example + + .. container:: sphx-glr-download sphx-glr-download-jupyter + + :download:`Download Jupyter notebook: viz_emwave_animation.ipynb ` + + .. container:: sphx-glr-download sphx-glr-download-python + + :download:`Download Python source code: viz_emwave_animation.py ` + + +.. only:: html + + .. rst-class:: sphx-glr-signature + + `Gallery generated by Sphinx-Gallery `_ diff --git a/v0.10.x/_sources/auto_examples/04_demos/viz_fiber_odf.rst.txt b/v0.10.x/_sources/auto_examples/04_demos/viz_fiber_odf.rst.txt new file mode 100644 index 000000000..628cd4dce --- /dev/null +++ b/v0.10.x/_sources/auto_examples/04_demos/viz_fiber_odf.rst.txt @@ -0,0 +1,451 @@ + +.. DO NOT EDIT. +.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. +.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: +.. "auto_examples/04_demos/viz_fiber_odf.py" +.. LINE NUMBERS ARE GIVEN BELOW. + +.. only:: html + + .. note:: + :class: sphx-glr-download-link-note + + :ref:`Go to the end ` + to download the full example code + +.. rst-class:: sphx-glr-example-title + +.. _sphx_glr_auto_examples_04_demos_viz_fiber_odf.py: + + +==================================== +Brain Fiber ODF Visualisation +==================================== + +This example demonstrate how to create a simple viewer for fiber +orientation distribution functions (ODF) using fury's odf_slicer. + +.. GENERATED FROM PYTHON SOURCE LINES 9-21 + +.. code-block:: Python + + + import nibabel as nib + + # First, we import some useful modules and methods. + import numpy as np + from dipy.data import get_sphere + from dipy.reconst.shm import sh_to_sf_matrix + + from fury import actor, ui, window + from fury.data import fetch_viz_dmri, fetch_viz_icons, read_viz_dmri + from fury.utils import fix_winding_order + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 22-24 + +Here, we fetch and load the fiber ODF volume to display. The ODF are +expressed as spherical harmonics (SH) coefficients in a 3D grid. + +.. GENERATED FROM PYTHON SOURCE LINES 24-32 + +.. code-block:: Python + + fetch_viz_dmri() + fetch_viz_icons() + + fodf_img = nib.load(read_viz_dmri('fodf.nii.gz')) + sh = fodf_img.get_fdata() + affine = fodf_img.affine + grid_shape = sh.shape[:-1] + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + Dataset is already in place. If you want to fetch it again please first remove the folder /Users/skoudoro/.fury/dmri + Data size is approximately 12KB + Dataset is already in place. If you want to fetch it again please first remove the folder /Users/skoudoro/.fury/icons + + + + +.. GENERATED FROM PYTHON SOURCE LINES 33-36 + +We then define a low resolution sphere used to visualize SH coefficients +as spherical functions (SF) as well as a matrix `B_low` to project SH +onto the sphere. + +.. GENERATED FROM PYTHON SOURCE LINES 36-39 + +.. code-block:: Python + + sphere_low = get_sphere('repulsion100') + B_low = sh_to_sf_matrix(sphere_low, 8, return_inv=False) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 40-42 + +Now, we create a slicer for each orientation to display a slice in +the middle of the volume and we add them to a `scene`. + +.. GENERATED FROM PYTHON SOURCE LINES 42-107 + +.. code-block:: Python + + + # Change these values to test various parameters combinations. + scale = 0.5 + norm = False + colormap = None + radial_scale = True + opacity = 1.0 + global_cm = False + + # ODF slicer for axial slice + odf_actor_z = actor.odf_slicer( + sh, + affine=affine, + sphere=sphere_low, + scale=scale, + norm=norm, + radial_scale=radial_scale, + opacity=opacity, + colormap=colormap, + global_cm=global_cm, + B_matrix=B_low, + ) + + # ODF slicer for coronal slice + odf_actor_y = actor.odf_slicer( + sh, + affine=affine, + sphere=sphere_low, + scale=scale, + norm=norm, + radial_scale=radial_scale, + opacity=opacity, + colormap=colormap, + global_cm=global_cm, + B_matrix=B_low, + ) + odf_actor_y.display_extent( + 0, grid_shape[0] - 1, grid_shape[1] // 2, grid_shape[1] // 2, 0, grid_shape[2] - 1 + ) + + # ODF slicer for sagittal slice + odf_actor_x = actor.odf_slicer( + sh, + affine=affine, + sphere=sphere_low, + scale=scale, + norm=norm, + radial_scale=radial_scale, + opacity=opacity, + colormap=colormap, + global_cm=global_cm, + B_matrix=B_low, + ) + odf_actor_x.display_extent( + grid_shape[0] // 2, grid_shape[0] // 2, 0, grid_shape[1] - 1, 0, grid_shape[2] - 1 + ) + + scene = window.Scene() + scene.add(odf_actor_z) + scene.add(odf_actor_y) + scene.add(odf_actor_x) + + show_m = window.ShowManager(scene, reset_camera=True, size=(1200, 900)) + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 108-110 + +Now that we have a `ShowManager` containing our slicer, we can go on and +configure our UI for changing the slices to visualize. + +.. GENERATED FROM PYTHON SOURCE LINES 110-134 + +.. code-block:: Python + + line_slider_z = ui.LineSlider2D( + min_value=0, + max_value=grid_shape[2] - 1, + initial_value=grid_shape[2] / 2, + text_template='{value:.0f}', + length=140, + ) + + line_slider_y = ui.LineSlider2D( + min_value=0, + max_value=grid_shape[1] - 1, + initial_value=grid_shape[1] / 2, + text_template='{value:.0f}', + length=140, + ) + + line_slider_x = ui.LineSlider2D( + min_value=0, + max_value=grid_shape[0] - 1, + initial_value=grid_shape[0] / 2, + text_template='{value:.0f}', + length=140, + ) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 135-137 + +We also define a high resolution sphere to demonstrate the capability to +dynamically change the sphere used for SH to SF projection. + +.. GENERATED FROM PYTHON SOURCE LINES 137-144 + +.. code-block:: Python + + sphere_high = get_sphere('symmetric362') + + # We fix the order of the faces' three vertices to a clockwise winding. This + # ensures all faces have a normal going away from the center of the sphere. + sphere_high.faces = fix_winding_order(sphere_high.vertices, sphere_high.faces, True) + B_high = sh_to_sf_matrix(sphere_high, 8, return_inv=False) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 145-146 + +We add a combobox for choosing the sphere resolution during execution. + +.. GENERATED FROM PYTHON SOURCE LINES 146-153 + +.. code-block:: Python + + sphere_dict = { + 'Low resolution': (sphere_low, B_low), + 'High resolution': (sphere_high, B_high), + } + combobox = ui.ComboBox2D(items=list(sphere_dict)) + scene.add(combobox) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 154-155 + +Here we will write callbacks for the sliders and combo box and register them. + +.. GENERATED FROM PYTHON SOURCE LINES 155-184 + +.. code-block:: Python + + + + def change_slice_z(slider): + i = int(np.round(slider.value)) + odf_actor_z.slice_along_axis(i) + + + def change_slice_y(slider): + i = int(np.round(slider.value)) + odf_actor_y.slice_along_axis(i, 'yaxis') + + + def change_slice_x(slider): + i = int(np.round(slider.value)) + odf_actor_x.slice_along_axis(i, 'xaxis') + + + def change_sphere(combobox): + sphere, B = sphere_dict[combobox.selected_text] + odf_actor_x.update_sphere(sphere.vertices, sphere.faces, B) + odf_actor_y.update_sphere(sphere.vertices, sphere.faces, B) + odf_actor_z.update_sphere(sphere.vertices, sphere.faces, B) + + + line_slider_z.on_change = change_slice_z + line_slider_y.on_change = change_slice_y + line_slider_x.on_change = change_slice_x + combobox.on_change = change_sphere + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 185-186 + +We then add labels for the sliders and position them inside a panel. + +.. GENERATED FROM PYTHON SOURCE LINES 186-219 + +.. code-block:: Python + + + + def build_label(text): + label = ui.TextBlock2D() + label.message = text + label.font_size = 18 + label.font_family = 'Arial' + label.justification = 'left' + label.bold = False + label.italic = False + label.shadow = False + label.background_color = (0, 0, 0) + label.color = (1, 1, 1) + + return label + + + line_slider_label_z = build_label(text='Z Slice') + line_slider_label_y = build_label(text='Y Slice') + line_slider_label_x = build_label(text='X Slice') + + panel = ui.Panel2D(size=(300, 200), color=(1, 1, 1), opacity=0.1, align='right') + panel.center = (1030, 120) + + panel.add_element(line_slider_label_x, (0.1, 0.75)) + panel.add_element(line_slider_x, (0.38, 0.75)) + panel.add_element(line_slider_label_y, (0.1, 0.55)) + panel.add_element(line_slider_y, (0.38, 0.55)) + panel.add_element(line_slider_label_z, (0.1, 0.35)) + panel.add_element(line_slider_z, (0.38, 0.35)) + + show_m.scene.add(panel) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 220-226 + +Then, we can render all the widgets and everything else in the screen and +start the interaction using ``show_m.start()``. + +However, if you change the window size, the panel will not update its +position properly. The solution to this issue is to update the position of +the panel using its ``re_align`` method every time the window size changes. + +.. GENERATED FROM PYTHON SOURCE LINES 226-238 + +.. code-block:: Python + + size = scene.GetSize() + + + def win_callback(obj, _event): + global size + if size != obj.GetSize(): + size_old = size + size = obj.GetSize() + size_change = [size[0] - size_old[0], 0] + panel.re_align(size_change) + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 239-241 + +Finally, please set the following variable to ``True`` to interact with the +datasets in 3D. + +.. GENERATED FROM PYTHON SOURCE LINES 241-253 + +.. code-block:: Python + + interactive = False + + if interactive: + show_m.add_window_callback(win_callback) + show_m.render() + show_m.start() + else: + window.record( + scene, out_path='odf_slicer_3D.png', size=(1200, 900), reset_camera=False + ) + + del show_m + + + +.. image-sg:: /auto_examples/04_demos/images/sphx_glr_viz_fiber_odf_001.png + :alt: viz fiber odf + :srcset: /auto_examples/04_demos/images/sphx_glr_viz_fiber_odf_001.png + :class: sphx-glr-single-img + + + + + + +.. rst-class:: sphx-glr-timing + + **Total running time of the script:** (0 minutes 1.238 seconds) + + +.. _sphx_glr_download_auto_examples_04_demos_viz_fiber_odf.py: + +.. only:: html + + .. container:: sphx-glr-footer sphx-glr-footer-example + + .. container:: sphx-glr-download sphx-glr-download-jupyter + + :download:`Download Jupyter notebook: viz_fiber_odf.ipynb ` + + .. container:: sphx-glr-download sphx-glr-download-python + + :download:`Download Python source code: viz_fiber_odf.py ` + + +.. only:: html + + .. rst-class:: sphx-glr-signature + + `Gallery generated by Sphinx-Gallery `_ diff --git a/v0.10.x/_sources/auto_examples/04_demos/viz_fine_tuning_gl_context.rst.txt b/v0.10.x/_sources/auto_examples/04_demos/viz_fine_tuning_gl_context.rst.txt new file mode 100644 index 000000000..4c2566262 --- /dev/null +++ b/v0.10.x/_sources/auto_examples/04_demos/viz_fine_tuning_gl_context.rst.txt @@ -0,0 +1,273 @@ + +.. DO NOT EDIT. +.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. +.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: +.. "auto_examples/04_demos/viz_fine_tuning_gl_context.py" +.. LINE NUMBERS ARE GIVEN BELOW. + +.. only:: html + + .. note:: + :class: sphx-glr-download-link-note + + :ref:`Go to the end ` + to download the full example code + +.. rst-class:: sphx-glr-example-title + +.. _sphx_glr_auto_examples_04_demos_viz_fine_tuning_gl_context.py: + + +======================================================= +Fine-tuning the OpenGL state using shader callbacks +======================================================= + +Sometimes we need to get more control about how +OpenGL will render the actors. This example shows how to change the OpenGL +state of one or more actors. This can be useful when we need to create +specialized visualization effects. + +.. GENERATED FROM PYTHON SOURCE LINES 13-14 + +First, let's import some functions + +.. GENERATED FROM PYTHON SOURCE LINES 14-23 + +.. code-block:: Python + + + import itertools + + import numpy as np + + from fury import actor, window + from fury.shaders import shader_apply_effects + from fury.utils import remove_observer_from_actor + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 24-26 + +We just proceed as usual: creating the actors and initializing a scene in +FURY + +.. GENERATED FROM PYTHON SOURCE LINES 26-76 + +.. code-block:: Python + + + centers = np.array([[0, 0, 0], [-0.1, 0, 0], [0.1, 0, 0]]) + colors = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]]) + + actor_no_depth_test = actor.markers( + centers, + marker='s', + colors=colors, + marker_opacity=0.5, + scales=0.2, + ) + actor_normal_blending = actor.markers( + centers - np.array([[0, -0.5, 0]]), + marker='s', + colors=colors, + marker_opacity=0.5, + scales=0.2, + ) + actor_add_blending = actor.markers( + centers - np.array([[0, -1, 0]]), + marker='s', + colors=colors, + marker_opacity=0.5, + scales=0.2, + ) + + actor_sub_blending = actor.markers( + centers - np.array([[0, -1.5, 0]]), + marker='s', + colors=colors, + marker_opacity=0.5, + scales=0.2, + ) + actor_mul_blending = actor.markers( + centers - np.array([[0, -2, 0]]), + marker='s', + colors=colors, + marker_opacity=0.5, + scales=0.2, + ) + + + scene = window.Scene() + + + scene.background((0.5, 0.5, 0.5)) + showm = window.ShowManager( + scene, size=(900, 768), reset_camera=False, order_transparent=False + ) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 77-78 + +All actors must be added in the scene + +.. GENERATED FROM PYTHON SOURCE LINES 78-84 + +.. code-block:: Python + + + scene.add(actor_no_depth_test) + scene.add(actor_normal_blending) + scene.add(actor_add_blending) + scene.add(actor_sub_blending) + scene.add(actor_mul_blending) + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 85-91 + +Now, we will enter in the topic of this example. First, we need to create +(or use one of the pre-built gl_function of FURY) to +change the OpenGL state of a given fury window instance (showm.window). + +Here we're using the pre-build FURY window functions which has already a +set of specific behaviors to be applied in the OpenGL context + +.. GENERATED FROM PYTHON SOURCE LINES 91-124 + +.. code-block:: Python + + + shader_apply_effects( + showm.window, actor_normal_blending, effects=window.gl_set_normal_blending + ) + + # ############################################################################### + # It's also possible use a list of effects. The final opengl state it'll + # be the composition of each effect that each function has in the opengl state + + id_observer = shader_apply_effects( + showm.window, + actor_no_depth_test, + effects=[window.gl_reset_blend, window.gl_disable_blend, window.gl_disable_depth], + ) + + shader_apply_effects( + showm.window, + actor_add_blending, + effects=[ + window.gl_reset_blend, + window.gl_enable_depth, + window.gl_set_additive_blending, + ], + ) + + shader_apply_effects( + showm.window, actor_sub_blending, effects=window.gl_set_subtractive_blending + ) + + shader_apply_effects( + showm.window, actor_mul_blending, effects=window.gl_set_multiplicative_blending + ) + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + + 5 + + + +.. GENERATED FROM PYTHON SOURCE LINES 125-126 + +Finally, just render and see the results + +.. GENERATED FROM PYTHON SOURCE LINES 126-154 + +.. code-block:: Python + + + + counter = itertools.count() + + # After some steps we will remove the no_depth_test effect + + + def timer_callback(obj, event): + cnt = next(counter) + showm.render() + # we will rotate the visualization just to help you to see + # the results of each specific opengl-state + showm.scene.azimuth(1) + if cnt == 400: + remove_observer_from_actor(actor_no_depth_test, id_observer) + shader_apply_effects( + showm.window, actor_no_depth_test, effects=window.gl_set_additive_blending + ) + if cnt == 1000: + showm.exit() + + + interactive = False + showm.add_timer_callback(interactive, 5, timer_callback) + if interactive: + showm.start() + + window.record(scene, out_path='viz_fine_tuning_gl_context.png', size=(600, 600)) + + + +.. image-sg:: /auto_examples/04_demos/images/sphx_glr_viz_fine_tuning_gl_context_001.png + :alt: viz fine tuning gl context + :srcset: /auto_examples/04_demos/images/sphx_glr_viz_fine_tuning_gl_context_001.png + :class: sphx-glr-single-img + + + + + + +.. rst-class:: sphx-glr-timing + + **Total running time of the script:** (0 minutes 0.086 seconds) + + +.. _sphx_glr_download_auto_examples_04_demos_viz_fine_tuning_gl_context.py: + +.. only:: html + + .. container:: sphx-glr-footer sphx-glr-footer-example + + .. container:: sphx-glr-download sphx-glr-download-jupyter + + :download:`Download Jupyter notebook: viz_fine_tuning_gl_context.ipynb ` + + .. container:: sphx-glr-download sphx-glr-download-python + + :download:`Download Python source code: viz_fine_tuning_gl_context.py ` + + +.. only:: html + + .. rst-class:: sphx-glr-signature + + `Gallery generated by Sphinx-Gallery `_ diff --git a/v0.10.x/_sources/auto_examples/04_demos/viz_fractals.rst.txt b/v0.10.x/_sources/auto_examples/04_demos/viz_fractals.rst.txt new file mode 100644 index 000000000..cf10bc863 --- /dev/null +++ b/v0.10.x/_sources/auto_examples/04_demos/viz_fractals.rst.txt @@ -0,0 +1,464 @@ + +.. DO NOT EDIT. +.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. +.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: +.. "auto_examples/04_demos/viz_fractals.py" +.. LINE NUMBERS ARE GIVEN BELOW. + +.. only:: html + + .. note:: + :class: sphx-glr-download-link-note + + :ref:`Go to the end ` + to download the full example code + +.. rst-class:: sphx-glr-example-title + +.. _sphx_glr_auto_examples_04_demos_viz_fractals.py: + + +======== +Fractals +======== + +Fractals are geometric structures that are self-similar at any scale. These +structures are easy to generate using recursion. In this demo, we'll be +implementing the following fractals: + +- Sierpinski Tetrahedron or Tetrix +- Menger Sponge +- Moseley Snowflake + +Let's begin by importing some necessary modules. We need ``fury.primitive`` to +avoid having to hardcode the geometry of a tetrahedron and a cube. +``fury.utils`` also contains a ``repeat_primitive`` function which we will use +for this demo. + +.. GENERATED FROM PYTHON SOURCE LINES 19-26 + +.. code-block:: Python + + + import math + + import numpy as np + + from fury import primitive, ui, utils, window + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 27-51 + +Before we create our first fractal, let's set some ground rules for us to +work with. + +1. Instead of creating a new actor to represent each primitive of the +fractal, we will compute the centers of each primitive and draw them at once +using ``repeat_primitive()``. + +2. How many primitives do we need? For each fractal, we define a depth which +will prevent infinite recursion. Assuming we have a depth of :math:`N`, and +at each level the shape is divided into :math:`k` smaller parts, we will need +:math:`k^{N}` primitives to represent the fractal. + +3. Ideally, we want to allocate the array of centers upfront. To achieve +this, we can use the method of representing a binary tree in an array, and +extend it to work with k-ary trees (formulas for the same can be found +`here`_). In this scheme of representation, we represent every primitive as a +node, and each sub-primitive as a child node. We can also skip storing the +first :math:`\frac{k^{N} - 1}{k - 1} + 1` entries as we only need to render +the leaf nodes. This allows us to create an array of exactly the required +size at the start, without any additional overhead. + +.. _here: https://book.huihoo.com/data-structures-and-algorithms-with-object-oriented-design-patterns-in-c++/html/page356.html # noqa + +----------------------------------------------------------------------------- + +.. GENERATED FROM PYTHON SOURCE LINES 53-58 + +The tetrix is a classic 3d fractal, a natural three-dimensional extension of +the Sierpinski Triangle. At each level, we need to calculate the new centers +for the next level. We can use the vertices of a tetrahedron as the offsets +for the new centers, provided that the tetrahedron is centered at the origin +(which is the case here). + +.. GENERATED FROM PYTHON SOURCE LINES 58-96 + +.. code-block:: Python + + + + def tetrix(N): + centers = np.zeros((4**N, 3)) + + # skipping non-leaf nodes (see above) + offset = (4**N - 1) // 3 + 1 + + # just need the vertices + U, _ = primitive.prim_tetrahedron() + + def gen_centers(depth, pos, center, dist): + if depth == N: + centers[pos - offset] = center + else: + idx = 4 * (pos - 1) + 2 + for i in range(4): + # distance gets halved at each level + gen_centers(depth + 1, idx + i, center + dist * U[i], dist / 2) + + # the division by sqrt(6) is to ensure correct scale + gen_centers(0, 1, np.zeros(3), 2 / (6**0.5)) + + vertices, faces = primitive.prim_tetrahedron() + + # primitive is scaled down depending on level + vertices /= 2 ** (N - 1) + + # compute some pretty colors + bounds_min, bounds_max = np.min(centers, axis=0), np.max(centers, axis=0) + colors = (centers - bounds_min) / (bounds_max - bounds_min) + + vertices, triangles, colors, _ = primitive.repeat_primitive( + centers=centers, colors=colors, vertices=vertices, faces=faces + ) + return utils.get_actor_from_primitive(vertices, triangles, colors) + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 97-104 + +For a Menger Sponge, each cube is divided into 27 smaller cubes, and we skip +some of them (face centers, and the center of the cube). This means that on +every level we get 20 new cubes. + +Here, to compute the points of each new center, we start at a corner cube's +center and add the offsets to each smaller cube, scaled according to the +level. + +.. GENERATED FROM PYTHON SOURCE LINES 104-164 + +.. code-block:: Python + + + + def sponge(N): + centers = np.zeros((20**N, 3)) + offset = (20**N - 1) // 19 + 1 + + # these are the offsets of the new centers at the next level of recursion + # each cube is divided into 20 smaller cubes for a snowflake + V = np.array( + [ + [0, 0, 0], + [0, 0, 1], + [0, 0, 2], + [0, 1, 0], + [0, 1, 2], + [0, 2, 0], + [0, 2, 1], + [0, 2, 2], + [1, 0, 0], + [1, 0, 2], + [1, 2, 0], + [1, 2, 2], + [2, 0, 0], + [2, 0, 1], + [2, 0, 2], + [2, 1, 0], + [2, 1, 2], + [2, 2, 0], + [2, 2, 1], + [2, 2, 2], + ] + ) + + def gen_centers(depth, pos, center, dist): + if depth == N: + centers[pos - offset] = center + else: + # we consider a corner cube as our starting point + start = center - np.array([1, 1, 1]) * dist**0.5 + idx = 20 * (pos - 1) + 2 + + # this moves from the corner cube to each new cube's center + for i in range(20): + # each cube is divided into 27 cubes so side gets divided by 3 + gen_centers(depth + 1, idx + i, start + V[i] * dist, dist / 3) + + gen_centers(0, 1, np.zeros(3), 1 / 3) + + vertices, faces = primitive.prim_box() + vertices /= 3**N + + bounds_min, bounds_max = np.min(centers, axis=0), np.max(centers, axis=0) + colors = (centers - bounds_min) / (bounds_max - bounds_min) + + vertices, triangles, colors, _ = primitive.repeat_primitive( + centers=centers, colors=colors, vertices=vertices, faces=faces + ) + return utils.get_actor_from_primitive(vertices, triangles, colors) + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 165-168 + +A snowflake is exactly the same as above, but we skip different cubes +(corners and center). I think this looks quite interesting, and it is +possible to see the Koch snowflake if you position the camera just right. + +.. GENERATED FROM PYTHON SOURCE LINES 168-219 + +.. code-block:: Python + + + + def snowflake(N): + centers = np.zeros((18**N, 3)) + offset = (18**N - 1) // 17 + 1 + V = np.array( + [ + [0, 0, 1], + [0, 1, 0], + [0, 1, 1], + [0, 1, 2], + [0, 2, 1], + [1, 0, 0], + [1, 0, 1], + [1, 0, 2], + [1, 1, 0], + [1, 1, 2], + [1, 2, 0], + [1, 2, 1], + [1, 2, 2], + [2, 0, 1], + [2, 1, 0], + [2, 1, 1], + [2, 1, 2], + [2, 2, 1], + ] + ) + + def gen_centers(depth, pos, center, side): + if depth == N: + centers[pos - offset] = center + else: + start = center - np.array([1, 1, 1]) * side**0.5 + idx = 18 * (pos - 1) + 2 + for i in range(18): + gen_centers(depth + 1, idx + i, start + V[i] * side, side / 3) + + gen_centers(0, 1, np.zeros(3), 1 / 3) + + vertices, faces = primitive.prim_box() + vertices /= 3**N + + bounds_min, bounds_max = np.min(centers, axis=0), np.max(centers, axis=0) + colors = (centers - bounds_min) / (bounds_max - bounds_min) + + vertices, triangles, colors, _ = primitive.repeat_primitive( + centers=centers, colors=colors, vertices=vertices, faces=faces + ) + return utils.get_actor_from_primitive(vertices, triangles, colors) + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 220-222 + +Now that we have the functions to generate fractals, we can start setting up +the Scene and ShowManager. + +.. GENERATED FROM PYTHON SOURCE LINES 222-226 + +.. code-block:: Python + + + scene = window.Scene() + showmgr = window.ShowManager(scene, 'Fractals', (800, 800), reset_camera=True) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 227-229 + +These values are what work nicely on my machine without lagging. If you have +a powerful machine, you could bump these up by around 2-3. + +.. GENERATED FROM PYTHON SOURCE LINES 229-232 + +.. code-block:: Python + + + fractals = [tetrix(6), sponge(3), snowflake(3)] + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 233-236 + +We want to be able to switch between the three fractals. To achieve this +we'll create a RadioButton and register a callback which will remove existing +fractals and add the selected one. This also resets the camera. + +.. GENERATED FROM PYTHON SOURCE LINES 236-264 + +.. code-block:: Python + + + options = { + 'Tetrix': 0, + 'Sponge': 1, + 'Snowflake': 2, + } + + shape_chooser = ui.RadioButton( + options.keys(), + padding=10, + font_size=16, + checked_labels=['Tetrix'], + position=(10, 10), + ) + + + def choose_shape(radio): + showmgr.scene.rm(*fractals) + showmgr.scene.add(fractals[options[radio.checked_labels[0]]]) + showmgr.scene.reset_camera() + + + shape_chooser.on_change = choose_shape + + # selected at start + showmgr.scene.add(fractals[0]) + showmgr.scene.add(shape_chooser) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 265-269 + +Let's add some basic camera movement to make it look a little interesting. +We can use a callback here to update a counter and calculate the camera +positions using the counter. ``sin`` and ``cos`` are used here to make smooth +looping movements. + +.. GENERATED FROM PYTHON SOURCE LINES 269-283 + +.. code-block:: Python + + + counter = 0 + + + def timer_callback(_obj, _event): + global counter + counter += 1 + showmgr.scene.azimuth(math.sin(counter * 0.01)) + showmgr.scene.elevation(math.cos(counter * 0.01) / 4) + showmgr.render() + + + showmgr.add_timer_callback(True, 20, timer_callback) + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + + 4 + + + +.. GENERATED FROM PYTHON SOURCE LINES 284-287 + +Finally, show the window if running in interactive mode or render to an image +otherwise. This is needed for generating the documentation that you are +reading. + +.. GENERATED FROM PYTHON SOURCE LINES 287-293 + +.. code-block:: Python + + + interactive = False + if interactive: + showmgr.start() + else: + window.record(showmgr.scene, out_path='fractals.png', size=(800, 800)) + + + +.. image-sg:: /auto_examples/04_demos/images/sphx_glr_viz_fractals_001.png + :alt: viz fractals + :srcset: /auto_examples/04_demos/images/sphx_glr_viz_fractals_001.png + :class: sphx-glr-single-img + + + + + + +.. rst-class:: sphx-glr-timing + + **Total running time of the script:** (0 minutes 0.193 seconds) + + +.. _sphx_glr_download_auto_examples_04_demos_viz_fractals.py: + +.. only:: html + + .. container:: sphx-glr-footer sphx-glr-footer-example + + .. container:: sphx-glr-download sphx-glr-download-jupyter + + :download:`Download Jupyter notebook: viz_fractals.ipynb ` + + .. container:: sphx-glr-download sphx-glr-download-python + + :download:`Download Python source code: viz_fractals.py ` + + +.. only:: html + + .. rst-class:: sphx-glr-signature + + `Gallery generated by Sphinx-Gallery `_ diff --git a/v0.10.x/_sources/auto_examples/04_demos/viz_helical_motion.rst.txt b/v0.10.x/_sources/auto_examples/04_demos/viz_helical_motion.rst.txt new file mode 100644 index 000000000..d28bf58d7 --- /dev/null +++ b/v0.10.x/_sources/auto_examples/04_demos/viz_helical_motion.rst.txt @@ -0,0 +1,373 @@ + +.. DO NOT EDIT. +.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. +.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: +.. "auto_examples/04_demos/viz_helical_motion.py" +.. LINE NUMBERS ARE GIVEN BELOW. + +.. only:: html + + .. note:: + :class: sphx-glr-download-link-note + + :ref:`Go to the end ` + to download the full example code + +.. rst-class:: sphx-glr-example-title + +.. _sphx_glr_auto_examples_04_demos_viz_helical_motion.py: + + +====================================================================== +Motion of a charged particle in a combined magnetic and electric field +====================================================================== + +A charged particle follows a curved path in a magnetic field. +In an electric field, the particle tends to accelerate in a direction +parallel/antiparallel to the electric field depending on the nature of +charge on the particle. In a combined electric and magnetic field, +the particle moves along a helical path. + +In this animation, there's a magnetic and an electric field present in +x +direction under whose influence the positively charged particle follows a +helical path. + +Importing necessary modules + +.. GENERATED FROM PYTHON SOURCE LINES 18-25 + +.. code-block:: Python + + + import itertools + + import numpy as np + + from fury import actor, ui, utils, window + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 26-40 + +Let's define some variable and their description: + +* `radius_particle`: radius of the point that will represent the particle + (default = 0.08) +* `initial_velocity`: initial velocity of the particle along +x + (default = 0.09) +* `acc`: acceleration of the particle along +x (due to the electric field) + (default = 0.004) +* `time`: time (default time i.e. time at beginning of the animation = 0) +* `incre_time`: value by which time is incremented for each call of + timer_callback (default = 0.09) +* `angular_frq`: angular frequency (default = 0.1) +* `phase_angle`: phase angle (default = 0.002) + + +.. GENERATED FROM PYTHON SOURCE LINES 40-50 + +.. code-block:: Python + + + radius_particle = 0.08 + initial_velocity = 0.09 + acc = 0.004 + time = 0 + incre_time = 0.09 + angular_frq = 0.1 + phase_angle = 0.002 + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 51-52 + +Creating a scene object and configuring the camera's position + +.. GENERATED FROM PYTHON SOURCE LINES 52-63 + +.. code-block:: Python + + + scene = window.Scene() + scene.zoom(1.2) + scene.set_camera( + position=(10, 12.5, 19), focal_point=(3.0, 0.0, 0.0), view_up=(0.0, 0.0, 0.0) + ) + showm = window.ShowManager( + scene, size=(800, 600), reset_camera=True, order_transparent=True + ) + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 64-66 + +Creating a blue colored arrow which shows the direction of magnetic field and +electric field. + +.. GENERATED FROM PYTHON SOURCE LINES 66-83 + +.. code-block:: Python + + + color_arrow = window.colors.blue # color of the arrow can be manipulated + centers = np.array([[0, 0, 0]]) + directions = np.array([[1, 0, 0]]) + heights = np.array([8]) + arrow_actor = actor.arrow( + centers, + directions, + color_arrow, + heights, + resolution=20, + tip_length=0.06, + tip_radius=0.012, + shaft_radius=0.005, + ) + scene.add(arrow_actor) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 84-85 + +Initializing the initial coordinates of the particle + +.. GENERATED FROM PYTHON SOURCE LINES 85-90 + +.. code-block:: Python + + + x = initial_velocity * time + 0.5 * acc * (time**2) + y = np.sin(angular_frq * time + phase_angle) + z = np.cos(angular_frq * time + phase_angle) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 91-92 + +Initializing point actor which will represent the charged particle + +.. GENERATED FROM PYTHON SOURCE LINES 92-104 + +.. code-block:: Python + + + color_particle = window.colors.red # color of particle can be manipulated + pts = np.array([[x, y, z]]) + charge_actor = actor.point(pts, color_particle, point_radius=radius_particle) + scene.add(charge_actor) + + vertices = utils.vertices_from_actor(charge_actor) + vcolors = utils.colors_from_actor(charge_actor, 'colors') + no_vertices_per_point = len(vertices) + initial_vertices = vertices.copy() - np.repeat(pts, no_vertices_per_point, axis=0) + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 105-106 + +Initializing text box to display the name of the animation + +.. GENERATED FROM PYTHON SOURCE LINES 106-113 + +.. code-block:: Python + + + tb = ui.TextBlock2D(bold=True, position=(100, 90)) + m1 = 'Motion of a charged particle in a ' + m2 = 'combined electric and magnetic field' + tb.message = m1 + m2 + scene.add(tb) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 114-115 + +Initializing counter + +.. GENERATED FROM PYTHON SOURCE LINES 115-118 + +.. code-block:: Python + + + counter = itertools.count() + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 119-120 + +end is used to decide when to end the animation + +.. GENERATED FROM PYTHON SOURCE LINES 120-123 + +.. code-block:: Python + + + end = 200 + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 124-125 + +This will be useful for plotting path of the particle + +.. GENERATED FROM PYTHON SOURCE LINES 125-129 + +.. code-block:: Python + + + coor_1 = np.array([0, 0, 0]) + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 130-132 + +Coordinates to be plotted are changed every time timer_callback is called by +using the update_coordinates function. The wave is rendered here. + +.. GENERATED FROM PYTHON SOURCE LINES 132-163 + +.. code-block:: Python + + + + def timer_callback(_obj, _event): + global pts, time, incre_time, coor_1 + time += incre_time + cnt = next(counter) + + x = initial_velocity * time + 0.5 * acc * (time**2) + y = np.sin(10 * angular_frq * time + phase_angle) + z = np.cos(10 * angular_frq * time + phase_angle) + pts = np.array([[x, y, z]]) + + vertices[:] = initial_vertices + np.repeat(pts, no_vertices_per_point, axis=0) + + utils.update_actor(charge_actor) + + # Plotting the path followed by the particle + coor_2 = np.array([x, y, z]) + coors = np.array([coor_1, coor_2]) + coors = [coors] + line_actor = actor.line(coors, window.colors.cyan, linewidth=3) + scene.add(line_actor) + coor_1 = coor_2 + + showm.render() + + # to end the animation + if cnt == end: + showm.exit() + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 164-165 + +Run every 15 milliseconds + +.. GENERATED FROM PYTHON SOURCE LINES 165-170 + +.. code-block:: Python + + + + showm.add_timer_callback(True, 15, timer_callback) + showm.start() + window.record(showm.scene, size=(800, 600), out_path='viz_helical_motion.png') + + + +.. image-sg:: /auto_examples/04_demos/images/sphx_glr_viz_helical_motion_001.png + :alt: viz helical motion + :srcset: /auto_examples/04_demos/images/sphx_glr_viz_helical_motion_001.png + :class: sphx-glr-single-img + + + + + + +.. rst-class:: sphx-glr-timing + + **Total running time of the script:** (0 minutes 4.550 seconds) + + +.. _sphx_glr_download_auto_examples_04_demos_viz_helical_motion.py: + +.. only:: html + + .. container:: sphx-glr-footer sphx-glr-footer-example + + .. container:: sphx-glr-download sphx-glr-download-jupyter + + :download:`Download Jupyter notebook: viz_helical_motion.ipynb ` + + .. container:: sphx-glr-download sphx-glr-download-python + + :download:`Download Python source code: viz_helical_motion.py ` + + +.. only:: html + + .. rst-class:: sphx-glr-signature + + `Gallery generated by Sphinx-Gallery `_ diff --git a/v0.10.x/_sources/auto_examples/04_demos/viz_markers.rst.txt b/v0.10.x/_sources/auto_examples/04_demos/viz_markers.rst.txt new file mode 100644 index 000000000..350e35190 --- /dev/null +++ b/v0.10.x/_sources/auto_examples/04_demos/viz_markers.rst.txt @@ -0,0 +1,157 @@ + +.. DO NOT EDIT. +.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. +.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: +.. "auto_examples/04_demos/viz_markers.py" +.. LINE NUMBERS ARE GIVEN BELOW. + +.. only:: html + + .. note:: + :class: sphx-glr-download-link-note + + :ref:`Go to the end ` + to download the full example code + +.. rst-class:: sphx-glr-example-title + +.. _sphx_glr_auto_examples_04_demos_viz_markers.py: + + +====================================================================== +Fury Markers +====================================================================== + +This example shows how to use the marker actor. + +.. GENERATED FROM PYTHON SOURCE LINES 8-14 + +.. code-block:: Python + + import numpy as np + + from fury import actor, window + + n = 10000 + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 15-17 + +There are nine types 2d markers: circle, square, diamond, triangle, pentagon, +hexagon, heptagon, cross and plus. + +.. GENERATED FROM PYTHON SOURCE LINES 17-25 + +.. code-block:: Python + + + marker_symbols = ['o', 's', 'd', '^', 'p', 'h', 's6', 'x', '+'] + markers = [np.random.choice(marker_symbols) for i in range(n)] + + centers = np.random.normal(size=(n, 3), scale=10) + + colors = np.random.uniform(size=(n, 3)) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 26-27 + +You can control the edge color and edge width for each marker + +.. GENERATED FROM PYTHON SOURCE LINES 27-37 + +.. code-block:: Python + + + nodes_actor = actor.markers( + centers, + marker=markers, + edge_width=0.1, + edge_color=[255, 255, 0], + colors=colors, + scales=0.5, + ) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 38-39 + +In addition, an 3D sphere it's also a valid type of marker + +.. GENERATED FROM PYTHON SOURCE LINES 39-58 + +.. code-block:: Python + + + nodes_3d_actor = actor.markers( + centers + np.ones_like(centers) * 25, + marker='3d', + colors=colors, + scales=0.5, + ) + + scene = window.Scene() + + scene.add(nodes_actor) + scene.add(nodes_3d_actor) + + interactive = False + + if interactive: + window.show(scene, size=(600, 600)) + + window.record(scene, out_path='viz_markers.png', size=(600, 600)) + + + +.. image-sg:: /auto_examples/04_demos/images/sphx_glr_viz_markers_001.png + :alt: viz markers + :srcset: /auto_examples/04_demos/images/sphx_glr_viz_markers_001.png + :class: sphx-glr-single-img + + + + + + +.. rst-class:: sphx-glr-timing + + **Total running time of the script:** (0 minutes 0.137 seconds) + + +.. _sphx_glr_download_auto_examples_04_demos_viz_markers.py: + +.. only:: html + + .. container:: sphx-glr-footer sphx-glr-footer-example + + .. container:: sphx-glr-download sphx-glr-download-jupyter + + :download:`Download Jupyter notebook: viz_markers.ipynb ` + + .. container:: sphx-glr-download sphx-glr-download-python + + :download:`Download Python source code: viz_markers.py ` + + +.. only:: html + + .. rst-class:: sphx-glr-signature + + `Gallery generated by Sphinx-Gallery `_ diff --git a/v0.10.x/_sources/auto_examples/04_demos/viz_network.rst.txt b/v0.10.x/_sources/auto_examples/04_demos/viz_network.rst.txt new file mode 100644 index 000000000..ab729ac1f --- /dev/null +++ b/v0.10.x/_sources/auto_examples/04_demos/viz_network.rst.txt @@ -0,0 +1,284 @@ + +.. DO NOT EDIT. +.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. +.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: +.. "auto_examples/04_demos/viz_network.py" +.. LINE NUMBERS ARE GIVEN BELOW. + +.. only:: html + + .. note:: + :class: sphx-glr-download-link-note + + :ref:`Go to the end ` + to download the full example code + +.. rst-class:: sphx-glr-example-title + +.. _sphx_glr_auto_examples_04_demos_viz_network.py: + + +======================================================= +Visualize Interdisciplinary map of the journals network +======================================================= + +The goal of this app is to show an overview of the journals network structure +as a complex network. Each journal is shown as a node and their connections +indicates a citation between two of them. + +.. GENERATED FROM PYTHON SOURCE LINES 12-13 + +First, let's import some useful functions + +.. GENERATED FROM PYTHON SOURCE LINES 13-23 + +.. code-block:: Python + + + from os.path import join as pjoin + + import numpy as np + + from fury import actor + from fury import colormap as cmap + from fury import window + from fury.data import fetch_viz_wiki_nw + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 24-25 + +Then let's download some available datasets. + +.. GENERATED FROM PYTHON SOURCE LINES 25-30 + +.. code-block:: Python + + + + files, folder = fetch_viz_wiki_nw() + categories_file, edges_file, positions_file = sorted(files.keys()) + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + Dataset is already in place. If you want to fetch it again please first remove the folder /Users/skoudoro/.fury/examples/wiki_nw + More information about complex networks can be found in this papers: https://arxiv.org/abs/0711.3199 + + + + +.. GENERATED FROM PYTHON SOURCE LINES 31-32 + +We read our datasets + +.. GENERATED FROM PYTHON SOURCE LINES 32-37 + +.. code-block:: Python + + + positions = np.loadtxt(pjoin(folder, positions_file)) + categories = np.loadtxt(pjoin(folder, categories_file), dtype=str) + edges = np.loadtxt(pjoin(folder, edges_file), dtype=int) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 38-40 + +We attribute a color to each category of our dataset which correspond to our +nodes colors. + +.. GENERATED FROM PYTHON SOURCE LINES 40-49 + +.. code-block:: Python + + + category2index = {category: i for i, category in enumerate(np.unique(categories))} + + index2category = np.unique(categories) + + categoryColors = cmap.distinguishable_colormap(nb_colors=len(index2category)) + + colors = np.array([categoryColors[category2index[category]] for category in categories]) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 50-51 + +We define our node size + +.. GENERATED FROM PYTHON SOURCE LINES 51-54 + +.. code-block:: Python + + + radii = 1 + np.random.rand(len(positions)) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 55-58 + +Lets create our edges now. They will indicate a citation between two nodes. +OF course, the colors of each edges will be an interpolation between the two +node that it connects. + +.. GENERATED FROM PYTHON SOURCE LINES 58-68 + +.. code-block:: Python + + + edgesPositions = [] + edgesColors = [] + for source, target in edges: + edgesPositions.append(np.array([positions[source], positions[target]])) + edgesColors.append(np.array([colors[source], colors[target]])) + + edgesPositions = np.array(edgesPositions) + edgesColors = np.average(np.array(edgesColors), axis=1) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 69-72 + +Our data preparation is ready, it is time to visualize them all. We start to +build 2 actors that we represent our data : sphere_actor for the nodes and +lines_actor for the edges. + +.. GENERATED FROM PYTHON SOURCE LINES 72-87 + +.. code-block:: Python + + + sphere_actor = actor.sphere( + centers=positions, + colors=colors, + radii=radii * 0.5, + theta=8, + phi=8, + ) + + lines_actor = actor.line( + edgesPositions, + colors=edgesColors, + opacity=0.1, + ) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 88-90 + +All actors need to be added in a scene, so we build one and add our +lines_actor and sphere_actor. + +.. GENERATED FROM PYTHON SOURCE LINES 90-96 + +.. code-block:: Python + + + scene = window.Scene() + + scene.add(lines_actor) + scene.add(sphere_actor) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 97-99 + +The final step ! Visualize and save the result of our creation! Please, +switch interactive variable to True if you want to visualize it. + +.. GENERATED FROM PYTHON SOURCE LINES 99-107 + +.. code-block:: Python + + + interactive = False + + if interactive: + window.show(scene, size=(600, 600)) + + window.record(scene, out_path='journal_networks.png', size=(600, 600)) + + + + +.. image-sg:: /auto_examples/04_demos/images/sphx_glr_viz_network_001.png + :alt: viz network + :srcset: /auto_examples/04_demos/images/sphx_glr_viz_network_001.png + :class: sphx-glr-single-img + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 108-110 + +This example can be improved by adding some interactivy with slider, +picking, etc. Play with it, improve it! + + +.. rst-class:: sphx-glr-timing + + **Total running time of the script:** (0 minutes 0.809 seconds) + + +.. _sphx_glr_download_auto_examples_04_demos_viz_network.py: + +.. only:: html + + .. container:: sphx-glr-footer sphx-glr-footer-example + + .. container:: sphx-glr-download sphx-glr-download-jupyter + + :download:`Download Jupyter notebook: viz_network.ipynb ` + + .. container:: sphx-glr-download sphx-glr-download-python + + :download:`Download Python source code: viz_network.py ` + + +.. only:: html + + .. rst-class:: sphx-glr-signature + + `Gallery generated by Sphinx-Gallery `_ diff --git a/v0.10.x/_sources/auto_examples/04_demos/viz_network_animated.rst.txt b/v0.10.x/_sources/auto_examples/04_demos/viz_network_animated.rst.txt new file mode 100644 index 000000000..2ff4c78f4 --- /dev/null +++ b/v0.10.x/_sources/auto_examples/04_demos/viz_network_animated.rst.txt @@ -0,0 +1,465 @@ + +.. DO NOT EDIT. +.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. +.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: +.. "auto_examples/04_demos/viz_network_animated.py" +.. LINE NUMBERS ARE GIVEN BELOW. + +.. only:: html + + .. note:: + :class: sphx-glr-download-link-note + + :ref:`Go to the end ` + to download the full example code + +.. rst-class:: sphx-glr-example-title + +.. _sphx_glr_auto_examples_04_demos_viz_network_animated.py: + + +======================================================= +Visualize Networks (Animated version) +======================================================= + +The goal of this demo is to show how to visualize a +complex network and use an force directed algorithm to +layout the network. A simpler animation of the network +made by adding some random displacements to nodes +positions is also demoed. + +.. GENERATED FROM PYTHON SOURCE LINES 14-15 + +First, let's import some useful functions + +.. GENERATED FROM PYTHON SOURCE LINES 15-26 + +.. code-block:: Python + + + import math + from os.path import join as pjoin + + import numpy as np + + from fury import actor + from fury import colormap as cmap + from fury import window + from fury.utils import compute_bounds, update_actor, vertices_from_actor + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 27-34 + +This demo has two modes. +Use `mode = 0` to visualize a randomly generated geographic network by +iterating it using a force-directed layout heuristic. + +Use `mode = 1` to visualize a large network being animated with random +displacements + + +.. GENERATED FROM PYTHON SOURCE LINES 34-37 + +.. code-block:: Python + + + mode = 0 + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 38-39 + +Then let's download some available datasets. (mode 1) + +.. GENERATED FROM PYTHON SOURCE LINES 39-46 + +.. code-block:: Python + + + if mode == 1: + from fury.data.fetcher import fetch_viz_wiki_nw + + files, folder = fetch_viz_wiki_nw() + categories_file, edges_file, positions_file = sorted(files.keys()) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 47-48 + +We read our datasets (mode 1) + +.. GENERATED FROM PYTHON SOURCE LINES 48-55 + +.. code-block:: Python + + + if mode == 1: + positions = np.loadtxt(pjoin(folder, positions_file)) + categories = np.loadtxt(pjoin(folder, categories_file), dtype=str) + edges = np.loadtxt(pjoin(folder, edges_file), dtype=int) + vertices_count = len(positions) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 56-57 + +Generate a geographic random network, requires networkx package (mode 0) + +.. GENERATED FROM PYTHON SOURCE LINES 57-69 + +.. code-block:: Python + + + if mode == 0: + import networkx as nx + + vertices_count = 100 + view_size = 100 + network = nx.random_geometric_graph(vertices_count, 0.2) + positions = view_size * np.random.random((vertices_count, 3)) - view_size / 2.0 + categories = np.arange(0, vertices_count) + edges = np.array(network.edges()) + positions = view_size * np.random.random((vertices_count, 3)) - view_size / 2.0 + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 70-72 + +We attribute a color to each category of our dataset which correspond to our +nodes colors. + +.. GENERATED FROM PYTHON SOURCE LINES 72-83 + +.. code-block:: Python + + + category2index = {category: i for i, category in enumerate(np.unique(categories))} + + index2category = np.unique(categories) + + category_colors = cmap.distinguishable_colormap(nb_colors=len(index2category)) + + colors = np.array( + [category_colors[category2index[category]] for category in categories] + ) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 84-85 + +We define our node size + +.. GENERATED FROM PYTHON SOURCE LINES 85-88 + +.. code-block:: Python + + + radii = 1 + np.random.rand(len(positions)) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 89-91 + +Let's create our edges now. They will indicate a citation between two nodes. +The colors of each edge are interpolated between the two endpoints. + +.. GENERATED FROM PYTHON SOURCE LINES 91-98 + +.. code-block:: Python + + + edges_colors = [] + for source, target in edges: + edges_colors.append(np.array([colors[source], colors[target]])) + + edges_colors = np.average(np.array(edges_colors), axis=1) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 99-102 + +Our data preparation is ready, it is time to visualize them all. We start to +build 2 actors that we represent our data : sphere_actor for the nodes and +lines_actor for the edges. + +.. GENERATED FROM PYTHON SOURCE LINES 102-116 + +.. code-block:: Python + + + sphere_actor = actor.sphere( + centers=np.zeros(positions.shape), colors=colors, radii=radii * 0.5, theta=8, phi=8 + ) + + + lines_actor = actor.line( + np.zeros((len(edges), 2, 3)), + colors=edges_colors, + lod=False, + fake_tube=True, + linewidth=3, + ) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 117-118 + +Defining timer callback and layout iterator + +.. GENERATED FROM PYTHON SOURCE LINES 118-225 + +.. code-block:: Python + + + + def new_layout_timer( + showm, + edges_list, + vertices_count, + max_iterations=1000, + vertex_initial_positions=None, + ): + view_size = 500 + viscosity = 0.10 + alpha = 0.5 + a = 0.0005 + b = 1.0 + deltaT = 1.0 + + sphere_geometry = np.array(vertices_from_actor(sphere_actor)) + geometry_length = sphere_geometry.shape[0] / vertices_count + + if vertex_initial_positions is not None: + pos = np.array(vertex_initial_positions) + else: + pos = view_size * np.random.random((vertices_count, 3)) - view_size / 2.0 + + velocities = np.zeros((vertices_count, 3)) + + def iterate(iterationCount): + nonlocal pos, velocities + for _ in range(iterationCount): + forces = np.zeros((vertices_count, 3)) + # repulstive forces + for vertex1 in range(vertices_count): + for vertex2 in range(vertex1): + x1, y1, z1 = pos[vertex1] + x2, y2, z2 = pos[vertex2] + distance = ( + math.sqrt( + (x2 - x1) * (x2 - x1) + + (y2 - y1) * (y2 - y1) + + (z2 - z1) * (z2 - z1) + ) + + alpha + ) + rx = (x2 - x1) / distance + ry = (y2 - y1) / distance + rz = (z2 - z1) / distance + Fx = -b * rx / distance / distance + Fy = -b * ry / distance / distance + Fz = -b * rz / distance / distance + forces[vertex1] += np.array([Fx, Fy, Fz]) + forces[vertex2] -= np.array([Fx, Fy, Fz]) + # attractive forces + for vFrom, vTo in edges_list: + if vFrom == vTo: + continue + x1, y1, z1 = pos[vFrom] + x2, y2, z2 = pos[vTo] + distance = math.sqrt( + (x2 - x1) * (x2 - x1) + + (y2 - y1) * (y2 - y1) + + (z2 - z1) * (z2 - z1) + ) + Rx = x2 - x1 + Ry = y2 - y1 + Rz = z2 - z1 + Fx = a * Rx * distance + Fy = a * Ry * distance + Fz = a * Rz * distance + forces[vFrom] += np.array([Fx, Fy, Fz]) + forces[vTo] -= np.array([Fx, Fy, Fz]) + velocities += forces * deltaT + velocities *= 1.0 - viscosity + pos += velocities * deltaT + pos[:, 0] -= np.mean(pos[:, 0]) + pos[:, 1] -= np.mean(pos[:, 1]) + pos[:, 2] -= np.mean(pos[:, 2]) + + counter = 0 + + def _timer(_obj, _event): + nonlocal counter, pos + counter += 1 + if mode == 0: + iterate(1) + else: + pos[:] += (np.random.random(pos.shape) - 0.5) * 1.5 + spheres_positions = vertices_from_actor(sphere_actor) + spheres_positions[:] = sphere_geometry + np.repeat(pos, geometry_length, axis=0) + + edges_positions = vertices_from_actor(lines_actor) + edges_positions[::2] = pos[edges_list[:, 0]] + edges_positions[1::2] = pos[edges_list[:, 1]] + + update_actor(lines_actor) + compute_bounds(lines_actor) + + update_actor(sphere_actor) + compute_bounds(lines_actor) + showm.scene.reset_clipping_range() + showm.render() + + if counter >= max_iterations: + showm.exit() + + return _timer + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 226-228 + +All actors need to be added in a scene, so we build one and add our +lines_actor and sphere_actor. + +.. GENERATED FROM PYTHON SOURCE LINES 228-237 + +.. code-block:: Python + + + + scene = window.Scene() + + camera = scene.camera() + + scene.add(lines_actor) + scene.add(sphere_actor) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 238-242 + +The final step! Visualize the result of our creation! Also, we need to move +the camera a little bit farther from the network. you can increase the +parameter max_iteractions of the timer callback to let the animation run for +more time. + +.. GENERATED FROM PYTHON SOURCE LINES 242-261 + +.. code-block:: Python + + + showm = window.ShowManager( + scene, reset_camera=False, size=(900, 768), order_transparent=True, multi_samples=8 + ) + + + scene.set_camera(position=(0, 0, -300)) + + timer_callback = new_layout_timer( + showm, edges, vertices_count, max_iterations=200, vertex_initial_positions=positions + ) + + + # Run every 16 milliseconds + showm.add_timer_callback(True, 16, timer_callback) + + showm.start() + + window.record(showm.scene, size=(900, 768), out_path='viz_animated_networks.png') + + + +.. image-sg:: /auto_examples/04_demos/images/sphx_glr_viz_network_animated_001.png + :alt: viz network animated + :srcset: /auto_examples/04_demos/images/sphx_glr_viz_network_animated_001.png + :class: sphx-glr-single-img + + + + + + +.. rst-class:: sphx-glr-timing + + **Total running time of the script:** (0 minutes 7.015 seconds) + + +.. _sphx_glr_download_auto_examples_04_demos_viz_network_animated.py: + +.. only:: html + + .. container:: sphx-glr-footer sphx-glr-footer-example + + .. container:: sphx-glr-download sphx-glr-download-jupyter + + :download:`Download Jupyter notebook: viz_network_animated.ipynb ` + + .. container:: sphx-glr-download sphx-glr-download-python + + :download:`Download Python source code: viz_network_animated.py ` + + +.. only:: html + + .. rst-class:: sphx-glr-signature + + `Gallery generated by Sphinx-Gallery `_ diff --git a/v0.10.x/_sources/auto_examples/04_demos/viz_pbr_interactive.rst.txt b/v0.10.x/_sources/auto_examples/04_demos/viz_pbr_interactive.rst.txt new file mode 100644 index 000000000..68eda165d --- /dev/null +++ b/v0.10.x/_sources/auto_examples/04_demos/viz_pbr_interactive.rst.txt @@ -0,0 +1,706 @@ + +.. DO NOT EDIT. +.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. +.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: +.. "auto_examples/04_demos/viz_pbr_interactive.py" +.. LINE NUMBERS ARE GIVEN BELOW. + +.. only:: html + + .. note:: + :class: sphx-glr-download-link-note + + :ref:`Go to the end ` + to download the full example code + +.. rst-class:: sphx-glr-example-title + +.. _sphx_glr_auto_examples_04_demos_viz_pbr_interactive.py: + + +=============================================== +Interactive PBR demo +=============================================== + +This is a demonstration of how Physically-Based Rendering (PBR) can be used to +simulate different materials. + +Let's start by importing the necessary modules: + +.. GENERATED FROM PYTHON SOURCE LINES 11-21 + +.. code-block:: Python + + + from fury import actor, material, ui, window + from fury.data import fetch_viz_cubemaps, read_viz_cubemap + from fury.io import load_cubemap_texture + from fury.utils import ( + normals_from_actor, + tangents_from_direction_of_anisotropy, + tangents_to_actor, + ) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 22-23 + +The following functions will help us to manage the sliders events. + +.. GENERATED FROM PYTHON SOURCE LINES 23-86 + +.. code-block:: Python + + + + def change_slice_metallic(slider): + global pbr_params + pbr_params.metallic = slider.value + + + def change_slice_roughness(slider): + global pbr_params + pbr_params.roughness = slider.value + + + def change_slice_anisotropy(slider): + global pbr_params + pbr_params.anisotropy = slider.value + + + def change_slice_anisotropy_direction_x(slider): + global doa, normals, sphere + doa[0] = slider.value + tangents = tangents_from_direction_of_anisotropy(normals, doa) + tangents_to_actor(sphere, tangents) + + + def change_slice_anisotropy_direction_y(slider): + global doa, normals, sphere + doa[1] = slider.value + tangents = tangents_from_direction_of_anisotropy(normals, doa) + tangents_to_actor(sphere, tangents) + + + def change_slice_anisotropy_direction_z(slider): + global doa, normals, sphere + doa[2] = slider.value + tangents = tangents_from_direction_of_anisotropy(normals, doa) + tangents_to_actor(sphere, tangents) + + + def change_slice_anisotropy_rotation(slider): + global pbr_params + pbr_params.anisotropy_rotation = slider.value + + + def change_slice_coat_strength(slider): + global pbr_params + pbr_params.coat_strength = slider.value + + + def change_slice_coat_roughness(slider): + global pbr_params + pbr_params.coat_roughness = slider.value + + + def change_slice_base_ior(slider): + global pbr_params + pbr_params.base_ior = slider.value + + + def change_slice_coat_ior(slider): + global pbr_params + pbr_params.coat_ior = slider.value + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 87-89 + +Last, but not least, we define the following function to help us to +reposition the UI elements every time we resize the window. + +.. GENERATED FROM PYTHON SOURCE LINES 89-100 + +.. code-block:: Python + + + + def win_callback(obj, event): + global control_panel, size + if size != obj.GetSize(): + size_old = size + size = obj.GetSize() + size_change = [size[0] - size_old[0], 0] + control_panel.re_align(size_change) + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 101-102 + +Let's fetch a skybox texture from the FURY data repository. + +.. GENERATED FROM PYTHON SOURCE LINES 102-105 + +.. code-block:: Python + + + fetch_viz_cubemaps() + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + Dataset is already in place. If you want to fetch it again please first remove the folder /Users/skoudoro/.fury/cubemaps + + ({'skybox-nx.jpg': ('https://raw.githubusercontent.com/fury-gl/fury-data/master/cubemaps/skybox-nx.jpg', '12B1CE6C91AA3AAF258A8A5944DF739A6C1CC76E89D4D7119D1F795A30FC1BF2'), 'skybox-ny.jpg': ('https://raw.githubusercontent.com/fury-gl/fury-data/master/cubemaps/skybox-ny.jpg', 'E18FE2206B63D3DF2C879F5E0B9937A61D99734B6C43AC288226C58D2418D23E'), 'skybox-nz.jpg': ('https://raw.githubusercontent.com/fury-gl/fury-data/master/cubemaps/skybox-nz.jpg', '00DDDD1B715D5877AF2A74C014FF6E47891F07435B471D213CD0673A8C47F2B2'), 'skybox-px.jpg': ('https://raw.githubusercontent.com/fury-gl/fury-data/master/cubemaps/skybox-px.jpg', 'BF20ACD6817C9E7073E485BBE2D2CE56DACFF73C021C2B613BA072BA2DF2B754'), 'skybox-py.jpg': ('https://raw.githubusercontent.com/fury-gl/fury-data/master/cubemaps/skybox-py.jpg', '16F0D692AF0B80E46929D8D8A7E596123C76729CC5EB7DFD1C9184B115DD143A'), 'skybox-pz.jpg': ('https://raw.githubusercontent.com/fury-gl/fury-data/master/cubemaps/skybox-pz.jpg', 'B850B5E882889DF26BE9289D7C25BA30524B37E56BC2075B968A83197AD977F3')}, '/Users/skoudoro/.fury/cubemaps') + + + +.. GENERATED FROM PYTHON SOURCE LINES 106-108 + +The following function returns the full path of the 6 images composing the +skybox. + +.. GENERATED FROM PYTHON SOURCE LINES 108-111 + +.. code-block:: Python + + + textures = read_viz_cubemap('skybox') + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 112-114 + +Now that we have the location of the textures, let's load them and create a +Cube Map Texture object. + +.. GENERATED FROM PYTHON SOURCE LINES 114-117 + +.. code-block:: Python + + + cubemap = load_cubemap_texture(textures) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 118-122 + +The Scene object in FURY can handle cube map textures and extract light +information from them, so it can be used to create more plausible materials +interactions. The ``skybox`` parameter takes as input a cube map texture and +performs the previously described process. + +.. GENERATED FROM PYTHON SOURCE LINES 122-125 + +.. code-block:: Python + + + scene = window.Scene(skybox=cubemap) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 126-128 + +With the scene created, we can then populate it. In this demo we will only +add a sphere actor. + +.. GENERATED FROM PYTHON SOURCE LINES 128-131 + +.. code-block:: Python + + + sphere = actor.sphere([[0, 0, 0]], (0.7, 0.7, 0.7), radii=2, theta=64, phi=64) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 132-134 + +The direction of anisotropy (DoA) defines the direction at which all the +tangents of our actor are pointing. + +.. GENERATED FROM PYTHON SOURCE LINES 134-137 + +.. code-block:: Python + + + doa = [0, 1, 0.5] + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 138-141 + +The following process gets the normals of the actor and computes the tangents +that are aligned to the provided DoA. Then it registers those tangents to the +actor. + +.. GENERATED FROM PYTHON SOURCE LINES 141-146 + +.. code-block:: Python + + + normals = normals_from_actor(sphere) + tangents = tangents_from_direction_of_anisotropy(normals, doa) + tangents_to_actor(sphere, tangents) + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 147-149 + +With the tangents computed and in place, we have all the elements needed to +add some material properties to the actor. + +.. GENERATED FROM PYTHON SOURCE LINES 149-152 + +.. code-block:: Python + + + pbr_params = material.manifest_pbr(sphere) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 153-154 + +Our actor is now ready to be added to the scene. + +.. GENERATED FROM PYTHON SOURCE LINES 154-157 + +.. code-block:: Python + + + scene.add(sphere) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 158-159 + +Let's setup now the window and the UI. + +.. GENERATED FROM PYTHON SOURCE LINES 159-165 + +.. code-block:: Python + + + show_m = window.ShowManager( + scene=scene, size=(1920, 1080), reset_camera=False, order_transparent=True + ) + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 166-167 + +We will create one single panel with all of our labels and sliders. + +.. GENERATED FROM PYTHON SOURCE LINES 167-172 + +.. code-block:: Python + + + control_panel = ui.Panel2D( + (400, 500), position=(5, 5), color=(0.25, 0.25, 0.25), opacity=0.75, align='right' + ) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 173-175 + +By using our previously defined function, we can easily create all the labels +we need for this demo. And then add them to the panel. + +.. GENERATED FROM PYTHON SOURCE LINES 175-208 + +.. code-block:: Python + + + slider_label_metallic = ui.TextBlock2D(text='Metallic', font_size=16) + slider_label_roughness = ui.TextBlock2D(text='Roughness', font_size=16) + slider_label_anisotropy = ui.TextBlock2D(text='Anisotropy', font_size=16) + slider_label_anisotropy_rotation = ui.TextBlock2D( + text='Anisotropy Rotation', font_size=16 + ) + slider_label_anisotropy_direction_x = ui.TextBlock2D( + text='Anisotropy Direction X', font_size=16 + ) + slider_label_anisotropy_direction_y = ui.TextBlock2D( + text='Anisotropy Direction Y', font_size=16 + ) + slider_label_anisotropy_direction_z = ui.TextBlock2D( + text='Anisotropy Direction Z', font_size=16 + ) + slider_label_coat_strength = ui.TextBlock2D(text='Coat Strength', font_size=16) + slider_label_coat_roughness = ui.TextBlock2D(text='Coat Roughness', font_size=16) + slider_label_base_ior = ui.TextBlock2D(text='Base IoR', font_size=16) + slider_label_coat_ior = ui.TextBlock2D(text='Coat IoR', font_size=16) + + control_panel.add_element(slider_label_metallic, (0.01, 0.95)) + control_panel.add_element(slider_label_roughness, (0.01, 0.86)) + control_panel.add_element(slider_label_anisotropy, (0.01, 0.77)) + control_panel.add_element(slider_label_anisotropy_rotation, (0.01, 0.68)) + control_panel.add_element(slider_label_anisotropy_direction_x, (0.01, 0.59)) + control_panel.add_element(slider_label_anisotropy_direction_y, (0.01, 0.5)) + control_panel.add_element(slider_label_anisotropy_direction_z, (0.01, 0.41)) + control_panel.add_element(slider_label_coat_strength, (0.01, 0.32)) + control_panel.add_element(slider_label_coat_roughness, (0.01, 0.23)) + control_panel.add_element(slider_label_base_ior, (0.01, 0.14)) + control_panel.add_element(slider_label_coat_ior, (0.01, 0.05)) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 209-210 + +Our sliders are created and added to the panel in the following way. + +.. GENERATED FROM PYTHON SOURCE LINES 210-248 + +.. code-block:: Python + + + slider_slice_metallic = ui.LineSlider2D( + initial_value=pbr_params.metallic, + max_value=1, + length=195, + text_template='{value:.1f}', + ) + slider_slice_roughness = ui.LineSlider2D( + initial_value=pbr_params.roughness, + max_value=1, + length=195, + text_template='{value:.1f}', + ) + slider_slice_anisotropy = ui.LineSlider2D( + initial_value=pbr_params.anisotropy, + max_value=1, + length=195, + text_template='{value:.1f}', + ) + slider_slice_anisotropy_rotation = ui.LineSlider2D( + initial_value=pbr_params.anisotropy_rotation, + max_value=1, + length=195, + text_template='{value:.1f}', + ) + slider_slice_coat_strength = ui.LineSlider2D( + initial_value=pbr_params.coat_strength, + max_value=1, + length=195, + text_template='{value:.1f}', + ) + slider_slice_coat_roughness = ui.LineSlider2D( + initial_value=pbr_params.coat_roughness, + max_value=1, + length=195, + text_template='{value:.1f}', + ) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 249-252 + +Notice that we are defining a range of [-1, 1] for the DoA. This is because +within that range we cover all the possible 3D directions needed to align the +tangents. + +.. GENERATED FROM PYTHON SOURCE LINES 252-275 + +.. code-block:: Python + + + slider_slice_anisotropy_direction_x = ui.LineSlider2D( + initial_value=doa[0], + min_value=-1, + max_value=1, + length=195, + text_template='{value:.1f}', + ) + slider_slice_anisotropy_direction_y = ui.LineSlider2D( + initial_value=doa[1], + min_value=-1, + max_value=1, + length=195, + text_template='{value:.1f}', + ) + slider_slice_anisotropy_direction_z = ui.LineSlider2D( + initial_value=doa[2], + min_value=-1, + max_value=1, + length=195, + text_template='{value:.1f}', + ) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 276-279 + +Another special case are the Index of Refraction (IoR) sliders. In these +cases, the values are defined in the range [1, 2.3] according to the +documentation of the material. + +.. GENERATED FROM PYTHON SOURCE LINES 279-295 + +.. code-block:: Python + + + slider_slice_base_ior = ui.LineSlider2D( + initial_value=pbr_params.base_ior, + min_value=1, + max_value=2.3, + length=195, + text_template='{value:.02f}', + ) + slider_slice_coat_ior = ui.LineSlider2D( + initial_value=pbr_params.coat_ior, + min_value=1, + max_value=2.3, + length=195, + text_template='{value:.02f}', + ) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 296-297 + +Let's add the event handlers functions to the corresponding sliders. + +.. GENERATED FROM PYTHON SOURCE LINES 297-310 + +.. code-block:: Python + + + slider_slice_metallic.on_change = change_slice_metallic + slider_slice_roughness.on_change = change_slice_roughness + slider_slice_anisotropy.on_change = change_slice_anisotropy + slider_slice_anisotropy_rotation.on_change = change_slice_anisotropy_rotation + slider_slice_anisotropy_direction_x.on_change = change_slice_anisotropy_direction_x + slider_slice_anisotropy_direction_y.on_change = change_slice_anisotropy_direction_y + slider_slice_anisotropy_direction_z.on_change = change_slice_anisotropy_direction_z + slider_slice_coat_strength.on_change = change_slice_coat_strength + slider_slice_coat_roughness.on_change = change_slice_coat_roughness + slider_slice_base_ior.on_change = change_slice_base_ior + slider_slice_coat_ior.on_change = change_slice_coat_ior + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 311-312 + +And then add the sliders to the panel. + +.. GENERATED FROM PYTHON SOURCE LINES 312-325 + +.. code-block:: Python + + + control_panel.add_element(slider_slice_metallic, (0.44, 0.95)) + control_panel.add_element(slider_slice_roughness, (0.44, 0.86)) + control_panel.add_element(slider_slice_anisotropy, (0.44, 0.77)) + control_panel.add_element(slider_slice_anisotropy_rotation, (0.44, 0.68)) + control_panel.add_element(slider_slice_anisotropy_direction_x, (0.44, 0.59)) + control_panel.add_element(slider_slice_anisotropy_direction_y, (0.44, 0.5)) + control_panel.add_element(slider_slice_anisotropy_direction_z, (0.44, 0.41)) + control_panel.add_element(slider_slice_coat_strength, (0.44, 0.32)) + control_panel.add_element(slider_slice_coat_roughness, (0.44, 0.23)) + control_panel.add_element(slider_slice_base_ior, (0.44, 0.14)) + control_panel.add_element(slider_slice_coat_ior, (0.44, 0.05)) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 326-327 + +Consequently, we add the panel to the scene. + +.. GENERATED FROM PYTHON SOURCE LINES 327-330 + +.. code-block:: Python + + + scene.add(control_panel) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 331-334 + +Previously we defined a function to help us when we resize the window, so +let's capture the current size and add our helper function as a +`window_callback` to the window. + +.. GENERATED FROM PYTHON SOURCE LINES 334-339 + +.. code-block:: Python + + + size = scene.GetSize() + + show_m.add_window_callback(win_callback) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 340-341 + +Finally, let's visualize our demo. + +.. GENERATED FROM PYTHON SOURCE LINES 341-347 + +.. code-block:: Python + + + interactive = False + if interactive: + show_m.start() + + window.record(scene, size=(1920, 1080), out_path='viz_pbr_interactive.png') + + + +.. image-sg:: /auto_examples/04_demos/images/sphx_glr_viz_pbr_interactive_001.png + :alt: viz pbr interactive + :srcset: /auto_examples/04_demos/images/sphx_glr_viz_pbr_interactive_001.png + :class: sphx-glr-single-img + + + + + + +.. rst-class:: sphx-glr-timing + + **Total running time of the script:** (0 minutes 0.974 seconds) + + +.. _sphx_glr_download_auto_examples_04_demos_viz_pbr_interactive.py: + +.. only:: html + + .. container:: sphx-glr-footer sphx-glr-footer-example + + .. container:: sphx-glr-download sphx-glr-download-jupyter + + :download:`Download Jupyter notebook: viz_pbr_interactive.ipynb ` + + .. container:: sphx-glr-download sphx-glr-download-python + + :download:`Download Python source code: viz_pbr_interactive.py ` + + +.. only:: html + + .. rst-class:: sphx-glr-signature + + `Gallery generated by Sphinx-Gallery `_ diff --git a/v0.10.x/_sources/auto_examples/04_demos/viz_play_video.rst.txt b/v0.10.x/_sources/auto_examples/04_demos/viz_play_video.rst.txt new file mode 100644 index 000000000..7bdb2fc67 --- /dev/null +++ b/v0.10.x/_sources/auto_examples/04_demos/viz_play_video.rst.txt @@ -0,0 +1,154 @@ + +.. DO NOT EDIT. +.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. +.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: +.. "auto_examples/04_demos/viz_play_video.py" +.. LINE NUMBERS ARE GIVEN BELOW. + +.. only:: html + + .. note:: + :class: sphx-glr-download-link-note + + :ref:`Go to the end ` + to download the full example code + +.. rst-class:: sphx-glr-example-title + +.. _sphx_glr_auto_examples_04_demos_viz_play_video.py: + + +======================================================= +Play a video in the 3D world +======================================================= + +The goal of this demo is to show how to visualize a video +on a rectangle by updating a texture. + +.. GENERATED FROM PYTHON SOURCE LINES 9-94 + + + +.. image-sg:: /auto_examples/04_demos/images/sphx_glr_viz_play_video_001.png + :alt: viz play video + :srcset: /auto_examples/04_demos/images/sphx_glr_viz_play_video_001.png + :class: sphx-glr-single-img + + + + + +.. code-block:: Python + + + import time + + import cv2 + import numpy as np + + from fury import actor, window + + + # The VideoCapturer Class + # This Class wraps OpenCV Videocapture + class VideoCapturer: + def __init__(self, video, time): + self.path = video + self.video = cv2.VideoCapture(self.path) + self.fps = int(self.video.get(cv2.CAP_PROP_FPS)) + self.frames = int(self.video.get(cv2.CAP_PROP_FRAME_COUNT)) + self.time = time + + # A generator to yield video frames on every call + def get_frame(self): + start = time.time() + for _ in range(self.frames): + isframe, frame = self.video.read() + dur = time.time() - start + if dur > self.time: + break + if isframe: + yield cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) + self.video.release() + yield None + + + class VideoPlayer: + def __init__(self, video, time=10): + # Initializes the Video object with the given Video + self.video = VideoCapturer(video, time) + self.video_generator = self.video.get_frame() + self.current_video_frame = next(self.video_generator) + # Initialize Scene + self.initialize_scene() + # Create a Show Manager and Initialize it + self.show_manager = window.ShowManager( + self.scene, size=(900, 768), reset_camera=False, order_transparent=True + ) + + # Initialize the Scene with actors + def initialize_scene(self): + self.scene = window.Scene() + # Initialize a Plane actor with the 1st video frame along with + # the actor grid which is to be updated in each iteration + self.plane_actor = actor.texture(self.current_video_frame) + self.scene.add(self.plane_actor) + + # The timer_callback function getting called by the show manager + def timer_callback(self, _obj, _event): + self.current_video_frame = next(self.video_generator) + if isinstance(self.current_video_frame, np.ndarray): + # update texture of the actor with the current frame image + # by updating the actor grid + actor.texture_update(self.plane_actor, self.current_video_frame) + self.show_manager.scene.azimuth(1.5) # to rotate the camera + else: + self.show_manager.exit() + + self.show_manager.render() + + def run(self): + # Add a timer callback to show manager after with + # video frame duration as the interval + self.frame_duration = int(1000 / self.video.fps) + self.show_manager.add_timer_callback( + True, self.frame_duration, self.timer_callback + ) + self.show_manager.start() + + + # Create VideoPlayer Object and run it + video_url = ( + 'http://commondatastorage.googleapis.com/' + + 'gtv-videos-bucket/sample/BigBuckBunny.mp4' + ) + vp = VideoPlayer(video_url) + vp.run() + window.record(vp.show_manager.scene, out_path='viz_play_video.png', size=(600, 600)) + + +.. rst-class:: sphx-glr-timing + + **Total running time of the script:** (0 minutes 10.581 seconds) + + +.. _sphx_glr_download_auto_examples_04_demos_viz_play_video.py: + +.. only:: html + + .. container:: sphx-glr-footer sphx-glr-footer-example + + .. container:: sphx-glr-download sphx-glr-download-jupyter + + :download:`Download Jupyter notebook: viz_play_video.ipynb ` + + .. container:: sphx-glr-download sphx-glr-download-python + + :download:`Download Python source code: viz_play_video.py ` + + +.. only:: html + + .. rst-class:: sphx-glr-signature + + `Gallery generated by Sphinx-Gallery `_ diff --git a/v0.10.x/_sources/auto_examples/04_demos/viz_roi_contour.rst.txt b/v0.10.x/_sources/auto_examples/04_demos/viz_roi_contour.rst.txt new file mode 100644 index 000000000..9924f401e --- /dev/null +++ b/v0.10.x/_sources/auto_examples/04_demos/viz_roi_contour.rst.txt @@ -0,0 +1,226 @@ + +.. DO NOT EDIT. +.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. +.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: +.. "auto_examples/04_demos/viz_roi_contour.py" +.. LINE NUMBERS ARE GIVEN BELOW. + +.. only:: html + + .. note:: + :class: sphx-glr-download-link-note + + :ref:`Go to the end ` + to download the full example code + +.. rst-class:: sphx-glr-example-title + +.. _sphx_glr_auto_examples_04_demos_viz_roi_contour.py: + + +====================================================== +Visualization of ROI Surface Rendered with Streamlines +====================================================== + +Here is a simple tutorial following the probabilistic CSA Tracking Example in +which we generate a dataset of streamlines from a corpus callosum ROI, and +then display them with the seed ROI rendered in 3D with 50% transparency. + +.. GENERATED FROM PYTHON SOURCE LINES 10-30 + +.. code-block:: Python + + + from dipy.data import default_sphere, read_stanford_labels + from dipy.direction import peaks_from_model + from dipy.reconst.shm import CsaOdfModel + + try: + from dipy.tracking.local import LocalTracking + from dipy.tracking.local import ( + ThresholdTissueClassifier as ThresholdStoppingCriterion, + ) + except ImportError: + from dipy.tracking.stopping_criterion import ThresholdStoppingCriterion + from dipy.tracking.local_tracking import LocalTracking + + from dipy.tracking import utils + from dipy.tracking.streamline import Streamlines + + from fury import actor, window + from fury.colormap import line_colors + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 31-34 + +First, we need to generate some streamlines. For a more complete +description of these steps, please refer to the CSA Probabilistic Tracking +Tutorial. + +.. GENERATED FROM PYTHON SOURCE LINES 34-63 + +.. code-block:: Python + + + hardi_img, gtab, labels_img = read_stanford_labels() + data = hardi_img.get_fdata() + labels = labels_img.get_fdata() + affine = hardi_img.affine + + white_matter = (labels == 1) | (labels == 2) + + csa_model = CsaOdfModel(gtab, sh_order=6) + csa_peaks = peaks_from_model( + csa_model, + data, + default_sphere, + relative_peak_threshold=0.8, + min_separation_angle=45, + mask=white_matter, + ) + + classifier = ThresholdStoppingCriterion(csa_peaks.gfa, 0.25) + + seed_mask = labels == 2 + seeds = utils.seeds_from_mask(seed_mask, density=[1, 1, 1], affine=affine) + + # Initialization of LocalTracking. The computation happens in the next step. + streamlines = LocalTracking(csa_peaks, classifier, seeds, affine, step_size=2) + + # Compute streamlines and store as a list. + streamlines = Streamlines(streamlines) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 64-65 + +We will create a streamline actor from the streamlines. + +.. GENERATED FROM PYTHON SOURCE LINES 65-68 + +.. code-block:: Python + + + streamlines_actor = actor.line(streamlines, line_colors(streamlines)) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 69-73 + +Next, we create a surface actor from the corpus callosum seed ROI. We +provide the ROI data, the affine, the color in [R,G,B], and the opacity as +a decimal between zero and one. Here, we set the color as blue/green with +50% opacity. + +.. GENERATED FROM PYTHON SOURCE LINES 73-81 + +.. code-block:: Python + + + surface_opacity = 0.5 + surface_color = [0, 1, 1] + + seedroi_actor = actor.contour_from_roi( + seed_mask, affine, surface_color, surface_opacity + ) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 82-84 + +Next, we initialize a ''Scene'' object and add both actors +to the rendering. + +.. GENERATED FROM PYTHON SOURCE LINES 84-89 + +.. code-block:: Python + + + scene = window.Scene() + scene.add(streamlines_actor) + scene.add(seedroi_actor) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 90-92 + +If you uncomment the following line, the rendering will pop up in an +interactive window. + +.. GENERATED FROM PYTHON SOURCE LINES 92-101 + +.. code-block:: Python + + + interactive = False + if interactive: + window.show(scene) + + # scene.zoom(1.5) + # scene.reset_clipping_range() + + window.record(scene, out_path='contour_from_roi_tutorial.png', size=(600, 600)) + + + +.. image-sg:: /auto_examples/04_demos/images/sphx_glr_viz_roi_contour_001.png + :alt: viz roi contour + :srcset: /auto_examples/04_demos/images/sphx_glr_viz_roi_contour_001.png + :class: sphx-glr-single-img + + + + + + +.. rst-class:: sphx-glr-timing + + **Total running time of the script:** (2 minutes 53.689 seconds) + + +.. _sphx_glr_download_auto_examples_04_demos_viz_roi_contour.py: + +.. only:: html + + .. container:: sphx-glr-footer sphx-glr-footer-example + + .. container:: sphx-glr-download sphx-glr-download-jupyter + + :download:`Download Jupyter notebook: viz_roi_contour.ipynb ` + + .. container:: sphx-glr-download sphx-glr-download-python + + :download:`Download Python source code: viz_roi_contour.py ` + + +.. only:: html + + .. rst-class:: sphx-glr-signature + + `Gallery generated by Sphinx-Gallery `_ diff --git a/v0.10.x/_sources/auto_examples/04_demos/viz_tesseract.rst.txt b/v0.10.x/_sources/auto_examples/04_demos/viz_tesseract.rst.txt new file mode 100644 index 000000000..51ad9d513 --- /dev/null +++ b/v0.10.x/_sources/auto_examples/04_demos/viz_tesseract.rst.txt @@ -0,0 +1,381 @@ + +.. DO NOT EDIT. +.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. +.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: +.. "auto_examples/04_demos/viz_tesseract.py" +.. LINE NUMBERS ARE GIVEN BELOW. + +.. only:: html + + .. note:: + :class: sphx-glr-download-link-note + + :ref:`Go to the end ` + to download the full example code + +.. rst-class:: sphx-glr-example-title + +.. _sphx_glr_auto_examples_04_demos_viz_tesseract.py: + + +====================================================================== +Tesseract (Hypercube) +====================================================================== +A tesseract is a four-dimensional cube. A tesseract can +be unfolded into eight cubes, Just as a cube can be unfolded into eight +squares. + +.. GENERATED FROM PYTHON SOURCE LINES 11-12 + +First, import some useful functions + +.. GENERATED FROM PYTHON SOURCE LINES 12-20 + +.. code-block:: Python + + + import itertools + + import numpy as np + + from fury import actor, utils, window + from fury.ui import TextBlock2D + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 21-25 + +Let's define some variables and their descriptions: + +Use `wireframe = True` to show wireframe like representation of the tesseract +`wireframe = False` will render it with point actor on each vertex. + +.. GENERATED FROM PYTHON SOURCE LINES 25-41 + +.. code-block:: Python + + + wireframe = False + + # p_color: color of the point actor (default: (0, 0.5, 1, 1)) + # e_color: color of the line actor (default: (1, 1, 1, 1)) + # dtheta: change in `angle` on each iteration. It determines the "speed" of the + # animation. Increase dtheta to increase speed of rotation, It may + # result in less smoother rotation (default: 0.02) + # angle: defines the angle to be rotated to perform the animation, It changes + # as we run the `callback` method later on. (initial value: 0) + + p_color = np.array([0, 0.5, 1, 1]) + e_color = np.array([1, 1, 1, 1]) + dtheta = 0.02 + angle = 0 + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 42-44 + +Let's define vertices for our 4D cube, `verts4D` contains the coordinates of +our 4D tesseract. + +.. GENERATED FROM PYTHON SOURCE LINES 44-64 + +.. code-block:: Python + + + verts3D = np.array( + [ + [1, 1, 1], + [1, -1, 1], + [-1, -1, 1], + [-1, 1, 1], + [-1, 1, -1], + [1, 1, -1], + [1, -1, -1], + [-1, -1, -1], + ] + ) + + # We can use primitive.box alternatively to get the cube's 3-D vertices. + + u = np.insert(verts3D, 3, 1, axis=1) + v = np.insert(verts3D, 3, -1, axis=1) + verts4D = np.append(u, v, axis=0) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 65-68 + +We define a `rotate4D` function that takes 4D matrix as parameter and rotates +it in XY plane (Z axis) and ZW plane (an imaginary axis), projects it to the +3D plane so that we can render it in a scene. + +.. GENERATED FROM PYTHON SOURCE LINES 68-92 + +.. code-block:: Python + + + + def rotate4D(verts4D): + cos = np.cos(angle) + sin = np.sin(angle) + rotation4d_xy = np.array( + [[cos, -sin, 0, 0], [sin, cos, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]] + ) + rotation4d_zw = np.array( + [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, cos, -sin], [0, 0, sin, cos]] + ) + distance = 2 + projected_marix = np.zeros((16, 3)) + for i, vert in enumerate(verts4D): + rotated_3D = np.dot(rotation4d_xy, vert) + rotated_3D = np.dot(rotation4d_zw, rotated_3D) + w = 1 / (distance - rotated_3D[3]) + proj_mat4D = np.array([[w, 0, 0, 0], [0, w, 0, 0], [0, 0, w, 0]]) + + projeced_mat3D = np.dot(proj_mat4D, rotated_3D) + projected_marix[i] = projeced_mat3D # vertices to be proj (3D) + return projected_marix + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 93-95 + +Now, We have 4D points projected to 3D. Let's define a function to connect +lines. + +.. GENERATED FROM PYTHON SOURCE LINES 95-118 + +.. code-block:: Python + + + + def connect_points(verts3D): + lines = np.array([]) + len_vert = len(verts3D) + + for i in range(len_vert - 1): + if i < 8: + lines = np.append(lines, [verts3D[i], verts3D[i + 8]]) + if i == 7: + pass + else: + lines = np.append(lines, [verts3D[i], verts3D[i + 1]]) + if i % 4 == 0: + lines = np.append(lines, [verts3D[i], verts3D[i + 3]]) + + for i in range(3): + lines = np.append(lines, [verts3D[i], verts3D[i + 5]]) + lines = np.append(lines, [verts3D[i + 8], verts3D[i + 5 + 8]]) + + return np.reshape(lines, (-1, 2, 3)) + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 119-120 + +Creating a scene object and configuring the camera's position + +.. GENERATED FROM PYTHON SOURCE LINES 120-128 + +.. code-block:: Python + + + scene = window.Scene() + scene.set_camera( + position=(0, 10, -1), focal_point=(0.0, 0.0, 0.0), view_up=(0.0, 0.0, 0.0) + ) + showm = window.ShowManager(scene, size=(1920, 1080), order_transparent=True) + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 129-130 + +Creating vertices and points actors + +.. GENERATED FROM PYTHON SOURCE LINES 130-140 + +.. code-block:: Python + + + verts3D = rotate4D(verts4D) + if not wireframe: + points = actor.point(verts3D, colors=p_color) + point_verts = utils.vertices_from_actor(points) + no_vertices = len(point_verts) / 16 + initial_verts = point_verts.copy() - np.repeat(verts3D, no_vertices, axis=0) + + scene.add(points) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 141-142 + +Connecting points with lines actor + +.. GENERATED FROM PYTHON SOURCE LINES 142-150 + +.. code-block:: Python + + + lines = connect_points(verts3D) + edges = actor.line(lines=lines, colors=e_color, lod=False, fake_tube=True, linewidth=4) + lines_verts = utils.vertices_from_actor(edges) + initial_lines = lines_verts.copy() - np.reshape(lines, (-1, 3)) + + scene.add(edges) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 151-152 + +Initializing text box to display the name + +.. GENERATED FROM PYTHON SOURCE LINES 152-156 + +.. code-block:: Python + + + tb = TextBlock2D(text='Tesseract', position=(900, 950), font_size=20) + showm.scene.add(tb) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 157-159 + +Define a timer_callback in which we'll update the vertices of point and lines +actor using `rotate4D`. + +.. GENERATED FROM PYTHON SOURCE LINES 159-183 + +.. code-block:: Python + + + counter = itertools.count() + end = 200 + + + def timer_callback(_obj, _event): + global verts3D, angle + cnt = next(counter) + verts3D = rotate4D(verts4D) + if not wireframe: + point_verts[:] = initial_verts + np.repeat(verts3D, no_vertices, axis=0) + utils.update_actor(points) + + lines = connect_points(verts3D) + lines_verts[:] = initial_lines + np.reshape(lines, (-1, 3)) + utils.update_actor(edges) + + showm.render() + angle += dtheta + + if cnt == end: + showm.exit() + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 184-185 + +Run every 20 milliseconds + +.. GENERATED FROM PYTHON SOURCE LINES 185-190 + +.. code-block:: Python + + + + showm.add_timer_callback(True, 20, timer_callback) + showm.start() + window.record(showm.scene, size=(600, 600), out_path='viz_tesseract.png') + + + +.. image-sg:: /auto_examples/04_demos/images/sphx_glr_viz_tesseract_001.png + :alt: viz tesseract + :srcset: /auto_examples/04_demos/images/sphx_glr_viz_tesseract_001.png + :class: sphx-glr-single-img + + + + + + +.. rst-class:: sphx-glr-timing + + **Total running time of the script:** (0 minutes 4.109 seconds) + + +.. _sphx_glr_download_auto_examples_04_demos_viz_tesseract.py: + +.. only:: html + + .. container:: sphx-glr-footer sphx-glr-footer-example + + .. container:: sphx-glr-download sphx-glr-download-jupyter + + :download:`Download Jupyter notebook: viz_tesseract.ipynb ` + + .. container:: sphx-glr-download sphx-glr-download-python + + :download:`Download Python source code: viz_tesseract.py ` + + +.. only:: html + + .. rst-class:: sphx-glr-signature + + `Gallery generated by Sphinx-Gallery `_ diff --git a/v0.10.x/_sources/auto_examples/07_ui/index.rst.txt b/v0.10.x/_sources/auto_examples/07_ui/index.rst.txt new file mode 100644 index 000000000..b019f3a24 --- /dev/null +++ b/v0.10.x/_sources/auto_examples/07_ui/index.rst.txt @@ -0,0 +1,277 @@ + + +.. _sphx_glr_auto_examples_07_ui: + +User Interface Elements +----------------------- + +These tutorials show how to create user interfaces elements. + + + +.. raw:: html + +
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/07_ui/images/thumb/sphx_glr_viz_shapes_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_07_ui_viz_shapes.py` + +.. raw:: html + +
Simple Shapes
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/07_ui/images/thumb/sphx_glr_viz_drawpanel_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_07_ui_viz_drawpanel.py` + +.. raw:: html + +
DrawPanel
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/07_ui/images/thumb/sphx_glr_viz_card_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_07_ui_viz_card.py` + +.. raw:: html + +
Card
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/07_ui/images/thumb/sphx_glr_viz_spinbox_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_07_ui_viz_spinbox.py` + +.. raw:: html + +
SpinBox UI
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/07_ui/images/thumb/sphx_glr_viz_combobox_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_07_ui_viz_combobox.py` + +.. raw:: html + +
ComboBox
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/07_ui/images/thumb/sphx_glr_viz_ui_listbox_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_07_ui_viz_ui_listbox.py` + +.. raw:: html + +
ListBox
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/07_ui/images/thumb/sphx_glr_viz_layout_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_07_ui_viz_layout.py` + +.. raw:: html + +
Using Layouts with different UI elements
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/07_ui/images/thumb/sphx_glr_viz_radio_buttons_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_07_ui_viz_radio_buttons.py` + +.. raw:: html + +
Sphere Color Control using Radio Buttons
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/07_ui/images/thumb/sphx_glr_viz_buttons_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_07_ui_viz_buttons.py` + +.. raw:: html + +
Buttons & Text
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/07_ui/images/thumb/sphx_glr_viz_card_sprite_sheet_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_07_ui_viz_card_sprite_sheet.py` + +.. raw:: html + +
Card
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/07_ui/images/thumb/sphx_glr_viz_ui_slider_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_07_ui_viz_ui_slider.py` + +.. raw:: html + +
Cube & Slider Control
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/07_ui/images/thumb/sphx_glr_viz_check_boxes_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_07_ui_viz_check_boxes.py` + +.. raw:: html + +
Figure and Color Control using Check boxes and Radio Buttons
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/07_ui/images/thumb/sphx_glr_viz_tab_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_07_ui_viz_tab.py` + +.. raw:: html + +
Tab UI
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/07_ui/images/thumb/sphx_glr_viz_ui_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_07_ui_viz_ui.py` + +.. raw:: html + +
User Interfaces
+
+ + +.. raw:: html + +
+ + +.. toctree:: + :hidden: + + /auto_examples/07_ui/viz_shapes + /auto_examples/07_ui/viz_drawpanel + /auto_examples/07_ui/viz_card + /auto_examples/07_ui/viz_spinbox + /auto_examples/07_ui/viz_combobox + /auto_examples/07_ui/viz_ui_listbox + /auto_examples/07_ui/viz_layout + /auto_examples/07_ui/viz_radio_buttons + /auto_examples/07_ui/viz_buttons + /auto_examples/07_ui/viz_card_sprite_sheet + /auto_examples/07_ui/viz_ui_slider + /auto_examples/07_ui/viz_check_boxes + /auto_examples/07_ui/viz_tab + /auto_examples/07_ui/viz_ui + diff --git a/v0.10.x/_sources/auto_examples/07_ui/sg_execution_times.rst.txt b/v0.10.x/_sources/auto_examples/07_ui/sg_execution_times.rst.txt new file mode 100644 index 000000000..6db61729b --- /dev/null +++ b/v0.10.x/_sources/auto_examples/07_ui/sg_execution_times.rst.txt @@ -0,0 +1,76 @@ + +:orphan: + +.. _sphx_glr_auto_examples_07_ui_sg_execution_times: + + +Computation times +================= +**00:00.931** total execution time for 14 files **from auto_examples/07_ui**: + +.. container:: + + .. raw:: html + + + + + + + + .. list-table:: + :header-rows: 1 + :class: table table-striped sg-datatable + + * - Example + - Time + - Mem (MB) + * - :ref:`sphx_glr_auto_examples_07_ui_viz_card_sprite_sheet.py` (``viz_card_sprite_sheet.py``) + - 00:00.931 + - 0.0 + * - :ref:`sphx_glr_auto_examples_07_ui_viz_buttons.py` (``viz_buttons.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_07_ui_viz_card.py` (``viz_card.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_07_ui_viz_check_boxes.py` (``viz_check_boxes.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_07_ui_viz_combobox.py` (``viz_combobox.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_07_ui_viz_drawpanel.py` (``viz_drawpanel.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_07_ui_viz_layout.py` (``viz_layout.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_07_ui_viz_radio_buttons.py` (``viz_radio_buttons.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_07_ui_viz_shapes.py` (``viz_shapes.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_07_ui_viz_spinbox.py` (``viz_spinbox.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_07_ui_viz_tab.py` (``viz_tab.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_07_ui_viz_ui.py` (``viz_ui.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_07_ui_viz_ui_listbox.py` (``viz_ui_listbox.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_07_ui_viz_ui_slider.py` (``viz_ui_slider.py``) + - 00:00.000 + - 0.0 diff --git a/v0.10.x/_sources/auto_examples/07_ui/viz_buttons.rst.txt b/v0.10.x/_sources/auto_examples/07_ui/viz_buttons.rst.txt new file mode 100644 index 000000000..b1b6e1bbc --- /dev/null +++ b/v0.10.x/_sources/auto_examples/07_ui/viz_buttons.rst.txt @@ -0,0 +1,236 @@ + +.. DO NOT EDIT. +.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. +.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: +.. "auto_examples/07_ui/viz_buttons.py" +.. LINE NUMBERS ARE GIVEN BELOW. + +.. only:: html + + .. note:: + :class: sphx-glr-download-link-note + + :ref:`Go to the end ` + to download the full example code + +.. rst-class:: sphx-glr-example-title + +.. _sphx_glr_auto_examples_07_ui_viz_buttons.py: + + +=============== +Buttons & Text +=============== + +This example shows how to use the UI API. We will demonstrate how to create +panel having buttons with callbacks. + +First, some imports. + +.. GENERATED FROM PYTHON SOURCE LINES 12-15 + +.. code-block:: Python + + from fury import ui, window + from fury.data import fetch_viz_icons, read_viz_icons + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 16-17 + +First we need to fetch some icons that are included in FURY. + +.. GENERATED FROM PYTHON SOURCE LINES 17-20 + +.. code-block:: Python + + + fetch_viz_icons() + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + Data size is approximately 12KB + Dataset is already in place. If you want to fetch it again please first remove the folder /Users/skoudoro/.fury/icons + + ({'icomoon.tar.gz': ('https://digital.lib.washington.edu/researchworks/bitstream/handle/1773/38478/icomoon.tar.gz', 'BC1FEEA6F58BA3601D6A0B029EB8DFC5F352E21F2A16BA41099A96AA3F5A4735')}, '/Users/skoudoro/.fury/icons') + + + +.. GENERATED FROM PYTHON SOURCE LINES 21-23 + +Let's create some buttons and text and put them in a panel. +First we'll make the panel. + +.. GENERATED FROM PYTHON SOURCE LINES 23-27 + +.. code-block:: Python + + + panel = ui.Panel2D(size=(300, 150), color=(1, 1, 1), align='right') + panel.center = (500, 400) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 28-30 + +Then we'll make two text labels and place them on the panel. +Note that we specify the position with integer numbers of pixels. + +.. GENERATED FROM PYTHON SOURCE LINES 30-36 + +.. code-block:: Python + + + text = ui.TextBlock2D(text='Click me') + text2 = ui.TextBlock2D(text='Me too') + panel.add_element(text, (50, 100)) + panel.add_element(text2, (180, 100)) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 37-41 + +Then we'll create two buttons and add them to the panel. + +Note that here we specify the positions with floats. In this case, these are +percentages of the panel size. + +.. GENERATED FROM PYTHON SOURCE LINES 41-59 + +.. code-block:: Python + + + + button_example = ui.Button2D( + icon_fnames=[('square', read_viz_icons(fname='stop2.png'))] + ) + + icon_files = [] + icon_files.append(('down', read_viz_icons(fname='circle-down.png'))) + icon_files.append(('left', read_viz_icons(fname='circle-left.png'))) + icon_files.append(('up', read_viz_icons(fname='circle-up.png'))) + icon_files.append(('right', read_viz_icons(fname='circle-right.png'))) + + second_button_example = ui.Button2D(icon_fnames=icon_files) + + panel.add_element(button_example, (0.25, 0.33)) + panel.add_element(second_button_example, (0.66, 0.33)) + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 60-61 + +We can add a callback to each button to perform some action. + +.. GENERATED FROM PYTHON SOURCE LINES 61-76 + +.. code-block:: Python + + + + def change_text_callback(i_ren, _obj, _button): + text.message = 'Clicked!' + i_ren.force_render() + + + def change_icon_callback(i_ren, _obj, _button): + _button.next_icon() + i_ren.force_render() + + + button_example.on_left_mouse_button_clicked = change_text_callback + second_button_example.on_left_mouse_button_pressed = change_icon_callback + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 77-79 + +Now that all the elements have been initialised, we add them to the show +manager. + +.. GENERATED FROM PYTHON SOURCE LINES 79-91 + +.. code-block:: Python + + + current_size = (800, 800) + show_manager = window.ShowManager(size=current_size, title='FURY Button Example') + + show_manager.scene.add(panel) + + interactive = False + + if interactive: + show_manager.start() + + window.record(show_manager.scene, size=current_size, out_path='viz_button.png') + + + +.. image-sg:: /auto_examples/07_ui/images/sphx_glr_viz_buttons_001.png + :alt: viz buttons + :srcset: /auto_examples/07_ui/images/sphx_glr_viz_buttons_001.png + :class: sphx-glr-single-img + + + + + + +.. rst-class:: sphx-glr-timing + + **Total running time of the script:** (0 minutes 0.071 seconds) + + +.. _sphx_glr_download_auto_examples_07_ui_viz_buttons.py: + +.. only:: html + + .. container:: sphx-glr-footer sphx-glr-footer-example + + .. container:: sphx-glr-download sphx-glr-download-jupyter + + :download:`Download Jupyter notebook: viz_buttons.ipynb ` + + .. container:: sphx-glr-download sphx-glr-download-python + + :download:`Download Python source code: viz_buttons.py ` + + +.. only:: html + + .. rst-class:: sphx-glr-signature + + `Gallery generated by Sphinx-Gallery `_ diff --git a/v0.10.x/_sources/auto_examples/07_ui/viz_card.rst.txt b/v0.10.x/_sources/auto_examples/07_ui/viz_card.rst.txt new file mode 100644 index 000000000..bad83a07d --- /dev/null +++ b/v0.10.x/_sources/auto_examples/07_ui/viz_card.rst.txt @@ -0,0 +1,158 @@ + +.. DO NOT EDIT. +.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. +.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: +.. "auto_examples/07_ui/viz_card.py" +.. LINE NUMBERS ARE GIVEN BELOW. + +.. only:: html + + .. note:: + :class: sphx-glr-download-link-note + + :ref:`Go to the end ` + to download the full example code + +.. rst-class:: sphx-glr-example-title + +.. _sphx_glr_auto_examples_07_ui_viz_card.py: + + +==== +Card +==== + +This example shows how to create a card. + +First, some imports. + +.. GENERATED FROM PYTHON SOURCE LINES 11-14 + +.. code-block:: Python + + from fury import ui, window + from fury.data import fetch_viz_icons + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 15-16 + +First we need to fetch some icons that are included in FURY. + +.. GENERATED FROM PYTHON SOURCE LINES 16-19 + +.. code-block:: Python + + + fetch_viz_icons() + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + Data size is approximately 12KB + Dataset is already in place. If you want to fetch it again please first remove the folder /Users/skoudoro/.fury/icons + + ({'icomoon.tar.gz': ('https://digital.lib.washington.edu/researchworks/bitstream/handle/1773/38478/icomoon.tar.gz', 'BC1FEEA6F58BA3601D6A0B029EB8DFC5F352E21F2A16BA41099A96AA3F5A4735')}, '/Users/skoudoro/.fury/icons') + + + +.. GENERATED FROM PYTHON SOURCE LINES 20-21 + +Let's create a card and add it to the show manager + +.. GENERATED FROM PYTHON SOURCE LINES 21-36 + +.. code-block:: Python + + + img_url = "https://raw.githubusercontent.com/fury-gl"\ + "/fury-communication-assets/main/fury-logo.png" + + title = "FURY" + body = "FURY - Free Unified Rendering in pYthon."\ + "A software library for scientific visualization in Python." + + card = ui.elements.Card2D(image_path=img_url, title_text=title, + body_text=body, + image_scale=0.55, size=(300, 300), + bg_color=(1, 0.294, 0.180), + bg_opacity=0.8, border_width=5, + border_color=(0.1, 0.4, 0.4)) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 37-39 + +Now that the card has been initialised, we add it to the show +manager. + +.. GENERATED FROM PYTHON SOURCE LINES 39-52 + +.. code-block:: Python + + + current_size = (1000, 1000) + show_manager = window.ShowManager(size=current_size, + title="FURY Card Example") + + show_manager.scene.add(card) + # To interact with the UI, set interactive = True + interactive = False + + if interactive: + show_manager.start() + + window.record(show_manager.scene, out_path="card_ui.png", size=(1000, 1000)) + + + +.. image-sg:: /auto_examples/07_ui/images/sphx_glr_viz_card_001.png + :alt: viz card + :srcset: /auto_examples/07_ui/images/sphx_glr_viz_card_001.png + :class: sphx-glr-single-img + + + + + + +.. rst-class:: sphx-glr-timing + + **Total running time of the script:** (0 minutes 0.257 seconds) + + +.. _sphx_glr_download_auto_examples_07_ui_viz_card.py: + +.. only:: html + + .. container:: sphx-glr-footer sphx-glr-footer-example + + .. container:: sphx-glr-download sphx-glr-download-jupyter + + :download:`Download Jupyter notebook: viz_card.ipynb ` + + .. container:: sphx-glr-download sphx-glr-download-python + + :download:`Download Python source code: viz_card.py ` + + +.. only:: html + + .. rst-class:: sphx-glr-signature + + `Gallery generated by Sphinx-Gallery `_ diff --git a/v0.10.x/_sources/auto_examples/07_ui/viz_card_sprite_sheet.rst.txt b/v0.10.x/_sources/auto_examples/07_ui/viz_card_sprite_sheet.rst.txt new file mode 100644 index 000000000..9e1bb855b --- /dev/null +++ b/v0.10.x/_sources/auto_examples/07_ui/viz_card_sprite_sheet.rst.txt @@ -0,0 +1,258 @@ + +.. DO NOT EDIT. +.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. +.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: +.. "auto_examples/07_ui/viz_card_sprite_sheet.py" +.. LINE NUMBERS ARE GIVEN BELOW. + +.. only:: html + + .. note:: + :class: sphx-glr-download-link-note + + :ref:`Go to the end ` + to download the full example code + +.. rst-class:: sphx-glr-example-title + +.. _sphx_glr_auto_examples_07_ui_viz_card_sprite_sheet.py: + + +==== +Card +==== + +This example shows how to create a card and use a sprite +sheet to update the image in the card. + +First, some imports. + +.. GENERATED FROM PYTHON SOURCE LINES 12-18 + +.. code-block:: Python + + import os + from fury import ui, window + from fury.data import fetch_viz_icons + from fury.io import load_image, load_sprite_sheet, save_image + from tempfile import TemporaryDirectory as InTemporaryDirectory + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 19-20 + +First we need to fetch some icons that are included in FURY. + +.. GENERATED FROM PYTHON SOURCE LINES 20-32 + +.. code-block:: Python + + + TARGET_FPS = 15 + FRAME_TIME = (1.0 / TARGET_FPS) * 1000 + + fetch_viz_icons() + + sprite_sheet = load_sprite_sheet('https://raw.githubusercontent.com/fury-gl/' + 'fury-data/master/unittests/fury_sprite.png', + 5, 5) + CURRENT_SPRITE_IDX = 0 + + vtk_sprites = [] + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + Data size is approximately 12KB + Dataset is already in place. If you want to fetch it again please first remove the folder /Users/skoudoro/.fury/icons + + + + +.. GENERATED FROM PYTHON SOURCE LINES 33-34 + +Let's create a card and add it to the show manager + +.. GENERATED FROM PYTHON SOURCE LINES 34-49 + +.. code-block:: Python + + + img_url = "https://raw.githubusercontent.com/fury-gl"\ + "/fury-communication-assets/main/fury-logo.png" + + title = "FURY" + body = "FURY - Free Unified Rendering in pYthon."\ + "A software library for scientific visualization in Python." + + card = ui.elements.Card2D(image_path=img_url, title_text=title, + body_text=body, + image_scale=0.55, size=(300, 300), + bg_color=(1, 0.294, 0.180), + bg_opacity=0.8, border_width=5, + border_color=(0.1, 0.4, 0.8)) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 50-51 + +Now we define the callback to update the image on card after some delay. + +.. GENERATED FROM PYTHON SOURCE LINES 51-63 + +.. code-block:: Python + + + + def timer_callback(_obj, _evt): + global CURRENT_SPRITE_IDX, show_manager + CURRENT_SPRITE_IDX += 1 + sprite = vtk_sprites[CURRENT_SPRITE_IDX % len(vtk_sprites)] + card.image.set_img(sprite) + i_ren = show_manager.scene.GetRenderWindow()\ + .GetInteractor().GetInteractorStyle() + + i_ren.force_render() + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 64-65 + +Lets create a function to convert the sprite to vtkImageData + +.. GENERATED FROM PYTHON SOURCE LINES 65-76 + +.. code-block:: Python + + + + def sprite_to_vtk(): + with InTemporaryDirectory() as tdir: + for idx, sprite in enumerate(list(sprite_sheet.values())): + sprite_path = os.path.join(tdir, f'{idx}.png') + save_image(sprite, sprite_path, compression_quality=100) + vtk_sprite = load_image(sprite_path, as_vtktype=True) + vtk_sprites.append(vtk_sprite) + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 77-79 + +Now that the card has been initialised, we add it to the show +manager. + +.. GENERATED FROM PYTHON SOURCE LINES 79-86 + +.. code-block:: Python + + + current_size = (1000, 1000) + show_manager = window.ShowManager(size=current_size, + title="FURY Card Example") + + show_manager.scene.add(card) + show_manager.initialize() + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 87-88 + +Converting numpy array sprites to vtk images + +.. GENERATED FROM PYTHON SOURCE LINES 88-90 + +.. code-block:: Python + + sprite_to_vtk() + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 91-92 + +Adding a timer to update the card image + +.. GENERATED FROM PYTHON SOURCE LINES 92-101 + +.. code-block:: Python + + show_manager.add_timer_callback(True, int(FRAME_TIME), timer_callback) + + # To interact with the UI, set interactive = True + interactive = False + + if interactive: + show_manager.start() + + window.record(show_manager.scene, out_path="card_ui.png", size=(1000, 1000)) + + + +.. image-sg:: /auto_examples/07_ui/images/sphx_glr_viz_card_sprite_sheet_001.png + :alt: viz card sprite sheet + :srcset: /auto_examples/07_ui/images/sphx_glr_viz_card_sprite_sheet_001.png + :class: sphx-glr-single-img + + + + + + +.. rst-class:: sphx-glr-timing + + **Total running time of the script:** (0 minutes 0.931 seconds) + + +.. _sphx_glr_download_auto_examples_07_ui_viz_card_sprite_sheet.py: + +.. only:: html + + .. container:: sphx-glr-footer sphx-glr-footer-example + + .. container:: sphx-glr-download sphx-glr-download-jupyter + + :download:`Download Jupyter notebook: viz_card_sprite_sheet.ipynb ` + + .. container:: sphx-glr-download sphx-glr-download-python + + :download:`Download Python source code: viz_card_sprite_sheet.py ` + + +.. only:: html + + .. rst-class:: sphx-glr-signature + + `Gallery generated by Sphinx-Gallery `_ diff --git a/v0.10.x/_sources/auto_examples/07_ui/viz_check_boxes.rst.txt b/v0.10.x/_sources/auto_examples/07_ui/viz_check_boxes.rst.txt new file mode 100644 index 000000000..054720429 --- /dev/null +++ b/v0.10.x/_sources/auto_examples/07_ui/viz_check_boxes.rst.txt @@ -0,0 +1,324 @@ + +.. DO NOT EDIT. +.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. +.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: +.. "auto_examples/07_ui/viz_check_boxes.py" +.. LINE NUMBERS ARE GIVEN BELOW. + +.. only:: html + + .. note:: + :class: sphx-glr-download-link-note + + :ref:`Go to the end ` + to download the full example code + +.. rst-class:: sphx-glr-example-title + +.. _sphx_glr_auto_examples_07_ui_viz_check_boxes.py: + + +============================================================ +Figure and Color Control using Check boxes and Radio Buttons +============================================================ + +This example shows how to use the CheckBox UI API. We will demonstrate how to +create a cube, sphere, cone and arrow and control its color and visibility +using checkboxes. + +First, some imports. + +.. GENERATED FROM PYTHON SOURCE LINES 12-18 + +.. code-block:: Python + + + import numpy as np + + from fury import actor, ui, utils, window + from fury.data import fetch_viz_icons + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 19-20 + +First we need to fetch some icons that are included in FURY. + +.. GENERATED FROM PYTHON SOURCE LINES 20-23 + +.. code-block:: Python + + + fetch_viz_icons() + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + Data size is approximately 12KB + Dataset is already in place. If you want to fetch it again please first remove the folder /Users/skoudoro/.fury/icons + + ({'icomoon.tar.gz': ('https://digital.lib.washington.edu/researchworks/bitstream/handle/1773/38478/icomoon.tar.gz', 'BC1FEEA6F58BA3601D6A0B029EB8DFC5F352E21F2A16BA41099A96AA3F5A4735')}, '/Users/skoudoro/.fury/icons') + + + +.. GENERATED FROM PYTHON SOURCE LINES 24-25 + +We create the corresponding object actors for cube, sphere, cone and arrow. + +.. GENERATED FROM PYTHON SOURCE LINES 25-57 + +.. code-block:: Python + + + cube = actor.cube( + centers=np.array([[15, 0, 0]]), + colors=np.array([[0, 0, 1]]), + scales=np.array([[20, 20, 20]]), + directions=np.array([[0, 0, 1]]), + ) + + sphere = actor.sphere( + centers=np.array([[50, 0, 0]]), + colors=np.array([[0, 0, 1]]), + radii=11.0, + theta=360, + phi=360, + ) + + cone = actor.cone( + centers=np.array([[-20, -0.5, 0]]), + directions=np.array([[0, 1, 0]]), + colors=np.array([[0, 0, 1]]), + heights=20, + resolution=100, + ) + + arrow = actor.arrow( + centers=np.array([[0, 25, 0]]), + colors=np.array([[0, 0, 1]]), + directions=np.array([[1, 0, 0]]), + heights=40, + resolution=100, + ) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 58-60 + +We perform symmetric difference to determine the unchecked options. +We also define methods to render visibility and color. + +.. GENERATED FROM PYTHON SOURCE LINES 60-103 + +.. code-block:: Python + + + + # Get difference between two lists. + def sym_diff(l1, l2): + return list(set(l1).symmetric_difference(set(l2))) + + + # Set Visibility of the figures + def set_figure_visiblity(checkboxes): + checked = checkboxes.checked_labels + unchecked = sym_diff(list(figure_dict), checked) + + for visible in checked: + figure_dict[visible].SetVisibility(True) + + for invisible in unchecked: + figure_dict[invisible].SetVisibility(False) + + + def update_colors(color_array): + for _, figure in figure_dict.items(): + vcolors = utils.colors_from_actor(figure) + vcolors[:] = color_array + utils.update_actor(figure) + + + # Toggle colors of the figures + def toggle_color(checkboxes): + colors = checkboxes.checked_labels + + color_array = np.array([0, 0, 0]) + + for col in colors: + if col == 'Red': + color_array[0] = 255 + elif col == 'Green': + color_array[1] = 255 + else: + color_array[2] = 255 + + update_colors(color_array) + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 104-106 + +We define a dictionary to store the actors with their names as keys. +A checkbox is created with actor names as it's options. + +.. GENERATED FROM PYTHON SOURCE LINES 106-117 + +.. code-block:: Python + + + figure_dict = {'cube': cube, 'sphere': sphere, 'cone': cone, 'arrow': arrow} + check_box = ui.Checkbox( + list(figure_dict), + list(figure_dict), + padding=1, + font_size=18, + font_family='Arial', + position=(400, 85), + ) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 118-119 + +A similar checkbox is created for changing colors. + +.. GENERATED FROM PYTHON SOURCE LINES 119-135 + +.. code-block:: Python + + + options = {'Blue': (0, 0, 1), 'Red': (1, 0, 0), 'Green': (0, 1, 0)} + color_toggler = ui.Checkbox( + list(options), + checked_labels=['Blue'], + padding=1, + font_size=16, + font_family='Arial', + position=(600, 120), + ) + + + check_box.on_change = set_figure_visiblity + color_toggler.on_change = toggle_color + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 136-141 + +Show Manager +================================== + +Now that all the elements have been initialised, we add them to the show +manager. + +.. GENERATED FROM PYTHON SOURCE LINES 141-152 + +.. code-block:: Python + + + current_size = (1000, 1000) + show_manager = window.ShowManager(size=current_size, title='FURY Checkbox Example') + + show_manager.scene.add(cube) + show_manager.scene.add(sphere) + show_manager.scene.add(cone) + show_manager.scene.add(arrow) + show_manager.scene.add(check_box) + show_manager.scene.add(color_toggler) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 153-154 + +Set camera for better visualization + +.. GENERATED FROM PYTHON SOURCE LINES 154-165 + +.. code-block:: Python + + + show_manager.scene.reset_camera() + show_manager.scene.set_camera(position=(0, 0, 150)) + show_manager.scene.reset_clipping_range() + show_manager.scene.azimuth(30) + interactive = False + + if interactive: + show_manager.start() + + window.record(show_manager.scene, size=current_size, out_path='viz_checkbox.png') + + + +.. image-sg:: /auto_examples/07_ui/images/sphx_glr_viz_check_boxes_001.png + :alt: viz check boxes + :srcset: /auto_examples/07_ui/images/sphx_glr_viz_check_boxes_001.png + :class: sphx-glr-single-img + + + + + + +.. rst-class:: sphx-glr-timing + + **Total running time of the script:** (0 minutes 0.140 seconds) + + +.. _sphx_glr_download_auto_examples_07_ui_viz_check_boxes.py: + +.. only:: html + + .. container:: sphx-glr-footer sphx-glr-footer-example + + .. container:: sphx-glr-download sphx-glr-download-jupyter + + :download:`Download Jupyter notebook: viz_check_boxes.ipynb ` + + .. container:: sphx-glr-download sphx-glr-download-python + + :download:`Download Python source code: viz_check_boxes.py ` + + +.. only:: html + + .. rst-class:: sphx-glr-signature + + `Gallery generated by Sphinx-Gallery `_ diff --git a/v0.10.x/_sources/auto_examples/07_ui/viz_combobox.rst.txt b/v0.10.x/_sources/auto_examples/07_ui/viz_combobox.rst.txt new file mode 100644 index 000000000..d78ff9fa3 --- /dev/null +++ b/v0.10.x/_sources/auto_examples/07_ui/viz_combobox.rst.txt @@ -0,0 +1,236 @@ + +.. DO NOT EDIT. +.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. +.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: +.. "auto_examples/07_ui/viz_combobox.py" +.. LINE NUMBERS ARE GIVEN BELOW. + +.. only:: html + + .. note:: + :class: sphx-glr-download-link-note + + :ref:`Go to the end ` + to download the full example code + +.. rst-class:: sphx-glr-example-title + +.. _sphx_glr_auto_examples_07_ui_viz_combobox.py: + + +======== +ComboBox +======== + +This example shows how to use the Combobox UI. We will demonstrate how to +create ComboBoxes for selecting colors for a label. + +First, some imports. + +.. GENERATED FROM PYTHON SOURCE LINES 11-14 + +.. code-block:: Python + + from fury import ui, window + from fury.data import fetch_viz_icons + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 15-16 + +First we need to fetch some icons that are included in FURY. + +.. GENERATED FROM PYTHON SOURCE LINES 16-19 + +.. code-block:: Python + + + fetch_viz_icons() + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + Data size is approximately 12KB + Dataset is already in place. If you want to fetch it again please first remove the folder /Users/skoudoro/.fury/icons + + ({'icomoon.tar.gz': ('https://digital.lib.washington.edu/researchworks/bitstream/handle/1773/38478/icomoon.tar.gz', 'BC1FEEA6F58BA3601D6A0B029EB8DFC5F352E21F2A16BA41099A96AA3F5A4735')}, '/Users/skoudoro/.fury/icons') + + + +.. GENERATED FROM PYTHON SOURCE LINES 20-21 + +First, we create a label. + +.. GENERATED FROM PYTHON SOURCE LINES 21-31 + +.. code-block:: Python + + + label = ui.TextBlock2D( + position=(200, 300), + font_size=40, + color=(1, 0.5, 0), + justification='center', + vertical_justification='top', + text='FURY rocks!!!', + ) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 32-34 + +Now we create a dictionary to store colors as its key and their +RGB values as its value. + +.. GENERATED FROM PYTHON SOURCE LINES 34-45 + +.. code-block:: Python + + + colors = { + 'Violet': (0.6, 0, 0.8), + 'Indigo': (0.3, 0, 0.5), + 'Blue': (0, 0, 1), + 'Green': (0, 1, 0), + 'Yellow': (1, 1, 0), + 'Orange': (1, 0.5, 0), + 'Red': (1, 0, 0), + } + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 46-50 + +ComboBox +=================== + +Now we create a ComboBox UI component for selecting colors. + +.. GENERATED FROM PYTHON SOURCE LINES 50-58 + +.. code-block:: Python + + + color_combobox = ui.ComboBox2D( + items=list(colors.keys()), + placeholder='Choose Text Color', + position=(75, 50), + size=(250, 150), + ) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 59-63 + +Callbacks +================================== + +Now we create a callback for setting the chosen color. + +.. GENERATED FROM PYTHON SOURCE LINES 63-73 + +.. code-block:: Python + + + + def change_color(combobox): + label.color = colors[combobox.selected_text] + + + # `on_change` callback is set to `change_color` method so that + # it's called whenever a different option is selected. + color_combobox.on_change = change_color + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 74-78 + +Show Manager +================================== + +Now we add label and combobox to the scene. + +.. GENERATED FROM PYTHON SOURCE LINES 78-90 + +.. code-block:: Python + + + current_size = (400, 400) + showm = window.ShowManager(size=current_size, title='ComboBox UI Example') + showm.scene.add(label, color_combobox) + + # To interact with the UI, set interactive = True + interactive = False + + if interactive: + showm.start() + + window.record(showm.scene, out_path='combobox_ui.png', size=(400, 400)) + + + +.. image-sg:: /auto_examples/07_ui/images/sphx_glr_viz_combobox_001.png + :alt: viz combobox + :srcset: /auto_examples/07_ui/images/sphx_glr_viz_combobox_001.png + :class: sphx-glr-single-img + + + + + + +.. rst-class:: sphx-glr-timing + + **Total running time of the script:** (0 minutes 0.050 seconds) + + +.. _sphx_glr_download_auto_examples_07_ui_viz_combobox.py: + +.. only:: html + + .. container:: sphx-glr-footer sphx-glr-footer-example + + .. container:: sphx-glr-download sphx-glr-download-jupyter + + :download:`Download Jupyter notebook: viz_combobox.ipynb ` + + .. container:: sphx-glr-download sphx-glr-download-python + + :download:`Download Python source code: viz_combobox.py ` + + +.. only:: html + + .. rst-class:: sphx-glr-signature + + `Gallery generated by Sphinx-Gallery `_ diff --git a/v0.10.x/_sources/auto_examples/07_ui/viz_drawpanel.rst.txt b/v0.10.x/_sources/auto_examples/07_ui/viz_drawpanel.rst.txt new file mode 100644 index 000000000..dbf9106f6 --- /dev/null +++ b/v0.10.x/_sources/auto_examples/07_ui/viz_drawpanel.rst.txt @@ -0,0 +1,152 @@ + +.. DO NOT EDIT. +.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. +.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: +.. "auto_examples/07_ui/viz_drawpanel.py" +.. LINE NUMBERS ARE GIVEN BELOW. + +.. only:: html + + .. note:: + :class: sphx-glr-download-link-note + + :ref:`Go to the end ` + to download the full example code + +.. rst-class:: sphx-glr-example-title + +.. _sphx_glr_auto_examples_07_ui_viz_drawpanel.py: + + +========= +DrawPanel +========= + +This example shows how to use the DrawPanel UI. We will demonstrate how to +create Various shapes and transform them. + +First, some imports. + +.. GENERATED FROM PYTHON SOURCE LINES 11-14 + +.. code-block:: Python + + from fury import ui, window + from fury.data import fetch_viz_new_icons + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 15-16 + +First we need to fetch some icons that are needed for DrawPanel. + +.. GENERATED FROM PYTHON SOURCE LINES 16-19 + +.. code-block:: Python + + + fetch_viz_new_icons() + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + Dataset is already in place. If you want to fetch it again please first remove the folder /Users/skoudoro/.fury/icons/new_icons + + ({'circle-pressed.png': ('https://raw.githubusercontent.com/fury-gl/fury-data/master/icons/new_icons/circle-pressed.png', 'CD859F244DF1BA719C65C869C3FAF6B8563ABF82F457730ADBFBD7CA72DDB7BC'), 'circle.png': ('https://raw.githubusercontent.com/fury-gl/fury-data/master/icons/new_icons/circle.png', '5896BDC9FF9B3D1054134D7D9A854677CE9FA4E64F494F156BB2E3F0E863F207'), 'delete-pressed.png': ('https://raw.githubusercontent.com/fury-gl/fury-data/master/icons/new_icons/delete-pressed.png', '937C46C25BC38B62021B01C97A4EE3CDE5F7C8C4A6D0DB75BF4E4CACE2AF1226'), 'delete.png': ('https://raw.githubusercontent.com/fury-gl/fury-data/master/icons/new_icons/delete.png', '476E00A0A5373E1CCDA4AF8E7C9158E0AC9B46B540CE410C6EA47D97F364A0CD'), 'drawing-pressed.png': ('https://raw.githubusercontent.com/fury-gl/fury-data/master/icons/new_icons/drawing-pressed.png', '08A914C5DC7997CB944B8C5FBB958951F80B715CFE04FF4F47A73F9D08C4B14B'), 'drawing.png': ('https://raw.githubusercontent.com/fury-gl/fury-data/master/icons/new_icons/drawing.png', 'FB2210B0393ECA8A5DD2B8F034DAE386BBB47EB95BB1CAC2A97DE807EE195ADF'), 'line-pressed.png': ('https://raw.githubusercontent.com/fury-gl/fury-data/master/icons/new_icons/line-pressed.png', '8D1AC2BB7C5BAA34E68578DAAD85F64EF824BE7BCB828CAC18E52833D4CBF4C9'), 'line.png': ('https://raw.githubusercontent.com/fury-gl/fury-data/master/icons/new_icons/line.png', 'E6D833B6D958129E12FF0F6087282CE92CD43C6DAFCE03F185746ECCA89E42A9'), 'polyline-pressed.png': ('https://raw.githubusercontent.com/fury-gl/fury-data/master/icons/new_icons/polyline-pressed.png', 'CFF12B8DE48FC19DA5D5F0EA7FF2D23DD942D05468E19522E7C7BEB72F0FF66E'), 'polyline.png': ('https://raw.githubusercontent.com/fury-gl/fury-data/master/icons/new_icons/polyline.png', '7AFE65EBAE0C0D0556393B979148AE15FC3E037D126CD1DA4A296F4E25F5B4AA'), 'quad-pressed.png': ('https://raw.githubusercontent.com/fury-gl/fury-data/master/icons/new_icons/quad-pressed.png', '5FD43F1C2D37BF9AF05D9FC591172684AC51BA236980CD1B0795B0225B9247E2'), 'quad.png': ('https://raw.githubusercontent.com/fury-gl/fury-data/master/icons/new_icons/quad.png', 'A2DA0CB963401C174919E1D8028AA6F0CB260A736FD26421DB5AB08E9F3C4FDF'), 'resize-pressed.png': ('https://raw.githubusercontent.com/fury-gl/fury-data/master/icons/new_icons/resize-pressed.png', 'FF49DDF9DF24729F4F6345C30C88DE0A11E5B12B2F2FF28375EF9762FE5F8995'), 'resize.png': ('https://raw.githubusercontent.com/fury-gl/fury-data/master/icons/new_icons/resize.png', 'A2D850CDBA8F332DA9CD7B7C9459CBDA587C18AF0D3C12CA68D6E6A864EF54BB'), 'selection-pressed.png': ('https://raw.githubusercontent.com/fury-gl/fury-data/master/icons/new_icons/selection-pressed.png', '54618FDC4589F0A039D531C07A110ED9BC57A256BB15A3B5429CF60E950887C3'), 'selection.png': ('https://raw.githubusercontent.com/fury-gl/fury-data/master/icons/new_icons/selection.png', 'CD573F5E4BF4A91A3B21F6124A95FFB3C036F926F8FEC1FD0180F5D27D8F48C0')}, '/Users/skoudoro/.fury/icons/new_icons') + + + +.. GENERATED FROM PYTHON SOURCE LINES 20-21 + +We then create a DrawPanel Object. + +.. GENERATED FROM PYTHON SOURCE LINES 21-24 + +.. code-block:: Python + + + drawing_canvas = ui.DrawPanel(size=(560, 560), position=(40, 10)) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 25-29 + +Show Manager +============ + +Now we add DrawPanel to the scene. + +.. GENERATED FROM PYTHON SOURCE LINES 29-46 + +.. code-block:: Python + + + current_size = (650, 650) + showm = window.ShowManager(size=current_size, title='DrawPanel UI Example') + + showm.scene.add(drawing_canvas) + + interactive = False + + if interactive: + showm.start() + else: + # If the UI isn't interactive, then adding a circle to the canvas + drawing_canvas.current_mode = 'circle' + drawing_canvas.draw_shape(shape_type='circle', current_position=(275, 275)) + drawing_canvas.shape_list[-1].resize((50, 50)) + + window.record(showm.scene, size=current_size, out_path='viz_drawpanel.png') + + + +.. image-sg:: /auto_examples/07_ui/images/sphx_glr_viz_drawpanel_001.png + :alt: viz drawpanel + :srcset: /auto_examples/07_ui/images/sphx_glr_viz_drawpanel_001.png + :class: sphx-glr-single-img + + + + + + +.. rst-class:: sphx-glr-timing + + **Total running time of the script:** (0 minutes 0.063 seconds) + + +.. _sphx_glr_download_auto_examples_07_ui_viz_drawpanel.py: + +.. only:: html + + .. container:: sphx-glr-footer sphx-glr-footer-example + + .. container:: sphx-glr-download sphx-glr-download-jupyter + + :download:`Download Jupyter notebook: viz_drawpanel.ipynb ` + + .. container:: sphx-glr-download sphx-glr-download-python + + :download:`Download Python source code: viz_drawpanel.py ` + + +.. only:: html + + .. rst-class:: sphx-glr-signature + + `Gallery generated by Sphinx-Gallery `_ diff --git a/v0.10.x/_sources/auto_examples/07_ui/viz_layout.rst.txt b/v0.10.x/_sources/auto_examples/07_ui/viz_layout.rst.txt new file mode 100644 index 000000000..235580a7b --- /dev/null +++ b/v0.10.x/_sources/auto_examples/07_ui/viz_layout.rst.txt @@ -0,0 +1,189 @@ + +.. DO NOT EDIT. +.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. +.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: +.. "auto_examples/07_ui/viz_layout.py" +.. LINE NUMBERS ARE GIVEN BELOW. + +.. only:: html + + .. note:: + :class: sphx-glr-download-link-note + + :ref:`Go to the end ` + to download the full example code + +.. rst-class:: sphx-glr-example-title + +.. _sphx_glr_auto_examples_07_ui_viz_layout.py: + + +======================================== +Using Layouts with different UI elements +======================================== + +This example shows how to place different UI elements in different Layouts. +The Layouts used here is GridLayout (with different cell shapes). + +First, some imports. + +.. GENERATED FROM PYTHON SOURCE LINES 11-15 + +.. code-block:: Python + + + from fury import ui, window + from fury.layout import GridLayout + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 16-19 + +We create some panels and then we arrange them in a grid fashion + +First, we create some panels with different sizes/positions + +.. GENERATED FROM PYTHON SOURCE LINES 19-24 + +.. code-block:: Python + + + panel_1 = ui.Panel2D(size=(200, 200), color=(0.4, 0.6, 0.3), position=(100, 100)) + + panel_2 = ui.Panel2D(size=(250, 250), color=(0.8, 0.3, 0.5), position=(150, 150)) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 25-26 + +Now we create two listboxes + +.. GENERATED FROM PYTHON SOURCE LINES 26-31 + +.. code-block:: Python + + + listbox_1 = ui.ListBox2D(size=(150, 150), values=['First', 'Second', 'Third']) + + listbox_2 = ui.ListBox2D(size=(250, 250), values=['First', 'Second', 'Third']) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 32-33 + +Now we create two different UI i.e. a slider and a listbox + +.. GENERATED FROM PYTHON SOURCE LINES 33-37 + +.. code-block:: Python + + + slider = ui.LineSlider2D(length=150) + listbox = ui.ListBox2D(size=(150, 150), values=['First', 'Second', 'Third']) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 38-39 + +Now, we create grids with different shapes + +.. GENERATED FROM PYTHON SOURCE LINES 39-45 + +.. code-block:: Python + + + rect_grid = GridLayout(position_offset=(0, 0, 0)) + square_grid = GridLayout(cell_shape='square', position_offset=(0, 300, 0)) + diagonal_grid = GridLayout(cell_shape='diagonal', position_offset=(0, 600, 0)) + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 46-47 + +Applying the grid to the ui elements + +.. GENERATED FROM PYTHON SOURCE LINES 47-64 + +.. code-block:: Python + + + rect_grid.apply([panel_1, panel_2]) + square_grid.apply([listbox_1, listbox_2]) + diagonal_grid.apply([slider, listbox]) + + current_size = (1500, 1500) + show_manager = window.ShowManager(size=current_size, title='FURY UI Layout') + + show_manager.scene.add(panel_1, panel_2, listbox_1, listbox_2, slider, listbox) + + # To interact with the UI, set interactive = True + interactive = False + + if interactive: + show_manager.start() + + window.record(show_manager.scene, out_path='ui_layout.png', size=(400, 400)) + + + +.. image-sg:: /auto_examples/07_ui/images/sphx_glr_viz_layout_001.png + :alt: viz layout + :srcset: /auto_examples/07_ui/images/sphx_glr_viz_layout_001.png + :class: sphx-glr-single-img + + + + + + +.. rst-class:: sphx-glr-timing + + **Total running time of the script:** (0 minutes 0.059 seconds) + + +.. _sphx_glr_download_auto_examples_07_ui_viz_layout.py: + +.. only:: html + + .. container:: sphx-glr-footer sphx-glr-footer-example + + .. container:: sphx-glr-download sphx-glr-download-jupyter + + :download:`Download Jupyter notebook: viz_layout.ipynb ` + + .. container:: sphx-glr-download sphx-glr-download-python + + :download:`Download Python source code: viz_layout.py ` + + +.. only:: html + + .. rst-class:: sphx-glr-signature + + `Gallery generated by Sphinx-Gallery `_ diff --git a/v0.10.x/_sources/auto_examples/07_ui/viz_radio_buttons.rst.txt b/v0.10.x/_sources/auto_examples/07_ui/viz_radio_buttons.rst.txt new file mode 100644 index 000000000..93df0425f --- /dev/null +++ b/v0.10.x/_sources/auto_examples/07_ui/viz_radio_buttons.rst.txt @@ -0,0 +1,206 @@ + +.. DO NOT EDIT. +.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. +.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: +.. "auto_examples/07_ui/viz_radio_buttons.py" +.. LINE NUMBERS ARE GIVEN BELOW. + +.. only:: html + + .. note:: + :class: sphx-glr-download-link-note + + :ref:`Go to the end ` + to download the full example code + +.. rst-class:: sphx-glr-example-title + +.. _sphx_glr_auto_examples_07_ui_viz_radio_buttons.py: + + +======================================== +Sphere Color Control using Radio Buttons +======================================== + +This example shows how to use the UI API. We will demonstrate how to +create a Sphere and control its color using radio buttons. + +First, some imports. + +.. GENERATED FROM PYTHON SOURCE LINES 11-17 + +.. code-block:: Python + + + import numpy as np + + from fury import actor, ui, utils, window + from fury.data import fetch_viz_icons + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 18-19 + +First we need to fetch some icons that are included in FURY. + +.. GENERATED FROM PYTHON SOURCE LINES 19-22 + +.. code-block:: Python + + + fetch_viz_icons() + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + Data size is approximately 12KB + Dataset is already in place. If you want to fetch it again please first remove the folder /Users/skoudoro/.fury/icons + + ({'icomoon.tar.gz': ('https://digital.lib.washington.edu/researchworks/bitstream/handle/1773/38478/icomoon.tar.gz', 'BC1FEEA6F58BA3601D6A0B029EB8DFC5F352E21F2A16BA41099A96AA3F5A4735')}, '/Users/skoudoro/.fury/icons') + + + +.. GENERATED FROM PYTHON SOURCE LINES 23-27 + +Sphere and Radio Buttons +======================== + +Add a Sphere to the scene. + +.. GENERATED FROM PYTHON SOURCE LINES 27-60 + +.. code-block:: Python + + + sphere = actor.sphere( + centers=np.array([[50, 0, 0]]), + colors=np.array([[0, 0, 1]]), + radii=11.0, + theta=360, + phi=360, + ) + + # Creating a dict of possible options and mapping it with their values. + options = {'Blue': (0, 0, 255), 'Red': (255, 0, 0), 'Green': (0, 255, 0)} + + color_toggler = ui.RadioButton( + list(options), + checked_labels=['Blue'], + padding=1, + font_size=16, + font_family='Arial', + position=(200, 200), + ) + + + # A callback which will set the values for the box + def toggle_color(radio): + vcolors = utils.colors_from_actor(sphere) + color = options[radio.checked_labels[0]] + vcolors[:] = np.array(color) + utils.update_actor(sphere) + + + color_toggler.on_change = toggle_color + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 61-66 + +Show Manager +============ + +Now that all the elements have been initialised, we add them to the show +manager. + +.. GENERATED FROM PYTHON SOURCE LINES 66-73 + +.. code-block:: Python + + + current_size = (800, 800) + show_manager = window.ShowManager(size=current_size, title='FURY Sphere Example') + + show_manager.scene.add(sphere) + show_manager.scene.add(color_toggler) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 74-75 + +Set camera for better visualization + +.. GENERATED FROM PYTHON SOURCE LINES 75-86 + +.. code-block:: Python + + + show_manager.scene.reset_camera() + show_manager.scene.set_camera(position=(0, 0, 150)) + show_manager.scene.reset_clipping_range() + show_manager.scene.azimuth(30) + interactive = False + + if interactive: + show_manager.start() + + window.record(show_manager.scene, size=current_size, out_path='viz_radio_buttons.png') + + + +.. image-sg:: /auto_examples/07_ui/images/sphx_glr_viz_radio_buttons_001.png + :alt: viz radio buttons + :srcset: /auto_examples/07_ui/images/sphx_glr_viz_radio_buttons_001.png + :class: sphx-glr-single-img + + + + + + +.. rst-class:: sphx-glr-timing + + **Total running time of the script:** (0 minutes 0.121 seconds) + + +.. _sphx_glr_download_auto_examples_07_ui_viz_radio_buttons.py: + +.. only:: html + + .. container:: sphx-glr-footer sphx-glr-footer-example + + .. container:: sphx-glr-download sphx-glr-download-jupyter + + :download:`Download Jupyter notebook: viz_radio_buttons.ipynb ` + + .. container:: sphx-glr-download sphx-glr-download-python + + :download:`Download Python source code: viz_radio_buttons.py ` + + +.. only:: html + + .. rst-class:: sphx-glr-signature + + `Gallery generated by Sphinx-Gallery `_ diff --git a/v0.10.x/_sources/auto_examples/07_ui/viz_shapes.rst.txt b/v0.10.x/_sources/auto_examples/07_ui/viz_shapes.rst.txt new file mode 100644 index 000000000..fc56d06d6 --- /dev/null +++ b/v0.10.x/_sources/auto_examples/07_ui/viz_shapes.rst.txt @@ -0,0 +1,186 @@ + +.. DO NOT EDIT. +.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. +.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: +.. "auto_examples/07_ui/viz_shapes.py" +.. LINE NUMBERS ARE GIVEN BELOW. + +.. only:: html + + .. note:: + :class: sphx-glr-download-link-note + + :ref:`Go to the end ` + to download the full example code + +.. rst-class:: sphx-glr-example-title + +.. _sphx_glr_auto_examples_07_ui_viz_shapes.py: + + +============== +Simple Shapes +============== + +This example shows how to use the UI API. We will demonstrate how to draw +some geometric shapes from FURY UI elements. + +First, a bunch of imports. + +.. GENERATED FROM PYTHON SOURCE LINES 12-16 + +.. code-block:: Python + + + from fury import ui, window + from fury.data import fetch_viz_icons + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 17-18 + +First we need to fetch some icons that are included in FURY. + +.. GENERATED FROM PYTHON SOURCE LINES 18-21 + +.. code-block:: Python + + + fetch_viz_icons() + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + Data size is approximately 12KB + Dataset is already in place. If you want to fetch it again please first remove the folder /Users/skoudoro/.fury/icons + + ({'icomoon.tar.gz': ('https://digital.lib.washington.edu/researchworks/bitstream/handle/1773/38478/icomoon.tar.gz', 'BC1FEEA6F58BA3601D6A0B029EB8DFC5F352E21F2A16BA41099A96AA3F5A4735')}, '/Users/skoudoro/.fury/icons') + + + +.. GENERATED FROM PYTHON SOURCE LINES 22-23 + +Let's draw some simple shapes. First, a rectangle. + +.. GENERATED FROM PYTHON SOURCE LINES 23-26 + +.. code-block:: Python + + + rect = ui.Rectangle2D(size=(100, 100), position=(400, 400), color=(1, 0, 1)) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 27-28 + +Then we can draw a solid circle, or disk. + +.. GENERATED FROM PYTHON SOURCE LINES 28-31 + +.. code-block:: Python + + + disk = ui.Disk2D(outer_radius=50, center=(400, 200), color=(1, 1, 0)) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 32-33 + +Add an inner radius to make a ring. + +.. GENERATED FROM PYTHON SOURCE LINES 33-37 + +.. code-block:: Python + + + ring = ui.Disk2D(outer_radius=50, inner_radius=45, center=(500, 600), color=(0, 1, 1)) + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 38-40 + +Now that all the elements have been initialised, we add them to the show +manager. + +.. GENERATED FROM PYTHON SOURCE LINES 40-54 + +.. code-block:: Python + + + current_size = (800, 800) + show_manager = window.ShowManager(size=current_size, title='FURY Shapes Example') + + show_manager.scene.add(rect) + show_manager.scene.add(disk) + show_manager.scene.add(ring) + + interactive = False + + if interactive: + show_manager.start() + + window.record(show_manager.scene, size=current_size, out_path='viz_shapes.png') + + + +.. image-sg:: /auto_examples/07_ui/images/sphx_glr_viz_shapes_001.png + :alt: viz shapes + :srcset: /auto_examples/07_ui/images/sphx_glr_viz_shapes_001.png + :class: sphx-glr-single-img + + + + + + +.. rst-class:: sphx-glr-timing + + **Total running time of the script:** (0 minutes 0.068 seconds) + + +.. _sphx_glr_download_auto_examples_07_ui_viz_shapes.py: + +.. only:: html + + .. container:: sphx-glr-footer sphx-glr-footer-example + + .. container:: sphx-glr-download sphx-glr-download-jupyter + + :download:`Download Jupyter notebook: viz_shapes.ipynb ` + + .. container:: sphx-glr-download sphx-glr-download-python + + :download:`Download Python source code: viz_shapes.py ` + + +.. only:: html + + .. rst-class:: sphx-glr-signature + + `Gallery generated by Sphinx-Gallery `_ diff --git a/v0.10.x/_sources/auto_examples/07_ui/viz_spinbox.rst.txt b/v0.10.x/_sources/auto_examples/07_ui/viz_spinbox.rst.txt new file mode 100644 index 000000000..523668309 --- /dev/null +++ b/v0.10.x/_sources/auto_examples/07_ui/viz_spinbox.rst.txt @@ -0,0 +1,216 @@ + +.. DO NOT EDIT. +.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. +.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: +.. "auto_examples/07_ui/viz_spinbox.py" +.. LINE NUMBERS ARE GIVEN BELOW. + +.. only:: html + + .. note:: + :class: sphx-glr-download-link-note + + :ref:`Go to the end ` + to download the full example code + +.. rst-class:: sphx-glr-example-title + +.. _sphx_glr_auto_examples_07_ui_viz_spinbox.py: + + +=========== +SpinBox UI +=========== + +This example shows how to use the UI API. We will demonstrate how to create +a SpinBox UI. + +First, some imports. + +.. GENERATED FROM PYTHON SOURCE LINES 12-16 + +.. code-block:: Python + + from fury import actor, ui, utils, window + from fury.data import fetch_viz_icons + import numpy as np + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 17-18 + +First we need to fetch some icons that are included in FURY. + +.. GENERATED FROM PYTHON SOURCE LINES 18-21 + +.. code-block:: Python + + + fetch_viz_icons() + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + Data size is approximately 12KB + Dataset is already in place. If you want to fetch it again please first remove the folder /Users/skoudoro/.fury/icons + + ({'icomoon.tar.gz': ('https://digital.lib.washington.edu/researchworks/bitstream/handle/1773/38478/icomoon.tar.gz', 'BC1FEEA6F58BA3601D6A0B029EB8DFC5F352E21F2A16BA41099A96AA3F5A4735')}, '/Users/skoudoro/.fury/icons') + + + +.. GENERATED FROM PYTHON SOURCE LINES 22-23 + +Let's create a Cone. + +.. GENERATED FROM PYTHON SOURCE LINES 23-28 + +.. code-block:: Python + + + cone = actor.cone(centers=np.random.rand(1, 3), + directions=np.random.rand(1, 3), + colors=(1, 1, 1), heights=np.random.rand(1)) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 29-30 + +Creating the SpinBox UI. + +.. GENERATED FROM PYTHON SOURCE LINES 30-34 + +.. code-block:: Python + + + spinbox = ui.SpinBox(position=(200, 100), size=(300, 100), min_val=0, + max_val=360, initial_val=180, step=10) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 35-37 + +Now that all the elements have been initialised, we add them to the show +manager. + +.. GENERATED FROM PYTHON SOURCE LINES 37-45 + +.. code-block:: Python + + + current_size = (800, 800) + show_manager = window.ShowManager(size=current_size, + title="FURY SpinBox Example") + + show_manager.scene.add(cone) + show_manager.scene.add(spinbox) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 46-47 + +Using the on_change hook to rotate the cone. + +.. GENERATED FROM PYTHON SOURCE LINES 47-61 + +.. code-block:: Python + + + # Tracking previous value to check in/decrement. + previous_value = spinbox.value + + + def rotate_cone(spinbox): + global previous_value + change_in_value = spinbox.value - previous_value + utils.rotate(cone, (change_in_value, 1, 0, 0)) + previous_value = spinbox.value + + + spinbox.on_change = rotate_cone + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 62-63 + +Starting the ShowManager. + +.. GENERATED FROM PYTHON SOURCE LINES 63-71 + +.. code-block:: Python + + + interactive = False + + if interactive: + show_manager.start() + + window.record(show_manager.scene, size=current_size, + out_path="viz_spinbox.png") + + + +.. image-sg:: /auto_examples/07_ui/images/sphx_glr_viz_spinbox_001.png + :alt: viz spinbox + :srcset: /auto_examples/07_ui/images/sphx_glr_viz_spinbox_001.png + :class: sphx-glr-single-img + + + + + + +.. rst-class:: sphx-glr-timing + + **Total running time of the script:** (0 minutes 0.083 seconds) + + +.. _sphx_glr_download_auto_examples_07_ui_viz_spinbox.py: + +.. only:: html + + .. container:: sphx-glr-footer sphx-glr-footer-example + + .. container:: sphx-glr-download sphx-glr-download-jupyter + + :download:`Download Jupyter notebook: viz_spinbox.ipynb ` + + .. container:: sphx-glr-download sphx-glr-download-python + + :download:`Download Python source code: viz_spinbox.py ` + + +.. only:: html + + .. rst-class:: sphx-glr-signature + + `Gallery generated by Sphinx-Gallery `_ diff --git a/v0.10.x/_sources/auto_examples/07_ui/viz_tab.rst.txt b/v0.10.x/_sources/auto_examples/07_ui/viz_tab.rst.txt new file mode 100644 index 000000000..e8dc1c7df --- /dev/null +++ b/v0.10.x/_sources/auto_examples/07_ui/viz_tab.rst.txt @@ -0,0 +1,432 @@ + +.. DO NOT EDIT. +.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. +.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: +.. "auto_examples/07_ui/viz_tab.py" +.. LINE NUMBERS ARE GIVEN BELOW. + +.. only:: html + + .. note:: + :class: sphx-glr-download-link-note + + :ref:`Go to the end ` + to download the full example code + +.. rst-class:: sphx-glr-example-title + +.. _sphx_glr_auto_examples_07_ui_viz_tab.py: + + +======== +Tab UI +======== + +This example shows how to use the Tab UI. We will demonstrate how to +create Tabs for: + +1. Slider controls for a Cube +2. Checkboxes for Cylinder and Sphere +3. Color combobox for Fury. + +First, some imports. + +.. GENERATED FROM PYTHON SOURCE LINES 15-20 + +.. code-block:: Python + + import numpy as np + + from fury import actor, ui, window + from fury.data import fetch_viz_icons + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 21-22 + +First we need to fetch some icons that are included in FURY. + +.. GENERATED FROM PYTHON SOURCE LINES 22-25 + +.. code-block:: Python + + + fetch_viz_icons() + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + Data size is approximately 12KB + Dataset is already in place. If you want to fetch it again please first remove the folder /Users/skoudoro/.fury/icons + + ({'icomoon.tar.gz': ('https://digital.lib.washington.edu/researchworks/bitstream/handle/1773/38478/icomoon.tar.gz', 'BC1FEEA6F58BA3601D6A0B029EB8DFC5F352E21F2A16BA41099A96AA3F5A4735')}, '/Users/skoudoro/.fury/icons') + + + +.. GENERATED FROM PYTHON SOURCE LINES 26-27 + +First, we create the Tab UI. + +.. GENERATED FROM PYTHON SOURCE LINES 27-30 + +.. code-block:: Python + + + tab_ui = ui.TabUI(position=(49, 94), size=(300, 300), nb_tabs=3, draggable=True) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 31-35 + +Slider Controls for a Cube for Tab Index 0 +========================================== + +Now we prepare content for the first tab. + +.. GENERATED FROM PYTHON SOURCE LINES 35-87 + +.. code-block:: Python + + + ring_slider = ui.RingSlider2D(initial_value=0, text_template='{angle:5.1f}°') + + line_slider_x = ui.LineSlider2D( + initial_value=0, + min_value=-10, + max_value=10, + orientation='horizontal', + text_alignment='Top', + ) + + line_slider_y = ui.LineSlider2D( + initial_value=0, + min_value=-10, + max_value=10, + orientation='vertical', + text_alignment='Right', + ) + + cube = actor.box( + centers=np.array([[10, 0, 0]]), + directions=np.array([[0, 1, 0]]), + colors=np.array([[0, 0, 1]]), + scales=np.array([[1, 1, 1]]), + ) + cube_x = 0 + cube_y = 0 + + + def rotate_cube(slider): + angle = slider.value + previous_angle = slider.previous_value + rotation_angle = angle - previous_angle + cube.RotateX(rotation_angle) + + + def translate_cube_x(slider): + global cube_x, cube_y + cube_x = slider.value + cube.SetPosition(cube_x, cube_y, 0) + + + def translate_cube_y(slider): + global cube_x, cube_y + cube_y = slider.value + cube.SetPosition(cube_x, cube_y, 0) + + + ring_slider.on_change = rotate_cube + line_slider_x.on_change = translate_cube_x + line_slider_y.on_change = translate_cube_y + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 88-89 + +After defining content, we define properties for the tab. + +.. GENERATED FROM PYTHON SOURCE LINES 89-95 + +.. code-block:: Python + + + tab_ui.tabs[0].title = 'Sliders' + tab_ui.add_element(0, ring_slider, (0.3, 0.3)) + tab_ui.add_element(0, line_slider_x, (0.0, 0.0)) + tab_ui.add_element(0, line_slider_y, (0.0, 0.1)) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 96-100 + +CheckBoxes For Cylinder and Sphere for Tab Index 1 +================================================== + +Now we prepare content for second tab. + +.. GENERATED FROM PYTHON SOURCE LINES 100-133 + +.. code-block:: Python + + + cylinder = actor.cylinder( + centers=np.array([[0, 0, 0]]), + directions=np.array([[1, 1, 0]]), + colors=np.array([[0, 1, 1]]), + radius=1.0, + ) + + sphere = actor.sphere(centers=np.array([[5, 0, 0]]), colors=(1, 1, 0)) + + figure_dict = {'cylinder': cylinder, 'sphere': sphere} + checkbox = ui.Checkbox(labels=['cylinder', 'sphere']) + + + # Get difference between two lists. + def sym_diff(l1, l2): + return list(set(l1).symmetric_difference(set(l2))) + + + # Set Visibility of the figures + def set_figure_visiblity(checkboxes): + checked = checkboxes.checked_labels + unchecked = sym_diff(list(figure_dict), checked) + + for visible in checked: + figure_dict[visible].SetVisibility(True) + + for invisible in unchecked: + figure_dict[invisible].SetVisibility(False) + + + checkbox.on_change = set_figure_visiblity + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 134-135 + +After defining content, we define properties for the tab. + +.. GENERATED FROM PYTHON SOURCE LINES 135-139 + +.. code-block:: Python + + + tab_ui.tabs[1].title = 'Checkbox' + tab_ui.add_element(1, checkbox, (0.2, 0.2)) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 140-144 + +Color Combobox for Fury for Tab Index 2 +======================================= + +Now we prepare content for third tab. + +.. GENERATED FROM PYTHON SOURCE LINES 144-178 + +.. code-block:: Python + + + label = ui.TextBlock2D( + position=(600, 300), + font_size=40, + color=(1, 0.5, 0), + justification='center', + vertical_justification='top', + text='FURY rocks!!!', + ) + + colors = { + 'Violet': (0.6, 0, 0.8), + 'Indigo': (0.3, 0, 0.5), + 'Blue': (0, 0, 1), + 'Green': (0, 1, 0), + 'Yellow': (1, 1, 0), + 'Orange': (1, 0.5, 0), + 'Red': (1, 0, 0), + } + + color_combobox = ui.ComboBox2D( + items=list(colors.keys()), + placeholder='Choose Text Color', + size=(250, 150), + draggable=True, + ) + + + def change_color(combobox): + label.color = colors[combobox.selected_text] + + + color_combobox.on_change = change_color + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 179-180 + +After defining content, we define properties for the tab. + +.. GENERATED FROM PYTHON SOURCE LINES 180-184 + +.. code-block:: Python + + + tab_ui.tabs[2].title = 'Colors' + tab_ui.add_element(2, color_combobox, (0.1, 0.3)) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 185-188 + +Define on_change & on_collapsed methods for tab ui to perform certain tasks +while active tab is changed or when the tab is collapsed. +Note: Tab UI can be collapsed by right clicking on it. + +.. GENERATED FROM PYTHON SOURCE LINES 188-221 + +.. code-block:: Python + + + + def hide_actors(tab_ui): + if tab_ui.tabs[tab_ui.active_tab_idx].title == 'Sliders': + cube.SetVisibility(True) + cylinder.SetVisibility(False) + sphere.SetVisibility(False) + label.set_visibility(False) + + elif tab_ui.tabs[tab_ui.active_tab_idx].title == 'Checkbox': + cube.SetVisibility(False) + set_figure_visiblity(checkbox) + label.set_visibility(False) + + else: + cube.SetVisibility(False) + cylinder.SetVisibility(False) + sphere.SetVisibility(False) + label.set_visibility(True) + + + def collapse(tab_ui): + if tab_ui.collapsed: + cube.SetVisibility(False) + cylinder.SetVisibility(False) + sphere.SetVisibility(False) + label.set_visibility(False) + + + tab_ui.on_change = hide_actors + tab_ui.on_collapse = collapse + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 222-223 + +Next we prepare the scene and render it with the help of show manager. + +.. GENERATED FROM PYTHON SOURCE LINES 223-234 + +.. code-block:: Python + + + sm = window.ShowManager(size=(800, 500), title='Viz Tab') + sm.scene.add(tab_ui, cube, cylinder, sphere, label) + + # To interact with the ui set interactive = True + interactive = False + + if interactive: + sm.start() + + window.record(sm.scene, size=(500, 500), out_path='viz_tab.png') + + + +.. image-sg:: /auto_examples/07_ui/images/sphx_glr_viz_tab_001.png + :alt: viz tab + :srcset: /auto_examples/07_ui/images/sphx_glr_viz_tab_001.png + :class: sphx-glr-single-img + + + + + + +.. rst-class:: sphx-glr-timing + + **Total running time of the script:** (0 minutes 0.071 seconds) + + +.. _sphx_glr_download_auto_examples_07_ui_viz_tab.py: + +.. only:: html + + .. container:: sphx-glr-footer sphx-glr-footer-example + + .. container:: sphx-glr-download sphx-glr-download-jupyter + + :download:`Download Jupyter notebook: viz_tab.ipynb ` + + .. container:: sphx-glr-download sphx-glr-download-python + + :download:`Download Python source code: viz_tab.py ` + + +.. only:: html + + .. rst-class:: sphx-glr-signature + + `Gallery generated by Sphinx-Gallery `_ diff --git a/v0.10.x/_sources/auto_examples/07_ui/viz_ui.rst.txt b/v0.10.x/_sources/auto_examples/07_ui/viz_ui.rst.txt new file mode 100644 index 000000000..eb4e4830e --- /dev/null +++ b/v0.10.x/_sources/auto_examples/07_ui/viz_ui.rst.txt @@ -0,0 +1,640 @@ + +.. DO NOT EDIT. +.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. +.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: +.. "auto_examples/07_ui/viz_ui.py" +.. LINE NUMBERS ARE GIVEN BELOW. + +.. only:: html + + .. note:: + :class: sphx-glr-download-link-note + + :ref:`Go to the end ` + to download the full example code + +.. rst-class:: sphx-glr-example-title + +.. _sphx_glr_auto_examples_07_ui_viz_ui.py: + + +=============== +User Interfaces +=============== + +This example shows how to use the UI API. We will demonstrate how to create +several FURY UI elements, then use a list box to toggle which element is shown. + +First, a bunch of imports. + +.. GENERATED FROM PYTHON SOURCE LINES 12-18 + +.. code-block:: Python + + + import numpy as np + + from fury import actor, ui, window + from fury.data import fetch_viz_icons, read_viz_icons + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 19-23 + +Shapes +====== + +Let's start by drawing some simple shapes. First, a rectangle. + +.. GENERATED FROM PYTHON SOURCE LINES 23-26 + +.. code-block:: Python + + + rect = ui.Rectangle2D(size=(200, 200), position=(400, 300), color=(1, 0, 1)) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 27-28 + +Then we can draw a solid circle, or disk. + +.. GENERATED FROM PYTHON SOURCE LINES 28-31 + +.. code-block:: Python + + + disk = ui.Disk2D(outer_radius=50, center=(500, 500), color=(1, 1, 0)) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 32-33 + +Add an inner radius to make a ring. + +.. GENERATED FROM PYTHON SOURCE LINES 33-36 + +.. code-block:: Python + + + ring = ui.Disk2D(outer_radius=50, inner_radius=45, center=(500, 300), color=(0, 1, 1)) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 37-42 + +Image +===== + +Now let's display an image. First we need to fetch some icons that are +included in FURY. + +.. GENERATED FROM PYTHON SOURCE LINES 42-45 + +.. code-block:: Python + + + fetch_viz_icons() + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + Data size is approximately 12KB + Dataset is already in place. If you want to fetch it again please first remove the folder /Users/skoudoro/.fury/icons + + ({'icomoon.tar.gz': ('https://digital.lib.washington.edu/researchworks/bitstream/handle/1773/38478/icomoon.tar.gz', 'BC1FEEA6F58BA3601D6A0B029EB8DFC5F352E21F2A16BA41099A96AA3F5A4735')}, '/Users/skoudoro/.fury/icons') + + + +.. GENERATED FROM PYTHON SOURCE LINES 46-47 + +Now we can create an image container. + +.. GENERATED FROM PYTHON SOURCE LINES 47-52 + +.. code-block:: Python + + + img = ui.ImageContainer2D( + img_path=read_viz_icons(fname='home3.png'), position=(450, 350) + ) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 53-58 + +Panel with buttons and text +=========================== + +Let's create some buttons and text and put them in a panel. First we'll +make the panel. + +.. GENERATED FROM PYTHON SOURCE LINES 58-62 + +.. code-block:: Python + + + panel = ui.Panel2D(size=(300, 150), color=(1, 1, 1), align='right') + panel.center = (500, 400) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 63-65 + +Then we'll make two text labels and place them on the panel. +Note that we specify the position with integer numbers of pixels. + +.. GENERATED FROM PYTHON SOURCE LINES 65-71 + +.. code-block:: Python + + + text = ui.TextBlock2D(text='Click me') + text2 = ui.TextBlock2D(text='Me too') + panel.add_element(text, (50, 100)) + panel.add_element(text2, (180, 100)) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 72-76 + +Then we'll create two buttons and add them to the panel. + +Note that here we specify the positions with floats. In this case, these are +percentages of the panel size. + +.. GENERATED FROM PYTHON SOURCE LINES 76-93 + +.. code-block:: Python + + + + button_example = ui.Button2D( + icon_fnames=[('square', read_viz_icons(fname='stop2.png'))] + ) + + icon_files = [] + icon_files.append(('down', read_viz_icons(fname='circle-down.png'))) + icon_files.append(('left', read_viz_icons(fname='circle-left.png'))) + icon_files.append(('up', read_viz_icons(fname='circle-up.png'))) + icon_files.append(('right', read_viz_icons(fname='circle-right.png'))) + + second_button_example = ui.Button2D(icon_fnames=icon_files) + + panel.add_element(button_example, (0.25, 0.33)) + panel.add_element(second_button_example, (0.66, 0.33)) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 94-95 + +We can add a callback to each button to perform some action. + +.. GENERATED FROM PYTHON SOURCE LINES 95-110 + +.. code-block:: Python + + + + def change_text_callback(i_ren, _obj, _button): + text.message = 'Clicked!' + i_ren.force_render() + + + def change_icon_callback(i_ren, _obj, _button): + _button.next_icon() + i_ren.force_render() + + + button_example.on_left_mouse_button_clicked = change_text_callback + second_button_example.on_left_mouse_button_pressed = change_icon_callback + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 111-115 + +Cube and sliders +================ + +Let's add a cube to the scene and control it with sliders. + +.. GENERATED FROM PYTHON SOURCE LINES 115-124 + +.. code-block:: Python + + + + cube = actor.cube( + centers=np.array([[15, 0, 0]]), + colors=np.array([[0, 0, 1]]), + scales=np.array([[20, 20, 20]]), + directions=np.array([[0, 0, 1]]), + ) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 125-126 + +Now we'll add three sliders: one circular and two linear. + +.. GENERATED FROM PYTHON SOURCE LINES 126-147 + +.. code-block:: Python + + + ring_slider = ui.RingSlider2D( + center=(740, 400), initial_value=0, text_template='{angle:5.1f}°' + ) + + line_slider_x = ui.LineSlider2D( + center=(500, 250), + initial_value=0, + min_value=-10, + max_value=10, + orientation='horizontal', + ) + + line_slider_y = ui.LineSlider2D( + center=(650, 350), + initial_value=0, + min_value=-10, + max_value=10, + orientation='vertical', + ) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 148-149 + +We can use a callback to rotate the cube with the ring slider. + +.. GENERATED FROM PYTHON SOURCE LINES 149-160 + +.. code-block:: Python + + + + def rotate_cube(slider): + angle = slider.value + previous_angle = slider.previous_value + rotation_angle = angle - previous_angle + cube.RotateX(rotation_angle) + + + ring_slider.on_change = rotate_cube + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 161-163 + +Similarly, we can translate the cube with line sliders. +We use global variables to keep track of the position of the cube. + +.. GENERATED FROM PYTHON SOURCE LINES 163-183 + +.. code-block:: Python + + + cube_x = 0 + cube_y = 0 + + + def translate_cube_x(slider): + global cube_x, cube_y + cube_x = slider.value + cube.SetPosition(cube_x, cube_y, 0) + + + def translate_cube_y(slider): + global cube_x, cube_y + cube_y = slider.value + cube.SetPosition(cube_x, cube_y, 0) + + + line_slider_x.on_change = translate_cube_x + line_slider_y.on_change = translate_cube_y + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 184-189 + +Range Slider +============ + +Finally, we can add a range slider. This element is composed of two sliders. +The first slider has two handles which let you set the range of the second. + +.. GENERATED FROM PYTHON SOURCE LINES 189-218 + +.. code-block:: Python + + + range_slider_x = ui.RangeSlider( + line_width=8, + handle_side=25, + range_slider_center=(450, 450), + value_slider_center=(450, 350), + length=150, + min_value=0, + max_value=10, + font_size=18, + range_precision=2, + value_precision=4, + shape='square', + ) + + range_slider_y = ui.RangeSlider( + line_width=8, + handle_side=25, + range_slider_center=(750, 400), + value_slider_center=(650, 400), + length=150, + min_value=0, + max_value=10, + font_size=18, + range_precision=2, + value_precision=4, + orientation='vertical', + shape='square', + ) + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 219-226 + +Select menu +============ + +We just added many examples. If we showed them all at once, they would fill +the screen. Let's make a simple menu to choose which example is shown. + +We'll first make a list of the examples. + +.. GENERATED FROM PYTHON SOURCE LINES 226-236 + +.. code-block:: Python + + + examples = [ + [rect], + [disk, ring], + [img], + [panel], + [ring_slider, line_slider_x, line_slider_y], + [range_slider_x, range_slider_y], + ] + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 237-239 + +Now we'll make a function to hide all the examples. Then we'll call it so +that none are shown initially. + +.. GENERATED FROM PYTHON SOURCE LINES 239-250 + +.. code-block:: Python + + + + def hide_all_examples(): + for example in examples: + for element in example: + element.set_visibility(False) + cube.SetVisibility(False) + + + hide_all_examples() + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 251-253 + +To make the menu, we'll first need to create a list of labels which +correspond with the examples. + +.. GENERATED FROM PYTHON SOURCE LINES 253-263 + +.. code-block:: Python + + + values = [ + 'Rectangle', + 'Disks', + 'Image', + 'Button Panel', + 'Line & Ring Slider', + 'Range Slider', + ] + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 264-265 + +Now we can create the menu. + +.. GENERATED FROM PYTHON SOURCE LINES 265-270 + +.. code-block:: Python + + + listbox = ui.ListBox2D( + values=values, position=(10, 300), size=(300, 200), multiselection=False + ) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 271-273 + +Then we will use a callback to show the correct example when a label is +clicked. + +.. GENERATED FROM PYTHON SOURCE LINES 273-286 + +.. code-block:: Python + + + + def display_element(): + hide_all_examples() + example = examples[values.index(listbox.selected[0])] + for element in example: + element.set_visibility(True) + if values.index(listbox.selected[0]) == 4: + cube.SetVisibility(True) + + + listbox.on_change = display_element + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 287-292 + +Show Manager +================================== + +Now that all the elements have been initialised, we add them to the show +manager. + +.. GENERATED FROM PYTHON SOURCE LINES 292-313 + +.. code-block:: Python + + + current_size = (800, 800) + show_manager = window.ShowManager(size=current_size, title='FURY UI Example') + + show_manager.scene.add(listbox) + for example in examples: + for element in example: + show_manager.scene.add(element) + show_manager.scene.add(cube) + show_manager.scene.reset_camera() + show_manager.scene.set_camera(position=(0, 0, 200)) + show_manager.scene.reset_clipping_range() + show_manager.scene.azimuth(30) + + # To interact with the UI, set interactive = True + interactive = False + + if interactive: + show_manager.start() + + window.record(show_manager.scene, size=current_size, out_path='viz_ui.png') + + + +.. image-sg:: /auto_examples/07_ui/images/sphx_glr_viz_ui_001.png + :alt: viz ui + :srcset: /auto_examples/07_ui/images/sphx_glr_viz_ui_001.png + :class: sphx-glr-single-img + + + + + + +.. rst-class:: sphx-glr-timing + + **Total running time of the script:** (0 minutes 0.090 seconds) + + +.. _sphx_glr_download_auto_examples_07_ui_viz_ui.py: + +.. only:: html + + .. container:: sphx-glr-footer sphx-glr-footer-example + + .. container:: sphx-glr-download sphx-glr-download-jupyter + + :download:`Download Jupyter notebook: viz_ui.ipynb ` + + .. container:: sphx-glr-download sphx-glr-download-python + + :download:`Download Python source code: viz_ui.py ` + + +.. only:: html + + .. rst-class:: sphx-glr-signature + + `Gallery generated by Sphinx-Gallery `_ diff --git a/v0.10.x/_sources/auto_examples/07_ui/viz_ui_listbox.rst.txt b/v0.10.x/_sources/auto_examples/07_ui/viz_ui_listbox.rst.txt new file mode 100644 index 000000000..5c24dc939 --- /dev/null +++ b/v0.10.x/_sources/auto_examples/07_ui/viz_ui_listbox.rst.txt @@ -0,0 +1,223 @@ + +.. DO NOT EDIT. +.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. +.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: +.. "auto_examples/07_ui/viz_ui_listbox.py" +.. LINE NUMBERS ARE GIVEN BELOW. + +.. only:: html + + .. note:: + :class: sphx-glr-download-link-note + + :ref:`Go to the end ` + to download the full example code + +.. rst-class:: sphx-glr-example-title + +.. _sphx_glr_auto_examples_07_ui_viz_ui_listbox.py: + + +========= +ListBox +========= + +This example shows how to use the UI API. We will create a list +some geometric shapes from FURY UI elements. + +First, a bunch of imports. + +.. GENERATED FROM PYTHON SOURCE LINES 12-15 + +.. code-block:: Python + + from fury import ui, window + from fury.data import fetch_viz_icons + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 16-17 + +First we need to fetch some icons that are included in FURY. + +.. GENERATED FROM PYTHON SOURCE LINES 17-20 + +.. code-block:: Python + + + fetch_viz_icons() + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + Data size is approximately 12KB + Dataset is already in place. If you want to fetch it again please first remove the folder /Users/skoudoro/.fury/icons + + ({'icomoon.tar.gz': ('https://digital.lib.washington.edu/researchworks/bitstream/handle/1773/38478/icomoon.tar.gz', 'BC1FEEA6F58BA3601D6A0B029EB8DFC5F352E21F2A16BA41099A96AA3F5A4735')}, '/Users/skoudoro/.fury/icons') + + + +.. GENERATED FROM PYTHON SOURCE LINES 21-23 + +Create some text blocks that will be shown when +list elements will be selected + +.. GENERATED FROM PYTHON SOURCE LINES 23-30 + +.. code-block:: Python + + + welcome_text = ui.TextBlock2D(text='Welcome', font_size=30, position=(500, 400)) + bye_text = ui.TextBlock2D(text='Bye', font_size=30, position=(500, 400)) + fury_text = ui.TextBlock2D(text='Fury', font_size=30, position=(500, 400)) + + example = [welcome_text, bye_text, fury_text] + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 31-32 + +Hide these text blocks for now + +.. GENERATED FROM PYTHON SOURCE LINES 32-41 + +.. code-block:: Python + + + + def hide_all_examples(): + for element in example: + element.set_visibility(False) + + + hide_all_examples() + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 42-43 + +Create ListBox with the values as parameter. + +.. GENERATED FROM PYTHON SOURCE LINES 43-49 + +.. code-block:: Python + + + values = ['Welcome', 'Bye', 'Fury'] + listbox = ui.ListBox2D( + values=values, position=(10, 300), size=(200, 200), multiselection=False + ) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 50-51 + +Function to show selected element. + +.. GENERATED FROM PYTHON SOURCE LINES 51-61 + +.. code-block:: Python + + + + def display_element(): + hide_all_examples() + element = example[values.index(listbox.selected[0])] + element.set_visibility(True) + + + listbox.on_change = display_element + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 62-64 + +Now that all the elements have been initialised, we add them to the show +manager. + +.. GENERATED FROM PYTHON SOURCE LINES 64-78 + +.. code-block:: Python + + + current_size = (800, 800) + show_manager = window.ShowManager(size=current_size, title='FURY UI ListBox_Example') + + show_manager.scene.add(listbox) + show_manager.scene.add(welcome_text) + show_manager.scene.add(bye_text) + show_manager.scene.add(fury_text) + interactive = False + + if interactive: + show_manager.start() + + window.record(show_manager.scene, size=current_size, out_path='viz_listbox.png') + + + +.. image-sg:: /auto_examples/07_ui/images/sphx_glr_viz_ui_listbox_001.png + :alt: viz ui listbox + :srcset: /auto_examples/07_ui/images/sphx_glr_viz_ui_listbox_001.png + :class: sphx-glr-single-img + + + + + + +.. rst-class:: sphx-glr-timing + + **Total running time of the script:** (0 minutes 0.077 seconds) + + +.. _sphx_glr_download_auto_examples_07_ui_viz_ui_listbox.py: + +.. only:: html + + .. container:: sphx-glr-footer sphx-glr-footer-example + + .. container:: sphx-glr-download sphx-glr-download-jupyter + + :download:`Download Jupyter notebook: viz_ui_listbox.ipynb ` + + .. container:: sphx-glr-download sphx-glr-download-python + + :download:`Download Python source code: viz_ui_listbox.py ` + + +.. only:: html + + .. rst-class:: sphx-glr-signature + + `Gallery generated by Sphinx-Gallery `_ diff --git a/v0.10.x/_sources/auto_examples/07_ui/viz_ui_slider.rst.txt b/v0.10.x/_sources/auto_examples/07_ui/viz_ui_slider.rst.txt new file mode 100644 index 000000000..c162b2623 --- /dev/null +++ b/v0.10.x/_sources/auto_examples/07_ui/viz_ui_slider.rst.txt @@ -0,0 +1,324 @@ + +.. DO NOT EDIT. +.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. +.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: +.. "auto_examples/07_ui/viz_ui_slider.py" +.. LINE NUMBERS ARE GIVEN BELOW. + +.. only:: html + + .. note:: + :class: sphx-glr-download-link-note + + :ref:`Go to the end ` + to download the full example code + +.. rst-class:: sphx-glr-example-title + +.. _sphx_glr_auto_examples_07_ui_viz_ui_slider.py: + + +===================== +Cube & Slider Control +===================== + +This example shows how to use the UI API. We will demonstrate how to +create a cube and control with sliders. + +First, some imports. + +.. GENERATED FROM PYTHON SOURCE LINES 12-17 + +.. code-block:: Python + + import numpy as np + + from fury import actor, ui, window + from fury.data import fetch_viz_icons + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 18-19 + +First we need to fetch some icons that are included in FURY. + +.. GENERATED FROM PYTHON SOURCE LINES 19-22 + +.. code-block:: Python + + + fetch_viz_icons() + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + Data size is approximately 12KB + Dataset is already in place. If you want to fetch it again please first remove the folder /Users/skoudoro/.fury/icons + + ({'icomoon.tar.gz': ('https://digital.lib.washington.edu/researchworks/bitstream/handle/1773/38478/icomoon.tar.gz', 'BC1FEEA6F58BA3601D6A0B029EB8DFC5F352E21F2A16BA41099A96AA3F5A4735')}, '/Users/skoudoro/.fury/icons') + + + +.. GENERATED FROM PYTHON SOURCE LINES 23-27 + +Cube and sliders +================ + +Add a cube to the scene . + +.. GENERATED FROM PYTHON SOURCE LINES 27-35 + +.. code-block:: Python + + + cube = actor.cube( + centers=np.array([[15, 0, 0]]), + colors=np.array([[0, 0, 1]]), + scales=np.array([[20, 20, 20]]), + directions=np.array([[0, 0, 1]]), + ) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 36-38 + +Now we'll add five sliders: 1 circular and 4 linear sliders. +By default the alignments are 'bottom' for horizontal and 'top' for vertical. + +.. GENERATED FROM PYTHON SOURCE LINES 38-80 + +.. code-block:: Python + + + ring_slider = ui.RingSlider2D( + center=(630, 400), initial_value=0, text_template='{angle:5.1f}°' + ) + + hor_line_slider_text_top = ui.LineSlider2D( + center=(400, 230), + initial_value=0, + orientation='horizontal', + min_value=-10, + max_value=10, + text_alignment='top', + ) + + hor_line_slider_text_bottom = ui.LineSlider2D( + center=(400, 200), + initial_value=0, + orientation='horizontal', + min_value=-10, + max_value=10, + text_alignment='bottom', + ) + + ver_line_slider_text_left = ui.LineSlider2D( + center=(100, 400), + initial_value=0, + orientation='vertical', + min_value=-10, + max_value=10, + text_alignment='left', + ) + + ver_line_slider_text_right = ui.LineSlider2D( + center=(150, 400), + initial_value=0, + orientation='vertical', + min_value=-10, + max_value=10, + text_alignment='right', + ) + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 81-82 + +We can use a callback to rotate the cube with the ring slider. + +.. GENERATED FROM PYTHON SOURCE LINES 82-93 + +.. code-block:: Python + + + + def rotate_cube(slider): + angle = slider.value + previous_angle = slider.previous_value + rotation_angle = angle - previous_angle + cube.RotateX(rotation_angle) + + + ring_slider.on_change = rotate_cube + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 94-95 + +Similarly, we can translate the cube with the line slider. + +.. GENERATED FROM PYTHON SOURCE LINES 95-112 + +.. code-block:: Python + + + + def translate_cube_ver(slider): + value = slider.value + cube.SetPosition(0, value, 0) + + + def translate_cube_hor(slider): + value = slider.value + cube.SetPosition(value, 0, 0) + + + hor_line_slider_text_top.on_change = translate_cube_hor + hor_line_slider_text_bottom.on_change = translate_cube_hor + ver_line_slider_text_left.on_change = translate_cube_ver + ver_line_slider_text_right.on_change = translate_cube_ver + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 113-118 + +Show Manager +================================== + +Now that all the elements have been initialised, we add them to the show +manager. + +.. GENERATED FROM PYTHON SOURCE LINES 118-130 + +.. code-block:: Python + + + current_size = (800, 800) + show_manager = window.ShowManager(size=current_size, title='FURY Cube Example') + + show_manager.scene.add(cube) + show_manager.scene.add(ring_slider) + show_manager.scene.add(hor_line_slider_text_top) + show_manager.scene.add(hor_line_slider_text_bottom) + show_manager.scene.add(ver_line_slider_text_left) + show_manager.scene.add(ver_line_slider_text_right) + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 131-132 + +Visibility by default is True + +.. GENERATED FROM PYTHON SOURCE LINES 132-140 + +.. code-block:: Python + + + cube.SetVisibility(True) + ring_slider.set_visibility(True) + hor_line_slider_text_top.set_visibility(True) + hor_line_slider_text_bottom.set_visibility(True) + ver_line_slider_text_left.set_visibility(True) + ver_line_slider_text_right.set_visibility(True) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 141-142 + +Set camera for better visualization + +.. GENERATED FROM PYTHON SOURCE LINES 142-153 + +.. code-block:: Python + + + show_manager.scene.reset_camera() + show_manager.scene.set_camera(position=(0, 0, 150)) + show_manager.scene.reset_clipping_range() + show_manager.scene.azimuth(30) + interactive = False + + if interactive: + show_manager.start() + + window.record(show_manager.scene, size=current_size, out_path='viz_slider.png') + + + +.. image-sg:: /auto_examples/07_ui/images/sphx_glr_viz_ui_slider_001.png + :alt: viz ui slider + :srcset: /auto_examples/07_ui/images/sphx_glr_viz_ui_slider_001.png + :class: sphx-glr-single-img + + + + + + +.. rst-class:: sphx-glr-timing + + **Total running time of the script:** (0 minutes 0.079 seconds) + + +.. _sphx_glr_download_auto_examples_07_ui_viz_ui_slider.py: + +.. only:: html + + .. container:: sphx-glr-footer sphx-glr-footer-example + + .. container:: sphx-glr-download sphx-glr-download-jupyter + + :download:`Download Jupyter notebook: viz_ui_slider.ipynb ` + + .. container:: sphx-glr-download sphx-glr-download-python + + :download:`Download Python source code: viz_ui_slider.py ` + + +.. only:: html + + .. rst-class:: sphx-glr-signature + + `Gallery generated by Sphinx-Gallery `_ diff --git a/v0.10.x/_sources/auto_examples/10_animation/index.rst.txt b/v0.10.x/_sources/auto_examples/10_animation/index.rst.txt new file mode 100644 index 000000000..a4e416308 --- /dev/null +++ b/v0.10.x/_sources/auto_examples/10_animation/index.rst.txt @@ -0,0 +1,226 @@ + + +.. _sphx_glr_auto_examples_10_animation: + +Animation +--------- + +These tutorials show: + +- How to animate FURY actors. +- How to use different interpolation methods in animations. + + + +.. raw:: html + +
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/10_animation/images/thumb/sphx_glr_viz_introduction_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_10_animation_viz_introduction.py` + +.. raw:: html + +
Keyframe animation introduction
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/10_animation/images/thumb/sphx_glr_viz_timeline_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_10_animation_viz_timeline.py` + +.. raw:: html + +
Timeline and setting keyframes
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/10_animation/images/thumb/sphx_glr_viz_spline_interpolator_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_10_animation_viz_spline_interpolator.py` + +.. raw:: html + +
Keyframes Spline Interpolator
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/10_animation/images/thumb/sphx_glr_viz_using_time_equations_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_10_animation_viz_using_time_equations.py` + +.. raw:: html + +
Keyframe animation
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/10_animation/images/thumb/sphx_glr_viz_interpolators_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_10_animation_viz_interpolators.py` + +.. raw:: html + +
Keyframe animation
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/10_animation/images/thumb/sphx_glr_viz_color_interpolators_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_10_animation_viz_color_interpolators.py` + +.. raw:: html + +
Keyframe Color Interpolators
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/10_animation/images/thumb/sphx_glr_viz_robot_arm_animation_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_10_animation_viz_robot_arm_animation.py` + +.. raw:: html + +
Arm Robot Animation
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/10_animation/images/thumb/sphx_glr_viz_hierarchical_animation_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_10_animation_viz_hierarchical_animation.py` + +.. raw:: html + +
Keyframe hierarchical Animation
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/10_animation/images/thumb/sphx_glr_viz_bezier_interpolator_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_10_animation_viz_bezier_interpolator.py` + +.. raw:: html + +
Bezier Interpolator
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/10_animation/images/thumb/sphx_glr_viz_camera_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_10_animation_viz_camera.py` + +.. raw:: html + +
Keyframe animation: Camera and opacity
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/10_animation/images/thumb/sphx_glr_viz_custom_interpolator_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_10_animation_viz_custom_interpolator.py` + +.. raw:: html + +
Making a custom interpolator
+
+ + +.. raw:: html + +
+ + +.. toctree:: + :hidden: + + /auto_examples/10_animation/viz_introduction + /auto_examples/10_animation/viz_timeline + /auto_examples/10_animation/viz_spline_interpolator + /auto_examples/10_animation/viz_using_time_equations + /auto_examples/10_animation/viz_interpolators + /auto_examples/10_animation/viz_color_interpolators + /auto_examples/10_animation/viz_robot_arm_animation + /auto_examples/10_animation/viz_hierarchical_animation + /auto_examples/10_animation/viz_bezier_interpolator + /auto_examples/10_animation/viz_camera + /auto_examples/10_animation/viz_custom_interpolator + diff --git a/v0.10.x/_sources/auto_examples/10_animation/sg_execution_times.rst.txt b/v0.10.x/_sources/auto_examples/10_animation/sg_execution_times.rst.txt new file mode 100644 index 000000000..ab0efefaa --- /dev/null +++ b/v0.10.x/_sources/auto_examples/10_animation/sg_execution_times.rst.txt @@ -0,0 +1,67 @@ + +:orphan: + +.. _sphx_glr_auto_examples_10_animation_sg_execution_times: + + +Computation times +================= +**00:00.700** total execution time for 11 files **from auto_examples/10_animation**: + +.. container:: + + .. raw:: html + + + + + + + + .. list-table:: + :header-rows: 1 + :class: table table-striped sg-datatable + + * - Example + - Time + - Mem (MB) + * - :ref:`sphx_glr_auto_examples_10_animation_viz_camera.py` (``viz_camera.py``) + - 00:00.585 + - 0.0 + * - :ref:`sphx_glr_auto_examples_10_animation_viz_custom_interpolator.py` (``viz_custom_interpolator.py``) + - 00:00.115 + - 0.0 + * - :ref:`sphx_glr_auto_examples_10_animation_viz_bezier_interpolator.py` (``viz_bezier_interpolator.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_10_animation_viz_color_interpolators.py` (``viz_color_interpolators.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_10_animation_viz_hierarchical_animation.py` (``viz_hierarchical_animation.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_10_animation_viz_interpolators.py` (``viz_interpolators.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_10_animation_viz_introduction.py` (``viz_introduction.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_10_animation_viz_robot_arm_animation.py` (``viz_robot_arm_animation.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_10_animation_viz_spline_interpolator.py` (``viz_spline_interpolator.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_10_animation_viz_timeline.py` (``viz_timeline.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_10_animation_viz_using_time_equations.py` (``viz_using_time_equations.py``) + - 00:00.000 + - 0.0 diff --git a/v0.10.x/_sources/auto_examples/10_animation/viz_bezier_interpolator.rst.txt b/v0.10.x/_sources/auto_examples/10_animation/viz_bezier_interpolator.rst.txt new file mode 100644 index 000000000..11aa8c449 --- /dev/null +++ b/v0.10.x/_sources/auto_examples/10_animation/viz_bezier_interpolator.rst.txt @@ -0,0 +1,510 @@ + +.. DO NOT EDIT. +.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. +.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: +.. "auto_examples/10_animation/viz_bezier_interpolator.py" +.. LINE NUMBERS ARE GIVEN BELOW. + +.. only:: html + + .. note:: + :class: sphx-glr-download-link-note + + :ref:`Go to the end ` + to download the full example code + +.. rst-class:: sphx-glr-example-title + +.. _sphx_glr_auto_examples_10_animation_viz_bezier_interpolator.py: + + +=================== +Bezier Interpolator +=================== + +Keyframe animation using cubic Bezier interpolator. + +.. GENERATED FROM PYTHON SOURCE LINES 8-14 + +.. code-block:: Python + + import numpy as np + + from fury import actor, window + from fury.animation import Animation, Timeline + from fury.animation.interpolator import cubic_bezier_interpolator + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 15-21 + +Position interpolation using cubic Bezier curve +=============================================== + +Cubic bezier curve is a widely used method for interpolating motion paths. +This can be achieved using positions and control points between those +positions. + +.. GENERATED FROM PYTHON SOURCE LINES 21-28 + +.. code-block:: Python + + + scene = window.Scene() + showm = window.ShowManager( + scene, size=(900, 768), reset_camera=False, order_transparent=True + ) + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 29-46 + +Cubic Bezier curve parameters +============================= +In order to make a cubic bezier curve based animation, you need four values +for every keyframe: +1- Timestamp: The time that the keyframe is assigned to. +2- value: The value of the keyframe. This might be position, quaternion, or + scale value. +3- In control point: The control point used when the value is the destination + value. +4- Out control point: The control point used when the value is the departure + value:: + + keyframe 0 -----------------> keyframe 1 +(time-0) (value-0) (out-cp-0) -----------------> (time-1) (value-1) (in-cp-1) + + keyframe 1 -----------------> keyframe 2 +(time-1) (value-1) (out-cp-1) -----------------> (time-2) (value-2) (in-cp-2) + +.. GENERATED FROM PYTHON SOURCE LINES 46-50 + +.. code-block:: Python + + + keyframe_1 = {'value': [-2, 0, 0], 'out_cp': [-15, 6, 0]} + keyframe_2 = {'value': [18, 0, 0], 'in_cp': [27, 18, 0]} + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 51-52 + +Visualizing points + +.. GENERATED FROM PYTHON SOURCE LINES 52-56 + +.. code-block:: Python + + pts_actor = actor.sphere( + np.array([keyframe_1.get('value'), keyframe_2.get('value')]), (1, 0, 0), radii=0.3 + ) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 57-58 + +Visualizing the control points + +.. GENERATED FROM PYTHON SOURCE LINES 58-62 + +.. code-block:: Python + + cps_actor = actor.sphere( + np.array([keyframe_2.get('in_cp'), keyframe_1.get('out_cp')]), (0, 0, 1), radii=0.6 + ) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 63-64 + +Visualizing the connection between the control points and the points + +.. GENERATED FROM PYTHON SOURCE LINES 64-69 + +.. code-block:: Python + + cline_actor = actor.line( + np.array([list(keyframe_1.values()), list(keyframe_2.values())]), + colors=np.array([0, 1, 0]), + ) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 70-71 + +Initializing an ``Animation`` and adding sphere actor to it. + +.. GENERATED FROM PYTHON SOURCE LINES 71-75 + +.. code-block:: Python + + animation = Animation() + sphere = actor.sphere(np.array([[0, 0, 0]]), (1, 0, 1)) + animation.add_actor(sphere) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 76-87 + +Setting Cubic Bezier keyframes +============================== + +Cubic Bezier keyframes consists of 4 data per keyframe +Timestamp, position, in control point, and out control point. +- In control point is the cubic bezier control point for the associated + position when this position is the destination position. +- Out control point is the cubic bezier control point for the associated + position when this position is the origin position or departing position. +Note: If a control point is not provided or set `None`, this control point +will be the same as the position itself. + +.. GENERATED FROM PYTHON SOURCE LINES 87-95 + +.. code-block:: Python + + + animation.set_position( + 0.0, np.array(keyframe_1.get('value')), out_cp=np.array(keyframe_1.get('out_cp')) + ) + animation.set_position( + 5.0, np.array(keyframe_2.get('value')), in_cp=np.array(keyframe_2.get('in_cp')) + ) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 96-97 + +Changing position interpolation into cubic bezier interpolation + +.. GENERATED FROM PYTHON SOURCE LINES 97-99 + +.. code-block:: Python + + animation.set_position_interpolator(cubic_bezier_interpolator) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 100-101 + +Adding the visualization actors to the scene. + +.. GENERATED FROM PYTHON SOURCE LINES 101-103 + +.. code-block:: Python + + scene.add(pts_actor, cps_actor, cline_actor) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 104-105 + +Adding the animation to the ``ShowManager`` + +.. GENERATED FROM PYTHON SOURCE LINES 105-114 + +.. code-block:: Python + + showm.add_animation(animation) + + interactive = False + + if interactive: + showm.start() + + window.record(scene, out_path='viz_keyframe_animation_bezier_1.png', size=(900, 768)) + + + + +.. image-sg:: /auto_examples/10_animation/images/sphx_glr_viz_bezier_interpolator_001.png + :alt: viz bezier interpolator + :srcset: /auto_examples/10_animation/images/sphx_glr_viz_bezier_interpolator_001.png + :class: sphx-glr-single-img + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 115-118 + +A more complex scene scene +========================== + + +.. GENERATED FROM PYTHON SOURCE LINES 118-124 + +.. code-block:: Python + + + scene = window.Scene() + show_manager = window.ShowManager( + scene, size=(900, 768), reset_camera=False, order_transparent=True + ) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 125-127 + +Note: If a control point is set to `None`, it gets the value of the +point it controls. + +.. GENERATED FROM PYTHON SOURCE LINES 127-134 + +.. code-block:: Python + + keyframes = { + # time - position - in control point - out control point + 0.0: {'value': [-2, 0, 0], 'out_cp': [-15, 6, 0]}, + 5.0: {'value': [18, 0, 0], 'in_cp': [27, 18, 0], 'out_cp': [27, -18, 0]}, + 9.0: {'value': [-5, -10, -10]}, + } + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 135-136 + +Create the sphere actor. + +.. GENERATED FROM PYTHON SOURCE LINES 136-138 + +.. code-block:: Python + + sphere = actor.sphere(np.array([[0, 0, 0]]), (1, 0, 1)) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 139-140 + +Create an ``Animation`` and adding the sphere actor to it. + +.. GENERATED FROM PYTHON SOURCE LINES 140-142 + +.. code-block:: Python + + animation = Animation(sphere) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 143-144 + +Setting Cubic Bezier keyframes + +.. GENERATED FROM PYTHON SOURCE LINES 144-146 + +.. code-block:: Python + + animation.set_position_keyframes(keyframes) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 147-148 + +changing position interpolation into cubic bezier interpolation + +.. GENERATED FROM PYTHON SOURCE LINES 148-150 + +.. code-block:: Python + + animation.set_position_interpolator(cubic_bezier_interpolator) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 151-152 + +visualizing the points and control points (only for demonstration) + +.. GENERATED FROM PYTHON SOURCE LINES 152-170 + +.. code-block:: Python + + for t, keyframe in keyframes.items(): + pos = keyframe.get('value') + in_control_point = keyframe.get('in_cp') + out_control_point = keyframe.get('out_cp') + + ########################################################################### + # visualizing position keyframe + vis_point = actor.sphere(np.array([pos]), (1, 0, 0), radii=0.3) + scene.add(vis_point) + + ########################################################################### + # Visualizing the control points and their length (if exist) + for cp in [in_control_point, out_control_point]: + if cp is not None: + vis_cps = actor.sphere(np.array([cp]), (0, 0, 1), radii=0.6) + cline_actor = actor.line(np.array([[pos, cp]]), colors=np.array([0, 1, 0])) + scene.add(vis_cps, cline_actor) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 171-173 + +Initializing the timeline to be able to control the playback of the +animation. + +.. GENERATED FROM PYTHON SOURCE LINES 173-175 + +.. code-block:: Python + + timeline = Timeline(animation, playback_panel=True) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 176-177 + +We only need to add the ``Timeline`` to the ``ShowManager`` + +.. GENERATED FROM PYTHON SOURCE LINES 177-179 + +.. code-block:: Python + + show_manager.add_animation(timeline) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 180-181 + +Start the animation + +.. GENERATED FROM PYTHON SOURCE LINES 181-185 + +.. code-block:: Python + + if interactive: + show_manager.start() + + window.record(scene, out_path='viz_keyframe_animation_bezier_2.png', size=(900, 768)) + + + +.. image-sg:: /auto_examples/10_animation/images/sphx_glr_viz_bezier_interpolator_002.png + :alt: viz bezier interpolator + :srcset: /auto_examples/10_animation/images/sphx_glr_viz_bezier_interpolator_002.png + :class: sphx-glr-single-img + + + + + + +.. rst-class:: sphx-glr-timing + + **Total running time of the script:** (0 minutes 0.212 seconds) + + +.. _sphx_glr_download_auto_examples_10_animation_viz_bezier_interpolator.py: + +.. only:: html + + .. container:: sphx-glr-footer sphx-glr-footer-example + + .. container:: sphx-glr-download sphx-glr-download-jupyter + + :download:`Download Jupyter notebook: viz_bezier_interpolator.ipynb ` + + .. container:: sphx-glr-download sphx-glr-download-python + + :download:`Download Python source code: viz_bezier_interpolator.py ` + + +.. only:: html + + .. rst-class:: sphx-glr-signature + + `Gallery generated by Sphinx-Gallery `_ diff --git a/v0.10.x/_sources/auto_examples/10_animation/viz_camera.rst.txt b/v0.10.x/_sources/auto_examples/10_animation/viz_camera.rst.txt new file mode 100644 index 000000000..c6ec5d2e9 --- /dev/null +++ b/v0.10.x/_sources/auto_examples/10_animation/viz_camera.rst.txt @@ -0,0 +1,436 @@ + +.. DO NOT EDIT. +.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. +.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: +.. "auto_examples/10_animation/viz_camera.py" +.. LINE NUMBERS ARE GIVEN BELOW. + +.. only:: html + + .. note:: + :class: sphx-glr-download-link-note + + :ref:`Go to the end ` + to download the full example code + +.. rst-class:: sphx-glr-example-title + +.. _sphx_glr_auto_examples_10_animation_viz_camera.py: + + +====================================== +Keyframe animation: Camera and opacity +====================================== + +Camera and opacity keyframe animation explained in this tutorial. + +.. GENERATED FROM PYTHON SOURCE LINES 8-15 + +.. code-block:: Python + + + import numpy as np + + from fury import actor, window + from fury.animation import Animation, CameraAnimation, Timeline + from fury.animation.interpolator import cubic_spline_interpolator + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 16-21 + +The Plan +======== + +The plan here is to animate (scale and translate) 50 spheres randomly, and +show `FURY` text that appears at the end! + +.. GENERATED FROM PYTHON SOURCE LINES 21-29 + +.. code-block:: Python + + + scene = window.Scene() + + showm = window.ShowManager( + scene, size=(900, 768), reset_camera=False, order_transparent=True + ) + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 30-42 + +Creating the main ``Timeline`` and adding static actors to it +============================================================= + +Here we create a ``Timeline``. so that we can use it as a controller for the +50 animations we will create. +So, Instead of updating and adding 50 Animations to the ``ShowManager``, +we only need to update the main ``Timeline``. Also, a playback panel can be +assigned to this main Timeline. + +But, why we need 50 ``Animations``, you may ask. +-> A single ``Animation`` can handle each property once at a time. So we need +50 ``Animations`` to translate and scale our 50 spheres. + +.. GENERATED FROM PYTHON SOURCE LINES 44-46 + +``playback_panel=True`` assigns a playback panel that can control the +playback of its ``Animations`` + +.. GENERATED FROM PYTHON SOURCE LINES 46-49 + +.. code-block:: Python + + + timeline = Timeline(playback_panel=True) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 50-51 + +Creating two actors for visualization, and to detect camera's animations. + +.. GENERATED FROM PYTHON SOURCE LINES 51-60 + +.. code-block:: Python + + arrow = actor.arrow( + np.array([[0, 0, 0]]), np.array([[0, 1, 0]]), np.array([[1, 1, 0]]), scales=5 + ) + plan = actor.box( + np.array([[0, 0, 0]]), + colors=np.array([[1, 1, 1]]), + scales=np.array([[20, 0.2, 20]]), + ) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 61-63 + +Creating "FURY" text +==================== + +.. GENERATED FROM PYTHON SOURCE LINES 63-65 + +.. code-block:: Python + + fury_text = actor.vector_text('FURY', pos=(-4.3, 15, 0), scale=(2, 2, 2)) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 66-67 + +Creating an ``Animation`` to animate the opacity of ``fury_text`` + +.. GENERATED FROM PYTHON SOURCE LINES 67-69 + +.. code-block:: Python + + text_anim = Animation(fury_text, loop=False) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 70-72 + +opacity is set to 0 at time 29 and set to one at time 35. +Linear interpolator is always used by default. + +.. GENERATED FROM PYTHON SOURCE LINES 72-75 + +.. code-block:: Python + + text_anim.set_opacity(29, 0) + text_anim.set_opacity(35, 1) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 76-77 + +``text_anim`` contains the text actor is added to the Timeline. + +.. GENERATED FROM PYTHON SOURCE LINES 77-79 + +.. code-block:: Python + + timeline.add_animation(text_anim) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 80-83 + +Creating and animating 50 Spheres +================================= + + +.. GENERATED FROM PYTHON SOURCE LINES 83-116 + +.. code-block:: Python + + + for i in range(50): + ########################################################################### + # create a sphere actor that's centered at the origin and has random color + # and radius. + actors = [ + actor.sphere( + np.array([[0, 0, 0]]), np.random.random([1, 3]), np.random.random([1, 3]) + ) + ] + + ########################################################################### + # create a timeline to animate this actor (single actor or list of actors) + # Actors can be added later using `Timeline.add_actor(actor)` + animation = Animation(actors) + + # We generate random position and scale values from time=0 to time=49 each + # two seconds. + for t in range(0, 50, 2): + ####################################################################### + # Position and scale are set to a random value at the timestamps + # mentioned above. + animation.set_position(t, np.random.random(3) * 30 - np.array([15, 0, 15])) + animation.set_scale(t, np.repeat(np.random.random(1), 3)) + + ########################################################################### + # change the position interpolator to cubic spline interpolator. + animation.set_position_interpolator(cubic_spline_interpolator) + + ########################################################################### + # Finally, the ``Animation`` is added to the ``Timeline``. + timeline.add_animation(animation) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 117-124 + +Animating the camera +==================== + +Since, only one camera is needed, camera animations are preferably done using +a separate ``Animation``. +Three properties can control the camera's animation: +Position, focal position (referred to by `focal`), and up-view. + +.. GENERATED FROM PYTHON SOURCE LINES 124-128 + +.. code-block:: Python + + + camera_anim = CameraAnimation(loop=False) + timeline.add_animation(camera_anim) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 129-131 + +Multiple keyframes can be set at once as follows. +camera focal positions + +.. GENERATED FROM PYTHON SOURCE LINES 131-152 + +.. code-block:: Python + + camera_positions = { + # time: camera position + 0: np.array([3, 3, 3]), + 4: np.array([50, 25, -40]), + 7: np.array([-50, 50, -40]), + 10: np.array([-25, 25, 20]), + 14: np.array([0, 16, 25]), + 20: np.array([0, 14.5, 20]), + } + + # camera focal positions + camera_focal_positions = { + # time: focal position + 15: np.array([0, 0, 0]), + 20: np.array([3, 9, 5]), + 23: np.array([7, 5, 3]), + 25: np.array([-2, 9, -6]), + 27: np.array([0, 16, 0]), + 31: np.array([0, 14.5, 0]), + } + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 153-155 + +``set_camera_focal`` can only set one keyframe, but +``set_camera_focal_keyframes`` can set a dictionary of keyframes. + +.. GENERATED FROM PYTHON SOURCE LINES 155-158 + +.. code-block:: Python + + camera_anim.set_focal_keyframes(camera_focal_positions) + camera_anim.set_position_keyframes(camera_positions) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 159-160 + +Change camera position and focal interpolators + +.. GENERATED FROM PYTHON SOURCE LINES 160-163 + +.. code-block:: Python + + camera_anim.set_position_interpolator(cubic_spline_interpolator) + camera_anim.set_focal_interpolator(cubic_spline_interpolator) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 164-165 + +Adding non-animatable actors to the scene. + +.. GENERATED FROM PYTHON SOURCE LINES 165-167 + +.. code-block:: Python + + scene.add(arrow, plan) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 168-169 + +Adding the timeline to the ShowManager. + +.. GENERATED FROM PYTHON SOURCE LINES 169-171 + +.. code-block:: Python + + showm.add_animation(timeline) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 172-173 + +The ShowManager must go on! + +.. GENERATED FROM PYTHON SOURCE LINES 173-180 + +.. code-block:: Python + + + interactive = False + + if interactive: + showm.start() + + window.record(scene, out_path='viz_keyframe_animation_camera.png', size=(900, 768)) + + + +.. image-sg:: /auto_examples/10_animation/images/sphx_glr_viz_camera_001.png + :alt: viz camera + :srcset: /auto_examples/10_animation/images/sphx_glr_viz_camera_001.png + :class: sphx-glr-single-img + + + + + + +.. rst-class:: sphx-glr-timing + + **Total running time of the script:** (0 minutes 0.585 seconds) + + +.. _sphx_glr_download_auto_examples_10_animation_viz_camera.py: + +.. only:: html + + .. container:: sphx-glr-footer sphx-glr-footer-example + + .. container:: sphx-glr-download sphx-glr-download-jupyter + + :download:`Download Jupyter notebook: viz_camera.ipynb ` + + .. container:: sphx-glr-download sphx-glr-download-python + + :download:`Download Python source code: viz_camera.py ` + + +.. only:: html + + .. rst-class:: sphx-glr-signature + + `Gallery generated by Sphinx-Gallery `_ diff --git a/v0.10.x/_sources/auto_examples/10_animation/viz_color_interpolators.rst.txt b/v0.10.x/_sources/auto_examples/10_animation/viz_color_interpolators.rst.txt new file mode 100644 index 000000000..d05e1a7c3 --- /dev/null +++ b/v0.10.x/_sources/auto_examples/10_animation/viz_color_interpolators.rst.txt @@ -0,0 +1,290 @@ + +.. DO NOT EDIT. +.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. +.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: +.. "auto_examples/10_animation/viz_color_interpolators.py" +.. LINE NUMBERS ARE GIVEN BELOW. + +.. only:: html + + .. note:: + :class: sphx-glr-download-link-note + + :ref:`Go to the end ` + to download the full example code + +.. rst-class:: sphx-glr-example-title + +.. _sphx_glr_auto_examples_10_animation_viz_color_interpolators.py: + + +============================ +Keyframe Color Interpolators +============================ + +Color animation explained in this tutorial and how to use different color +space interpolators. + +.. GENERATED FROM PYTHON SOURCE LINES 9-30 + +.. code-block:: Python + + + import numpy as np + + from fury import actor, window + from fury.animation import Animation + from fury.animation.interpolator import ( + hsv_color_interpolator, + lab_color_interpolator, + step_interpolator, + xyz_color_interpolator, + ) + from fury.animation.timeline import Timeline + from fury.colormap import distinguishable_colormap + + scene = window.Scene() + + showm = window.ShowManager( + scene, size=(900, 768), reset_camera=False, order_transparent=True + ) + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 31-32 + +Initializing positions of the cubes that will be color-animated. + +.. GENERATED FROM PYTHON SOURCE LINES 32-42 + +.. code-block:: Python + + cubes_pos = np.array( + [ + [[-2, 0, 0]], + [[0, 0, 0]], + [[2, 0, 0]], + [[4, 0, 0]], + [[6, 0, 0]], + ] + ) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 43-44 + +Static labels for different interpolators (for show) + +.. GENERATED FROM PYTHON SOURCE LINES 44-51 + +.. code-block:: Python + + linear_text = actor.vector_text('Linear', (-2.64, -1, 0)) + lab_text = actor.vector_text('LAB', (-0.37, -1, 0)) + hsv_text = actor.vector_text('HSV', (1.68, -1, 0)) + xyz_text = actor.vector_text('XYZ', (3.6, -1, 0)) + step_text = actor.vector_text('Step', (5.7, -1, 0)) + scene.add(step_text, lab_text, linear_text, hsv_text, xyz_text) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 52-56 + +Creating an animation to animate the actor. +Also cube actor is provided for each timeline to handle as follows: +``Animation(actor)``, ``Animation(list_of_actors)``, or actors can be added +later using ``animation.add()`` or ``animation.add_actor()`` + +.. GENERATED FROM PYTHON SOURCE LINES 56-62 + +.. code-block:: Python + + anim_linear_color = Animation(actor.cube(cubes_pos[0])) + anim_LAB_color = Animation(actor.cube(cubes_pos[1])) + anim_HSV_color = Animation(actor.cube(cubes_pos[2])) + anim_XYZ_color = Animation(actor.cube(cubes_pos[3])) + anim_step_color = Animation(actor.cube(cubes_pos[4])) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 63-65 + +Creating a timeline to control all the animations (one for each color +interpolation method) + +.. GENERATED FROM PYTHON SOURCE LINES 65-68 + +.. code-block:: Python + + + timeline = Timeline(playback_panel=True) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 69-70 + +Adding animations to a Timeline. + +.. GENERATED FROM PYTHON SOURCE LINES 70-74 + +.. code-block:: Python + + timeline.add_animation( + [anim_linear_color, anim_LAB_color, anim_HSV_color, anim_XYZ_color, anim_step_color] + ) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 75-79 + +Setting color keyframes +======================= + +Setting the same color keyframes to all the animations + +.. GENERATED FROM PYTHON SOURCE LINES 81-82 + +First, we generate some distinguishable colors + +.. GENERATED FROM PYTHON SOURCE LINES 82-84 + +.. code-block:: Python + + colors = distinguishable_colormap(nb_colors=4) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 85-86 + +Then, we set them as keyframes for the animations + +.. GENERATED FROM PYTHON SOURCE LINES 86-94 + +.. code-block:: Python + + for t in range(0, 20, 5): + col = colors.pop() + anim_linear_color.set_color(t, col) + anim_LAB_color.set_color(t, col) + anim_HSV_color.set_color(t, col) + anim_XYZ_color.set_color(t, col) + anim_step_color.set_color(t, col) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 95-97 + +Changing the default scale interpolator to be a step interpolator +The default is linear interpolator for color keyframes + +.. GENERATED FROM PYTHON SOURCE LINES 97-102 + +.. code-block:: Python + + anim_HSV_color.set_color_interpolator(hsv_color_interpolator) + anim_LAB_color.set_color_interpolator(lab_color_interpolator) + anim_step_color.set_color_interpolator(step_interpolator) + anim_XYZ_color.set_color_interpolator(xyz_color_interpolator) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 103-104 + +Adding the main timeline to the show manager + +.. GENERATED FROM PYTHON SOURCE LINES 104-112 + +.. code-block:: Python + + showm.add_animation(timeline) + + interactive = False + + if interactive: + showm.start() + + window.record(scene, out_path='viz_keyframe_animation_colors.png', size=(900, 768)) + + + +.. image-sg:: /auto_examples/10_animation/images/sphx_glr_viz_color_interpolators_001.png + :alt: viz color interpolators + :srcset: /auto_examples/10_animation/images/sphx_glr_viz_color_interpolators_001.png + :class: sphx-glr-single-img + + + + + + +.. rst-class:: sphx-glr-timing + + **Total running time of the script:** (0 minutes 0.109 seconds) + + +.. _sphx_glr_download_auto_examples_10_animation_viz_color_interpolators.py: + +.. only:: html + + .. container:: sphx-glr-footer sphx-glr-footer-example + + .. container:: sphx-glr-download sphx-glr-download-jupyter + + :download:`Download Jupyter notebook: viz_color_interpolators.ipynb ` + + .. container:: sphx-glr-download sphx-glr-download-python + + :download:`Download Python source code: viz_color_interpolators.py ` + + +.. only:: html + + .. rst-class:: sphx-glr-signature + + `Gallery generated by Sphinx-Gallery `_ diff --git a/v0.10.x/_sources/auto_examples/10_animation/viz_custom_interpolator.rst.txt b/v0.10.x/_sources/auto_examples/10_animation/viz_custom_interpolator.rst.txt new file mode 100644 index 000000000..c6057d0bd --- /dev/null +++ b/v0.10.x/_sources/auto_examples/10_animation/viz_custom_interpolator.rst.txt @@ -0,0 +1,306 @@ + +.. DO NOT EDIT. +.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. +.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: +.. "auto_examples/10_animation/viz_custom_interpolator.py" +.. LINE NUMBERS ARE GIVEN BELOW. + +.. only:: html + + .. note:: + :class: sphx-glr-download-link-note + + :ref:`Go to the end ` + to download the full example code + +.. rst-class:: sphx-glr-example-title + +.. _sphx_glr_auto_examples_10_animation_viz_custom_interpolator.py: + + +============================ +Making a custom interpolator +============================ + +Keyframe animation using custom interpolator. + +.. GENERATED FROM PYTHON SOURCE LINES 8-13 + +.. code-block:: Python + + import numpy as np + + from fury import actor, window + from fury.animation import Animation, helpers + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 14-21 + +Implementing a custom interpolator +=============================================== + +A keyframe interpolator function must return a function which take the time +as an argument and returns a value. +It's recommended to import `fury.animation.helpers`, which has some useful +functions that would help to implement the interpolator. + +.. GENERATED FROM PYTHON SOURCE LINES 23-52 + +In glTF, animations using cubic spline interpolator needs at least two +points, and each point has two tangent vectors. +The interpolation equation for such data is in the glTF tutorials below: +https://github.khronos.org/glTF-Tutorials/gltfTutorial/gltfTutorial_007_Animations.html#cubic-spline-interpolation + +Tangent based cubic spline interpolation function: + +>>> def cubicSpline(previousPoint, previousTangent, nextPoint, nextTangent, +>>> interpolationValue): +>>> t = interpolationValue +>>> t2 = t * t +>>> t3 = t2 * t +>>> return (2 * t3 - 3 * t2 + 1) * previousPoint + +>>> (t3 - 2 * t2 + t) * previousTangent + +>>> (-2 * t3 + 3 * t2) * nextPoint + +>>> (t3 - t2) * nextTangent + +First we create a function that must take a dict object that contains the +animation keyframes when initialized as follows: + +>>> def tan_cubic_spline_interpolator(keyframes): +>>> ... +>>> def interpolate(t): +>>> return interpolated_value +>>> return interpolator + +Note: Also any other additional arguments are ok, see `spline_interpolator` +Second step is to implement the `interpolate` closure that only takes the +current time as input. + +.. GENERATED FROM PYTHON SOURCE LINES 52-122 + +.. code-block:: Python + + + + def tan_cubic_spline_interpolator(keyframes): + # First we must get ordered timestamps array: + timestamps = helpers.get_timestamps_from_keyframes(keyframes) + + # keyframes should be on the following form: + # { + # 1: {'value': ndarray, 'in_tangent': ndarray, 'out_tangent': ndarray}, + # 2: {'value': np.array([1, 2, 3], 'in_tangent': ndarray}, + # } + # See here, we might get incomplete data (out_tangent) in the second + # keyframe. In this case we need to have a default behaviour dealing + # with these missing data. + # Setting the tangent to a zero vector in this case is the best choice + for time in keyframes: + data = keyframes.get(time) + value = data.get('value') + if data.get('in_tangent') is None: + data['in_tangent'] = np.zeros_like(value) + if data.get('in_tangent') is None: + data['in_tangent'] = np.zeros_like(value) + + def interpolate(t): + # `get_previous_timestamp`and `get_next_timestamp` functions take + # timestamps array and current time as inputs and returns the + # surrounding timestamps. + t0 = helpers.get_previous_timestamp(timestamps, t) + t1 = helpers.get_next_timestamp(timestamps, t) + + # `get_time_tau` function takes current time and surrounding + # timestamps and returns a value from 0 to 1 + dt = helpers.get_time_tau(t, t0, t1) + + time_delta = t1 - t0 + + # to get a keyframe data at a specific timestamp, use + # `keyframes.get(t0)`. This keyframe data contains `value` and any + # other data set as a custom argument using keyframe setters. + # for example: + # >>> animation = Animation() + # >>> animation.set_position(0, np.array([1, 1, 1]), + # >>> custom_field=np.array([2, 3, 1])) + # In this case `keyframes.get(0)` would return: + # {'value': array(1, 1, 1), 'custom_field': array(2, 3, 1)} + # + # now we continue with the cubic spline equation. + p0 = keyframes.get(t0).get('value') + tan_0 = keyframes.get(t0).get('out_tangent') * time_delta + p1 = keyframes.get(t1).get('value') + tan_1 = keyframes.get(t1).get('in_tangent') * time_delta + # cubic spline equation using tangents + t2 = dt * dt + t3 = t2 * dt + return ( + (2 * t3 - 3 * t2 + 1) * p0 + + (t3 - 2 * t2 + dt) * tan_0 + + (-2 * t3 + 3 * t2) * p1 + + (t3 - t2) * tan_1 + ) + + return interpolate + + + scene = window.Scene() + showm = window.ShowManager( + scene, size=(900, 768), reset_camera=False, order_transparent=True + ) + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 123-125 + +Cubic spline keyframes data same as the one you get from glTF file. +=================================================================== + +.. GENERATED FROM PYTHON SOURCE LINES 125-135 + +.. code-block:: Python + + + # t in tangent position out tangent + translation = [ + [0.0, [0.0, 0.0, 0.0], [3.3051798, 6.640117, 0.0], [1.0, 0.0, 0.0]], + [1.0, [0.0, 0.0, 0.0], [3.3051798, 8.0, 0.0], [-1.0, 0.0, 0.0]], + [2.0, [-1.0, 0.0, 0.0], [3.3051798, 6.0, 0.0], [1.0, 0.0, 0.0]], + [3.0, [0.0, 0.0, 0.0], [3.3051798, 8.0, 0.0], [-1.0, 0.0, 0.0]], + [4.0, [0, -1.0, 0.0], [3.3051798, 6.0, 0.0], [0.0, 0.0, 0.0]], + ] + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 136-137 + +Initializing an ``Animation`` and adding sphere actor to it. + +.. GENERATED FROM PYTHON SOURCE LINES 137-143 + +.. code-block:: Python + + animation = Animation(motion_path_res=100) + + sphere = actor.sphere(np.array([[0, 0, 0]]), (1, 0, 1), radii=0.1) + + animation.add_actor(sphere) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 144-146 + +Setting position keyframes +========================== + +.. GENERATED FROM PYTHON SOURCE LINES 146-152 + +.. code-block:: Python + + for keyframe_data in translation: + t, in_tan, pos, out_tan = keyframe_data + # Since we used the name 'in_tangent' and 'out_tangent' in the interpolator + # We must use the same name as an argument to set it in the keyframe data. + animation.set_position(t, pos, in_tangent=in_tan, out_tangent=out_tan) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 153-154 + +Set the new interpolator to interpolate position keyframes + +.. GENERATED FROM PYTHON SOURCE LINES 154-156 + +.. code-block:: Python + + animation.set_position_interpolator(tan_cubic_spline_interpolator) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 157-158 + +adding the animation to the show manager. + +.. GENERATED FROM PYTHON SOURCE LINES 158-167 + +.. code-block:: Python + + showm.add_animation(animation) + + + interactive = False + + if interactive: + showm.start() + + window.record(scene, out_path='viz_keyframe_custom_interpolator.png', size=(900, 768)) + + + +.. image-sg:: /auto_examples/10_animation/images/sphx_glr_viz_custom_interpolator_001.png + :alt: viz custom interpolator + :srcset: /auto_examples/10_animation/images/sphx_glr_viz_custom_interpolator_001.png + :class: sphx-glr-single-img + + + + + + +.. rst-class:: sphx-glr-timing + + **Total running time of the script:** (0 minutes 0.115 seconds) + + +.. _sphx_glr_download_auto_examples_10_animation_viz_custom_interpolator.py: + +.. only:: html + + .. container:: sphx-glr-footer sphx-glr-footer-example + + .. container:: sphx-glr-download sphx-glr-download-jupyter + + :download:`Download Jupyter notebook: viz_custom_interpolator.ipynb ` + + .. container:: sphx-glr-download sphx-glr-download-python + + :download:`Download Python source code: viz_custom_interpolator.py ` + + +.. only:: html + + .. rst-class:: sphx-glr-signature + + `Gallery generated by Sphinx-Gallery `_ diff --git a/v0.10.x/_sources/auto_examples/10_animation/viz_hierarchical_animation.rst.txt b/v0.10.x/_sources/auto_examples/10_animation/viz_hierarchical_animation.rst.txt new file mode 100644 index 000000000..98921f6d1 --- /dev/null +++ b/v0.10.x/_sources/auto_examples/10_animation/viz_hierarchical_animation.rst.txt @@ -0,0 +1,414 @@ + +.. DO NOT EDIT. +.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. +.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: +.. "auto_examples/10_animation/viz_hierarchical_animation.py" +.. LINE NUMBERS ARE GIVEN BELOW. + +.. only:: html + + .. note:: + :class: sphx-glr-download-link-note + + :ref:`Go to the end ` + to download the full example code + +.. rst-class:: sphx-glr-example-title + +.. _sphx_glr_auto_examples_10_animation_viz_hierarchical_animation.py: + + +=============================== +Keyframe hierarchical Animation +=============================== + +Creating hierarchical keyframes animation in fury + +.. GENERATED FROM PYTHON SOURCE LINES 8-20 + +.. code-block:: Python + + import numpy as np + + from fury import actor, window + from fury.animation import Animation + + scene = window.Scene() + + showm = window.ShowManager( + scene, size=(900, 768), reset_camera=False, order_transparent=True + ) + showm.initialize() + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 21-22 + +Creating the road + +.. GENERATED FROM PYTHON SOURCE LINES 22-26 + +.. code-block:: Python + + road = actor.box( + np.array([[0, 0, 0]]), colors=np.array([[1, 1, 1]]), scales=np.array([[22, 0.1, 5]]) + ) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 27-28 + +Constructing the car geometry + +.. GENERATED FROM PYTHON SOURCE LINES 28-35 + +.. code-block:: Python + + + body_actor = actor.box( + np.array([[0, 0.5, 0], [-0.2, 1, 0]]), + scales=((4, 1, 2), (2.5, 1.5, 1.8)), + colors=(0.6, 0.3, 0.1), + ) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 36-37 + +Adding the the car's body to an Animation to be able to animate it later. + +.. GENERATED FROM PYTHON SOURCE LINES 37-39 + +.. code-block:: Python + + car_anim = Animation(body_actor) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 40-41 + +Creating the wheels of the car + +.. GENERATED FROM PYTHON SOURCE LINES 41-64 + +.. code-block:: Python + + wheel_center = np.array([[0, 0, 0]]) + + wheel_direction = np.array([[0, 0, 1]]) + wheel_positions = [ + [1.2, 0, 1.1], + [-1.2, 0, 1.1], + [1.2, 0, -1.1], + [-1.2, 0, -1.1], + ] + + wheels = [ + actor.cylinder( + wheel_center, + wheel_direction, + (0.1, 0.7, 0.3), + radius=1.7, + heights=0.3, + resolution=10, + capped=True, + ) + for _ in range(4) + ] + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 65-67 + +Animating each wheel and setting its position to the right position using a +single keyframe that will not change. + +.. GENERATED FROM PYTHON SOURCE LINES 67-75 + +.. code-block:: Python + + + wheels_animations = [Animation(wheel) for wheel in wheels] + + for wheel_anim in wheels_animations: + wheel_anim.set_position(0.0, wheel_positions.pop()) + wheel_anim.set_rotation(0.0, [0, 0, 1, 1]) + wheel_anim.set_rotation(1.0, [0, 0, 1, -1]) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 76-77 + +Creating a radar on top of the car + +.. GENERATED FROM PYTHON SOURCE LINES 79-80 + +First we create the shaft holding and rotating the radar + +.. GENERATED FROM PYTHON SOURCE LINES 80-84 + +.. code-block:: Python + + radar_shaft = actor.cylinder( + np.array([[0, 0, 0]]), np.array([[0, 1, 0]]), (0, 1, 0), heights=1 + ) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 85-86 + +In order to animate the shaft actor we have to add it to an Animation + +.. GENERATED FROM PYTHON SOURCE LINES 86-88 + +.. code-block:: Python + + radar_shaft_anim = Animation(radar_shaft) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 89-91 + +Setting a single position keyframe will make sure the actor will be placed at +that position + +.. GENERATED FROM PYTHON SOURCE LINES 91-93 + +.. code-block:: Python + + radar_shaft_anim.set_position(0.0, [0, 2, 0]) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 94-95 + +Rotating the shaft around Y axis + +.. GENERATED FROM PYTHON SOURCE LINES 95-99 + +.. code-block:: Python + + radar_shaft_anim.set_rotation(0.0, [0, -250, 0]) + radar_shaft_anim.set_rotation(1.0, [0, 250, 0]) + radar_shaft_anim.set_rotation(2.0, [0, -250, 0]) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 100-101 + +Now we create the radar itself + +.. GENERATED FROM PYTHON SOURCE LINES 101-103 + +.. code-block:: Python + + radar = actor.cone(np.array([[0, 0, 0]]), directions=(0, 0, 0), colors=(0.2, 0.2, 0.9)) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 104-105 + +Then add it to an animation in order to rotate it + +.. GENERATED FROM PYTHON SOURCE LINES 105-107 + +.. code-block:: Python + + radar_animation = Animation(radar) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 108-109 + +Set position and rotation as done above with the shaft. + +.. GENERATED FROM PYTHON SOURCE LINES 109-114 + +.. code-block:: Python + + radar_animation.set_position(0, [-0.4, 0.5, 0]) + radar_animation.set_rotation(0.0, [0, 0, 0]) + radar_animation.set_rotation(1.0, [180, 0, 0]) + radar_animation.set_rotation(2.0, [0, 0, 0]) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 115-118 + +Now, we want the radar to rotate when the shaft rotates in hierarchical way. +To do that we must add the radar animation as a child animation of the shaft +animation as below: + +.. GENERATED FROM PYTHON SOURCE LINES 118-120 + +.. code-block:: Python + + radar_shaft_anim.add_child_animation(radar_animation) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 121-124 + +After that we want everything to animate related to the car. +The wheels should always be attached to the car no matter where it moves. +we do that by adding them as child animations of the car's body animation + +.. GENERATED FROM PYTHON SOURCE LINES 124-126 + +.. code-block:: Python + + car_anim.add_child_animation([wheels_animations, radar_shaft_anim]) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 127-128 + +Moving the car + +.. GENERATED FROM PYTHON SOURCE LINES 128-131 + +.. code-block:: Python + + car_anim.set_position(0.0, [-10, 0.5, 0]) + car_anim.set_position(6.0, [10, 0.5, 0]) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 132-133 + +Adding the car Animation to the show manager + +.. GENERATED FROM PYTHON SOURCE LINES 133-145 + +.. code-block:: Python + + showm.add_animation(car_anim) + scene.add(road) + scene.camera().SetPosition(0, 20, 30) + + interactive = False + + if interactive: + showm.start() + + window.record( + scene, out_path='viz_keyframe_hierarchical_animation.png', size=(900, 768) + ) + + + +.. image-sg:: /auto_examples/10_animation/images/sphx_glr_viz_hierarchical_animation_001.png + :alt: viz hierarchical animation + :srcset: /auto_examples/10_animation/images/sphx_glr_viz_hierarchical_animation_001.png + :class: sphx-glr-single-img + + + + + + +.. rst-class:: sphx-glr-timing + + **Total running time of the script:** (0 minutes 0.102 seconds) + + +.. _sphx_glr_download_auto_examples_10_animation_viz_hierarchical_animation.py: + +.. only:: html + + .. container:: sphx-glr-footer sphx-glr-footer-example + + .. container:: sphx-glr-download sphx-glr-download-jupyter + + :download:`Download Jupyter notebook: viz_hierarchical_animation.ipynb ` + + .. container:: sphx-glr-download sphx-glr-download-python + + :download:`Download Python source code: viz_hierarchical_animation.py ` + + +.. only:: html + + .. rst-class:: sphx-glr-signature + + `Gallery generated by Sphinx-Gallery `_ diff --git a/v0.10.x/_sources/auto_examples/10_animation/viz_interpolators.rst.txt b/v0.10.x/_sources/auto_examples/10_animation/viz_interpolators.rst.txt new file mode 100644 index 000000000..071c335e1 --- /dev/null +++ b/v0.10.x/_sources/auto_examples/10_animation/viz_interpolators.rst.txt @@ -0,0 +1,343 @@ + +.. DO NOT EDIT. +.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. +.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: +.. "auto_examples/10_animation/viz_interpolators.py" +.. LINE NUMBERS ARE GIVEN BELOW. + +.. only:: html + + .. note:: + :class: sphx-glr-download-link-note + + :ref:`Go to the end ` + to download the full example code + +.. rst-class:: sphx-glr-example-title + +.. _sphx_glr_auto_examples_10_animation_viz_interpolators.py: + + +===================== +Keyframe animation +===================== + +Minimal tutorial of making keyframe-based animation in FURY. + +.. GENERATED FROM PYTHON SOURCE LINES 10-15 + +What is an ``Animation`` +======================== + +``Animation`` is responsible for animating FURY actors using a set of +keyframes by interpolating values between timestamps of these keyframes. + +.. GENERATED FROM PYTHON SOURCE LINES 15-29 + +.. code-block:: Python + + + import numpy as np + + from fury import actor, window + from fury.animation import Animation + from fury.animation.interpolator import cubic_spline_interpolator + + keyframes = { + 1.0: {'value': np.array([0, 0, 0])}, + 2.0: {'value': np.array([-4, 1, 0])}, + 5.0: {'value': np.array([0, 0, 12])}, + 6.0: {'value': np.array([25, 0, 12])}, + } + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 30-34 + +Why keyframes data are also a dictionary ``{'value': np.array([0, 0, 0])})``? +-> Since some keyframes data can only be defined by a set of data i.e. a +single position keyframe could consist of a position, in control point, and +out control point or any other data that helps to define this keyframe. + +.. GENERATED FROM PYTHON SOURCE LINES 37-45 + +What are the interpolators +========================== + +The keyframes interpolators are functions that takes a set of keyframes and +returns a function that calculates an interpolated value between these +keyframes. +Below there is an example on how to use interpolators manually to interpolate +the above defined ``keyframes``. + +.. GENERATED FROM PYTHON SOURCE LINES 45-48 + +.. code-block:: Python + + + interpolation_function = cubic_spline_interpolator(keyframes) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 49-51 + +Now, if we feed any time to this function it would return the cubic +interpolated position at that time. + +.. GENERATED FROM PYTHON SOURCE LINES 51-54 + +.. code-block:: Python + + + position = interpolation_function(1.44434) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 55-56 + +``position`` would contain an interpolated position at time equals 1.44434 + +.. GENERATED FROM PYTHON SOURCE LINES 58-63 + +Creating the environment +======================== + +In order to make any animations in FURY, a `ShowManager` is needed to handle +updating the animation and rendering the scene. + +.. GENERATED FROM PYTHON SOURCE LINES 63-73 + +.. code-block:: Python + + + scene = window.Scene() + + showm = window.ShowManager( + scene, size=(900, 768), reset_camera=False, order_transparent=True + ) + showm.initialize() + + arrow = actor.arrow(np.array([[0, 0, 0]]), (0, 0, 0), (1, 0, 1), scales=6) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 74-78 + +Creating an ``Animation`` +========================= + +First step is creating the Animation. + +.. GENERATED FROM PYTHON SOURCE LINES 78-80 + +.. code-block:: Python + + animation = Animation() + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 81-83 + +Adding the sphere actor to the timeline +This could've been done during initialization. + +.. GENERATED FROM PYTHON SOURCE LINES 83-85 + +.. code-block:: Python + + animation.add_actor(arrow) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 86-90 + +Setting position keyframes +========================== + +Adding some position keyframes + +.. GENERATED FROM PYTHON SOURCE LINES 90-95 + +.. code-block:: Python + + animation.set_position(0.0, np.array([0, 0, 0])) + animation.set_position(2.0, np.array([10, 10, 10])) + animation.set_position(5.0, np.array([-10, -3, -6])) + animation.set_position(9.0, np.array([10, 6, 20])) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 96-107 + +Changing the default interpolator for a single property +======================================================= + +For all properties except **rotation**, linear interpolator is used by +default. In order to change the default interpolator and set another +interpolator, call ``animation.set__interpolator(interpolator)`` +FURY already has some interpolators located at: +``fury.animation.interpolator``. + +Below we set the interpolator for position keyframes to be +**cubic spline interpolator**. + +.. GENERATED FROM PYTHON SOURCE LINES 107-109 + +.. code-block:: Python + + animation.set_position_interpolator(cubic_spline_interpolator) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 110-111 + +Adding some rotation keyframes. + +.. GENERATED FROM PYTHON SOURCE LINES 111-114 + +.. code-block:: Python + + animation.set_rotation(0.0, np.array([160, 50, 0])) + animation.set_rotation(8.0, np.array([60, 160, 0])) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 115-120 + +For Rotation keyframes, Slerp is used as the default interpolator. +What is Slerp? +Slerp (spherical linear interpolation) of quaternions results in a constant +speed rotation in keyframe animation. +Reed more about Slerp: https://en.wikipedia.org/wiki/Slerp + +.. GENERATED FROM PYTHON SOURCE LINES 122-123 + +Setting camera position to see the animation better. + +.. GENERATED FROM PYTHON SOURCE LINES 123-125 + +.. code-block:: Python + + scene.set_camera(position=(0, 0, 90)) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 126-127 + +Adding main animation to the ``ShowManager``. + +.. GENERATED FROM PYTHON SOURCE LINES 127-129 + +.. code-block:: Python + + showm.add_animation(animation) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 130-131 + +Start the ``ShowManager`` to start playing the animation + +.. GENERATED FROM PYTHON SOURCE LINES 131-137 + +.. code-block:: Python + + interactive = False + + if interactive: + showm.start() + + window.record(scene, out_path='viz_keyframe_interpolator.png', size=(900, 768)) + + + +.. image-sg:: /auto_examples/10_animation/images/sphx_glr_viz_interpolators_001.png + :alt: viz interpolators + :srcset: /auto_examples/10_animation/images/sphx_glr_viz_interpolators_001.png + :class: sphx-glr-single-img + + + + + + +.. rst-class:: sphx-glr-timing + + **Total running time of the script:** (0 minutes 0.101 seconds) + + +.. _sphx_glr_download_auto_examples_10_animation_viz_interpolators.py: + +.. only:: html + + .. container:: sphx-glr-footer sphx-glr-footer-example + + .. container:: sphx-glr-download sphx-glr-download-jupyter + + :download:`Download Jupyter notebook: viz_interpolators.ipynb ` + + .. container:: sphx-glr-download sphx-glr-download-python + + :download:`Download Python source code: viz_interpolators.py ` + + +.. only:: html + + .. rst-class:: sphx-glr-signature + + `Gallery generated by Sphinx-Gallery `_ diff --git a/v0.10.x/_sources/auto_examples/10_animation/viz_introduction.rst.txt b/v0.10.x/_sources/auto_examples/10_animation/viz_introduction.rst.txt new file mode 100644 index 000000000..29889dc5b --- /dev/null +++ b/v0.10.x/_sources/auto_examples/10_animation/viz_introduction.rst.txt @@ -0,0 +1,260 @@ + +.. DO NOT EDIT. +.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. +.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: +.. "auto_examples/10_animation/viz_introduction.py" +.. LINE NUMBERS ARE GIVEN BELOW. + +.. only:: html + + .. note:: + :class: sphx-glr-download-link-note + + :ref:`Go to the end ` + to download the full example code + +.. rst-class:: sphx-glr-example-title + +.. _sphx_glr_auto_examples_10_animation_viz_introduction.py: + + +=============================== +Keyframe animation introduction +=============================== + +This tutorial explains keyframe animation in FURY. + +.. GENERATED FROM PYTHON SOURCE LINES 9-17 + +Animations in FURY +================== + +FURY provides an easy-to-use animation system that enables users creating +complex animations based on keyframes. +The user only need to provide the attributes of actors at certain +times (keyframes), and the system will take care of animating everything +through interpolating between those keyframes. + +.. GENERATED FROM PYTHON SOURCE LINES 20-27 + +What exactly is a keyframe +========================== + +A Keyframe is simply a marker of time which stores the value of a property. + +A keyframe consists of a timestamp and some data. These data can be anything +such as temperature, position, or scale. + +.. GENERATED FROM PYTHON SOURCE LINES 29-57 + +What is Keyframe Animation +========================== + +Keyframe animations is a technique to simplify the process of animating a +scene. +Instead of providing the actor attributes for each frame, only a small amount +of keyframes are needed to create a smooth animation. Each keyframe encodes +the state of an actor at a certain timestamp. For instance a keyframe might +define that an actor should be positioned at the origin (0,0,0) at the start +of the animation. Another keyframe may define that the actor should move to +position (1,0,0) after 10 seconds. The system will take care of interpolating +the position of that actor between these two keyframes. + +Almost any parameter that you can set for FURY actors can be animated +using keyframes. + +For example, a Keyframe might define that the position of a FURY actor is +(0, 0, 0) at time equals 1 second. + +The goal of a Keyframe is to allow for interpolated animation, meaning, +for example, that the user could then add another key at time equals 3 +seconds, specifying the actor's position is (1, 1, 0), + +Then the correct position of the actor for all the times between 3 and 10 +will be interpolated. + +For this tutorial, we are going to use the FURY animation module to translate +FURY sphere actor. + +.. GENERATED FROM PYTHON SOURCE LINES 57-70 + +.. code-block:: Python + + + + import numpy as np + + from fury import actor, window + from fury.animation import Animation + + scene = window.Scene() + + showm = window.ShowManager(scene, size=(900, 768)) + showm.initialize() + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 71-77 + +Translating a sphere +==================== + +This is a quick demo showing how to translate a sphere from (0, 0, 0) to +(1, 1, 1). +First, we create an ``Animation``. See ``viz_interpolators.py`` tutorial + +.. GENERATED FROM PYTHON SOURCE LINES 77-79 + +.. code-block:: Python + + animation = Animation() + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 80-81 + +We also create the FURY sphere actor that will be animated. + +.. GENERATED FROM PYTHON SOURCE LINES 81-83 + +.. code-block:: Python + + sphere = actor.sphere(np.zeros([1, 3]), np.ones([1, 3])) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 84-85 + +Then lets add the sphere actor to the ``Animation`` + +.. GENERATED FROM PYTHON SOURCE LINES 85-87 + +.. code-block:: Python + + animation.add_actor(sphere) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 88-92 + +Then, we set our position keyframes at different timestamps +Here we want the sphere's position at the beginning to be [0, 0, 0]. And then +at time equals 3 seconds to be at [1, 1, 0] then finally at the end +(time equals 6) to return to the initial position which is [0, 0, 0] again. + +.. GENERATED FROM PYTHON SOURCE LINES 92-97 + +.. code-block:: Python + + + animation.set_position(0.0, [-1, -1, 0]) + animation.set_position(3.0, [1, 1, 0]) + animation.set_position(6.0, [-1, -1, 0]) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 98-99 + +The ``Animation`` must be added to the ``ShowManager`` as follows: + +.. GENERATED FROM PYTHON SOURCE LINES 99-102 + +.. code-block:: Python + + showm.add_animation(animation) + scene.camera().SetPosition(0, 0, 10) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 103-105 + +Animation can be added to the scene instead of the ``ShowManager`` but, the +animation will need to be updated and then render the scene manually. + +.. GENERATED FROM PYTHON SOURCE LINES 108-110 + +No need to add the sphere actor to scene, since it's now a part of the +``Animation``. + +.. GENERATED FROM PYTHON SOURCE LINES 110-119 + +.. code-block:: Python + + + interactive = False + + if interactive: + showm.start() + + window.record( + scene, out_path='viz_keyframe_animation_introduction.png', size=(900, 768) + ) + + + +.. image-sg:: /auto_examples/10_animation/images/sphx_glr_viz_introduction_001.png + :alt: viz introduction + :srcset: /auto_examples/10_animation/images/sphx_glr_viz_introduction_001.png + :class: sphx-glr-single-img + + + + + + +.. rst-class:: sphx-glr-timing + + **Total running time of the script:** (0 minutes 0.120 seconds) + + +.. _sphx_glr_download_auto_examples_10_animation_viz_introduction.py: + +.. only:: html + + .. container:: sphx-glr-footer sphx-glr-footer-example + + .. container:: sphx-glr-download sphx-glr-download-jupyter + + :download:`Download Jupyter notebook: viz_introduction.ipynb ` + + .. container:: sphx-glr-download sphx-glr-download-python + + :download:`Download Python source code: viz_introduction.py ` + + +.. only:: html + + .. rst-class:: sphx-glr-signature + + `Gallery generated by Sphinx-Gallery `_ diff --git a/v0.10.x/_sources/auto_examples/10_animation/viz_robot_arm_animation.rst.txt b/v0.10.x/_sources/auto_examples/10_animation/viz_robot_arm_animation.rst.txt new file mode 100644 index 000000000..fb25fb267 --- /dev/null +++ b/v0.10.x/_sources/auto_examples/10_animation/viz_robot_arm_animation.rst.txt @@ -0,0 +1,364 @@ + +.. DO NOT EDIT. +.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. +.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: +.. "auto_examples/10_animation/viz_robot_arm_animation.py" +.. LINE NUMBERS ARE GIVEN BELOW. + +.. only:: html + + .. note:: + :class: sphx-glr-download-link-note + + :ref:`Go to the end ` + to download the full example code + +.. rst-class:: sphx-glr-example-title + +.. _sphx_glr_auto_examples_10_animation_viz_robot_arm_animation.py: + + +=================== +Arm Robot Animation +=================== + +Tutorial on making a robot arm animation in FURY. + +.. GENERATED FROM PYTHON SOURCE LINES 8-22 + +.. code-block:: Python + + import numpy as np + + from fury import actor, window + from fury.animation import Animation, Timeline + from fury.utils import set_actor_origin + + scene = window.Scene() + + showm = window.ShowManager( + scene, size=(900, 768), reset_camera=False, order_transparent=True + ) + showm.initialize() + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 23-24 + +Creating robot arm components + +.. GENERATED FROM PYTHON SOURCE LINES 24-42 + +.. code-block:: Python + + + base = actor.cylinder( + np.array([[0, 0, 0]]), np.array([[0, 1, 0]]), colors=(0, 1, 0), radius=1 + ) + main_arm = actor.box(np.array([[0, 0, 0]]), colors=(1, 0.5, 0), scales=(12, 1, 1)) + + sub_arm = actor.box(np.array([[0, 0, 0]]), colors=(0, 0.5, 0.8), scales=(8, 0.7, 0.7)) + joint_1 = actor.sphere(np.array([[0, 0, 0]]), colors=np.array([1, 0, 1]), radii=1.2) + joint_2 = actor.sphere(np.array([[0, 0, 0]]), colors=np.array([1, 0, 1])) + + end = actor.cone( + np.array([[0, 0, 0]]), + np.array([[1, 0, 0]]), + np.array([[1, 0, 0]]), + heights=2.2, + resolution=6, + ) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 43-44 + +Setting the center of both shafts to the beginning. + +.. GENERATED FROM PYTHON SOURCE LINES 44-47 + +.. code-block:: Python + + set_actor_origin(main_arm, np.array([-6, 0, 0])) + set_actor_origin(sub_arm, np.array([-4, 0, 0])) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 48-49 + +Creating a timeline + +.. GENERATED FROM PYTHON SOURCE LINES 49-51 + +.. code-block:: Python + + timeline = Timeline(playback_panel=True) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 52-53 + +Creating animations + +.. GENERATED FROM PYTHON SOURCE LINES 53-58 + +.. code-block:: Python + + main_arm_animation = Animation([main_arm, joint_1], length=2 * np.pi) + child_arm_animation = Animation([sub_arm, joint_2]) + drill_animation = Animation(end) + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 59-60 + +Adding other Animations in hierarchical order + +.. GENERATED FROM PYTHON SOURCE LINES 60-64 + +.. code-block:: Python + + main_arm_animation.add_child_animation(child_arm_animation) + child_arm_animation.add_child_animation(drill_animation) + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 65-66 + +Creating Arm joints time dependent animation functions. + +.. GENERATED FROM PYTHON SOURCE LINES 66-80 + +.. code-block:: Python + + + + def rot_main_arm(t): + return np.array([np.sin(t / 2) * 180, np.cos(t / 2) * 180, 0]) + + + def rot_sub_arm(t): + return np.array([np.sin(t) * 180, np.cos(t) * 70, np.cos(t) * 40]) + + + def rot_drill(t): + return np.array([t * 1000, 0, 0]) + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 81-83 + +Setting timelines (joints) relative position +1- Placing the main arm on the cube static base. + +.. GENERATED FROM PYTHON SOURCE LINES 83-85 + +.. code-block:: Python + + main_arm_animation.set_position(0, np.array([0, 1.3, 0])) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 86-88 + +2- Translating the timeline containing the sub arm to the end of the first +arm. + +.. GENERATED FROM PYTHON SOURCE LINES 88-90 + +.. code-block:: Python + + child_arm_animation.set_position(0, np.array([12, 0, 0])) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 91-92 + +3- Translating the timeline containing the drill to the end of the sub arm. + +.. GENERATED FROM PYTHON SOURCE LINES 92-94 + +.. code-block:: Python + + drill_animation.set_position(0, np.array([8, 0, 0])) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 95-96 + +Setting rotation time-based evaluators + +.. GENERATED FROM PYTHON SOURCE LINES 96-100 + +.. code-block:: Python + + main_arm_animation.set_rotation_interpolator(rot_main_arm, is_evaluator=True) + child_arm_animation.set_rotation_interpolator(rot_sub_arm, is_evaluator=True) + drill_animation.set_rotation_interpolator(rot_drill, is_evaluator=True) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 101-102 + +Setting camera position to observe the robot arm. + +.. GENERATED FROM PYTHON SOURCE LINES 102-104 + +.. code-block:: Python + + scene.camera().SetPosition(0, 0, 90) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 105-106 + +Adding the base actor to the scene + +.. GENERATED FROM PYTHON SOURCE LINES 106-108 + +.. code-block:: Python + + scene.add(base) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 109-110 + +Adding the main parent animation to the Timeline. + +.. GENERATED FROM PYTHON SOURCE LINES 110-112 + +.. code-block:: Python + + timeline.add_animation(main_arm_animation) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 113-114 + +Now we add the timeline to the ShowManager + +.. GENERATED FROM PYTHON SOURCE LINES 114-122 + +.. code-block:: Python + + showm.add_animation(timeline) + + interactive = False + + if interactive: + showm.start() + + window.record(scene, out_path='viz_robot_arm.png', size=(900, 768)) + + + +.. image-sg:: /auto_examples/10_animation/images/sphx_glr_viz_robot_arm_animation_001.png + :alt: viz robot arm animation + :srcset: /auto_examples/10_animation/images/sphx_glr_viz_robot_arm_animation_001.png + :class: sphx-glr-single-img + + + + + + +.. rst-class:: sphx-glr-timing + + **Total running time of the script:** (0 minutes 0.107 seconds) + + +.. _sphx_glr_download_auto_examples_10_animation_viz_robot_arm_animation.py: + +.. only:: html + + .. container:: sphx-glr-footer sphx-glr-footer-example + + .. container:: sphx-glr-download sphx-glr-download-jupyter + + :download:`Download Jupyter notebook: viz_robot_arm_animation.ipynb ` + + .. container:: sphx-glr-download sphx-glr-download-python + + :download:`Download Python source code: viz_robot_arm_animation.py ` + + +.. only:: html + + .. rst-class:: sphx-glr-signature + + `Gallery generated by Sphinx-Gallery `_ diff --git a/v0.10.x/_sources/auto_examples/10_animation/viz_spline_interpolator.rst.txt b/v0.10.x/_sources/auto_examples/10_animation/viz_spline_interpolator.rst.txt new file mode 100644 index 000000000..01b44b835 --- /dev/null +++ b/v0.10.x/_sources/auto_examples/10_animation/viz_spline_interpolator.rst.txt @@ -0,0 +1,290 @@ + +.. DO NOT EDIT. +.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. +.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: +.. "auto_examples/10_animation/viz_spline_interpolator.py" +.. LINE NUMBERS ARE GIVEN BELOW. + +.. only:: html + + .. note:: + :class: sphx-glr-download-link-note + + :ref:`Go to the end ` + to download the full example code + +.. rst-class:: sphx-glr-example-title + +.. _sphx_glr_auto_examples_10_animation_viz_spline_interpolator.py: + + +============================= +Keyframes Spline Interpolator +============================= + +Tutorial on making keyframe-based animation in FURY using Spline interpolators. + +.. GENERATED FROM PYTHON SOURCE LINES 8-22 + +.. code-block:: Python + + + import numpy as np + + from fury import actor, window + from fury.animation import Animation, Timeline + from fury.animation.interpolator import spline_interpolator + + scene = window.Scene() + + showm = window.ShowManager( + scene, size=(900, 768), reset_camera=False, order_transparent=True + ) + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 23-25 + +Position keyframes as a dict object containing timestamps as keys and +positions as values. + +.. GENERATED FROM PYTHON SOURCE LINES 25-34 + +.. code-block:: Python + + position_keyframes = { + 0.0: np.array([0, 0, 0]), + 2.0: np.array([10, 3, 5]), + 4.0: np.array([20, 14, 13]), + 6.0: np.array([-20, 20, 0]), + 8.0: np.array([17, -10, 15]), + 10.0: np.array([0, -6, 0]), + } + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 35-36 + +creating FURY dots to visualize the position values. + +.. GENERATED FROM PYTHON SOURCE LINES 36-38 + +.. code-block:: Python + + pos_dots = actor.dot(np.array(list(position_keyframes.values()))) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 39-41 + +creating two timelines (one uses linear and the other uses' spline +interpolator), each timeline controls a sphere actor + +.. GENERATED FROM PYTHON SOURCE LINES 41-49 + +.. code-block:: Python + + + sphere_linear = actor.sphere(np.array([[0, 0, 0]]), (1, 0.5, 0.2), 0.5) + + linear_anim = Animation() + linear_anim.add_actor(sphere_linear) + + linear_anim.set_position_keyframes(position_keyframes) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 50-52 + +Note: linear_interpolator is used by default. So, no need to set it for this +first animation that we need to linearly interpolate positional animation. + +.. GENERATED FROM PYTHON SOURCE LINES 54-56 + +creating a second timeline that translates another larger sphere actor using +spline interpolator. + +.. GENERATED FROM PYTHON SOURCE LINES 56-60 + +.. code-block:: Python + + sphere_spline = actor.sphere(np.array([[0, 0, 0]]), (0.3, 0.9, 0.6), 1) + spline_anim = Animation(sphere_spline) + spline_anim.set_position_keyframes(position_keyframes) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 61-62 + +Setting 5th degree spline interpolator for position keyframes. + +.. GENERATED FROM PYTHON SOURCE LINES 62-64 + +.. code-block:: Python + + spline_anim.set_position_interpolator(spline_interpolator, degree=5) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 65-69 + +Wrapping animations up! +============================================================================= + +Adding everything to a ``Timeline`` to control the two timelines. + +.. GENERATED FROM PYTHON SOURCE LINES 71-72 + +First we create a timeline with a playback panel: + +.. GENERATED FROM PYTHON SOURCE LINES 72-74 + +.. code-block:: Python + + timeline = Timeline(playback_panel=True) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 75-76 + +Add visualization dots actor to the scene. + +.. GENERATED FROM PYTHON SOURCE LINES 76-78 + +.. code-block:: Python + + scene.add(pos_dots) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 79-80 + +Adding the animations to the timeline (so that it controls their playback). + +.. GENERATED FROM PYTHON SOURCE LINES 80-82 + +.. code-block:: Python + + timeline.add_animation([linear_anim, spline_anim]) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 83-84 + +Adding the timeline to the show manager. + +.. GENERATED FROM PYTHON SOURCE LINES 84-87 + +.. code-block:: Python + + showm.add_animation(timeline) + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 88-90 + +Now that these two animations are added to timeline, if the timeline +is played, paused, ..., all these changes will reflect on the animations. + +.. GENERATED FROM PYTHON SOURCE LINES 90-98 + +.. code-block:: Python + + + + interactive = False + + if interactive: + showm.start() + + window.record(scene, out_path='viz_keyframe_animation_spline.png', size=(900, 768)) + + + +.. image-sg:: /auto_examples/10_animation/images/sphx_glr_viz_spline_interpolator_001.png + :alt: viz spline interpolator + :srcset: /auto_examples/10_animation/images/sphx_glr_viz_spline_interpolator_001.png + :class: sphx-glr-single-img + + + + + + +.. rst-class:: sphx-glr-timing + + **Total running time of the script:** (0 minutes 0.216 seconds) + + +.. _sphx_glr_download_auto_examples_10_animation_viz_spline_interpolator.py: + +.. only:: html + + .. container:: sphx-glr-footer sphx-glr-footer-example + + .. container:: sphx-glr-download sphx-glr-download-jupyter + + :download:`Download Jupyter notebook: viz_spline_interpolator.ipynb ` + + .. container:: sphx-glr-download sphx-glr-download-python + + :download:`Download Python source code: viz_spline_interpolator.py ` + + +.. only:: html + + .. rst-class:: sphx-glr-signature + + `Gallery generated by Sphinx-Gallery `_ diff --git a/v0.10.x/_sources/auto_examples/10_animation/viz_timeline.rst.txt b/v0.10.x/_sources/auto_examples/10_animation/viz_timeline.rst.txt new file mode 100644 index 000000000..3676be917 --- /dev/null +++ b/v0.10.x/_sources/auto_examples/10_animation/viz_timeline.rst.txt @@ -0,0 +1,247 @@ + +.. DO NOT EDIT. +.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. +.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: +.. "auto_examples/10_animation/viz_timeline.py" +.. LINE NUMBERS ARE GIVEN BELOW. + +.. only:: html + + .. note:: + :class: sphx-glr-download-link-note + + :ref:`Go to the end ` + to download the full example code + +.. rst-class:: sphx-glr-example-title + +.. _sphx_glr_auto_examples_10_animation_viz_timeline.py: + + +============================== +Timeline and setting keyframes +============================== + +In his tutorial, you will learn how to use Fury ``Timeline`` for playing the +animations. + +.. GENERATED FROM PYTHON SOURCE LINES 11-18 + +What is ``Timeline``? +===================== + +``Timeline`` is responsible for handling the playback of Fury Animations. + +``Timeline`` has playback methods such as ``play``, ``pause``, ``stop``, ... +which can be used to control the animation. + +.. GENERATED FROM PYTHON SOURCE LINES 18-25 + +.. code-block:: Python + + + + import numpy as np + + from fury import actor, window + from fury.animation import Animation, Timeline + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 26-27 + +We create our ``Scene`` and ``ShowManager`` as usual. + +.. GENERATED FROM PYTHON SOURCE LINES 27-32 + +.. code-block:: Python + + scene = window.Scene() + + showm = window.ShowManager(scene, size=(900, 768)) + showm.initialize() + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 33-38 + +Creating a ``Timeline`` +======================= + +FURY ``Timeline`` has the option to attaches a very useful panel for +controlling the animation by setting ``playback_panel=True``. + +.. GENERATED FROM PYTHON SOURCE LINES 40-41 + +Creating a ``Timeline`` with a PlaybackPanel. + +.. GENERATED FROM PYTHON SOURCE LINES 41-43 + +.. code-block:: Python + + timeline = Timeline(playback_panel=True) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 44-45 + +Creating a Fury Animation as usual + +.. GENERATED FROM PYTHON SOURCE LINES 45-52 + +.. code-block:: Python + + anim = Animation() + sphere = actor.sphere(np.zeros([1, 3]), np.ones([1, 3])) + anim.add_actor(sphere) + # Now that the actor is add to the ``Animation``, setting keyframes to the + # Animation will animate the actor accordingly. + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 53-61 + +Setting Keyframes +================= + +There are multiple ways to set keyframes: + +1- To set a single keyframe, you may use ``animation.set_(t, k)``, +where is the name of the property to be set. I.e. setting position +to (1, 2, 3) at time 0.0 would be as following: + +.. GENERATED FROM PYTHON SOURCE LINES 61-63 + +.. code-block:: Python + + anim.set_position(0.0, np.array([1, 2, 3])) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 64-68 + +Supported properties are: **position, rotation, scale, color, and opacity**. + +2- To set multiple keyframes at once, you may use +``animation.set__keyframes(keyframes)``. + +.. GENERATED FROM PYTHON SOURCE LINES 68-72 + +.. code-block:: Python + + keyframes = {1.0: np.array([0, 0, 0]), 3.0: np.array([-2, 0, 0])} + + anim.set_position_keyframes(keyframes) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 73-74 + +That's it! Now we are done setting keyframes. + +.. GENERATED FROM PYTHON SOURCE LINES 76-78 + +In order to control this animation by the timeline we created earlier, this +animation must be added to the timeline. + +.. GENERATED FROM PYTHON SOURCE LINES 78-80 + +.. code-block:: Python + + timeline.add_animation(anim) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 81-83 + +Now we add only the ``Timeline`` to the ``ShowManager`` the same way we add +``Animation`` to the ``ShowManager``. + +.. GENERATED FROM PYTHON SOURCE LINES 83-93 + +.. code-block:: Python + + showm.add_animation(timeline) + + scene.set_camera(position=(0, 0, -10)) + + interactive = False + + if interactive: + showm.start() + + window.record(scene, out_path='viz_keyframe_animation_timeline.png', size=(900, 768)) + + + +.. image-sg:: /auto_examples/10_animation/images/sphx_glr_viz_timeline_001.png + :alt: viz timeline + :srcset: /auto_examples/10_animation/images/sphx_glr_viz_timeline_001.png + :class: sphx-glr-single-img + + + + + + +.. rst-class:: sphx-glr-timing + + **Total running time of the script:** (0 minutes 0.120 seconds) + + +.. _sphx_glr_download_auto_examples_10_animation_viz_timeline.py: + +.. only:: html + + .. container:: sphx-glr-footer sphx-glr-footer-example + + .. container:: sphx-glr-download sphx-glr-download-jupyter + + :download:`Download Jupyter notebook: viz_timeline.ipynb ` + + .. container:: sphx-glr-download sphx-glr-download-python + + :download:`Download Python source code: viz_timeline.py ` + + +.. only:: html + + .. rst-class:: sphx-glr-signature + + `Gallery generated by Sphinx-Gallery `_ diff --git a/v0.10.x/_sources/auto_examples/10_animation/viz_using_time_equations.rst.txt b/v0.10.x/_sources/auto_examples/10_animation/viz_using_time_equations.rst.txt new file mode 100644 index 000000000..c8dab7e59 --- /dev/null +++ b/v0.10.x/_sources/auto_examples/10_animation/viz_using_time_equations.rst.txt @@ -0,0 +1,218 @@ + +.. DO NOT EDIT. +.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. +.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: +.. "auto_examples/10_animation/viz_using_time_equations.py" +.. LINE NUMBERS ARE GIVEN BELOW. + +.. only:: html + + .. note:: + :class: sphx-glr-download-link-note + + :ref:`Go to the end ` + to download the full example code + +.. rst-class:: sphx-glr-example-title + +.. _sphx_glr_auto_examples_10_animation_viz_using_time_equations.py: + + +===================== +Keyframe animation +===================== + +Tutorial on making keyframe-based animation in FURY using custom functions. + +.. GENERATED FROM PYTHON SOURCE LINES 8-22 + +.. code-block:: Python + + import numpy as np + + from fury import actor, window + from fury.animation import Animation + + scene = window.Scene() + + showm = window.ShowManager( + scene, size=(900, 768), reset_camera=False, order_transparent=True + ) + + + cube = actor.cube(np.array([[0, 0, 0]]), (0, 0, 0), (1, 0, 1), scales=6) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 23-24 + +Creating an ``Animation`` to animate the actor and show its motion path. + +.. GENERATED FROM PYTHON SOURCE LINES 24-26 + +.. code-block:: Python + + anim = Animation(length=2 * np.pi, loop=True, motion_path_res=200) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 27-29 + +Adding the sphere actor to the timeline +This could've been done during initialization. + +.. GENERATED FROM PYTHON SOURCE LINES 29-32 + +.. code-block:: Python + + anim.add_actor(cube) + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 33-34 + +Creating time dependent functions. + +.. GENERATED FROM PYTHON SOURCE LINES 34-56 + +.. code-block:: Python + + def pos_eval(t): + return np.array([np.sin(t), np.cos(t) * np.sin(t), 0]) * 15 + + + def color_eval(t): + return ( + np.array([np.sin(t), np.sin(t - 2 * np.pi / 3), np.sin(t + np.pi / 3)]) + + np.ones(3) + ) / 2 + + + def rotation_eval(t): + return np.array([np.sin(t) * 360, np.cos(t) * 360, 0]) + + + def scale_eval(t): + return ( + np.array([np.sin(t), np.sin(t - 2 * np.pi / 3), np.sin(t + np.pi / 3)]) + + np.ones(3) * 2 + ) / 5 + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 57-60 + +Setting evaluator functions is the same as setting interpolators, but with +one extra argument: `is_evaluator=True` since these functions does not need +keyframes as input. + +.. GENERATED FROM PYTHON SOURCE LINES 60-65 + +.. code-block:: Python + + anim.set_position_interpolator(pos_eval, is_evaluator=True) + anim.set_rotation_interpolator(rotation_eval, is_evaluator=True) + anim.set_color_interpolator(color_eval, is_evaluator=True) + anim.set_interpolator('scale', scale_eval, is_evaluator=True) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 66-67 + +changing camera position to observe the animation better. + +.. GENERATED FROM PYTHON SOURCE LINES 67-69 + +.. code-block:: Python + + scene.set_camera(position=(0, 0, 90)) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 70-71 + +Adding the animation to the show manager. + +.. GENERATED FROM PYTHON SOURCE LINES 71-80 + +.. code-block:: Python + + showm.add_animation(anim) + + + interactive = False + + if interactive: + showm.start() + + window.record(scene, out_path='viz_keyframe_animation_evaluators.png', size=(900, 768)) + + + +.. image-sg:: /auto_examples/10_animation/images/sphx_glr_viz_using_time_equations_001.png + :alt: viz using time equations + :srcset: /auto_examples/10_animation/images/sphx_glr_viz_using_time_equations_001.png + :class: sphx-glr-single-img + + + + + + +.. rst-class:: sphx-glr-timing + + **Total running time of the script:** (0 minutes 0.120 seconds) + + +.. _sphx_glr_download_auto_examples_10_animation_viz_using_time_equations.py: + +.. only:: html + + .. container:: sphx-glr-footer sphx-glr-footer-example + + .. container:: sphx-glr-download sphx-glr-download-jupyter + + :download:`Download Jupyter notebook: viz_using_time_equations.ipynb ` + + .. container:: sphx-glr-download sphx-glr-download-python + + :download:`Download Python source code: viz_using_time_equations.py ` + + +.. only:: html + + .. rst-class:: sphx-glr-signature + + `Gallery generated by Sphinx-Gallery `_ diff --git a/v0.10.x/_sources/auto_examples/13_shaders/index.rst.txt b/v0.10.x/_sources/auto_examples/13_shaders/index.rst.txt new file mode 100644 index 000000000..1f1797176 --- /dev/null +++ b/v0.10.x/_sources/auto_examples/13_shaders/index.rst.txt @@ -0,0 +1,136 @@ + + +.. _sphx_glr_auto_examples_13_shaders: + +Shaders +------- + +These tutorials show: + +- How to use shaders in FURY actors. +- How to create new user shaders and internal conventions. + + + +.. raw:: html + +
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/13_shaders/images/thumb/sphx_glr_viz_sdfactor_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_13_shaders_viz_sdfactor.py` + +.. raw:: html + +
Visualize SDF Actor
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/13_shaders/images/thumb/sphx_glr_viz_principled_spheres_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_13_shaders_viz_principled_spheres.py` + +.. raw:: html + +
Principled BRDF shader on spheres
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/13_shaders/images/thumb/sphx_glr_viz_shader_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_13_shaders_viz_shader.py` + +.. raw:: html + +
Varying Color
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/13_shaders/images/thumb/sphx_glr_viz_pbr_spheres_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_13_shaders_viz_pbr_spheres.py` + +.. raw:: html + +
Physically-Based Rendering (PBR) on spheres
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/13_shaders/images/thumb/sphx_glr_viz_billboard_sdf_spheres_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_13_shaders_viz_billboard_sdf_spheres.py` + +.. raw:: html + +
SDF Impostors on Billboards
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/13_shaders/images/thumb/sphx_glr_viz_sdf_cylinder_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_13_shaders_viz_sdf_cylinder.py` + +.. raw:: html + +
Make a Cylinder using polygons vs SDF
+
+ + +.. raw:: html + +
+ + +.. toctree:: + :hidden: + + /auto_examples/13_shaders/viz_sdfactor + /auto_examples/13_shaders/viz_principled_spheres + /auto_examples/13_shaders/viz_shader + /auto_examples/13_shaders/viz_pbr_spheres + /auto_examples/13_shaders/viz_billboard_sdf_spheres + /auto_examples/13_shaders/viz_sdf_cylinder + diff --git a/v0.10.x/_sources/auto_examples/13_shaders/sg_execution_times.rst.txt b/v0.10.x/_sources/auto_examples/13_shaders/sg_execution_times.rst.txt new file mode 100644 index 000000000..ea3f6778c --- /dev/null +++ b/v0.10.x/_sources/auto_examples/13_shaders/sg_execution_times.rst.txt @@ -0,0 +1,52 @@ + +:orphan: + +.. _sphx_glr_auto_examples_13_shaders_sg_execution_times: + + +Computation times +================= +**00:01.540** total execution time for 6 files **from auto_examples/13_shaders**: + +.. container:: + + .. raw:: html + + + + + + + + .. list-table:: + :header-rows: 1 + :class: table table-striped sg-datatable + + * - Example + - Time + - Mem (MB) + * - :ref:`sphx_glr_auto_examples_13_shaders_viz_principled_spheres.py` (``viz_principled_spheres.py``) + - 00:00.608 + - 0.0 + * - :ref:`sphx_glr_auto_examples_13_shaders_viz_billboard_sdf_spheres.py` (``viz_billboard_sdf_spheres.py``) + - 00:00.333 + - 0.0 + * - :ref:`sphx_glr_auto_examples_13_shaders_viz_shader.py` (``viz_shader.py``) + - 00:00.216 + - 0.0 + * - :ref:`sphx_glr_auto_examples_13_shaders_viz_sdf_cylinder.py` (``viz_sdf_cylinder.py``) + - 00:00.208 + - 0.0 + * - :ref:`sphx_glr_auto_examples_13_shaders_viz_pbr_spheres.py` (``viz_pbr_spheres.py``) + - 00:00.176 + - 0.0 + * - :ref:`sphx_glr_auto_examples_13_shaders_viz_sdfactor.py` (``viz_sdfactor.py``) + - 00:00.000 + - 0.0 diff --git a/v0.10.x/_sources/auto_examples/13_shaders/viz_billboard_sdf_spheres.rst.txt b/v0.10.x/_sources/auto_examples/13_shaders/viz_billboard_sdf_spheres.rst.txt new file mode 100644 index 000000000..009459137 --- /dev/null +++ b/v0.10.x/_sources/auto_examples/13_shaders/viz_billboard_sdf_spheres.rst.txt @@ -0,0 +1,710 @@ + +.. DO NOT EDIT. +.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. +.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: +.. "auto_examples/13_shaders/viz_billboard_sdf_spheres.py" +.. LINE NUMBERS ARE GIVEN BELOW. + +.. only:: html + + .. note:: + :class: sphx-glr-download-link-note + + :ref:`Go to the end ` + to download the full example code + +.. rst-class:: sphx-glr-example-title + +.. _sphx_glr_auto_examples_13_shaders_viz_billboard_sdf_spheres.py: + + +=============================================================================== +SDF Impostors on Billboards +=============================================================================== + +Traditional rendering engines discretize surfaces using triangles or +quadrilateral polygons. The visual quality of these elements depends on the +number of polygons used to build the 3D mesh, i.e., a smoother surface will +require more polygons. However, increasing the amount of rendered polygons +comes at the cost of performance as it decreases the number of frames per +second (FPS), which might compromise the real-time interactivity of a +visualization. + +Billboarding is a technique that changes an object's orientation to always face +a specific direction, in most cases, the camera. This technique became popular +in games and applications with a high polygonal quota requirement. + +Signed Distance Functions (SDFs) are mathematical functions that take as input +a point in a metric space and return the distance from that point to the +boundary of the function. Depending on whether the point is contained within +this boundary or outside it, the function will return negative or positive +values [Hart1996]_. For visualization purposes, the task is to display only the +points within the boundary or, in other words, those whose distance to the +border is either negative or positive, depending on the definition of the SDF. + +This tutorial exemplifies why FURY's billboard actor is a suitable rendering +option when thinking about performance and how it can be used to create +impostors using SDFs. + +Let's start by importing the necessary modules: + +.. GENERATED FROM PYTHON SOURCE LINES 32-41 + +.. code-block:: Python + + + import os + + import numpy as np + + from fury import actor, window + from fury.shaders import compose_shader, import_fury_shader + from fury.utils import represent_actor_as_wireframe + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 42-43 + +Now set up a new scene to place our actors in. + +.. GENERATED FROM PYTHON SOURCE LINES 43-45 + +.. code-block:: Python + + scene = window.Scene() + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 46-48 + +This tutorial is divided into two parts. First, we will render spheres in the +traditional way and then render them using SDFs on billboards. + +.. GENERATED FROM PYTHON SOURCE LINES 50-54 + +Traditional sphere rendering +============================ +FURY provides an easy way to create sphere glyphs from numpy arrays as +follows: + +.. GENERATED FROM PYTHON SOURCE LINES 54-64 + +.. code-block:: Python + + centers = np.array([ + [0, 0, 0], [-6, -6, -6], [8, 8, 8], [8.5, 9.5, 9.5], [10, -10, 10], + [-13, 13, -13], [-17, -17, 17]]) + colors = np.array([ + [1, 1, 0], [1, 0, 1], [0, 0, 1], [1, 1, 1], [1, 0, 0], [0, 1, 0], + [0, 1, 1]]) + scales = np.array([6, 1.2, 1, .2, .7, 3, 2]) + spheres_actor = actor.sphere( + centers, colors, radii=scales, phi=8, theta=8, use_primitive=False) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 65-68 + +To interactively visualize the recently created actors, we only need to add +them to the previously created `scene` and set the following variable to +**True**, otherwise, we will screenshot the scene. + +.. GENERATED FROM PYTHON SOURCE LINES 68-77 + +.. code-block:: Python + + scene.add(spheres_actor) + + interactive = False + + if interactive: + window.show(scene) + else: + window.record(scene, size=(600, 600), out_path='viz_regular_spheres.png') + + + + +.. image-sg:: /auto_examples/13_shaders/images/sphx_glr_viz_billboard_sdf_spheres_001.png + :alt: viz billboard sdf spheres + :srcset: /auto_examples/13_shaders/images/sphx_glr_viz_billboard_sdf_spheres_001.png + :class: sphx-glr-single-img + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 78-82 + +Now, let's explore our scene to understand what we have created. Traditional +FURY spheres are designed using a set of interconnected triangles. To +visualize them, we want to transform our representation from *Surface* to +*Wireframe* using the following command. + +.. GENERATED FROM PYTHON SOURCE LINES 82-89 + +.. code-block:: Python + + represent_actor_as_wireframe(spheres_actor) + + if interactive: + window.show(scene) + else: + window.record(scene, size=(600, 600), out_path='viz_low_res_wireframe.png') + + + + +.. image-sg:: /auto_examples/13_shaders/images/sphx_glr_viz_billboard_sdf_spheres_002.png + :alt: viz billboard sdf spheres + :srcset: /auto_examples/13_shaders/images/sphx_glr_viz_billboard_sdf_spheres_002.png + :class: sphx-glr-single-img + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 90-91 + +Let's clean the scene and play with the parameters `phi` and `theta`. + +.. GENERATED FROM PYTHON SOURCE LINES 91-102 + +.. code-block:: Python + + scene.clear() + spheres_actor = actor.sphere( + centers, colors, radii=scales, phi=16, theta=16, use_primitive=False) + represent_actor_as_wireframe(spheres_actor) + scene.add(spheres_actor) + + if interactive: + window.show(scene) + else: + window.record(scene, size=(600, 600), out_path='viz_hi_res_wireframe.png') + + + + +.. image-sg:: /auto_examples/13_shaders/images/sphx_glr_viz_billboard_sdf_spheres_003.png + :alt: viz billboard sdf spheres + :srcset: /auto_examples/13_shaders/images/sphx_glr_viz_billboard_sdf_spheres_003.png + :class: sphx-glr-single-img + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 103-108 + +As you might have noticed, these parameters control the resolution of the +spheres. Evidently, these parameters directly impact the quality of the +visualization, but increasing such resolution comes at the cost of +performance, i.e., more computing power will be needed and drawn to interact +with these actors. + +.. GENERATED FROM PYTHON SOURCE LINES 110-113 + +Luckily for us, a technique delivers high-resolution glyphs at a much lower +cost. This technique is known as Signed Distance Functions (SDFs), and they +work as follows: + +.. GENERATED FROM PYTHON SOURCE LINES 115-119 + +SDF sphere rendering +==================== +It is possible to render SDFs in FURY by using the following configuration, +but first, let's clear the scene. + +.. GENERATED FROM PYTHON SOURCE LINES 119-121 + +.. code-block:: Python + + scene.clear() + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 122-124 + +The billboard actor is suited and continuously improved to render SDFs. To +create and visualize it, we can use the following instructions: + +.. GENERATED FROM PYTHON SOURCE LINES 124-134 + +.. code-block:: Python + + billboards_actor = actor.billboard(centers, colors=colors, scales=scales) + represent_actor_as_wireframe(billboards_actor) + scene.add(billboards_actor) + + if interactive: + window.show(scene) + else: + window.record( + scene, size=(600, 600), out_path='viz_billboards_wireframe.png') + + + + +.. image-sg:: /auto_examples/13_shaders/images/sphx_glr_viz_billboard_sdf_spheres_004.png + :alt: viz billboard sdf spheres + :srcset: /auto_examples/13_shaders/images/sphx_glr_viz_billboard_sdf_spheres_004.png + :class: sphx-glr-single-img + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 135-139 + +If you interacted with this actor, you might have noticed how it always +aligned itself to the camera or, in other words, your FURY window. Now that +we know how billboards work, we can start working on our Signed Distance +Spheres. Let's clear our scene first. + +.. GENERATED FROM PYTHON SOURCE LINES 139-141 + +.. code-block:: Python + + scene.clear() + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 142-144 + +FURY already includes a shader function with the definition of a Signed +Distance Sphere. So we can load it and use it like this: + +.. GENERATED FROM PYTHON SOURCE LINES 144-146 + +.. code-block:: Python + + sd_sphere = import_fury_shader(os.path.join('sdf', 'sd_sphere.frag')) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 147-150 + +Additionally, we need to define the radii of our spheres. Since we prefer +these to be determined by the billboards' size, we will use the maximum +radius distance allowed by our billboards. + +.. GENERATED FROM PYTHON SOURCE LINES 150-152 + +.. code-block:: Python + + sphere_radius = 'const float RADIUS = 1.;' + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 153-155 + +Let's calculate the distance to the sphere by combining the previously +defined variables. + +.. GENERATED FROM PYTHON SOURCE LINES 155-157 + +.. code-block:: Python + + sphere_dist = 'float dist = sdSphere(point, RADIUS);' + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 158-159 + +Now, evaluate the signed distance function. + +.. GENERATED FROM PYTHON SOURCE LINES 159-167 + +.. code-block:: Python + + sdf_eval = \ + """ + if (dist < 0) + fragOutput0 = vec4(color, opacity); + else + discard; + """ + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 168-170 + +Putting all of our declarations (constants and function) and implementations +(distance calculation and evaluation) together. + +.. GENERATED FROM PYTHON SOURCE LINES 170-173 + +.. code-block:: Python + + fs_dec = compose_shader([sphere_radius, sd_sphere]) + fs_impl = compose_shader([sphere_dist, sdf_eval]) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 174-175 + +We are ready to create and visualize our SDF-billboard actors. + +.. GENERATED FROM PYTHON SOURCE LINES 175-185 + +.. code-block:: Python + + spheres_actor = actor.billboard( + centers, colors=colors, scales=scales, fs_dec=fs_dec, fs_impl=fs_impl) + scene.add(spheres_actor) + + if interactive: + window.show(scene) + else: + window.record( + scene, size=(600, 600), out_path='viz_billboards_circles.png') + + + + +.. image-sg:: /auto_examples/13_shaders/images/sphx_glr_viz_billboard_sdf_spheres_005.png + :alt: viz billboard sdf spheres + :srcset: /auto_examples/13_shaders/images/sphx_glr_viz_billboard_sdf_spheres_005.png + :class: sphx-glr-single-img + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 186-190 + +Hold on, those actors don't look exactly like the ones we created using +traditional techniques; they don't even look 3D but 2D. Well, that's because +we still need an essential component: shading. So let's clear our scene and +add shading to our SDF billboard actors. + +.. GENERATED FROM PYTHON SOURCE LINES 190-192 + +.. code-block:: Python + + scene.clear() + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 193-198 + +The first thing necessary to add shading to our SDF-billboard actors is to +calculate the normals of the SDFs. In this tutorial we are not going to get +into detail in the gradient and derivatives of SDFs, so we will use the +central differences technique implemented in the following FURY shader +function: + +.. GENERATED FROM PYTHON SOURCE LINES 198-201 + +.. code-block:: Python + + central_diffs_normal = import_fury_shader( + os.path.join('sdf', 'central_diffs.frag')) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 202-204 + +To use the central differences technique, we need to define a map function +that wraps our SDF and evaluates only a point. + +.. GENERATED FROM PYTHON SOURCE LINES 204-212 + +.. code-block:: Python + + sd_sphere_normal = \ + """ + float map(vec3 p) + { + return sdSphere(p, RADIUS); + } + """ + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 213-214 + +Then we can load the Blinn-Phong illumination model. + +.. GENERATED FROM PYTHON SOURCE LINES 214-217 + +.. code-block:: Python + + blinn_phong_model = import_fury_shader( + os.path.join('lighting', 'blinn_phong_model.frag')) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 218-220 + +Again, let's bring all of our declarations (constants and functions) +together. + +.. GENERATED FROM PYTHON SOURCE LINES 220-224 + +.. code-block:: Python + + fs_dec = compose_shader([ + sphere_radius, sd_sphere, sd_sphere_normal, central_diffs_normal, + blinn_phong_model]) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 225-230 + +Now, we can start our fragment shader implementation with the signed distance +function evaluation. You might notice that in this case, we are not using an +if statement but a `step` function, which is a more efficient way to perform +this evaluation. You can also replace the `step` function with a `smoothstep` +operation and, in that way, add a very efficient form of antialiasing. + +.. GENERATED FROM PYTHON SOURCE LINES 230-232 + +.. code-block:: Python + + sdf_eval = 'opacity *= 1 - step(0, dist);' + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 233-235 + +In this case, we also need the absolute value of the distance to compensate +for the depth of the SDF sphere. + +.. GENERATED FROM PYTHON SOURCE LINES 235-237 + +.. code-block:: Python + + abs_dist = 'float absDist = abs(dist);' + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 238-239 + +We are ready to calculate the normals. + +.. GENERATED FROM PYTHON SOURCE LINES 239-241 + +.. code-block:: Python + + normal = 'vec3 normal = centralDiffsNormals(vec3(point.xy, absDist), .0001);' + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 242-243 + +With the normals we can calculate a light attenuation factor. + +.. GENERATED FROM PYTHON SOURCE LINES 243-245 + +.. code-block:: Python + + light_attenuation = 'float lightAttenuation = normal.z;' + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 246-247 + +Now, we are ready to calculate the color and output it. + +.. GENERATED FROM PYTHON SOURCE LINES 247-256 + +.. code-block:: Python + + color = \ + """ + color = blinnPhongIllumModel( + lightAttenuation, lightColor0, diffuseColor, specularPower, + specularColor, ambientColor); + """ + + frag_output = 'fragOutput0 = vec4(color, opacity);' + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 257-258 + +As before, we can bring our implementation code together. + +.. GENERATED FROM PYTHON SOURCE LINES 258-262 + +.. code-block:: Python + + fs_impl = compose_shader([ + sphere_dist, sdf_eval, abs_dist, normal, light_attenuation, color, + frag_output]) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 263-264 + +Finally, recreate the SDF billboard actors and visualize them. + +.. GENERATED FROM PYTHON SOURCE LINES 264-274 + +.. code-block:: Python + + spheres_actor = actor.billboard( + centers, colors=colors, scales=scales, fs_dec=fs_dec, fs_impl=fs_impl) + scene.add(spheres_actor) + + if interactive: + window.show(scene) + else: + window.record( + scene, size=(600, 600), out_path='viz_billboards_spheres.png') + + + + +.. image-sg:: /auto_examples/13_shaders/images/sphx_glr_viz_billboard_sdf_spheres_006.png + :alt: viz billboard sdf spheres + :srcset: /auto_examples/13_shaders/images/sphx_glr_viz_billboard_sdf_spheres_006.png + :class: sphx-glr-single-img + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 275-282 + +References +---------- +.. [Hart1996] Hart, John C. "Sphere tracing: A geometric method for the + antialiased ray tracing of implicit surfaces." The Visual + Computer 12.10 (1996): 527-545. + +.. include:: ../links_names.inc + + +.. rst-class:: sphx-glr-timing + + **Total running time of the script:** (0 minutes 0.333 seconds) + + +.. _sphx_glr_download_auto_examples_13_shaders_viz_billboard_sdf_spheres.py: + +.. only:: html + + .. container:: sphx-glr-footer sphx-glr-footer-example + + .. container:: sphx-glr-download sphx-glr-download-jupyter + + :download:`Download Jupyter notebook: viz_billboard_sdf_spheres.ipynb ` + + .. container:: sphx-glr-download sphx-glr-download-python + + :download:`Download Python source code: viz_billboard_sdf_spheres.py ` + + +.. only:: html + + .. rst-class:: sphx-glr-signature + + `Gallery generated by Sphinx-Gallery `_ diff --git a/v0.10.x/_sources/auto_examples/13_shaders/viz_pbr_spheres.rst.txt b/v0.10.x/_sources/auto_examples/13_shaders/viz_pbr_spheres.rst.txt new file mode 100644 index 000000000..b79265818 --- /dev/null +++ b/v0.10.x/_sources/auto_examples/13_shaders/viz_pbr_spheres.rst.txt @@ -0,0 +1,308 @@ + +.. DO NOT EDIT. +.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. +.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: +.. "auto_examples/13_shaders/viz_pbr_spheres.py" +.. LINE NUMBERS ARE GIVEN BELOW. + +.. only:: html + + .. note:: + :class: sphx-glr-download-link-note + + :ref:`Go to the end ` + to download the full example code + +.. rst-class:: sphx-glr-example-title + +.. _sphx_glr_auto_examples_13_shaders_viz_pbr_spheres.py: + + +=============================================================================== +Physically-Based Rendering (PBR) on spheres +=============================================================================== + +PBR engines aim to simulate properties of light when it interacts with objects +in the scene in a physically plausible way. The interaction of light with an +object depends on the material the object is made of. In computer graphics, +materials are usually divided in 2 main categories based on their conductive +properties: dielectrics and metals. + +This tutorial, illustrates how to model some material properties in FURY by +using the PBR material. + +Let's start by importing the necessary modules: + +.. GENERATED FROM PYTHON SOURCE LINES 17-27 + +.. code-block:: Python + + + import numpy as np + + from fury import actor, material, window + from fury.utils import ( + normals_from_actor, + tangents_from_direction_of_anisotropy, + tangents_to_actor, + ) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 28-29 + +Now set up a new scene. + +.. GENERATED FROM PYTHON SOURCE LINES 29-33 + +.. code-block:: Python + + + scene = window.Scene() + scene.background((0.9, 0.9, 0.9)) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 34-36 + +Let's define the parameters we are going to showcase in this tutorial. +These subset of parameters have their values constrained in the 0 to 1 range. + +.. GENERATED FROM PYTHON SOURCE LINES 36-49 + +.. code-block:: Python + + + material_params = [ + [[1, 1, 0], {'metallic': 0, 'roughness': 0}], + [(0, 0, 1), {'roughness': 0}], + [(1, 0, 1), {'anisotropy': 0, 'metallic': 0.25, 'roughness': 0.5}], + [ + (1, 0, 1), + {'anisotropy_rotation': 0, 'anisotropy': 1, 'metallic': 0.25, 'roughness': 0.5}, + ], + [(0, 1, 1), {'coat_strength': 0, 'roughness': 0}], + [(0, 1, 1), {'coat_roughness': 0, 'coat_strength': 1, 'roughness': 0}], + ] + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 50-53 + +Now we can start to add our actors to the scene and see how different values +of the parameters produce interesting effects. For the purpose of this +tutorial, we will see the effect of 11 different values of each parameter. + +.. GENERATED FROM PYTHON SOURCE LINES 53-71 + +.. code-block:: Python + + + num_values = 11 + + for i, mp in enumerate(material_params): + color = mp[0] + params = mp[1] + center = [[0, -5 * i, 0]] + for j in range(num_values): + center[0][0] = -25 + 5 * j + sphere = actor.sphere(center, color, radii=2, theta=32, phi=32) + normals = normals_from_actor(sphere) + tangents = tangents_from_direction_of_anisotropy(normals, (0, 1, 0.5)) + tangents_to_actor(sphere, tangents) + keys = list(params) + params[keys[0]] = np.round(0.1 * j, decimals=1) + material.manifest_pbr(sphere, **params) + scene.add(sphere) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 72-74 + +For interpretability purposes we will add some labels to guide us through our +visualization. + +.. GENERATED FROM PYTHON SOURCE LINES 74-99 + +.. code-block:: Python + + + labels = [ + 'Metallic', + 'Roughness', + 'Anisotropy', + 'Anisotropy Rotation', + 'Coat Strength', + 'Coat Roughness', + ] + + for i, l in enumerate(labels): + pos = [-40, -5 * i, 0] + label = actor.vector_text(l, pos=pos, scale=(0.8, 0.8, 0.8), color=(0, 0, 0)) + scene.add(label) + + for j in range(num_values): + pos = [-26 + 5 * j, 3, 0] + label = actor.vector_text( + str(np.round(j * 0.1, decimals=1)), + pos=pos, + scale=(0.8, 0.8, 0.8), + color=(0, 0, 0), + ) + scene.add(label) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 100-104 + +Some parameters of this material have their values constrained to be between +1 and 2.3. These parameters are the Base Index of Refraction (IOR) and the +Clear coat Index of Refraction (IOR). Therefore, we will interpolate some +values within this range and see how they affect the rendering. + +.. GENERATED FROM PYTHON SOURCE LINES 104-132 + +.. code-block:: Python + + + iors = np.round(np.linspace(1, 2.3, num=num_values), decimals=2) + + ior_params = [ + [(0, 1, 1), {'base_ior': iors[0], 'roughness': 0}], + [ + (0, 1, 1), + { + 'coat_ior': iors[0], + 'coat_roughness': 0.1, + 'coat_strength': 1, + 'roughness': 0, + }, + ], + ] + + for i, iorp in enumerate(ior_params): + color = iorp[0] + params = iorp[1] + center = [[0, -35 - (5 * i), 0]] + for j in range(num_values): + center[0][0] = -25 + 5 * j + sphere = actor.sphere(center, color, radii=2, theta=32, phi=32) + keys = list(params) + params[keys[0]] = iors[j] + material.manifest_pbr(sphere, **params) + scene.add(sphere) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 133-134 + +Let's add the respective labels to the scene. + +.. GENERATED FROM PYTHON SOURCE LINES 134-149 + +.. code-block:: Python + + + labels = ['Base IoR', 'Coat IoR'] + + for i, l in enumerate(labels): + pos = [-40, -35 - (5 * i), 0] + label = actor.vector_text(l, pos=pos, scale=(0.8, 0.8, 0.8), color=(0, 0, 0)) + scene.add(label) + + for j in range(num_values): + pos = [-26 + 5 * j, -32, 0] + label = actor.vector_text( + '{:.02f}'.format(iors[j]), pos=pos, scale=(0.8, 0.8, 0.8), color=(0, 0, 0) + ) + scene.add(label) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 150-151 + +Finally, let's visualize our tutorial. + +.. GENERATED FROM PYTHON SOURCE LINES 151-157 + +.. code-block:: Python + + + interactive = False + if interactive: + window.show(scene) + + window.record(scene, size=(600, 600), out_path='viz_pbr_spheres.png') + + + +.. image-sg:: /auto_examples/13_shaders/images/sphx_glr_viz_pbr_spheres_001.png + :alt: viz pbr spheres + :srcset: /auto_examples/13_shaders/images/sphx_glr_viz_pbr_spheres_001.png + :class: sphx-glr-single-img + + + + + + +.. rst-class:: sphx-glr-timing + + **Total running time of the script:** (0 minutes 0.176 seconds) + + +.. _sphx_glr_download_auto_examples_13_shaders_viz_pbr_spheres.py: + +.. only:: html + + .. container:: sphx-glr-footer sphx-glr-footer-example + + .. container:: sphx-glr-download sphx-glr-download-jupyter + + :download:`Download Jupyter notebook: viz_pbr_spheres.ipynb ` + + .. container:: sphx-glr-download sphx-glr-download-python + + :download:`Download Python source code: viz_pbr_spheres.py ` + + +.. only:: html + + .. rst-class:: sphx-glr-signature + + `Gallery generated by Sphinx-Gallery `_ diff --git a/v0.10.x/_sources/auto_examples/13_shaders/viz_principled_spheres.rst.txt b/v0.10.x/_sources/auto_examples/13_shaders/viz_principled_spheres.rst.txt new file mode 100644 index 000000000..a3fd9aeb2 --- /dev/null +++ b/v0.10.x/_sources/auto_examples/13_shaders/viz_principled_spheres.rst.txt @@ -0,0 +1,233 @@ + +.. DO NOT EDIT. +.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. +.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: +.. "auto_examples/13_shaders/viz_principled_spheres.py" +.. LINE NUMBERS ARE GIVEN BELOW. + +.. only:: html + + .. note:: + :class: sphx-glr-download-link-note + + :ref:`Go to the end ` + to download the full example code + +.. rst-class:: sphx-glr-example-title + +.. _sphx_glr_auto_examples_13_shaders_viz_principled_spheres.py: + + +=============================================================================== +Principled BRDF shader on spheres +=============================================================================== + +The Principled Bidirectional Reflectance Distribution Function ([BRDF] +(https://en.wikipedia.org/wiki/Bidirectional_reflectance_distribution_function) +) was introduced by Brent Burley as part of the [SIGGRAPH 2012 Physically Based +Shading course] +(https://blog.selfshadow.com/publications/s2012-shading-course/). Although it +is not strictly physically based, it was designed so the parameters included +could model materials in the [MERL 100](https://www.merl.com/brdf/) (Material +Exchange and Research Library) database. Moreover, each parameter was +carefully chosen and limited to be easy to use and understand, so that +blending multiple layers together would give intuitive results. + +In this demo, we showcase our implementation of the Principled BRDF in FURY. + +Let's start by importing the necessary modules: + +.. GENERATED FROM PYTHON SOURCE LINES 21-26 + +.. code-block:: Python + + + import numpy as np + + from fury import actor, material, window + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 27-28 + +Now set up a new scene. + +.. GENERATED FROM PYTHON SOURCE LINES 28-32 + +.. code-block:: Python + + + scene = window.Scene() + scene.background((0.9, 0.9, 0.9)) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 33-37 + +Let's define the parameters needed for our demo. In this demo we will see the +effect of each one of the 10 parameters defined by the Principled shader. +For interpretability and usability purposes, each parameter is limited to +values between the range 0 to 1. + +.. GENERATED FROM PYTHON SOURCE LINES 37-51 + +.. code-block:: Python + + + material_params = [ + [(1, 1, 1), {'subsurface': 0}], + [[1, 1, 0], {'metallic': 0}], + [(1, 0, 0), {'specular': 0}], + [(1, 0, 0), {'specular_tint': 0, 'specular': 1}], + [(0, 0, 1), {'roughness': 0}], + [(1, 0, 1), {'anisotropic': 0, 'metallic': 0.25, 'roughness': 0.5}], + [[0, 1, 0.5], {'sheen': 0}], + [(0, 1, 0.5), {'sheen_tint': 0, 'sheen': 1}], + [(0, 1, 1), {'clearcoat': 0}], + [(0, 1, 1), {'clearcoat_gloss': 0, 'clearcoat': 1}], + ] + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 52-54 + +We can start to add our actors to the scene and see how different values of +the parameters produce interesting effects. + +.. GENERATED FROM PYTHON SOURCE LINES 54-67 + +.. code-block:: Python + + + for i in range(10): + center = np.array([[0, -5 * i, 0]]) + for j in range(11): + center[0][0] = -25 + 5 * j + sphere = actor.sphere( + center, colors=material_params[i][0], radii=2, theta=32, phi=32 + ) + keys = list(material_params[i][1]) + material_params[i][1][keys[0]] = np.round(0.1 * j, decimals=1) + material.manifest_principled(sphere, **material_params[i][1]) + scene.add(sphere) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 68-69 + +Finally, let's add some labels to guide us through our visualization. + +.. GENERATED FROM PYTHON SOURCE LINES 69-100 + +.. code-block:: Python + + + labels = [ + 'Subsurface', + 'Metallic', + 'Specular', + 'Specular Tint', + 'Roughness', + 'Anisotropic', + 'Sheen', + 'Sheen Tint', + 'Clearcoat', + 'Clearcoat Gloss', + ] + + for i in range(10): + pos = [-40, -5 * i, 0] + label = actor.vector_text( + labels[i], pos=pos, scale=(0.8, 0.8, 0.8), color=(0, 0, 0) + ) + scene.add(label) + + for j in range(11): + pos = [-26 + 5 * j, 5, 0] + label = actor.vector_text( + str(np.round(j * 0.1, decimals=1)), + pos=pos, + scale=(0.8, 0.8, 0.8), + color=(0, 0, 0), + ) + scene.add(label) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 101-102 + +And visualize our demo. + +.. GENERATED FROM PYTHON SOURCE LINES 102-108 + +.. code-block:: Python + + + interactive = False + if interactive: + window.show(scene) + + window.record(scene, size=(600, 600), out_path='viz_principled_spheres.png') + + + +.. image-sg:: /auto_examples/13_shaders/images/sphx_glr_viz_principled_spheres_001.png + :alt: viz principled spheres + :srcset: /auto_examples/13_shaders/images/sphx_glr_viz_principled_spheres_001.png + :class: sphx-glr-single-img + + + + + + +.. rst-class:: sphx-glr-timing + + **Total running time of the script:** (0 minutes 0.608 seconds) + + +.. _sphx_glr_download_auto_examples_13_shaders_viz_principled_spheres.py: + +.. only:: html + + .. container:: sphx-glr-footer sphx-glr-footer-example + + .. container:: sphx-glr-download sphx-glr-download-jupyter + + :download:`Download Jupyter notebook: viz_principled_spheres.ipynb ` + + .. container:: sphx-glr-download sphx-glr-download-python + + :download:`Download Python source code: viz_principled_spheres.py ` + + +.. only:: html + + .. rst-class:: sphx-glr-signature + + `Gallery generated by Sphinx-Gallery `_ diff --git a/v0.10.x/_sources/auto_examples/13_shaders/viz_sdf_cylinder.rst.txt b/v0.10.x/_sources/auto_examples/13_shaders/viz_sdf_cylinder.rst.txt new file mode 100644 index 000000000..be5795e6b --- /dev/null +++ b/v0.10.x/_sources/auto_examples/13_shaders/viz_sdf_cylinder.rst.txt @@ -0,0 +1,693 @@ + +.. DO NOT EDIT. +.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. +.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: +.. "auto_examples/13_shaders/viz_sdf_cylinder.py" +.. LINE NUMBERS ARE GIVEN BELOW. + +.. only:: html + + .. note:: + :class: sphx-glr-download-link-note + + :ref:`Go to the end ` + to download the full example code + +.. rst-class:: sphx-glr-example-title + +.. _sphx_glr_auto_examples_13_shaders_viz_sdf_cylinder.py: + + +=============================================================================== +Make a Cylinder using polygons vs SDF +=============================================================================== +This tutorial is intended to show two ways of primitives creation with the use +of polygons, and Signed Distance Functions (SDFs). We will use cylinders as an +example since they have a simpler polygonal representation. Hence, it allows us +to see better the difference between using one or the other method. + +For the cylinder representation with polygons, we will use cylinder actor +implementation on FURY, and for the visualization using SDFs, we will +implement shader code to create the cylinder and use a box actor to put our +implementation inside. + +We start by importing the necessary modules: + +.. GENERATED FROM PYTHON SOURCE LINES 17-30 + +.. code-block:: Python + + + import os + + import numpy as np + + from fury import actor, window + from fury.shaders import ( + attribute_to_actor, + compose_shader, + import_fury_shader, + shader_to_actor, + ) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 31-42 + +Cylinder using polygons +======================= +Polygons-based modeling, use smaller components namely triangles or polygons +to represent 3D objects. Each polygon is defined by the position of its +vertices and its connecting edges. In order to get a better representation +of an object, it may be necessary to increase the number of polygons in the +model, which is translated into the use of more space to store data and more +rendering time to display the object. + +Now we define some properties of our actors, use them to create a set of +cylinders, and add them to the scene. + +.. GENERATED FROM PYTHON SOURCE LINES 42-85 + +.. code-block:: Python + + + centers = np.array( + [ + [-3.2, 0.9, 0.4], + [-3.5, -0.5, 1], + [-2.1, 0, 0.4], + [-0.2, 0.9, 0.4], + [-0.5, -0.5, 1], + [0.9, 0, 0.4], + [2.8, 0.9, 1.4], + [2.5, -0.5, 2], + [3.9, 0, 1.4], + ] + ) + dirs = np.array( + [ + [-0.2, 0.9, 0.4], + [-0.5, -0.5, 1], + [0.9, 0, 0.4], + [-0.2, 0.9, 0.4], + [-0.5, -0.5, 1], + [0.9, 0, 0.4], + [-0.2, 0.9, 0.4], + [-0.5, -0.5, 1], + [0.9, 0, 0.4], + ] + ) + colors = np.array( + [ + [1, 0, 0], + [1, 0, 0], + [1, 0, 0], + [0, 1, 0], + [0, 1, 0], + [0, 1, 0], + [0, 0, 1], + [0, 0, 1], + [0, 0, 1], + ] + ) + radius = 0.5 + height = 1 + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 86-89 + +In order to see how cylinders are made, we set different resolutions (number +of sides used to define the bases of the cylinder) to see how it changes the +surface of the primitive. + +.. GENERATED FROM PYTHON SOURCE LINES 89-118 + +.. code-block:: Python + + + cylinders_8 = actor.cylinder( + centers[:3], + dirs[:3], + colors[:3], + radius=radius, + heights=height, + capped=True, + resolution=8, + ) + cylinders_16 = actor.cylinder( + centers[3:6], + dirs[3:6], + colors[3:6], + radius=radius, + heights=height, + capped=True, + resolution=16, + ) + cylinders_32 = actor.cylinder( + centers[6:9], + dirs[6:9], + colors[6:9], + radius=radius, + heights=height, + capped=True, + resolution=32, + ) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 119-120 + +Next, we set up a new scene to add and visualize the actors created. + +.. GENERATED FROM PYTHON SOURCE LINES 120-134 + +.. code-block:: Python + + + scene = window.Scene() + + scene.add(cylinders_8) + scene.add(cylinders_16) + scene.add(cylinders_32) + + interactive = False + + if interactive: + window.show(scene) + + window.record(scene, size=(600, 600), out_path='viz_poly_cylinder.png') + + + + +.. image-sg:: /auto_examples/13_shaders/images/sphx_glr_viz_sdf_cylinder_001.png + :alt: viz sdf cylinder + :srcset: /auto_examples/13_shaders/images/sphx_glr_viz_sdf_cylinder_001.png + :class: sphx-glr-single-img + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 135-136 + +Visualize the surface geometry representation for the object. + +.. GENERATED FROM PYTHON SOURCE LINES 136-146 + +.. code-block:: Python + + + cylinders_8.GetProperty().SetRepresentationToWireframe() + cylinders_16.GetProperty().SetRepresentationToWireframe() + cylinders_32.GetProperty().SetRepresentationToWireframe() + + if interactive: + window.show(scene) + + window.record(scene, size=(600, 600), out_path='viz_poly_cylinder_geom.png') + + + + +.. image-sg:: /auto_examples/13_shaders/images/sphx_glr_viz_sdf_cylinder_002.png + :alt: viz sdf cylinder + :srcset: /auto_examples/13_shaders/images/sphx_glr_viz_sdf_cylinder_002.png + :class: sphx-glr-single-img + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 147-149 + +Then we clean the scene to render the boxes we will use to render our +SDF-based actors. + +.. GENERATED FROM PYTHON SOURCE LINES 149-152 + +.. code-block:: Python + + + scene.clear() + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 153-165 + +Cylinder using SDF +================== +Signed Distance Functions are mathematical functions that take as input a +point in a metric space and return the distance from that point to the +boundary of an object. + +We will use the ray marching algorithm to render the SDF primitive using +shaders. Ray marching is a technique where you step along a ray in order to +find intersections with solid geometry. Objects in the scene are defined by +SDF, and because we don’t use polygonal meshes it is possible to define +perfectly smooth surfaces and allows a faster rendering in comparison to +polygon-based modeling (more details in [Hart1996]_). + +.. GENERATED FROM PYTHON SOURCE LINES 167-169 + +Now we create cylinders using box actor and SDF implementation on shaders. +For this, we first create a box actor. + +.. GENERATED FROM PYTHON SOURCE LINES 169-177 + +.. code-block:: Python + + + box_actor = actor.box( + centers=centers, + directions=dirs, + colors=colors, + scales=(height, radius * 2, radius * 2), + ) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 178-184 + +Now we use attribute_to_actor to link a NumPy array, with the centers and +directions data, with a vertex attribute. We do this to pass the data to +the vertex shader, with the corresponding attribute name. + +We need to associate the data to each of the 8 vertices that make up the box +since we handle the processing of individual vertices in the vertex shader. + +.. GENERATED FROM PYTHON SOURCE LINES 184-195 + +.. code-block:: Python + + + rep_directions = np.repeat(dirs, 8, axis=0) + rep_centers = np.repeat(centers, 8, axis=0) + rep_radii = np.repeat(np.repeat(radius, 9), 8, axis=0) + rep_heights = np.repeat(np.repeat(height, 9), 8, axis=0) + + attribute_to_actor(box_actor, rep_centers, 'center') + attribute_to_actor(box_actor, rep_directions, 'direction') + attribute_to_actor(box_actor, rep_radii, 'radius') + attribute_to_actor(box_actor, rep_heights, 'height') + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 196-201 + +Then we have the shader code implementation corresponding to vertex and +fragment shader. Here we are passing data to the fragment shader through +the vertex shader. + +Vertex shaders perform basic processing of each individual vertex. + +.. GENERATED FROM PYTHON SOURCE LINES 201-223 + +.. code-block:: Python + + + vs_dec = """ + in vec3 center; + in vec3 direction; + in float height; + in float radius; + + out vec4 vertexMCVSOutput; + out vec3 centerMCVSOutput; + out vec3 directionVSOutput; + out float heightVSOutput; + out float radiusVSOutput; + """ + + vs_impl = """ + vertexMCVSOutput = vertexMC; + centerMCVSOutput = center; + directionVSOutput = direction; + heightVSOutput = height; + radiusVSOutput = radius; + """ + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 224-227 + +Then we add the vertex shader code to the box_actor. We use shader_to_actor +to apply our implementation to the shader creation process, this function +joins our code to the shader template that FURY has by default. + +.. GENERATED FROM PYTHON SOURCE LINES 227-230 + +.. code-block:: Python + + + shader_to_actor(box_actor, 'vertex', decl_code=vs_dec, impl_code=vs_impl) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 231-239 + +Fragment shaders are used to define the colors of each pixel being processed, +the program runs on each of the pixels that the object occupies on the +screen. + +Fragment shaders also allow us to have control over details of movement, +lighting, and color in a scene. In this case, we are using vertex shader not +just to define the colors of the cylinders but to manipulate its position in +world space, rotation with respect to the box, and lighting of the scene. + +.. GENERATED FROM PYTHON SOURCE LINES 239-250 + +.. code-block:: Python + + + fs_vars_dec = """ + in vec4 vertexMCVSOutput; + in vec3 centerMCVSOutput; + in vec3 directionVSOutput; + in float heightVSOutput; + in float radiusVSOutput; + + uniform mat4 MCVCMatrix; + """ + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 251-254 + +We use this function to generate an appropriate rotation matrix which help us +to transform our position vectors in order to align the direction of +cylinder with respect to the box. + +.. GENERATED FROM PYTHON SOURCE LINES 254-259 + +.. code-block:: Python + + + vec_to_vec_rot_mat = import_fury_shader( + os.path.join('utils', 'vec_to_vec_rot_mat.glsl') + ) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 260-261 + +We calculate the distance using the SDF function for the cylinder. + +.. GENERATED FROM PYTHON SOURCE LINES 261-264 + +.. code-block:: Python + + + sd_cylinder = import_fury_shader(os.path.join('sdf', 'sd_cylinder.frag')) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 265-266 + +This is used on calculations for surface normals of the cylinder. + +.. GENERATED FROM PYTHON SOURCE LINES 266-283 + +.. code-block:: Python + + + sdf_map = """ + float map(in vec3 position) + { + // the sdCylinder function creates vertical cylinders by default, that + // is the cylinder is created pointing in the up direction (0, 1, 0). + // We want to rotate that vector to be aligned with the box's direction + mat4 rot = vec2VecRotMat(normalize(directionVSOutput), + normalize(vec3(0, 1, 0))); + + vec3 pos = (rot * vec4(position - centerMCVSOutput, 0.0)).xyz; + + // distance to the cylinder's boundary + return sdCylinder(pos, radiusVSOutput, heightVSOutput / 2); + } + """ + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 284-285 + +We use central differences technique for computing surface normals. + +.. GENERATED FROM PYTHON SOURCE LINES 285-288 + +.. code-block:: Python + + + central_diffs_normal = import_fury_shader(os.path.join('sdf', 'central_diffs.frag')) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 289-290 + +We use cast_ray for the implementation of Ray Marching. + +.. GENERATED FROM PYTHON SOURCE LINES 290-293 + +.. code-block:: Python + + + cast_ray = import_fury_shader(os.path.join('ray_marching', 'cast_ray.frag')) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 294-295 + +For the illumination of the scene we use the Blinn-Phong model. + +.. GENERATED FROM PYTHON SOURCE LINES 295-300 + +.. code-block:: Python + + + blinn_phong_model = import_fury_shader( + os.path.join('lighting', 'blinn_phong_model.frag') + ) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 301-302 + +Now we use compose_shader to join our pieces of GLSL shader code. + +.. GENERATED FROM PYTHON SOURCE LINES 302-317 + +.. code-block:: Python + + + fs_dec = compose_shader( + [ + fs_vars_dec, + vec_to_vec_rot_mat, + sd_cylinder, + sdf_map, + central_diffs_normal, + cast_ray, + blinn_phong_model, + ] + ) + + shader_to_actor(box_actor, 'fragment', decl_code=fs_dec) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 318-320 + +Here we have the implementation of all the previous code with all the +necessary variables and functions to build the cylinders. + +.. GENERATED FROM PYTHON SOURCE LINES 320-355 + +.. code-block:: Python + + + sdf_cylinder_frag_impl = """ + vec3 point = vertexMCVSOutput.xyz; + + // ray origin + vec4 ro = -MCVCMatrix[3] * MCVCMatrix; // camera position in world space + + // ray direction + vec3 rd = normalize(point - ro.xyz); + + // light direction + vec3 ld = normalize(ro.xyz - point); + + ro += vec4((point - ro.xyz), 0); + + float t = castRay(ro.xyz, rd); + + if(t < 20.0) + { + vec3 position = ro.xyz + t * rd; + vec3 normal = centralDiffsNormals(position, .0001); + float lightAttenuation = dot(ld, normal); + vec3 color = blinnPhongIllumModel( + lightAttenuation, lightColor0, diffuseColor, + specularPower, specularColor, ambientColor); + fragOutput0 = vec4(color, opacity); + } + else + { + discard; + } + """ + + shader_to_actor(box_actor, 'fragment', impl_code=sdf_cylinder_frag_impl, block='light') + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 356-357 + +Finally, we visualize the cylinders made using ray marching and SDFs. + +.. GENERATED FROM PYTHON SOURCE LINES 357-365 + +.. code-block:: Python + + + scene.add(box_actor) + + if interactive: + window.show(scene) + + window.record(scene, size=(600, 600), out_path='viz_sdf_cylinder.png') + + + + +.. image-sg:: /auto_examples/13_shaders/images/sphx_glr_viz_sdf_cylinder_003.png + :alt: viz sdf cylinder + :srcset: /auto_examples/13_shaders/images/sphx_glr_viz_sdf_cylinder_003.png + :class: sphx-glr-single-img + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 366-373 + +References +---------- +.. [Hart1996] Hart, John C. "Sphere tracing: A geometric method for the + antialiased ray tracing of implicit surfaces." The Visual + Computer 12.10 (1996): 527-545. + +.. include:: ../links_names.inc + + +.. rst-class:: sphx-glr-timing + + **Total running time of the script:** (0 minutes 0.208 seconds) + + +.. _sphx_glr_download_auto_examples_13_shaders_viz_sdf_cylinder.py: + +.. only:: html + + .. container:: sphx-glr-footer sphx-glr-footer-example + + .. container:: sphx-glr-download sphx-glr-download-jupyter + + :download:`Download Jupyter notebook: viz_sdf_cylinder.ipynb ` + + .. container:: sphx-glr-download sphx-glr-download-python + + :download:`Download Python source code: viz_sdf_cylinder.py ` + + +.. only:: html + + .. rst-class:: sphx-glr-signature + + `Gallery generated by Sphinx-Gallery `_ diff --git a/v0.10.x/_sources/auto_examples/13_shaders/viz_sdfactor.rst.txt b/v0.10.x/_sources/auto_examples/13_shaders/viz_sdfactor.rst.txt new file mode 100644 index 000000000..aa00a2862 --- /dev/null +++ b/v0.10.x/_sources/auto_examples/13_shaders/viz_sdfactor.rst.txt @@ -0,0 +1,176 @@ + +.. DO NOT EDIT. +.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. +.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: +.. "auto_examples/13_shaders/viz_sdfactor.py" +.. LINE NUMBERS ARE GIVEN BELOW. + +.. only:: html + + .. note:: + :class: sphx-glr-download-link-note + + :ref:`Go to the end ` + to download the full example code + +.. rst-class:: sphx-glr-example-title + +.. _sphx_glr_auto_examples_13_shaders_viz_sdfactor.py: + + +=================== +Visualize SDF Actor +=================== +Here is a simple tutorial that shows how to visualize SDF primitives using +FURY. + +SDFs or Signed-distance functions when passed the coordinates of a point in +space, return the shortest distance between that point and some surface. +This property of SDFs can be used to model 3D geometry at a faster rate +compared to traditional polygons based modeling. + +In this example we use the raymarching algorithm to render the SDF primitives +shapes using shaders + +.. GENERATED FROM PYTHON SOURCE LINES 16-21 + +.. code-block:: Python + + + import numpy as np + + from fury import actor, window + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 22-23 + +Lets define variables for the SDF Actor + +.. GENERATED FROM PYTHON SOURCE LINES 23-30 + +.. code-block:: Python + + + dirs = np.random.rand(4, 3) + colors = np.random.rand(4, 3) * 255 + centers = np.array([[1, 0, 0], [0, 0, 0], [-1, 0, 0], [0, 1, 0]]) + scales = np.random.rand(4, 1) + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 31-32 + +Create SDF Actor + +.. GENERATED FROM PYTHON SOURCE LINES 32-41 + +.. code-block:: Python + + + sdfactor = actor.sdf( + centers=centers, + directions=dirs, + colors=colors, + primitives=['sphere', 'torus', 'ellipsoid', 'capsule'], + scales=scales, + ) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 42-43 + +Create a scene + +.. GENERATED FROM PYTHON SOURCE LINES 43-49 + +.. code-block:: Python + + + scene = window.Scene() + scene.background((1.0, 0.8, 0.8)) + scene.add(sdfactor) + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 50-54 + +Show Manager + +Since all the elements have been initialised ,we add them to the show +manager. + +.. GENERATED FROM PYTHON SOURCE LINES 54-64 + +.. code-block:: Python + + + current_size = (1024, 720) + showm = window.ShowManager(scene, size=current_size, title='Visualize SDF Actor') + + interactive = False + + if interactive: + showm.start() + + window.record(scene, out_path='viz_sdfactor.png', size=current_size) + + + +.. image-sg:: /auto_examples/13_shaders/images/sphx_glr_viz_sdfactor_001.png + :alt: viz sdfactor + :srcset: /auto_examples/13_shaders/images/sphx_glr_viz_sdfactor_001.png + :class: sphx-glr-single-img + + + + + + +.. rst-class:: sphx-glr-timing + + **Total running time of the script:** (0 minutes 0.074 seconds) + + +.. _sphx_glr_download_auto_examples_13_shaders_viz_sdfactor.py: + +.. only:: html + + .. container:: sphx-glr-footer sphx-glr-footer-example + + .. container:: sphx-glr-download sphx-glr-download-jupyter + + :download:`Download Jupyter notebook: viz_sdfactor.ipynb ` + + .. container:: sphx-glr-download sphx-glr-download-python + + :download:`Download Python source code: viz_sdfactor.py ` + + +.. only:: html + + .. rst-class:: sphx-glr-signature + + `Gallery generated by Sphinx-Gallery `_ diff --git a/v0.10.x/_sources/auto_examples/13_shaders/viz_shader.rst.txt b/v0.10.x/_sources/auto_examples/13_shaders/viz_shader.rst.txt new file mode 100644 index 000000000..d2cd27995 --- /dev/null +++ b/v0.10.x/_sources/auto_examples/13_shaders/viz_shader.rst.txt @@ -0,0 +1,302 @@ + +.. DO NOT EDIT. +.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. +.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: +.. "auto_examples/13_shaders/viz_shader.py" +.. LINE NUMBERS ARE GIVEN BELOW. + +.. only:: html + + .. note:: + :class: sphx-glr-download-link-note + + :ref:`Go to the end ` + to download the full example code + +.. rst-class:: sphx-glr-example-title + +.. _sphx_glr_auto_examples_13_shaders_viz_shader.py: + + +============= +Varying Color +============= + +This example shows how to use shaders to generate a shaded output. We will +demonstrate how to load polydata then use a custom shader calls to render +a custom shaded model. +First, a bunch of imports. + +.. GENERATED FROM PYTHON SOURCE LINES 12-17 + +.. code-block:: Python + + + from fury import io, ui, utils, window + from fury.data.fetcher import fetch_viz_models, read_viz_models + from fury.shaders import add_shader_callback, shader_to_actor + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 18-19 + +Let's download and load the model + +.. GENERATED FROM PYTHON SOURCE LINES 19-25 + +.. code-block:: Python + + + + fetch_viz_models() + model = read_viz_models('utah.obj') + + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + Dataset is already in place. If you want to fetch it again please first remove the folder /Users/skoudoro/.fury/models + + + + +.. GENERATED FROM PYTHON SOURCE LINES 26-29 + +Let's start by loading the polydata of choice. +For this example we use the standard utah teapot model. +currently supported formats include OBJ, VTK, FIB, PLY, STL and XML + +.. GENERATED FROM PYTHON SOURCE LINES 30-37 + +.. code-block:: Python + + + utah = io.load_polydata(model) + utah = utils.get_polymapper_from_polydata(utah) + utah = utils.get_actor_from_polymapper(utah) + mapper = utah.GetMapper() + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 38-41 + +To change the default shader we add a shader replacement. +Specify vertex shader using vtkShader.Vertex +Specify fragment shader using vtkShader.Fragment + +.. GENERATED FROM PYTHON SOURCE LINES 41-67 + +.. code-block:: Python + + vertex_shader_code_decl = """ + out vec4 myVertexVC; + """ + + vertex_shader_code_impl = """ + myVertexVC = vertexMC; + """ + + fragment_shader_code_decl = """ + uniform float time; + varying vec4 myVertexVC; + """ + + fragment_shader_code_impl = """ + vec2 iResolution = vec2(1024,720); + vec2 uv = myVertexVC.xy/iResolution; + vec3 col = 0.5 + 0.5 * cos((time/30) + uv.xyx + vec3(0, 2, 4)); + fragOutput0 = vec4(col, fragOutput0.a); + """ + + shader_to_actor( + utah, 'vertex', impl_code=vertex_shader_code_impl, decl_code=vertex_shader_code_decl + ) + shader_to_actor(utah, 'fragment', decl_code=fragment_shader_code_decl) + shader_to_actor(utah, 'fragment', impl_code=fragment_shader_code_impl, block='light') + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 68-69 + +Let's create a scene. + +.. GENERATED FROM PYTHON SOURCE LINES 69-75 + +.. code-block:: Python + + + scene = window.Scene() + + global timer + timer = 0 + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 76-77 + +The timer will call this user defined callback every 30 milliseconds. + +.. GENERATED FROM PYTHON SOURCE LINES 77-86 + +.. code-block:: Python + + + + def timer_callback(obj, event): + global timer + timer += 1.0 + showm.render() + scene.azimuth(5) + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 87-89 + +The shader callback will update the color of our utah pot via the update of +the timer variable. + +.. GENERATED FROM PYTHON SOURCE LINES 89-102 + +.. code-block:: Python + + + + def shader_callback(_caller, _event, calldata=None): + program = calldata + global timer + if program is not None: + try: + program.SetUniformf('time', timer) + except ValueError: + pass + + + add_shader_callback(utah, shader_callback) + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + + 1 + + + +.. GENERATED FROM PYTHON SOURCE LINES 103-104 + +Let's add a textblock to the scene with a custom message + +.. GENERATED FROM PYTHON SOURCE LINES 104-108 + +.. code-block:: Python + + + tb = ui.TextBlock2D() + tb.message = 'Hello Shaders' + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 109-113 + +Show Manager + +Now that all the elements have been initialised, we add them to the show +manager. + +.. GENERATED FROM PYTHON SOURCE LINES 113-128 + +.. code-block:: Python + + + current_size = (1024, 720) + showm = window.ShowManager(scene, size=current_size, reset_camera=False) + + + showm.add_timer_callback(True, 30, timer_callback) + + scene.add(utah) + scene.add(tb) + + interactive = False + if interactive: + showm.start() + + window.record(showm.scene, size=current_size, out_path='viz_shader.png') + + + +.. image-sg:: /auto_examples/13_shaders/images/sphx_glr_viz_shader_001.png + :alt: viz shader + :srcset: /auto_examples/13_shaders/images/sphx_glr_viz_shader_001.png + :class: sphx-glr-single-img + + + + + + +.. rst-class:: sphx-glr-timing + + **Total running time of the script:** (0 minutes 0.216 seconds) + + +.. _sphx_glr_download_auto_examples_13_shaders_viz_shader.py: + +.. only:: html + + .. container:: sphx-glr-footer sphx-glr-footer-example + + .. container:: sphx-glr-download sphx-glr-download-jupyter + + :download:`Download Jupyter notebook: viz_shader.ipynb ` + + .. container:: sphx-glr-download sphx-glr-download-python + + :download:`Download Python source code: viz_shader.py ` + + +.. only:: html + + .. rst-class:: sphx-glr-signature + + `Gallery generated by Sphinx-Gallery `_ diff --git a/v0.10.x/_sources/auto_examples/17_pybullet/index.rst.txt b/v0.10.x/_sources/auto_examples/17_pybullet/index.rst.txt new file mode 100644 index 000000000..d0b8f603d --- /dev/null +++ b/v0.10.x/_sources/auto_examples/17_pybullet/index.rst.txt @@ -0,0 +1,115 @@ + + +.. _sphx_glr_auto_examples_17_pybullet: + +Integrate Physics using pybullet +-------------------------------- + +These demos show how to use connect FURY with a physics engine library. + + + +.. raw:: html + +
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/17_pybullet/images/thumb/sphx_glr_viz_ball_collide_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_17_pybullet_viz_ball_collide.py` + +.. raw:: html + +
Ball Collision Simulation
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/17_pybullet/images/thumb/sphx_glr_viz_domino_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_17_pybullet_viz_domino.py` + +.. raw:: html + +
Domino Physics Simulation
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/17_pybullet/images/thumb/sphx_glr_viz_chain_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_17_pybullet_viz_chain.py` + +.. raw:: html + +
Chain Simulation
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/17_pybullet/images/thumb/sphx_glr_viz_brick_wall_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_17_pybullet_viz_brick_wall.py` + +.. raw:: html + +
Brick Wall Simulation
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/17_pybullet/images/thumb/sphx_glr_viz_wrecking_ball_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_17_pybullet_viz_wrecking_ball.py` + +.. raw:: html + +
Wrecking Ball Simulation
+
+ + +.. raw:: html + +
+ + +.. toctree:: + :hidden: + + /auto_examples/17_pybullet/viz_ball_collide + /auto_examples/17_pybullet/viz_domino + /auto_examples/17_pybullet/viz_chain + /auto_examples/17_pybullet/viz_brick_wall + /auto_examples/17_pybullet/viz_wrecking_ball + diff --git a/v0.10.x/_sources/auto_examples/17_pybullet/sg_execution_times.rst.txt b/v0.10.x/_sources/auto_examples/17_pybullet/sg_execution_times.rst.txt new file mode 100644 index 000000000..0eec5e742 --- /dev/null +++ b/v0.10.x/_sources/auto_examples/17_pybullet/sg_execution_times.rst.txt @@ -0,0 +1,49 @@ + +:orphan: + +.. _sphx_glr_auto_examples_17_pybullet_sg_execution_times: + + +Computation times +================= +**00:00.591** total execution time for 5 files **from auto_examples/17_pybullet**: + +.. container:: + + .. raw:: html + + + + + + + + .. list-table:: + :header-rows: 1 + :class: table table-striped sg-datatable + + * - Example + - Time + - Mem (MB) + * - :ref:`sphx_glr_auto_examples_17_pybullet_viz_chain.py` (``viz_chain.py``) + - 00:00.591 + - 0.0 + * - :ref:`sphx_glr_auto_examples_17_pybullet_viz_ball_collide.py` (``viz_ball_collide.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_17_pybullet_viz_brick_wall.py` (``viz_brick_wall.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_17_pybullet_viz_domino.py` (``viz_domino.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_17_pybullet_viz_wrecking_ball.py` (``viz_wrecking_ball.py``) + - 00:00.000 + - 0.0 diff --git a/v0.10.x/_sources/auto_examples/17_pybullet/viz_ball_collide.rst.txt b/v0.10.x/_sources/auto_examples/17_pybullet/viz_ball_collide.rst.txt new file mode 100644 index 000000000..1839c0781 --- /dev/null +++ b/v0.10.x/_sources/auto_examples/17_pybullet/viz_ball_collide.rst.txt @@ -0,0 +1,266 @@ + +.. DO NOT EDIT. +.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. +.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: +.. "auto_examples/17_pybullet/viz_ball_collide.py" +.. LINE NUMBERS ARE GIVEN BELOW. + +.. only:: html + + .. note:: + :class: sphx-glr-download-link-note + + :ref:`Go to the end ` + to download the full example code + +.. rst-class:: sphx-glr-example-title + +.. _sphx_glr_auto_examples_17_pybullet_viz_ball_collide.py: + + +========================= +Ball Collision Simulation +========================= + +This example simulation shows how to use pybullet to render physics simulations +in fury. In this example we render the collision between a blue ball and red +ball and also display a message by confirming the collision. + +First some imports. + +.. GENERATED FROM PYTHON SOURCE LINES 12-21 + +.. code-block:: Python + + import itertools + + import numpy as np + import pybullet as p + + from fury import actor, ui, window + + client = p.connect(p.DIRECT) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 22-23 + +Parameters and definition of red and blue balls. + +.. GENERATED FROM PYTHON SOURCE LINES 23-56 + +.. code-block:: Python + + + red_radius = 0.5 + blue_radius = 0.5 + duration = 50 + + # Red Ball + red_ball_actor = actor.sphere( + centers=np.array([[0, 0, 0]]), colors=np.array([[1, 0, 0]]), radii=red_radius + ) + + red_ball_coll = p.createCollisionShape(p.GEOM_SPHERE, radius=red_radius) + + red_ball = p.createMultiBody( + baseMass=0.5, + baseCollisionShapeIndex=red_ball_coll, + basePosition=[10, 0, 0], + baseOrientation=[0, 0, 0, 1], + ) + + # Blue ball + blue_ball_actor = actor.sphere( + centers=np.array([[0, 0, 0]]), colors=np.array([[0, 0, 1]]), radii=blue_radius + ) + + blue_ball_coll = p.createCollisionShape(p.GEOM_SPHERE, radius=blue_radius) + + blue_ball = p.createMultiBody( + baseMass=0.5, + baseCollisionShapeIndex=blue_ball_coll, + basePosition=[-10, 0, 0], + baseOrientation=[0, 0, 0, 1], + ) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 57-58 + +We set the coefficient of restitution of both the balls to `0.6`. + +.. GENERATED FROM PYTHON SOURCE LINES 58-62 + +.. code-block:: Python + + + p.changeDynamics(red_ball, -1, restitution=0.6) + p.changeDynamics(blue_ball, -1, restitution=0.6) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 63-64 + +We add all the actors to the scene. + +.. GENERATED FROM PYTHON SOURCE LINES 64-77 + +.. code-block:: Python + + + scene = window.Scene() + scene.add(actor.axes()) + scene.add(red_ball_actor) + scene.add(blue_ball_actor) + + showm = window.ShowManager( + scene, size=(900, 700), reset_camera=False, order_transparent=True + ) + + + counter = itertools.count() + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 78-79 + +Method to sync objects. + +.. GENERATED FROM PYTHON SOURCE LINES 79-96 + +.. code-block:: Python + + + + def sync_actor(actor, multibody): + pos, orn = p.getBasePositionAndOrientation(multibody) + actor.SetPosition(*pos) + orn_deg = np.degrees(p.getEulerFromQuaternion(orn)) + actor.SetOrientation(*orn_deg) + + + apply_force = True + tb = ui.TextBlock2D(position=(0, 600), font_size=30, color=(1, 0.5, 0), text='') + scene.add(tb) + scene.set_camera( + position=(0.30, -18.78, 0.89), focal_point=(0.15, 0.25, 0.40), view_up=(0, 0, 1.00) + ) + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 97-98 + +Timer callback to sync and step simulation every second. + +.. GENERATED FROM PYTHON SOURCE LINES 98-141 + +.. code-block:: Python + + + + def timer_callback(_obj, _event): + global apply_force + cnt = next(counter) + showm.render() + red_pos, red_orn = p.getBasePositionAndOrientation(red_ball) + blue_pos, blue_orn = p.getBasePositionAndOrientation(blue_ball) + + # Apply force for the first step of the simulation. + if apply_force: + p.applyExternalForce( + red_ball, -1, forceObj=[-40000, 0, 0], posObj=red_pos, flags=p.WORLD_FRAME + ) + + p.applyExternalForce( + blue_ball, -1, forceObj=[40000, 0, 0], posObj=blue_pos, flags=p.WORLD_FRAME + ) + + apply_force = 0 + + sync_actor(blue_ball_actor, blue_ball) + sync_actor(red_ball_actor, red_ball) + + # Get various collision information using `p.getContactPoints`. + contact = p.getContactPoints(red_ball, blue_ball, -1, -1) + if len(contact) != 0: + tb.message = 'Collision!!' + + p.stepSimulation() + + if cnt == 50: + showm.exit() + + + showm.add_timer_callback(True, duration, timer_callback) + + interactive = False + + if interactive: + showm.start() + + window.record(scene, size=(900, 700), out_path='viz_ball_collide.png') + + + +.. image-sg:: /auto_examples/17_pybullet/images/sphx_glr_viz_ball_collide_001.png + :alt: viz ball collide + :srcset: /auto_examples/17_pybullet/images/sphx_glr_viz_ball_collide_001.png + :class: sphx-glr-single-img + + + + + + +.. rst-class:: sphx-glr-timing + + **Total running time of the script:** (0 minutes 0.558 seconds) + + +.. _sphx_glr_download_auto_examples_17_pybullet_viz_ball_collide.py: + +.. only:: html + + .. container:: sphx-glr-footer sphx-glr-footer-example + + .. container:: sphx-glr-download sphx-glr-download-jupyter + + :download:`Download Jupyter notebook: viz_ball_collide.ipynb ` + + .. container:: sphx-glr-download sphx-glr-download-python + + :download:`Download Python source code: viz_ball_collide.py ` + + +.. only:: html + + .. rst-class:: sphx-glr-signature + + `Gallery generated by Sphinx-Gallery `_ diff --git a/v0.10.x/_sources/auto_examples/17_pybullet/viz_brick_wall.rst.txt b/v0.10.x/_sources/auto_examples/17_pybullet/viz_brick_wall.rst.txt new file mode 100644 index 000000000..477f36dbd --- /dev/null +++ b/v0.10.x/_sources/auto_examples/17_pybullet/viz_brick_wall.rst.txt @@ -0,0 +1,538 @@ + +.. DO NOT EDIT. +.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. +.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: +.. "auto_examples/17_pybullet/viz_brick_wall.py" +.. LINE NUMBERS ARE GIVEN BELOW. + +.. only:: html + + .. note:: + :class: sphx-glr-download-link-note + + :ref:`Go to the end ` + to download the full example code + +.. rst-class:: sphx-glr-example-title + +.. _sphx_glr_auto_examples_17_pybullet_viz_brick_wall.py: + + +===================== +Brick Wall Simulation +===================== + +This example simulation shows how to use pybullet to render physics simulations +in fury. In this example we specifically render a ball beign thrown at a brick +wall. + +First some imports. + +.. GENERATED FROM PYTHON SOURCE LINES 12-19 + +.. code-block:: Python + + import itertools + + import numpy as np + import pybullet as p + + from fury import actor, ui, utils, window + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 20-22 + +Next, we initialize a pybullet client to render the physics. We use `DIRECT` +mode to initialize pybullet without a GUI. + +.. GENERATED FROM PYTHON SOURCE LINES 22-25 + +.. code-block:: Python + + + p.connect(p.DIRECT) + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + + 1 + + + +.. GENERATED FROM PYTHON SOURCE LINES 26-27 + +Apply gravity to the scene. In pybullet all values are in SI units. + +.. GENERATED FROM PYTHON SOURCE LINES 27-29 + +.. code-block:: Python + + p.setGravity(0, 0, -10) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 30-32 + +We define some global parameters so that its easier for us to tweak the +tweak the simulation. + +.. GENERATED FROM PYTHON SOURCE LINES 32-52 + +.. code-block:: Python + + + # Ball Parameters + ball_radius = 0.3 + ball_color = np.array([1, 0, 0]) + ball_mass = 3 + ball_position = np.array([2, 0, 1.5]) + ball_orientation = np.array([0, 0, 0, 1]) + + # Base Plane Parameters + base_size = np.array([5, 5, 0.2]) + base_color = np.array([1, 1, 1]) + base_position = np.array([0, 0, -0.1]) + base_orientation = np.array([0, 0, 0, 1]) + + # Wall Parameters + wall_height = 10 + wall_width = 10 + brick_mass = 0.5 + brick_size = np.array([0.2, 0.4, 0.2]) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 53-54 + +Now we define the required parameters to render the Ball. + +.. GENERATED FROM PYTHON SOURCE LINES 54-74 + +.. code-block:: Python + + + # Ball actor + ball_actor = actor.sphere( + centers=np.array([[0, 0, 0]]), colors=ball_color, radii=ball_radius + ) + + # Collision shape for the ball. + ball_coll = p.createCollisionShape(p.GEOM_SPHERE, radius=ball_radius) + + # Creating a multi-body which will be tracked by pybullet. + ball = p.createMultiBody( + baseMass=3, + baseCollisionShapeIndex=ball_coll, + basePosition=ball_position, + baseOrientation=ball_orientation, + ) + + # Change the dynamics of the ball by adding friction and restitution. + p.changeDynamics(ball, -1, lateralFriction=0.3, restitution=0.5) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 75-76 + +Render a base plane to support the bricks. + +.. GENERATED FROM PYTHON SOURCE LINES 76-95 + +.. code-block:: Python + + + base_actor = actor.box( + centers=np.array([[0, 0, 0]]), + directions=[0, 0, 0], + scales=base_size, + colors=base_color, + ) + + base_coll = p.createCollisionShape(p.GEOM_BOX, halfExtents=base_size / 2) + # half of the actual size. + + base = p.createMultiBody( + baseCollisionShapeIndex=base_coll, + basePosition=base_position, + baseOrientation=base_orientation, + ) + + p.changeDynamics(base, -1, lateralFriction=0.3, restitution=0.5) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 96-98 + +Now we render the bricks. All the bricks are rendered by a single actor for +better performance. + +.. GENERATED FROM PYTHON SOURCE LINES 98-141 + +.. code-block:: Python + + + nb_bricks = wall_height * wall_width + + brick_centers = np.zeros((nb_bricks, 3)) + + brick_directions = np.zeros((nb_bricks, 3)) + brick_directions[:] = np.array([1.57, 0, 0]) + + brick_orns = np.zeros((nb_bricks, 4)) + + brick_sizes = np.zeros((nb_bricks, 3)) + brick_sizes[:] = brick_size + + brick_colors = np.random.rand(nb_bricks, 3) + + brick_coll = p.createCollisionShape(p.GEOM_BOX, halfExtents=brick_size / 2) + + # We use this array to store the reference of brick objects in pybullet world. + bricks = np.zeros(nb_bricks, dtype=np.int8) + + # Logic to position the bricks appropriately to form a wall. + i = 0 + for k in range(wall_height): + for j in range(wall_width): + center_pos = np.array([-1, (j * 0.4) - 1.8, (0.2 * k) + 0.1]) + brick_centers[i] = center_pos + brick_orns[i] = np.array([0, 0, 0, 1]) + bricks[i] = p.createMultiBody( + baseMass=brick_mass, + baseCollisionShapeIndex=brick_coll, + basePosition=center_pos, + baseOrientation=brick_orns[i], + ) + p.changeDynamics(bricks[i], -1, lateralFriction=0.1, restitution=0.1) + i += 1 + + brick_actor = actor.box( + centers=brick_centers, + directions=brick_directions, + scales=brick_sizes, + colors=brick_colors, + ) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 142-143 + +Now, we define a scene and add actors to it. + +.. GENERATED FROM PYTHON SOURCE LINES 143-162 + +.. code-block:: Python + + + scene = window.Scene() + scene.add(actor.axes()) + scene.add(ball_actor) + scene.add(base_actor) + scene.add(brick_actor) + + # Create show manager. + showm = window.ShowManager( + scene, size=(900, 768), reset_camera=False, order_transparent=True + ) + + + # Counter iterator for tracking simulation steps. + counter = itertools.count() + + # Variable for tracking applied force. + apply_force = True + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 163-164 + +Now, we define methods to sync objects between fury and Pybullet. + +.. GENERATED FROM PYTHON SOURCE LINES 164-180 + +.. code-block:: Python + + + # Get the position of base and set it. + base_pos, _ = p.getBasePositionAndOrientation(base) + base_actor.SetPosition(*base_pos) + + # Do the same for ball. + ball_pos, _ = p.getBasePositionAndOrientation(ball) + ball_actor.SetPosition(*ball_pos) + + # Calculate the vertices of the bricks. + vertices = utils.vertices_from_actor(brick_actor) + num_vertices = vertices.shape[0] + num_objects = brick_centers.shape[0] + sec = int(num_vertices / num_objects) + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 181-195 + +============== +Syncing Bricks +============== + +Here, we perform three major steps to sync bricks accurately. +* Get the position and orientation of the bricks from pybullet. +* Calculate the Rotation Matrix. + + - Get the difference in orientations (Quaternion). + - Generate the corresponding rotation matrix according to that difference. + - Reshape it in a 3x3 matrix. + +* Perform calculations to get the required position and orientation. +* Update the position and orientation. + +.. GENERATED FROM PYTHON SOURCE LINES 195-216 + +.. code-block:: Python + + + + def sync_brick(object_index, multibody): + pos, orn = p.getBasePositionAndOrientation(multibody) + + rot_mat = np.reshape( + p.getMatrixFromQuaternion( + p.getDifferenceQuaternion(orn, brick_orns[object_index]) + ), + (3, 3), + ) + + vertices[object_index * sec : object_index * sec + sec] = ( + vertices[object_index * sec : object_index * sec + sec] + - brick_centers[object_index] + ) @ rot_mat + pos + + brick_centers[object_index] = pos + brick_orns[object_index] = orn + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 217-219 + +A simpler but inaccurate approach is used here to update the position and +orientation. + +.. GENERATED FROM PYTHON SOURCE LINES 219-228 + +.. code-block:: Python + + + + def sync_actor(actor, multibody): + pos, orn = p.getBasePositionAndOrientation(multibody) + actor.SetPosition(*pos) + orn_deg = np.degrees(p.getEulerFromQuaternion(orn)) + actor.SetOrientation(*orn_deg) + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 229-230 + +Here, we define a textblock to display the Avg. FPS and simulation steps. + +.. GENERATED FROM PYTHON SOURCE LINES 230-237 + +.. code-block:: Python + + + fpss = np.array([]) + tb = ui.TextBlock2D( + text='Avg. FPS: \nSim Steps: ', position=(0, 680), font_size=30, color=(1, 0.5, 0) + ) + scene.add(tb) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 238-239 + +Set the camera for better visualization. + +.. GENERATED FROM PYTHON SOURCE LINES 239-247 + +.. code-block:: Python + + + scene.set_camera( + position=(10.46, -8.13, 6.18), + focal_point=(0.0, 0.0, 0.79), + view_up=(-0.27, 0.26, 0.90), + ) + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 248-250 + +Timer callback is created which is responsible for calling the sync and +simulation methods. + +.. GENERATED FROM PYTHON SOURCE LINES 250-303 + +.. code-block:: Python + + + + # Create timer callback which will execute at each step of simulation. + def timer_callback(_obj, _event): + global apply_force, fpss + cnt = next(counter) + showm.render() + + if cnt % 1 == 0: + fps = showm.frame_rate + fpss = np.append(fpss, fps) + tb.message = ( + 'Avg. FPS: ' + str(np.round(np.mean(fpss), 0)) + '\nSim Steps: ' + str(cnt) + ) + + # Get the position and orientation of the ball. + ball_pos, ball_orn = p.getBasePositionAndOrientation(ball) + + # Apply force for 5 times for the first step of simulation. + if apply_force: + # Apply the force. + p.applyExternalForce( + ball, -1, forceObj=[-10000, 0, 0], posObj=ball_pos, flags=p.WORLD_FRAME + ) + apply_force = False + + # Set position and orientation of the ball. + sync_actor(ball_actor, ball) + + # Updating the position and orientation of each individual brick. + for idx, brick in enumerate(bricks): + sync_brick(idx, brick) + utils.update_actor(brick_actor) + + # Simulate a step. + p.stepSimulation() + + # Exit after 2000 steps of simulation. + if cnt == 130: + showm.exit() + + + # Add the timer callback to showmanager. + # Increasing the duration value will slow down the simulation. + showm.add_timer_callback(True, 1, timer_callback) + + interactive = False + + # start simulation + if interactive: + showm.start() + + window.record(scene, out_path='viz_brick_wall.png', size=(900, 768)) + + + +.. image-sg:: /auto_examples/17_pybullet/images/sphx_glr_viz_brick_wall_001.png + :alt: viz brick wall + :srcset: /auto_examples/17_pybullet/images/sphx_glr_viz_brick_wall_001.png + :class: sphx-glr-single-img + + + + + + +.. rst-class:: sphx-glr-timing + + **Total running time of the script:** (0 minutes 0.258 seconds) + + +.. _sphx_glr_download_auto_examples_17_pybullet_viz_brick_wall.py: + +.. only:: html + + .. container:: sphx-glr-footer sphx-glr-footer-example + + .. container:: sphx-glr-download sphx-glr-download-jupyter + + :download:`Download Jupyter notebook: viz_brick_wall.ipynb ` + + .. container:: sphx-glr-download sphx-glr-download-python + + :download:`Download Python source code: viz_brick_wall.py ` + + +.. only:: html + + .. rst-class:: sphx-glr-signature + + `Gallery generated by Sphinx-Gallery `_ diff --git a/v0.10.x/_sources/auto_examples/17_pybullet/viz_chain.rst.txt b/v0.10.x/_sources/auto_examples/17_pybullet/viz_chain.rst.txt new file mode 100644 index 000000000..f04adc019 --- /dev/null +++ b/v0.10.x/_sources/auto_examples/17_pybullet/viz_chain.rst.txt @@ -0,0 +1,430 @@ + +.. DO NOT EDIT. +.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. +.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: +.. "auto_examples/17_pybullet/viz_chain.py" +.. LINE NUMBERS ARE GIVEN BELOW. + +.. only:: html + + .. note:: + :class: sphx-glr-download-link-note + + :ref:`Go to the end ` + to download the full example code + +.. rst-class:: sphx-glr-example-title + +.. _sphx_glr_auto_examples_17_pybullet_viz_chain.py: + + +===================== +Chain Simulation +===================== + +This example simulation shows how to use pybullet to render physics simulations +in fury. In this example we specifically render a Chain oscillating to and from. + +First some imports. + +.. GENERATED FROM PYTHON SOURCE LINES 11-18 + +.. code-block:: Python + + import itertools + + import numpy as np + import pybullet as p + + from fury import actor, ui, utils, window + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 19-20 + +Setup pybullet and add gravity. + +.. GENERATED FROM PYTHON SOURCE LINES 20-26 + +.. code-block:: Python + + + p.connect(p.DIRECT) + + # Apply gravity to the scene. + p.setGravity(0, 0, -10) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 27-28 + +Now we render the Chain using the following parameters and definitions. + +.. GENERATED FROM PYTHON SOURCE LINES 28-106 + +.. code-block:: Python + + + # Parameters + n_links = 20 + dx_link = 0.1 # Size of segments + link_mass = 0.5 + base_mass = 0.1 + radii = 0.5 + + joint_friction = 0.0005 # rotational joint friction [N/(rad/s)] + + link_shape = p.createCollisionShape( + p.GEOM_CYLINDER, + radius=radii, + height=dx_link, + collisionFramePosition=[0, 0, -dx_link / 2], + ) + + base_shape = p.createCollisionShape(p.GEOM_BOX, halfExtents=[0.01, 0.01, 0.01]) + + visualShapeId = -1 + + link_Masses = np.zeros(n_links) + link_Masses[:] = link_mass + + linkCollisionShapeIndices = np.zeros(n_links) + linkCollisionShapeIndices[:] = np.array(link_shape) + linkVisualShapeIndices = -1 * np.ones(n_links) + linkPositions = np.zeros((n_links, 3)) + linkPositions[:] = np.array([0, 0, -dx_link]) + linkOrientations = np.zeros((n_links, 4)) + linkOrientations[:] = np.array([0, 0, 0, 1]) + linkInertialFramePositions = np.zeros((n_links, 3)) + linkInertialFrameOrns = np.zeros((n_links, 4)) + linkInertialFrameOrns[:] = np.array([0, 0, 0, 1]) + indices = np.arange(n_links) + jointTypes = np.zeros(n_links) + jointTypes[:] = np.array(p.JOINT_SPHERICAL) + axis = np.zeros((n_links, 3)) + axis[:] = np.array([1, 0, 0]) + + linkDirections = np.zeros((n_links, 3)) + linkDirections[:] = np.array([1, 1, 1]) + + link_radii = np.zeros(n_links) + link_radii[:] = radii + + link_heights = np.zeros(n_links) + link_heights[:] = dx_link + + rope_actor = actor.cylinder( + centers=linkPositions, + directions=linkDirections, + colors=np.random.rand(n_links, 3), + radius=radii, + heights=link_heights, + capped=True, + ) + + basePosition = [0, 0, 2] + baseOrientation = [0, 0, 0, 1] + rope = p.createMultiBody( + base_mass, + base_shape, + visualShapeId, + basePosition, + baseOrientation, + linkMasses=link_Masses, + linkCollisionShapeIndices=linkCollisionShapeIndices.astype(int), + linkVisualShapeIndices=linkVisualShapeIndices.astype(int), + linkPositions=linkPositions, + linkOrientations=linkOrientations, + linkInertialFramePositions=linkInertialFramePositions, + linkInertialFrameOrientations=linkInertialFrameOrns, + linkParentIndices=indices.astype(int), + linkJointTypes=jointTypes.astype(int), + linkJointAxis=axis.astype(int), + ) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 107-108 + +We remove stiffness among the joints by adding friction to them. + +.. GENERATED FROM PYTHON SOURCE LINES 108-123 + +.. code-block:: Python + + + friction_vec = [joint_friction] * 3 # same all axis + control_mode = p.POSITION_CONTROL # set pos control mode + for j in range(p.getNumJoints(rope)): + p.setJointMotorControlMultiDof( + rope, + j, + control_mode, + targetPosition=[0, 0, 0, 1], + targetVelocity=[0, 0, 0], + positionGain=0, + velocityGain=1, + force=friction_vec, + ) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 124-126 + +Next, we define a constraint base that will help us in the oscillation of the +chain. + +.. GENERATED FROM PYTHON SOURCE LINES 126-143 + +.. code-block:: Python + + + root_robe_c = p.createConstraint( + rope, -1, -1, -1, p.JOINT_FIXED, [0, 0, 0], [0, 0, 0], [0, 0, 2] + ) + + # some traj to inject motion + amplitude_x = 0.3 + amplitude_y = 0.0 + freq = 0.6 + + base_actor = actor.box( + centers=np.array([[0, 0, 0]]), + directions=np.array([[0, 0, 0]]), + scales=(0.02, 0.02, 0.02), + colors=np.array([[1, 0, 0]]), + ) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 144-145 + +We add the necessary actors to the scene. + +.. GENERATED FROM PYTHON SOURCE LINES 145-163 + +.. code-block:: Python + + + scene = window.Scene() + scene.background((1, 1, 1)) + scene.set_camera((2.2, -3.0, 3.0), (-0.3, 0.6, 0.7), (-0.2, 0.2, 1.0)) + scene.add(actor.axes(scale=(0.1, 0.1, 0.1))) + scene.add(rope_actor) + scene.add(base_actor) + + # Create show manager. + showm = window.ShowManager( + scene, size=(900, 768), reset_camera=False, order_transparent=True + ) + + + # Counter iterator for tracking simulation steps. + counter = itertools.count() + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 164-165 + +We define a couple of syncing methods for the base and chain. + +.. GENERATED FROM PYTHON SOURCE LINES 165-202 + +.. code-block:: Python + + + # Function for syncing actors with multi-bodies. + def sync_actor(actor, multibody): + pos, orn = p.getBasePositionAndOrientation(multibody) + actor.SetPosition(*pos) + orn_deg = np.degrees(p.getEulerFromQuaternion(orn)) + actor.SetOrientation(*orn_deg) + + + vertices = utils.vertices_from_actor(rope_actor) + num_vertices = vertices.shape[0] + num_objects = linkPositions.shape[0] + sec = int(num_vertices / num_objects) + + + def sync_joints(actor_list, multibody): + for joint in range(p.getNumJoints(multibody)): + # `p.getLinkState` offers various information about the joints + # as a list and the values in 4th and 5th index refer to the joint's + # position and orientation respectively. + pos, orn = p.getLinkState(multibody, joint)[4:6] + + rot_mat = np.reshape( + p.getMatrixFromQuaternion( + p.getDifferenceQuaternion(orn, linkOrientations[joint]) + ), + (3, 3), + ) + + vertices[joint * sec : joint * sec + sec] = ( + vertices[joint * sec : joint * sec + sec] - linkPositions[joint] + ) @ rot_mat + pos + + linkPositions[joint] = pos + linkOrientations[joint] = orn + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 203-204 + +We define a TextBlock to display the Avg. FPS and Simulation steps. + +.. GENERATED FROM PYTHON SOURCE LINES 204-215 + +.. code-block:: Python + + + fpss = np.array([]) + tb = ui.TextBlock2D( + position=(0, 680), font_size=30, color=(1, 0.5, 0), text='Avg. FPS: \nSim Steps: ' + ) + scene.add(tb) + + t = 0.0 + freq_sim = 240 + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 216-217 + +Timer callback to sync objects, simulate steps and oscillate the base. + +.. GENERATED FROM PYTHON SOURCE LINES 217-266 + +.. code-block:: Python + + + + def timer_callback(_obj, _event): + cnt = next(counter) + global t, fpss + showm.render() + + t += 1.0 / freq_sim + + if cnt % 1 == 0: + fps = showm.frame_rate + fpss = np.append(fpss, fps) + tb.message = ( + 'Avg. FPS: ' + str(np.round(np.mean(fpss), 0)) + '\nSim Steps: ' + str(cnt) + ) + + # some trajectory + ux = amplitude_x * np.sin(2 * np.pi * freq * t) + uy = amplitude_y * np.cos(2 * np.pi * freq * t) + + # move base around + pivot = [3 * ux, uy, 2] + orn = p.getQuaternionFromEuler([0, 0, 0]) + p.changeConstraint(root_robe_c, pivot, jointChildFrameOrientation=orn, maxForce=500) + + # Sync base and chain. + sync_actor(base_actor, rope) + sync_joints(rope_actor, rope) + utils.update_actor(rope_actor) + + # Simulate a step. + p.stepSimulation() + + # Exit after 2000 steps of simulation. + if cnt == 130: + showm.exit() + + + # Add the timer callback to showmanager. + # Increasing the duration value will slow down the simulation. + showm.add_timer_callback(True, 1, timer_callback) + + interactive = False + + # start simulation + if interactive: + showm.start() + + window.record(scene, size=(900, 768), out_path='viz_chain.png') + + + +.. image-sg:: /auto_examples/17_pybullet/images/sphx_glr_viz_chain_001.png + :alt: viz chain + :srcset: /auto_examples/17_pybullet/images/sphx_glr_viz_chain_001.png + :class: sphx-glr-single-img + + + + + + +.. rst-class:: sphx-glr-timing + + **Total running time of the script:** (0 minutes 0.591 seconds) + + +.. _sphx_glr_download_auto_examples_17_pybullet_viz_chain.py: + +.. only:: html + + .. container:: sphx-glr-footer sphx-glr-footer-example + + .. container:: sphx-glr-download sphx-glr-download-jupyter + + :download:`Download Jupyter notebook: viz_chain.ipynb ` + + .. container:: sphx-glr-download sphx-glr-download-python + + :download:`Download Python source code: viz_chain.py ` + + +.. only:: html + + .. rst-class:: sphx-glr-signature + + `Gallery generated by Sphinx-Gallery `_ diff --git a/v0.10.x/_sources/auto_examples/17_pybullet/viz_domino.rst.txt b/v0.10.x/_sources/auto_examples/17_pybullet/viz_domino.rst.txt new file mode 100644 index 000000000..b29ccb36e --- /dev/null +++ b/v0.10.x/_sources/auto_examples/17_pybullet/viz_domino.rst.txt @@ -0,0 +1,411 @@ + +.. DO NOT EDIT. +.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. +.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: +.. "auto_examples/17_pybullet/viz_domino.py" +.. LINE NUMBERS ARE GIVEN BELOW. + +.. only:: html + + .. note:: + :class: sphx-glr-download-link-note + + :ref:`Go to the end ` + to download the full example code + +.. rst-class:: sphx-glr-example-title + +.. _sphx_glr_auto_examples_17_pybullet_viz_domino.py: + + +========================= +Domino Physics Simulation +========================= + +This example simulation shows how to use pybullet to render physics simulations +in fury. In this example we specifically render a series of Dominoes which are +under Domino Effect. + +First some imports. + +.. GENERATED FROM PYTHON SOURCE LINES 12-26 + +.. code-block:: Python + + import itertools + + import numpy as np + import pybullet as p + + from fury import actor, ui, utils, window + + # Next, we initialize a pybullet client to render the physics. + # We use `DIRECT` mode to initialize pybullet without a GUI. + client = p.connect(p.DIRECT) + + # Apply gravity to the scene. + p.setGravity(0, 0, -10, physicsClientId=client) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 27-28 + +Set the Number of Dominoes for Simulation. + +.. GENERATED FROM PYTHON SOURCE LINES 28-55 + +.. code-block:: Python + + number_of_dominoes = 10 + + # Base Plane Parameters + base_size = np.array([number_of_dominoes * 2, number_of_dominoes * 2, 0.2]) + base_color = np.array([1, 1, 1]) + base_position = np.array([0, 0, -0.1]) + base_orientation = np.array([0, 0, 0, 1]) + + # Render a BASE plane to support the Dominoes. + base_actor = actor.box( + centers=np.array([[0, 0, 0]]), + directions=[0, 0, 0], + scales=base_size, + colors=base_color, + ) + + # half of the actual size. + base_coll = p.createCollisionShape(p.GEOM_BOX, halfExtents=base_size / 2) + + base = p.createMultiBody( + baseCollisionShapeIndex=base_coll, + basePosition=base_position, + baseOrientation=base_orientation, + ) + + p.changeDynamics(base, -1, lateralFriction=1, restitution=0.5) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 56-58 + +We define some global parameters of the Dominoes so that its easier for +us to tweak the simulation. + +.. GENERATED FROM PYTHON SOURCE LINES 58-103 + +.. code-block:: Python + + + domino_mass = 0.5 + domino_size = np.array([0.1, 1, 2]) + + domino_centers = np.zeros((number_of_dominoes, 3)) + + # Keeping all the dominos Parallel + domino_directions = np.zeros((number_of_dominoes, 3)) + domino_directions[:] = np.array([1.57, 0, 0]) + + domino_orns = np.zeros((number_of_dominoes, 4)) + + domino_sizes = np.zeros((number_of_dominoes, 3)) + domino_sizes[:] = domino_size + + domino_colors = np.random.rand(number_of_dominoes, 3) + + domino_coll = p.createCollisionShape(p.GEOM_BOX, halfExtents=domino_size / 2) + + # We use this array to store the reference of domino objects in pybullet world. + dominos = np.zeros(number_of_dominoes, dtype=np.int8) + + centers_list = np.zeros((number_of_dominoes, 3)) + + # Adding the dominoes + for i in range(number_of_dominoes): + center_pos = np.array([(i * 0.99) - 5.5, 0.4, 1]) + domino_centers[i] = center_pos + domino_orns[i] = np.array([0, 0, 0, 1]) + dominos[i] = p.createMultiBody( + baseMass=domino_mass, + baseCollisionShapeIndex=domino_coll, + basePosition=center_pos, + baseOrientation=domino_orns[i], + ) + p.changeDynamics(dominos[i], -1, lateralFriction=0.2, restitution=0.1) + + + domino_actor = actor.box( + centers=domino_centers, + directions=domino_directions, + scales=domino_sizes, + colors=domino_colors, + ) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 104-105 + +Now, we define a scene and add actors to it. + +.. GENERATED FROM PYTHON SOURCE LINES 105-121 + +.. code-block:: Python + + scene = window.Scene() + scene.add(actor.axes()) + scene.add(base_actor) + scene.add(domino_actor) + + # Create show manager. + showm = window.ShowManager( + scene, size=(900, 768), reset_camera=False, order_transparent=True + ) + + + # Counter iterator for tracking simulation steps. + counter = itertools.count() + + # Variable for tracking applied force. + apply_force = True + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 122-123 + +Now, we define methods to sync objects between fury and Pybullet. + +.. GENERATED FROM PYTHON SOURCE LINES 123-135 + +.. code-block:: Python + + + # Get the position of base and set it. + base_pos, _ = p.getBasePositionAndOrientation(base) + base_actor.SetPosition(*base_pos) + + + # Calculate the vertices of the dominos. + vertices = utils.vertices_from_actor(domino_actor) + num_vertices = vertices.shape[0] + num_objects = domino_centers.shape[0] + sec = int(num_vertices / num_objects) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 136-150 + +================ +Syncing Dominoes +================ + +Here, we perform three major steps to sync Dominoes accurately. +* Get the position and orientation of the Dominoes from pybullet. +* Calculate the Rotation Matrix. + + - Get the difference in orientations (Quaternion). + - Generate the corresponding rotation matrix according to that difference. + - Reshape it in a 3x3 matrix. + +* Perform calculations to get the required position and orientation. +* Update the position and orientation. + +.. GENERATED FROM PYTHON SOURCE LINES 150-171 + +.. code-block:: Python + + + + def sync_domino(object_index, multibody): + pos, orn = p.getBasePositionAndOrientation(multibody) + + rot_mat = np.reshape( + p.getMatrixFromQuaternion( + p.getDifferenceQuaternion(orn, domino_orns[object_index]) + ), + (3, 3), + ) + + vertices[object_index * sec : object_index * sec + sec] = ( + vertices[object_index * sec : object_index * sec + sec] + - domino_centers[object_index] + ) @ rot_mat + pos + + domino_centers[object_index] = pos + domino_orns[object_index] = orn + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 172-173 + +Here, we define a textblock to display the Avg. FPS and simulation steps. + +.. GENERATED FROM PYTHON SOURCE LINES 173-180 + +.. code-block:: Python + + + fpss = np.array([]) + tb = ui.TextBlock2D( + text='Avg. FPS: \nSim Steps: ', position=(0, 680), font_size=30, color=(1, 0.5, 0) + ) + scene.add(tb) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 181-182 + +Set the camera for better visualization. + +.. GENERATED FROM PYTHON SOURCE LINES 182-190 + +.. code-block:: Python + + + scene.set_camera( + position=(10.46, -8.13, 6.18), + focal_point=(0.0, 0.0, 0.79), + view_up=(-0.27, 0.26, 0.90), + ) + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 191-193 + +Timer callback is created which is responsible for calling the sync and +simulation methods. + +.. GENERATED FROM PYTHON SOURCE LINES 193-247 + +.. code-block:: Python + + + + # Create timer callback which will execute at each step of simulation. + def timer_callback(_obj, _event): + global apply_force, fpss + cnt = next(counter) + showm.render() + + if cnt % 1 == 0: + fps = showm.frame_rate + fpss = np.append(fpss, fps) + tb.message = ( + 'Avg. FPS: ' + str(np.round(np.mean(fpss), 0)) + '\nSim Steps: ' + str(cnt) + ) + + # Get the position and orientation of the first domino. + domino1_pos, domino1_orn = p.getBasePositionAndOrientation(dominos[0]) + + # Apply force on the First Domino (domino) above the Center of Mass. + if apply_force: + # Apply the force. + p.applyExternalForce( + dominos[0], + -1, + forceObj=[100, 0, 0], + posObj=domino1_pos + np.array([0, 0, 1.7]), + flags=p.WORLD_FRAME, + ) + apply_force = False + + # Updating the position and orientation of individual dominos. + for idx, domino in enumerate(dominos): + sync_domino(idx, domino) + utils.update_actor(domino_actor) + + # Simulate a step. + p.stepSimulation() + + # Exit after 300 steps of simulation. + if cnt == 300: + showm.exit() + + + # Add the timer callback to showmanager. + # Increasing the duration value will slow down the simulation. + showm.add_timer_callback(True, 1, timer_callback) + + interactive = False + + # start simulation + if interactive: + showm.start() + + window.record(scene, out_path='viz_domino.png', size=(900, 768)) + + + +.. image-sg:: /auto_examples/17_pybullet/images/sphx_glr_viz_domino_001.png + :alt: viz domino + :srcset: /auto_examples/17_pybullet/images/sphx_glr_viz_domino_001.png + :class: sphx-glr-single-img + + + + + + +.. rst-class:: sphx-glr-timing + + **Total running time of the script:** (0 minutes 0.110 seconds) + + +.. _sphx_glr_download_auto_examples_17_pybullet_viz_domino.py: + +.. only:: html + + .. container:: sphx-glr-footer sphx-glr-footer-example + + .. container:: sphx-glr-download sphx-glr-download-jupyter + + :download:`Download Jupyter notebook: viz_domino.ipynb ` + + .. container:: sphx-glr-download sphx-glr-download-python + + :download:`Download Python source code: viz_domino.py ` + + +.. only:: html + + .. rst-class:: sphx-glr-signature + + `Gallery generated by Sphinx-Gallery `_ diff --git a/v0.10.x/_sources/auto_examples/17_pybullet/viz_wrecking_ball.rst.txt b/v0.10.x/_sources/auto_examples/17_pybullet/viz_wrecking_ball.rst.txt new file mode 100644 index 000000000..8833ca85a --- /dev/null +++ b/v0.10.x/_sources/auto_examples/17_pybullet/viz_wrecking_ball.rst.txt @@ -0,0 +1,632 @@ + +.. DO NOT EDIT. +.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. +.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: +.. "auto_examples/17_pybullet/viz_wrecking_ball.py" +.. LINE NUMBERS ARE GIVEN BELOW. + +.. only:: html + + .. note:: + :class: sphx-glr-download-link-note + + :ref:`Go to the end ` + to download the full example code + +.. rst-class:: sphx-glr-example-title + +.. _sphx_glr_auto_examples_17_pybullet_viz_wrecking_ball.py: + + +======================== +Wrecking Ball Simulation +======================== + +This example simulation shows how to use pybullet to render physics simulations +in fury. In this example we specifically render a brick wall being destroyed by +a wrecking ball. + +First some imports. + +.. GENERATED FROM PYTHON SOURCE LINES 12-19 + +.. code-block:: Python + + import itertools + + import numpy as np + import pybullet as p + + from fury import actor, ui, utils, window + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 20-21 + +Initiate pybullet and enable gravity. + +.. GENERATED FROM PYTHON SOURCE LINES 21-25 + +.. code-block:: Python + + + p.connect(p.DIRECT) + p.setGravity(0, 0, -10) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 26-27 + +Define some handy parameters to customize simulation. + +.. GENERATED FROM PYTHON SOURCE LINES 27-50 + +.. code-block:: Python + + + # Parameters + wall_length = 5 + wall_breadth = 5 + wall_height = 5 + + brick_size = np.array([0.2, 0.4, 0.2]) + + n_links = 15 + # Size of segments + dx_link = 0.1 + link_mass = 0.5 + base_mass = 0.1 + # radius of the cylindrical links or the rope + radii = 0.1 + + ball_mass = 10 + # radius of the wrecking ball + ball_radius = 0.5 + ball_color = np.array([[1, 0, 0]]) + + joint_friction = 0.0005 + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 51-52 + +Creating the base plane actor. + +.. GENERATED FROM PYTHON SOURCE LINES 52-68 + +.. code-block:: Python + + + # Base + base_actor = actor.box( + centers=np.array([[0, 0, 0]]), + directions=[0, 0, 0], + scales=(5, 5, 0.2), + colors=(1, 1, 1), + ) + base_coll = p.createCollisionShape(p.GEOM_BOX, halfExtents=[2.5, 2.5, 0.1]) + base = p.createMultiBody( + baseCollisionShapeIndex=base_coll, + basePosition=[0, 0, -0.1], + baseOrientation=[0, 0, 0, 1], + ) + p.changeDynamics(base, -1, lateralFriction=0.3, restitution=0.5) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 69-70 + +The following definitions are made to render a NxNxN brick wall. + +.. GENERATED FROM PYTHON SOURCE LINES 70-89 + +.. code-block:: Python + + + # Generate bricks. + nb_bricks = wall_length * wall_breadth * wall_height + brick_centers = np.zeros((nb_bricks, 3)) + + brick_directions = np.zeros((nb_bricks, 3)) + brick_directions[:] = np.array([1.57, 0, 0]) + + brick_orns = np.zeros((nb_bricks, 4)) + + brick_sizes = np.zeros((nb_bricks, 3)) + brick_sizes[:] = brick_size + + brick_colors = np.random.rand(nb_bricks, 3) + + brick_coll = p.createCollisionShape(p.GEOM_BOX, halfExtents=brick_size / 2) + + bricks = np.zeros(nb_bricks, dtype=np.int16) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 90-92 + +The following is the logic to position the bricks in our desired location and +generate the actor. + +.. GENERATED FROM PYTHON SOURCE LINES 92-117 + +.. code-block:: Python + + + idx = 0 + # Setting up wall + for i in range(wall_length): + for k in range(wall_height): + for j in range(wall_breadth): + center_pos = np.array([(i * 0.2) - 1.8, (j * 0.4) - 0.9, (0.2 * k) + 0.1]) + brick_centers[idx] = center_pos + brick_orns[idx] = np.array([0, 0, 0, 1]) + bricks[idx] = p.createMultiBody( + baseMass=0.5, + baseCollisionShapeIndex=brick_coll, + basePosition=center_pos, + baseOrientation=brick_orns[i], + ) + p.changeDynamics(bricks[idx], -1, lateralFriction=0.1, restitution=0.1) + idx += 1 + + brick_actor = actor.box( + centers=brick_centers, + directions=brick_directions, + scales=brick_sizes, + colors=brick_colors, + ) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 118-119 + +Now we render the wrecking ball consisting of a fixed hinge, a ball and rope. + +.. GENERATED FROM PYTHON SOURCE LINES 119-191 + +.. code-block:: Python + + + # Generate wrecking ball + link_shape = p.createCollisionShape( + p.GEOM_CYLINDER, + radius=radii, + height=dx_link, + collisionFramePosition=[0, 0, -dx_link / 2], + ) + + base_shape = p.createCollisionShape(p.GEOM_BOX, halfExtents=[0.01, 0.01, 0.01]) + ball_shape = p.createCollisionShape(p.GEOM_SPHERE, radius=ball_radius) + + visualShapeId = -1 + + link_Masses = np.zeros(n_links) + link_Masses[:] = link_mass + link_Masses[-1] = 5 + linkCollisionShapeIndices = np.zeros(n_links) + linkCollisionShapeIndices[:] = np.array(link_shape) + linkCollisionShapeIndices[-1] = ball_shape + linkVisualShapeIndices = -1 * np.ones(n_links) + linkPositions = np.zeros((n_links, 3)) + linkPositions[:] = np.array([0, 0, -dx_link]) + linkOrientations = np.zeros((n_links, 4)) + linkOrientations[:] = np.array([0, 0, 0, 1]) + linkInertialFramePositions = np.zeros((n_links, 3)) + linkInertialFrameOrns = np.zeros((n_links, 4)) + linkInertialFrameOrns[:] = np.array([0, 0, 0, 1]) + indices = np.arange(n_links) + jointTypes = np.zeros(n_links) + jointTypes[:] = np.array(p.JOINT_SPHERICAL) + axis = np.zeros((n_links, 3)) + axis[:] = np.array([1, 0, 0]) + + linkDirections = np.zeros((n_links, 3)) + linkDirections[:] = np.array([1, 1, 1]) + + link_radii = np.zeros(n_links) + link_radii[:] = radii + + link_heights = np.zeros(n_links) + link_heights[:] = dx_link + + rope_actor = actor.cylinder( + centers=linkPositions, + directions=linkDirections, + colors=np.random.rand(n_links, 3), + radius=radii, + heights=link_heights, + capped=True, + ) + + basePosition = [0, 0, 2] + baseOrientation = [0, 0, 0, 1] + rope = p.createMultiBody( + base_mass, + base_shape, + visualShapeId, + basePosition, + baseOrientation, + linkMasses=link_Masses, + linkCollisionShapeIndices=linkCollisionShapeIndices.astype(int), + linkVisualShapeIndices=linkVisualShapeIndices.astype(int), + linkPositions=linkPositions.astype(int), + linkOrientations=linkOrientations.astype(int), + linkInertialFramePositions=linkInertialFramePositions.astype(int), + linkInertialFrameOrientations=linkInertialFrameOrns.astype(int), + linkParentIndices=indices.astype(int), + linkJointTypes=jointTypes.astype(int), + linkJointAxis=axis.astype(int), + ) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 192-193 + +Next we define the frictional force between the joints of wrecking ball. + +.. GENERATED FROM PYTHON SOURCE LINES 193-208 + +.. code-block:: Python + + + friction_vec = [joint_friction] * 3 # same all axis + control_mode = p.POSITION_CONTROL # set pos control mode + for j in range(p.getNumJoints(rope)): + p.setJointMotorControlMultiDof( + rope, + j, + control_mode, + targetPosition=[0, 0, 0, 1], + targetVelocity=[0, 0, 0], + positionGain=0, + velocityGain=1, + force=friction_vec, + ) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 209-210 + +We add the following constraint to keep the cubical hinge fixed. + +.. GENERATED FROM PYTHON SOURCE LINES 210-226 + +.. code-block:: Python + + + root_robe_c = p.createConstraint( + rope, -1, -1, -1, p.JOINT_FIXED, [0, 0, 0], [0, 0, 0], [0, 0, 2] + ) + + box_actor = actor.box( + centers=np.array([[0, 0, 0]]), + directions=np.array([[0, 0, 0]]), + scales=(0.02, 0.02, 0.02), + colors=np.array([[1, 0, 0]]), + ) + + ball_actor = actor.sphere( + centers=np.array([[0, 0, 0]]), radii=ball_radius, colors=np.array([1, 0, 1]) + ) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 227-229 + +Now we add the necessary actors to the scene and set the camera for better +visualization. + +.. GENERATED FROM PYTHON SOURCE LINES 229-240 + +.. code-block:: Python + + + scene = window.Scene() + scene.set_camera((10.28, -7.10, 6.39), (0.0, 0.0, 0.4), (-0.35, 0.26, 1.0)) + scene.add(actor.axes(scale=(0.5, 0.5, 0.5)), base_actor, brick_actor) + scene.add(rope_actor, box_actor, ball_actor) + + showm = window.ShowManager( + scene, size=(900, 768), reset_camera=False, order_transparent=True + ) + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 241-242 + +Position the base correctly. + +.. GENERATED FROM PYTHON SOURCE LINES 242-246 + +.. code-block:: Python + + + base_pos, base_orn = p.getBasePositionAndOrientation(base) + base_actor.SetPosition(*base_pos) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 247-248 + +Calculate the vertices of the bricks. + +.. GENERATED FROM PYTHON SOURCE LINES 248-254 + +.. code-block:: Python + + + brick_vertices = utils.vertices_from_actor(brick_actor) + num_vertices = brick_vertices.shape[0] + num_objects = brick_centers.shape[0] + brick_sec = int(num_vertices / num_objects) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 255-256 + +Calculate the vertices of the wrecking ball. + +.. GENERATED FROM PYTHON SOURCE LINES 256-263 + +.. code-block:: Python + + + chain_vertices = utils.vertices_from_actor(rope_actor) + num_vertices = chain_vertices.shape[0] + num_objects = brick_centers.shape[0] + chain_sec = int(num_vertices / num_objects) + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 264-265 + +We define methods to sync bricks and wrecking ball. + +.. GENERATED FROM PYTHON SOURCE LINES 265-312 + +.. code-block:: Python + + + # Function for syncing actors with multibodies. + def sync_brick(object_index, multibody): + pos, orn = p.getBasePositionAndOrientation(multibody) + + rot_mat = np.reshape( + p.getMatrixFromQuaternion( + p.getDifferenceQuaternion(orn, brick_orns[object_index]) + ), + (3, 3), + ) + + sec = brick_sec + + brick_vertices[object_index * sec : object_index * sec + sec] = ( + brick_vertices[object_index * sec : object_index * sec + sec] + - brick_centers[object_index] + ) @ rot_mat + pos + + brick_centers[object_index] = pos + brick_orns[object_index] = orn + + + def sync_chain(actor_list, multibody): + for joint in range(p.getNumJoints(multibody)): + # `p.getLinkState` offers various information about the joints + # as a list and the values in 4th and 5th index refer to the joint's + # position and orientation respectively. + pos, orn = p.getLinkState(multibody, joint)[4:6] + + rot_mat = np.reshape( + p.getMatrixFromQuaternion( + p.getDifferenceQuaternion(orn, linkOrientations[joint]) + ), + (3, 3), + ) + + sec = chain_sec + + chain_vertices[joint * sec : joint * sec + sec] = ( + chain_vertices[joint * sec : joint * sec + sec] - linkPositions[joint] + ) @ rot_mat + pos + + linkPositions[joint] = pos + linkOrientations[joint] = orn + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 313-314 + +Some helper tools to keep track of avg. FPS and simulation steps. + +.. GENERATED FROM PYTHON SOURCE LINES 314-322 + +.. code-block:: Python + + + counter = itertools.count() + fpss = np.array([]) + tb = ui.TextBlock2D( + position=(0, 680), font_size=30, color=(1, 0.5, 0), text='Avg. FPS: \nSim Steps: ' + ) + scene.add(tb) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 323-324 + +Timer callback to sync objects, simulate steps and apply force. + +.. GENERATED FROM PYTHON SOURCE LINES 324-377 + +.. code-block:: Python + + + apply_force = True + + + # Create timer callback which will execute at each step of simulation. + def timer_callback(_obj, _event): + global apply_force, fpss + cnt = next(counter) + showm.render() + + if cnt % 1 == 0: + fps = showm.frame_rate + fpss = np.append(fpss, fps) + tb.message = ( + 'Avg. FPS: ' + str(np.round(np.mean(fpss), 0)) + '\nSim Steps: ' + str(cnt) + ) + + # Updating the position and orientation of each individual brick. + for idx, brick in enumerate(bricks): + sync_brick(idx, brick) + + pos, _ = p.getBasePositionAndOrientation(rope) + + if apply_force: + p.applyExternalForce( + rope, -1, forceObj=[-500, 0, 0], posObj=pos, flags=p.WORLD_FRAME + ) + apply_force = False + + pos = p.getLinkState(rope, p.getNumJoints(rope) - 1)[4] + ball_actor.SetPosition(*pos) + sync_chain(rope_actor, rope) + utils.update_actor(brick_actor) + utils.update_actor(rope_actor) + + # Simulate a step. + p.stepSimulation() + + if cnt == 130: + showm.exit() + + + # Add the timer callback to showmanager. + # Increasing the duration value will slow down the simulation. + showm.add_timer_callback(True, 1, timer_callback) + + interactive = True #False + + # start simulation + if interactive: + showm.start() + + window.record(scene, size=(900, 768), out_path='viz_wrecking_ball.png') + + + +.. image-sg:: /auto_examples/17_pybullet/images/sphx_glr_viz_wrecking_ball_001.png + :alt: viz wrecking ball + :srcset: /auto_examples/17_pybullet/images/sphx_glr_viz_wrecking_ball_001.png + :class: sphx-glr-single-img + + + + + + +.. rst-class:: sphx-glr-timing + + **Total running time of the script:** (0 minutes 3.473 seconds) + + +.. _sphx_glr_download_auto_examples_17_pybullet_viz_wrecking_ball.py: + +.. only:: html + + .. container:: sphx-glr-footer sphx-glr-footer-example + + .. container:: sphx-glr-download sphx-glr-download-jupyter + + :download:`Download Jupyter notebook: viz_wrecking_ball.ipynb ` + + .. container:: sphx-glr-download sphx-glr-download-python + + :download:`Download Python source code: viz_wrecking_ball.py ` + + +.. only:: html + + .. rst-class:: sphx-glr-signature + + `Gallery generated by Sphinx-Gallery `_ diff --git a/v0.10.x/_sources/auto_examples/20_stream/index.rst.txt b/v0.10.x/_sources/auto_examples/20_stream/index.rst.txt new file mode 100644 index 000000000..725b373e0 --- /dev/null +++ b/v0.10.x/_sources/auto_examples/20_stream/index.rst.txt @@ -0,0 +1,83 @@ + + +.. _sphx_glr_auto_examples_20_stream: + +Streaming +--------- + +These tutorials show: + +- How to create a simple streaming server and turn that available. +- How to create a streaming server with user interaction. +- How to create a streaming server using the Widget Object. + + + +.. raw:: html + +
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/20_stream/images/thumb/sphx_glr_viz_widget_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_20_stream_viz_widget.py` + +.. raw:: html + +
Streaming FURY with WebRTC/MJPEG using the Widget Object
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/20_stream/images/thumb/sphx_glr_viz_no_interaction_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_20_stream_viz_no_interaction.py` + +.. raw:: html + +
Streaming FURY with WebRTC/MJPEG
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/20_stream/images/thumb/sphx_glr_viz_interaction_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_20_stream_viz_interaction.py` + +.. raw:: html + +
Streaming FURY with user interaction
+
+ + +.. raw:: html + +
+ + +.. toctree:: + :hidden: + + /auto_examples/20_stream/viz_widget + /auto_examples/20_stream/viz_no_interaction + /auto_examples/20_stream/viz_interaction + diff --git a/v0.10.x/_sources/auto_examples/20_stream/sg_execution_times.rst.txt b/v0.10.x/_sources/auto_examples/20_stream/sg_execution_times.rst.txt new file mode 100644 index 000000000..ba4feeeb0 --- /dev/null +++ b/v0.10.x/_sources/auto_examples/20_stream/sg_execution_times.rst.txt @@ -0,0 +1,43 @@ + +:orphan: + +.. _sphx_glr_auto_examples_20_stream_sg_execution_times: + + +Computation times +================= +**00:03.155** total execution time for 3 files **from auto_examples/20_stream**: + +.. container:: + + .. raw:: html + + + + + + + + .. list-table:: + :header-rows: 1 + :class: table table-striped sg-datatable + + * - Example + - Time + - Mem (MB) + * - :ref:`sphx_glr_auto_examples_20_stream_viz_widget.py` (``viz_widget.py``) + - 00:01.648 + - 0.0 + * - :ref:`sphx_glr_auto_examples_20_stream_viz_no_interaction.py` (``viz_no_interaction.py``) + - 00:01.397 + - 0.0 + * - :ref:`sphx_glr_auto_examples_20_stream_viz_interaction.py` (``viz_interaction.py``) + - 00:00.109 + - 0.0 diff --git a/v0.10.x/_sources/auto_examples/20_stream/viz_interaction.rst.txt b/v0.10.x/_sources/auto_examples/20_stream/viz_interaction.rst.txt new file mode 100644 index 000000000..93f6f1391 --- /dev/null +++ b/v0.10.x/_sources/auto_examples/20_stream/viz_interaction.rst.txt @@ -0,0 +1,206 @@ + +.. DO NOT EDIT. +.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. +.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: +.. "auto_examples/20_stream/viz_interaction.py" +.. LINE NUMBERS ARE GIVEN BELOW. + +.. only:: html + + .. note:: + :class: sphx-glr-download-link-note + + :ref:`Go to the end ` + to download the full example code + +.. rst-class:: sphx-glr-example-title + +.. _sphx_glr_auto_examples_20_stream_viz_interaction.py: + + +==================================== +Streaming FURY with user interaction +==================================== + +In this tutorial, we show how to use the FURY Streaming system to +serve an interactive visualization through a web browser. + +You can choose between two different encodings: WebRTC or MJPEG. +WebRTC is a more robust option and can be used to perform +a live streaming with a low-latency connection for example using +ngrok. However, to use webRTC you need to install the aiortc library. + +.. code-block:: bash + + pip install aiortc + + +Notes +----- +If you don't have ffmpeg installed, you need to install it to use WebRTC + +Linux + + +`apt install libavdevice-dev libavfilter-dev libopus-dev libvpx-dev pkg-config` + +OS X + +`brew install ffmpeg opus libvpx pkg-config` + +.. GENERATED FROM PYTHON SOURCE LINES 33-147 + + + +.. image-sg:: /auto_examples/20_stream/images/sphx_glr_viz_interaction_001.png + :alt: viz interaction + :srcset: /auto_examples/20_stream/images/sphx_glr_viz_interaction_001.png + :class: sphx-glr-single-img + + + + + +.. code-block:: Python + + + import multiprocessing + import sys + + import numpy as np + + from fury import actor, window + from fury.stream.client import FuryStreamClient, FuryStreamInteraction + + # if this example it's not working for you and you're using MacOs + # uncomment the following line + # multiprocessing.set_start_method('spawn') + from fury.stream.server.main import WEBRTC_AVAILABLE, web_server, web_server_raw_array + + if __name__ == '__main__': + interactive = False + # `use_raw_array` is a flag to tell the server to use python RawArray + # instead of SharedMemory which is a new feature in python 3.8 + # https://docs.python.org/3/library/multiprocessing.html#multiprocessing.Array + # https://docs.python.org/3/library/multiprocessing.html#shared-memory-objects + + use_raw_array = sys.version_info < (3, 8) + window_size = (300, 300) + # `max_window_size` are the maximum size of the window that will be + # allowed to be sent to the browser. For example, if you set + # `max_window_size=(800, 800)` then the browser will be limited to + # a window of size (800, 800). + + max_window_size = (400, 400) + # 0 ms_stream means that the frame will be sent to the server + # right after the rendering + + # `ms_interaction` is the time in milliseconds that the user will have + # to interact with the visualization + + ms_interaction = 1 + # `ms_stream` is the number of milliseconds that the server will + # wait before sending a new frame to the browser. If `ms_stream=0` + # then the server will send the frame right after the rendering. + + ms_stream = 0 + # max number of interactions to be stored inside the queue + max_queue_size = 17 + ###################################################################### + centers = np.array([[0, 0, 0], [-1, 0, 0], [1, 0, 0]]) + colors = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]]) + + actors = actor.sphere(centers, opacity=0.5, radii=0.4, colors=colors) + scene = window.Scene() + + scene.add(actors) + + showm = window.ShowManager(scene, size=(window_size[0], window_size[1])) + + stream = FuryStreamClient( + showm, max_window_size=max_window_size, use_raw_array=use_raw_array + ) + stream_interaction = FuryStreamInteraction( + showm, max_queue_size=max_queue_size, use_raw_array=use_raw_array + ) + + if use_raw_array: + p = multiprocessing.Process( + target=web_server_raw_array, + args=( + stream.img_manager.image_buffers, + stream.img_manager.info_buffer, + stream_interaction.circular_queue.head_tail_buffer, + stream_interaction.circular_queue.buffer._buffer, + 8000, + 'localhost', + True, + WEBRTC_AVAILABLE, + ), + ) + + else: + p = multiprocessing.Process( + target=web_server, + args=( + stream.img_manager.image_buffer_names, + stream.img_manager.info_buffer_name, + stream_interaction.circular_queue.head_tail_buffer_name, + stream_interaction.circular_queue.buffer.buffer_name, + 8000, + 'localhost', + True, + WEBRTC_AVAILABLE, + ), + ) + p.start() + stream_interaction.start(ms=ms_interaction) + stream.start( + ms_stream, + ) + ########################################################################### + # If you have aiortc in your system, you can see your live streaming + # through the following url: htttp://localhost:8000/?encoding=webrtc + # Other wise, you can use the following url: + # http://localhost:8000/?encoding=mjpeg + + if interactive: + showm.start() + + # We need to close the server after the show is over + p.kill() + ########################################################################### + # We release the resources and stop the interactive mode + stream.stop() + stream_interaction.stop() + stream.cleanup() + stream_interaction.cleanup() + + window.record(showm.scene, size=window_size, out_path='viz_interaction.png') + + +.. rst-class:: sphx-glr-timing + + **Total running time of the script:** (0 minutes 0.109 seconds) + + +.. _sphx_glr_download_auto_examples_20_stream_viz_interaction.py: + +.. only:: html + + .. container:: sphx-glr-footer sphx-glr-footer-example + + .. container:: sphx-glr-download sphx-glr-download-jupyter + + :download:`Download Jupyter notebook: viz_interaction.ipynb ` + + .. container:: sphx-glr-download sphx-glr-download-python + + :download:`Download Python source code: viz_interaction.py ` + + +.. only:: html + + .. rst-class:: sphx-glr-signature + + `Gallery generated by Sphinx-Gallery `_ diff --git a/v0.10.x/_sources/auto_examples/20_stream/viz_no_interaction.rst.txt b/v0.10.x/_sources/auto_examples/20_stream/viz_no_interaction.rst.txt new file mode 100644 index 000000000..2d0c3b9df --- /dev/null +++ b/v0.10.x/_sources/auto_examples/20_stream/viz_no_interaction.rst.txt @@ -0,0 +1,179 @@ + +.. DO NOT EDIT. +.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. +.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: +.. "auto_examples/20_stream/viz_no_interaction.py" +.. LINE NUMBERS ARE GIVEN BELOW. + +.. only:: html + + .. note:: + :class: sphx-glr-download-link-note + + :ref:`Go to the end ` + to download the full example code + +.. rst-class:: sphx-glr-example-title + +.. _sphx_glr_auto_examples_20_stream_viz_no_interaction.py: + + +==================================== +Streaming FURY with WebRTC/MJPEG +==================================== + +.. GENERATED FROM PYTHON SOURCE LINES 6-107 + + + +.. image-sg:: /auto_examples/20_stream/images/sphx_glr_viz_no_interaction_001.png + :alt: viz no interaction + :srcset: /auto_examples/20_stream/images/sphx_glr_viz_no_interaction_001.png + :class: sphx-glr-single-img + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + webrtc not available + Dataset is already in place. If you want to fetch it again please first remove the folder /Users/skoudoro/.fury/examples/wiki_nw + More information about complex networks can be found in this papers: https://arxiv.org/abs/0711.3199 + + + + + + +| + +.. code-block:: Python + + + import multiprocessing + from os.path import join as pjoin + + # if this example it's not working for you and you're using MacOs + # uncomment the following line + # multiprocessing.set_start_method('spawn') + import numpy as np + + from fury import actor + from fury import colormap as cmap + from fury import window + from fury.data.fetcher import fetch_viz_wiki_nw + from fury.stream.client import FuryStreamClient + from fury.stream.server.main import web_server_raw_array + + if __name__ == '__main__': + + interactive = False + ########################################################################### + # First we will set the resolution which it'll be used by the streamer + + window_size = (400, 400) + + files, folder = fetch_viz_wiki_nw() + categories_file, edges_file, positions_file = sorted(files.keys()) + positions = np.loadtxt(pjoin(folder, positions_file)) + categories = np.loadtxt(pjoin(folder, categories_file), dtype=str) + edges = np.loadtxt(pjoin(folder, edges_file), dtype=int) + category2index = {category: i for i, category in enumerate(np.unique(categories))} + + index2category = np.unique(categories) + + categoryColors = cmap.distinguishable_colormap(nb_colors=len(index2category)) + + colors = np.array( + [categoryColors[category2index[category]] for category in categories] + ) + radii = 1 + np.random.rand(len(positions)) + + edgesPositions = [] + edgesColors = [] + for source, target in edges: + edgesPositions.append(np.array([positions[source], positions[target]])) + edgesColors.append(np.array([colors[source], colors[target]])) + + edgesPositions = np.array(edgesPositions) + edgesColors = np.average(np.array(edgesColors), axis=1) + + sphere_actor = actor.sdf( + centers=positions, + colors=colors, + primitives='sphere', + scales=radii * 0.5, + ) + + lines_actor = actor.line( + edgesPositions, + colors=edgesColors, + opacity=0.1, + ) + scene = window.Scene() + + scene.add(lines_actor) + scene.add(sphere_actor) + + scene.set_camera( + position=(0, 0, 1000), focal_point=(0.0, 0.0, 0.0), view_up=(0.0, 0.0, 0.0) + ) + + showm = window.ShowManager( + scene, + reset_camera=False, + size=(window_size[0], window_size[1]), + order_transparent=False, + ) + + ########################################################################### + # ms define the amount of mileseconds that will be used in the timer event. + + ms = 0 + + stream = FuryStreamClient(showm, use_raw_array=True) + p = multiprocessing.Process( + target=web_server_raw_array, + args=( + stream.img_manager.image_buffers, + stream.img_manager.info_buffer, + ), + ) + p.start() + + stream.start( + ms, + ) + if interactive: + showm.start() + stream.stop() + stream.cleanup() + + window.record(showm.scene, size=window_size, out_path='viz_no_interaction.png') + + +.. rst-class:: sphx-glr-timing + + **Total running time of the script:** (0 minutes 1.397 seconds) + + +.. _sphx_glr_download_auto_examples_20_stream_viz_no_interaction.py: + +.. only:: html + + .. container:: sphx-glr-footer sphx-glr-footer-example + + .. container:: sphx-glr-download sphx-glr-download-jupyter + + :download:`Download Jupyter notebook: viz_no_interaction.ipynb ` + + .. container:: sphx-glr-download sphx-glr-download-python + + :download:`Download Python source code: viz_no_interaction.py ` + + +.. only:: html + + .. rst-class:: sphx-glr-signature + + `Gallery generated by Sphinx-Gallery `_ diff --git a/v0.10.x/_sources/auto_examples/20_stream/viz_widget.rst.txt b/v0.10.x/_sources/auto_examples/20_stream/viz_widget.rst.txt new file mode 100644 index 000000000..78682c2d5 --- /dev/null +++ b/v0.10.x/_sources/auto_examples/20_stream/viz_widget.rst.txt @@ -0,0 +1,181 @@ + +.. DO NOT EDIT. +.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. +.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: +.. "auto_examples/20_stream/viz_widget.py" +.. LINE NUMBERS ARE GIVEN BELOW. + +.. only:: html + + .. note:: + :class: sphx-glr-download-link-note + + :ref:`Go to the end ` + to download the full example code + +.. rst-class:: sphx-glr-example-title + +.. _sphx_glr_auto_examples_20_stream_viz_widget.py: + + +======================================================== +Streaming FURY with WebRTC/MJPEG using the Widget Object +======================================================== + +The Widget Object simplifies the process of streaming +your data visualization with WebRTC or MJPEG. Encoding. +Other users can view and interact with your data visualization +in real-time using a web-browser. + +By default, the widget will open a local server on port 8000. +With the encoding parameter you can choose between mjpeg or +webrtc. WebRTC is a more robust option and can be used to perform +a live streaming with a low-latency connection. However, to use +webRTC you need to install the aiortc library. + +.. code-block:: bash + + pip install aiortc + +In addition, if you don't have ffmpeg installed, you need +to install it. + +Linux + + +`apt install libavdevice-dev libavfilter-dev libopus-dev libvpx-dev pkg-config` + +OS X + +`brew install ffmpeg opus libvpx pkg-config` + +Notes +----- +For this example your python version should be 3.8 or greater + +.. GENERATED FROM PYTHON SOURCE LINES 38-58 + +.. code-block:: Python + + + import asyncio + import platform + import time + + import numpy as np + + from fury import actor, window + from fury.stream.widget import Widget + + interactive = False + window_size = (720, 500) + N = 4 + centers = np.random.normal(size=(N, 3)) + colors = np.random.uniform(0.1, 1.0, size=(N, 3)) + actors = actor.sphere(centers, opacity=0.5, radii=0.4, colors=colors) + scene = window.Scene() + scene.add(actors) + showm = window.ShowManager(scene, size=(window_size[0], window_size[1])) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 59-60 + +Create a stream widget + +.. GENERATED FROM PYTHON SOURCE LINES 60-69 + +.. code-block:: Python + + + widget = Widget(showm, port=8000) + + # if you want to use webRTC, you can pass the argument to choose this encoding + # which is a more robust option. + # `widget = Widget(showm, port=8000, encoding='webrtc')` + + time_sleep = 1000 if interactive else 1 + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 70-73 + +If you want to use the widget in a Windows environment without the WSL +you need to use the asyncio version of the widget. + + +.. GENERATED FROM PYTHON SOURCE LINES 73-90 + +.. code-block:: Python + + if platform.system() == 'Windows': + + async def main(): + widget.start() + await asyncio.sleep(time_sleep) + widget.stop() + + loop = asyncio.get_event_loop() + loop.run_until_complete(main()) + else: + # Running the widget in a normal Python environment in Linux or MacOS + # we can use the normal version of the widget. + widget.start() + time.sleep(time_sleep) + widget.stop() + + window.record(showm.scene, size=window_size, out_path='viz_widget.png') + + + +.. image-sg:: /auto_examples/20_stream/images/sphx_glr_viz_widget_001.png + :alt: viz widget + :srcset: /auto_examples/20_stream/images/sphx_glr_viz_widget_001.png + :class: sphx-glr-single-img + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + url: http://localhost:8000?iframe=1&encoding=mjpeg + + + + + +.. rst-class:: sphx-glr-timing + + **Total running time of the script:** (0 minutes 1.648 seconds) + + +.. _sphx_glr_download_auto_examples_20_stream_viz_widget.py: + +.. only:: html + + .. container:: sphx-glr-footer sphx-glr-footer-example + + .. container:: sphx-glr-download sphx-glr-download-jupyter + + :download:`Download Jupyter notebook: viz_widget.ipynb ` + + .. container:: sphx-glr-download sphx-glr-download-python + + :download:`Download Python source code: viz_widget.py ` + + +.. only:: html + + .. rst-class:: sphx-glr-signature + + `Gallery generated by Sphinx-Gallery `_ diff --git a/v0.10.x/_sources/auto_examples/index.rst.txt b/v0.10.x/_sources/auto_examples/index.rst.txt new file mode 100644 index 000000000..cb243f216 --- /dev/null +++ b/v0.10.x/_sources/auto_examples/index.rst.txt @@ -0,0 +1,1471 @@ +:orphan: + +.. _ref_examples: + +Tutorials +========= + +How to use widgets, ui, actor and windows module. Below some examples and apps to go in details. + + + +.. raw:: html + +
+ + +.. raw:: html + +
+ +Introductory +------------ + +These tutorials show: + +- How to combine a timer with an actor +- How to slice data with the slicer actor +- How to use the normals of your data. + + + +.. raw:: html + +
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/01_introductory/images/thumb/sphx_glr_viz_texture_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_01_introductory_viz_texture.py` + +.. raw:: html + +
Sphere Texture
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/01_introductory/images/thumb/sphx_glr_viz_gltf_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_01_introductory_viz_gltf.py` + +.. raw:: html + +
Visualizing a glTF file
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/01_introductory/images/thumb/sphx_glr_viz_sphere_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_01_introductory_viz_sphere.py` + +.. raw:: html + +
FURY sphere Actor
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/01_introductory/images/thumb/sphx_glr_viz_cone_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_01_introductory_viz_cone.py` + +.. raw:: html + +
Fury Cone Actor
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/01_introductory/images/thumb/sphx_glr_viz_arrow_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_01_introductory_viz_arrow.py` + +.. raw:: html + +
Fury Arrow Actor
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/01_introductory/images/thumb/sphx_glr_viz_gltf_animated_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_01_introductory_viz_gltf_animated.py` + +.. raw:: html + +
Visualizing a glTF file
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/01_introductory/images/thumb/sphx_glr_viz_morphing_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_01_introductory_viz_morphing.py` + +.. raw:: html + +
Morphing Animation in a glTF
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/01_introductory/images/thumb/sphx_glr_viz_gltf_export_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_01_introductory_viz_gltf_export.py` + +.. raw:: html + +
Exporting scene as a glTF file
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/01_introductory/images/thumb/sphx_glr_viz_skinning_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_01_introductory_viz_skinning.py` + +.. raw:: html + +
Skeletal Animation in a glTF file
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/01_introductory/images/thumb/sphx_glr_viz_timers_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_01_introductory_viz_timers.py` + +.. raw:: html + +
Using a timer
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/01_introductory/images/thumb/sphx_glr_viz_spiky_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_01_introductory_viz_spiky.py` + +.. raw:: html + +
Spiky Sphere
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/01_introductory/images/thumb/sphx_glr_viz_surfaces_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_01_introductory_viz_surfaces.py` + +.. raw:: html + +
Visualize surfaces
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/01_introductory/images/thumb/sphx_glr_viz_selection_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_01_introductory_viz_selection.py` + +.. raw:: html + +
Selecting multiple objects
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/01_introductory/images/thumb/sphx_glr_viz_multithread_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_01_introductory_viz_multithread.py` + +.. raw:: html + +
Multithreading Example
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/01_introductory/images/thumb/sphx_glr_viz_picking_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_01_introductory_viz_picking.py` + +.. raw:: html + +
Simple picking
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/01_introductory/images/thumb/sphx_glr_viz_earth_animation_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_01_introductory_viz_earth_animation.py` + +.. raw:: html + +
Texture Sphere Animation
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/01_introductory/images/thumb/sphx_glr_viz_earth_coordinates_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_01_introductory_viz_earth_coordinates.py` + +.. raw:: html + +
Earth Coordinate Conversion
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/01_introductory/images/thumb/sphx_glr_viz_slice_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_01_introductory_viz_slice.py` + +.. raw:: html + +
Simple volume slicing
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/01_introductory/images/thumb/sphx_glr_viz_solar_system_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_01_introductory_viz_solar_system.py` + +.. raw:: html + +
Solar System Animation
+
+ + +.. raw:: html + +
+ +Demos +----- + +Below is a gallery of Demos. A bunch of apps powered by FURY. + + + +.. raw:: html + +
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/04_demos/images/thumb/sphx_glr_viz_markers_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_04_demos_viz_markers.py` + +.. raw:: html + +
Fury Markers
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/04_demos/images/thumb/sphx_glr_viz_network_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_04_demos_viz_network.py` + +.. raw:: html + +
Visualize Interdisciplinary map of the journals network
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/04_demos/images/thumb/sphx_glr_viz_roi_contour_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_04_demos_viz_roi_contour.py` + +.. raw:: html + +
Visualization of ROI Surface Rendered with Streamlines
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/04_demos/images/thumb/sphx_glr_viz_helical_motion_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_04_demos_viz_helical_motion.py` + +.. raw:: html + +
Motion of a charged particle in a combined magnetic and electric field
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/04_demos/images/thumb/sphx_glr_viz_brownian_motion_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_04_demos_viz_brownian_motion.py` + +.. raw:: html + +
Brownian motion
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/04_demos/images/thumb/sphx_glr_viz_play_video_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_04_demos_viz_play_video.py` + +.. raw:: html + +
Play a video in the 3D world
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/04_demos/images/thumb/sphx_glr_viz_fine_tuning_gl_context_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_04_demos_viz_fine_tuning_gl_context.py` + +.. raw:: html + +
Fine-tuning the OpenGL state using shader callbacks
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/04_demos/images/thumb/sphx_glr_viz_emwave_animation_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_04_demos_viz_emwave_animation.py` + +.. raw:: html + +
Electromagnetic Wave Propagation Animation
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/04_demos/images/thumb/sphx_glr_viz_animated_surfaces_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_04_demos_viz_animated_surfaces.py` + +.. raw:: html + +
Animated 2D functions
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/04_demos/images/thumb/sphx_glr_viz_bundles_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_04_demos_viz_bundles.py` + +.. raw:: html + +
Visualize bundles and metrics on bundles
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/04_demos/images/thumb/sphx_glr_viz_tesseract_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_04_demos_viz_tesseract.py` + +.. raw:: html + +
Tesseract (Hypercube)
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/04_demos/images/thumb/sphx_glr_collision-particles_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_04_demos_collision-particles.py` + +.. raw:: html + +
Collisions of particles in a box
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/04_demos/images/thumb/sphx_glr_viz_advanced_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_04_demos_viz_advanced.py` + +.. raw:: html + +
Advanced interactive visualization
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/04_demos/images/thumb/sphx_glr_viz_fiber_odf_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_04_demos_viz_fiber_odf.py` + +.. raw:: html + +
Brain Fiber ODF Visualisation
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/04_demos/images/thumb/sphx_glr_viz_fractals_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_04_demos_viz_fractals.py` + +.. raw:: html + +
Fractals
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/04_demos/images/thumb/sphx_glr_viz_network_animated_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_04_demos_viz_network_animated.py` + +.. raw:: html + +
Visualize Networks (Animated version)
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/04_demos/images/thumb/sphx_glr_viz_dt_ellipsoids_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_04_demos_viz_dt_ellipsoids.py` + +.. raw:: html + +
Display Tensor Ellipsoids for DTI using tensor_slicer vs ellipsoid actor
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/04_demos/images/thumb/sphx_glr_viz_pbr_interactive_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_04_demos_viz_pbr_interactive.py` + +.. raw:: html + +
Interactive PBR demo
+
+ + +.. raw:: html + +
+ +User Interface Elements +----------------------- + +These tutorials show how to create user interfaces elements. + + + +.. raw:: html + +
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/07_ui/images/thumb/sphx_glr_viz_shapes_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_07_ui_viz_shapes.py` + +.. raw:: html + +
Simple Shapes
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/07_ui/images/thumb/sphx_glr_viz_drawpanel_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_07_ui_viz_drawpanel.py` + +.. raw:: html + +
DrawPanel
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/07_ui/images/thumb/sphx_glr_viz_card_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_07_ui_viz_card.py` + +.. raw:: html + +
Card
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/07_ui/images/thumb/sphx_glr_viz_spinbox_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_07_ui_viz_spinbox.py` + +.. raw:: html + +
SpinBox UI
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/07_ui/images/thumb/sphx_glr_viz_combobox_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_07_ui_viz_combobox.py` + +.. raw:: html + +
ComboBox
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/07_ui/images/thumb/sphx_glr_viz_ui_listbox_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_07_ui_viz_ui_listbox.py` + +.. raw:: html + +
ListBox
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/07_ui/images/thumb/sphx_glr_viz_layout_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_07_ui_viz_layout.py` + +.. raw:: html + +
Using Layouts with different UI elements
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/07_ui/images/thumb/sphx_glr_viz_radio_buttons_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_07_ui_viz_radio_buttons.py` + +.. raw:: html + +
Sphere Color Control using Radio Buttons
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/07_ui/images/thumb/sphx_glr_viz_buttons_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_07_ui_viz_buttons.py` + +.. raw:: html + +
Buttons & Text
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/07_ui/images/thumb/sphx_glr_viz_card_sprite_sheet_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_07_ui_viz_card_sprite_sheet.py` + +.. raw:: html + +
Card
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/07_ui/images/thumb/sphx_glr_viz_ui_slider_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_07_ui_viz_ui_slider.py` + +.. raw:: html + +
Cube & Slider Control
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/07_ui/images/thumb/sphx_glr_viz_check_boxes_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_07_ui_viz_check_boxes.py` + +.. raw:: html + +
Figure and Color Control using Check boxes and Radio Buttons
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/07_ui/images/thumb/sphx_glr_viz_tab_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_07_ui_viz_tab.py` + +.. raw:: html + +
Tab UI
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/07_ui/images/thumb/sphx_glr_viz_ui_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_07_ui_viz_ui.py` + +.. raw:: html + +
User Interfaces
+
+ + +.. raw:: html + +
+ +Animation +--------- + +These tutorials show: + +- How to animate FURY actors. +- How to use different interpolation methods in animations. + + + +.. raw:: html + +
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/10_animation/images/thumb/sphx_glr_viz_introduction_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_10_animation_viz_introduction.py` + +.. raw:: html + +
Keyframe animation introduction
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/10_animation/images/thumb/sphx_glr_viz_timeline_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_10_animation_viz_timeline.py` + +.. raw:: html + +
Timeline and setting keyframes
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/10_animation/images/thumb/sphx_glr_viz_spline_interpolator_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_10_animation_viz_spline_interpolator.py` + +.. raw:: html + +
Keyframes Spline Interpolator
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/10_animation/images/thumb/sphx_glr_viz_using_time_equations_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_10_animation_viz_using_time_equations.py` + +.. raw:: html + +
Keyframe animation
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/10_animation/images/thumb/sphx_glr_viz_interpolators_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_10_animation_viz_interpolators.py` + +.. raw:: html + +
Keyframe animation
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/10_animation/images/thumb/sphx_glr_viz_color_interpolators_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_10_animation_viz_color_interpolators.py` + +.. raw:: html + +
Keyframe Color Interpolators
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/10_animation/images/thumb/sphx_glr_viz_robot_arm_animation_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_10_animation_viz_robot_arm_animation.py` + +.. raw:: html + +
Arm Robot Animation
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/10_animation/images/thumb/sphx_glr_viz_hierarchical_animation_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_10_animation_viz_hierarchical_animation.py` + +.. raw:: html + +
Keyframe hierarchical Animation
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/10_animation/images/thumb/sphx_glr_viz_bezier_interpolator_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_10_animation_viz_bezier_interpolator.py` + +.. raw:: html + +
Bezier Interpolator
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/10_animation/images/thumb/sphx_glr_viz_camera_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_10_animation_viz_camera.py` + +.. raw:: html + +
Keyframe animation: Camera and opacity
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/10_animation/images/thumb/sphx_glr_viz_custom_interpolator_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_10_animation_viz_custom_interpolator.py` + +.. raw:: html + +
Making a custom interpolator
+
+ + +.. raw:: html + +
+ +Shaders +------- + +These tutorials show: + +- How to use shaders in FURY actors. +- How to create new user shaders and internal conventions. + + + +.. raw:: html + +
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/13_shaders/images/thumb/sphx_glr_viz_sdfactor_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_13_shaders_viz_sdfactor.py` + +.. raw:: html + +
Visualize SDF Actor
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/13_shaders/images/thumb/sphx_glr_viz_principled_spheres_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_13_shaders_viz_principled_spheres.py` + +.. raw:: html + +
Principled BRDF shader on spheres
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/13_shaders/images/thumb/sphx_glr_viz_shader_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_13_shaders_viz_shader.py` + +.. raw:: html + +
Varying Color
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/13_shaders/images/thumb/sphx_glr_viz_pbr_spheres_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_13_shaders_viz_pbr_spheres.py` + +.. raw:: html + +
Physically-Based Rendering (PBR) on spheres
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/13_shaders/images/thumb/sphx_glr_viz_billboard_sdf_spheres_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_13_shaders_viz_billboard_sdf_spheres.py` + +.. raw:: html + +
SDF Impostors on Billboards
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/13_shaders/images/thumb/sphx_glr_viz_sdf_cylinder_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_13_shaders_viz_sdf_cylinder.py` + +.. raw:: html + +
Make a Cylinder using polygons vs SDF
+
+ + +.. raw:: html + +
+ +Integrate Physics using pybullet +-------------------------------- + +These demos show how to use connect FURY with a physics engine library. + + + +.. raw:: html + +
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/17_pybullet/images/thumb/sphx_glr_viz_ball_collide_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_17_pybullet_viz_ball_collide.py` + +.. raw:: html + +
Ball Collision Simulation
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/17_pybullet/images/thumb/sphx_glr_viz_domino_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_17_pybullet_viz_domino.py` + +.. raw:: html + +
Domino Physics Simulation
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/17_pybullet/images/thumb/sphx_glr_viz_chain_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_17_pybullet_viz_chain.py` + +.. raw:: html + +
Chain Simulation
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/17_pybullet/images/thumb/sphx_glr_viz_brick_wall_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_17_pybullet_viz_brick_wall.py` + +.. raw:: html + +
Brick Wall Simulation
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/17_pybullet/images/thumb/sphx_glr_viz_wrecking_ball_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_17_pybullet_viz_wrecking_ball.py` + +.. raw:: html + +
Wrecking Ball Simulation
+
+ + +.. raw:: html + +
+ +Streaming +--------- + +These tutorials show: + +- How to create a simple streaming server and turn that available. +- How to create a streaming server with user interaction. +- How to create a streaming server using the Widget Object. + + + +.. raw:: html + +
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/20_stream/images/thumb/sphx_glr_viz_widget_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_20_stream_viz_widget.py` + +.. raw:: html + +
Streaming FURY with WebRTC/MJPEG using the Widget Object
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/20_stream/images/thumb/sphx_glr_viz_no_interaction_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_20_stream_viz_no_interaction.py` + +.. raw:: html + +
Streaming FURY with WebRTC/MJPEG
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /auto_examples/20_stream/images/thumb/sphx_glr_viz_interaction_thumb.png + :alt: + + :ref:`sphx_glr_auto_examples_20_stream_viz_interaction.py` + +.. raw:: html + +
Streaming FURY with user interaction
+
+ + +.. raw:: html + +
+ + +.. toctree:: + :hidden: + :includehidden: + + + /auto_examples/01_introductory/index.rst + /auto_examples/04_demos/index.rst + /auto_examples/07_ui/index.rst + /auto_examples/10_animation/index.rst + /auto_examples/13_shaders/index.rst + /auto_examples/17_pybullet/index.rst + /auto_examples/20_stream/index.rst + + +.. only:: html + + .. container:: sphx-glr-footer sphx-glr-footer-gallery + + .. container:: sphx-glr-download sphx-glr-download-python + + :download:`Download all examples in Python source code: auto_examples_python.zip ` + + .. container:: sphx-glr-download sphx-glr-download-jupyter + + :download:`Download all examples in Jupyter notebooks: auto_examples_jupyter.zip ` + + +.. only:: html + + .. rst-class:: sphx-glr-signature + + `Gallery generated by Sphinx-Gallery `_ diff --git a/v0.10.x/_sources/auto_examples/sg_execution_times.rst.txt b/v0.10.x/_sources/auto_examples/sg_execution_times.rst.txt new file mode 100644 index 000000000..ccb2da185 --- /dev/null +++ b/v0.10.x/_sources/auto_examples/sg_execution_times.rst.txt @@ -0,0 +1,37 @@ + +:orphan: + +.. _sphx_glr_auto_examples_sg_execution_times: + + +Computation times +================= +**00:00.000** total execution time for 0 files **from auto_examples**: + +.. container:: + + .. raw:: html + + + + + + + + .. list-table:: + :header-rows: 1 + :class: table table-striped sg-datatable + + * - Example + - Time + - Mem (MB) + * - N/A + - N/A + - N/A diff --git a/v0.10.x/_sources/blog.rst.txt b/v0.10.x/_sources/blog.rst.txt new file mode 100644 index 000000000..6a1bb5dad --- /dev/null +++ b/v0.10.x/_sources/blog.rst.txt @@ -0,0 +1,3 @@ +==== +Blog +==== diff --git a/v0.10.x/_sources/community.rst.txt b/v0.10.x/_sources/community.rst.txt new file mode 100644 index 000000000..a12efa4a6 --- /dev/null +++ b/v0.10.x/_sources/community.rst.txt @@ -0,0 +1,89 @@ +.. _community: + +========= +Community +========= + +Join Us! +-------- + +.. raw:: html + + + +Contributors +------------ + +.. raw:: html + +
+
+
+
+
+
+ +
+ Stars + +
+
+
+
+
+ +
+ {{ basic_stats["forks_count"] }} Forks + +
+
+
+
+
+ +
+ {{ contributors["total_contributors"] }} Contributors + +
+
+
+
+
+ +
+ {{ contributors["total_commits"] }} Commits + +
+
+
+ +
+
diff --git a/v0.10.x/_sources/fury-pybullet.rst.txt b/v0.10.x/_sources/fury-pybullet.rst.txt new file mode 100644 index 000000000..bd1c8077c --- /dev/null +++ b/v0.10.x/_sources/fury-pybullet.rst.txt @@ -0,0 +1,519 @@ +.. _fury_pybullet: + +FURY - pyBullet Integration Guide +================================= + +.. contents:: + :local: + :depth: 3 + +**Official docs:** + * `FURY `__ + + * `pyBullet `__ + +.. note:: All elements are in SI units. + +Simple Rigid Body Dynamics +************************** + +Necessary Imports +----------------- +The following imports are necessary for physics simulations: + ++-----------------------+---------------------------------------------------------------+ +| Imports | Usage | ++=======================+===============================================================+ +| Numpy | Creation of arrays and conversion of radians to degrees. | ++-----------------------+---------------------------------------------------------------+ +| FURY | Window and Actor API is used to visualize the simulation. | ++-----------------------+---------------------------------------------------------------+ +| pyBullet | Physics simulation. | ++-----------------------+---------------------------------------------------------------+ +| Itertools | The Counter iterator for keeping track of simulation steps. | ++-----------------------+---------------------------------------------------------------+ + + +.. code-block:: python + + import numpy as np + from fury import window, actor + import itertools + import pybullet as p + +Connection Mode +--------------- + +*"After importing the PyBullet module, the first thing to do is 'connecting' to the physics simulation. PyBullet is designed around a client-server driven API, with a client sending commands and a physics server returning the status. PyBullet has some built-in physics servers: DIRECT and GUI."* + +In our case we use **DIRECT** connection as the visualization will be handled by FURY. + +.. code-block:: python + + client = p.connect(p.DIRECT) + +.. note:: Keeping track of physics client ID is optional unless multiple physics clients are used. In order to observe the same simulation in pybullet, replace ``p.DIRECT`` with ``p.GUI``. + +Disconnection +------------- + +PyBullet Physics client can be shutdown by the following command: + +.. code-block:: python + + p.disconnect() + +Setting Gravity +--------------- + +Global :py:class:`.Scene()` gravity can be set using the following command: + +.. code-block:: python + + # Gravity vector. + gravity_x = 0 + gravity_y = 0 + gravity_z = -10 + p.setGravity(gravity_x, gravity_y, gravity_z) + +Creating Objects +---------------- + +The following criterion must be fulfilled in order to create an object which is in sync with both FURY and pyBullet: + + ++-----------------------+----------------------------------------------------------------------+ +| Object Actor | The actor which will be rendered by FURY | ++-----------------------+----------------------------------------------------------------------+ +| Collision Shape | The shape used by pybullet for collision simulations. | +| | **Optional** if collision simulation is not required. | ++-----------------------+----------------------------------------------------------------------+ +| Multi-Body | The object that will be tracked by pybullet for general simulations.| ++-----------------------+----------------------------------------------------------------------+ + +The following is a snippet for creating a spherical ball of radius = 0.3 + +.. code-block:: python + + ###### Creating BALL + # Ball actor + ball_actor = actor.sphere(centers = np.array([[0, 0, 0]]), + colors=np.array([1,0,0]), + radii=0.3) + + # Collision shape for the ball. + ball_coll = p.createCollisionShape(p.GEOM_SPHERE, + radius=0.3) + + # Creating a Multibody which will be tracked by pybullet. + ball = p.createMultiBody(baseMass=3, + baseCollisionShapeIndex=ball_coll, + basePosition=[2, 0, 1.5], + baseOrientation=[ 0, 0, 0, 1 ]) + +.. warning:: Centers for the actor must be set to ``(0, 0, 0)`` or else the simulation will be offset by that particular value. + +Changing Object Dynamics +------------------------ + +Object dynamics such as mass, lateral_friction, damping, inertial_pos, inertial_orn, restitution, rolling friction etc can be changed. The following snippet shows how to change the lateral_friction and coeff of restitution of the same ball: + +.. code-block:: python + + p.changeDynamics(ball, -1, lateralFriction=0.3, restitution=0.5) + +.. note:: The second parameter is ``linkIndex`` which is for bodies having multiple links or joints. Passing -1 means applying changes to the base object. + +Adding objects to the scene +--------------------------- + +Objects can be added simply by adding their respective actors to the scene. + +.. code-block:: python + + scene = window.Scene() + scene.add(ball_actor) + +Application of Force/Torque +--------------------------- + +External force or torque to a body can be applied using applyExternalForce and applyExternalTorque. For e.g + +.. code-block:: python + + p.applyExternalForce(ball, -1, + forceObj=[-2000, 0, 0], + posObj=ball_pos, + flags=p.WORLD_FRAME) + +Here, the first argument refers to the object, the second one refers to the link, ``forceObj`` = force vector, ``posObj`` = Position Vector of the application of force. [Not applicable for ``applyExternalTorque``]. + +.. code-block:: python + + p.applyExternalTorque(ball, -1, + forceObj=[-2000, 0, 0], + flags=p.WORLD_FRAME) + +Enabling collision +------------------ + +By default, collision detection is enabled between different dynamic moving bodies. The following snippet can be used to enable/disable collision explicitly between a pair of objects. + +.. code-block:: python + + enableCol = 1 + p.setCollisionFilterPair(ball, brick, -1, -1, enableCol) + +Here, we enable the collision between a ball and a brick object. + +Creation of Show Manager +------------------------ + +A ``window.ShowManager`` and ``itertools.count`` instance must be created before defining the timer callback function and setting it to initialize. + +.. code-block:: python + + # Create a show manager. + showm = window.ShowManager(scene, + size=(900, 768), reset_camera=False, + order_transparent=True) + showm.initialize() + # Counter iterator for tracking simulation steps. + counter = itertools.count() + +Syncing properties of actors +---------------------------- + +The position and orientation of the actors in FURY can be updated by the values generated in pybullet during simulation. The following snippet updates all required parameters. + +.. code-block:: python + + # Get the position and orientation of the ball. + ball_pos, ball_orn = p.getBasePositionAndOrientation(ball) + + # Set position and orientation of the ball. + ball_actor.SetPosition(*ball_pos) + orn_deg = np.degrees(p.getEulerFromQuaternion(ball_orn)) + ball_actor.SetOrientation(*orn_deg) + +``ball`` and ``ball_actor`` can be replaced by the appropriate object and actor. + +Creation of Timer Callback +-------------------------- + +To simulate physics we need to call ``p.stepSimulation()`` in order to simulate a single step of physics simulation. Therefore, in order to update actors and simulate steps at each interval, we need to create a timer callback. At this point one can perform any operation that they feel like during each step of the simulation. This is also the appropriate section for the user to define all syncing activities required by the actors and render the scene accordingly. The following can be an example snippet: + +.. code-block:: python + + # Counter iterator for tracking simulation steps. + counter = itertools.count() + + # Variable for tracking applied force. + apply_force = True + + # Create a timer callback which will execute at each step of simulation. + def timer_callback(_obj, _event): + global apply_force + cnt = next(counter) + showm.render() + # Get the position and orientation of the ball. + ball_pos, ball_orn = p.getBasePositionAndOrientation(ball) + + # Apply force for 5 times for the first step of simulation. + if apply_force: + # Apply the force. + p.applyExternalForce(ball, -1, + forceObj=[-2000, 0, 0], + posObj=ball_pos, + flags=p.WORLD_FRAME) + apply_force = False + + # Set position and orientation of the ball. + ball_actor.SetPosition(*ball_pos) + orn_deg = np.degrees(p.getEulerFromQuaternion(ball_orn)) + ball_actor.SetOrientation(*orn_deg) + ball_actor.RotateWXYZ(*ball_orn) + + # Simulate a step. + p.stepSimulation() + + # Exit after 2000 steps of simulation. + if cnt == 2000: + showm.exit() + + # Add the timer callback to showmanager. + # Increasing the duration value will slow down the simulation. + showm.add_timer_callback(True, 10, timer_callback) + +Initiating the simulation +------------------------- + +Once everything is set up, one can execute ``showm.start()`` to start the simulation. + +Rendering multiple objects by a single actor +-------------------------------------------- + +Rendering multiple similar objects by a single actor is possible by manually updating the vertices of the individual objects. The said procedure will be demonstrated with the help of the brick wall simulation example where each brick is rendered by a single actor. +Firstly, we need to define the following parameters: + ++-------------------------+-----------------------+-------------------------------------------------------------------------+ +| Variable | Shape | Description | ++=========================+=======================+=========================================================================+ +| nb_objects | 1, 1 | Number of objects to be rendered | ++-------------------------+-----------------------+-------------------------------------------------------------------------+ +| object_centers | nb_objects, 3 | To keep track of the centers in the xyz coordinate system. [x, y, z] | ++-------------------------+-----------------------+-------------------------------------------------------------------------+ +| object_directions | nb_objects, 3 | Array to track directions. | ++-------------------------+-----------------------+-------------------------------------------------------------------------+ +| object_orientations | nb_objects, 4 | Array to track orientations in quaternions. [x, y, z, w] | ++-------------------------+-----------------------+-------------------------------------------------------------------------+ +| object_colors | nb_bricks, 3 | Array to track colors. | ++-------------------------+-----------------------+-------------------------------------------------------------------------+ +| object_collision | 1, 1 | Collision shape of the objects. | ++-------------------------+-----------------------+-------------------------------------------------------------------------+ + +.. warning:: ``object_directions`` & ``object_orientations`` must be updated together or else orientation of objects in both the worlds may not be in sync. + +Once we are ready with the above variables and array, we can proceed further to render the objects both in the FURY and pybullet world: + +Rendering objects in FURY +~~~~~~~~~~~~~~~~~~~~~~~~~ + +To render objects in the FURY world we simply call the respective actors. For this example we call ``actor.box`` for rendering the bricks: + +.. code-block:: python + + brick_actor_single = actor.box(centers=brick_centers, + directions=brick_directions, + scales=brick_sizes, + colors=brick_colors) + + scene.add(brick_actor_single) + +Render Pybullet Objects +~~~~~~~~~~~~~~~~~~~~~~~ + +Now to render pybullet objects we simply create a list of multibodies: + +.. code-block:: python + + bricks[i] = p.createMultiBody(baseMass=0.5, + baseCollisionShapeIndex=brick_coll, + basePosition=center_pos, + baseOrientation=brick_orn) + +Syncing objects +~~~~~~~~~~~~~~~ + +Now in order to calculate and the vertices we execute the following snippet: + +.. code-block:: python + + vertices = utils.vertices_from_actor(brick_actor_single) + num_vertices = vertices.shape[0] + num_objects = brick_centers.shape[0] + sec = int(num_vertices / num_objects) + ++-------------------+---------------------------------------------------------+ +| Vertices | Array storing vertices of all the objects. | ++===================+=========================================================+ +| num_vertices | Number of vertices required to render the objects. | ++-------------------+---------------------------------------------------------+ +| num_objects | Number of objects rendered | ++-------------------+---------------------------------------------------------+ +| sec | Number of vertices required to render a single object. | ++-------------------+---------------------------------------------------------+ + + +Now the pybullet and FURY objects can be synced together by the following snippet: + +.. code-block:: python + + def sync_brick(object_index, multibody): + pos, orn = p.getBasePositionAndOrientation(multibody) + + rot_mat = np.reshape( + p.getMatrixFromQuaternion( + p.getDifferenceQuaternion(orn, brick_orns[object_index])), + (3, 3)) + + vertices[object_index * sec: object_index * sec + sec] = \ + (vertices[object_index * sec: object_index * sec + sec] - + brick_centers[object_index])@rot_mat + pos + + brick_centers[object_index] = pos + brick_orns[object_index] = orn + + +In order to Sync correctly, we do the following: + +#. First we get the current position and orientation of the objects in the pybullet world with the help of ``p.getBasePositionAndOrientation``. +#. Then we calculate the difference between two quaternions using ``p.getDifferenceFromQuarternion``. +#. The said difference is then passed to ``p.getMatrixFromQuaternion`` to calculate the rotation matrix. +#. Now the method returns a tuple of size 9. Therefore we finally need to reshape the said tuple into a 3x3 matrix with the help of ``np.reshape``. +#. Next, we slice the necessary part of the vertices which render our desired object. +#. Then we bring it back to the origin by subtracting their centers. +#. After that we perform matrix multiplication of the rotation matrix and the vertices to orient the object. +#. After orientation we bring the object to its new position. +#. Finally we update the centers and the orientation of the object. + +Lastly, we call this function in our timer callback to sync the objects correctly. + +.. note:: VTK has an in-built method to handle gimbal locks therefore using ``actor.SetOrientation`` may lead to unwanted spinning simulations each time a gimbal lock is experienced. Hence, it is always advisable to use vertices and its corresponding rotation matrix to set the orientation. + +Rendering Joints +---------------- + +.. image:: https://raw.githubusercontent.com/fury-gl/fury-communication-assets/main/physics_joints.png + :align: center + +A simulated robot as described in a URDF file has a base, and optionally links connected by joints. Each joint connects one parent link to a child link. At the root of the hierarchy there is a single root parent that we call base. The base can be either fully fixed, 0 degrees of freedom, or fully free, with 6 degrees of freedom. Since each link is connected to a parent with a single joint, the number of joints is equal to the number of links. Regular links have link indices in the range ``[0..getNumJoints()]`` Since the base is not a regular 'link', we use the convention of -1 as its link index. We use the convention that joint frames are expressed relative to the parent center of mass inertial frame, which is aligned with the principal axis of inertia. To know more how joints are implemented in pybullet refer the official docs. + +We can create and sync joints in pybullet and FURY by following a few simple steps: + +Firstly, in order to create objects with multiple joints we need to keep track of the following parameters: + + ++-----------------------------+--------------------+------------------------------------------+ +| Vertices | Shape | Description | ++=============================+====================+==========================================+ +| nb_links | 1,1 | Number of links to be rendered. | ++-----------------------------+--------------------+------------------------------------------+ +| link_masses | nb_links | Masses of the links. | ++-----------------------------+--------------------+------------------------------------------+ +| linkCollisionShapeIndices | nb_links | Array tracking the collision shape IDs. | ++-----------------------------+--------------------+------------------------------------------+ +| linkVisualShapeIndices | nb_links | Optional as we won't be using | +| | | pybullet’s GUI render. | ++-----------------------------+--------------------+------------------------------------------+ +| linkPositions | nb_links, 3 | Position of the links in [x, y, z]. | ++-----------------------------+--------------------+------------------------------------------+ +| linkOrientations | nb_links, 4 | Orientation of the links in | +| | | [x, y, z, w]. | ++-----------------------------+--------------------+------------------------------------------+ +| linkInertialFramePositions | nb_links, 3 | Position of the inertial frame of the | +| | | links. | ++-----------------------------+--------------------+------------------------------------------+ +| linkInertialFrameOrns | nb_links, 4 | Orientation of the inertial frame of | +| | | the links. | ++-----------------------------+--------------------+------------------------------------------+ +| indices | nb_link | Link ID each corresponding link is | +| | | supposed to attach at. | ++-----------------------------+--------------------+------------------------------------------+ +| jointTypes | nb_link | The type of joint between the links. | +| | | Multiple joint types are available. | ++-----------------------------+--------------------+------------------------------------------+ +| axis | nb_links, 3 | The axis at which each link is supposed | +| | | to rotate. | ++-----------------------------+--------------------+------------------------------------------+ +| linkDirections | nb_links, 3 | Direction vector required to render | +| | | links in FURY. | ++-----------------------------+--------------------+------------------------------------------+ + +Extra Arrays such as ``linkHeights``, ``linkRadii`` etc may be required based on the link shape. +**Base link** is rendered separately, hence the above parameters should not contain information about the base link. + +Now separately create definitions for the base link using the following parameters. Once we are ready with the required link parameters and definition, we can create a multibody to be rendered in the pybullet world. We can do so using ``p.createMultiBody``. Here’s a snippet: + +.. code-block:: python + + rope = p.createMultiBody(base_mass, + base_shape, + visualShapeId, + basePosition, + baseOrientation, + linkMasses=link_Masses, + linkCollisionShapeIndices=linkCollisionShapeIndices, + linkVisualShapeIndices=linkVisualShapeIndices, + linkPositions=linkPositions, + linkOrientations=linkOrientations, + linkInertialFramePositions=linkInertialFramePositions, + linkInertialFrameOrientations=linkInertialFrameOrns, + linkParentIndices=indices, + linkJointTypes=jointTypes, + linkJointAxis=axis) + +Once we are done with the multibody we can create the actor to render the links: + +.. code-block:: python + + rope_actor = actor.cylinder(centers=linkPositions, + directions=linkDirections, + colors=np.random.rand(n_links, 3), + radius=radii, + heights=link_heights, capped=True) + +We can sync the joints using the following code snippet: + +.. code-block:: python + + def sync_joints(actor_list, multibody): + for joint in range(p.getNumJoints(multibody)): + pos, orn = p.getLinkState(multibody, joint)[4:6] + + rot_mat = np.reshape( + p.getMatrixFromQuaternion( + p.getDifferenceQuaternion(orn, linkOrientations[joint])), + (3, 3)) + + vertices[joint * sec: joint * sec + sec] =\ + (vertices[joint * sec: joint * sec + sec] - + linkPositions[joint])@rot_mat + pos + + linkPositions[joint] = pos + linkOrientations[joint] = orn + +Here, we determine the total number of joints using ``p.getNumJoints`` and run a loop to iterate through all the joints present within the object. Once we get access to a particular joint we use the ``p.getLinkState`` to get various information about a particular joint. Within the list of information we have access to positions and orientation of the joints at index 4 and 5. So we perform the query to get the position and orientation of the joints. After that the process of translation and rotation are the same as shown here. + +--------------------- + +Examples +******** + +Brick Wall Simulation +--------------------- + +.. image:: https://raw.githubusercontent.com/fury-gl/fury-communication-assets/main/physics_bricks_multi_actor.gif + :align: center + +The code for the above simulation can be found `here `__. + +Ball Collision Simulation +------------------------- + +.. image:: https://raw.githubusercontent.com/fury-gl/fury-communication-assets/main/physics_collision.gif + :align: center + +The code for the above simulation can be found `here `__. + +Brick Wall Simulation(Single Actor) +----------------------------------- + +.. image:: https://raw.githubusercontent.com/fury-gl/fury-communication-assets/main/physics_bricks_fast.gif + :align: center + +The code for the above simulation can be found `here `__. + +Chain Simulation +---------------- + +.. image:: https://raw.githubusercontent.com/fury-gl/fury-communication-assets/main/physics_chain.gif + :align: center + +The code for the above simulation can be found `here `__. + +Wrecking Ball Simulation +------------------------ + +.. image:: https://raw.githubusercontent.com/fury-gl/fury-communication-assets/main/physics_wrecking_ball.gif + :align: center + +The code for the above simulation can be found `here `__. + +Domino Simulation +----------------- + +.. image:: https://raw.githubusercontent.com/fury-gl/fury-communication-assets/main/physics_domino.gif + :align: center + +The code for the above simulation can be found `here `__. diff --git a/v0.10.x/_sources/getting_started.rst.txt b/v0.10.x/_sources/getting_started.rst.txt new file mode 100644 index 000000000..94d54d859 --- /dev/null +++ b/v0.10.x/_sources/getting_started.rst.txt @@ -0,0 +1,92 @@ +=============== +Getting Started +=============== + +Start by importing FURY. + +.. code-block:: python + + import numpy as np + from fury import window, actor, ui, io, utils + +To import a model, use :py:func:`.io.load_polydata`. Currently supported formats include OBJ, VTK, FIB, PLY, STL and XML. + +Here we are going to use ``suzanne`` model used by Blender. You can find more detail about what is suzanne model `here `_. + +We can download the model by + +.. code-block:: python + + from fury.data import fetch_viz_models + fetch_viz_models() + +The models will be downloaded in ``~/.fury/models`` directory. + +If you store the return value to ``models``, you can find the detailed information about models in the dictionary. The directory of the ``suzanne`` model will be in ``models[1]``. + +.. code-block:: python + + models = fetch_viz_models() + print(models[1]) + +To get the path of suzanne + +.. code-block:: python + + import os + path_suzanne = os.path.join(models[1], 'suzanne.obj') + print(path_suzanne) + +Now we can include the ``suzanne`` model used by Blender: + +.. code-block:: python + + suzanne = io.load_polydata(path_suzanne) + suzanne = utils.get_polymapper_from_polydata(suzanne) + suzanne = utils.get_actor_from_polymapper(suzanne) + +Set the opacity of the model:: + + suzanne.GetProperty().SetOpacity(0.5) + +Let's create some random variables for the cylinder parameters + +.. code-block:: python + + centers = np.random.rand(2, 3) + directions = np.random.rand(2, 3) + heights = np.random.rand(2) + colors = np.random.rand(2, 3) + +Now, we create a cylinder:: + + cylinders = actor.cylinder(centers, directions, colors, heights=heights) + +Anything that has to be rendered needs to be added to the scene so let's create a :py:class:`.Scene()`:: + + scene = window.Scene() + +We set the window scene variables e.g. (width, height):: + + showm = window.ShowManager(scene, size=(1024,720), reset_camera=False) + showm.initialize() + +We add a text block to add some information:: + + tb = ui.TextBlock2D(position=(450, 550), font_size=23) + tb.message = "Hello Fury" + +The function :py:meth:`.Scene.add()` is used to add the created objects to the scene to be rendered:: + + scene.add(suzanne) + scene.add(cylinders) + scene.add(tb) + +Start the rendering of the scene:: + + showm.start() + + +.. image:: _static/images/suzanne.png + :alt: suzanne fury + :align: center diff --git a/v0.10.x/_sources/index.rst.txt b/v0.10.x/_sources/index.rst.txt new file mode 100644 index 000000000..5971ef414 --- /dev/null +++ b/v0.10.x/_sources/index.rst.txt @@ -0,0 +1,42 @@ + +test + +.. toctree:: + :maxdepth: 2 + :caption: About FURY + :hidden: + + introduction + License + blog + +.. toctree:: + :maxdepth: 2 + :caption: Programming with FURY + :hidden: + + installation + getting_started + auto_examples/index + fury-pybullet + +.. toctree:: + :maxdepth: 2 + :caption: Developers Guide + :hidden: + + reference/index + symlink/contributing.rst + release-history + +.. toctree:: + :maxdepth: 1 + :caption: Join our community! + :hidden: + + Contributors + Discord Community + Mailing list + Source Code + File a bug + Feature Request diff --git a/v0.10.x/_sources/installation.rst.txt b/v0.10.x/_sources/installation.rst.txt new file mode 100644 index 000000000..d5f6b5957 --- /dev/null +++ b/v0.10.x/_sources/installation.rst.txt @@ -0,0 +1,211 @@ +============ +Installation +============ + +FURY supports Python 3.5+. You can currently still use Python 2.7 but it will soon stop being supported as the Python 2.7 end of life is on December 31st 2019. + +Dependencies +------------ + +The mandatory dependencies are: + +- numpy >= 1.7.1 +- vtk >= 8.1.0 +- scipy >= 0.9 +- aiohttp +- pygltflib + +The optional dependencies are: + +- matplotlib >= 2.0.0 +- dipy >= 0.16.0 + + +Installation with PyPi +---------------------- + +In a terminal, issue the following command + +.. code-block:: shell + + pip install fury + +Installation with Conda +----------------------- + +Our conda package is on the Conda-Forge channel. You will need to run the following command + +.. code-block:: shell + + conda install -c conda-forge fury + +Installation via Source +----------------------- + +**Step 1.** Get the latest source by cloning this repo + +.. code-block:: shell + + git clone https://github.com/fury-gl/fury.git + +**Step 2.** Install requirements + +.. code-block:: shell + + pip install -r requirements/default.txt + +**Step 3.** Install fury via + +.. code-block:: shell + + pip install . + +or + +.. code-block:: shell + + pip install -e . + +**Step 4:** Enjoy! + +Test the Installation +--------------------- + +You can check your installation via this command + +.. code-block:: shell + + python -c "from fury import get_info; print(get_info())" + +This command will give you important information about FURY's installation. The next step will be to run a :doc:`tutorial `. + +Running the Tests +----------------- + +Let's install all required packages for the running the test + +.. code-block:: shell + + pip install -r requirements/default.txt + pip install -r requirements/test.txt + +There are two ways to run FURY tests: + +- From the command line. You need to be on the FURY package folder + +.. code-block:: shell + + pytest -svv fury + +- To run a specific test file + +.. code-block:: shell + + pytest -svv fury/tests/test_actor.py + +- To run a specific test directory + +.. code-block:: shell + + pytest -svv fury/tests + +- To run a specific test function + +.. code-block:: shell + + pytest -svv -k "test_my_function_name" + +Running the Tests Offscreen +--------------------------- + +FURY is based on VTK which uses OpenGL for all its rendering. For a headless rendering, we recommend to install and use Xvfb software on linux or OSX. +Since Xvfb will require an X server (we also recommend to install XQuartz package on OSX). After Xvfb is installed you have 2 options to run FURY tests: + +- First option + +.. code-block:: shell + + export DISPLAY=:0 + Xvfb :0 -screen 1920x1080x24 > /dev/null 2>1 & + pytest -svv fury + +- Second option + +.. code-block:: shell + + export DISPLAY=:0 + xvfb-run --server-args="-screen 0 1920x1080x24" pytest -svv fury + + +Populating our Documentation +---------------------------- + +Folder Structure +~~~~~~~~~~~~~~~~ + +Let’s start by showcasing the ``docs`` folder structure: + +| fury +| ├── docs +| │ ├── build +| │ ├── make.bat +| │ ├── Makefile +| │ ├── Readme.md +| │ ├── upload_to_gh-pages.py +| │ ├── examples +| │ ├── experimental +| │ └── source +| ├── requirements.txt +| ├── fury +| │ ├── actor.py +| │ ├── ... +| │ +| │── ... +| +| + +In our ``docs`` folder structure above: + +- ``source`` is the folder that contains all ``*.rst`` files. +- ``examples`` is the directory where we have all python scripts that describe how to use the library. +- ``experimental`` directory contains experimental Python scripts. The goal is to keep a trace of experimental work. + +Building the documentation +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**Step 1.** Install all required packages for the documentation generation + +.. code-block:: shell + + pip install -U -r requirements/default.txt + pip install -U -r requirements/optional.txt + pip install -U -r requirements/docs.txt + +**Step 2.** Go to the ``docs`` folder and run the following command to generate it (Linux and macOS) + +.. code-block:: shell + + make -C . clean && make -C . html + +To generate the documentation without running the examples + +.. code-block:: shell + + make -C . clean && make -C . html-no-examples + +or under Windows + +.. code-block:: shell + + make clean + make html + +To generate the documentation without running the examples under Windows + +.. code-block:: shell + + make clean + make html-no-examples + + +**Step 3.** Congratulations! the ``build`` folder has been generated! Go to ``build/html`` and open with browser ``index.html`` to see your generated documentation. diff --git a/v0.10.x/_sources/introduction.rst.txt b/v0.10.x/_sources/introduction.rst.txt new file mode 100644 index 000000000..b617e1092 --- /dev/null +++ b/v0.10.x/_sources/introduction.rst.txt @@ -0,0 +1,64 @@ +===== +About +===== + +Overview +-------- + +Free Unified Rendering in pYthon is a Python package that provides a minimalistic but powerful API that enables advanced scientific visualization and 3D animations for scientific research. + +FURY is a community-driven, open-source, and high-performance scientific visualization library that harnesses the graphics processing unit (GPU) for improved speed, precise interactivity, and visual clarity. + +Statement of Need +----------------- + +FURY was created to address the growing necessity of high-performance 3D scientific visualization in an easy-to-use API fully compatible with the Pythonic ecosystem. To achieve this FURY takes ideas from CGI (Computer-Generated Imagery) and game engines to then be deployed for usage in everyday research practices. + +Mission Statement +----------------- + +The purpose of FURY is to make it easier to perform advanced visualizations and animations without compromising performance. We aim to build software that is: + +* clearly written +* clearly explained +* a good fit for the underlying ideas +* a natural home for collaboration + +We hope that, if we fail to do this, you will let us know and we will try and make it better. An easy way to access the FURY development team is either through our Discord live chat room or in GitHub. + +Features +-------- + +- Physically based and Cinematic Rendering. +- Ray Tracing and Signed Distance Functionality. +- Includes multiple physics and collision engines. +- Pythonic API easy to use with Numpy and Jupyter. +- Multiplatform. With wheels available for Linux, Mac and Windows. +- Super easy to install. Just write: pip install fury. +- Provides integrated user interfaces. +- Easy to create multithreaded animations. +- Contains a series of shaders including a Principled BRDF and BTDF. +- Enables LaTeX fonts in 3D. +- Supports a series of 3D file formats including (.Obj and .glTF) and 2D file formats such as PNG. + +Architecture +------------ + +.. image:: https://github.com/fury-gl/fury-communication-assets/raw/main/fury_paper/architecture.png + :width: 600 + :alt: FURY Architecture + +License +------- + +FURY is distributed under the BSD 3 License + +Credits +------- + +Go to :doc:`Community page ` to see who have been involved in the development of FURY. + +Bug reports and support +----------------------- + +Please report any issues via https://github.com/fury-gl/fury/issues. All types of issues are welcome including bug reports, documentation typos, feature requests and so on. diff --git a/v0.10.x/_sources/posts/2018/2018-09-21-release-announcement.rst.txt b/v0.10.x/_sources/posts/2018/2018-09-21-release-announcement.rst.txt new file mode 100644 index 000000000..2b99fb735 --- /dev/null +++ b/v0.10.x/_sources/posts/2018/2018-09-21-release-announcement.rst.txt @@ -0,0 +1,41 @@ +FURY 0.1.0 Released +=================== + +.. post:: September 21 2018 + :author: skoudoro + :tags: fury + :category: release + + +The FURY project is happy to announce the release of FURY 0.1.0! +FURY is a free and open source software library for scientific visualization and 3D animations. + +You can show your support by `adding a star `_ on FURY github project. + +The **major highlights** of this release are: + +.. include:: ../../release_notes/releasev0.1.0.rst + :start-after: -------------- + +.. note:: The complete release notes are :ref:`available here ` + +**To upgrade or install FURY** + +Run the following command in your terminal:: + + pip install --upgrade fury + +or:: + + conda install -c conda-forge fury + + +**Questions or suggestions?** + +For any questions go to http://fury.gl, or send an e-mail to fury@python.org +We can also join our `discord community `_ + + +On behalf of the :ref:`FURY developers `, + +Serge K. diff --git a/v0.10.x/_sources/posts/2018/2018-10-31-release-announcement.rst.txt b/v0.10.x/_sources/posts/2018/2018-10-31-release-announcement.rst.txt new file mode 100644 index 000000000..6a769ca1a --- /dev/null +++ b/v0.10.x/_sources/posts/2018/2018-10-31-release-announcement.rst.txt @@ -0,0 +1,41 @@ +FURY 0.1.3 Released +=================== + +.. post:: October 31 2018 + :author: skoudoro + :tags: fury + :category: release + + +The FURY project is happy to announce the release of FURY 0.1.3! +FURY is a free and open source software library for scientific visualization and 3D animations. + +You can show your support by `adding a star `_ on FURY github project. + +The **major highlights** of this release are: + +.. include:: ../../release_notes/releasev0.1.3.rst + :start-after: -------------- + +.. note:: The complete release notes are :ref:`available here ` + +**To upgrade or install FURY** + +Run the following command in your terminal:: + + pip install --upgrade fury + +or:: + + conda install -c conda-forge fury + + +**Questions or suggestions?** + +For any questions go to http://fury.gl, or send an e-mail to fury@python.org +We can also join our `discord community `_ + + +On behalf of the :ref:`FURY developers `, + +Serge K. diff --git a/v0.10.x/_sources/posts/2018/2018-11-26-release-announcement.rst.txt b/v0.10.x/_sources/posts/2018/2018-11-26-release-announcement.rst.txt new file mode 100644 index 000000000..e64bfed42 --- /dev/null +++ b/v0.10.x/_sources/posts/2018/2018-11-26-release-announcement.rst.txt @@ -0,0 +1,41 @@ +FURY 0.1.4 Released +=================== + +.. post:: November 26 2018 + :author: skoudoro + :tags: fury + :category: release + + +The FURY project is happy to announce the release of FURY 0.1.4! +FURY is a free and open source software library for scientific visualization and 3D animations. + +You can show your support by `adding a star `_ on FURY github project. + +The **major highlights** of this release are: + +.. include:: ../../release_notes/releasev0.1.4.rst + :start-after: -------------- + +.. note:: The complete release notes are :ref:`available here ` + +**To upgrade or install FURY** + +Run the following command in your terminal:: + + pip install --upgrade fury + +or:: + + conda install -c conda-forge fury + + +**Questions or suggestions?** + +For any questions go to http://fury.gl, or send an e-mail to fury@python.org +We can also join our `discord community `_ + + +On behalf of the :ref:`FURY developers `, + +Serge K. diff --git a/v0.10.x/_sources/posts/2019/2019-03-08-release-announcement.rst.txt b/v0.10.x/_sources/posts/2019/2019-03-08-release-announcement.rst.txt new file mode 100644 index 000000000..c3dadc84c --- /dev/null +++ b/v0.10.x/_sources/posts/2019/2019-03-08-release-announcement.rst.txt @@ -0,0 +1,48 @@ +FURY 0.2.0 Released +=================== + +.. post:: March 8 2019 + :author: skoudoro + :tags: fury + :category: release + + +The FURY project is happy to announce the release of FURY 0.2.0! +FURY is a free and open source software library for scientific visualization and 3D animations. + +You can show your support by `adding a star `_ on FURY github project. + +The **major highlights** of this release are: + +.. include:: ../../release_notes/releasev0.2.0.rst + :start-after: -------------- + :end-before: Details + +.. note:: The complete release notes are :ref:`available here ` + +**To upgrade or install FURY** + +Run the following command in your terminal:: + + pip install --upgrade fury + +or:: + + conda install -c conda-forge fury + + +**Questions or suggestions?** + +For any questions go to http://fury.gl, or send an e-mail to fury@python.org +We can also join our `discord community `_ + +We would like to thanks to :ref:`all contributors ` for this release: + +.. include:: ../../release_notes/releasev0.2.0.rst + :start-after: commits. + :end-before: We closed + + +On behalf of the :ref:`FURY developers `, + +Serge K. diff --git a/v0.10.x/_sources/posts/2019/2019-06-19-brain-art.rst.txt b/v0.10.x/_sources/posts/2019/2019-06-19-brain-art.rst.txt new file mode 100644 index 000000000..81816ca51 --- /dev/null +++ b/v0.10.x/_sources/posts/2019/2019-06-19-brain-art.rst.txt @@ -0,0 +1,17 @@ + +Success on Brain Art Competition using FURY +=========================================== + +.. post:: June 19 2019 + :author: skoudoro + :tags: shader + :category: news + + +Congratulations to `David `_ who won the `OHBM BrainArt (MELPOMENE category) `_ by using DIPY and FURY!!! + +As you can see below, really beautiful streamlines effect created during shader experiment/fail! + +.. image:: Melpomene_Brain-Streamlines-shader-experiment_by_David-Reagan.jpg + :alt: Brain Streamlines Shader Experiment + :align: center diff --git a/v0.10.x/_sources/posts/2019/2019-08-02-release-announcement.rst.txt b/v0.10.x/_sources/posts/2019/2019-08-02-release-announcement.rst.txt new file mode 100644 index 000000000..ec0c72910 --- /dev/null +++ b/v0.10.x/_sources/posts/2019/2019-08-02-release-announcement.rst.txt @@ -0,0 +1,48 @@ +FURY 0.3.0 Released +=================== + +.. post:: August 2 2019 + :author: skoudoro + :tags: fury + :category: release + + +The FURY project is happy to announce the release of FURY 0.3.0! +FURY is a free and open source software library for scientific visualization and 3D animations. + +You can show your support by `adding a star `_ on FURY github project. + +The **major highlights** of this release are: + +.. include:: ../../release_notes/releasev0.3.0.rst + :start-after: -------------- + :end-before: Details + +.. note:: The complete release notes are :ref:`available here ` + +**To upgrade or install FURY** + +Run the following command in your terminal:: + + pip install --upgrade fury + +or:: + + conda install -c conda-forge fury + + +**Questions or suggestions?** + +For any questions go to http://fury.gl, or send an e-mail to fury@python.org +We can also join our `discord community `_ + +We would like to thanks to :ref:`all contributors ` for this release: + +.. include:: ../../release_notes/releasev0.3.0.rst + :start-after: commits. + :end-before: We closed + + +On behalf of the :ref:`FURY developers `, + +Serge K. diff --git a/v0.10.x/_sources/posts/2019/2019-10-29-release-announcement.rst.txt b/v0.10.x/_sources/posts/2019/2019-10-29-release-announcement.rst.txt new file mode 100644 index 000000000..cc3544e69 --- /dev/null +++ b/v0.10.x/_sources/posts/2019/2019-10-29-release-announcement.rst.txt @@ -0,0 +1,48 @@ +FURY 0.4.0 Released +=================== + +.. post:: October 29 2019 + :author: skoudoro + :tags: fury + :category: release + + +The FURY project is happy to announce the release of FURY 0.4.0! +FURY is a free and open source software library for scientific visualization and 3D animations. + +You can show your support by `adding a star `_ on FURY github project. + +The **major highlights** of this release are: + +.. include:: ../../release_notes/releasev0.4.0.rst + :start-after: -------------- + :end-before: Details + +.. note:: The complete release notes are :ref:`available here ` + +**To upgrade or install FURY** + +Run the following command in your terminal:: + + pip install --upgrade fury + +or:: + + conda install -c conda-forge fury + + +**Questions or suggestions?** + +For any questions go to http://fury.gl, or send an e-mail to fury@python.org +We can also join our `discord community `_ + +We would like to thanks to :ref:`all contributors ` for this release: + +.. include:: ../../release_notes/releasev0.4.0.rst + :start-after: commits. + :end-before: We closed + + +On behalf of the :ref:`FURY developers `, + +Serge K. diff --git a/v0.10.x/_sources/posts/2020/2020-01-05-gsoc.rst.txt b/v0.10.x/_sources/posts/2020/2020-01-05-gsoc.rst.txt new file mode 100644 index 000000000..fd5620388 --- /dev/null +++ b/v0.10.x/_sources/posts/2020/2020-01-05-gsoc.rst.txt @@ -0,0 +1,20 @@ +Google Summer of Code +===================== + +.. post:: January 5 2020 + :author: skoudoro + :tags: google + :category: gsoc + + +FURY is participating in the `Google Summer of Code 2020 `_ under the umbrella of the `Python Software Foundation `_. + +FURY is a free and open source software library for scientific visualization and 3D animations. FURY contains many tools for visualizing a series of scientific data including graph and imaging data. + +A list of project ideas and application info is on our `GitHub Wiki `_. + +If you are interested in talking to us about projects, applications join us to our `discord community `_ or drop us a line on our `mailing list `_. + +Be part of our community and Enjoy your summer of code! + +Serge K. diff --git a/v0.10.x/_sources/posts/2020/2020-04-09-release-announcement.rst.txt b/v0.10.x/_sources/posts/2020/2020-04-09-release-announcement.rst.txt new file mode 100644 index 000000000..d75d8b044 --- /dev/null +++ b/v0.10.x/_sources/posts/2020/2020-04-09-release-announcement.rst.txt @@ -0,0 +1,48 @@ +FURY 0.5.1 Released +=================== + +.. post:: April 9 2020 + :author: skoudoro + :tags: fury + :category: release + + +The FURY project is happy to announce the release of FURY 0.5.1! +FURY is a free and open source software library for scientific visualization and 3D animations. + +You can show your support by `adding a star `_ on FURY github project. + +The **major highlights** of this release are: + +.. include:: ../../release_notes/releasev0.5.1.rst + :start-after: -------------- + :end-before: Details + +.. note:: The complete release notes are available :ref:`here ` + +**To upgrade or install FURY** + +Run the following command in your terminal:: + + pip install --upgrade fury + +or:: + + conda install -c conda-forge fury + + +**Questions or suggestions?** + +For any questions go to http://fury.gl, or send an e-mail to fury@python.org +We can also join our `discord community `_ + +We would like to thanks to :ref:`all contributors ` for this release: + +.. include:: ../../release_notes/releasev0.5.1.rst + :start-after: commits. + :end-before: We closed + + +On behalf of the :ref:`FURY developers `, + +Serge K. diff --git a/v0.10.x/_sources/posts/2020/2020-05-30-week-1-lenix.rst.txt b/v0.10.x/_sources/posts/2020/2020-05-30-week-1-lenix.rst.txt new file mode 100644 index 000000000..de2210ec1 --- /dev/null +++ b/v0.10.x/_sources/posts/2020/2020-05-30-week-1-lenix.rst.txt @@ -0,0 +1,23 @@ +Weekly Check-in #1 +================== + +.. post:: May 30 2020 + :author: Lenix Lobo + :tags: google + :category: gsoc + +Welcome to my GSoC Blog!!! +-------------------------- +Hey everyone! +This is my blog for this summer’s GSoC @ PSF +I am Lenix Lobo, an undergraduate student from India, and this summer I will be working with project Fury under the umbrella of the Python Software foundation. I will be working on improving the current shader framework. + +What did you do during the Community Bonding Period? +---------------------------------------------------- +Since most of the places including my university are closed due to the pandemic outbreak, I decided to get a head start and start with the project early. During the community bonding period, I had video conference meetings with my mentors scheduled every week on Wednesday. During these meetings i interacted with the mentors to have a coherent understanding of how the project design and implementation will be managed over the course of the entire period.  + +Since my project involves a lot of theoretical understanding of concepts such as ray marching, I spent the period going through the theory of each topic.This week also involved going through the documentation for shaders used in VTK.  + +What is coming up next week? +---------------------------- +The next task assigned to me is to go through the theory of geometry shaders and to create a example using the same.  diff --git a/v0.10.x/_sources/posts/2020/2020-05-30-week-1-soham.rst.txt b/v0.10.x/_sources/posts/2020/2020-05-30-week-1-soham.rst.txt new file mode 100644 index 000000000..13659f249 --- /dev/null +++ b/v0.10.x/_sources/posts/2020/2020-05-30-week-1-soham.rst.txt @@ -0,0 +1,23 @@ +Welcome to my GSoC Blog!!! +========================== + +.. post:: May 30 2020 + :author: Soham Biswas + :tags: google + :category: gsoc + +Hello Everyone, this is **Soham Biswas** currently in 2nd year pursuing my Bachelor’s(B.Tech) degree in Computer Science & Engineering from Institute of Engineering & Management, Kolkata. I have been selected for GSoC' 20 at sub-org **FURY** under the umbrella organization of **Python Software Foundation**. I will be working on building sci-fi-like 2D and 3D interfaces and provide physics engine integration under project titled "Create new UI widgets & Physics Engine Integration". + +What did you do during the Community Bonding Period? +---------------------------------------------------- +Due to the pandemic outbreak and the country wide lockdown in India, many places including my university were closed and therefore I decided to get a head start and start with the project early. During the community bonding period, we had video conference meetings with our mentors and the project's core team. We interacted with each other and discussed the implementation details and their respective deadlines for the entire event period. We will be having such meetings every week on Wednesday in order to update ourselves about the progress of our respective tasks. + +I completed the remaining Pull Requests that I had pending before the GSoC students announcement. I also reviewed other issues and pull requests to make sure everything remains up-to-date. + +What is coming up next week? +---------------------------- +Currently, I am focusing on building the ComboBox2D UI element. I will try to get the skeleton model, required sub-components and their respective default callbacks done by next week. + +While working with my previous PR related to *Double Click* callbacks, I faced an issue where I was unable to create and implement User Events properly in VTK. Thankfully, my mentors helped me out I was able to implement double click callbacks for all three mouse buttons successfully. + +``See you next week, cheers!!`` diff --git a/v0.10.x/_sources/posts/2020/2020-06-07-week-2-lenix.rst.txt b/v0.10.x/_sources/posts/2020/2020-06-07-week-2-lenix.rst.txt new file mode 100644 index 000000000..61e4d697e --- /dev/null +++ b/v0.10.x/_sources/posts/2020/2020-06-07-week-2-lenix.rst.txt @@ -0,0 +1,30 @@ +First week of coding!! +====================== + +.. post:: June 7 2020 + :author: Lenix Lobo + :tags: google + :category: gsoc + +Hey everyone! +This week : Geometry Shaders! + +What did you do this week? +-------------------------- +To get a better understanding of the working of the shader pipeline, the mentors assigned me a challenging task of implementing a Dynamic Texture. The basic idea is to create a 'volumetric' texture by stacking layer of textures. Such an example is an ideal use case for a geometry shader. Since i had not much prior experience with Geometry shaders before, i spent the initial days going through existing implementations of similar ideas in OpenGL/DirectX. +After working on the code, the final image rendered is given below. + +.. image:: https://raw.githubusercontent.com/lenixlobo/fury-outputs/master/blog-week-2.png + +I created a PR for the fur texture which is available `here `_ + + +What is coming up next week? +---------------------------- +The current PR has some minor bugs which need to be fixed. The next step would be to review the code and find the solutions for the bugs. Also we are looking into ideas on optimization for faster rendering time. + +The next week will be spent looking into ray marching algorithms and adding them to the current code base as possible alternatives for FURY Actor primitives. + +Did you get stuck anywhere? +--------------------------- +Nothing major. diff --git a/v0.10.x/_sources/posts/2020/2020-06-07-week-2-soham.rst.txt b/v0.10.x/_sources/posts/2020/2020-06-07-week-2-soham.rst.txt new file mode 100644 index 000000000..fa9d6b676 --- /dev/null +++ b/v0.10.x/_sources/posts/2020/2020-06-07-week-2-soham.rst.txt @@ -0,0 +1,27 @@ +First week of coding!! +====================== + +.. post:: June 7 2020 + :author: Soham Biswas + :tags: google + :category: gsoc + +Hello and welcome to my second weekly check-in, I will be sharing my progress for the first week of coding. + +What did you do this week? +-------------------------- +This week my objective was to create the skeleton model for ComboBox2D UI element along with its required sub-components and their respective default callbacks. So far, I have successfully been able to implement them. Apart from some issues that I was facing regarding the sizing and position of the sub-components. + +What is coming up next week? +---------------------------- +Next week, my main focus will be on fixing the sizing issue and I will also be working on respective default and specialized class methods required by the component and its sub-components for proper functioning. I will also create tests for the same. + +Did you get stuck anywhere? +--------------------------- +The main problem that I faced while coding the UI element was regarding the sizing and positioning of the sub-components. The sub-components appeared flipped and the TextBlock2D element had no option to resize based on a particular width & height definition. + +.. image:: https://user-images.githubusercontent.com/29832615/82089691-b713fc80-9711-11ea-8d72-efaeaac1044c.png + +As you can see, the ComboBox UI element doesn't look the way its supposed to. Along with this issue the scrollbars callback doesn't work either. Hopefully, I will be able to get these issues fixed by next week. + +``Thank you for reading, see you next week!!`` diff --git a/v0.10.x/_sources/posts/2020/2020-06-14-week-3-lenix.rst.txt b/v0.10.x/_sources/posts/2020/2020-06-14-week-3-lenix.rst.txt new file mode 100644 index 000000000..f29447fc6 --- /dev/null +++ b/v0.10.x/_sources/posts/2020/2020-06-14-week-3-lenix.rst.txt @@ -0,0 +1,29 @@ +Raymarching!! +===================== + +.. post:: June 14 2020 + :author: Lenix Lobo + :tags: google + :category: gsoc + +Make sure to check out Project `FURY `_ + +Hey ! +This week, Raymarching! + +What did you do this week? +-------------------------- +This was an exciting week as i got to learn and implement the ray marching algorithm in the FURY repo. In the weekly meeting, the mentors suggested adding support for SDF modelled actors as an alternative to the existing FURY actors. After going through a few implementations of ray marching in GLSL, i proceeded with the implementation in VTK. After being able to render a torus , the next logical step was to add support for multiple actors in the same window. The below render shows support for multiple SDF actors : + +.. image:: https://raw.githubusercontent.com/lenixlobo/fury-outputs/master/blog-week-3.gif + +The code for the above render is available at the `branch `_ + +What is coming up next week? +---------------------------- +In the above output, there is some deformation in some of the cubes, The next step is to get rid of this deformation . +Also i will be working on adding lighting within the shaders for a slightly more realistic experience. + +Did you get stuck anywhere? +--------------------------- +Going through and understanding theVTK documentation was quite a challenging task, however whenever i was confused the doubts were immediately cleared by the mentors diff --git a/v0.10.x/_sources/posts/2020/2020-06-14-week-3-soham.rst.txt b/v0.10.x/_sources/posts/2020/2020-06-14-week-3-soham.rst.txt new file mode 100644 index 000000000..af18ee966 --- /dev/null +++ b/v0.10.x/_sources/posts/2020/2020-06-14-week-3-soham.rst.txt @@ -0,0 +1,25 @@ +ComboBox2D Progress!! +===================== + +.. post:: June 14 2020 + :author: Soham Biswas + :tags: google + :category: gsoc + +Hello and welcome to my third weekly check-in, I will be sharing my progress with the project so far. In case you wondered, the sub-org that I am affiliated to is FURY. Make sure to check out the official repository `here `_. + +What did you do this week? +-------------------------- +This week my objective was to work on the sizing and positioning issue regarding the sub-components of the ComboBox2D UI element. After countless debugging sessions and my mentor's support, I was successfully able to fix the issue. I also developed helpful methods and callbacks for this element to allow users to interact with them in a user friendly manner. I also wrote tests for the same. So far the said progress can be summarized via this gif: + +.. image:: https://user-images.githubusercontent.com/29832615/84592637-cc8d5b00-ae64-11ea-9ff3-c1ce2095f7f2.gif + +What is coming up next week? +---------------------------- +Unfortunately, one of the sub-components ``TextBlock2D``, didn't have a resizing feature that I could make use of for this new UI component. Thus, I need to add that feature on a different PR. This feature will also be required while building other UI elements therefore adding this feature is currently my top priority. There's also a bug regarding the scrollbar that needs to be fixed. The scrollbar overshoots the specified combobox area after new items are appended to the combobox's list of items during runtime. Hopefully I will be able to get them done by next week. + +Did you get stuck anywhere? +--------------------------- +I was really confused with the coordinate system of Panel2D that was the main reason why components were misplaced. I also faced some issues regarding the scrollbar callback as it wasn't scrolling the elements properly, the items were stuck in place. So far I was able to fix them. Apart from these, I didn't face any major issues. + +``Thank you for reading, see you next week!!`` diff --git a/v0.10.x/_sources/posts/2020/2020-06-21-week-4-lenix.rst.txt b/v0.10.x/_sources/posts/2020/2020-06-21-week-4-lenix.rst.txt new file mode 100644 index 000000000..88d84ce9d --- /dev/null +++ b/v0.10.x/_sources/posts/2020/2020-06-21-week-4-lenix.rst.txt @@ -0,0 +1,38 @@ +Raymarching continued +====================== + +.. post:: June 21 2020 + :author: Lenix Lobo + :tags: google + :category: gsoc + +Make sure to check out Project `FURY `_ + +Hey ! +Raymarching continued + +What did you do this week? +-------------------------- +As you read in my last blog post, while the SDF primitives were working , there was slight deformation in the render. So the main focus for this week was working on solving the deformation bug. Initially the suspect was possibly the coordinate space in which the ray marching algorithm was being computed, however after testing multiple combination of transformations the issue wasn't solved. To avoid getting stuck too long on a single bug, I decided to simultaneously work on any alternatives to the current approach. So i started working on the 2nd approach. The idea was to render multiple primitives in a single cube rather than one SDF per cube. This turned out to be highly beneficial as while implementing this , i realized what was causing the deformation . + +I have added the GIFs for both the renders below. I also worked on a lambertian lighting model to create a more realistic render. + + + +Multiple Primitives within a single cube: + +.. image:: https://raw.githubusercontent.com/lenixlobo/fury-outputs/master/blog-week-4a.gif + +Solved deformation with added lambertian Lighting: + +.. image:: https://raw.githubusercontent.com/lenixlobo/fury-outputs/master/blog-week-4b.gif + +The code for the above render is available at the `branch `_ + +What is coming up next week? +---------------------------- +The next task assigned is to add support for spherical harmonics as primitives. + +Did you get stuck anywhere? +--------------------------- +I was stuck on the deformation issue for most of the week, but was eventually able to solve that. diff --git a/v0.10.x/_sources/posts/2020/2020-06-21-week-4-soham.rst.txt b/v0.10.x/_sources/posts/2020/2020-06-21-week-4-soham.rst.txt new file mode 100644 index 000000000..e6b628f19 --- /dev/null +++ b/v0.10.x/_sources/posts/2020/2020-06-21-week-4-soham.rst.txt @@ -0,0 +1,35 @@ +TextBlock2D Progress!! +====================== + +.. post:: June 21 2020 + :author: Soham Biswas + :tags: google + :category: gsoc + +Hello and welcome to my 4th weekly check-in, I will be sharing my progress with TextBlock2D UI component. The official repository of my sub-org, FURY can always be found `here `_. + +What did you do this week? +-------------------------- +This week my objective was to work on the ``TextBlock2D`` resizing feature and also work on the scrollbar bug in ``ComboBox2D`` UI component. The ``TextBlock2D`` component makes use of ``vtkTextActor`` and its methods available in VTK for handling all Text related properties such as font size, color, background color etc. Now, going through the official `docs `_ I figured out that the there were three different scaling modes for the said actor: + +- TEXT_SCALE_MODE_NONE +- TEXT_SCALE_MODE_PROP +- TEXT_SCALE_MODE_VIEWPORT + +The first scaling mode was currently implemented in FURY's ``TextBlock2D`` code base. This was done mainly because the only way for the user to create a text block was by providing the font size as parameter. We couldn't use the third option as the FURY API tries to maintain abstraction by not exposing ``vtkViewport`` parameter. Now in order to allow size as a parameter I had to use the second scaling option which is ``TEXT_SCALE_MODE_PROP``. With this mode one can set the ``Position2`` parameter to the desired value of height and width. But the problem is I cannot use this for the combobox element as the background size will be inconsistent with respect to font size and text length. + +.. image:: https://user-images.githubusercontent.com/29832615/85226809-12af6500-b3f7-11ea-8a75-7e86d40701d1.png + +.. image:: https://user-images.githubusercontent.com/29832615/85226812-14792880-b3f7-11ea-8edd-1df25382a48f.png + +Therefore, as a solution we agreed to add a separate Rectangle2D UI component as the background for Text Block along with vtkTextActor. With this implementation one can easily manipulate the background irrespective of the text properties. But this had another issue, the user now had 2 different ways of initializing a TextBlock2D. Therefore, when the user uses size a constructor parameter, then everything works in sync, but the same is not true for the font size parameter. This is mainly because we do not have a specific way of determining the size of the actor based on font size. My mentors have agreed to look into this problem and advised me to focus on something else instead. + +What is coming up next week? +---------------------------- +Next week I am planning to start with Physics engine integration of FURY with pyBullet. My main focus would be to create simple simulations first before initiating the integration process. If the size issue is solved before I move into Physics engine then I would complete the ComboBox UI and start with Tab UI instead. I have also fixed the scrollbar bug. + +Did you get stuck anywhere? +--------------------------- +The main problem that I faced so far was regarding the variable background size of the Text Block component. Also the ``GetPosition2`` method of ``vtkTextActor`` would always return the same value irrespective of the font size parameter passed as a constructor argument. Therefore, it was not possible for me to determine the actual size or bounding box of the said text actor. + +``Thank you for reading, see you next week!!`` diff --git a/v0.10.x/_sources/posts/2020/2020-06-28-week-5-lenix.rst.txt b/v0.10.x/_sources/posts/2020/2020-06-28-week-5-lenix.rst.txt new file mode 100644 index 000000000..6a9cc6816 --- /dev/null +++ b/v0.10.x/_sources/posts/2020/2020-06-28-week-5-lenix.rst.txt @@ -0,0 +1,31 @@ +Spherical harmonics +=========================== + +.. post:: June 28 2020 + :author: Lenix Lobo + :tags: google + :category: gsoc + +Make sure to check out Project `FURY `_ + +Hey ! +This week, Spherical harmonics! + +What did you do this week? +-------------------------- +The main task for the week was to include an implementation of spherical harmonics (upto the order of 4) as a FURY actor. This was the initial milestone to be achieved to work towards the support of using spherical harmonics as an visualization technique. I have added the GIFs for both the renders below. I also worked on a occlusion based lighting model. + +Spherical harmonics for different values of order and degree: + +.. image:: https://raw.githubusercontent.com/lenixlobo/fury-outputs/master/blog-week-5a.gif + +.. image:: https://raw.githubusercontent.com/lenixlobo/fury-outputs/master/blog-week-5b.gif + + +What is coming up next week? +---------------------------- +The next task to add support for the user to be able to render different spherical harmonics by passing arguments + +Did you get stuck anywhere? +--------------------------- +Spherical harmonics involve a lot of complicated math behind the hood. So the initial days were spent understanding the math .I was confused while working on the implementation but eventually got it working. diff --git a/v0.10.x/_sources/posts/2020/2020-06-28-week-5-soham.rst.txt b/v0.10.x/_sources/posts/2020/2020-06-28-week-5-soham.rst.txt new file mode 100644 index 000000000..c7b2b0991 --- /dev/null +++ b/v0.10.x/_sources/posts/2020/2020-06-28-week-5-soham.rst.txt @@ -0,0 +1,37 @@ +May the Force be with you!! +=========================== + +.. post:: June 28 2020 + :author: Soham Biswas + :tags: google + :category: gsoc + +Hello and welcome to my 5th weekly check-in, I will be sharing my progress of pyBullet Physics Engine Integration with FURY. The official repository of my sub-org, FURY can always be found `here `_. + +What did you do this week? +-------------------------- +Last week due to the ``vtkTextActor`` sizing issue I was not able to continue my work with ``ComboBox2D`` UI element. Thus, I decided to work on the "Physics Engine Integration" part of my project. It took me quite a while to understand the terminology of various methods and algorithms used for detection and physics simulation. Nevertheless, I was able to create a couple of rigid body examples to showcase the integration procedure. For physics calculations we used pyBullet and for rendering we used FURY. In other words, pyBullet will handle the backend part of the simulation and FURY will handle the frontend. I have documented the entire integration process `here `__ in detail. + +Ball Collision Simulation: +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. image:: https://user-images.githubusercontent.com/29832615/85949638-988e5b80-b975-11ea-85ba-16c1f78dec89.gif + +For the first example, I created a simple collision between two balls in which two spheres were created both in FURY and pyBullet world and then both the worlds are connected by syncing the position and orientation of the said bodies. Timer callback is created to update the positions and to simulate Physics for each step. + +Brick Wall Simulation: +^^^^^^^^^^^^^^^^^^^^^^ + +.. image:: https://raw.githubusercontent.com/Nibba2018/testing-fury/master/2020-06-26_21-15-47.gif + +For the second example I tried to increase the complexity of the simulations by increasing the number of dynamic objects. Here a brick-wall is created using 100 bricks and then a ball is thrown at it. The rest of it is simulated. The same concepts from the first example is used to render the second one. Timer callback is created to update position of all the objects and to simulate Physics for each step. + +What is coming up next week? +---------------------------- +In the above examples I used a separate actor for each object which is highly un-optimized. Thus, my mentor suggested me to render all the bricks using a single actor, so that the simulation is more optimized. I am not very confident in changing the position and orientation of different objects rendered by a single actor. Therefore, I will have to research a bit more about it. Apart from that I will also try to work on Constraint based simulation examples if possible. + +Did you get stuck anywhere? +--------------------------- +The pyBullet documentation isn't well written for cross rendering, hence it was a bit of a challenge for me to implement the integration. I also faced a problem regarding the offset of actors between the FURY world and pyBullet world. Both use different coordinate systems for rendering and simulation because of which I had a constant offset between the objects during simulations. I was able to fix it by converting one coordinate system to the other. Apart from this I did not have any major issues. + +``Thank you for reading, see you next week!!`` diff --git a/v0.10.x/_sources/posts/2020/2020-07-05-week-6-lenix.rst.txt b/v0.10.x/_sources/posts/2020/2020-07-05-week-6-lenix.rst.txt new file mode 100644 index 000000000..54b5746f7 --- /dev/null +++ b/v0.10.x/_sources/posts/2020/2020-07-05-week-6-lenix.rst.txt @@ -0,0 +1,30 @@ +Spherical harmonics, Continued. +================================== + +.. post:: July 5 2020 + :author: Lenix Lobo + :tags: google + :category: gsoc + +Make sure to check out Project `FURY `_ + +Hey ! +Spherical harmonics, Continued! + +What did you do this week? +-------------------------- +Last week I added a basic implementation of Spherical harmonics based actors. However, the implementation was quite restricted and we needed to add support for more accurate generation of spherical harmonics. So the task assigned this week was to implement the spherical harmonics function within the shader rather than passing variables as uniforms. This was quite an challenging task as it involved understanding of mathematical formulae and implementing them using existing GLSL functions. +The output of the implementation is shown below : + +.. image:: https://raw.githubusercontent.com/lenixlobo/fury-outputs/master/blog-week-6.gif + +While , i was able to complete the task the frame rate for the generated output was quite lower than expected. +The code for the above render is available at the `branch `_ + +What is coming up next week? +---------------------------- +The next task is to discuss possible performance improvements with the mentors and also look into alternative ideas to add spherical harmonics as actors in FURY. + +Did you get stuck anywhere? +--------------------------- +Spherical harmonics involve a lot of complicated math behind the hood as a result the generated output has a very poor frame rate. Currently, we are looking into improving this. diff --git a/v0.10.x/_sources/posts/2020/2020-07-05-week-6-soham.rst.txt b/v0.10.x/_sources/posts/2020/2020-07-05-week-6-soham.rst.txt new file mode 100644 index 000000000..1aa4d88b0 --- /dev/null +++ b/v0.10.x/_sources/posts/2020/2020-07-05-week-6-soham.rst.txt @@ -0,0 +1,86 @@ +Translation, Reposition, Rotation. +================================== + +.. post:: July 5 2020 + :author: Soham Biswas + :tags: google + :category: gsoc + +Hello and welcome to my 6th weekly check-in. The first evaluation period officially ends and I am very excited to move on to the second coding period. I will be sharing my progress with handling specific object's properties among various multiple objects rendered by a single actor. I am mainly focusing on making it easier to translate, rotate and reposition a particular object, so that I can use them to render physics simulations more efficiently. The official repository of my sub-org, FURY can always be found `here `_. + +What did you do this week? +-------------------------- +Last week I worked on physics simulations rendered in FURY with the help of pyBullet. Now the simulations were highly un-optimized, specially the brick wall simulation as each brick was rendered by its own actor. In other words, 1 brick = 1 actor. Now my objective was to render all the bricks using a single actor, but before jumping into the simulation I had to figure out how to modify specific properties of an individual object. Thanks to my mentor's `PR `_, I was able to experiment my implementations quickly. + +Translation: +^^^^^^^^^^^^ + +.. image:: https://user-images.githubusercontent.com/29832615/86536066-5085b080-bf02-11ea-9bcd-9e555adc2ca1.gif + +The algorithm behind translation is to first identify the vertices of the object, then bring the vertices to the origin by subtracting their centers and then adding the displacement vector. The said operation can be achieved by the following snippet: + +.. code-block:: + + # Update vertices positions + vertices[object_index * sec: object_index * sec + sec] = \ + (vertices[object_index * sec: object_index * sec + sec] - centers[object_index]) + transln_vector​ + + +Rotation: +^^^^^^^^^ + +.. image:: https://user-images.githubusercontent.com/29832615/86536065-4fed1a00-bf02-11ea-815d-f7f297165c53.gif + +The algorithm behind rotation is to first calculate the difference between the vertices and the center of the object. Once we get the resultant matrix, we matrix multiply it with the rotation matrix and then we further add the centers back to it so that we preserve the position of the object. Rotation matrix can be defined as: + +.. image:: https://wikimedia.org/api/rest_v1/media/math/render/svg/242deb7010fd504134a6cacab3d0ef4ce02e7613 + +where gamma, beta and alpha corresponds to the angle of rotation along Z-axis, Y-axis and X-axis. + +.. code-block:: python + + def get_R(gamma, beta, alpha): + """ Returns rotational matrix. + """ + r = [ + [np.cos(alpha)*np.cos(beta), np.cos(alpha)*np.sin(beta)*np.sin(gamma) - np.sin(alpha)*np.cos(gamma), + np.cos(alpha)*np.sin(beta)*np.cos(gamma) + np.sin(alpha)*np.sin(gamma)], + [np.sin(alpha)*np.cos(beta), np.sin(alpha)*np.sin(beta)*np.sin(gamma) + np.cos(alpha)*np.cos(gamma), + np.sin(alpha)*np.sin(beta)*np.cos(gamma) - np.cos(alpha)*np.sin(gamma)], + [-np.sin(beta), np.cos(beta)*np.sin(gamma), np.cos(beta)*np.cos(gamma)] + ] + r = np.array(r) + return r + + vertices[object_index * sec: object_index * sec + sec] = \ + (vertices[object_index * sec: object_index * sec + sec] - + centers[object_index])@get_R(0, np.pi/4, np.pi/4) + centers[object_index] + + +Reposition: +^^^^^^^^^^^ + +.. image:: https://user-images.githubusercontent.com/29832615/86536063-4ebbed00-bf02-11ea-8592-a695d7b91426.gif + +Repositioning is similar to that of translation, except in this case, while repositioning we update centers with the new position value. + +.. code-block:: python + + new_pos = np.array([1, 2, 3]) + + # Update vertices positions + vertices[object_index * sec: object_index * sec + sec] = \ + (vertices[object_index * sec: object_index * sec + sec] - + centers[object_index]) + new_pos + + centers[object_index] = new_pos + +What is coming up next week? +---------------------------- +Currently, I am yet to figure out the orientation problem. Once I figure that out I will be ready to implement simulations without any major issues. I am also tasked with creating a wrecking ball simulation and a quadruped robot simulation. + +Did you get stuck anywhere? +--------------------------- +I did face some problems while rotating objects. My mentors suggested me to implement it via rotation matrix. I still haven't figured out the orientation problem, which I plan to work on next. Apart from these I did not face any major issues. + +``Thank you for reading, see you next week!!`` diff --git a/v0.10.x/_sources/posts/2020/2020-07-12-week-7-soham.rst.txt b/v0.10.x/_sources/posts/2020/2020-07-12-week-7-soham.rst.txt new file mode 100644 index 000000000..8520df360 --- /dev/null +++ b/v0.10.x/_sources/posts/2020/2020-07-12-week-7-soham.rst.txt @@ -0,0 +1,27 @@ +Orientation, Sizing, Tab UI. +============================ + +.. post:: July 12 2020 + :author: Soham Biswas + :tags: google + :category: gsoc + +Hello and welcome to my 7th weekly check-in. I will be sharing my progress with single actor physics simulation and ``TextBlock2D`` sizing issue which was pending for quite a while now. I will also be sharing my thoughts regarding the ``TAB UI`` component. The official repository of my sub-org, FURY can always be found `here `_. + +What did you do this week? +-------------------------- +This week I was working with the orientation problem I mentioned in my previous check-in. I did have some problems regarding it, but thanks to my mentor I was able to figure it out and implement it with the help of scipy's Quaternion to Rotation Matrix `method `_. After understanding the orientation implementation, I spent some time regarding the design of the TAB UI component. I expect the design to be something similar as follows: + +.. image:: https://user-images.githubusercontent.com/29832615/87254337-906b0b80-c49f-11ea-93f3-3af0f2d8de10.png + +Fortunately, we have good news this week. The ``TextBlock2D`` sizing issue that we were facing for quite a while has now been fixed. We simply have to keep track of the ``scene`` parameter in the ``_add_to_scene`` method of each UI component. This scene parameter inherits ``vtkViewport``, hence it allows us to determine the necessary details about the environment of the 3D objects. + +What is coming up next week? +---------------------------- +As the sizing issue regarding ``TextBlock2D`` has been fixed, I am very much eager to finish the remaining work left. ``ComboBox2D`` and ``TextBlock2D`` were left incomplete because of the issue. Therefore, my main objective next week would be to finish them first. Once I am done with it, I will move on to ``Tab UI``. If not, I will continue with the physics simulation. + +Did you get stuck anywhere? +--------------------------- +Apart from the orientation and sizing problem, I did not face any major issues. + +``Thank you for reading, see you next week!!`` diff --git a/v0.10.x/_sources/posts/2020/2020-07-13-week-7-lenix.rst.txt b/v0.10.x/_sources/posts/2020/2020-07-13-week-7-lenix.rst.txt new file mode 100644 index 000000000..e58574cbe --- /dev/null +++ b/v0.10.x/_sources/posts/2020/2020-07-13-week-7-lenix.rst.txt @@ -0,0 +1,29 @@ +Multiple SDF primitives. +============================ + +.. post:: July 13 2020 + :author: Lenix Lobo + :tags: google + :category: gsoc + +Make sure to check out Project `FURY `_ + +Hey Everyone! +This week, multiple SDF primitives. + +What did you do this week? +-------------------------- +The objective of this week was to understand the capabilities of the multiple SDF primitives within the same cube project. To get a clearer understanding of what we can achieve with this approach, i added support for real time rotating primitives. The output of 2 cubes with rotating SDFs is shown below. + +.. image:: https://raw.githubusercontent.com/lenixlobo/fury-outputs/master/blog-week-7.gif + + +The code for the above render is available at the `branch `_ + +What is coming up next week? +---------------------------- +The task for next week is to implement features in the SDF actor and also to fix minor bugs within the shaders. Once everything is done as planned, the PR will be merged for users to access the features. + +Did you get stuck anywhere? +--------------------------- +No issues this week diff --git a/v0.10.x/_sources/posts/2020/2020-07-19-week-8-soham.rst.txt b/v0.10.x/_sources/posts/2020/2020-07-19-week-8-soham.rst.txt new file mode 100644 index 000000000..18db9a2b8 --- /dev/null +++ b/v0.10.x/_sources/posts/2020/2020-07-19-week-8-soham.rst.txt @@ -0,0 +1,39 @@ +ComboBox2D, TextBlock2D, Clipping Overflow. +=========================================== + +.. post:: July 19 2020 + :author: Soham Biswas + :tags: google + :category: gsoc + +Hello and welcome to my 8th weekly check-in. I will be sharing my progress with ``ComboBox2D`` and ``TextBlock2D`` UI components. After solving ``TextBlock2D`` sizing issue, I was finally able to complete the implementation of combo box. I also faced some problems while refactoring ``TextBlock2D``. The official repository of my sub-org, FURY can always be found `here `_. + +What did you do this week? +-------------------------- +This week I finished the implementation of ``TextBlock2D`` and ``ComboBox2D``. I also added necessary tests and tutorials to aid the implementation. It still needs some color design, which will be decided later on. Here's an overview of the tutorial: + +.. image:: https://user-images.githubusercontent.com/29832615/87884567-a8f19d80-ca2c-11ea-8fd2-e7e37b30602f.gif + +Its a simple tutorial where I change the color of the label based on the option selected on the combo box. + +Now while refactoring TextBlock2D, I noticed that the Text Overflow workaround on ListBox2D broke and started acting weird. This was mainly because the size implementation was changed and the code that I wrote a few months back wasn't relevant anymore. So I removed the previous code and had to re-implement the same. I later found out that I would be needing such an implementation for most of my UI components so I decided to create a separate method for clipping overflowing texts. + +I had to figure out a specific algorithm to achieve this as the height and width of each characters were different and the combined width of multiple characters were not equal to the sum of their widths. I decided to go for a binary search implementation as it was faster compared to a simple linear checking algorithm. The said algorithm works as expected and is more effective compared to its previous implementation. I tweaked the previous combo box example to showcase this algorithm. + +.. image:: https://user-images.githubusercontent.com/29832615/87884568-aabb6100-ca2c-11ea-9ab8-b05bdb8b0631.gif + +The extremely long text is now clipped correctly. + +What is coming up next week? +---------------------------- +Next week, I have a couple of things to work on. Firstly, the single actor wall brick simulation is yet to be completed. Once I am done with that I will continue working on Tab UI and try to finish its skeletal implementation. + +Did you get stuck anywhere? +--------------------------- +I did get stuck regarding the previous implementation of Text Overflow in ListBox2D. Before the current implementation it looked something like this: + +.. image:: https://user-images.githubusercontent.com/29832615/87430848-6b8fa900-c603-11ea-87b8-327f6e7f2ee0.png + +Apart from that, I did not face any major issues. + +``Thank you for reading, see you next week!!`` diff --git a/v0.10.x/_sources/posts/2020/2020-07-20-release-announcement.rst.txt b/v0.10.x/_sources/posts/2020/2020-07-20-release-announcement.rst.txt new file mode 100644 index 000000000..6c0b79c77 --- /dev/null +++ b/v0.10.x/_sources/posts/2020/2020-07-20-release-announcement.rst.txt @@ -0,0 +1,48 @@ +FURY 0.6.0 Released +=================== + +.. post:: July 20 2020 + :author: skoudoro + :tags: fury + :category: release + + +The FURY project is happy to announce the release of FURY 0.6.0! +FURY is a free and open source software library for scientific visualization and 3D animations. + +You can show your support by `adding a star `_ on FURY github project. + +The **major highlights** of this release are: + +.. include:: ../../release_notes/releasev0.6.0.rst + :start-after: -------------- + :end-before: Details + +.. note:: The complete release notes are available :ref:`here ` + +**To upgrade or install FURY** + +Run the following command in your terminal:: + + pip install --upgrade fury + +or:: + + conda install -c conda-forge fury + + +**Questions or suggestions?** + +For any questions go to http://fury.gl, or send an e-mail to fury@python.org +We can also join our `discord community `_ + +We would like to thanks to :ref:`all contributors ` for this release: + +.. include:: ../../release_notes/releasev0.6.0.rst + :start-after: commits. + :end-before: We closed + + +On behalf of the :ref:`FURY developers `, + +Serge K. diff --git a/v0.10.x/_sources/posts/2020/2020-07-20-week-8-lenix.rst.txt b/v0.10.x/_sources/posts/2020/2020-07-20-week-8-lenix.rst.txt new file mode 100644 index 000000000..c84d693f4 --- /dev/null +++ b/v0.10.x/_sources/posts/2020/2020-07-20-week-8-lenix.rst.txt @@ -0,0 +1,34 @@ +Improvements in SDF primitives. +=========================================== + +.. post:: July 20 2020 + :author: Lenix Lobo + :tags: google + :category: gsoc + +Make sure to check out Project `FURY `_ + +Hey Everyone! +This week, Improvements in SDF primitives. + +What did you do this week? +-------------------------- +Over the past few weeks i have been working on adding SDF based actors in FURY. The task for this week was to complete the remaining features such as support for scaling and rotation based on user direction for the actors. The main objective is to complete the SDF actor and make it ready to merge into the FURY codebase. Below are the outputs after added the improvements to the SDF primitives. + +Scaling: + +.. image:: https://raw.githubusercontent.com/lenixlobo/fury-outputs/master/blog-week-8b.gif + +Rotation based on passed directions: + +.. image:: https://raw.githubusercontent.com/lenixlobo/fury-outputs/master/blog-week-8a.gif + +The code for the above render is available at the `branch `_ + +What is coming up next week? +---------------------------- +Since the features are almost done the task for next week is clean the code and test for bugs. And then to eventually merge the sdf_actor into the fury codebase. + +Did you get stuck anywhere? +--------------------------- +No major issues this week. diff --git a/v0.10.x/_sources/posts/2020/2020-07-26-week-9-soham.rst.txt b/v0.10.x/_sources/posts/2020/2020-07-26-week-9-soham.rst.txt new file mode 100644 index 000000000..bc9563c32 --- /dev/null +++ b/v0.10.x/_sources/posts/2020/2020-07-26-week-9-soham.rst.txt @@ -0,0 +1,37 @@ +Tab UI, TabPanel2D, Tab UI Tutorial. +==================================== + +.. post:: July 26 2020 + :author: Soham Biswas + :tags: google + :category: gsoc + +Hello and welcome to my 9th weekly check-in. I will be sharing my progress with ``TabUI`` and its corresponding tutorial. The official repository of my sub-org, FURY can always be found `here `_. + +What did you do this week? +-------------------------- +This week I finished the basic implementation of ``TabUI``. Apart from that I was also able to finish the tutorial which showcases different features of this said UI. With the help of this UI one can have multiple panels containing different UI elements within them. The basic implementation can be demonstrated as follows: + +.. image:: https://user-images.githubusercontent.com/29832615/88484746-87456880-cf8e-11ea-9e96-9cba111b90d3.gif + +After finishing with the basic implementation I moved on to create its tutorial. For that, I decided to combine 3 of the existing UI tutorials to be rendered with the help of Tab UI. I implemented the following in individual tabs: + +- Controlling a cube with the help of ``LineSlider2D`` and ``RingSlider2D``. +- Using a ``CheckBox`` to render a cylinder or a sphere or both. +- Using ``ComboBox`` to set the color of a label. + +The above tutorial can be demonstrated as follows: + +.. image:: https://user-images.githubusercontent.com/29832615/88481324-6a9e3600-cf78-11ea-8c5b-e26bf158388a.gif + +What is coming up next week? +---------------------------- +Next week I will continue working on the Physics engine integration. Previously we were facing a problem regarding the uncontrollable spinning of objects rendered by a single actor. There must be an issue with mismatching axes alignment of FURY and pyBullet. The spinning problem is as following: + +.. image:: https://user-images.githubusercontent.com/29832615/88485303-87476780-cf92-11ea-850c-cc63e1376ef8.gif + +Did you get stuck anywhere? +--------------------------- +I did get stuck with the collapsing functionality of Tab UI and the uncontrollable spinning of the bricks in the Physics simulation. Apart from that I did not face any major issues. + +``Thank you for reading, see you next week!!`` diff --git a/v0.10.x/_sources/posts/2020/2020-07-27-week-9-lenix.rst.txt b/v0.10.x/_sources/posts/2020/2020-07-27-week-9-lenix.rst.txt new file mode 100644 index 000000000..b4ee28aa7 --- /dev/null +++ b/v0.10.x/_sources/posts/2020/2020-07-27-week-9-lenix.rst.txt @@ -0,0 +1,35 @@ +Merging SDF primitives. +=========================================== + +.. post:: July 27 2020 + :author: Lenix Lobo + :tags: google + :category: gsoc + +Make sure to check out Project `FURY `_ + +Hey Everyone! +This week, Merging SDF primitives. + +What did you do this week? +-------------------------- +Since GSoC started I have been working on adding support for raymarching based SDF actors as primitives in the FURY codebase. This week with the release of FURY 0.6.0 , the task assigned to me was to complete the remaining parts of the SDF actor including tests and tutorial. THe SDF actor is now part of the FURY actor and can be accessed using sdf_actor. +Currently we support , ellipsoids, spheres and torus as primitive options. As expected, SDF based actors have shown tremendous performance improvements over traditional polygon based actor. + +Despite using 100,000 torus the FPS is higher than 60 : + +.. image:: https://raw.githubusercontent.com/lenixlobo/fury-outputs/master/blog-week-9.gif + +10,000 actors : + +.. image:: https://raw.githubusercontent.com/lenixlobo/fury-outputs/master/blog-week-9b.gif + +I also made a tutorial for new users to get started `here `_ + +What is coming up next week? +---------------------------- +Now that the SDF actor is merged , the next step is to focus on spherical harmonics and i will also be working on creating shader visualization to showcase the features of FURY + +Did you get stuck anywhere? +--------------------------- +This week involved a lot of work , including making tests, tutorial and looking for bugs but everything went smoothly . diff --git a/v0.10.x/_sources/posts/2020/2020-08-02-week-10-lenix.rst.txt b/v0.10.x/_sources/posts/2020/2020-08-02-week-10-lenix.rst.txt new file mode 100644 index 000000000..afce10095 --- /dev/null +++ b/v0.10.x/_sources/posts/2020/2020-08-02-week-10-lenix.rst.txt @@ -0,0 +1,34 @@ +More Shaders!! +===================== + +.. post:: August 02 2020 + :author: Lenix Lobo + :tags: google + :category: gsoc + +Make sure to check out Project `FURY `_ + +Hey ! +This week, More Shaders! + +What did you do this week? +-------------------------- +After merging the SDF actor last week , the mentors and I decided to work on another project idea which was discussed prior to GSoC . So the next step assigned to me was to look into the current shader framework and create immersive visualizations using shaders. Being interested in volumetric rendering I looked into volumetric cloud rendering algorithms and created a basic shader-based render in FURY. + + +The output for the same is given below: + +.. image:: https://raw.githubusercontent.com/lenixlobo/fury-outputs/master/blog-week-10a.gif + + +.. image:: https://raw.githubusercontent.com/lenixlobo/fury-outputs/master/blog-week-10b.gif + +The shader demos are available `here `_ + +What is coming up next week? +---------------------------- +The main focus now is to discuss and work on shader demos which an demonstrate the capabilities of FURY + +Did you get stuck anywhere? +--------------------------- +No issues were faced this week diff --git a/v0.10.x/_sources/posts/2020/2020-08-02-week-10-soham.rst.txt b/v0.10.x/_sources/posts/2020/2020-08-02-week-10-soham.rst.txt new file mode 100644 index 000000000..7e2c22d21 --- /dev/null +++ b/v0.10.x/_sources/posts/2020/2020-08-02-week-10-soham.rst.txt @@ -0,0 +1,50 @@ +Single Actor, Physics, Scrollbars. +==================================== + +.. post:: August 02 2020 + :author: Soham Biswas + :tags: google + :category: gsoc + +Hello and welcome to my 10th weekly check-in. Second evaluation ended this week and now we move on to our 3rd and final coding period. In today's check-in I will be sharing my progress with the single actor physics simulation that I facing some issues with and I will also be discussing my future plans regarding UI components. The official repository of my sub-org, FURY can always be found `here `__. + +What did you do this week? +-------------------------- +This week I was able to figure out the uncontrollable spinning problem that I was facing while rendering physics simulations. Specifically the simulation where a brick wall was rendered by a single actor. The spinning problem was as follows: + +.. image:: https://user-images.githubusercontent.com/29832615/88485303-87476780-cf92-11ea-850c-cc63e1376ef8.gif + +Here's how the fixed simulation looks like: + +.. image:: https://user-images.githubusercontent.com/29832615/89126963-946ed400-d507-11ea-93cd-aad3a9f59ab0.gif + +I was facing this particular issue because I was directly syncing the orientation of the objects in pyBullet world to the objects in the Fury world. So I decided to apply the change in orientation instead and it worked. In order to achieve this I had to keep track of the bricks' orientation at each step of the simulation, sync the change and then update the tracked orientation. Thankfully, pybullet had convenient tools to achieve this. Here's a snippet on how to update individual objects rendered by a single actor: + +.. code-block:: python + + def sync_brick(object_index, multibody): + pos, orn = p.getBasePositionAndOrientation(multibody) + + rot_mat = np.reshape( + p.getMatrixFromQuaternion( + p.getDifferenceQuaternion(orn, brick_orns[object_index])), + (3, 3)) + + vertices[object_index * sec: object_index * sec + sec] = \ + (vertices[object_index * sec: object_index * sec + sec] - + brick_centers[object_index])@rot_mat + pos + + brick_centers[object_index] = pos + brick_orns[object_index] = orn + +All the necessary information is updated `here `_. + +What is coming up next week? +---------------------------- +Currently, the scrollbars are native to ``ListBox2D`` only. We are planning to separate scrollbars from ``ListBox2D`` to create a standalone UI component. This was in progress previously but was later discontinued, so I was given the responsibility to complete it. After this we plan to improve File Dialog capabilities later on. + +Did you get stuck anywhere? +--------------------------- +I did not face any major issues but it took me some time to understand and evaluate the existing discontinued `PR `_ regarding scrollbar separation. + +``Thank you for reading, see you next week!!`` diff --git a/v0.10.x/_sources/posts/2020/2020-08-09-week-11-lenix.rst.txt b/v0.10.x/_sources/posts/2020/2020-08-09-week-11-lenix.rst.txt new file mode 100644 index 000000000..f74b68275 --- /dev/null +++ b/v0.10.x/_sources/posts/2020/2020-08-09-week-11-lenix.rst.txt @@ -0,0 +1,37 @@ +More Shaders!! +===================== + +.. post:: August 09 2020 + :author: Lenix Lobo + :tags: google + :category: gsoc + +Make sure to check out Project `FURY `_ + +Hey ! +This week, More Shaders! + +What did you do this week? +-------------------------- +The task assigned for this week was to explore more shader techniques which could be implemented using FURY and which would demonstrate the capability of FURY shader system. So i decided to work on implementing shading examples such as Gooch shading and reflection shader using textures. + + +Below are the outputs of the techniques i worked on : + +.. image:: https://raw.githubusercontent.com/lenixlobo/fury-outputs/master/blog-week-11a.gif + + +.. image:: https://raw.githubusercontent.com/lenixlobo/fury-outputs/master/blog-week-11b.gif + + +.. image:: https://raw.githubusercontent.com/lenixlobo/fury-outputs/master/blog-week-11c.gif + +The shader demos are available `here `_ + +What is coming up next week? +---------------------------- +The next week will involve working on more such demos which can demonstrate the capabilities of FURY + +Did you get stuck anywhere? +--------------------------- +No issues were faced this week diff --git a/v0.10.x/_sources/posts/2020/2020-08-09-week-11-soham.rst.txt b/v0.10.x/_sources/posts/2020/2020-08-09-week-11-soham.rst.txt new file mode 100644 index 000000000..b202d9be8 --- /dev/null +++ b/v0.10.x/_sources/posts/2020/2020-08-09-week-11-soham.rst.txt @@ -0,0 +1,41 @@ +Chain Simulation, Scrollbar Refactor, Tutorial Update. +====================================================== + +.. post:: August 09 2020 + :author: Soham Biswas + :tags: google + :category: gsoc + +Hello and welcome to my 11th weekly check-in. In this blog I will be discussing my progress with multiple topics related to physics and ui components. I was actively working on a couple of things, specifically Joint simulations in pyBullet and scrollbar UI component. I also took up the responsibility to complete an incomplete Pull Request which was pending for quite a while. The official repository of my sub-org can be found `here `_. + +What did you do this week? +-------------------------- +The first thing that I did this week was to figure out joint simulations in pybullet. Due to lack of proper documentation I was not aware that Joints are kept stiff by default, hence I had no idea what was wrong with my simulations. Thankfully, while I was browsing pybullet forums, I found this `post `_ regarding rope simulations when I realized that I had to explicitly set the friction force to prevent stiffness among the Joints. Keeping this point in mind I was able to simulate the following Chain of hexagonal prisms: + +.. image:: https://user-images.githubusercontent.com/29832615/89737601-b7613100-da8f-11ea-947f-a96c66caefae.gif + +This week I was mainly supposed to work on refactoring scrollbars as a standalone component. I have made some progress for now. I am able to render the scrollbars properly, with proper size, orientation and color but I am having some issues regarding its scrolling callbacks. I need to look further into it. Here's a brief glimpse: + +.. image:: https://user-images.githubusercontent.com/29832615/89738159-28a2e300-da94-11ea-9167-e825f82edf98.png + +This particular `PR `_ by a fellow contributor was pending for quite a while, so I decided to look into it and complete it. The objective of the PR was to add examples for the ``CheckBox`` and ``RadioButton`` UI components, but the problem was that the objects were not rendered using FURY API in the tutorial, so I decided to complete that. It was already a well made tutorial. I only had to replace the appropriate functions with FURY's API calls. + +The ``CheckBox`` tutorial: + +.. image:: https://user-images.githubusercontent.com/29832615/89438967-20326b80-d767-11ea-8f47-e7711e900c9f.gif + +There's still some internal issues while updating the colors of the cube which is currently being worked on by my mentors. + +The ``RadioButton`` tutorial: + +.. image:: https://user-images.githubusercontent.com/29832615/89438999-2e808780-d767-11ea-8b08-2a36a05294bc.gif + +What is coming up next week? +---------------------------- +Next week I will continue working on the scrollbar component and try to fix the issues that I am having with its callbacks. I will also try to work on the wrecking ball simulation. + +Did you get stuck anywhere? +--------------------------- +Apart from the scrollbar callbacks and stiff joints, I did not face any major issues. + +``Thank you for reading, see you next week!!`` diff --git a/v0.10.x/_sources/posts/2020/2020-08-16-week-12-soham.rst.txt b/v0.10.x/_sources/posts/2020/2020-08-16-week-12-soham.rst.txt new file mode 100644 index 000000000..1cec7f843 --- /dev/null +++ b/v0.10.x/_sources/posts/2020/2020-08-16-week-12-soham.rst.txt @@ -0,0 +1,38 @@ +Wrecking Ball Simulation, Scrollbars Update, Physics Tutorials. +=============================================================== + +.. post:: August 16 2020 + :author: Soham Biswas + :tags: google + :category: gsoc + +Hello and welcome to my 12th weekly check-in. In this blog I will be discussing my progress with the wrecking ball simulation and my scrollbar separation work. Apart from this I have also finalized the physics simulation tutorials and have created a Pull Request to finally get it merged with the official repository. The official repository of my sub-org can be found `here `_. + +What did you do this week? +-------------------------- +This week I was mainly focusing on the wrecking ball simulation. This simulation is basically the combination of chain simulation and brick wall simulation. A sphere attached to a chain smashes a "NxNxN" brick wall. The simulation is as follows: + +.. image :: https://user-images.githubusercontent.com/29832615/90336291-84232280-dff8-11ea-869b-21a99b203c31.gif + +There's a rendering bug with the cylinders because of which the chain segments look weird. My mentors confirmed that this bug originated from VTK's `cylinder source` method and they are currently working on it to fix it. The simulation will render correctly once that bug is fixed. + +Regarding the scrollbar separation task, I was able to fix those callback issues that I was facing. The mouse callbacks on the scrollbar now work correctly: + +.. image :: https://user-images.githubusercontent.com/29832615/90337280-1af2dd80-dfff-11ea-94c4-508121307583.gif + +I have also created a pull request to add the following physics simulations with proper documentation to the main repository: + +- Brick Wall Simulation +- Ball Collision Simulation +- Chain Simulation +- Wrecking Ball Simulation + +What is coming up next week? +---------------------------- +Currently I am a bit confused with the implementation of scrollbars with UI components. I had a meeting with my mentor and he decided to help me out with this. So most probably I will be working with the scrollbar component and its implementation. Next week will also be the final week for GSoC 2020 before the evaluations start so I would work on getting the final documentation and formalities ready. + +Did you get stuck anywhere? +--------------------------- +Apart from the scrollbar implementation idea, I did not face any major issues. + +``Thank you for reading, see you next week!!`` diff --git a/v0.10.x/_sources/posts/2020/2020-08-17-week-12-lenix.rst.txt b/v0.10.x/_sources/posts/2020/2020-08-17-week-12-lenix.rst.txt new file mode 100644 index 000000000..7fc3c71e0 --- /dev/null +++ b/v0.10.x/_sources/posts/2020/2020-08-17-week-12-lenix.rst.txt @@ -0,0 +1,32 @@ +Outline Picker +===================== + +.. post:: August 17 2020 + :author: Lenix Lobo + :tags: google + :category: gsoc + +Make sure to check out Project `FURY `_ + +Hey ! +This week, Picking Outline! + +What did you do this week? +-------------------------- +We needed a Outline feature in FURY to indicate which model we choose in the scene. So the task assigned was to find options to achieve this. There were two ways to do this, 1. Using shader and 2. Using Vtk PolyData Silhouette. Despite trying multiple implementation methods the shader approach was not working . I also tried using VTKs inbuilt function , but there is a bug when i use some models. When i choose a model, it renders outline for every polygon , which is not what we want to achieve. The bug is shown below: + + +Below are the outputs of the techniques i worked on : + +.. image:: https://raw.githubusercontent.com/lenixlobo/fury-outputs/master/blog-week-12.gif + + +The shader demos are available `here `_ + +What is coming up next week? +---------------------------- +With the end of GSoC approaching soon, the next task is to create a PR which can help new users to test different shaders using UI to get started. + +Did you get stuck anywhere? +--------------------------- +I still was not able to figure out how we can achieve the outline effect. Am currently looking into other approaches we could use diff --git a/v0.10.x/_sources/posts/2020/2020-08-18-release-announcement.rst.txt b/v0.10.x/_sources/posts/2020/2020-08-18-release-announcement.rst.txt new file mode 100644 index 000000000..163a9d990 --- /dev/null +++ b/v0.10.x/_sources/posts/2020/2020-08-18-release-announcement.rst.txt @@ -0,0 +1,48 @@ +FURY 0.6.1 Released +=================== + +.. post:: August 18 2020 + :author: skoudoro + :tags: fury + :category: release + + +The FURY project is happy to announce the release of FURY 0.6.1! +FURY is a free and open source software library for scientific visualization and 3D animations. + +You can show your support by `adding a star `_ on FURY github project. + +This Release is mainly a maintenance release. The **major highlights** of this release are: + +.. include:: ../../release_notes/releasev0.6.1.rst + :start-after: -------------- + :end-before: Details + +.. note:: The complete release notes are available :ref:`here ` + +**To upgrade or install FURY** + +Run the following command in your terminal:: + + pip install --upgrade fury + +or:: + + conda install -c conda-forge fury + + +**Questions or suggestions?** + +For any questions go to http://fury.gl, or send an e-mail to fury@python.org +We can also join our `discord community `_ + +We would like to thanks to :ref:`all contributors ` for this release: + +.. include:: ../../release_notes/releasev0.6.1.rst + :start-after: commits. + :end-before: We closed + + +On behalf of the :ref:`FURY developers `, + +Serge K. diff --git a/v0.10.x/_sources/posts/2020/2020-08-23-week-13-soham.rst.txt b/v0.10.x/_sources/posts/2020/2020-08-23-week-13-soham.rst.txt new file mode 100644 index 000000000..17984405d --- /dev/null +++ b/v0.10.x/_sources/posts/2020/2020-08-23-week-13-soham.rst.txt @@ -0,0 +1,35 @@ +Part of the Journey is the end unless its Open Source! +====================================================== + +.. post:: August 23 2020 + :author: Soham Biswas + :tags: google + :category: gsoc + +Hello and welcome to my final weekly check-in. Today officially marks the end of the coding period for GSoC 2020. I enjoyed every bit of it. This was a life-changing experience for me and now I observe and interpret everything from a different perspective altogether. I have grown into a better developer and a person since GSoC. I would like to thank all my mentors and especially Serge for his immense support and mentorship. I would love to contribute to fury even after GSoC is over but unfortunately my semester break is over so I won't be as active as I was during the summer. + +Now, regarding work I will be sharing my progress with the File Dialog UI component. The official repository of my sub-org can be found `here `_. + +What did you do this week? +-------------------------- +This week I worked on the File Dialog UI component. Fury previously had a FileMenu component which could browse through the file system but we needed a dialog like implementation for it so that its easier for the users to read and write files during runtime. I tried implementing a simple design for it. It specifically has two modes, one for saving files and the other for writing files. The implementation can be demonstrated as follows: + +Open Dialog: +^^^^^^^^^^^^ + +.. image :: https://user-images.githubusercontent.com/29832615/90978632-df12c780-e56c-11ea-8517-6243ea06bdd2.gif + +Save Dialog: +^^^^^^^^^^^^ + +.. image :: https://user-images.githubusercontent.com/29832615/90978638-eafe8980-e56c-11ea-835a-3a82ccee2973.gif + +What is coming up next week? +---------------------------- +Next week I will start with my final GSoC documentation and code submission. I will also try to implement the tests and tutorials for File Dialog or any further changes requested by my mentors. If I am not able to finish it within the next week, I will get it done after GSoC. + +Did you get stuck anywhere? +--------------------------- +I did not face any major issues this week. + +``Thank you all for your love and support. ❤️😄`` diff --git a/v0.10.x/_sources/posts/2020/2020-08-24-final-work-lenix.rst.txt b/v0.10.x/_sources/posts/2020/2020-08-24-final-work-lenix.rst.txt new file mode 100644 index 000000000..3f47870ea --- /dev/null +++ b/v0.10.x/_sources/posts/2020/2020-08-24-final-work-lenix.rst.txt @@ -0,0 +1,132 @@ +.. image:: https://developers.google.com/open-source/gsoc/resources/downloads/GSoC-logo-horizontal.svg + :height: 50 + :align: center + +.. image:: https://www.python.org/static/community_logos/python-logo.png + :width: 40% + +.. image:: https://python-gsoc.org/logos/FURY.png + :height: 30 + + + +Google Summer of Code 2020 Final Work Product +============================================= + +.. post:: August 24 2020 + :author: Lenix Lobo + :tags: google + :category: gsoc + +- **Name:** Lenix Lobo +- **Organisation:** Python Software Foundation +- **Sub-Organisation:** FURY +- **Project:** `FURY - Improve Shader Framework `__ + +Introduction +------------ +The current shader framework for FURY is based on VTK and lacks documentation to get started which can be overwhelming for new users. The objective of this project is to enable users to be easily able to understand and use the shader framework to render stunning visual representations of data. The project involves programming vertex and fragment shaders to generate effects for more immersive visualization. + +Proposed Objectives +------------------- +**Adding SDF actor to the API** + +This actor uses raymarching to model actors using SDF. The method provides several actors including `ellipsoid`, `sphere` and `torus`. +**Shader demos** + + Use the FURY shader system to create and visualize different shading algorithms. Implementations include `SphereMap`, `Toon`, `Gooch` and `Vertex Noise` + +Unsubmitted Functionalities +--------------------------- +**Spherical Harmonics using Shaders.** + +The spherical harmonics algorithm is used to generate spherical surfaces using biases and coefficients computed. The general approach to achieve this is computationally expensive. The idea proposed was to leverage the GPU hardware using shaders to provide a faster more efficient alternative to the current implementations. The second month of the coding period was devoted to the same task but unfortunately, the observed performance was quite unsatisfactory than the expected performance. Moreover, the output shape of the geometry was distorted. It was then decided to continue the work after the GSoC period and prioritize the task at hand. + +The Work in Progress can be accessed here. https://github.com/lenixlobo/fury/tree/Spherical-Harmonics + +**Dynamic Texture using Geometry Shader** + +Geometry Shaders provide a lot of flexibility to users to create custom geometry behaviors such as instancing. The idea was to create a dynamic Fur/Hair effect on top of a FURY actor. Unfortunately due to missing documentation on VTK geometry shaders and lack of resources, the project was not completed during the GSoC period. However, I will continue to try to solve the issue. + +The source code for the current progress can be accessed here. https://github.com/lenixlobo/fury/tree/Dynamic-Texture + + +Objectives Completed +-------------------- +**SDF based Actor** + + The objective here was to provide an alternative approach to users to use SDF modeled actors in the scene. This actor is modeled using the raymarching algorithm which provides much better performance than conventional polygon-based actors. Currently, the shapes supported include ellipsoid, sphere and torus + + *Pull Requests:* + **SDF Actor method:** https://github.com/fury-gl/fury/pull/250 + +**Multiple SDF Actor** + + The objective was to create a method through which multiple SDF primitives are rendered within a single cube. This task helped us explore the limitations of the shader system and also benchmarking the performance. + + *Pull Requests:* + **MultiSDF Shader:** https://github.com/fury-gl/fury/blob/master/docs/experimental/viz_multisdf.py + +**Shader Demos** + + The task here was to create a pull request showcasing the capabilities of the FURY shader system and to also provide examples or new users to get started with integrating custom shaders into the scenes. + + *Pull Requests:* + **Shader Demos:** https://github.com/fury-gl/fury/pull/296 + + + +Other Objectives +---------------- +- **Tutorials** + + Create Tutorials for new users to get familiar with the Shader System + + *Pull Requests:* + - **Shader UI Tutorial** + + https://github.com/fury-gl/fury/pull/296 + + -**SDF Actor Tutorial** + + https://github.com/fury-gl/fury/pull/267 + +- **GSoC weekly Blogs** + + Weekly blogs were added for FURY's Website. + + *Pull Requests:* + - **First & Second Evaluation:** + + https://github.com/fury-gl/fury/pull/250 + https://github.com/fury-gl/fury/pull/267 + + - **Third Evaluation:** + + https://github.com/fury-gl/fury/pull/296 + + +Timeline +-------- + +==================== ============================================================ =========================================================================================== +Date Description Blog Link +==================== ============================================================ =========================================================================================== +Week 1(30-05-2020) Welcome to my GSoC Blog! `Weekly Check-in #1 `__ +Week 2(07-06-2020) Geometry Shaders! `Weekly Check-in #2 `__ +Week 3(14-06-2020) Ray Marching! `Weekly Check-in #3 `__ +Week 4(21-06-2020) RayMarching Continued `Weekly Check-in #4 `__ +Week 5(28-06-2020) Spherical Harmonics `Weekly Check-in #5 `__ +Week 6(05-07-2020) Spherical Harmonics Continued `Weekly Check-in #6 `__ +Week 7(12-07-2020) Multiple SDF Primitives `Weekly Check-in #7 `__ +Week 8(19-07-2020) Improvements in SDF primitives `Weekly Check-in #8 `__ +Week 9(26-07-2020) Merging SDF Actor and Benchmarks! `Weekly Check-in #9 `__ +Week 10(02-08-2020) More Shaders `Weekly Check-in #10 `__ +Week 11(08-08-2020) Even More Shaders `Weekly Check-in #11 `__ +Week 12(16-08-2020) Picking Outline `Weekly Check-in #12 `__ +Week 13(23-08-2020) Final Week `Weekly Check-in #13 `__ +==================== ============================================================ =========================================================================================== + + +Detailed weekly tasks and work done can be found +`here `__. diff --git a/v0.10.x/_sources/posts/2020/2020-08-24-final-work-soham.rst.txt b/v0.10.x/_sources/posts/2020/2020-08-24-final-work-soham.rst.txt new file mode 100644 index 000000000..d6aee15be --- /dev/null +++ b/v0.10.x/_sources/posts/2020/2020-08-24-final-work-soham.rst.txt @@ -0,0 +1,235 @@ +.. image:: https://developers.google.com/open-source/gsoc/resources/downloads/GSoC-logo-horizontal.svg + :height: 50 + :align: center + :target: https://summerofcode.withgoogle.com/projects/#6653942668197888 + +.. image:: https://www.python.org/static/community_logos/python-logo.png + :width: 40% + :target: https://blogs.python-gsoc.org/en/nibba2018s-blog/ + +.. image:: https://python-gsoc.org/logos/FURY.png + :width: 25% + :target: https://fury.gl/latest/community.html + +Google Summer of Code Final Work Product +======================================== + +.. post:: August 24 2020 + :author: Soham Biswas + :tags: google + :category: gsoc + +- **Name:** Soham Biswas +- **Organisation:** Python Software Foundation +- **Sub-Organisation:** FURY +- **Project:** `FURY - Create new UI Widgets & Physics Engine + Integration `_ + +Proposed Objectives +------------------- + +- ComboBox +- Tab UI +- File Dialog Improvements + +Modified Objectives +------------------- + +- Combobox +- Tab UI +- File Dialog Improvements +- Double Click Callback +- TextBlock2D Improvements +- Scrollbars as a Standalone Component +- Physics Engine Integration + +Objectives Completed +-------------------- + +- **ComboBox2D UI Component** + + A combobox is a commonly used graphical user interface widget. + Traditionally, it is a combination of a drop-down list or list box and a + single-line textbox, allowing the user to select a value from the list. + The term "combo box" is sometimes used to mean "drop-down list". + Respective components, tests and tutorials were created. + + *Pull Requests:* + + - **Combobox UI component:** https://github.com/fury-gl/fury/pull/240 + - **Combobox UI Tutorial:** https://github.com/fury-gl/fury/pull/246 + +- **Tab UI Component** + + In interface design, a tabbed document interface or Tab is a graphical + control element that allows multiple documents or panels to be contained + within a single window, using tabs as a navigational widget for + switching between sets of documents. Respective components, tests and + tutorials were created. + + *Pull Requests:* + + - **Tab UI component:** https://github.com/fury-gl/fury/pull/252 + - **Tab UI tutorial:** https://github.com/fury-gl/fury/pull/275 + +- **Double Click Callback** + + Double click callbacks aren't implemented in VTK by default so they need + to be implemented manually. With my mentor's help I was able to + implement double click callbacks for all the three mouse buttons + successfully. + + *Pull Requests:* + + - **Adding Double Click Callback:** + https://github.com/fury-gl/fury/pull/231 + +- **TextBlock2D Improvements** + + The previous implementation of ``TextBlock2D`` was lacking a few + features such as size arguments and text overflow. There was no specific + way to create Texts occupying a said height or width area. Apart from + that UI components like ``ListBoxItem2D``, ``FileMenu2D`` etc had an + issue where text would overflow from their specified width. In order to + tackle these problems, a modification was done to ``TextBlock2D`` to + accept size as an argument and a new method was added to clip + overflowing text based on a specified width and to replace the + overflowing characters with ``...``. + + *Pull Requests:* + + - **Setting Bounding Box for TextBlock2D:** + https://github.com/fury-gl/fury/pull/248 + - **Clip Text Overflow:** https://github.com/fury-gl/fury/pull/268 + +- **Physics Engine Integration** + + Optional support for Physics engine integration of Pybullet was added to + Fury. Pybullet's engine was used for the simulations and FURY was used + for rendering the said simulations. Exhaustive examples were added to + demonstrate various types of physics simulations possible using pybullet + and fury. The said examples are as follows: + + - Brick Wall Simulation + + - Explains how to render and simulate external forces, objects and + gravity. + + - Ball Collision Simulation + + - Explains how collisions work and how to detect said collisions. + + - Chain Simulation + + - Explains how to render and simulate joints. + + - Wrecking Ball Simulation + + - A more complicated simulation that combines concepts explained by + the other examples. + + Apart from that, a document was created to explain the integration + process between pybullet and fury in detail. + + *Pull Requests:* + + - **Physics Simulation Examples:** + https://github.com/fury-gl/fury/pull/287 + - **Fury-Pybullet Integration Docs:** + https://docs.google.com/document/d/1XJcG1TL5ZRJZDyi8V76leYZt_maxGp0kOB7OZIxKsTA/edit?usp=sharing + +Objectives in Progress +---------------------- + +- **Scrollbars as a standalone component** + + The previous implementation of scrollbars were hard coded into + ``ListBox2D``. Therefore, it was not possible to use scrollbars with any + other UI component. Apart from that, scrollbars in terms of design were + limited. Creating a horizontal scrollbar was not possible. The objective + of this PR is to make scrollbars separate so that other UI elements can + also make use of it. + + Currently, the skeletal and design aspects of the scrollbars are + implemented but the combination of scrollbars with other UI components + are still in progress. + + *Pull Requests:* + + - **Scrollbars as a Standalone API:** + https://github.com/fury-gl/fury/pull/285 + +- **File Dialog Improvements** + + Currently, we have access to ``FileMenu2D`` which allows us to navigate + through the filesystem but it does not provide a user friendly Dialog to + read and write files in Fury. Hence the idea is to create a file dialog + which can easily open or save file at runtime. As of now, ``Open`` and + ``Save`` operations are implemented. Corresponding tests and tutorials + are in progress. + + *Pull Requests:* + + - **File Dialog UI component:** + https://github.com/fury-gl/fury/pull/294 + +Other Objectives +---------------- + +- **Radio Checkbox Tutorial using FURY API** + + The objects for Radio button and Checkbox tutorial were rendered using + VTK's method by a fellow contributor so I decided to replace them with + native FURY API. The methods were rewritten keeping the previous commits + intact. + + *Pull Requests:* + + - **Radio Checkbox tutorial using FURY API:** + https://github.com/fury-gl/fury/pull/281 + +- **GSoC weekly Blogs** + + Weekly blogs were added for FURY's Website. + + *Pull Requests:* + + - **First & Second Evaluation:** + https://github.com/fury-gl/fury/pull/272 + - **Third Evaluation:** https://github.com/fury-gl/fury/pull/286 + +Timeline +-------- + ++-----------------------+------------------------------------------------------------------+----------------------------------------------------------------------------------------------------+ +| Date | Description | Blog Link | ++=======================+==================================================================+====================================================================================================+ +| Week 1(30-05-2020) | Welcome to my GSoC Blog!! | `Weekly Check-in #1 `__ | ++-----------------------+------------------------------------------------------------------+----------------------------------------------------------------------------------------------------+ +| Week 2(07-06-2020) | First Week of Coding!! | `Weekly Check-in #2 `__ | ++-----------------------+------------------------------------------------------------------+----------------------------------------------------------------------------------------------------+ +| Week 3(14-06-2020) | ComboBox2D Progress!! | `Weekly Check-in #3 `__ | ++-----------------------+------------------------------------------------------------------+----------------------------------------------------------------------------------------------------+ +| Week 4(21-06-2020) | TextBlock2D Progress!! | `Weekly Check-in #4 `__ | ++-----------------------+------------------------------------------------------------------+----------------------------------------------------------------------------------------------------+ +| Week 5(28-06-2020) | May the Force be with you!! | `Weekly Check-in #5 `__ | ++-----------------------+------------------------------------------------------------------+----------------------------------------------------------------------------------------------------+ +| Week 6(05-07-2020) | Translation, Reposition, Rotation. | `Weekly Check-in #6 `__ | ++-----------------------+------------------------------------------------------------------+----------------------------------------------------------------------------------------------------+ +| Week 7(12-07-2020) | Orientation, Sizing, Tab UI. | `Weekly Check-in #7 `__ | ++-----------------------+------------------------------------------------------------------+----------------------------------------------------------------------------------------------------+ +| Week 8(19-07-2020) | ComboBox2D, TextBlock2D, ClippingOverflow. | `Weekly Check-in #8 `__ | ++-----------------------+------------------------------------------------------------------+----------------------------------------------------------------------------------------------------+ +| Week 9(26-07-2020) | Tab UI, TabPanel2D, Tab UI Tutorial. | `Weekly Check-in #9 `__ | ++-----------------------+------------------------------------------------------------------+----------------------------------------------------------------------------------------------------+ +| Week 10(02-08-2020) | Single Actor, Physics, Scrollbars. | `Weekly Check-in #10 `__ | ++-----------------------+------------------------------------------------------------------+----------------------------------------------------------------------------------------------------+ +| Week 11(09-08-2020) | Chain Simulation, Scrollbar Refactor,Tutorial Update. | `Weekly Check-in #11 `__ | ++-----------------------+------------------------------------------------------------------+----------------------------------------------------------------------------------------------------+ +| Week 12(16-08-2020) | Wrecking Ball Simulation, ScrollbarsUpdate, Physics Tutorials. | `Weekly Check-in #12 `__ | ++-----------------------+------------------------------------------------------------------+----------------------------------------------------------------------------------------------------+ +| Week 13(23-08-2020) | Part of the Journey is the end unless itsOpen Source! | `Weekly Check-in #13 `__ | ++-----------------------+------------------------------------------------------------------+----------------------------------------------------------------------------------------------------+ + +Detailed weekly tasks and work done can be found +`here `__. diff --git a/v0.10.x/_sources/posts/2020/2020-08-24-week-13-lenix.rst.txt b/v0.10.x/_sources/posts/2020/2020-08-24-week-13-lenix.rst.txt new file mode 100644 index 000000000..6ae257a18 --- /dev/null +++ b/v0.10.x/_sources/posts/2020/2020-08-24-week-13-lenix.rst.txt @@ -0,0 +1,34 @@ +Shader Showcase +===================== + +.. post:: August 24 2020 + :author: Lenix Lobo + :tags: google + :category: gsoc + +Make sure to check out Project `FURY `_ + +Hey Everyone! +Today marked the official end of the coding period for Google Summer of Code 2020. On this day I would like to take the opportunity to thank all my mentors and Soham who have shown immense support during this time and helped me grow not only to be a better programmer but also to be a better team member. While the GSoC period ends, I will try my best to be active and contribute to the project and help it grow. +Cheers! + +What did you do this week? +-------------------------- +This being the final week of GSoC , my task was to create a PR which showcases not only the shader capabilities of the project but also to create a example which integrates both the UI and shader system of project FURY. This example can help new users to get familiar with both the UI and shaders. +Apart from this i also worked on a Toon Shader. + +The output for the above task is given below : + + +.. image:: https://raw.githubusercontent.com/lenixlobo/fury-outputs/master/blog-week-13.gif + + +The shader demos are available `here `_ + +What is coming up next week? +---------------------------- +The next week I will work on the final GSoC documentation which explains what I worked on throughout the GSoC period. In case of any changes are requested by the mentors I will also try to implement them. + +Did you get stuck anywhere? +--------------------------- +With the help of Soham and the mentors this week went smoothly. diff --git a/v0.10.x/_sources/posts/2021/2021-03-09-gsoc.rst.txt b/v0.10.x/_sources/posts/2021/2021-03-09-gsoc.rst.txt new file mode 100644 index 000000000..4e1323a4c --- /dev/null +++ b/v0.10.x/_sources/posts/2021/2021-03-09-gsoc.rst.txt @@ -0,0 +1,20 @@ +Google Summer of Code +===================== + +.. post:: March 9 2021 + :author: skoudoro + :tags: google + :category: gsoc + + +FURY is participating in the `Google Summer of Code 2021 `_ under the umbrella of the `Python Software Foundation `_. + +FURY is a free and open source software library for scientific visualization and 3D animations. FURY contains many tools for visualizing a series of scientific data including graph and imaging data. + +A list of project ideas and application info is on our `GitHub Wiki `_. + +If you are interested in talking to us about projects, applications join us to our `discord community `_ or drop us a line on our `mailing list `_. + +Be part of our community and Enjoy your summer of code! + +Serge K. diff --git a/v0.10.x/_sources/posts/2021/2021-03-13-release-announcement.rst.txt b/v0.10.x/_sources/posts/2021/2021-03-13-release-announcement.rst.txt new file mode 100644 index 000000000..acfbc5082 --- /dev/null +++ b/v0.10.x/_sources/posts/2021/2021-03-13-release-announcement.rst.txt @@ -0,0 +1,48 @@ +FURY 0.7.0 Released +=================== + +.. post:: March 13 2021 + :author: skoudoro + :tags: fury + :category: release + + +The FURY project is happy to announce the release of FURY 0.7.0! +FURY is a free and open source software library for scientific visualization and 3D animations. + +You can show your support by `adding a star `_ on FURY github project. + +This Release is mainly a maintenance release. The **major highlights** of this release are: + +.. include:: ../../release_notes/releasev0.7.0.rst + :start-after: -------------- + :end-before: Details + +.. note:: The complete release notes are available :ref:`here ` + +**To upgrade or install FURY** + +Run the following command in your terminal:: + + pip install --upgrade fury + +or:: + + conda install -c conda-forge fury + + +**Questions or suggestions?** + +For any questions go to http://fury.gl, or send an e-mail to fury@python.org +We can also join our `discord community `_ + +We would like to thanks to :ref:`all contributors ` for this release: + +.. include:: ../../release_notes/releasev0.7.0.rst + :start-after: commits. + :end-before: We closed + + +On behalf of the :ref:`FURY developers `, + +Serge K. diff --git a/v0.10.x/_sources/posts/2021/2021-06-08-gsoc-devmessias-1.rst.txt b/v0.10.x/_sources/posts/2021/2021-06-08-gsoc-devmessias-1.rst.txt new file mode 100644 index 000000000..bd3190ae5 --- /dev/null +++ b/v0.10.x/_sources/posts/2021/2021-06-08-gsoc-devmessias-1.rst.txt @@ -0,0 +1,50 @@ +Weekly Check-In #1 +================== + +.. post:: June 08 2021 + :author: Bruno Messias + :tags: google + :category: gsoc + +Hi everyone! My name is Bruno Messias currently I'm a Ph.D student at +USP/Brazil. In this summer I'll develop new tools and features for +FURY-GL. Specifically, I'll focus into developing a system for +collaborative visualization of large network layouts using FURY and VTK. + +What did I do this week? +------------------------ + +In my first meeting the mentors explained the rules and the code of +conduct inside the FURY organization. We also made some modifications in +the timeline and discussed the next steps of my project. I started +coding during the community bonding period. The next paragraph shows my +contributions in the past weeks + +- `A FURY/VTK webrtc stream system proposal:`_ to the second part of my + GSoC project I need to have a efficiently and easy to use streaming + system to send the graph visualizations across the Internet. In + addition, I also need this to my Ph.D. Therefore, I’ve been working a + lot in this PR. This PR it’s also help me to achieve the first part + of my project. Because I don’t have a computer with good specs in my + house and I need to access a external computer to test the examples + for large graphs. +- Minor improvements into the `shader markers PR`_ and `fine tuning + open-gl state PR`_. + +Did I get stuck anywhere? +------------------------- + +I’ve been stuck into a performance issue (copying the opengl framebuffer +to a python rawarray) which caused a lot of lag in the webrtc streamer. +Fortunately, I discovered that I’ve been using rawarrays in the wrong +way. My `commit`_ solved this performance issue. + +What is coming up next? +----------------------- + +In this week I'll focus on finish the #432 and #422 pull-requests. + +.. _`A FURY/VTK webrtc stream system proposal:`: https://github.com/fury-gl/fury/pull/437 +.. _shader markers PR: https://github.com/fury-gl/fury/pull/422 +.. _fine tuning open-gl state PR: https://github.com/fury-gl/fury/pull/432/ +.. _commit: https://github.com/fury-gl/fury/pull/437/commits/b1b0caf30db762cc018fc99dd4e77ba0390b2f9e%20 diff --git a/v0.10.x/_sources/posts/2021/2021-06-08-week-1-antriksh.rst.txt b/v0.10.x/_sources/posts/2021/2021-06-08-week-1-antriksh.rst.txt new file mode 100644 index 000000000..9fcaf04ca --- /dev/null +++ b/v0.10.x/_sources/posts/2021/2021-06-08-week-1-antriksh.rst.txt @@ -0,0 +1,27 @@ +Week #1: Welcome to my weekly Blogs! +==================================== + +.. post:: June 08 2021 + :author: Antriksh Misri + :tags: google + :category: gsoc + +Hi everyone! I am **Antriksh Misri**. I am a Pre-Final year student at MIT Pune. This summer, I will be working on **Layout Management** under FURY's `UI `_ module as my primary goal. This includes addition of different classes under Layout Management to provide different layouts/arrangements in which the UI elements can be arranged. As my stretch goals, I will be working on a couple of UI components for FURY’s UI module. These 2D and 3D components will be sci-fi like as seen in the movie “**Guardians of The Galaxy**”. My objective for the stretch goals would be to develop these UI components with their respective test and tutorials such that it adds on to the UI module of FURY and doesn’t hinder existing functionalities/performance. + +What did I do this week? +------------------------ +During the community bonding period I got to know the mentors as well as other participants. We had an introductory meeting, in which the rules and code of conduct was explained. Also, my proposal was reviewed and modified slightly. Initially, I had to develop UI elements as my primary goal and I had to work on layout management as my stretch goals but the tasks were switched. Now I have to work on Layout Management as my primary task and develop UI in the stretch goals period. I also started coding before hand to actually make use of this free period. I worked on different PR's which are described below:- + +* `Added tests for Layout module `_ : The layout module of FURY didn't had any tests implemented, so I made this PR to add tests for **Layout** & **GridLayout** class. +* `Complied available classes for Layout Management in different libraries `_ : In order to decide the behavior and functionality of Layout Management in FURY, I made a document that has all classes available in different libraries to manage layout of UI elements. This document also contains code snippets for these classes. +* `Resize Panel2D UI on WindowResizeEvent `_ : Currently, the **Panel2D** UI is not responsive to window resizing which means its size is static. In this branch I implemented this feature. + +Did I get stuck anywhere? +------------------------- +I got stuck at Panel resizing feature. I couldn't figure out how to propagate the window invoked events to a specific actor. Fortunately, the mentors helped me to solve this problem by using **partial** from **functools**. + +What is coming up next? +----------------------- +The next tasks will be decided in this week's open meeting with the mentors. + +**See you guys next week!** diff --git a/v0.10.x/_sources/posts/2021/2021-06-08-week-1-sajag.rst.txt b/v0.10.x/_sources/posts/2021/2021-06-08-week-1-sajag.rst.txt new file mode 100644 index 000000000..ec97ceedf --- /dev/null +++ b/v0.10.x/_sources/posts/2021/2021-06-08-week-1-sajag.rst.txt @@ -0,0 +1,41 @@ +Welcome to my GSoC Blog! +======================== + +.. post:: June 8 2021 + :author: Sajag Swami + :tags: google + :category: gsoc + +Hi all! +I'm Sajag Swami, a sophomore at Indian Institute of Technology, Roorkee. This summer, I will be working on adding a new functionality to **FURY** which shall enable users to +visualise various types of proteins via different representations like Richardson aka Ribbon diagrams and molecular surface diagrams. +As a part of my stretch goals, I’ll try to expand protein diagrams via other representations including: + +1. Stick +2. Ball and stick +3. Wire +4. Pipes and Planks +5. Sphere + +What did you do during the Community Bonding Period? +---------------------------------------------------- +I had weekly meetings with my mentors and other core team members. In the first meeting I got acquainted with the team members and learnt about the organisation and its goal/vision. +In the later meetings we discussed about various representations of proteins and how to go about implementing them in FURY. +We discussed about various libraries which can be used to parse PDB and PDBx files. +I made a `document `_ for the same to list pros and cons of using each library. +I worked upon my `previous PR `_ too during the community bonding period and fixed its docstring syntax. + +As my college ended early courtesy covid, I had extra time during which I experimented and learnt more about PDB and PDBx files - the details they contain and how to parse them. +A small backbone visualisation of 1mb0 protein made on FURY by extracting coordinate data of its alpha carbons: + +.. figure:: https://github.com/SunTzunami/gsoc2021_blog_data/blob/master/visuals/week1_backbone.png?raw=true + :align: center + +What is coming up next week? +---------------------------- +I have two major goals for the next week: + +1. Make an actor for the space filling model of the proteins and make PR for the same which will also include the unit tests and a small tutorial for the users. +2. Try to understand the documentation of vtkProteinRibbonFilter which will prove beneficial in generating Ribbon diagrams. + +``Au Revoir!`` diff --git a/v0.10.x/_sources/posts/2021/2021-06-12-gsoc-devmessias-2.rst.txt b/v0.10.x/_sources/posts/2021/2021-06-12-gsoc-devmessias-2.rst.txt new file mode 100644 index 000000000..a0e9ab661 --- /dev/null +++ b/v0.10.x/_sources/posts/2021/2021-06-12-gsoc-devmessias-2.rst.txt @@ -0,0 +1,156 @@ +A Stadia-like system for data visualization +=========================================== + +.. post:: June 13 2021 + :author: Bruno Messias + :tags: google + :category: gsoc + +Hi all! In this post I'll talk about the PR +`#437 `__. + +There are several reasons to have a streaming system for data +visualization. Because I’m doing a PhD in a developing country I always +need to think of the cheapest way to use the computational resources +available. For example, with the GPUs prices increasing, it’s necessary +to share a machine with a GPU with different users in different +locations. Therefore, to convince my Brazilian friends to use FURY I +need to code thinking inside of the (a) low-budget scenario. + +To construct the streaming system for my project I’m thinking about the +following properties and behaviors: + +#. I want to avoid blocking the code execution in the main thread (where + the vtk/fury instance resides). +#. The streaming should work inside of a low bandwidth environment. +#. I need an easy way to share the rendering result. For example, using + the free version of ngrok. + +To achieve the property **1.** we need to circumvent the GIL problem. +Using the threading module alone it’s not good enough because we can’t +use the python-threading for parallel CPU computation. In addition, to +achieve a better organization it’s better to define the server system as +an uncoupled module. Therefore, I believe that multiprocessing-lib in +python will fit very well for our proposes. + +For the streaming system to work smoothly in a low-bandwidth scenario we +need to choose the protocol wisely. In the recent years the WebRTC +protocol has been used in a myriad of applications like google hangouts +and Google Stadia aiming low latency behavior. Therefore, I choose the +webrtc as my first protocol to be available in the streaming system +proposal. + +To achieve the third property, we must be economical in adding +requirements and dependencies. + +Currently, the system has some issues, but it's already working. You can +see some tutorials about how to use this streaming system +`here `__. +After running one of these examples you can easily share the results and +interact with other users. For example, using the ngrok For example, +using the ngrok + +:: + + ./ngrok http 8000 + + +| + +How does it works? +------------------ + +The image below it's a simple representation of the streaming system. + +|image1| + +As you can see, the streaming system is made up of different processes +that share some memory blocks with each other. One of the hardest part +of this PR was to code this sharing between different objects like VTK, +numpy and the webserver. I'll discuss next some of technical issues that +I had to learn/circumvent. + +Sharing data between process +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +We want to avoid any kind of unnecessary duplication of data or +expensive copy/write actions. We can achieve this economy of +computational resources using the multiprocessing module from python. + +multiprocessing RawArray +^^^^^^^^^^^^^^^^^^^^^^^^ + +| The + `RawArray `__ + from multiprocessing allows to share resources between different + processes. However, there are some tricks to get a better performance + when we are dealing with RawArray's. For example, `take a look at my + PR in a older + stage. `__ + In this older stage my streaming system was working well. However, one + of my mentors (Filipi Nascimento) saw a huge latency for + high-resolutions examples. My first thought was that latency was + caused by the GPU-CPU copy from the opengl context. However, I + discovered that I've been using RawArray's wrong in my entire life! +| See for example this line of code + `fury/stream/client.py#L101 `__ + The code below shows how I've been updating the raw arrays + +:: + + raw_arr_buffer[:] = new_data + +This works fine for small and medium sized arrays, but for large ones it +takes a large amount of time, more than GPU-CPU copy. The explanation +for this bad performance is available here : `Demystifying sharedctypes +performance. `__ +The solution which gives a stupendous performance improvement is quite +simple. RawArrays implements the buffer protocol. Therefore, we just +need to use the memoryview: + +:: + + memview(arr_buffer)[:] = new_data + +The memview is really good, but there it's a little issue when we are +dealing with uint8 RawArrays. The following code will cause an exception: + +:: + + memview(arr_buffer_uint8)[:] = new_data_uint8 + +There is a solution for uint8 rawarrays using just memview and cast +methods. However, numpy comes to rescue and offers a simple and a +generic solution. You just need to convert the rawarray to a np +representation in the following way: + +:: + + arr_uint8_repr = np.ctypeslib.as_array(arr_buffer_uint8) + arr_uint8_repr[:] = new_data_uint8 + +You can navigate to my repository in this specific `commit +position `__ +and test the streaming examples to see how this little modification +improves the performance. + +Multiprocessing inside of different Operating Systems +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Serge Koudoro, who is one of my mentors, has pointed out an issue of the +streaming system running in MacOs. I don't know many things about MacOs, +and as pointed out by Filipi the way that MacOs deals with +multiprocessing is very different than the Linux approach. Although we +solved the issue discovered by Serge, I need to be more careful to +assume that different operating systems will behave in the same way. If +you want to know more,I recommend that you read this post `Python: +Forking vs +Spawm `__. +And it's also important to read the official documentation from python. +It can save you a lot of time. Take a look what the +official python documentation says about the multiprocessing method + +|image2| Source:\ https://docs.python.org/3/library/multiprocessing.html + +.. |image1| image:: https://user-images.githubusercontent.com/6979335/121934889-33ff1480-cd1e-11eb-89a4-562fbb953ba4.png +.. |image2| image:: https://user-images.githubusercontent.com/6979335/121958121-b0ebb780-cd39-11eb-862a-37244f7f635b.png diff --git a/v0.10.x/_sources/posts/2021/2021-06-13-week-2-antriksh.rst.txt b/v0.10.x/_sources/posts/2021/2021-06-13-week-2-antriksh.rst.txt new file mode 100644 index 000000000..ee04de3be --- /dev/null +++ b/v0.10.x/_sources/posts/2021/2021-06-13-week-2-antriksh.rst.txt @@ -0,0 +1,26 @@ +Week #2: Feature additions in UI and IO modules +=============================================== + +.. post:: June 13 2021 + :author: Antriksh Misri + :tags: google + :category: gsoc + +What did I do this week? +------------------------ +This week I had to work on 3 PRs as well as some documentation. I really enjoyed this week's work as the tasks were really interesting. The aim for these PRs were to actually add a couple of features in the UI as well as the IO module, which includes, adding support for border in Panel2D, adding support for network/URL images in load_image method in IO module, adding resizing Panel2D from bottom right corner, completing the document with layout solutions provided by Unity/Unreal engine. Below are the PRs that I worked on: + +* `Added support for URL image in load_image `_ : The load_image of IO module didn't support network /URL images, so I made this PR to add support for the same. +* `Added support for border in Panel2D `_ : This PR was made in association with the Card2D PR. This PR adds support for border in Panel2D. The borders are individually customizable just like in CSS. This PR needs a little tweaking in terms of getters/setters. The same support needs to be added in Rectangle2D. +* `Complete the document with layout solutions provided by Unity/Unreal engine `_ : Completed the document with layout solutions provided by Unity/Unreal Engine. +* Behind the scenes I also worked on a Watcher class for the UI elements. The purpose of the watcher would be to monitor the UI elements for any changes after they have been added to the scene. A PR should be up by 2-3 days. + +Did I get stuck anywhere? +------------------------- +I had a minor issue with the tests for the **IO** module. When running the tests for IO module using **pytest 5.0.0** resulted in Window fatal error, this was a sideeffect of pytest 5.0.0 wherein support for **faulthandler** was added. This error was suppressed by using certain flags while running the tests. + +What is coming up next? +----------------------- +Next week I would probably work on adapting the **GridLayout** with UI elements, some other tasks that will be decided in the next meeting. + +**See you guys next week!** diff --git a/v0.10.x/_sources/posts/2021/2021-06-14-week-2-sajag.rst.txt b/v0.10.x/_sources/posts/2021/2021-06-14-week-2-sajag.rst.txt new file mode 100644 index 000000000..a8eee25ad --- /dev/null +++ b/v0.10.x/_sources/posts/2021/2021-06-14-week-2-sajag.rst.txt @@ -0,0 +1,42 @@ +First week of coding! +===================== + +.. post:: June 14 2021 + :author: Sajag Swami + :tags: google + :category: gsoc + +Welcome to the second weekly check-in. I'll be sharing my progress for the first week of coding. + +What did you do this week? +-------------------------- +I implemented the space filling model for proteins and created a PR for the same. Preview: + +.. figure:: https://user-images.githubusercontent.com/65067354/121518963-b92cb580-ca0e-11eb-8232-3512edc04670.png + + (protein rendered: `3pgk `_) + +The PR has: + +1. Actor for space_filling_model. + +2. Two examples where I show how to visualize the proteins: + + a. In `example 1 `_, I parse a PDBx file myself and extract the atomic info essential for constructing the model which is then used by the actor to visualize it. + + b. In `example 2 `_, I parse a PDB file by using `Biopython module `_ and extract the atomic info essential for constructing the model which is then used by the actor to visualize it. + +I created a basic test for the actor which needs to be improved. I'll discuss how to improve the test with the mentors. + +What is coming up next week? +---------------------------- +I have two major goals for the next week: + +1. Make an actor for the space filling model of the proteins and make PR for the same which will also include the unit tests and a small tutorial for the users. +2. Try to understand the documentation of vtkProteinRibbonFilter which will prove beneficial in generating Ribbon diagrams. + +Did you get stuck anywhere? +--------------------------- +I tried to create a class in python which inherits from a vtk class called vtkMoleculeReaderBase but was unsuccessful in this endeavour. I'll try to find a workaround. + +``Au Revoir!`` diff --git a/v0.10.x/_sources/posts/2021/2021-06-21-gsoc-devmessias-3.rst.txt b/v0.10.x/_sources/posts/2021/2021-06-21-gsoc-devmessias-3.rst.txt new file mode 100644 index 000000000..392d8cd4e --- /dev/null +++ b/v0.10.x/_sources/posts/2021/2021-06-21-gsoc-devmessias-3.rst.txt @@ -0,0 +1,81 @@ +Weekly Check-In #3 +================== + +.. post:: June 21 2021 + :author: Bruno Messias + :tags: google + :category: gsoc + + + +What did you do this week? +-------------------------- + +- `PR fury-gl/fury#422 + (merged): `__ + Integrated the 3d impostor spheres with the marker actor. +- `PR fury-gl/fury#422 + (merged): `__ Fixed some + issues with my maker PR which now it's merged on fury. +- `PR fury-gl/fury#432 `__ + I've made some improvements in my PR which can be used to fine tune + the opengl state on VTK. +- `PR fury-gl/fury#437 `__ + I've made several improvements in my streamer proposal for FURY related to memory management. + + +- `PR fury-gl/helios#1 `__ + First version of async network layout using force-directed. + +Did I get stuck anywhere? +------------------------- + +A python-core issue +~~~~~~~~~~~~~~~~~~~ + +I've spent some hours trying to discover this issue. But now it's solved +through the commit +`devmessias/fury/commit/071dab85 `__ + +The `SharedMemory `__ +from python>=3.8 offers a new a way to share memory resources between +unrelated process. One of the advantages of using the SharedMemory +instead of the RawArray from multiprocessing is that the SharedMemory +allows to share memory blocks without those processes be related with a +fork or spawm method. The SharedMemory behavior allowed to achieve our +jupyter integration and `simplifies the use of the streaming +system `__. +However, I saw a issue in the shared memory implementation. + +Let’s see the following scenario: + +:: + + 1-Process A creates a shared memory X + 2-Process A creates a subprocess B using popen (shell=False) + 3-Process B reads X + 4-Process B closes X + 5-Process A kills B + 4-Process A closes X + 5-Process A unlink() the shared memory resource X + +The above scenario should work flawless. Calling unlink() in X is the right way as +discussed in the python official documentation. However, there is a open +issue related the unlink method + +- `Issue: + https://bugs.python.org/issue38119 `__ +- `PR + python/cpython/pull/21516 `__ + +Fortunately, I could use a +`monkey-patching `__ solution to fix +that meanwhile we wait to the python-core team to fix the +resource_tracker (38119) issue. + +What is coming up next? +----------------------- + +I'm planning to work in the +`fury-gl/fury#432 `__ and +`fury-gl/helios#1 `__. diff --git a/v0.10.x/_sources/posts/2021/2021-06-21-week-3-antriksh.rst.txt b/v0.10.x/_sources/posts/2021/2021-06-21-week-3-antriksh.rst.txt new file mode 100644 index 000000000..6f0898ecb --- /dev/null +++ b/v0.10.x/_sources/posts/2021/2021-06-21-week-3-antriksh.rst.txt @@ -0,0 +1,30 @@ +Week #3: Adapting GridLayout to work with UI +============================================ + +.. post:: June 21 2021 + :author: Antriksh Misri + :tags: google + :category: gsoc + +What did I do this week? +------------------------ +This week my tasks revolved around layout and UI elements. The primary goal for this week was to adapt the GridLayout to work with different UI elements. Currently, GridLayout just supports vtk actors and not UI elements, my task was to modify the class to support UI elements. The other tasks for this week are described below in detail: + +* `Adapt GridLayout to support UI elements `_ : This was the main task for the week and the aim for this was to actually modify GridLayout to support UI elements. This was not possible before because GridLayout only supported vtk actors (because of certain methods only being provided by vtk actors). I modified the main class itself along with some utility functions. The problem that I faced during this was circular imports. Currently, the structure of FURY doesn't allow certain modules to be imported into other modules because of circular imports. A way to get around this was to actually import the modules inside the methods but this is not ideal always. This will be fixed in the future PRs where the UI module will be redesigned. I also added support for grid position offsetting, which basically means that the position of the UI elements that are placed in the Grid can be offset by a global offset passed in the constructor of GridLayout class. Below is an example showing the current state of GridLayout with different UI elements. I also created a brief example to demonstrate how to use GridLayout of different cellshapes with UI elements link to which is `here `_. + + .. image:: https://i.imgur.com/EX2cN1i.png + :width: 200 + :height: 200 +* `Reviewed the FileDialog2D PR `_ : This PR added support for FileDialog2D in the UI module. The PR needed to be reviewed in order to merge it as soon as other required PRs were merged. One of the mentors already reviewed the PR briefly my job was to review the PR for any remaining bugs. +* `Study #422 PR to understand contours around the drawn markers `_ : In my previous week's tasks I created a PR to add support for borders in Panel2D. The borders were individually customizable just like in CSS which meant 4 Rectangle2D objects were needed to represent border in each direction. This is not ideal for a scenario where a lot of Panel2D are present in the scene as it can be performance taxing. A possible solution for this was to actually look how this was implemented in the #422. This PR allowed drawing millions of markers in one call that too from the GPU. Interestingly, each marker had a contour surrounding it which is exactly what we needed for Panel2D. This is something that can be considered in the future for border implementation in other complex UI elements. +* I also continued my work on the watcher class that I mentioned in the previous week's blog. The work for this is almost done and just needs some tests implemented, which should be done soon. + +Did I get stuck anywhere? +------------------------- +Fortunately, I did not get stuck this week. + +What is coming up next? +----------------------- +Next week I would probably continue to work on GridLayout and possibly other layouts as well, other tasks will be decided in the next meeting. + +**See you guys next week!** diff --git a/v0.10.x/_sources/posts/2021/2021-06-21-week-3-sajag.rst.txt b/v0.10.x/_sources/posts/2021/2021-06-21-week-3-sajag.rst.txt new file mode 100644 index 000000000..fb6409c77 --- /dev/null +++ b/v0.10.x/_sources/posts/2021/2021-06-21-week-3-sajag.rst.txt @@ -0,0 +1,49 @@ +Second week of coding! +====================== + +.. post:: June 21 2021 + :author: Sajag Swami + :tags: google + :category: gsoc + +Welcome to the third weekly check-in. I'll be sharing my progress for the second week of coding. + +What did you do this week? +-------------------------- +I created an example to demonstrate how one can render multiple bonds (double and triple). This required me to write an algorithm to detect bonding. +I used `this blog `_ as a reference and made a few tweaks of my own to detect the presence of double/triple bonds from interatomic distances. +The math involved in generating the coordinates of bonds was quite intriguing. Preview: + + .. figure:: https://user-images.githubusercontent.com/65067354/122672109-7d040c80-d1e7-11eb-815d-1d07fe47bbc4.png + :width: 300 + :height: 300 + + molecules rendered: Ethane, Ethene, Ethyne (from left to right) + +In addition to this, I tried understanding the codebase of vtkMolecule, vtkSimpleBondPerceiver, vtkMoleculeMapper, vtkPeriodicTable and was able to render bond-stick models and stick models using it. +This will be of great help although it's rather slow in rendering large molecules (using shaders to improve its speed will be crucial if it's to be utilised). + + + .. figure:: https://github.com/SunTzunami/gsoc2021_blog_data/blob/master/visuals/week2_wire_rep.png?raw=true + :width: 300 + :height: 300 + + Stick representation using vtkMoleculeMapper + + + + .. figure:: https://raw.githubusercontent.com/SunTzunami/gsoc2021_blog_data/master/visuals/week2_bs_rep.png + :width: 300 + :height: 300 + + Ball and Stick representation using vtkMoleculeMapper + +What is coming up next week? +---------------------------- +Try to see if the above models can be implemented using shaders. Try implementing the ribbon model using the vtkProteinRibbonFilter. The rest will be decided in the meeting with the mentors. + +Did you get stuck anywhere? +--------------------------- +Predicting bonds had been a problem since the past few weeks, it was resolved to a large extent by vtkSimpleBondPerceiver (the only limitation of vtkSimpleBondPerceiver being its inability to predict multiple bonds). + +``Au Revoir!`` diff --git a/v0.10.x/_sources/posts/2021/2021-06-28-gsoc-devmessias-4.rst.txt b/v0.10.x/_sources/posts/2021/2021-06-28-gsoc-devmessias-4.rst.txt new file mode 100644 index 000000000..94fcaa35f --- /dev/null +++ b/v0.10.x/_sources/posts/2021/2021-06-28-gsoc-devmessias-4.rst.txt @@ -0,0 +1,288 @@ +SOLID, monkey patching a python issue and network visualization through WebRTC +================================================================================ + +.. post:: July 05 2021 + :author: Bruno Messias + :tags: google + :category: gsoc + + + +These past two weeks I’ve spent most of my time in the `Streaming System +PR `__ and the `Network Layout +PR `__ . In this post I’ll +focus on the most relevant things I’ve made for those PRs. + +Streaming System +---------------- + +**Pull +request** : \ `fury-gl/fury/pull/437 `__. + +Code Refactoring +~~~~~~~~~~~~~~~~ + +Abstract class and SOLID +^^^^^^^^^^^^^^^^^^^^^^^^ + +The past weeks I've spent some time refactoring the code to see what +I’ve done let’ s take a look into this +`fury/blob/b1e985.../fury/stream/client.py#L20 `__, +the FuryStreamClient Object before the refactoring. + +The code is a mess. To see why this code is not good according to SOLID +principles let’s just list all the responsibilities of FuryStreamClient: + +- Creates a RawArray or SharedMemory to store the n-buffers +- Creates a RawArray or SharedMemory to store the information about + each buffer +- Cleanup the shared memory resources if the SharedMemory was used +- Write the vtk buffer into the shared memory resource +- Creates the vtk callbacks to update the vtk-buffer + +That’s a lot and those responsibilities are not even related to each +other. How can we be more SOLID[1]? An obvious solution is to create a +specific object to deal with the shared memory resources. But it's not +good enough because we still have a poor generalization since this new +object still needs to deal with different memory management systems: +rawarray or shared memory (maybe sockets in the future). Fortunately, we +can use the python Abstract Classes[2] to organize the code. + +To use the ABC from python I first listed all the behaviors that should +be mandatory in the new abstract class. If we are using SharedMemory or +RawArrays we need first to create the memory resource in a proper way. +Therefore, the GenericImageBufferManager must have a abstract method +create_mem_resource. Now take a look into the ImageBufferManager inside +of +`stream/server/server.py `__, +sometimes it is necessary to load the memory resource in a proper way. +Because of that, the GenericImageBufferManager needs to have a +load_mem_resource abstract method. Finally, each type of +ImageBufferManager should have a different cleanup method. The code +below presents the sketch of the abstract class + + +.. code-block:: python + + from abc import ABC, abstractmethod + + GenericImageBufferManager(ABC): + def __init__( + self, max_window_size=None, num_buffers=2, use_shared_mem=False): + ... + @abstractmethod + def load_mem_resource(self): + pass + @abstractmethod + def create_mem_resource(self): + pass + @abstractmethod + def cleanup(self): + pass + +Now we can look for those behaviors inside of FuryStreamClient.py and +ImageBufferManger.py that does not depend if we are using the +SharedMemory or RawArrays. These behaviors should be methods inside of +the new GenericImageBufferManager. + + + +.. code-block:: python + + # code at: https://github.com/devmessias/fury/blob/440a39d427822096679ba384c7d1d9a362dab061/fury/stream/tools.py#L491 + + class GenericImageBufferManager(ABC): + def __init__( + self, max_window_size=None, num_buffers=2, use_shared_mem=False) + self.max_window_size = max_window_size + self.num_buffers = num_buffers + self.info_buffer_size = num_buffers*2 + 2 + self._use_shared_mem = use_shared_mem + # omitted code + @property + def next_buffer_index(self): + index = int((self.info_buffer_repr[1]+1) % self.num_buffers) + return index + @property + def buffer_index(self): + index = int(self.info_buffer_repr[1]) + return index + def write_into(self, w, h, np_arr): + buffer_size = buffer_size = int(h*w) + next_buffer_index = self.next_buffer_index + # omitted code + + def get_current_frame(self): + if not self._use_shared_mem: + # omitted code + return self.width, self.height, self.image_buffer_repr + + def get_jpeg(self): + width, height, image = self.get_current_frame() + if self._use_shared_mem: + # omitted code + return image_encoded.tobytes() + + async def async_get_jpeg(self, ms=33): + # omitted code + @abstractmethod + def load_mem_resource(self): + pass + + @abstractmethod + def create_mem_resource(self): + pass + + @abstractmethod + def cleanup(self): + Pass + +With the +`GenericImageBufferManager `__ +the +`RawArrayImageBufferManager `__ +and +`SharedMemImageBufferManager `__ +is now implemented with less duplication of code (DRY principle). This +makes the code more readable and easier to find bugs. In addition, later +we can implement other memory management systems in the streaming system +without modifying the behavior of FuryStreamClient or the code inside of +server.py. + +I’ve also applied the same SOLID principles to improve the CircularQueue +object. Although the CircularQueue and FuryStreamInteraction were not +violating the S from SOLID, the head-tail buffer from the CircularQueue +must have a way to lock the write/read if the memory resource is busy. +Meanwhile the +`multiprocessing.Arrays `__ +already has a context which allows lock (.get_lock()) SharedMemory +doesn’t[2]. The use of abstract class allowed me to deal with those +peculiarities. `commit +358402e `__ + +Using namedtuples to grant immutability and to avoid silent bugs +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The circular queue and the user interaction are implemented in the +streaming system using numbers to identify the type of event (mouse +click, mouse weel, ...) and where to store the specific values +associated with the event , for example if the ctrl key is pressed or +not. Therefore, those numbers appear in different files and locations: +tests/test_stream.py, stream/client.py, steam/server/app_async.py. This +can be problematic because a typo can create a silent bug. One +possibility to mitigate this is to use a python dictionary to store the +constant values, for example + +.. code-block:: python + + EVENT_IDS = { + "mouse_move" : 2, "mouse_weel": 1, #... + } + +But this solution has another issue, anywhere in the code we can change +the values of EVENT_IDS and this will produce a new silent bug. To avoid +this I chose to use +`namedtuples `__ +to create an immutable object which holds all the constant values +associated with the user interactions. +`stream/constants.py `__ + +The namedtuple has several advantages when compared to dictionaries for +this specific situation. In addition, it has a better performance. A +good tutorial about namedtuples it’s available here +https://realpython.com/python-namedtuple/ + +Testing +~~~~~~~ + +My mentors asked me to write tests for this PR. Therefore, this past +week I’ve implemented the most important tests for the streaming system: +`/fury/tests/test_stream.py `__ + +Most relevant bugs +~~~~~~~~~~~~~~~~~~ + +As I discussed in my `third +week `__ +check-in there is an open issue related to SharedMemory in python. +This"bug" happens in the streaming system through the following scenario + +.. code-block:: bash + + 1-Process A creates a shared memory X + 2-Process A creates a subprocess B using popen (shell=False) + 3-Process B reads X + 4-Process B closes X + 5-Process A kills B + 4-Process A closes X + 5-Process A unlink() the shared memory resource + +In python, this scenario translates to + +.. code-block:: python + + from multiprocessing import shared_memory as sh + import time + import subprocess + import sys + + shm_a = sh.SharedMemory(create=True, size=10000) + command_string = f"from multiprocessing import shared_memory as sh;import time;shm_b = sh.SharedMemory('{shm_a.name}');shm_b.close();" + time.sleep(2) + p = subprocess.Popen( + [sys.executable, '-c', command_string], + stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=False) + p.wait() + print("\nSTDOUT") + print("=======\n") + print(p.stdout.read()) + print("\nSTDERR") + print("=======\n") + print(p.stderr.read()) + print("========\n") + time.sleep(2) + shm_a.close() + shm_a.unlink() + +Fortunately, I could use a monkey-patching[3] solution to fix that; +meanwhile we're waiting for the python-core team to fix the +resource_tracker (38119) issue [4]. + +Network Layout (Helios-FURY) +---------------------------- + +**Pull +request**\ `fury-gl/helios/pull/1 `__ + +Finally, the first version of FURY network layout is working as you can +see in the video below. + +In addition, this already can be used with the streaming system allowing +user interactions across the internet with WebRTC protocol. + +One of the issues that I had to solve to achieve the result presented in +the video above was to find a way to update the positions of the vtk +objects without blocking the main thread and at the same time allowing +the vtk events calls. My solution was to define an interval timer using +the python threading module: +`/fury/stream/tools.py#L776 `__, +`/fury/stream/client.py#L112 `__ +`/fury/stream/client.py#L296 `__ + +Refs: +----- + +- [1] A. Souly,"5 Principles to write SOLID Code (examples in Python)," + Medium, Apr. 26, 2021. + https://towardsdatascience.com/5-principles-to-write-solid-code-examples-in-python-9062272e6bdc + (accessed Jun. 28, 2021). +- [2]"[Python-ideas] Re: How to prevent shared memory from being + corrupted ?" + https://www.mail-archive.com/python-ideas@python.org/msg22935.html + (accessed Jun. 28, 2021). +- [3]“Message 388287 - Python tracker." + https://bugs.python.org/msg388287 (accessed Jun. 28, 2021). +- [4]“bpo-38119: Fix shmem resource tracking by vinay0410 · Pull + Request #21516 · python/cpython," GitHub. + https://github.com/python/cpython/pull/21516 (accessed Jun. 28, + 2021). diff --git a/v0.10.x/_sources/posts/2021/2021-06-28-week-4-antriksh.rst.txt b/v0.10.x/_sources/posts/2021/2021-06-28-week-4-antriksh.rst.txt new file mode 100644 index 000000000..0f7a2266f --- /dev/null +++ b/v0.10.x/_sources/posts/2021/2021-06-28-week-4-antriksh.rst.txt @@ -0,0 +1,38 @@ +Week #4: Adding Tree UI to the UI module +======================================== + +.. post:: June 28 2021 + :author: Antriksh Misri + :tags: google + :category: gsoc + +What did I do this week? +------------------------ +This week I had very few tasks to do, almost all of them revolved around UI elements and adding stuff to the UI module. Earlier, it was pointed out that due to some design issues, importing certain modules into others caused circular imports which led to importing the specific modules inside a class/method which is not the best approach. This will be resolved as soon as the PR that fixes this issue is reviewed/merged in the codebase. In the meantime, all the PR's related to UI will be on hold, which is why this I had few tasks this week. The tasks are described below in detail: + +* `Addition of watcher class in UI `_ :This is finally done, as described in the previous blogs this was something that was on hold for a long time. Primarily, due to other tasks I couldn't work on this but this week due to less tasks I was able to complete the watcher class and create a PR. This PR adds support for a watcher class in the UI elements. The purpose of this class is to monitor a particular attribute from the UI element after it has been added to the scene. If the attribute changes in the real time, a user defined callback is triggered and the scene is force rendered. Currently, if any attribute of the UI element changes after it is added to the scene it does not get updated accordingly. The only way to update the UI element would be to add a custom user hook that will be triggered when a particular event that can change the attribute is invoked. This is highly ambiguous as some unmonitored event can easily change many attributes of the UI element. Also it would be really hard to add user hooks for so many events. The watcher class does this automatically, it monitors the attribute for changes and if the attribute changes, a user defined callback is triggered. If this is something that is required in the UI module, then in the future a good addition would be to monitor the UI element instance as a whole instead of a single attribute . +* `Addition of Tree UI in the UI module `_ : Another task for this week was to work on either Tree UI or the Accordion UI. I chose to work on Tree UI as it is very interesting to implement and the logic for Tree is almost similar to that of an Accordion. So far, I have managed to implement TreeNode2D. The Tree UI contains several nodes and each node can have its own sub-nodes/children. Also, each node has an expand/collapse button which can be used to chow/hide the underlying children. The Tree UI would take some sort of data structure that contains nodes/sub-nodes and convert each node to TreeNode2D and add all the processed node to the main Panel. So far this the result I have achieved: + + .. image:: https://i.imgur.com/WIMWsrp.png + :width: 200 + :height: 200 + + .. image:: https://i.imgur.com/u33D7Qi.png + :width: 200 + :height: 200 +* `Resize Panel2D on window resizing `_ : This PR adds support for resizing Panel2D on WindowResizeEvent. This means that the Panle2D resizes itself with respect to the changed window size. It also retains its maximum possible size and does not overflow. Also, this PR adds support for resizing the Panel2D for the bottom right corner. A placeholder button is placed at the bottom right corner of the Panel2D and when it is dragged by the placeholder the Panel2D resize accordingly. Below is an example: + + .. image:: https://i.imgur.com/87PN7TQ.gif + :width: 200 + :height: 200 +* Also, I did some testing of GridLayout when placed inside a resizable Panel2D. This will need to be worked on before advancing any further. Currently the elements present in the Panel2D do not resize properly w.r.t the changed panel size. Hopefully, this will be fixed in the future PRs. + +Did I get stuck anywhere? +------------------------- +Fortunately, I did not get stuck this week. + +What is coming up next? +----------------------- +The tasks for the next week will be decided in this weeks meeting. + +**See you guys next week!** diff --git a/v0.10.x/_sources/posts/2021/2021-06-28-week-4-sajag.rst.txt b/v0.10.x/_sources/posts/2021/2021-06-28-week-4-sajag.rst.txt new file mode 100644 index 000000000..0246295e2 --- /dev/null +++ b/v0.10.x/_sources/posts/2021/2021-06-28-week-4-sajag.rst.txt @@ -0,0 +1,48 @@ +Third week of coding! +===================== + +.. post:: June 28 2021 + :author: Sajag Swami + :tags: google + :category: gsoc + +Welcome to the fourth weekly check-in. I'll be sharing my progress for the third week of coding. + +What did you do this week? +-------------------------- + +I made a document with code snippets and visuals to show how one can use +some vtk classes in python for molecular visualization. Classes of +interest: + +- vtkMolecule (store atomic information about the molecule). +- vtkSimpleBondPerceiver (calculate bonding info for a vtkMolecule). +- vtkMoleculeMapper (mapper to draw vtkMolecule object). +- vtkPeriodicTable (stores chemical data sourced from the Blue Obelisk + Data). + +Link to the document: `Molecular_viz_vtk`_. In addition to the +document, I read some research papers recommended by my mentors to +understand some other (and potentially better) methods of ribbon +visualization. Tried to implement vtkProteinRibbonFilter usage without +using vtkPDBReader but was unsuccessful in this endeavor. + +What is coming up next week? +---------------------------- + +Three goals for next week: + +#. Implement vtkProteinRibbonFilter usage without using vtkPDBReader. +#. Make a class for vtkMolecule which can store molecular data and pass + it on to different function for rendering purposes. +#. Read papers on surface model. + +Did you get stuck anywhere? +--------------------------- + +Implementing vtkProteinRibbonFilter usage via vtkPolyData without using +vtkPDBReader has confounded me for some time now. + +.. _Molecular_viz_vtk: https://docs.google.com/document/d/1LC2MgT9mUQK0Yo9hsI4lWqaTXHWAkSNxyBKWGAqHqe8/edit + +``Au Revoir!`` diff --git a/v0.10.x/_sources/posts/2021/2021-07-05-gsoc-devmessias-5.rst.txt b/v0.10.x/_sources/posts/2021/2021-07-05-gsoc-devmessias-5.rst.txt new file mode 100644 index 000000000..d1c4b81b6 --- /dev/null +++ b/v0.10.x/_sources/posts/2021/2021-07-05-gsoc-devmessias-5.rst.txt @@ -0,0 +1,64 @@ +Weekly Check-In #5 +=================== + +.. post:: July 05 2021 + :author: Bruno Messias + :tags: google + :category: gsoc + +What did you do this week? +-------------------------- + +`fury-gl/fury PR#437: WebRTC streaming system for FURY`_ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +- Before the `8c670c2`_ commit, for some versions of MacOs the + streaming system was falling in a silent bug. I’ve spent a lot of + time researching to found a cause for this. Fortunately, I could found + the cause and the solution. This troublesome MacOs was falling in a + silent bug because the SharedMemory Object was creating a memory + resource with at least 4086 bytes independent if I've requested less + than that. If we look into the MultiDimensionalBuffer Object + (stream/tools.py) before the 8c670c2 commit we can see that Object + has max_size parameter which needs to be updated if the SharedMemory + was created with a "wrong" size. + +`fury-gl/helios PR 1: Network Layout and SuperActors`_ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In the past week I've made a lot of improvements in this PR, from +performance improvements to visual effects. Below are the list of the +tasks related with this PR: + +- Code refactoring. +- Visual improvements: Using the UniformTools from my pull request + `#424`_ now is possible to control all the visual characteristics at + runtime. +- 2D Layout: Meanwhile 3d network representations are very usefully + for exploring a dataset is hard to convince a group of network + scientists to use a visualization system which doesn't allow 2d + representations. Because of that I started to coding the 2d behavior + in the network visualization system. +- Minimum Distortion Embeddings examples: I've created some examples + which shows how integrate pymde (Python Minimum Distortion + Embeddings) with fury/helios. The image below shows the result of + this integration: a "perfect" graph embedding + +.. image:: https://user-images.githubusercontent.com/6979335/124524052-da937e00-ddcf-11eb-83ca-9b58ca692c2e.png + +What is coming up next week? +---------------------------- + +I'll probably focus on the `heliosPR#1`_. Specifically, writing tests +and improving the minimum distortion embedding layout. + +Did you get stuck anywhere? +--------------------------- + +I did not get stuck this week. + +.. _`fury-gl/fury PR#437: WebRTC streaming system for FURY`: https://github.com/fury-gl/fury/pull/427 +.. _8c670c2: https://github.com/fury-gl/fury/pull/437/commits/8c670c284368029cdb5b54c178a792ec615e4d4d +.. _`fury-gl/helios PR 1: Network Layout and SuperActors`: https://github.com/fury-gl/helios/pull/1 +.. _#424: https://github.com/fury-gl/fury/pull/424 +.. _heliosPR#1: diff --git a/v0.10.x/_sources/posts/2021/2021-07-05-week-5-antriksh.rst.txt b/v0.10.x/_sources/posts/2021/2021-07-05-week-5-antriksh.rst.txt new file mode 100644 index 000000000..671de1b74 --- /dev/null +++ b/v0.10.x/_sources/posts/2021/2021-07-05-week-5-antriksh.rst.txt @@ -0,0 +1,30 @@ +Week #5: Rebasing all PRs w.r.t the UI restructuring, Tree2D, Bug Fixes +======================================================================== + +.. post:: July 05 2021 + :author: Antriksh Misri + :tags: google + :category: gsoc + +What did I do this week? +------------------------ +The UI restructuring was finally merged this week. This means UI is now a submodule in itself and provides different UI elements based on their types which are, core, elements, containers and some helper methods/classes. So, this week my main tasks were to rebase and fix merge conflicts of my open PR's. Other than that, I had to continue my work on Tree2D UI element and finish the remaining aspects of it. Also, I had to create an example demonstrating how to use the newly added UI element. Many use cases were discussed in the open meeting like, an image gallery which displays preview image on the title and when expanded reveals the full scale image. I am thinking of adding multiple examples for the Tree2D to brainstorm on its certain features. Also, I had this annoying bug in Panel2D which didn't allow it to be resized from the bottom right corner. It was resizing from the top right corner. I had to address this bug as well. Below are the tasks in detail: + +* `Rebasing all PRs w.r.t the UI restructuring `_: As discussed in the earlier blogs, due to circular imports and large size of the UI module, a bit of restructuring was required. This week the PR that converts the UI into a sub module was finally merged. This meant I had to fix all the merge conflicts and rebase all UI related PR's. So, I rebased all the UI related PR's and fixed the merge conflicts. Currently, there are still some PR's that need some attention as still some of the imports are circular in nature. This means if the issue is correct then some more restructuring is required, which will be hopefully done in the near future. +* `Continuing the work on Tree2D `_ : This week I continued my work on Tree2D, TreeNode2D. I had to fix/add multiple features on both the classes but my priority was to fix the looks of the UI element as well as make it easier for the user to manipulate the UI element. The first thing that I fixed was node offsetting, when a node is collapsed and expanded the nodes below the current node should also offset. Previously, only the child nodes within the same parents were offset and not the nodes/parent beyond that. With some minor adjusting, now the nodes are offset recursively and all child/parent nodes below the current nodes are offset. Secondly, before only a node could be added to a node which meant it wasn't any easy way to add any other UI element to a node but with some updates/fixes any UI element can be added to a node. Also, the Tree2D lacked some properties/methods to easily manipulate it. So, i added some properties/methods that allow to easily/efficiently manipulate individual node inside the Tree2D. Below is the current state of the Tree2D. In the below tree, two panels are added to a child node after the tree has been initialized. Also, the coordinated of the child elements are totally fluid i.e they can be placed anywhere inside the content panel by passing normalized or absolute coordinates. + + .. image:: https://i.imgur.com/rQQvLqs.png + :width: 200 + :height: 200 + +* Fixed Panel2D bottom corner resizing: Previously, the panel would not resize from the bottom left corner but it would resize from top right corner. I didn't understand what was going wrong and was stuck on this for a long time. But I finally figured out the problem, I was calculating the Y-offset wrong as well as the panel resized from the top side instead of bottom. With some minor tweaking the bug was gone and the panel resizes correctly from the bottom right corner. + +Did I get stuck anywhere? +------------------------- +I got stuck on recording events for the updated panel UI element. The panel updates w.r.t the window size but I couldn't figure out how to record the events invoked by the window. Unfortunately, I still haven't figured out how this will be done. My guess is that I have to propagate the event first to the interactor and then to the UI element. + +What is coming up next? +----------------------- +I will probably finish up the GridLayout, Tree2D UI along side some other UI's. This will be decided in the next meeting. + +**See you guys next week!** diff --git a/v0.10.x/_sources/posts/2021/2021-07-05-week-5-sajag.rst.txt b/v0.10.x/_sources/posts/2021/2021-07-05-week-5-sajag.rst.txt new file mode 100644 index 000000000..e5977581b --- /dev/null +++ b/v0.10.x/_sources/posts/2021/2021-07-05-week-5-sajag.rst.txt @@ -0,0 +1,35 @@ +Fourth week of coding! +====================== + +.. post:: July 5 2021 + :author: Sajag Swami + :tags: google + :category: gsoc + +Welcome to the fifth weekly check-in. I'll be sharing my progress for the fourth week of coding. + +What did you do this week? +-------------------------- + +Created a `PR`_ for the molecular module. Enables the ability to create +three types of molecular representations: + +#. Space-filling model aka calotte model and CPK model. +#. Stick model. +#. Ball and Stick model. + +What is coming up next week? +---------------------------- + +Mentors suggested changes to be made to the molecular module which I +shall make. Other goals to be decided post mid-week meeting. + +Did you get stuck anywhere? +--------------------------- + +Sending protein data to ProteinRibbonFilter via a vtkPolyData has been +unsuccessful so far. + +.. _PR: https://github.com/fury-gl/fury/pull/452 + +``Au Revoir!`` diff --git a/v0.10.x/_sources/posts/2021/2021-07-12-gsoc-devmessias-6.rst.txt b/v0.10.x/_sources/posts/2021/2021-07-12-gsoc-devmessias-6.rst.txt new file mode 100644 index 000000000..133597229 --- /dev/null +++ b/v0.10.x/_sources/posts/2021/2021-07-12-gsoc-devmessias-6.rst.txt @@ -0,0 +1,165 @@ +Network layout algorithms using IPC +=================================== + +.. post:: July 12 2021 + :author: Bruno Messias + :tags: google + :category: gsoc + +Hi all. In the past weeks, I’ve been focusing on developing Helios; the +network visualization library for FURY. I improved the visual aspects of +the network rendering as well as implemented the most relevant network +layout methods. + +In this post I will discuss the most challenging task that I faced to +implement those new network layout methods and how I solved it. + +The problem: network layout algorithm implementations with a blocking behavior +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**Case 1:** Suppose that you need to monitor a hashtag and build a +social graph. You want to interact with the graph and at the same time +get insights about the structure of the user interactions. To get those +insights you can perform a node embedding using any kind of network +layout algorithm, such as force-directed or minimum distortion +embeddings. + +**Case 2:** Suppose that you are modelling a network dynamic such as an +epidemic spreading or a Kuramoto model. In some of those network +dynamics a node can change the state and the edges related to the node +must be deleted. For example, in an epidemic model a node can represent +a person who died due to a disease. Consequently, the layout of the +network must be recomputed to give better insights. + +In described cases if we want a better (UX) and at the same time a more +practical and insightful application of Helios layouts algorithms +shouldn’t block any kind of computation in the main thread. + +In Helios we already have a lib written in C (with a python wrapper) +which performs the force-directed layout algorithm using separated +threads avoiding the GIL problem and consequently avoiding the blocking. +But and the other open-source network layout libs available on the +internet? Unfortunately, most of those libs have not been implemented +like Helios force-directed methods and consequently, if we want to +update the network layout the python interpreter will block the +computation and user interaction in your network visualization. How to +solve this problem? + +Why is using the python threading is not a good solution? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +One solution to remove the blocking behavior of the network layout libs +like PyMDE is to use the threading module from python. However, remember +the GIL problem: only one thread can execute python code at once. +Therefore, this solution will be unfeasible for networks with more than +some hundreds of nodes or even less! Ok, then how to solve it well? + +IPC using python +~~~~~~~~~~~~~~~~ + +As I said in my previous posts I’ve created a streaming system for data +visualization for FURY using webrtc. The streaming system is already +working and an important piece in this system was implemented using the +python SharedMemory from multiprocessing. We can get the same ideas from +the streaming system to remove the blocking behavior of the network +layout libs. + +My solution to have PyMDE and CuGraph-ForceAtlas without blocking was to +break the network layout method into two different types of processes: A +and B. The list below describes the most important behaviors and +responsibilities for each process + +**Process A:** + +- Where the visualization (NetworkDraw) will happen +- Create the shared memory resources: edges, weights, positions, info.. +- Check if the process B has updated the shared memory resource which + stores the positions using the timestamp stored in the info_buffer +- Update the positions inside of NetworkDraw instance + +**Process B:** + +- Read the network information stored in the shared memory resources: + edges , weights, positions +- Execute the network layout algorithm +- Update the positions values inside of the shared memory resource +- Update the timestamp inside of the shared memory resource + +I used the timestamp information to avoid unnecessary updates in the +FURY/VTK window instance, which can consume a lot of computational +resources. + +How have I implemented the code for A and B? +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Because we need to deal with a lot of different data and share them +between different processes I’ve created a set of tools to deal with +that, take a look for example in the `ShmManagerMultiArrays +Object `__ +, which makes the memory management less painful. + +I'm breaking the layout method into two different processes. Thus I’ve +created two abstract objects to deal with any kind of network layout +algorithm which must be performed using inter-process-communication +(IPC). Those objects are: +`NetworkLayoutIPCServerCalc `__ +; used by processes of type B and +`NetworkLayoutIPCRender `__ +; which should be used by processes of type A. + +I’ll not bore you with the details of the implementation. But let’s take +a look into some important points. As I’ve said saving the timestamp +after each step of the network layout algorithm. Take a look into the +method \_check_and_sync from NetworkLayoutIPCRender +`here `__. +Notice that the update happens only if the stored timestamp has been +changed. Also, look at this line +`helios/layouts/mde.py#L180 `__, +the IPC-PyMDE implementation This line writes a value 1 into the second +element of the info_buffer. This value is used to inform the process A +that everything worked well. I used that info for example in the tests +for the network layout method, see the link +`helios/tests/test_mde_layouts.py#L43 `__ + +Results +~~~~~~~ + +Until now Helios has three network layout methods implemented: Force +Directed , Minimum Distortion Embeddings and Force Atlas 2. Here +`docs/examples/viz_helios_mde.ipynb `__ +you can get a jupyter notebook that I’ve a created showing how to use +MDE with IPC in Helios. + +In the animation below we can see the result of the Helios-MDE +application into a network with a set of anchored nodes. + +|image1| + +Next steps +~~~~~~~~~~ + +I’ll probably focus on the Helios network visualization system. +Improving the documentation and testing the ForceAtlas2 in a computer +with cuda installed. See the list of opened +`issues `__ + +Summary of most important pull-requests: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +- IPC tools for network layout methods (helios issue #7) + `fury-gl/helios/pull/6 `__ +- New network layout methods for fury (helios issue #7) + `fury-gl/helios/pull/9 `__ + `fury-gl/helios/pull/14 `__ + `fury-gl/helios/pull/13 `__ +- Improved the visual aspects and configurations of the network + rendering(helios issue #12) + https://github.com/devmessias/helios/tree/fury_network_actors_improvements +- Tests, examples and documentation for Helios (helios issues #3 and + #4) + `fury-gl/helios/pull/5 `__ +- Reduced the flickering effect on the FURY/Helios streaming system + `fury-gl/helios/pull/10 `__ + `fury-gl/fury/pull/437/commits/a94e22dbc2854ec87b8c934f6cabdf48931dc279 `__ + +.. |image1| image:: https://user-images.githubusercontent.com/6979335/125310065-a3a9f480-e308-11eb-98d9-0ff5406a0e96.gif diff --git a/v0.10.x/_sources/posts/2021/2021-07-12-week-6-antriksh.rst.txt b/v0.10.x/_sources/posts/2021/2021-07-12-week-6-antriksh.rst.txt new file mode 100644 index 000000000..0c78dfd80 --- /dev/null +++ b/v0.10.x/_sources/posts/2021/2021-07-12-week-6-antriksh.rst.txt @@ -0,0 +1,27 @@ +Week #6: Bug fixes, Working on Tree2D UI +======================================== + +.. post:: July 12 2021 + :author: Antriksh Misri + :tags: google + :category: gsoc + +What did I do this week? +------------------------ +This week I had relatively few tasks and most of them were to fix some bugs/design flaws that were discussed in last week's meeting. Other than that, I had to implement a few things in the Tree2D UI element that will be discussed in detail below. I also had to update some existing PRs in order to make things work well. Below are the list of things I worked on this week: + +* `Extracted Button2D class from elements to core `_ : Button2D was placed in elements during the UI restructuring. The problem with that was that Button2D was needed in other UI elements outside UI elements present in elements in Panel2D. So, it was decided to create a rule that only the UI elements that do not depend on any other UI element are allowed to be placed in core UI elements. Button2D does not depend on any other UI element so it was extracted from elements to core. + +* `Adapting GridLayout to work with UI elements `_ : This was a PR that aimed to add support for UI elements to be placed in a grid fashion. the problem was that there still some circular imports even after UI restructuring, primarily because UI was being imported in the layout module that in turn indirectly imported some UI elements making them circularly dependent. To remove the circular imports, it was decided to determine the UI element by checking for a add_to_scene method attribute in the instance. I updated the existing PR to implement the same. + +* `Continuing my work on Tree2D `_: The Tree2D lacked some important things related to design and visual aspect of it. Before, if the children of any node exceeded its height they would just overflow. To prevent this I came up with a few solutions two of which were to either add a scrollbar on the overflowing node or to simply auto resize the parent node. Currently, there is no global API for the scrollbar and it has to be manually setup in a UI element, this will be hopefully implemented in the near future probably using layout management. Till then the auto resizing has been implemented for the nodes. In future, an option for scrollbar will be added. + +Did I get stuck anywhere? +------------------------- +I am still stuck with adding tests for panel resizing PR. As it needs windows events to be recorded as well. I tried to propagate the event to the interactor first but that just lead to that particular event being registered multiple times. I will try to find a workaround for it. + +What is coming up next? +----------------------- +If the Tree2D gets merged by this week then I'll probably work on other UI elements. Other tasks will be decided in the next meeting. + +**See you guys next week!** diff --git a/v0.10.x/_sources/posts/2021/2021-07-12-week-6-sajag.rst.txt b/v0.10.x/_sources/posts/2021/2021-07-12-week-6-sajag.rst.txt new file mode 100644 index 000000000..28189a1b7 --- /dev/null +++ b/v0.10.x/_sources/posts/2021/2021-07-12-week-6-sajag.rst.txt @@ -0,0 +1,44 @@ +Fifth week of coding! +===================== + +.. post:: July 12 2021 + :author: Sajag Swami + :tags: google + :category: gsoc + +Welcome to the sixth weekly check-in. I'll be sharing my progress for the fifth week of coding. + +What did you do this week? +-------------------------- + +1. Generalised the vtkProteinRibbonFilter implementation. +2. Updated the molecular module based on suggestions of team members + and mentors (`PR #452`_). +3. Updated wave function animation (`PR #362`_). + + .. figure:: https://user-images.githubusercontent.com/65067354/125155195-d4105800-e17b-11eb-9e6d-2b66ba7a8f6e.gif + :width: 300 + :height: 300 + + an animation + + +What is coming up next week? +---------------------------- + +1. Update molecular module based on team members' suggestions and add + tests for the same. +2. Add protein ribbon implementation to the molecular module. +3. Begin working on molecular surface model. + +Did you get stuck anywhere? +--------------------------- + +No! **I was finally able to generalise the vtkProteinRibbonFilter implementation!!** I'm +grateful to the mentors for keeping a meeting and for helping me debug +the code. I figured out most of the stuff courtesy the meeting. + +.. _PR #452: https://github.com/fury-gl/fury/pull/452 +.. _PR #362: https://github.com/fury-gl/fury/pull/362 + +``Au Revoir!`` diff --git a/v0.10.x/_sources/posts/2021/2021-07-19-gsoc-devmessias-7.rst.txt b/v0.10.x/_sources/posts/2021/2021-07-19-gsoc-devmessias-7.rst.txt new file mode 100644 index 000000000..b50442d11 --- /dev/null +++ b/v0.10.x/_sources/posts/2021/2021-07-19-gsoc-devmessias-7.rst.txt @@ -0,0 +1,50 @@ +Weekly Check-In #7 +=================== + +.. post:: July 19 2021 + :author: Bruno Messias + :tags: google + :category: gsoc + + +What did I do this week? +------------------------ + +- `PR fury-gl/helios#16 + (merged): `__ Helios IPC + network layout support for MacOs + +- `PR fury-gl/helios#17 + (merged): `__ Smooth + animations for IPC network layout algorithms + + Before this commit was not possible to record the positions to have a + smooth animations with IPCLayout approach. See the animation below + + |image1| + + After this PR now it's possible to tell Helios to store the evolution + of the network positions using the record_positions parameter. This + parameter should be passed on the start method. Notice in the image + below how this gives to us a better visualization + + |image2| + +- `PR fury-gl/helios#13 + (merged) `__ Merged the + forceatlas2 cugraph layout algorithm + +Did I get stuck anywhere? +------------------------- + +I did not get stuck this week. + +What is coming up next? +----------------------- + +Probably, I'll work more on Helios. Specifically I want to improve the +memory management system. It seems that some shared memory resources are +not been released when using the IPCLayout approach. + +.. |image1| image:: https://user-images.githubusercontent.com/6979335/126175596-e6e2b415-bd79-4d99-82e7-53e10548be8c.gif +.. |image2| image:: https://user-images.githubusercontent.com/6979335/126175583-c7d85f0a-3d0c-400e-bbdd-4cbcd2a36fed.gif diff --git a/v0.10.x/_sources/posts/2021/2021-07-19-week-7-antriksh.rst.txt b/v0.10.x/_sources/posts/2021/2021-07-19-week-7-antriksh.rst.txt new file mode 100644 index 000000000..2952f030c --- /dev/null +++ b/v0.10.x/_sources/posts/2021/2021-07-19-week-7-antriksh.rst.txt @@ -0,0 +1,23 @@ +Week #7: Finalizing the stalling PRs, finishing up Tree2D UI. +============================================================== + +.. post:: July 19 2021 + :author: Antriksh Misri + :tags: google + :category: gsoc + +What did I do this week? +------------------------ +This week I had limited tasks to do, mostly tasks related to existing PRs. Other than some minor fixes I had to implement some more things in Tree2D which included some minor UI fixes, some changes in tutorial, adding tests. Below is the detailed description of what I worked on this week: + +* `Tests, tutorial changes, UI fixes for Tree2D `_ : The Tree2D lacked some things like proper UI resizing, relative indentation, tests for the UI class. These were added with this PR. Currently, the indentation, resizing needs some improvement, which will be fixed after feedback from this week's meeting. Also, tests for Tree2D, TreeNode2D were added as well. +* `Updating Panel2D tests, re-recording the events `_ : This PR is almost done with just some tests blocking the PR. The tests were added this week, but tests for some callbacks that are associated with window event are still not added. This is because there is no way to count the WindowResizeEvent without actually using the API of the window provided by the OS. This can become very complicated very soon so, these tests may be added in the future. +* `Fixing the failing CI's for #443 `_ : The CI was failing on this PR and needed some fixing which was done this week. This PR still needs some refactoring before the all CI's pass. This will hopefully be fixed before this week's meeting. +* `Addressing all comments regarding #442 `_ : Previously, it was pointed out that the some code can be extracted into a function and can be reused in other methods. So, this week the extracted method was updated to reuse even more code and now almost no code is repeated. +* `Adding has_border flag in Panel2D `_ : Adding a has_border flag in Panel2D: Previously, to create the borders 4 Rectangle2D's were used and they were created every time even when border_width was set to 0. This would take a lot of wasted system resources. To fix this, a flag is added in the the constructor which is by default set to False. If false, the borders are not initialized and the resources are saved. + +Did I get stuck anywhere? +------------------------- +Fortunately, this week I didn't get stuck anywhere. + +**See you guys next week!** diff --git a/v0.10.x/_sources/posts/2021/2021-07-19-week-7-sajag.rst.txt b/v0.10.x/_sources/posts/2021/2021-07-19-week-7-sajag.rst.txt new file mode 100644 index 000000000..1daaa1c36 --- /dev/null +++ b/v0.10.x/_sources/posts/2021/2021-07-19-week-7-sajag.rst.txt @@ -0,0 +1,65 @@ +Sixth week of coding! +===================== + +.. post:: July 19 2021 + :author: Sajag Swami + :tags: google + :category: gsoc + +Welcome to the seventh weekly check-in. I'll be sharing my progress for the sixth week of coding. + +What did you do this week? +-------------------------- + +#. Updated `Molecular module`_: made it more pythonic, implemented + ribbon actor, added support to pass numpy arrays (earlier, atomic + data could only be added by using the add_atom). +#. Created `PR #462`_ to: + + - Update the helical motion animation to use a single line actor, + added textblocks to display velocity of the particle. + + |image1| + + - For brownian motion animation, I removed rotation(azimuth) and box + actor, added textblock to display the number of particles and to + show the simulation steps. + + |image2| + +#. Updated surface animation (used gridUI, added multiple animations). + + |image3| + +#. Created a `topic`_ on vtk discourse forum to query about gaps in + bonds (tried resolving it by manipulating vtkProperties: + BackfaceCulling, FrontfaceCulling but was unsuccessful). +#. Read about molecular surface (theory behind it). + +What is coming up next week? +---------------------------- + +#. Update molecular module by adding tests, ribbon actor. +#. Try to implement molecular surface representation. +#. Interactivity of the molecules. + +Did you get stuck anywhere? +--------------------------- + +I didn't get stuck anywhere this week. + +.. _Molecular module: https://github.com/fury-gl/fury/pull/452 +.. _PR #462: https://github.com/fury-gl/fury/pull/462 +.. _topic: https://discourse.vtk.org/t/vtkmoleculemapper-gaps-in-bonds-on-zooming-in/6183 + +.. |image1| image:: https://user-images.githubusercontent.com/65067354/126033284-882ed6fd-fcc3-4a1c-8dfd-3220908859b1.png + :width: 400px + :height: 300px +.. |image2| image:: https://user-images.githubusercontent.com/65067354/126033291-da68cb0d-b856-48ad-9aa4-c46621052267.png + :width: 400px + :height: 400px +.. |image3| image:: https://user-images.githubusercontent.com/65067354/126061012-b183a47d-ed5e-4026-938b-4124da291524.png + :width: 400px + :height: 400px + +``Au Revoir!`` diff --git a/v0.10.x/_sources/posts/2021/2021-07-26-gsoc-devmessias-8.rst.txt b/v0.10.x/_sources/posts/2021/2021-07-26-gsoc-devmessias-8.rst.txt new file mode 100644 index 000000000..4b4ab4963 --- /dev/null +++ b/v0.10.x/_sources/posts/2021/2021-07-26-gsoc-devmessias-8.rst.txt @@ -0,0 +1,33 @@ +Weekly Check-In #8 +================== + +.. post:: July 26 2021 + :author: Bruno Messias + :tags: google + :category: gsoc + + +What did I do this week? +------------------------ + +- `PR fury-gl/helios#18 (merged):`_ Helios Documentation/ + I’ve been working on Helios documentation. Now it’s available + online at https://fury-gl.github.io/helios-website |image1| + +- `PR fury-gl/helios#17 (merged):`_ Helios CI for tests and code + coverage + +Did I get stuck anywhere? +------------------------- + +I did not get stuck this week. + +What is coming up next? +----------------------- + +I’ll discuss that with my mentors tomorrow. + +.. _`PR fury-gl/helios#18 (merged):`: https://github.com/fury-gl/helios/pull/18 +.. _`PR fury-gl/helios#17 (merged):`: https://github.com/fury-gl/helios/pull/17 + +.. |image1| image:: https://fury-gl.github.io/helios-website/_images/logo.png diff --git a/v0.10.x/_sources/posts/2021/2021-07-26-week-8-antriksh.rst.txt b/v0.10.x/_sources/posts/2021/2021-07-26-week-8-antriksh.rst.txt new file mode 100644 index 000000000..ba774ae7d --- /dev/null +++ b/v0.10.x/_sources/posts/2021/2021-07-26-week-8-antriksh.rst.txt @@ -0,0 +1,29 @@ +Week #8: Code Cleanup, Finishing up open PRs, Continuing work on Tree2D +======================================================================== + +.. post:: July 26 2021 + :author: Antriksh Misri + :tags: google + :category: gsoc + +What did I do this week? +------------------------ +This week I had to work on the open PRs specifically work on the bugs that were pointed out in last week's meeting. Along side the bugs I had to continue the work on Tree2D UI element. Below is the detailed description of what I worked on this week: + +* `Added new tutorial, code clean-up, bug fixes `_ : The Tree2D had some issues with its resizing of child nodes. The size for the nodes was calculated automatically based on the vertical size occupied by its children but this could be problematic when working with sliders or UI elements that take up a lot of vertical size. To avoid this the children sizes are calculated relative to each other and the vertical size is calculated such that all children fit in perfectly. Besides this, a multiselection flag has been added that decides whether multiple child nodes can be selected or not. +* `Adding tests for corner resize callback `_ : This PR is almost done as it was decided that WindowsResizeEvent will be ignored for now. Which leaves us with corner resizing, the callback for corner resizing didn't have any tests so the recording was redone and tests for the corner resize callback was added. +* `Fixing the failing CI's for #443 `_ : The solution that ended up working was creating custom objects for testing of is_ui method. With this update there will be no circular dependencies and no failing CI's. +* `Addressing all comments regarding #442 `_ : In the last meeting, a bug was pointed out wherein the text wouldn't wrap as expected. The reason for this was some minor calculation mistakes. The whole wrap_overflow method was redone and now everything works as expected. Hopefully, no bugs pop up during this week's meeting. +* `Addressing some minor comments `_ : This PR is almost done too, there were some minor changes that were required to be addressed before this could be merged. So, these comments were fixed and hopefully this will be merged soon. +* Using different fonts using FreeType python API: A major thing that FURY needs right now is using different fonts on the fly. This is more complicated than it seems, in case of browser environment this is not a problem as browsers can support and render all fonts using various techniques. In case of a desktop environment, we need to generate the bitmap for the fonts and then use them in form of textures. For now I have created a small example that generates these bitmaps from a python API called freetype-py, the fonts are fetched from google fonts and then they are displayed as textures. +* **Starting working on Vertical Layout**: As majority of PRs are almost done, I started working on Vertical Layout. This will be hihgly inspired from the Grid Layout with obvious differences. The same techniques are being used in the Tree2D so this shouldn't be difficult to implement. + +Did I get stuck anywhere? +------------------------- +The failing CI's for Grid Layout Pr needed some custom objects to remove circular dependencies. I couldn't figure out where should these custom objects go but fortunaltely the mentors showed me a quick example of where it should go. + +What is coming up next week? +---------------------------- +Next week I will continue my work on some other UI's and the remaining Layouts. + +**See you guys next week!** diff --git a/v0.10.x/_sources/posts/2021/2021-07-26-week-8-sajag.rst.txt b/v0.10.x/_sources/posts/2021/2021-07-26-week-8-sajag.rst.txt new file mode 100644 index 000000000..be9da8b01 --- /dev/null +++ b/v0.10.x/_sources/posts/2021/2021-07-26-week-8-sajag.rst.txt @@ -0,0 +1,47 @@ +Seventh week of coding! +======================= + +.. post:: July 26 2021 + :author: Sajag Swami + :tags: google + :category: gsoc + +Welcome to the eighth weekly check-in. I'll be sharing my progress for the seventh week of coding. + +What did you do this week? +-------------------------- + +#. Updated `PR #452`_: + + - Added ribbon actor to the molecular module. + - Added tests for all functions in the molecular module. + +#. Updated `PR #462`_: Addressed the reviews of team members and + mentors, added new features. + + |image1| + +#. Updated `PR #362`_: Addressed the feedbacks of team members and + mentors. + +What is coming up next week? +---------------------------- + +#. Work more on molecular module, meeting with mentors and core team on + Thursday to optimize the module and merge `PR #452`_. +#. Start working upon molecular surface model. + +Did you get stuck anywhere? +--------------------------- + +No. + +.. _PR #452: https://github.com/fury-gl/fury/pull/452 +.. _PR #462: https://github.com/fury-gl/fury/pull/462 +.. _PR #362: https://github.com/fury-gl/fury/pull/362 + +.. |image1| image:: https://user-images.githubusercontent.com/65067354/126382288-b755c01d-8010-43ab-87db-2f1a4fb5b015.png + :width: 300px + :height: 300px + +``Au Revoir!`` diff --git a/v0.10.x/_sources/posts/2021/2021-08-02-gsoc-devmessias-9.rst.txt b/v0.10.x/_sources/posts/2021/2021-08-02-gsoc-devmessias-9.rst.txt new file mode 100644 index 000000000..f40f46dfd --- /dev/null +++ b/v0.10.x/_sources/posts/2021/2021-08-02-gsoc-devmessias-9.rst.txt @@ -0,0 +1,47 @@ +Week #09: Sphinx custom summary +=============================== + +.. post:: August 02 2021 + :author: Bruno Messias + :tags: google + :category: gsoc + + +What did I do this week? +------------------------ + +FURY/Helios +^^^^^^^^^^^ + + +- `PR fury-gl/helios#22 + : `__ Helios Documentation + Improvements. + I’ve spent some time studying sphinx in order to discover how I could create a + custom summary inside of a template module. + +FURY +^^^^ +Added my GSoC blogs to the FURY blogs as requested by my mentors. +- `PR fury-gl/fury#437: `__ + + - Docstrings improvements + - Covered more tests + - Covered tests using optional dependencies. + - Aiortc now it’s not a mandatory dependency + - improvements in memory management + +- PR #432 Fixed some typos, improved the tests and docstrings +- `PR fury-gl/fury#474: `__ +- Helped to review and made some suggestions to the PR #474 made by @mehabhalodiya. + + +Did I get stuck anywhere? +------------------------- + +I did not get stuck this week. + +What is coming up next? +----------------------- + +I’ll discuss that with my mentors tomorrow. diff --git a/v0.10.x/_sources/posts/2021/2021-08-02-week-9-antriksh.rst.txt b/v0.10.x/_sources/posts/2021/2021-08-02-week-9-antriksh.rst.txt new file mode 100644 index 000000000..cd4ac170b --- /dev/null +++ b/v0.10.x/_sources/posts/2021/2021-08-02-week-9-antriksh.rst.txt @@ -0,0 +1,35 @@ +Week #9: More Layouts! +====================== + +.. post:: August 02 2021 + :author: Antriksh Misri + :tags: google + :category: gsoc + +What did I do this week? +------------------------ +Below are the tasks that I worked on: + +* `Added Horizontal/Vertical Layout to the layout module `_ : These PRs add support for Horizontal/Vertical layouts. These layouts allow the actors to be placed in a horizontal/vertical stack. + + .. image:: https://user-images.githubusercontent.com/54466356/127688192-8412b604-d6c7-4da9-87c4-dfae044a136e.png + :width: 200 + :height: 200 + + .. image:: https://user-images.githubusercontent.com/54466356/127620054-7e14f86e-1579-46ac-b4a6-ac98c109094a.png + :width: 200 + :height: 200 + +* `Finalizing Card2D UI element `_ : As panel border, wrap overflow PRs were merged this week I updated the Card2D UI to take advantage of these features. +* `Added GSoC blog posts `_ : Added GSoC blog posts in .rst format for the FURY's blog website. Also reviewed the blog posts of other members. +* `Added support for dragging by label text/icon in Tree2D UI `_ : Added support for dragging TreeNode2D by the label text/icon. This will help making the Tree2D as well as TreeNode2D UIs more mobile. + +Did I get stuck anywhere? +------------------------- +For now I am not stuck anywhere but I have yet to start my work on freetype this could pose some trouble. + +What is coming up next week? +---------------------------- +Next week I will finish the remaining UI elements which includes Accordion2D, SpinBox2D. + +**See you guys next week!** diff --git a/v0.10.x/_sources/posts/2021/2021-08-02-week-9-sajag.rst.txt b/v0.10.x/_sources/posts/2021/2021-08-02-week-9-sajag.rst.txt new file mode 100644 index 000000000..fc6eadf8c --- /dev/null +++ b/v0.10.x/_sources/posts/2021/2021-08-02-week-9-sajag.rst.txt @@ -0,0 +1,44 @@ +Eighth coding week! +======================= + +.. post:: August 02 2021 + :author: Sajag Swami + :tags: google + :category: gsoc + +Welcome to the ninth weekly check-in. I'll be sharing my progress for the eighth week of coding. + +What did you do this week? +-------------------------- + +#. Updated `PR #452`_: Had an extra meeting with the mentors in which we fine-tuned the molecular module and optimised the code to make it more pythonic. + +#. I was able to generate vertices and triangles for Solvent Excluded Surfaces (SES) by using a bioconda package called `msms`_. It's based on `this paper`_ by Michel F. Sanner, Arthur J. Olson & Jean-Claude Spehner. The vertices and triangles were then sent to surface actor to generate a surface. + + .. figure:: https://user-images.githubusercontent.com/65067354/128756004-553d1880-b6e1-4a43-99fa-5bd6a2ee70d4.png + :width: 300 + :height: 300 + + SES surface generated via msms and surface actor + +#. Added my GSoC blogs to the FURY blogs directory. (`PR #475`_) + +Other goals will be decided in the meeting with mentors. + +What is coming up next week? +---------------------------- + +#. Research about recent papers having good (fast) algorithms to create the molecular surfaces. +#. Create tutorials to explain how to use molecular module. + +Did you get stuck anywhere? +--------------------------- + +No. + +.. _PR #452: https://github.com/fury-gl/fury/pull/452 +.. _msms: https://anaconda.org/bioconda/msms +.. _this paper: https://onlinelibrary.wiley.com/doi/10.1002/%28SICI%291097-0282%28199603%2938%3A3%3C305%3A%3AAID-BIP4%3E3.0.CO%3B2-Y +.. _PR #475: https://github.com/fury-gl/fury/pull/475 + +``Au Revoir!`` diff --git a/v0.10.x/_sources/posts/2021/2021-08-03-release-announcement.rst.txt b/v0.10.x/_sources/posts/2021/2021-08-03-release-announcement.rst.txt new file mode 100644 index 000000000..584bbeccd --- /dev/null +++ b/v0.10.x/_sources/posts/2021/2021-08-03-release-announcement.rst.txt @@ -0,0 +1,48 @@ +FURY 0.7.0 Released +=================== + +.. post:: August 03 2021 + :author: skoudoro + :tags: fury + :category: release + + +The FURY project is happy to announce the release of FURY 0.7.1! +FURY is a free and open source software library for scientific visualization and 3D animations. + +You can show your support by `adding a star `_ on FURY github project. + +This Release is mainly a maintenance release. The **major highlights** of this release are: + +.. include:: ../../release_notes/releasev0.7.1.rst + :start-after: -------------- + :end-before: Details + +.. note:: The complete release notes are available :ref:`here ` + +**To upgrade or install FURY** + +Run the following command in your terminal:: + + pip install --upgrade fury + +or:: + + conda install -c conda-forge fury + + +**Questions or suggestions?** + +For any questions go to http://fury.gl, or send an e-mail to fury@python.org +We can also join our `discord community `_ + +We would like to thanks to :ref:`all contributors ` for this release: + +.. include:: ../../release_notes/releasev0.7.1.rst + :start-after: commits. + :end-before: We closed + + +On behalf of the :ref:`FURY developers `, + +Serge K. diff --git a/v0.10.x/_sources/posts/2021/2021-08-09-week-10-antriksh.rst.txt b/v0.10.x/_sources/posts/2021/2021-08-09-week-10-antriksh.rst.txt new file mode 100644 index 000000000..9b439c2b8 --- /dev/null +++ b/v0.10.x/_sources/posts/2021/2021-08-09-week-10-antriksh.rst.txt @@ -0,0 +1,36 @@ +Week#10: Accordion UI, Support for sprite sheet animations +========================================================== + +.. post:: August 09 2021 + :author: Antriksh Misri + :tags: google + :category: gsoc + +What did I do this week? +------------------------ +Below are the tasks that I worked on: + +* `Added Accordion2D to UI sub-module `_ : This PR adds the Accordion UI to the UI sub-module. This UI inherits from the Tree2D UI and can only be merged once the Tree2D UI is in. Here's a screenshot for reference: + + .. image:: https://i.imgur.com/klI4Tb5.png + :width: 200 + :height: 200 + +* `Adding X, Y, Z Layouts `_ : It was pointed out in last week's meeting that in 3D space horizontal/vertical means nothing. Instead X, Y, Z are used, so, these three layouts were added on top of horizontal/vertical layouts. They also have functionality of changing the direction i.e. reverse the stacking order. +* `Added support of sprite sheet animation in Card2D `_ : The image in Card2D was static in nature and wasn't very interesting. So, to make things a bit interesting support for animated images were added. These animations are played from a sprite sheet or a texture atlas. A buffer of processed sprite chunks is maintained and with the help of a timer callback the image in the card is updated after a certain delay which is dependent of the frame rate. Below is the demonstration: + + .. image:: https://i.imgur.com/DliSpf0.gif + :width: 200 + :height: 200 + +* **Researching more about Freetype/Freetype-GL**: Apart from coding stuff, i did some more research on custom font using freetype and freetype-gl. I found some examples that used the python bindings of the c++ library and displayed custom fonts that were transformable i.e. can be rotated by some angle. Hopefully I can create a working example by this weeks meeting. + +Did I get stuck anywhere? +------------------------- +No, I did not get stuck anywhere. + +What is coming up next week? +---------------------------- +Next week I will finish up my remaining work. Which includes addressing all PR reviews and adding some more features. + +**See you guys next week!** diff --git a/v0.10.x/_sources/posts/2021/2021-08-09-week-10-sajag.rst.txt b/v0.10.x/_sources/posts/2021/2021-08-09-week-10-sajag.rst.txt new file mode 100644 index 000000000..774a01554 --- /dev/null +++ b/v0.10.x/_sources/posts/2021/2021-08-09-week-10-sajag.rst.txt @@ -0,0 +1,44 @@ +Ninth coding week! +======================= + +.. post:: August 09 2021 + :author: Sajag Swami + :tags: google + :category: gsoc + +Welcome to the tenth weekly check-in. I'll be sharing my progress for the ninth week of coding. + +What did you do this week? +-------------------------- + +#. Updated `PR #452`_ : + + - Made ribbon representation faster. + - Added an actor to display bounding box around the molecule. + + .. figure:: https://user-images.githubusercontent.com/65067354/128624529-03c026be-7f80-4792-b57e-eceeb1767ec2.png + :width: 300 + :height: 300 + + Bounding Box + +#. Made a tutorial which showcases the abilities of molecular module (will create a PR after molecular module is merged). + +#. I'm trying to implement a native implementation of molecular surfaces in FURY. Currently searching for recent research papers to find good algorithms to generate the molecular surfaces (the ones I'd collected in the research period were archaic and rather time consuming). The papers that I've read so far seem a tad bit intimidating as I've never done math related to this domain yet. Implementing them will be a good learning experience I reckon. + +What is coming up next week? +---------------------------- + +#. Try to create a native implementation of molecular surface. +#. Small fixes to `PR #362`_, `PR #462`_. + +Did you get stuck anywhere? +--------------------------- + +No. + +.. _PR #452: https://github.com/fury-gl/fury/pull/452 +.. _PR #362: https://github.com/fury-gl/fury/pull/362 +.. _PR #462: https://github.com/fury-gl/fury/pull/462 + +``Au Revoir!`` diff --git a/v0.10.x/_sources/posts/2021/2021-08-16-week-11-antriksh.rst.txt b/v0.10.x/_sources/posts/2021/2021-08-16-week-11-antriksh.rst.txt new file mode 100644 index 000000000..b229f0343 --- /dev/null +++ b/v0.10.x/_sources/posts/2021/2021-08-16-week-11-antriksh.rst.txt @@ -0,0 +1,26 @@ +Week #11: Finalizing open Pull Requests +======================================= + +.. post:: August 16 2021 + :author: Antriksh Misri + :tags: google + :category: gsoc + +What did I do this week? +------------------------ +Below are the tasks that I worked on: + +* `Created PR for sprite sheet animation `_ : This PR adds support for playing animations from a sprite sheet. This feature will be used in Card2D to create a tutorial in which the card will show the animation in the image box. Previously, the utility functions for this were added directly inside the tutorial but now they are refactored to go in their respective modules. +* `Finalized the x, y, z layouts `_ : The PR that adds these layouts needed some updates for it to work as intended. These changes were added and this PR is ready to go. +* `Resolved all conflicts in the GridLayout PR `_ : As the Horizontal and Vertical layouts were merged this week the GridLayout PR had got some conflicts. These conflicts were resolved and the PR is almost ready. +* **Continuing the work on custom font rendering** : In the last meeting, a few points were brought up. Firstly, to position each glyph to their respective location in the atlas a separate module is used which is freetype-gl. The python bindings for this module are not available which means either we have to write the bindings ourselves or the freetype team will be emailed about this and they will add bindings for that. On the other hand, I looked how latex is rendered in matplotlib. `This `_ is the Text class that is used to represent the string that is to be drawn and `This is the class that it inherits from.`_ Everything is handled internally in matplotlib, to draw the rasterized text `this function is used. `_ The text can be rendered in two ways, the first one is by using the default renderer and the second way is by using PathEffectRenderer that is used to add effects like outlines, anti-aliasing etc. It is a very rigid way of rendering text and is designed to be used internally. + +Did I get stuck anywhere? +------------------------- +No, I did not get stuck anywhere. + +What is coming up next week? +---------------------------- +Hopefully everything is resolved by the end of this week and next week I will hopefully submit my final code in a gist format. + +**See you guys next week!** diff --git a/v0.10.x/_sources/posts/2021/2021-08-16-week-11-sajag.rst.txt b/v0.10.x/_sources/posts/2021/2021-08-16-week-11-sajag.rst.txt new file mode 100644 index 000000000..4fa614fb6 --- /dev/null +++ b/v0.10.x/_sources/posts/2021/2021-08-16-week-11-sajag.rst.txt @@ -0,0 +1,53 @@ +Tenth coding week! +======================= + +.. post:: August 16 2021 + :author: Sajag Swami + :tags: google + :category: gsoc + +Welcome to the eleventh weekly check-in. I'll be sharing my progress for the tenth week of coding. + +What did you do this week? +-------------------------- + +#. Implemented `this paper`_ to generate Van der Waals surface and solvent-accessible surface (PR created: `PR #492`_). It was a good learning experience because the first time I read the paper, I didn't understand the underlying math, it all seemed alien to me. I had to read it many times, read about the algorithms used and understand the terminologies. I had a meeting with the mentors to understand a bit of the theory which proved to be quite fruitful as I understood how to go about making the space-filling model. `This`_ blog was helpful in understanding how to use vtkMarchingCubes with numpy arrays. One of the earliest SAS rendering looked like this (this implementation was not strictly according to the paper): + + .. figure:: https://user-images.githubusercontent.com/65067354/129559593-baf201bf-720c-45f7-9269-3b31954efd5e.png + :width: 300 + :height: 300 + + Notice that it's rather rough + + Current implementation (this implementation was according to the paper): + + .. figure:: https://user-images.githubusercontent.com/65067354/129560374-14180b22-14b2-449b-88a6-b3140226418d.png + :width: 300 + :height: 300 + + grid dimensions = 256 × 256 × 256, used smoothing algorithms recommended by vtk + +I also understood how to go about rendering volumes. I think that the ability to render volumes with FURY will be a cool capability and I'll discuss my implementation and request the mentors for feedback and ideas in the weekly meeting. Example of volume rendering: + + .. figure:: https://user-images.githubusercontent.com/65067354/129562606-50a9f0cf-e16d-4501-b0fa-a0038fda406b.png + :width: 300 + :height: 300 + + grid dimensions = 256 × 256 × 256 + +What is coming up next week? +---------------------------- + +I'll try to get `PR #452`_ merged. Documentation work to be done as GSoC coding period has come to an end. + +Did you get stuck anywhere? +--------------------------- + +No. + +.. _this paper: https://journals.plos.org/plosone/article?id=10.1371/journal.pone.0008140 +.. _PR #492: https://github.com/fury-gl/fury/pull/492 +.. _This: ttps://pyscience.wordpress.com/2014/09/11/surface-extraction-creating-a-mesh-from-pixel-data-using-python-and-vtk/ +.. _PR #452: https://github.com/fury-gl/fury/pull/452 + +``Au Revoir!`` diff --git a/v0.10.x/_sources/posts/2021/2021-08-23-final-work-antriksh.rst.txt b/v0.10.x/_sources/posts/2021/2021-08-23-final-work-antriksh.rst.txt new file mode 100644 index 000000000..8bf4f39bf --- /dev/null +++ b/v0.10.x/_sources/posts/2021/2021-08-23-final-work-antriksh.rst.txt @@ -0,0 +1,205 @@ +.. image:: https://developers.google.com/open-source/gsoc/resources/downloads/GSoC-logo-horizontal.svg + :height: 50 + :align: center + :target: https://summerofcode.withgoogle.com/projects/#6653942668197888 + +.. image:: https://www.python.org/static/community_logos/python-logo.png + :width: 40% + :target: https://blogs.python-gsoc.org/en/nibba2018s-blog/ + +.. image:: https://python-gsoc.org/logos/FURY.png + :width: 25% + :target: https://fury.gl/latest/community.html + +Google Summer of Code Final Work Product +======================================== + +.. post:: August 23 2021 + :author: Antriksh Misri + :tags: google + :category: gsoc + +- **Name:** Antriksh Misri +- **Organisation:** Python Software Foundation +- **Sub-Organisation:** FURY +- **Project:** `FURY: Create new user interface widget `_ + +Proposed Objectives +------------------- + +* Add support for Layouts in UI elements +* Add support for Horizontal Layout +* Add support for Vertical Layout +* Add support for Layout along X, Y, Z axes. +* Stretch Goals: + + * Add Tree2D UI element to the UI sub-module + * Add Accordion2D UI element to the UI sub-module + * Add SpinBox2D UI element to the UI sub-module + +Objectives Completed +-------------------- + + +- **Add support for Horizontal Layout** + + Added support for Horizontal Layout in the layout module. This layout allows the user to stack actors in a horizontal fashion. Primarily, should be used for laying out UI elements as there is no meaning of horizontal/vertical in 3D space. + + *Pull Requests:* + + - **Horizontal Layout:** https://github.com/fury-gl/fury/pull/480 + - **Ribbon Representation demo:** https://github.com/fury-gl/fury/pull/480 + +- **Add support for Vertical Layout** + + Added support for Vertical Layout in the layout module. This layout allows the user to stack actors in a vertical fashion. Primarily, should be used for laying out UI elements as there is no meaning of horizontal/vertical in 3D space. + + *Pull Requests:* + + - **Vertical Layout:** https://github.com/fury-gl/fury/pull/479 + - **Vertical Layout demo:** https://github.com/fury-gl/fury/pull/479 + +- **Add support for Layout along X, Y, Z axes** + + Added support for Layout along x, y, z axes. Allows user to layout different actors along any given axes. Also it allows users to switch the stacking order by passing a axis+ or axis- to the constructor. + + *Pull Requests:* + + - **X, Y, Z axes Layout:** https://github.com/fury-gl/fury/pull/486 + - **X, Y, Z axes Layout demo:** https://github.com/fury-gl/fury/pull/486 + +- **Add Tree2D UI element to the UI sub-module** + + Added Tree2D UI element to the UI sub-module. This allows user to visualize some data in a hierarchical fashion. Each node inside the tree can have N child nodes and the depth can be infinite. Each node can be clicked to trigger a user defined callback to perform some action. Tests and two demos were added for this UI element. Below is a screenshot for reference: + + .. image:: https://camo.githubusercontent.com/dd23b7c8503e4d01c80f2d9e84ee173e06c61eeb7c348c35aeadc75f722647ca/68747470733a2f2f692e696d6775722e636f6d2f4e49334873746c2e706e67 + :width: 200 + :height: 200 + + *Pull Requests:* + + - **Tree2D UI element:** https://github.com/fury-gl/fury/pull/460 + - **Tree2D UI element demo:** https://github.com/fury-gl/fury/pull/460 + +- **Add Accordion2D UI element to the UI sub-module** + + Added Accordion2D to the UI sub-module. This Ui element allows users to visualize data in a tree with depth of one. Each node has a title and a content panel. The children for each node can be N if and only if the children are not nodes themselves. The child UIs can be placed inside the content panel by passing some coordinates, which can be absolute or normalized w.r.t the node content panel size. Tests and two demos were added for this UI element. Below is a screenshot for reference + + .. image:: https://camo.githubusercontent.com/9395d0ea572d7f253a051823f02496450c9f79d19ff0baf32841ec648b6f2860/68747470733a2f2f692e696d6775722e636f6d2f7854754f645a742e706e67 + :width: 200 + :height: 200 + + *Pull Requests:* + + - **Accordion2D UI element:** https://github.com/fury-gl/fury/pull/487 + - **Accordion2D UI element demo:** https://github.com/fury-gl/fury/pull/487 + +Objectives in Progress +---------------------- + +- **Add support for Layout in UI elements** + + Currently all the available layouts are only available for actors i.e. of type vtkActor2D. In order to add support for the layouts in UI elements there needs to be some tweaking in the base Layout class. Currently, the PR that adds these functionalities in stalling because of some circular imports. These will hopefully be fixed soon and as soon as the circular imports are fixed, the PR will be merged. + + *Pull Requests:* + + - **Add support for Layout in UI elements:** https://github.com/fury-gl/fury/pull/443 + +- **Method to process and load sprite sheets** + + This method adds support for loading and processing a sprite sheet. This will be very useful in playing animations from a n*m sprite sheet. This also has a flag to convert the processed chunks into vtkimageData which can be directly used to update the texture in some UI elements. The primary use of this method will in a tutorial for Card2D, wherein, the image panel of the card will play the animation directly from the sprite sheet. + + *Pull Requests:* + + - **Method to process and load sprite sheets:** https://github.com/fury-gl/fury/pull/491 + +Other Objectives +---------------- + +- **Add Card2D UI element to UI sub-module** + + Added Card2D UI element to the UI sub-module. A Card2D is generally divided into two parts i.e. the image content and the text content. This version of card has an image which can be fetched from a URL and the text content which is yet again divided into two parts i.e. the title and the body. The space distribution between the image and the text content is decided by a float between 0 and 1. A value of 0 means the image takes up no space and a value of 1 means the image consumes the whole space. Below is a demonstration: + + .. image:: https://camo.githubusercontent.com/a2e461352799b6490088de15ac041162d7bf8adf9c07485ea921b525fecd0a8e/68747470733a2f2f692e696d6775722e636f6d2f446c69537066302e676966 + :width: 200 + :height: 200 + + *Pull Requests:* + + - **Add Card2D UI element to UI sub-module:** https://github.com/fury-gl/fury/pull/398 + +- **Resize Panel2D with WindowResizeEvent or from corner placeholder** + + Currently, the size of the Panel2D is static and cannot be changed dynamically. The size is passed in during the initialization and cannot be changed easily at runtime. This PR adds support for resizing the Panel2D dynamically by adding a placeholder icon at the bottom right corner of the panel. This icon can be click and dragged on to change the size accordingly. Other than this, the panel also retains a specific size ratio when the window is resized. This means if the window is resized in any direction the panel adapts itself w.r.t the updated size. This is done by adding relevant observers for the WindowResizeEvent and binding the relevant callback to it. Below is a quick demonstration: + + .. image:: https://camo.githubusercontent.com/3b1bf6a1b6522a6079055ff196551362fcf89a41b35ac4b32315ce02333e496d/68747470733a2f2f692e696d6775722e636f6d2f3837504e3754512e676966 + :width: 200 + :height: 200 + + *Pull Requests:* + + - **Resize Panel2D with WindowResizeEvent or from corner placeholder:** https://github.com/fury-gl/fury/pull/446 + +- **Added the watcher class to UI** + + This PR adds support for a watcher class in the UI elements. The purpose of this class is to monitor a particular attribute from the UI element after it has been added to the scene. If the attribute changes in the real time, a user defined callback is triggered and the scene is force rendered. + + *Pull Requests:* + + - **Added wathcer class to the UI sub-module:** https://github.com/fury-gl/fury/pull/448 + +- **Added support for borders in Panel2D** + + The Panel2D previously, didn't support any sort of effect, the main reason behind this is that, all UI elements are individual entities that are comprised of different actors. These are not the widgets provided by vtk and in order to have some effects provided by vtk shaders must be involved. This obviously makes the whole system very complicated. The border on the other hand uses 4 Rectangle2Ds to draw the 4 borders. This makes the whole process easier but makes the Panel2D very performance heavy as we are adding 5 actors to the scene. Future iterations will replace these rectangles by textures, that way we don't compromise performance and we can have different patterns in the border. Below is a demonstration: + + .. image:: https://user-images.githubusercontent.com/54466356/121709989-bd340280-caf6-11eb-9b8a-81c65260d277.png + :width: 200 + :height: 200 + + *Pull Requests:* + + - **Added support for borders in Panel2D:** https://github.com/fury-gl/fury/pull/441 + +- **GSoC weekly Blogs** + + Weekly blogs were added for FURY's Website. + + *Pull Requests:* + + - **First Evaluation:** https://github.com/fury-gl/fury/pull/477 + + - **Second Evaluation:** https://github.com/fury-gl/fury/pull/494 + +Timeline +-------- + ++-----------------------+------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Date | Description | Blog Link | ++=======================+==================================================================+=======================================================================================================================================================+ +| Week 1(08-06-2021) | Welcome to my weekly Blogs! | `Weekly Check-in #1 `__ | ++-----------------------+------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 2(14-06-2021) | Feature additions in UI and IO modules | `Weekly Check-in #2 `__ | ++-----------------------+------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 3(21-06-2021) | Adapting GridLayout to work with UI | `Weekly Check-in #3 `__ | ++-----------------------+------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 4(28-06-2021) | Adding Tree UI to the UI module | `Weekly Check-in #4 `__ | ++-----------------------+------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 5(05-07-2021) | Rebasing all PR's w.r.t the UI restructuring, Tree2D, Bug Fixes | `Weekly Check-in #5 `__ | ++-----------------------+------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 6(12-07-2021) | Bug fixes, Working on Tree2D UI | `Weekly Check-in #6 `__ | ++-----------------------+------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 7(19-07-2021) | Finalizing the stalling PR's, finishing up Tree2D UI. | `Weekly Check-in #7 `__ | ++-----------------------+------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 8(26-07-2020) | Code Cleanup, Finishing up open PR's, Continuing work on Tree2D. | `Weekly Check-in #8 `__ | ++-----------------------+------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 9(02-08-2021) | More Layouts! | `Weekly Check-in #9 `__ | ++-----------------------+------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 10(09-08-2021) | Accordion UI, Support for sprite sheet animations. | `Weekly Check-in #10 `__ | ++-----------------------+------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 11(16-08-2021) | More tutorials for Accordion2D, Finalizing remaining PRs. | `Weekly Check-in #11 `__ | ++-----------------------+------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------+ + + + +Detailed weekly tasks and work done can be found +`here `_. diff --git a/v0.10.x/_sources/posts/2021/2021-08-23-final-work-sajag.rst.txt b/v0.10.x/_sources/posts/2021/2021-08-23-final-work-sajag.rst.txt new file mode 100644 index 000000000..6f9185f9b --- /dev/null +++ b/v0.10.x/_sources/posts/2021/2021-08-23-final-work-sajag.rst.txt @@ -0,0 +1,192 @@ +.. image:: https://developers.google.com/open-source/gsoc/resources/downloads/GSoC-logo-horizontal.svg + :height: 50 + :align: center + :target: https://summerofcode.withgoogle.com/projects/#6653942668197888 + +.. image:: https://www.python.org/static/community_logos/python-logo.png + :width: 40% + :target: https://blogs.python-gsoc.org/en/nibba2018s-blog/ + +.. image:: https://python-gsoc.org/logos/FURY.png + :width: 25% + :target: https://fury.gl/latest/community.html + +Google Summer of Code Final Work Product +======================================== + +.. post:: August 23 2021 + :author: Sajag Swami + :tags: google + :category: gsoc + +- **Name:** Sajag Swami +- **Organisation:** Python Software Foundation +- **Sub-Organisation:** FURY +- **Project:** `FURY: Ribbon and Molecular Surface Representations for + Proteins `_ + +Proposed Objectives +------------------- + +* Ribbon Representation +* Molecular Surface Representation +* Stretch Goals: + + * Stick Representation + * Ball and stick Representation + * Wire Representation + * Pipes and Planks Representation + * Sphere Representation + +Objectives Completed +-------------------- + + +- **Ribbon Representation** + + Ribbon diagrams, also known as Richardson diagrams, + are 3D schematic representations of protein structure. Ribbon diagrams are + generated by interpolating a smooth curve through the polypeptide backbone. + α-helices are shown as coiled ribbons. β-strands as sheets, and non-repetitive + coils or loops as lines or thin strips. It was implemented by using + `vtkProteinRibbonFilter`. Generating a `vtkPolyData` of appropriate format + required by `vtkProteinRibbonFilter` was initially unclear due to lack of + examples. I was able to understand what kind of output the filter required + after a meeting with mentors. Tests were added and a demo was created. + + *Pull Requests:* + + - **Ribbon representation:** https://github.com/fury-gl/fury/pull/452 + - **Ribbon Representation demo:** https://github.com/fury-gl/fury/pull/452 + + +- **Ball and Stick Representation** + + The ball-and-stick model is a molecular model of a chemical substance which + displays both the three-dimensional position of the atoms and the bonds between + them. The atoms are typically represented by spheres, connected by tubes which + represent the bonds. It was created by using `vtkOpenGLMoleculeMapper`. + Added `vtkSimpleBondPerceiver` for detection of bonds. Tests were added and a + demo was created. + + *Pull Requests:* + + - **Ball and Stick Representation:** https://github.com/fury-gl/fury/pull/452 + - **Ball and Stick Representation demo:** https://github.com/fury-gl/fury/pull/452 + +- **Stick Representation** + + Stick model is a special case of Ball and Stick model where atomic radius of all + molecules is set equal to the radius of tubes used to create bonds. It was created + by using `vtkOpenGLMoleculeMapper`. Tests were added and a demo was created. + + *Pull Requests:* + + - **Stick Representation:** https://github.com/fury-gl/fury/pull/452 + - **Stick Representation demo:** https://github.com/fury-gl/fury/pull/452 + +- **Sphere Representation** + + In chemistry, a space-filling model, also known as a calotte or sphere model, is a + type of three-dimensional (3D) molecular model where the atoms are represented by + spheres whose radii are proportional to the radii of the atoms. It was created by + using `vtkOpenGLMoleculeMapper`. Tests were added and a demo was created. + + *Pull Requests:* + + - **Sphere Representation:** https://github.com/fury-gl/fury/pull/452 + - **Sphere Representation demo:** https://github.com/fury-gl/fury/pull/452 + + + +Objectives in Progress +---------------------- + +- **Molecular Surfaces** + + There are three types of molecular surfaces: + + - Van der Waals + - Solvent Accessible + - Solvent Excluded + + Currently the first two molecular surfaces i.e. Van der Waals and Solvent + Accessible are implemented. The code is based on the paper "Generating + Triangulated Macromolecular Surfaces by Euclidean Distance Transform" by + Dong Xu and Yang Zhang. + + *Pull Requests:* + + - **Molecular Surfaces Implementation:** https://github.com/fury-gl/fury/pull/492 + + +Other Objectives +---------------- + +- **2D Animated Surfaces** + + This was a simple demonstration that animated Two-Dimensional (2D) functions using FURY. + Created a grid of x-y coordinates and mapped the heights (z-values) to the corresponding x, y + coordinates to generate the surfaces. Used colormaps to color the surfaces. + + *Pull Requests:* + + - **Animated Surfaces:** https://github.com/fury-gl/fury/pull/362 + +- **Updated miscellaneous animations** + + - Updated the demo of helical motion to stop using multiple line actors as discussed in the meeting. + - Updated the demo of brownian motion to make it more scientifically useful (removed unnecessary rotation of camera + during animation and box actor). + - Display simulation data for brownian motion and helical motion animations (number of simulated steps for brownian + motion and velocity of the particle for helical motion). + - Created utility functions to make the code understandable and used these in emwave, helical and brownian + animations. + + *Pull Requests:* + + - **Updated helical, brownian, emwave animations:** https://github.com/fury-gl/fury/pull/462 + +- **GSoC weekly Blogs** + + Weekly blogs were added for FURY's Website. + + *Pull Requests:* + + - **First Evaluation:** https://github.com/fury-gl/fury/pull/475 + + - **Second Evaluation:** https://github.com/fury-gl/fury/pull/493 + +Timeline +-------- + ++-----------------------+------------------------------------------------------------------+----------------------------------------------------------------------------------------------------+ +| Date | Description | Blog Link | ++=======================+==================================================================+====================================================================================================+ +| Week 1(08-06-2021) | Welcome to my GSoC Blog! | `Weekly Check-in #1 `__ | ++-----------------------+------------------------------------------------------------------+----------------------------------------------------------------------------------------------------+ +| Week 2(14-06-2021) | First Week of coding: sphere model. | `Weekly Check-in #2 `__ | ++-----------------------+------------------------------------------------------------------+----------------------------------------------------------------------------------------------------+ +| Week 3(21-06-2021) | Bonding algorithms, Ball and Stick model progress. | `Weekly Check-in #3 `__ | ++-----------------------+------------------------------------------------------------------+----------------------------------------------------------------------------------------------------+ +| Week 4(28-06-2021) | VTK molecular visualization classes. | `Weekly Check-in #4 `__ | ++-----------------------+------------------------------------------------------------------+----------------------------------------------------------------------------------------------------+ +| Week 5(05-07-2021) | Genesis of `molecular` module. | `Weekly Check-in #5 `__ | ++-----------------------+------------------------------------------------------------------+----------------------------------------------------------------------------------------------------+ +| Week 6(12-07-2021) | Ribbon representation, updated `molecular` module (more pythonic)| `Weekly Check-in #6 `__ | ++-----------------------+------------------------------------------------------------------+----------------------------------------------------------------------------------------------------+ +| Week 7(19-07-2021) | More features to `molecular`, updated misc. animations. | `Weekly Check-in #7 `__ | ++-----------------------+------------------------------------------------------------------+----------------------------------------------------------------------------------------------------+ +| Week 8(26-07-2020) | Ribbon to `molecular`, tests for `molecular`, animated surfaces. | `Weekly Check-in #8 `__ | ++-----------------------+------------------------------------------------------------------+----------------------------------------------------------------------------------------------------+ +| Week 9(02-08-2021) | Optimized `molecular` with mentors, GSoC blogs to FURY docs. | `Weekly Check-in #9 `__ | ++-----------------------+------------------------------------------------------------------+----------------------------------------------------------------------------------------------------+ +| Week 10(09-08-2021) | Bounding box, `molecular` tutorial, molecular surfaces progress. | `Weekly Check-in #10 `__ | ++-----------------------+------------------------------------------------------------------+----------------------------------------------------------------------------------------------------+ +| Week 11(16-08-2021) | Molecular Surfaces (VDW, SAS) implementation. | `Weekly Check-in #11 `__ | ++-----------------------+------------------------------------------------------------------+----------------------------------------------------------------------------------------------------+ + + + +Detailed weekly tasks and work done can be found +`here `_. diff --git a/v0.10.x/_sources/posts/2021/2021-08-23-gsoc-devmessias-final-report.rst.txt b/v0.10.x/_sources/posts/2021/2021-08-23-gsoc-devmessias-final-report.rst.txt new file mode 100644 index 000000000..25a53e720 --- /dev/null +++ b/v0.10.x/_sources/posts/2021/2021-08-23-gsoc-devmessias-final-report.rst.txt @@ -0,0 +1,392 @@ +Google Summer of Code 2021 - Final Report - Bruno Messias +========================================================= + +.. post:: August 23 2021 + :author: Bruno Messias + :tags: google + :category: gsoc + + +Abstract +-------- + +We have changed some points of my project in the first meeting. +Specifically, we focused the efforts into developing a streaming system +using the WebRTC protocol that could be used in more generic scenarios +than just the network visualization. In addition to that, we have opted +to develop the network visualization for fury as a separated repository +and package available `here `__. The +name Helios was selected for this new network visualization system based +on the Fury rendering pipeline. + +Proposed Objectives +------------------- + +- Create a streaming system (stadia-like) for FURY + + - Should work in a low-bandwidth scenario + - Should allow user interactions and collaboration across the + Internet using a web-browser + +- Helios Network System objectives: + + - Implement the Force-Directed Algorithm with examples + - Implement the ForceAtlas2 algorithm using cugraph with examples + - Implement Minimum-Distortion Embeddings algorithm (PyMDE) and + examples + - Non-blocking network algorithms computation avoiding the GIL using + the Shared Memory approach + - Create the documentation and the actions for the CI + +- Stretch Goals: + + - Create an actor in FURY to draw text efficiently using shaders + - Add support to draw millions of nodes using FURY + - Add support to control the opengl state on FURY + +Objectives Completed +-------------------- + +- .. rubric:: Create a streaming system (stadia-like) for FURY + :name: create-a-streaming-system-stadia-like-for-fury + + To construct the streaming system for my project we have opted to + follow three main properties and behaviors: + + 1. avoid blocking the code execution in the main thread (where the + vtk/fury instance resides) + 2. work inside of a low bandwidth environment + 3. make it easy and cheap to share the rendering result. For example, + using the free version of ``ngrok`` + + To achieve the first property we need to circumvent the GIL and allow + python code to execute in parallel. Using the threading module alone + is not good enough to reach real parallelism as Python calls in the + same process can not execute concurrently. In addition to that, to + achieve better organization it is desirable to define the server + system as an uncoupled module from the rendering pipeline. Therefore, + I have chosen to employ the multiprocessing approach for that. The + second and third property can be only achieved choosing a suitable + protocol for transferring the rendered results to the client. We have + opted to implement two streaming protocols: the MJPEG and the WebRTC. + The latter is more suitable for low-bandwidth scenarios [1]. + + The image below shows a simple representation of the streaming + system. + +.. raw:: html + +
+ ... +
+ + The video below shows how our streaming system works smothly and can + be easily integrated inside of a Jupyter notebook. + +`Video: WebRTC Streaming + +Ngrok `__ + +`Video: WebRTC Streaming + +Jupyter `__ + +*Pull Requests:* \* https://github.com/fury-gl/fury/pull/480 + +- .. rubric:: 2D and 3D marker actor + :name: d-and-3d-marker-actor + + This feature gave FURY the ability to efficiently draw millions of + markers and impostor 3D spheres. This feature was essential for the + development of Helios. This feature work with signed distance fields + (SDFs) you can get more information about how SDFs works here [4] . + + The image below shows 1 million of markers rendered using an Intel + HD graphics 3000. + +.. raw:: html + +
+ +
+ +- .. rubric:: Fine-Tunning the OpenGl State + :name: fine-tunning-the-opengl-state + + Sometimes users may need to have finer control on how OpenGL will + render the actors. This can be useful when they need to create + specialized visualization effects or to improve the performance. + + In this PR I have worked in a feature that allows FURY to control the + OpenGL context created by VTK + + *Pull Request:* + + - https://github.com/fury-gl/fury/pull/432 + +- .. rubric:: Helios Network Visualization Lib: Network Layout + Algorithms + :name: helios-network-visualization-lib-network-layout-algorithms + + **Case 1:** Suppose that you need to monitor a hashtag and build a + social graph. You want to interact with the graph and at the same + time get insights about the structure of the user interactions. To + get those insights you can perform a node embedding using any kind of + network layout algorithm, such as force-directed or minimum + distortion embeddings. + + **Case 2:** Suppose that you are modelling a network dynamic such as + an epidemic spreading or a Kuramoto model. In some of those network + dynamics a node can change the state and the edges related to the + node must be deleted. For example, in an epidemic model a node can + represent a person who died due to a disease. Consequently, the + layout of the network must be recomputed to give better insights. + + In the described cases, if we want a better (UX) and at the same time + a more practical and insightful application of Helios, the employed + layout algorithms should not block any kind of computation in the + main thread. + + In Helios we already have a lib written in C (with a python wrapper) + which performs the force-directed layout algorithm using separated + threads avoiding the GIL problem and consequently avoiding blocking + the main thread. But what about the other open-source network layout + libs available on the internet? Unfortunately, most of those libs + have not been implemented like Helios force-directed methods and + consequently, if we want to update the network layout the Python + interpreter will block the computation and user interaction in your + network visualization. + + My solution for having PyMDE and CuGraph-ForceAtlas not blocking the + main thread was to break the network layout method into two different + types of processes: A and B and communicate both process using the + Shared Memory approach. You can more information about this PR + through my following posts [2], [3]. + +The image below show an example that I made and is available at +https://github.com/fury-gl/helios/blob/main/docs/examples/viz_mde.py + +|image2| *Pull Requests:* + +- **MDE Layout:** https://github.com/fury-gl/helios/pull/6 + +- **CuGraph ForceAtlas2** https://github.com/fury-gl/helios/pull/13 + +- **Force-Directed and MDE improvements** + https://github.com/fury-gl/helios/pull/14 + +- .. rubric:: Helios Network Visualization Lib: Visual Aspects + :name: helios-network-visualization-lib-visual-aspects + +I’ve made several stuffs to give Helios a better visual aspects. One of +them was to give a smooth real-time network layout animations. Because +the layout computations happens into a different process that the +process responsible to render the network was necessary to record the +positions and communicate the state of layout between both process. + +The GIF below shows how the network layout through IPC behaved before +these modification + +.. raw:: html + +
+ +
+ +below, you can see how after those modifications the visual aspect is +better. + +.. raw:: html + +
+ ... +
+ +*Pull Requests:* + +- **OpenGL SuperActors:** https://github.com/fury-gl/helios/pull/1 + +- **Fixed the flickering effect** + https://github.com/fury-gl/helios/pull/10 + +- **Improvements in the network node visual aspects** + https://github.com/fury-gl/helios/pull/15 + +- **Smooth animations when using IPC layouts** + https://github.com/fury-gl/helios/pull/17 + +- .. rubric:: Helios Network Visualization Lib: CI and Documentation + :name: helios-network-visualization-lib-ci-and-documentation + +Because Helios was an project that begins in my GSoC project It was +necessary to create the documentation, hosting and more. Now we have a +online documentation available at https://heliosnetwork.io/ although the +documentation still need some improvements. + +The Helios Logo which was developed by +Filipi Nascimento. + +.. raw:: html + + Helios Network Logo + +*Pull Requests:* + +- **CI and pytests:** https://github.com/fury-gl/helios/pull/5, + https://github.com/fury-gl/helios/pull/20 + +- **Helios Logo, Sphinx Gallery and API documentation** + https://github.com/fury-gl/helios/pull/18 + +- **Documentation improvements:** + https://github.com/fury-gl/helios/pull/8 + +- .. rubric:: Objectives in Progress + :name: objectives-in-progress + +- .. rubric:: Draw texts on FURY and Helios + :name: draw-texts-on-fury-and-helios + + This two PRs allows FURY and Helios to draw millions of characters in + VTK windows instance with low computational resources consumptions. I + still working on that, finishing the SDF font rendering which the + theory behinds was developed here [5]. + + *Pull Requests:* + + - https://github.com/fury-gl/helios/pull/24 + + - https://github.com/fury-gl/fury/pull/489 + + .. raw:: html + +
+ ... +
+ +- .. rubric:: GSoC weekly Blogs + :name: gsoc-weekly-blogs + + Weekly blogs were added to the FURY Website. + + *Pull Requests:* + + - **First Evaluation:** https://github.com/fury-gl/fury/pull/476 + - **Second Evaluation:** TBD + +Timeline +-------- + ++-----------------+-----------------------------+-----------------------------+ +| Date | Description | Blog Link | ++=================+=============================+=============================+ +| Week 1 | Welcome to my weekly Blogs! | `Weekly Check-in | +| (08-06-2021) | | #1 `__ | ++-----------------+-----------------------------+-----------------------------+ +| Week 2 | Post #1: A Stadia-like | `Weekly Check-in | +| (14-06-2021) | system for data | # | +| | visualization | 2 `__ | ++-----------------+-----------------------------+-----------------------------+ +| Week 3 | 2d and 3d fake impostors | `Weekly Check-in | +| (21-06-2021) | marker; fine-tunning | #3 `__ | +| | streaming system; | | +| | first-version of helios: | | +| | the network visualization | | +| | lib for helios | | ++-----------------+-----------------------------+-----------------------------+ +| Week 4 | Post #2: SOLID, monkey | `Weekly Check-in | +| (28-06-2020) | patching a python issue and | #4 | +| | network layouts through | `__ | ++-----------------+-----------------------------+-----------------------------+ +| Week 5 | Code refactoring; 2d | `Weekly Check-in | +| (05-07-2021) | network layouts for Helios; | #5 `__ | +| | algorithm using the IPC | | +| | approach | | ++-----------------+-----------------------------+-----------------------------+ +| Week 6 | Post #3: Network layout | `Weekly Check-in | +| (12-07-2020) | algorithms using IPC | #6 `__ | ++-----------------+-----------------------------+-----------------------------+ +| Week 7 | Helios IPC network layout | `Weekly Check-in | +| (19-07-2020) | algorithms support for | #7 `__ | +| | ForceAtlas2 network layout | | +| | using cugraph/cuda | | ++-----------------+-----------------------------+-----------------------------+ +| Week 8 | Helios CI, Helios | `Weekly Check-in | +| (26-07-2020) | documentation | #8 `__ | ++-----------------+-----------------------------+-----------------------------+ +| Week 9 | Helios documentation; | `Weekly Check-in | +| (02-08-2020) | improved the examples and | #9 `__ | +| | some improvements in the | | +| | compatibility removing some | | +| | dependencies | | ++-----------------+-----------------------------+-----------------------------+ +| Week 10 | Helios documentation | `Weekly Check-in | +| (09-08-2020) | improvements; found and | #10 `__ | +| | improved the memory | | +| | management system for the | | +| | network layout algorithms | | +| | using IPC | | ++-----------------+-----------------------------+-----------------------------+ +| Week 11 | Created a PR that allows | `Weekly Check-in | +| (16-08-2020) | FURY to draw hundred of | #11 `__ | +| | fixed the flickering effect | | +| | on the streaming system; | | +| | helios node labels feature; | | +| | finalizing remaining PRs | | ++-----------------+-----------------------------+-----------------------------+ + +Detailed weekly tasks, progress and work done can be found +`here `__. + +References +~~~~~~~~~~ + +[1] ( Python GSoC - Post #1 - A Stadia-like system for data +visualization - demvessias s Blog, n.d.; +https://blogs.python-gsoc.org/en/demvessiass-blog/post-1-a-stadia-like-system-for-data-visualization/ + +[2] Python GSoC - Post #2: SOLID, monkey patching a python issue and +network layouts through WebRTC - demvessias s Blog, n.d.; +https://blogs.python-gsoc.org/en/demvessiass-blog/post-2-solid-monkey-patching-a-python-issue-and-network-layouts-through-webrtc/ + +[3] Python GSoC - Post #3: Network layout algorithms using IPC - +demvessias s Blog, +n.d.)https://blogs.python-gsoc.org/en/demvessiass-blog/post-3-network-layout-algorithms-using-ipc/ + +[4] Rougier, N.P., 2018. An open access book on Python, OpenGL and +Scientific Visualization [WWW Document]. An open access book on Python, +OpenGL and Scientific Visualization. URL +https://github.com/rougier/python-opengl (accessed 8.21.21). + +[5] Green, C., 2007. Improved alpha-tested magnification for vector +textures and special effects, in: ACM SIGGRAPH 2007 Courses on - +SIGGRAPH ’07. Presented at the ACM SIGGRAPH 2007 courses, ACM Press, San +Diego, California, p. 9. https://doi.org/10.1145/1281500.1281665 + +.. |image2| image:: https://user-images.githubusercontent.com/6979335/125310065-a3a9f480-e308-11eb-98d9-0ff5406a0e96.gif diff --git a/v0.10.x/_sources/posts/2021/2021-09-08-gsoc-devmessias-10.rst.txt b/v0.10.x/_sources/posts/2021/2021-09-08-gsoc-devmessias-10.rst.txt new file mode 100644 index 000000000..b0734b086 --- /dev/null +++ b/v0.10.x/_sources/posts/2021/2021-09-08-gsoc-devmessias-10.rst.txt @@ -0,0 +1,52 @@ +Week #10: SDF Fonts +=================== + +.. post:: August 09 2021 + :author: Bruno Messias + :tags: google + :category: gsoc + + +What did I do this week? +------------------------ + +FURY/Helios +^^^^^^^^^^^ + +- `PR fury-gl/helios#22 + : `__ Helios Documentation + Improvements. +- `PR fury-gl/helios#23: `__ + A PR that makes helios IPCLayout system compatible with Windows. + +FURY +^^^^ + +- `PR fury-gl/fury#484: I've found and fixed a bug in FURY time + management system `__ +- `PR fury-gl/fury#437: `__ + + - Fixed the tests on Windows + - Improve the streaming memory management system for IPC + communication + +- I've developing a feature that will allows FURY to draw hundreds + thousands of labels using texture maps and signed distance functions. + Until now I've a sketch that at least is able to draw the labels + using the markers billboards and bitmap fonts |image1| +- `PR fury-gl/fury#432: `__ + minor improvements +- `PR #474 `__ Helped to + review this PR + +Did I get stuck anywhere? +------------------------- + +I did not get stuck this week. + +What is coming up next? +----------------------- + +I’ll discuss that with my mentors tomorrow. + +.. |image1| image:: https://user-images.githubusercontent.com/6979335/128761833-53f53e2c-5bc0-4ff3-93c4-0ad01dc7d8eb.png diff --git a/v0.10.x/_sources/posts/2021/2021-16-08-gsoc-devmessias-11.rst.txt b/v0.10.x/_sources/posts/2021/2021-16-08-gsoc-devmessias-11.rst.txt new file mode 100644 index 000000000..29a6f67b6 --- /dev/null +++ b/v0.10.x/_sources/posts/2021/2021-16-08-gsoc-devmessias-11.rst.txt @@ -0,0 +1,85 @@ +Week #11: Removing the flickering effect +======================================== + +.. post:: August 16 2021 + :author: Bruno Messias + :tags: google + :category: gsoc + +What did I do this week? +------------------------ + +FURY +^^^^ + +- `PR fury-gl/fury#489: `__ + + This PR give to FURY three + pre-built texture maps using different fonts. However, is quite easy + to create new fonts to be used in a visualization. +| It's was quite hard to develop the shader code and find the correct + positions of the texture maps to be used in the shader. Because we + used the freetype-py to generate the texture and packing the glyps. + However, the lib has some examples with bugs. But fortunelly, now + everything is woking on FURY. I've also created two different examples + to show how this PR works. + + The first example, viz_huge_amount_of_labels.py, shows that the user can + draw hundreds of thousands of characters. + + + |image2| + + The second example, viz_billboad_labels.py, shows the different behaviors of the label actor. In addition, presents + to the user how to create a new texture atlas font to be used across different visualizations. + +- `PR fury-gl/fury#437: `__ + + - Fix: avoid multiple OpenGl context on windows using asyncio + The streaming system must be generic, but opengl and vtk behaves in uniques ways in each Operating System. Thus, can be tricky + to have the same behavior acrros different OS. One hard stuff that we founded is that was not possible to use my + TimeIntervals objects (implemented with threading module) with vtk. The reason for this impossibility is because we can't use + vtk in windows in different threads. But fortunely, moving from the threading (multithreading) to the asyncio approcach (concurrency) + have fixed this issue and now the streaming system is ready to be used anywhere. + + - Flickering: + + Finally, I could found the cause of the flickering effect on the streaming system. + This flickering was appearing only when the streaming was created using the Widget object. + The cause seems to be a bug or a strange behavior from vtk. + Calling iren.MouseWheelForwardEvent() or iren.MouseWheelBackwardEvent() + inside of a thread without invoking the + Start method from a vtk instance produces a memory corruption. + Fortunately, I could fix this behavior and now the streaming system is + working without this glitch effect. + + +FURY/Helios +^^^^^^^^^^^ + +- `PR fury-gl/helios#24 + : `__ + +This uses the +`PRfury-gl/fury#489: `__ to +give the network label feature to helios. Is possible to draw node +labels, update the colors, change the positions at runtime. In addition, +when a network layout algorithm is running this will automatically +update the node labels positions to follow the nodes across the screen. + +|image1| + +- `PR fury-gl/helios#23: + Merged. `__ + +This PR granted compatibility between IPC Layouts and Windows. Besides +that , now is quite easier to create new network layouts using inter +process communication + +Did I get stuck anywhere? +------------------------- + +I did not get stuck this week. + +.. |image1| image:: https://user-images.githubusercontent.com/6979335/129642582-fc6785d8-0e4f-4fdd-81f4-b2552e1ff7c7.png +.. |image2| image:: https://user-images.githubusercontent.com/6979335/129643743-6cb12c06-3415-4a02-ba43-ccc97003b02d.png diff --git a/v0.10.x/_sources/posts/2022/2022-01-31-release-announcement.rst.txt b/v0.10.x/_sources/posts/2022/2022-01-31-release-announcement.rst.txt new file mode 100644 index 000000000..3d1d7429c --- /dev/null +++ b/v0.10.x/_sources/posts/2022/2022-01-31-release-announcement.rst.txt @@ -0,0 +1,48 @@ +FURY 0.8.0 Released +=================== + +.. post:: January 31 2022 + :author: skoudoro + :tags: fury + :category: release + + +The FURY project is happy to announce the release of FURY 0.8.0! +FURY is a free and open source software library for scientific visualization and 3D animations. + +You can show your support by `adding a star `_ on FURY github project. + +This Release is mainly a maintenance release. The **major highlights** of this release are: + +.. include:: ../../release_notes/releasev0.8.0.rst + :start-after: -------------- + :end-before: Details + +.. note:: The complete release notes are available :ref:`here ` + +**To upgrade or install FURY** + +Run the following command in your terminal:: + + pip install --upgrade fury + +or:: + + conda install -c conda-forge fury + + +**Questions or suggestions?** + +For any questions go to http://fury.gl, or send an e-mail to fury@python.org +We can also join our `discord community `_ + +We would like to thanks to :ref:`all contributors ` for this release: + +.. include:: ../../release_notes/releasev0.8.0.rst + :start-after: commits. + :end-before: We closed + + +On behalf of the :ref:`FURY developers `, + +Serge K. diff --git a/v0.10.x/_sources/posts/2022/2022-02-01-gsoc.rst.txt b/v0.10.x/_sources/posts/2022/2022-02-01-gsoc.rst.txt new file mode 100644 index 000000000..eef122c44 --- /dev/null +++ b/v0.10.x/_sources/posts/2022/2022-02-01-gsoc.rst.txt @@ -0,0 +1,20 @@ +Contribute to FURY via Google Summer of Code 2022 +================================================= + +.. post:: February 1 2022 + :author: skoudoro + :tags: google + :category: gsoc + + +FURY is participating in the `Google Summer of Code 2022 `_ under the umbrella of the `Python Software Foundation `_. + +FURY is a free and open source software library for scientific visualization and 3D animations. FURY contains many tools for visualizing a series of scientific data including graph and imaging data. + +A list of project ideas and application info is on our `GitHub Wiki `_. + +If you are interested in talking to us about projects, applications join us to our `discord community `_ or drop us a line on our `mailing list `_. + +Be part of our community and Enjoy your summer of code! + +Serge K. diff --git a/v0.10.x/_sources/posts/2022/2022-05-23-first-post-mohamed.rst.txt b/v0.10.x/_sources/posts/2022/2022-05-23-first-post-mohamed.rst.txt new file mode 100644 index 000000000..8a8d13bda --- /dev/null +++ b/v0.10.x/_sources/posts/2022/2022-05-23-first-post-mohamed.rst.txt @@ -0,0 +1,92 @@ +My journey till getting accepted into GSoC22 +============================================ + + +.. post:: May 23 2022 + :author: Mohamed Abouagour + :tags: google + :category: gsoc + +A Little About Myself +~~~~~~~~~~~~~~~~~~~~~ + +My name is Mohamed and I'm from Egypt. I am pursuing a Bachelor of Engineering in Computer Engineering and Automatic Control (expected: 2023), Tanta University, Egypt. + +I've been around computers since 2008 when I had my first PC with 128MB RAM and ran on Windows XP (that's almost all I could remember about it). + +Around 2013, I had some questions about how games are made and how to make them myself! +There was no one to answer these questions for me. + +My english wasn't any good and the game development arabic community was very hard to find on the internet. But eventually, I came across a forum with some people speaking about some stuff such as game engines, 3D models, textures, animations, and a lot of fun stuff. That made sense back then and answered some of my questions. Then It was time to get involved with this amazing community. I was lucky enough to start with 3ds Max 2009 Edition, with that little view cube begging me to touch it. It was just love at first sight. + +I learned enough to model a basic house with no interior or a low poly human face. + +I was very curious about these game engines. Back then, the top three game engines available for the public were `CryEngine 3 `_, `UDK `_, and `Unity `_. + +I was advised to use CryEngine 3 since it required no coding experience to use it. I started designing and texturing terrains and adding 3D models (I remember adding a pyramid and had a hard time scaling it down). + + +My first coding experience +~~~~~~~~~~~~~~~~~~~~~~~~~~ +It started with C programming language, which I came across while taking Harvard's CS50. I then used it in competitive programming as my primary language. + +When I heard about OpenGL API for the first time from a senior and that it is being used to develop game engines, I started learning it along with GLSL. + +And it finally hit me: It is all math! + +I then started practicing pipelines, lighting models such as Blinn and Blinn-Phong models, cameras, texturing, fog, skybox, shadows, etc... + + +Developing a 3D game +~~~~~~~~~~~~~~~~~~~~ +In the Graphics course, OpenGL was being taught to us using python and there was a course project! + +I started preparing my notes and the shaders I wrote during that summer, only for the Professor to restrict us to use OpenGL v1.0 and only use PyOpenGL and Pygame. + +So, no Numpy, no PyGLM, fixed pipelines, no custom shaders, and each vertex had to be sent individually to the GPU. + +At first, I got disappointed, but while developing the game, I had a lot of optimization challenges that made me have fun figuring out how to still make the 3D game I've always wanted to make! + +I searched on GitHub for similar projects to the one I'm trying to make and did not find any 3D FPS game using this version of OpenGL (at least not listed publicly). + +I ended up implementing almost everything from scratch. + +Real-world physics inspired the physics of the game. This means that I have collected data about walking speed, running speed, initial jumping velocity, and gravity. Even the sound Sound intensity is inversely proportional to the square of the distance between the source and the player. + +I used Interpolation (bilinear interpolation) to interpolate the terrain's height (y) at any given (x-z) coordinates so that entities can move on 64*64 pixels height map based terrain smoothly to reduce the number of triangles. I also implemented for this game an animation system that used obj sequence animations, then optimized it to load faster, and consume 95% less disk space compared to the non-optimized form. + +Source code of the game: `MummyIsland `_ + + + + + +My journey to GSoC22 +~~~~~~~~~~~~~~~~~~~~ +I first knew about GSoC from a friend last year. I then went through the organization's list. There were a lot of familiar names that I recognized such as Anki, Godot, Blender. + +Then I glanced at the Python software foundation. I had to go in and scroll through the sub-organizations only to come across FURY. The luminous horse got my attention. I felt the connection right away. + +I went through the docs of both FURY and VTK. + +I tried to contribute back then by adding the option to use the FXAA anti-aliasing algorithm for the window (I didn't notice it has already been implemented as a method for the window). + +So instead, I implemented the first mentioned shader in the GSoC 21's project idea “**Add new shader effects**” (`the fire shader `_) in GLSL using Gaussian noise. + +The next step was to implement the shader to make it work with FURY actors but then I knew I'm having a mandatory training required by the University last summer. I was disappointed, and I decided to postpone until next year's GSoC. + +This year when the accepted organizations were announced, I didn't bother to go through the list since I knew exactly which organization I'm going to apply for. So I just went directly to read the Ideas list for FURY. + + +The keyframe animation system was the perfect match! I have been around keyframes for half of my life to even guess the required features before I read them! I then started to contribute and one contribution led to the other one. + +**Code contributions:** + +1. https://github.com/fury-gl/fury/pull/552 +2. https://github.com/fury-gl/fury/pull/555 + + +The day I got accepted +~~~~~~~~~~~~~~~~~~~~~~ +I made it my mission for the day to keep watching the email for any changes. When It got 8:00 pm in the Cairo timezone, I didn't see any changes. So I started searching for any news whatsoever and I couldn't find any. +The GSoC dashboard doesn't say anything (story of my life. I didn't even get any promotions or spam mails that day). That's when I gave up. But, something doesn't feel right! Right? I went again to check the dashboard to find that my proposal got accepted. I couldn't even believe it. I would better not jump to conclusions and wait for the official email before celebrating. Shortly after, I received the official email. It was a whole new feeling I had never experienced ever before! I reached a whole new level of happiness. diff --git a/v0.10.x/_sources/posts/2022/2022-05-24-my-journey-to-gsoc-2022-shivam.rst.txt b/v0.10.x/_sources/posts/2022/2022-05-24-my-journey-to-gsoc-2022-shivam.rst.txt new file mode 100644 index 000000000..6e9c6a0dc --- /dev/null +++ b/v0.10.x/_sources/posts/2022/2022-05-24-my-journey-to-gsoc-2022-shivam.rst.txt @@ -0,0 +1,51 @@ +My Journey to GSoC 2022 +======================= + +.. post:: May 24 2022 + :author: Shivam Sahu + :tags: google + :category: gsoc + + +About Myself +~~~~~~~~~~~~ + +Hi! I'm Shivam, currently pursuing my bachelor's (expected 2024) in Production and Industrial engineering from the Indian Institute of Technology (IIT) Roorkee. + +I was introduced to the C programming language through the Introduction to programming course in my first year of college. I always liked computers, and I was overwhelmed by printing "hello world" in the terminal. The course continued to teach us data structures and algorithms. It was a lot of fun competing with friends over a programming question. I learned python on my own and did a lot of projects. After learning basic programming, I participated in many hackathons and won some, but lost a lot. Coding was enjoyable, and I knew this was what I wanted to do for the rest of my life. +In my second semester, I learned about open-source, git, and GitHub. I came across some computer graphics enthusiasts in my college; they told me that they created a 2D game engine on their own using OpenGL. This gave me enough motivation to learn OpenGL and basic computer graphics. + +Intro to Open-Source and GSoC +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In October 2021, I participated in Hactoberfest and completed it successfully. I learned a lot about Free and Open Source Software during this time. I heard about GSoC around this time from one of my seniors and asked him about the program. + +I went through the previous year's accepted organizations list and shortlisted 2-3 organizations. I started contributing to a few projects based on android and kotlin, but I lost interest after some time. +It was about December, and I hadn't chosen any organization yet. + +I heard about FURY from one of my seniors. I started looking at its docs. Picked up some books from the library to brush up on my concepts of computer graphics. The documentation of FURY is remarkable. I created my `first pull request `_ by improving one of the tutorials, and It got merged in a few days. + +I started looking at the source code of FURY and tried to understand it again. I read the `API reference` part of FURY docs this time along with the documentation of `VTK`. I also tried to solve some of the open issues. I created a few pull requests for the same. My first contribution was in the fury `primitive` class, I created a sphere primitive (inspired by the sphere in Blender). + +I started looking at bugs and improvements that can be made to the source code and created PRs for the same. During this time I was also learning how computer graphics work from the `UCSC lectures `_ & `OpenGL by Victor Gordon `_. + +After the accepted organizations were announced, I was so happy that FURY got selected this year for GSoC and went straight to the Ideas list. The first project idea was `glTF Integration`. I heard about the `glTF` file format before but didn't know how it works. So I went straight through the reference materials provided on the `wiki `_. I read a lot of documentation by the Khronos group. I also tried to implement a basic glTF loader during this time using VTK's built-in `glTFReader`. + +I also liked the Improve UI drawing project idea (I had a basic understanding of line drawing algorithms and rasterizations at that time) and thought I'll make a proposal for that too. After completing my proposal for glTF integration I started my research on this one too. + +I started writing the proposal early so that I could get my proposal reviewed at least once with the project mentors. I almost forgot the fact that I had my end-term examinations at hand (Somehow I managed to pass all of my courses), I kept contributing to the project till the end of April 2022. + +Code contributions: + +1. [https://github.com/fury-gl/fury/pull/520] +2. [https://github.com/fury-gl/fury/pull/525] +3. [https://github.com/fury-gl/fury/pull/533] +4. [https://github.com/fury-gl/fury/pull/547] +5. [https://github.com/fury-gl/fury/pull/556] +6. [https://github.com/fury-gl/fury/pull/559] + +The Day +~~~~~~~ +May 18: I was a bit anxious since on May 18th the GSoC website was showing my proposal for glTF integration had been rejected. (p.s. maybe it was a bug of some sort that they fixed later on). + +May 20: I woke up very early in the morning and started checking the contributor's profile. I kept checking for new emails but didn't receive any emails that day. "The result will be announced at 11:30 PM, isn't it? " My dad said, It was 8:00 AM Indian Standard Time. I called my friends in the night to join me on discord, I was talking to them and refreshing the GSoC site at the same time. One of my friends shouted that he got selected in NumFocus. I refreshed the page again, my proposal for glTF Integration was accepted. I can't express what I felt at that moment. I told my friends and my parents, they were happy for me and I got a lot of blessings :). I received an official email the next day. diff --git a/v0.10.x/_sources/posts/2022/2022-05-25-pre-gsoc-journey-praneeth.rst.txt b/v0.10.x/_sources/posts/2022/2022-05-25-pre-gsoc-journey-praneeth.rst.txt new file mode 100644 index 000000000..e50909583 --- /dev/null +++ b/v0.10.x/_sources/posts/2022/2022-05-25-pre-gsoc-journey-praneeth.rst.txt @@ -0,0 +1,44 @@ +Pre-GSoC Journey +================= + +.. post:: May 25 2022 + :author: Praneeth Shetty + :tags: google + :category: gsoc + + +The Beginning of Programming +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Hello Guys!! I am Praneeth Shetty, currently pursuing Bachelor of Engineering in Computer Engineering, and here is my journey from where I started to the selection into GSoC22. + +My programming journey started way back in 7th std, where we had a subject called Information Technology in which the last two lessons were based on HTML and Javascript. I loved to create simple pages in HTML but was struggling to learn Javascript as it felt a bit complex at the start. +I would practice these programs in our computer lab whenever we would have our practical lab (once or twice a month). +Next year I received a laptop from my cousin brother(which I still use). While setting up the things he started enquiring about my academics and asked me to create an HTML code. He was happy to see that I could do that so to explain to me the usage of javascript he created a small program. He executed it and gave it to me, where it was written “Enter your Name?” I typed Praneeth and pressed Enter. A new page was loaded with a Text stating “Hello Praneeth!! How are you??” I was amazed to see the output. How could that machine know me and greet me?? Is Javascript such a powerful tool?? Can I make the computer talk using Javascript?? These questions flooded my mind. That day I realized that, If I had a good command of Javascript, I could control the whole computer and can make it do whatever I want. Because of this I started giving more attention to Javascript. + + +Interest in Game Development and Animation +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Around one and a half years after this, I was able to code basic javascript programs. In my vacation while I was searching for a gameplay video on Youtube, A video titled “How to make a Game” by Brackeys grabbed my attention and made me click on it. I watched the whole video but was unable to understand the most of the things ie transform, rigidbody, mesh, collider etc. But it generated an internal feeling that I can also create a game. I tried to replicate the process in the video but when I went on to the Official Website of Unity(Game Engine) the whole package size was around 1.5 Gigabytes which was a huge sum at that time(the time when 2G ruled and 100 Megabytes was for 10 INR). So I was unable to work on it. But still, some unknown inspiration motivated me to watch the whole “How to make a Game” playlist of 10 videos. As I moved ahead some concepts were getting cleared and I had a surface level idea of how to make things work in game(Not how games actually worked). As I was pretty much immersed into game development my feeds started showing “How to create a 3D character”, “How to Animate” videos which led me to discover Blender, 3Ds Max, etc. animation software. +I downloaded Blender as it was a lightweight free package and started messing around with things in it. But after a few months Blender made some remarkable changes and brought version 2.80 which required a few system specifications which my laptop didn't satisfied. +By this time I used to spend some extra hours in my College to learn Unity and created my first Game which was an exact copy of the Brackeys Game Series. I was very happy to successfully create a game all on my own and used to think what all new features can be added to it. + + +Intro to Opensource +~~~~~~~~~~~~~~~~~~~~ + +While finding alternatives to Unity and Blender, I found a lightweight software called Godot and I was surprised to see the whole game engine was just around 100 Megabytes(which compared to Unity and Unreal is 10/20 times smaller). I tried searching about How and Why is Godot so Small and one of the reasons I found was, it is an open source software. I had heard this term before while working with blender but still was unable to clearly understand what it is. Another answer I received is an extended application of the previous one which stated most features are implemented from scratch by various contributors in open source software whereas in other big software libraries are used a lot for very minimalistic features too which make it dependent and bulky. Around this time I had also switched to Python and was working on some mini projects and games using it. It also helped me in working with Godot, which has its own language called GDScript which resembles python. + + +GSoC - 21 +~~~~~~~~~~ + +As I was drowning in the oceans of Open Source, I read some blogs which mentioned some of the programs and events related to it viz. Google Summer of Code (GSoC), Hacktoberfest, GirlScript Summer of Code(GSSoC), etc. +I was excited to participate in these events but wasn’t getting proper guidance. I used to watch interviews and best practices for these events due to which I found out that for GSoC we have to select the organizations then apply and this would be the basic flow of the program. So taking this into consideration I started searching for organizations on GSoC archives. Firstly I was looking for any Javascript related project as I had a better command on it than python and there I found out about p5.js which was a creative coding library. I forked their repo, cloned it, and then tried to build it on my local machine but after many attempts I was still unsuccessful to build it locally. I raised a question in their community and also mailed an old GSoC student but they too were unable to solve the query. This disappointed me a lot and kind of I was going to end my opensource journey here, but just thought of giving it a try again. While searching through the organizations I found lots of known projects regarding which I had no idea that those too were open source. While searching I found Python Software Foundation in the organization list and thought why not to consider python. After looking into the organization I found out that PSF was an umbrella project for many sub projects in which FURY(Free Unified Rendering in pYthon) suited me the most because I was a beginner and didn’t had any idea regarding the data analysis, API formation and the other stuff. But because of prior experience and interest in Game Dev, I was comfortable with FURY. I again forked, cloned and tried to execute the first tutorial on it, it took few minutes to run then few more minutes to download some required files and then a black box appeared but with nothing on it, I thought there would be some error with something so re executed it and it took few minutes and the first Earth Animation tutorial was successfully executed. I was fascinated by viewing the visuals of the Earth with the orbiting moon and the satellite animation (I had doubts whether my laptop will be able to handle these computations or not, but till now It hasn’t proved me wrong in most of the cases). I checked the code then and within 200 lines of code all this was all possible. That made me understand the real power of FURY. After this I checked for some of the good first issues but as it was GSoC period most of the issues were under process so I tried to learn more about the tutorials and the code. There I found a few documentation errors which I fixed as my first PR. I also pointed out some issues which I faced while working with FURY. FURY has a great discord community which engages newbies and solves most of their issues. After two months GSoC Contributors Applications started and I also tried to apply for the same. I created a proposal on Improving the UI system but due to lack of experience and as I was unable to prove my coding skills, I was rejected. But this didn’t disengage me from FURY. I loved the simplicity by which each part was created. Then as time passed I worked on some of the issues and created some more PRs. + + +GSoC - 22 +~~~~~~~~~~ + +Again this year GSoC Started with new rules, new energy and with more enthusiasm I too prepared to participate in it. Five new ideas were posted for GSoC in which I again chose the UI improvement as I had a good understanding of the existing UI system in FURY. Last year's experience helped me a lot in creating the proposal. This time I was also prepared(compared to last time) as I had made some contributions and also had spent time on the code base to understand it. Days passed and lastly the result day arrived, anxiety was at its peak. I had set an alarm to remind me to keep checking the mail for the result, refreshing and changing tabs. Exactly at 11:32 PM Indian Standard Time, a mail dropped with the subject “Congratulations, your proposal with Python Software Foundation has been accepted!” and my happiness had no bound. diff --git a/v0.10.x/_sources/posts/2022/2022-06-08-week-1-mohamed.rst.txt b/v0.10.x/_sources/posts/2022/2022-06-08-week-1-mohamed.rst.txt new file mode 100644 index 000000000..b9abdf0de --- /dev/null +++ b/v0.10.x/_sources/posts/2022/2022-06-08-week-1-mohamed.rst.txt @@ -0,0 +1,46 @@ +Week 1: Implementing a basic Keyframe animation API +=================================================== + +.. post:: June 19 2022 + :author: Mohamed Abouagour + :tags: google + :category: gsoc + + +What did you do during the Community Bonding Period? +---------------------------------------------------- + +During the community bonding period, we had weekly meetings in which I got to know the mentors better and bonded with Shivam and Praneeth, my fellow contributors. +We talked about the importance of open-source contribution and discussed scientific visualization, how important it is and how it differs from game engines despite having some similarities. +We also discussed how important the code review is and how to do a proper code review. + + +What did you do this week? +-------------------------- + +I continued implementing the `Timeline` class. Added some functionalities according to what we discussed in the weekly meeting, such as handling Fury Actors, adding, removing, translating, scaling them according to the keyframes. Then made two tutorials for it with simple UI to control the playback of the animation. + + .. raw:: html + + + + +Reviewed Bruno's PR `#424`_ as Filipi advised to help me figure out how to change uniforms' values during runtime. I found it straightforward. I also found a similar method already used in some tutorials and experiments to set the time uniform, which is based on the same idea. They both are using shaders callback functions. +Going through the VTK's documentations, I found a more efficient way to do this. It's newly implemented in VTK 9, does not require callbacks, and is easy to use on individual actors. I had to verify first that Fury does not support an older version of VTK and it does not. I tested it and ran into some issues so As Filip instructed I don't waste a lot of time with uniforms so I postponed it for the next week. + +Also, when I was attending Shivam's meeting, he showed us a smooth glTF model which differed from the last time I saw it. When I asked him he said he applied the normal. Him saying that reminded me of how we can use normals to smooth shade a shapes. I applied this trick to the sphere actor in this PR `#604`_ and worked as expected. + + +What is coming up next week? +---------------------------- + +If the implemented `Timeline` is good to go, I will write the associated tests, finish up any missing methods, and document it properly. +I will probably continue implementing the other interpolation methods as well. + +Did you get stuck anywhere? +--------------------------- + +I got stuck changing the color of some actors. + +.. _`#424`: https://github.com/fury-gl/fury/pull/424 +.. _`#604`: https://github.com/fury-gl/fury/pull/604 diff --git a/v0.10.x/_sources/posts/2022/2022-06-08-week-1-praneeth.rst.txt b/v0.10.x/_sources/posts/2022/2022-06-08-week-1-praneeth.rst.txt new file mode 100644 index 000000000..cc9a8ce4e --- /dev/null +++ b/v0.10.x/_sources/posts/2022/2022-06-08-week-1-praneeth.rst.txt @@ -0,0 +1,51 @@ +============================================== +Week 1 - Laying the Foundation of DrawPanel UI +============================================== + +.. post:: June 8 2022 + :author: Praneeth Shetty + :tags: google + :category: gsoc + +This week we started with our first technical meeting in which the weekly tasks were assigned. So I had to start with some background or canvas and draw a line using mouse clicks. + + +What did you do this week? +-------------------------- + +I started with a simple ``Panel2D`` (which is basically a movable rectangle on which we can add other UI elements) as a background and then assigned its mouse click callback to print “**Clicked!**” to verify the event triggering. + +Then I modified the event callback to create a ``Rectangle2D`` at that current mouse position(Now you would ask, Why ``Rectangle2D``?? We wanted to change the width of the line, which wasn't possible with the regular line). This would create a rectangle at that point but it had size. +So I had to then calculate the distance between the first point where the mouse was clicked and the current position to resize it accordingly. + +.. image:: https://user-images.githubusercontent.com/64432063/174661567-76251ce9-380f-4a41-a572-65865d028a9c.gif + :width: 400 + +This thing creates a Rectangle, not a line. So I had to think of some other approach. +The first thing that came to my mind was to keep the width of the rectangle constant and apply some rotation to the rectangle according to the mouse position and this worked! + +.. image:: https://user-images.githubusercontent.com/64432063/174661632-98e1c4ec-31a2-4c4d-8e52-7bf2a47592c7.gif + :width: 400 + +As previously we created an interactive rectangle(unintentionally), I thought it would be great if I could add different modes for creating different shapes(ie. line, rectangle, circle as these shapes already existed in the UI System). + +Considering this I implemented a class to create and manage these shapes and a panel to select which shape is to be drawn along with a ``TextBlock2D`` to show the current mode. + +``DrawPanel UI``: + +https://github.com/fury-gl/fury/pull/599 + +.. image:: https://user-images.githubusercontent.com/64432063/174661680-8a5120ff-ec88-4739-945b-b87074f9742b.gif + :width: 500 + :align: center + + +Did you get stuck anywhere? +--------------------------- +I was facing issues with implementing the rotation. I scanned the utils to find some method to do the same but there wasn't any for ``Actor2D``. Then I read some docs and tried out various functions. +At last, I decided to implement it by the most general method which is to calculate the new rotated points by multiplying them with the rotation matrix and that seemed fine for now!! + + +What is coming up next? +----------------------- +Deletion of the shapes is to be implemented along with tests and tutorials. diff --git a/v0.10.x/_sources/posts/2022/2022-06-15-week-2-praneeth.rst.txt b/v0.10.x/_sources/posts/2022/2022-06-15-week-2-praneeth.rst.txt new file mode 100644 index 000000000..1bb2fd0e3 --- /dev/null +++ b/v0.10.x/_sources/posts/2022/2022-06-15-week-2-praneeth.rst.txt @@ -0,0 +1,34 @@ +=============================== +Week 2 - Improving DrawPanel UI +=============================== + +.. post:: June 15 2022 + :author: Praneeth Shetty + :tags: google + :category: gsoc + + +What did you do this week? +-------------------------- +This week I had to refactor and make my code cleaner along with some bug fixing, I started by adding tests and tutorials so that my changes could be tested by everyone. Then I separated the mode for *selection* so that it would be easy to select an individual element and work along with it. Once the selection mode was complete I started with the *deletion* of the elements. + +Now, as we have various modes the question arises, How do we know which mode is currently active and how would users know it?? For this, I took references from some other similar applications and came up with an idea to toggle the icon of the selected mode whenever the mode is selected/deselected as we had individual buttons with an icon for each mode. + +https://github.com/fury-gl/fury/pull/599 + +.. image:: https://user-images.githubusercontent.com/64432063/174710174-87604e78-e563-458d-8db7-28941301b02c.gif + :width: 300 + :height: 300 + :align: center + +Along with this I also started to learn how to access key events so that in near future some keyboard shortcuts can be added. + + +Did you get stuck anywhere? +--------------------------- +No, Everything went well. + + +What is coming up next? +----------------------- +In the current version of the DrawPanel, the shapes can be created and translated beyond the canvas boundaries, so we have to clamp the positions according to the canvas. diff --git a/v0.10.x/_sources/posts/2022/2022-06-20-week1-shivam.rst.txt b/v0.10.x/_sources/posts/2022/2022-06-20-week1-shivam.rst.txt new file mode 100644 index 000000000..8b1db4bd1 --- /dev/null +++ b/v0.10.x/_sources/posts/2022/2022-06-20-week1-shivam.rst.txt @@ -0,0 +1,53 @@ +Week 1 - A Basic glTF Importer +============================== + +.. post:: June 20 2022 + :author: Shivam Anand + :tags: google + :category: gsoc + + +What did you do during the Community Bonding Period? +---------------------------------------------------- + +In the community bonding period I met with my mentor Serge Koudoro, along with other mentors in FURY and gsoc contributors. +We discussed about my project and set up project timeline on github projects section. As my project (glTF Integration) +and Keyframe animations were related so we discussed on that too. + +I read documentation of various glTF loading libraries (``pygltflib``, ``panda3D-gltf`` and ``pyrender``) in python and tried to understand how do they work. +I started creating a basic glTF loader, it was using dataclasses to store json data. I created polydata for each primitive in a mesh, each polydata will contain the vertices, triangles, normals. +To apply textures properly, I had to apply texture coordinates to polydata and flip the texture along X axis by 90 degrees. + + +What did you do this week? +-------------------------- + +After discussing on pros and cons of various glTF libraries we decided to use ``pygltflib`` to handle json to python dataclass conversion. +This week I reshaped PR `#600 `_ to use pygltflib. I also modified the code to handle multiple base textures. +While experimenting with textures, I accidentally applied normals to the polydata and discovered that it makes the surface look much smoother, however in few models it results in a darker model which reflects almost no light. So I made it optional for now to apply normals in a model. + +I also created a basic fetcher (PR `#602 `_) to get glTF models from Khronos group's glTF sample repository. +I also made this function asynchronous, as Serge suggested me to use asyncio and aiohttp to make the API callbacks asynchronous and it decreased the downloading time of multiple models. + +I am also working on exporting scene to a glTF file. Using `pygltflib` I am converting the python dataclass to a json like structure. + + +What is coming up next week? +---------------------------- + +Create a PR for the fetcher function, add tests, fix bugs and merge it by the end of the week. +Fix the colors issue in the glTF exporter. +Add texture and camera in glTF exporter and create a PR for it. + + +Did you get stuck anywhere? +--------------------------- + +* ``var: list[int]`` was causing the error ``TypeError: 'type' object is not subscriptable`` since the ability to use the [] operator on types like list was added in 3.9+. I had to modify the dataclasses and use ``Typing.List`` instead. +* Texture in actors weren't applied correctly. I tried flipping the texture image by 90 degrees using gimp and the texture worked nicely. The reason for this issue was the coordinate system of glTF texture format which has origin (0, 0) at top-left and (1, 1) in the bottom-right corner, Where as in vtkTexture we want coordinate (0, 0) and (1, 1) at bottom-left and top-right corner respectively. Here's an example of the issue: + +.. image:: https://raw.githubusercontent.com/xtanion/Blog-Images/main/-1_orig.jpg + :width: 500 + :align: center + +* Praneeth told me that some models with multiple nodes and multiple meshes weren't loading correctly. The reason for it was the way SCALAR data was extracted from the binary blob, I had to change some variables in `get_accessor_data` method and everything started to work just fine. diff --git a/v0.10.x/_sources/posts/2022/2022-06-22-week-3-praneeth.rst.txt b/v0.10.x/_sources/posts/2022/2022-06-22-week-3-praneeth.rst.txt new file mode 100644 index 000000000..5650ff734 --- /dev/null +++ b/v0.10.x/_sources/posts/2022/2022-06-22-week-3-praneeth.rst.txt @@ -0,0 +1,40 @@ +============================== +Week 3 - Dealing with Problems +============================== + +.. post:: June 22 2022 + :author: Praneeth Shetty + :tags: google + :category: gsoc + + +What did you do this week? +-------------------------- +This week was full of researching, playing around with things, prototyping ideas, etc. +I started with last week's clamping issue and managed to solve this issue while drawing shapes by clipping the mouse position according to canvas size, but it didn't solve the problem with translating these shapes. I tried solving this using various approaches, but if one thing would get fixed, other things would raise a new error. + +Instead of spending too much time on this, I thought it would be great to switch to other work and discuss this problem with the mentors. So I started to create a basic prototype for the properties panel, which would be used to manipulate different properties of the selected shape. + +.. image:: https://user-images.githubusercontent.com/64432063/176094716-6be012b8-36c5-43e7-a981-612dbd37ab09.gif + :width: 300 + :align: center + +But then the question arises `How to efficiently take data from the user?`, `Which data format would be easy to compute and best for user experience?` and so on. + +Alongside I was trying to create polylines but whenever I wanted to start the creation of the second line the dragging event wasn't triggered as each dragging event required a left mouse click event associated with it. +I tried to do that manually but it didn't work. + +Did you get stuck anywhere? +--------------------------- +As I mentioned when I translated the shapes it would go out of the canvas bounds. Here the problem was with the reference point by which I was calculating all the transformations it changed depending on various cases as shown below. + +.. image:: https://user-images.githubusercontent.com/64432063/176093855-6129cc25-d03d-45ba-872e-c8d2c6329a1e.gif + :width: 400 + :align: center + +This became more complex when working with a line because then the cases again differ depending on the quadrant in which the line lies. +I worked around and tried to compute the bounds but it wasn't getting updated as the shape transformed. + +What is coming up next? +----------------------- +Solving the clamping issue to restrict the shape's position to be in the canvas boundaries. diff --git a/v0.10.x/_sources/posts/2022/2022-06-28-week-2-mohamed.rst.txt b/v0.10.x/_sources/posts/2022/2022-06-28-week-2-mohamed.rst.txt new file mode 100644 index 000000000..56970fe0e --- /dev/null +++ b/v0.10.x/_sources/posts/2022/2022-06-28-week-2-mohamed.rst.txt @@ -0,0 +1,56 @@ +Week 2: Implementing non-linear and color interpolators +======================================================= + +.. post:: June 28 2022 + :author: Mohamed Abouagour + :tags: google + :category: gsoc + + +What did you do this week? +-------------------------- + +- Implemented some other general interpolators such as n-th degree spline and cubic spline interpolators. Also implemented HSV and LAB color interpolators. + + PRs `#612`_ and `#613`_ + + + .. raw:: html + + + + + .. raw:: html + + + + + +- Added animation slider to seek a particular time and visualize the timeline in real-time. + + .. raw:: html + + + + +- Managed to do the transformation on the GPU side using GLSL using matrices. And did some digging about how and when we interpolate the camera and also how to do this on the GPU side. + + +What is coming up next week? +---------------------------- + +This week I will do the following + +- Allow FURY actors to maintain the number of primitives as an object property so that it can be used to manipulate only a subset of primitives in a single actor. +- Change the structure of the Animation API to a newer one designed by Filipi to solve performance issues when creating a large number of timelines. +- Implement the Bézier curve interpolation. + + + +Did you get stuck anywhere? +--------------------------- + +I got stuck trying to fix the clipping plans not being appropriately set. Which caused actors to disappear at some point. + +.. _`#612`: https://github.com/fury-gl/fury/pull/612 +.. _`#613`: https://github.com/fury-gl/fury/pull/613 diff --git a/v0.10.x/_sources/posts/2022/2022-06-29-week-4-praneeth.rst.txt b/v0.10.x/_sources/posts/2022/2022-06-29-week-4-praneeth.rst.txt new file mode 100644 index 000000000..015c88374 --- /dev/null +++ b/v0.10.x/_sources/posts/2022/2022-06-29-week-4-praneeth.rst.txt @@ -0,0 +1,53 @@ +================================== +Week 4 - Fixing the Clamping Issue +================================== + +.. post:: June 29 2022 + :author: Praneeth Shetty + :tags: google + :category: gsoc + + +What did you do this week? +-------------------------- +Phew!! This week was a tedious week for me as parallelly my End-Sem exams also started. So as usual I started from where I left off last week, *The Clamping Issue*. As per the discussion with the mentors, we decided to use the *AABB bounding box* method to calculate the bounding box around the shape and then reposition or transform respectively, as now we had a fixed reference point. So after doing some calculations with the mouse positions and the bounding box points at last, I was able to clamp all the shapes successfully. + +`DrawPanel UI `_ + + +.. image:: https://user-images.githubusercontent.com/64432063/175497817-21974f43-d82b-4245-b93d-2db1081e6b04.gif + :width: 450 + :align: center + +While testing these changes, I found an issue that whenever we just do a single *left mouse click* on the shape, it automatically translated a bit. As you can see below. + +.. image:: https://user-images.githubusercontent.com/32108826/175790660-e4b05269-e8d3-44e9-92e1-336c0eeb34ca.gif + :width: 400 + :align: center + +This was due to the difference between the global mouse click position and the canvas position, which was then fixed by converting the mouse click position to the relative canvas position. + +Along with this, I tried to add some control points using `Disk2D` for the shape so that we can use them later on to transform the shapes. + +`Control points `_ + +.. image:: https://user-images.githubusercontent.com/64432063/177264804-15e67715-b714-4e33-ac68-423375d81740.gif + :width: 300 + :align: center + +Also, to enhance the visualization of the bounding box, I added a box border covering the shapes. + +`Bounding Box Borders `_ + +.. image:: https://user-images.githubusercontent.com/64432063/177264077-a8859a96-e3f7-444c-9760-8b9b17542f0f.gif + :width: 300 + :align: center + + +Did you get stuck anywhere? +--------------------------- +No, Everything worked out fine. + +What is coming up next? +----------------------- +Enhancing the control points to work perfectly. diff --git a/v0.10.x/_sources/posts/2022/2022-06-29-week2-shivam.rst.txt b/v0.10.x/_sources/posts/2022/2022-06-29-week2-shivam.rst.txt new file mode 100644 index 000000000..0c740d8f3 --- /dev/null +++ b/v0.10.x/_sources/posts/2022/2022-06-29-week2-shivam.rst.txt @@ -0,0 +1,30 @@ +Week 2 - Improving Fetcher and Exporting glTF +============================================= + +.. post:: June 29 2022 + :author: Shivam Anand + :tags: google + :category: gsoc + + +What did you do this week? +-------------------------- +This week I worked primarily on the glTF fetcher and exporting scenes to a glTF file. I added tests and docstrings for all functions. I modified the ``fetch_gltf`` function to return the downloaded files. As we planned, the PR for the glTF fetcher was merged this week. + +I fixed the color issue of the glTF exporter by manually appending the color data from the actor to the ``polydata``. But there's another issue raised while using actors from ``vtkSource``. The ``utils.get_polydata_triangles(polydata)`` method only works with primitives and it raises an error when used with ``vtkSource`` actors. + +Textures and Cameras can now be added to the glTF file. However, it supports baseTexture only. I'll be working on materials support later on. + + +What is coming up next week? +---------------------------- + +* Saving all models download link (from the Khronos glTF-Samples-Models repository) to a JSON file, create a separate branch and add the download script. +* Add tests and docstring for PR `#600 `_. +* Create a PR for glTF exporter. + +Did you get stuck anywhere? +--------------------------- + +* I managed to fix colors in polydata by adding them manually, but it raised another issue with indices (triangles) of the actor weren't of the correct shape. We decided to take a look at it later. +* Due to Github's API limit, it raised an error due to limits exceeding. We decided to save a JSON file with all model names and their download links. Then use that to download the model. diff --git a/v0.10.x/_sources/posts/2022/2022-07-04-week-3-mohamed.rst.txt b/v0.10.x/_sources/posts/2022/2022-07-04-week-3-mohamed.rst.txt new file mode 100644 index 000000000..c1544a408 --- /dev/null +++ b/v0.10.x/_sources/posts/2022/2022-07-04-week-3-mohamed.rst.txt @@ -0,0 +1,48 @@ +Week 3: Redesigning the API, Implementing cubic Bezier Interpolator, and making progress on the GPU side! +========================================================================================================= + +.. post:: July 04 2022 + :author: Mohamed Abouagour + :tags: google + :category: gsoc + + +What did you do this week? +-------------------------- + +- Redesigned the keyframe animations API to optimize having a lot of timelines by composing them into a parent ``Timeline`` called ``CompositeTimeline`` while maintaining playing individual timelines separately. + +- Implemented the cubic Bezier Interpolator using two control points for each keyframe. Also made a tutorial for it below: + + .. raw:: html + + + + + +- Also Implemented linear and cubic Bezier in GLSL interpolations to be computed by the GPU by sending two keyframes as uniforms and the current animation time. + +- Composed the playback panel as a single component ``PlaybackPanel`` (slider does not function yet). + +- As we tried to come up with a way to do keyframe animations on a partial subset of the actor's primitives not all of them, we found that there is no currently implemented way to get the primitives count of a single actor. So I made this PR `#617`_ so that the primitives' count is saved inside the polydata of the actor as suggested by Filipi and Javier so that the primitives' count can be used to distinguish the vertices of different primitives. + + +What is coming up next week? +---------------------------- + +This week I will do the following + +- Finish up the ``PlaybackPanel``. +- Implement all other interpolators in GLSL (color interpolators included). +- Start Implementing slerp interpolation using quaternions in both Python and GLSL. +- Add tests for the previous work. +- Now that I made some progress with the keyframe animation API, I should be able to make a mergeable PR! + + +Did you get stuck anywhere? +--------------------------- + +- Couldn't get the ``LineSlider2D`` to work inside my new ``PlaybackPanel``. + + +.. _`#617`: https://github.com/fury-gl/fury/pull/617 diff --git a/v0.10.x/_sources/posts/2022/2022-07-04-week3-shivam.rst.txt b/v0.10.x/_sources/posts/2022/2022-07-04-week3-shivam.rst.txt new file mode 100644 index 000000000..c172a7481 --- /dev/null +++ b/v0.10.x/_sources/posts/2022/2022-07-04-week3-shivam.rst.txt @@ -0,0 +1,42 @@ +Week 3 - Fixing fetcher, adding tests and docs +============================================== + +.. post:: July 04 2022 + :author: Shivam Anand + :tags: google + :category: gsoc + + +What did you do this week? +-------------------------- + +- The first task for this week was to fix the glTF fetcher. We noticed that while running tests it reaches the API limit. So we decided to use a JSON file that contains the download URLs for all models. + +- Created a function to generate JSON files with download URLs for all models, which can be found `here `_. + +- Modified the tests and ``fetcher.py`` to download using the JSON URLs and merged the PR `#616 `_. + +- Added docstring for all functions in `#600 `_. Wrote tests for transformation functions. + +- Multiple actor support in glTF export. Added tutorial and created a new branch for the same. Here's an example: (The glTF model below is created using FURY and rendered back using the glTF class) + +.. image:: https://github.com/xtanion/Blog-Images/blob/main/Screenshot%20from%202022-07-05%2014-51-06.png?raw=true + :width: 500 + :align: center + + +What is coming up next week? +---------------------------- + +I will be doing the following: + +- We still need to figure out how to get indices from ``vtkSource`` actors +- I'll be finishing the exporting functions and adding tests for the same and I should be able to create a mergeable PR for the exporting function. + +Other tasks will be decided after the meeting. + + +Did you get stuck anywhere? +--------------------------- + +No diff --git a/v0.10.x/_sources/posts/2022/2022-07-06-week-5-praneeth.rst.txt b/v0.10.x/_sources/posts/2022/2022-07-06-week-5-praneeth.rst.txt new file mode 100644 index 000000000..604822859 --- /dev/null +++ b/v0.10.x/_sources/posts/2022/2022-07-06-week-5-praneeth.rst.txt @@ -0,0 +1,48 @@ +================================ +Week 5 - Working on new features +================================ + +.. post:: July 06 2022 + :author: Praneeth Shetty + :tags: google + :category: gsoc + + +What did you do this week? +-------------------------- +This week I tried to create a base for some upcoming new features. +The first thing I updated was the Properties panel which I prototyped in `Week 3 `_. +So previously, it was just displaying the properties but now after the update, it is able to modify the properties(such as `color`, `position`, and `rotation`) too. This was a quick change to test the callbacks. + +`Properties Panel: `_ + +.. image:: https://user-images.githubusercontent.com/64432063/178412630-a0013a1a-3bfd-46fa-8445-fb5cff728e9c.gif + :align: center + :width: 300 + +Then I worked with the bounding box to make it visible whenever a shape is selected. +For this, I used the existing functionality of the ``Panel2D`` actor to create borders around the bounding box. + +`Bounding Box `_ + +.. image:: https://user-images.githubusercontent.com/64432063/178413769-5e4626d6-a207-489a-9789-59777c3e0522.gif + :align: center + :width: 300 + +Also along with this, I managed to add the `polyline` feature on user interactions. This creation isn't that smooth but works as intended. + +`Poly Line `_ + +.. image:: https://user-images.githubusercontent.com/64432063/178414652-f47f3b25-a2c5-484a-bdbe-94f4ba1eff1f.gif + :align: center + :width: 300 + + +Did you get stuck anywhere? +--------------------------- +Handling interactions for the `polyline` was complicated. I wasn't able to invoke the `left_mouse_click` event, then as I was trying to invoke the events internally, it started creating multiple copies of the same line. + + +What is coming up next? +----------------------- +I will be enhancing the `polyline` feature. diff --git a/v0.10.x/_sources/posts/2022/2022-07-11-week-4-mohamed.rst.txt b/v0.10.x/_sources/posts/2022/2022-07-11-week-4-mohamed.rst.txt new file mode 100644 index 000000000..f65d3334a --- /dev/null +++ b/v0.10.x/_sources/posts/2022/2022-07-11-week-4-mohamed.rst.txt @@ -0,0 +1,58 @@ +Week 4: Camera animation, interpolation in GLSL, and a single ``Timeline``! +=========================================================================== + +.. post:: July 11 2022 + :author: Mohamed Abouagour + :tags: google + :category: gsoc + + +What did you do this week? +-------------------------- + +- Managed to implement a single ``Timeline`` using the ``Container`` class. So, instead of having two classes: ``Timeline`` and ``CompositeTimeline``, now the ``Timeline`` can have multiple ``Timeline`` objects and controls them as in the code below. + + .. code-block:: python + + main_timeline = Timeline() + sub_timeline = Timeline(actors_list) + main_timeline.add_timeline(sub_timeline) + +| + +- Implemented the HSV, Lab, and XYZ color interpolators in GLSL. + +- Added support for animating two camera properties: position and focal position, which can be interpolated using any general ``Interpolator``. + + .. raw:: html + + + + +- Allowed all ``actors`` inside all timelines to be added to the ``Scene`` automatically when the main (parent) ``Timeline`` is added to the ``Scene``. + +- Fixed the ``PlaybackPanel``, added a counter to display the animation time as in the video above, and added an option to attach a ``PlaybackPanel`` to the ``Timeline``. + + .. code-block:: python + + main_timeline = Timeline(playback_panel=True) + + +| + +What is coming up next week? +---------------------------- + +This week I will do the following: + +- Start Implementing slerp interpolation using quaternions in both Python and GLSL. And use slerp to apply camera rotation. +- Add tests for the previous work. +- Make a PR to merge the non-shader-based version of the ``Timeline``. +- Test how shader attributes can be used to hold keyframes for each vertex and benchmark it. +- Study 'colormaps' and implement some 'colormaps' in GLSL. + + +Did you get stuck anywhere? +--------------------------- + +- Uniforms don't maintain their data after shaders are unbounded and another uniform with the same name in a different shader is set. diff --git a/v0.10.x/_sources/posts/2022/2022-07-12-week4-shivam.rst.txt b/v0.10.x/_sources/posts/2022/2022-07-12-week4-shivam.rst.txt new file mode 100644 index 000000000..984401f88 --- /dev/null +++ b/v0.10.x/_sources/posts/2022/2022-07-12-week4-shivam.rst.txt @@ -0,0 +1,219 @@ +Week 4 - Finalizing glTF loader +=============================== +.. post:: July 12 2022 + :author: Shivam Anand + :tags: google + :category: gsoc + + +What did you do this week? +-------------------------- + +This week I had to travel back to my college since the summer vacations have ended. +I had a coding session with Serge this week, we modified the exporter function and looked at some bugs I faced. + +We managed to use the ``io.load_io`` function. There was a strange issue with loading png files. I had to convert the PIL ``Image`` to ``RGB`` format, and it fixed the issue, turns out png images are stored as ``P`` (pallet) mode. + +I also added the ``glb`` format support to the importer. While loading a ``.glb`` model, I noticed that the image data is also stored in the buffer and there can be a ``bufferview`` index to get the buffer. + +During this time, I also tested the glTF loader with all models in the ``KhronoosGroup/glTF-samples`` repository. Here's the table of models working well: `see file `_. + ++---------------------------------+---------+-------------------------------------------------------------------------------------+ +| Model Name | Status | Error Type | ++=================================+=========+=====================================================================================+ +| BoxInterleaved | No | "BoxInterleaved.gltf: shapes (4,4) and (7,12) not aligned: 4 (dim 1) != 7 (dim 0)" | ++---------------------------------+---------+-------------------------------------------------------------------------------------+ +| Box | Yes | | ++---------------------------------+---------+-------------------------------------------------------------------------------------+ +| SpecularTest | Yes | | ++---------------------------------+---------+-------------------------------------------------------------------------------------+ +| AnimatedCube | Yes | | ++---------------------------------+---------+-------------------------------------------------------------------------------------+ +| NormalTangentMirrorTest | Yes | | ++---------------------------------+---------+-------------------------------------------------------------------------------------+ +| AnimatedTriangle | Yes | | ++---------------------------------+---------+-------------------------------------------------------------------------------------+ +| SpecGlossVsMetalRough | No | SpecGlossVsMetalRough.gltf: 'NoneType' object has no attribute 'baseColorTexture' | ++---------------------------------+---------+-------------------------------------------------------------------------------------+ +| CesiumMilkTruck | Yes | | ++---------------------------------+---------+-------------------------------------------------------------------------------------+ +| VC | Yes | | ++---------------------------------+---------+-------------------------------------------------------------------------------------+ +| WaterBottle | Yes | | ++---------------------------------+---------+-------------------------------------------------------------------------------------+ +| AnimatedMorphCube | Yes | | ++---------------------------------+---------+-------------------------------------------------------------------------------------+ +| Sponza | Yes | | ++---------------------------------+---------+-------------------------------------------------------------------------------------+ +| SciFiHelmet | No | SciFiHelmet.gltf: Python int too large to convert to C long | ++---------------------------------+---------+-------------------------------------------------------------------------------------+ +| Triangle | No | None: file not downloaded | ++---------------------------------+---------+-------------------------------------------------------------------------------------+ +| IridescenceMetallicSpheres | No | None: file not downloaded | ++---------------------------------+---------+-------------------------------------------------------------------------------------+ +| Corset | Yes | | ++---------------------------------+---------+-------------------------------------------------------------------------------------+ +| Cube | Yes | | ++---------------------------------+---------+-------------------------------------------------------------------------------------+ +| TextureLinearInterpolationTest | Yes | | ++---------------------------------+---------+-------------------------------------------------------------------------------------+ +| SimpleMeshes | Yes | | ++---------------------------------+---------+-------------------------------------------------------------------------------------+ +| Lantern | Yes | | ++---------------------------------+---------+-------------------------------------------------------------------------------------+ +| TextureTransformMultiTest | Yes | | ++---------------------------------+---------+-------------------------------------------------------------------------------------+ +| TextureSettingsTest | Yes | | ++---------------------------------+---------+-------------------------------------------------------------------------------------+ +| LightsPunctualLamp | Yes | | ++---------------------------------+---------+-------------------------------------------------------------------------------------+ +| DamagedHelmet | Yes | | ++---------------------------------+---------+-------------------------------------------------------------------------------------+ +| CesiumMan | Yes | | ++---------------------------------+---------+-------------------------------------------------------------------------------------+ +| Cameras | Yes | | ++---------------------------------+---------+-------------------------------------------------------------------------------------+ +| BarramundiFish | Yes | | ++---------------------------------+---------+-------------------------------------------------------------------------------------+ +| MetalRoughSpheresNoTextures | Yes | | ++---------------------------------+---------+-------------------------------------------------------------------------------------+ +| EnvironmentTest | No | None: file not downloaded | ++---------------------------------+---------+-------------------------------------------------------------------------------------+ +| MosquitoInAmber | No | MosquitoInAmber.gltf: buffer is smaller than requested size | ++---------------------------------+---------+-------------------------------------------------------------------------------------+ +| BoxTexturedNonPowerOfTwo | Yes | | ++---------------------------------+---------+-------------------------------------------------------------------------------------+ +| BrainStem | Yes | | ++---------------------------------+---------+-------------------------------------------------------------------------------------+ +| SimpleMorph | Yes | | ++---------------------------------+---------+-------------------------------------------------------------------------------------+ +| OrientationTest | Yes | | ++---------------------------------+---------+-------------------------------------------------------------------------------------+ +| BoxAnimated | Yes | | ++---------------------------------+---------+-------------------------------------------------------------------------------------+ +| StainedGlassLamp | Yes | | ++---------------------------------+---------+-------------------------------------------------------------------------------------+ +| TextureTransformTest | No | None: file not downloaded | ++---------------------------------+---------+-------------------------------------------------------------------------------------+ +| ClearCoatTest | Yes | | ++---------------------------------+---------+-------------------------------------------------------------------------------------+ +| IridescenceLamp | No | None: file not downloaded | ++---------------------------------+---------+-------------------------------------------------------------------------------------+ +| DragonAttenuation | No | DragonAttenuation.gltf: buffer is smaller than requested size | ++---------------------------------+---------+-------------------------------------------------------------------------------------+ +| RecursiveSkeletons | No | RecursiveSkeletons.gltf: cannot reshape array of size 120 into shape (9) | ++---------------------------------+---------+-------------------------------------------------------------------------------------+ +| Suzanne | Yes | | ++---------------------------------+---------+-------------------------------------------------------------------------------------+ +| RiggedSimple | Yes | | ++---------------------------------+---------+-------------------------------------------------------------------------------------+ +| TextureEncodingTest | Yes | | ++---------------------------------+---------+-------------------------------------------------------------------------------------+ +| 2CylinderEngine | Yes | | ++---------------------------------+---------+-------------------------------------------------------------------------------------+ +| NormalTangentTest | Yes | | ++---------------------------------+---------+-------------------------------------------------------------------------------------+ +| MorphStressTest | Yes | | ++---------------------------------+---------+-------------------------------------------------------------------------------------+ +| IridescenceDielectricSpheres | No | None: file not downloaded | ++---------------------------------+---------+-------------------------------------------------------------------------------------+ +| TextureCoordinateTest | Yes | | ++---------------------------------+---------+-------------------------------------------------------------------------------------+ +| Duck | Yes | | ++---------------------------------+---------+-------------------------------------------------------------------------------------+ +| AlphaBlendModeTest | Yes | | ++---------------------------------+---------+-------------------------------------------------------------------------------------+ +| TriangleWithoutIndices | Yes | | ++---------------------------------+---------+-------------------------------------------------------------------------------------+ +| MultiUVTest | Yes | | ++---------------------------------+---------+-------------------------------------------------------------------------------------+ +| BoomBoxWithAxes | Yes | | ++---------------------------------+---------+-------------------------------------------------------------------------------------+ +| Box With Spaces | No | Box%20With%20Spaces.gltf: 'NoneType' object has no attribute 'shape' | ++---------------------------------+---------+-------------------------------------------------------------------------------------+ +| SheenCloth | Yes | | ++---------------------------------+---------+-------------------------------------------------------------------------------------+ +| ToyCar | No | None: file not downloaded | ++---------------------------------+---------+-------------------------------------------------------------------------------------+ +| MaterialsVariantsShoe | No | MaterialsVariantsShoe.gltf: buffer is smaller than requested size | ++---------------------------------+---------+-------------------------------------------------------------------------------------+ +| IridescentDishWithOlives | Yes | | ++---------------------------------+---------+-------------------------------------------------------------------------------------+ +| VertexColorTest | Yes | | ++---------------------------------+---------+-------------------------------------------------------------------------------------+ +| SheenChair | Yes | | ++---------------------------------+---------+-------------------------------------------------------------------------------------+ +| Fox | Yes | | ++---------------------------------+---------+-------------------------------------------------------------------------------------+ +| AntiqueCamera | Yes | | ++---------------------------------+---------+-------------------------------------------------------------------------------------+ +| TransmissionTest | No | None: file not downloaded | ++---------------------------------+---------+-------------------------------------------------------------------------------------+ +| TransmissionRoughnessTest | Yes | | ++---------------------------------+---------+-------------------------------------------------------------------------------------+ +| BoxVertexColors | Yes | | ++---------------------------------+---------+-------------------------------------------------------------------------------------+ +| ReciprocatingSaw | Yes | | ++---------------------------------+---------+-------------------------------------------------------------------------------------+ +| MorphPrimitivesTest | Yes | | ++---------------------------------+---------+-------------------------------------------------------------------------------------+ +| MetalRoughSpheres | Yes | | ++---------------------------------+---------+-------------------------------------------------------------------------------------+ +| GearboxAssy | Yes | | ++---------------------------------+---------+-------------------------------------------------------------------------------------+ +| TwoSidedPlane | Yes | | ++---------------------------------+---------+-------------------------------------------------------------------------------------+ +| Buggy | Yes | | ++---------------------------------+---------+-------------------------------------------------------------------------------------+ +| SimpleSparseAccessor | Yes | | ++---------------------------------+---------+-------------------------------------------------------------------------------------+ +| BoxTextured | Yes | | ++---------------------------------+---------+-------------------------------------------------------------------------------------+ +| UnlitTest | Yes | | ++---------------------------------+---------+-------------------------------------------------------------------------------------+ +| SimpleSkin | Yes | | ++---------------------------------+---------+-------------------------------------------------------------------------------------+ +| FlightHelmet | Yes | | ++---------------------------------+---------+-------------------------------------------------------------------------------------+ +| Unicode❤♻Test | No | Unicode%E2%9D%A4%E2%99%BBTest.gltf: 'NoneType' object has no attribute 'shape' | ++---------------------------------+---------+-------------------------------------------------------------------------------------+ +| Avocado | Yes | | ++---------------------------------+---------+-------------------------------------------------------------------------------------+ +| InterpolationTest | Yes | | ++---------------------------------+---------+-------------------------------------------------------------------------------------+ +| GlamVelvetSofa | Yes | | ++---------------------------------+---------+-------------------------------------------------------------------------------------+ +| RiggedFigure | Yes | | ++---------------------------------+---------+-------------------------------------------------------------------------------------+ +| BoomBox | Yes | | ++---------------------------------+---------+-------------------------------------------------------------------------------------+ +| EmissiveStrengthTest | No | None: file not downloaded | ++---------------------------------+---------+-------------------------------------------------------------------------------------+ +| AttenuationTest | Yes | | ++---------------------------------+---------+-------------------------------------------------------------------------------------+ +| AnimatedMorphSphere | Yes | | ++---------------------------------+---------+-------------------------------------------------------------------------------------+ +| IridescenceSuzanne | Yes | | ++---------------------------------+---------+-------------------------------------------------------------------------------------+ + + + +What is coming up next week? +---------------------------- + +- Adding tests and merging export function PR. +- Start working on Simple Animations. + + +Did you get stuck anywhere? +--------------------------- + +- To create a texture, we needed the RGB values, However ``.png`` images were returning a 2D array when read using PIL. It is fixed by + + .. code-block :: python + + if pil_image.mode in ['P']: + pil_image = pil_image.convert('RGB') + + +- pygltflib's ``load`` method does not handle glb files very well. It does not contain the buffer ``uri``. I used ``glb2gltf`` method as of now. diff --git a/v0.10.x/_sources/posts/2022/2022-07-13-week-6-praneeth.rst.txt b/v0.10.x/_sources/posts/2022/2022-07-13-week-6-praneeth.rst.txt new file mode 100644 index 000000000..a7e30da89 --- /dev/null +++ b/v0.10.x/_sources/posts/2022/2022-07-13-week-6-praneeth.rst.txt @@ -0,0 +1,45 @@ +========================================================== +Week 6 - Supporting Rotation of the Shapes from the Center +========================================================== + +.. post:: July 13 2022 + :author: Praneeth Shetty + :tags: google + :category: gsoc + + +What did you do this week? +-------------------------- +This week I started implementing a new feature to rotate the shapes from the center using ``RingSlider2D``. I already had a `rotate` function that rotates the shape around its pivot vertex, so I updated it to support rotation from the center. + +`Rotation from center `_ + +.. image:: https://user-images.githubusercontent.com/64432063/180257893-196baafe-3c42-4152-b5f4-643b794176d2.gif + :align: center + :width: 300 + +Then I tried to group the shapes to transform and modify them all at once. For this, I had to investigate more about the key press and release events. Then I managed to select and deselect shapes by holding the ``Ctrl`` key. + +`Grouping Shapes `_ + +.. image:: https://user-images.githubusercontent.com/64432063/180261113-39760cba-0343-41e7-924a-c741eb838f0b.gif + :align: center + :width: 300 + +I improved the `polyline` feature by adding a separate class to manage the creation and manipulation of the lines but still; I was facing the same issue with the dragging event, which initialized a new object every time a new line was created. + +Did you get stuck anywhere? +--------------------------- +It was difficult to rotate the shape from the center because the pivot(or the reference point) of the shape wasn't consistent. As you can see below it changed depending on how the shape was created. + +.. image:: https://user-images.githubusercontent.com/64432063/176093855-6129cc25-d03d-45ba-872e-c8d2c6329a1e.gif + :width: 400 + :align: center + +To handle this, I created an interface between the actual pivot point and the center of the bounding box, which made it easy to calculate and set the positions. + +Also, I wasn't able to find a way by which I could manually call the dragging event without a preceding click event which was required for the `polyline`` feature. + +What is coming up next? +----------------------- +Complete `Rotation from center `_ PR. diff --git a/v0.10.x/_sources/posts/2022/2022-07-19-week-5-mohamed.rst.txt b/v0.10.x/_sources/posts/2022/2022-07-19-week-5-mohamed.rst.txt new file mode 100644 index 000000000..869a9bfaf --- /dev/null +++ b/v0.10.x/_sources/posts/2022/2022-07-19-week-5-mohamed.rst.txt @@ -0,0 +1,37 @@ +Week 5: Slerp implementation, documenting the Timeline, and adding unit tests +============================================================================= + +.. post:: July 19 2022 + :author: Mohamed Abouagour + :tags: google + :category: gsoc + + +What did you do this week? +-------------------------- + +- Implemented Slerp (spherical linear interpolation) for rotation keyframes. +- Controlling the speed of the animation is now an option. +- Added the tests and documented the ``Timeline``. +- Used the geometry shader to generate billboard actors using a minimal set of calculations `#631`_. + + .. raw:: html + + + + +What is coming up next week? +---------------------------- + +This week I will do the following: + +- Focus on finalizing PR `#626`_ to be merged. +- Make some upgrades to the playback panel to make it more functional and responsive. +- Add more tutorials to explain how to use all the functionalities of the ``Timeline``. + +Did you get stuck anywhere? +--------------------------- +I didn't get stuck this week. + +.. _`#626`: https://github.com/fury-gl/fury/pull/626 +.. _`#631`: https://github.com/fury-gl/fury/pull/631 diff --git a/v0.10.x/_sources/posts/2022/2022-07-19-week5-shivam.rst.txt b/v0.10.x/_sources/posts/2022/2022-07-19-week5-shivam.rst.txt new file mode 100644 index 000000000..f1b1607a0 --- /dev/null +++ b/v0.10.x/_sources/posts/2022/2022-07-19-week5-shivam.rst.txt @@ -0,0 +1,34 @@ +Week 5 - Creating PR for glTF exporter and fixing the loader +============================================================ +.. post:: July 19 2022 + :author: Shivam Anand + :tags: google + :category: gsoc + + +What did you do this week? +-------------------------- + +- Finalised the glTF export PR `#630`_., adding tutorial, docs, and tests for all functions. +- Added support for exporting lines and dot actors. +- ``primitive.modes`` is now set if the rendering mode is a line, dot, or triangle. +- Working on importing different primitive modes, the current glTF importer can render only triangles. + + +What is coming up next week? +---------------------------- + +This week I'll be working on the following: + +- Get the PR `#630`_. merged by this week. +- Loading the animations (simple, morph, and skeletal) data as dictionaries from the glTF model so that it can be sent to the timeline. +- Try different examples on Mohamed's PR (`#626`_.) and try running glTF animations if time permits. + + +Did you get stuck anywhere? +--------------------------- + +- There wasn't any model in the Khronos glTF samples repository that uses the ``LINE`` or ``POINT`` modes. So I had to rely on the models that I exported using the glTF exporter. + +.. _`#630`: https://github.com/fury-gl/fury/pull/630 +.. _`#626`: https://github.com/fury-gl/fury/pull/626 diff --git a/v0.10.x/_sources/posts/2022/2022-07-20-week-7-praneeth.rst.txt b/v0.10.x/_sources/posts/2022/2022-07-20-week-7-praneeth.rst.txt new file mode 100644 index 000000000..553f5d47a --- /dev/null +++ b/v0.10.x/_sources/posts/2022/2022-07-20-week-7-praneeth.rst.txt @@ -0,0 +1,53 @@ +=========================================================== +Week 7 - Working on Rotation PR and Trying Freehand Drawing +=========================================================== + +.. post:: July 20 2022 + :author: Praneeth Shetty + :tags: google + :category: gsoc + + +What did you do this week? +-------------------------- +I continued PR `#623`_ and fixed the displacement of the shape from its original position when applying rotation. This was happening because most of the calculations resulted in `float` values, but as the pixel position were integers we had to explicitly convert these values into `int`. This conversion rounded off the values and as we call this function continuously, each time the round-off would happen, the shape would get displaced. + +.. image:: https://user-images.githubusercontent.com/64432063/181723334-ef9ec75d-d3bf-4b79-83bf-272545c4dd12.gif + :width: 400 + :align: center + +To fix this, I converted all the calculations into integer calculations using floor division ``//`` instead of normal division ``/``. + +.. image:: https://user-images.githubusercontent.com/64432063/181723783-352092aa-b7a7-4d13-8d26-553315c7e1aa.gif + :width: 400 + :align: center + +The tests were failing in `Ubuntu` and the `macOS` because the mouse click event wasn't propagated to the line due to some unknown reasons. When investigating more about the issue, Mohamed suggested and helped me implement another approach to select the shapes. In this approach, we calculate the distance between the mouse click event position and each of the shapes, and if any of the distances is less than a specific value (which I call as limit value), then we send this current event to that element. + +`New shape selection technique: `_ + + +.. image:: https://user-images.githubusercontent.com/64432063/181730428-debd0617-dc32-4232-93ab-18ab903e92de.gif + :width: 400 + :align: center + +I also tried to implement a freehand drawing mode by adding ``Disk2D`` as points. But as you can see below, there are many flaws in this. + +- First of all, we add many ``Disk2D`` objects which make it memory consuming process. +- If the mouse moves very fast, then we can see the gaps between points. +- Storing, managing, and transforming are difficult. + +.. image:: https://user-images.githubusercontent.com/64432063/181731181-1f242c65-ccb8-4589-a2ed-40bfb3718cfd.gif + :width: 400 + :align: center + + +Did you get stuck anywhere? +--------------------------- +It was hard to debug why the tests were failing in `Ubuntu` and `macOS`. I tried investigating it by installing Ubuntu and got nothing, but then while implementing the new selection approach, it automatically got fixed. + +What is coming up next? +----------------------- +Getting PR `#623`_ merged and working on the polyline feature. + +.. _`#623`: https://github.com/fury-gl/fury/pull/623 diff --git a/v0.10.x/_sources/posts/2022/2022-07-25-week-6-mohamed.rst.txt b/v0.10.x/_sources/posts/2022/2022-07-25-week-6-mohamed.rst.txt new file mode 100644 index 000000000..61fb8e831 --- /dev/null +++ b/v0.10.x/_sources/posts/2022/2022-07-25-week-6-mohamed.rst.txt @@ -0,0 +1,48 @@ +Week 6: Fixing the ``Timeline`` issues and equipping it with more features +========================================================================== + +.. post:: July 25 2022 + :author: Mohamed Abouagour + :tags: google + :category: gsoc + + +What did you do this week? +-------------------------- + +- Improved the ``PlaybackPanel`` by adding speed control and the ability to loop the animation. Also, fixed the lagging issue of play and pause buttons and composed them into a single play/pause button. + +- Updated the old tutorials' syntax to match the other tutorials and added a new tutorial on position animation using spline interpolation. Added unit tests for the ``PlaybackPanel`` and the newly added color converters in ``colormap.py``. + +- Added more hooks to the 2D sliders to cover two more states: + + 1. ``on_value_changed``, which gets called whenever the value of the slider is changed without interacting with the slider. + + 2. ``on_moving_slider``, which gets called when the position of the slider is changed by user interaction. `#634`_. + + - The reason for adding these two hooks is that there was only the ``on_change`` hook, which always gets called when the value of the slider is changed without considering how the value is changed, hence, the functionality of the slider was limited. + +- Provided the ability to add static actors to the ``Timeline``, which might be needed in the animation part of Shivam's glTF project `#643`_. + + - If an ``actor`` is added to the ``Timeline`` as a static actor, it won't be animated by the ``Timeline``, but it will get added to the scene along with the ``Timeline``. + +- Implemented a custom evaluator for the ``Timeline``'s properties. + + - A custom evaluator uses a user-provided function that takes time as input and evaluates the property at that time. This feature is yet to be discussed more in today's meeting. + +- Fixed camera rotation and the view-up issue when interacting with the scene. + + +What is coming up next week? +---------------------------- +- Make a tutorial on how to implement a new custom Interpolator to work with the ``Timeline``. +- Add motion path visualization feature for both position and color properties. +- Add custom evaluation functions directly, without using the ``CustomInterpolator``. +- Implement an already existing complex interpolator using closures instead of classes. + +Did you get stuck anywhere? +--------------------------- +I didn't get stuck this week. + +.. _`#634`: https://github.com/fury-gl/fury/pull/634 +.. _`#643`: https://github.com/fury-gl/fury/pull/643 diff --git a/v0.10.x/_sources/posts/2022/2022-07-25-week-6-shivam.rst.txt b/v0.10.x/_sources/posts/2022/2022-07-25-week-6-shivam.rst.txt new file mode 100644 index 000000000..b8d3ce089 --- /dev/null +++ b/v0.10.x/_sources/posts/2022/2022-07-25-week-6-shivam.rst.txt @@ -0,0 +1,41 @@ +Week 6 - Extracting the animation data +====================================== + +.. post:: July 25 2022 + :author: Shivam Anand + :tags: google + :category: gsoc + + +What did you do this week? +-------------------------- + +- This week, it was all about reading docs and extracting the animation data from buffers. + +- Currently, the glTF class can extract simple node transformation and morphing data, as they are stored in the ``Animations`` of the glTF file. + +- Skinning (Skeletal Animation) data is stored in ``Nodes`` inside the skin parameter. We shall be able to load that before our next meeting on Wednesday. + +- Created a `tutorial `_ using keyframe animations (`#626`_) and adding multiple ``timelines`` into a main ``timeline`` as suggested by Mohamed. + + .. raw:: html + + + + + +What is coming up next week? +---------------------------- + +As of now, we've decided the following: + +- Create a custom Interpolator (for simple node transformations, morph and Skeletal animations). + + +Did you get stuck anywhere? +--------------------------- + +No, I didn't get stuck this week. + + +.. _`#626`: https://github.com/fury-gl/fury/pull/626 diff --git a/v0.10.x/_sources/posts/2022/2022-07-27-week-8-praneeth.rst.txt b/v0.10.x/_sources/posts/2022/2022-07-27-week-8-praneeth.rst.txt new file mode 100644 index 000000000..698d770d6 --- /dev/null +++ b/v0.10.x/_sources/posts/2022/2022-07-27-week-8-praneeth.rst.txt @@ -0,0 +1,35 @@ +======================================== +Week 8 - Working on the polyline feature +======================================== + +.. post:: July 27 2022 + :author: Praneeth Shetty + :tags: google + :category: gsoc + + +What did you do this week? +-------------------------- +This week I started working on the `polyline` feature. After a lot of investigating and trying out different things, I found a way to call the dragging event manually without any prior click event. VTK actually captures the mouse movement using the ``MouseMoveEvent``. This event is then modified by FURY to only be called after the click event. So I added a new callback to track the mouse movement and set the current canvas as an active prop because it is required to capture the drag event happening on it. + +.. image:: https://user-images.githubusercontent.com/64432063/182432684-abd015e5-b63d-4aab-b6a5-c8ba5dab3252.gif + :width: 400 + :align: center + +I had to look for some ways by which we could make the icons look smoother. For this, I created an icon test file, which consisted of a set of icons of varying scales. Then on these icons, I used some vtkTexture methods discussed in the meeting, such as ``MipmapOn`` and ``InterpolateOn``. You can see some differences in the icons below: + +.. image:: https://user-images.githubusercontent.com/64432063/182910990-fe4934ee-4201-4c3c-8ab4-1a4f7bfa9276.png + :width: 600 + :align: center + +Did you get stuck anywhere? +--------------------------- +It took some time to get settled with all the things as my college reopened. +I was trying to use shaders with the UI elements to implement the freehand drawing, but then my mentors suggested that I should look into the tracer widget in the VTK. + +What is coming up next? +----------------------- +Updating PR `#623`_ to keep `rotation_slider` on the top of the screen. +Looking into various vtk tracer widgets to see if we can use that to create freehand drawings. + +.. _`#623`: https://github.com/fury-gl/fury/pull/623 diff --git a/v0.10.x/_sources/posts/2022/2022-08-01-week-7-mohamed.rst.txt b/v0.10.x/_sources/posts/2022/2022-08-01-week-7-mohamed.rst.txt new file mode 100644 index 000000000..bbd9633a0 --- /dev/null +++ b/v0.10.x/_sources/posts/2022/2022-08-01-week-7-mohamed.rst.txt @@ -0,0 +1,40 @@ +Week 7: Billboard spheres and implementing interpolators using closures +======================================================================= + +.. post:: August 1 2022 + :author: Mohamed Abouagour + :tags: google + :category: gsoc + + +What did you do this week? +-------------------------- + +- Restructured the keyframe animation interpolators using closures to be functions instead of classes `#647`_. Now it is easier to implement new interpolators with the help of the functions existing in `fury/animation/helpers.py`_. Also, now unit tests can be added for the latter functions. + +- Added two examples explaining how to implement a custom interpolator that can be used by the ``Timeline``, one using `classes`_ and the other using `closures`_. + +- Fixed rotation issue that Shivam discovered while using the ``Timeline`` to animate glTF models. So, rotation in VTK is done by rotating first around Z-axis, then X-axis, then finally around Y-axis, which was not the order I was using to convert from quaternions to Euler degrees. + +- Made changes requested by Javier and Filipi on the billboards using geometry shader `PR`_, and made an example of how to use this billboard to show an impostor sphere which looks almost like a real high poly sphere. Also benchmarked using this version of billboard vs using a quad-based billboard, and how they both affect the FPS of the animation. + + .. raw:: html + + + +What is coming up next week? +---------------------------- +- Document the new closure-based interpolators. And make some slight renaming changes that we discussed in today's meeting. +- Add tests to the functions inside `fury/animation/helpers.py`_. +- Make changes to the geometry-shader-based billboard to make it more like the quad-based billboard actor while maintaining the new features. +- Integrate the already-implemented shader functionality to the new ``Timeline`` in a separate draft or PR. + +Did you get stuck anywhere? +--------------------------- +I got stuck trying to get and modify the vertices (centers) of the billboard actor. + +.. _`PR`: https://github.com/fury-gl/fury/pull/631 +.. _`#647`: https://github.com/fury-gl/fury/pull/647 +.. _`fury/animation/helpers.py`: https://github.com/fury-gl/fury/blob/670d3a41645eb7bcd445a7d8ae9ddd7bebc376b7/fury/animation/helpers.py +.. _`closures`: https://github.com/fury-gl/fury/blob/670d3a41645eb7bcd445a7d8ae9ddd7bebc376b7/docs/tutorials/05_animation/viz_keyframe_custom_interpolator.py +.. _`classes`: https://github.com/fury-gl/fury/blob/e0539269adc2a51e35282f83b8b0672bbe047a39/docs/tutorials/05_animation/viz_keyframe_custom_interpolator.py diff --git a/v0.10.x/_sources/posts/2022/2022-08-01-week-7-shivam.rst.txt b/v0.10.x/_sources/posts/2022/2022-08-01-week-7-shivam.rst.txt new file mode 100644 index 000000000..7195993aa --- /dev/null +++ b/v0.10.x/_sources/posts/2022/2022-08-01-week-7-shivam.rst.txt @@ -0,0 +1,40 @@ +Week 7 - Fixing bugs in animations +================================== + +.. post:: August 01 2022 + :author: Shivam Anand + :tags: google + :category: gsoc + + +What did you do this week? +-------------------------- + +- This week I started with implementing scaling to the animation example. + +- I had a meeting with Mohamed in which we discussed the rotation issue, and we found out that glTF uses ``Slerp`` interpolator instead of the ``LinearInterpolator``. Using ``Slerp`` interpolator for rotation fixed the rotation issue. + +- Another issue we faced was with the multi-actor system. Some actors weren't rotating or translating as intended. This was caused because the transformations were applied to the ``polydata`` before creating an actor; Mohamed suggested applying transformation after the actor is created from polydata (keeping the center to origin). + + + .. raw:: html + + + +Expected animation: `Interpolation Test Sample `_ + +- Created functions to return a list of animation timelines and apply them to the main timeline for keyframe animations. + +- ``CubicSpline`` has not been implemented to glTF animation yet since it works differently than other Interpolators (takes tangent input to smoothen the curve) but it'll be done before our next meeting. + + +What is coming up next week? +---------------------------- + +- Adding skinning animations support + + +Did you get stuck anywhere? +--------------------------- + +I still need to figure out how to apply the transformation matrix to the actor and not to the polydata. diff --git a/v0.10.x/_sources/posts/2022/2022-08-03-week-9-praneeth.rst.txt b/v0.10.x/_sources/posts/2022/2022-08-03-week-9-praneeth.rst.txt new file mode 100644 index 000000000..0bd170e63 --- /dev/null +++ b/v0.10.x/_sources/posts/2022/2022-08-03-week-9-praneeth.rst.txt @@ -0,0 +1,34 @@ +========================================= +Week 9 - Grouping and Transforming Shapes +========================================= + +.. post:: August 3 2022 + :author: Praneeth Shetty + :tags: google + :category: gsoc + + +What did you do this week? +-------------------------- +I started this week by creating a quick PR `#645 `_ for the UI sliders. The sliders raised ``ZeroDivsionError`` when the min and max values were the same. To solve this, I handled the case where the value_range becomes zero and then manually set the handle position to zero. + +Then I updated the implementation of the Grouping Shapes feature to support the translation and rotation of the shapes grouped together, as you can see below. + +.. image:: https://user-images.githubusercontent.com/64432063/183248609-4281087c-c930-4141-907a-5a906732524a.gif + :width: 400 + :align: center + +After this, I worked on the `PolyLine` and removed the extra point being added to the start of the `PolyLine` whenever a new instance was created. + +.. image:: https://user-images.githubusercontent.com/64432063/183280803-5d7ae350-f080-478d-8a2f-a71460037ea4.gif + :width: 400 + :align: center + +Did you get stuck anywhere? +--------------------------- +No, everything went well. + +What is coming up next? +----------------------- +Completing the PR `#623 `_ and `#653 `_. +Searching different approaches for implementing the freehand drawing. diff --git a/v0.10.x/_sources/posts/2022/2022-08-09-week-08-shivam.rst.txt b/v0.10.x/_sources/posts/2022/2022-08-09-week-08-shivam.rst.txt new file mode 100644 index 000000000..5efb197ee --- /dev/null +++ b/v0.10.x/_sources/posts/2022/2022-08-09-week-08-shivam.rst.txt @@ -0,0 +1,40 @@ +Week 8 - Fixing animation bugs +============================== +.. post:: August 10 2022 + :author: Shivam Anand + :tags: google + :category: gsoc + + +What did you do this week? +-------------------------- + +This week I had to fix the transformation issue in glTF animation. As discussed in the last meeting, I disabled vertex transformation and applied the transformation after the actor was formed. + +- Creating transformation matrix using the TRS data from nodes. +- Extract Translation, Rotation, and Scale matrices from the transformation matrix. + + .. raw:: html + + + +I also started investigating more on the skinning animation. + +- I created functions to extract and apply the ``InvertBindMatrices`` to the vertices. +- Also, applying the ``globalTransformMatrices`` to the mesh. + + +What is coming up next week? +---------------------------- + +- Skeletal animations support + + +Did you get stuck anywhere? +--------------------------- + +- Even after applying the transformation to the actor, after it's created. Some models did not behave as intended. We still need to figure this issue out and fix it. + + .. raw:: html + + diff --git a/v0.10.x/_sources/posts/2022/2022-08-09-week-8-mohamed.rst.txt b/v0.10.x/_sources/posts/2022/2022-08-09-week-8-mohamed.rst.txt new file mode 100644 index 000000000..01ce7ebc0 --- /dev/null +++ b/v0.10.x/_sources/posts/2022/2022-08-09-week-8-mohamed.rst.txt @@ -0,0 +1,37 @@ +Week 8: Back to the shader-based version of the `Timeline` +========================================================== + +.. post:: August 9 2022 + :author: Mohamed Abouagour + :tags: google + :category: gsoc + + +What did you do this week? +-------------------------- + +- First, I made some modifications to the main animation PR. Then as Filipi requested, I integrated the vertex shader that I was implementing a few weeks ago to work with the new improved version of the ``Timeline``. + +- As for how keyframes are sent to the GPU, the method being used is to send the needed keyframes for each draw. This is heavy because we only roll out the interpolation part, which with linear or step interpolation won't make any difference! Instead, I tried setting all the keyframes at once as a GLSL variable using string manipulation before animation starts. This also was slow to initialize, and the shader was getting bigger and slower to bind and unbind. To solve this problem, I made a uniform that holds all the keyframes of the animation and sent data as vectors, which was faster than string manipulation, also it was faster to render since data are now stored directly in memory, and the shader program was a lot more compact. But this method had an issue; uniforms do not keep data stored as expected! If two or more actors have the same uniform name in their shader program and only one of them was set, the other actor will get this value as well. A way around this is to change the names of the uniforms so that they maintain their data. + +- Tested animating 160K billboard spheres animation but this time using translation as well. And they performed very well. + + .. raw:: html + + + + +What is coming up next week? +---------------------------- + +- Fix issues I encountered this week working with GLSL shaders. + +- Implement slerp in GLSL as well as figure out a way to optimize sending keyframes to the shader program. + +- Figure a way to animate primitives of the same actor by different timelines. + + +Did you get stuck anywhere? +--------------------------- + +I had two issues, one mentioned above which was uniforms not being able to hold data. The second one is that VTK does not send specular-related uniforms and ``lightColor0`` to the ``point`` primitive, which are needed for light calculations. diff --git a/v0.10.x/_sources/posts/2022/2022-08-10-week-10-praneeth.rst.txt b/v0.10.x/_sources/posts/2022/2022-08-10-week-10-praneeth.rst.txt new file mode 100644 index 000000000..9ccc27a64 --- /dev/null +++ b/v0.10.x/_sources/posts/2022/2022-08-10-week-10-praneeth.rst.txt @@ -0,0 +1,40 @@ +======================================================== +Week 10 - Understanding Codes and Playing with Animation +======================================================== + +.. post:: August 10 2022 + :author: Praneeth Shetty + :tags: google + :category: gsoc + + +What did you do this week? +-------------------------- +I started working on the PR `#645 `_ created last week and tested a few more corner cases such as What happens if the maximum value is exceeded?? What if we give a value less than the minimum value range?? +Most of these worked as intended. + +Then I moved on to `vtkImageTracer`, I tried implementing this locally. It required an ImageSource on which the tracing was done. As you can see below, I managed to implement the pure VTK version of the widget. After this, I tried integrating this with FURY and besides the ImageSource all things were successfully handled by FURY. + +.. image:: https://user-images.githubusercontent.com/64432063/185802405-b289dbc9-08a3-496a-8cc4-ef8c4d40bf60.gif + :width: 400 + :align: center + +As per the suggestions from the mentors, I started looking at the implementation of the `vtkImageTracer `_ to see how they manage the widget. My prior experience with C++ helped me a lot with this because the original implementation of vtk is in C++. + +Here, I found an approach similar to the polyline. They first grab the current point, check whether it's inside the area, and then use the last point to draw a line by calculating some kind of motion vector. + +Using the Animation Architecture created by Mohamed, I created a Bouncing Text Animation using UI elements to check the compatibility of the UI System with the Animation. + +`Bouncing text animation: `_ + +.. image:: https://user-images.githubusercontent.com/64432063/185803066-70e320de-0777-478d-87bf-30767b02efe2.gif + :width: 400 + :align: center + +Did you get stuck anywhere? +--------------------------- +Proper tutorials weren't there to implement `vtkImageTracer`, which took time to make it work locally. + +What is coming up next? +----------------------- +Working on the Freehand Drawing. diff --git a/v0.10.x/_sources/posts/2022/2022-08-16-week-9-mohamed.rst.txt b/v0.10.x/_sources/posts/2022/2022-08-16-week-9-mohamed.rst.txt new file mode 100644 index 000000000..8687bd3ab --- /dev/null +++ b/v0.10.x/_sources/posts/2022/2022-08-16-week-9-mohamed.rst.txt @@ -0,0 +1,39 @@ +Week 9: Animating primitives of the same actor +============================================== + +.. post:: August 16 2022 + :author: Mohamed Abouagour + :tags: google + :category: gsoc + + +What did you do this week? +-------------------------- + +- Made two tutorials in this `PR`_ that show two approaches on how to animate primitives of the same FURY actor using the ``Timeline``. + + .. raw:: html + + + +- Tried sending all keyframes at once as uniforms, but I faced a performance issue doing this. + +- Set uniforms that are not being sent by VTK for the billboard actor. + + +What is coming up next week? +---------------------------- + +- Alter the ``Timeline`` to use matrices instead of setting values directly to allow hierarchical transformation. + +- Improve the API of the ``PartialActor`` to act almost like a normal actor. + + +Did you get stuck anywhere? +--------------------------- + +I had some issues trying to get shader’s uniforms to hold their data, and solving this issue led to another issue, which was a performance issue. + + + +.. _`PR`: https://github.com/fury-gl/fury/pull/660 diff --git a/v0.10.x/_sources/posts/2022/2022-08-17-week-09-shivam.rst.txt b/v0.10.x/_sources/posts/2022/2022-08-17-week-09-shivam.rst.txt new file mode 100644 index 000000000..c6354f0f1 --- /dev/null +++ b/v0.10.x/_sources/posts/2022/2022-08-17-week-09-shivam.rst.txt @@ -0,0 +1,36 @@ +Week 9 - First working skeletal animation prototype +=================================================== +.. post:: August 17 2022 + :author: Shivam Anand + :tags: google + :category: gsoc + + +What did you do this week? +-------------------------- + +- This week I had the first working `example`_ of skeletal animation ready. I was able to render the `SimpleSkin`_ model. Here's a quick preview: + + .. raw:: html + + + +- I wrote a custom `interpolator`_ (just like the tangent cubic spline interpolator) for interpolating two transformation matrices. + + +What is coming up next week? +---------------------------- + +- Generalising the skinning code to work with other models as well (it supports only the ``SimpleSkin`` model as of now). +- Creating a custom interpolator to interpolate more than 4 matrices at once. + + +Did you get stuck anywhere? +--------------------------- + +No, I didn't get stuck this week. + + +.. _`SimpleSkin`: https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0/SimpleSkin +.. _`example`: https://github.com/xtanion/fury/blob/gltf-skin-test/docs/tutorials/01_introductory/viz_skinning.py +.. _`interpolator`: https://github.com/xtanion/fury/blob/e5b2b9b4984f244fb4a8e8b410d494ba7d17cb49/fury/gltf.py#L684 diff --git a/v0.10.x/_sources/posts/2022/2022-08-17-week-11-praneeth.rst.txt b/v0.10.x/_sources/posts/2022/2022-08-17-week-11-praneeth.rst.txt new file mode 100644 index 000000000..c68a0f86d --- /dev/null +++ b/v0.10.x/_sources/posts/2022/2022-08-17-week-11-praneeth.rst.txt @@ -0,0 +1,32 @@ +============================================== +Week 11 - Creating a base for Freehand Drawing +============================================== + +.. post:: August 17 2022 + :author: Praneeth Shetty + :tags: google + :category: gsoc + + +What did you do this week? +-------------------------- +This week I tried to imitate the working of `vtkImageTracer`. Previously, I had created a small prototype for freehand drawing by adding points at the mouse position (which you can check out `here `_). As mentioned, there were some drawback of this method. +So to overcome these issues, I tried combining both methods. Considering points using the previous method and instead of adding points I tried creating lines between them which looks promising. Below you can see a demo. + +`Freehand Drawing: `_ + +.. image:: https://user-images.githubusercontent.com/64432063/186952329-636a0d81-6631-4e8d-9486-9a8c5e88a9a7.gif + :width: 400 + :align: center + +While doing this, I started working on how I could efficiently draw the lines and smoothen them out. My mentors referred me `this `_ to learn more about constructing and rendering lines. + +Along with this, I updated a few tests and some small bugs in PR `#623 `_ and `#653 `_. + +Did you get stuck anywhere? +--------------------------- +No, I didn't get stuck anywhere. + +What is coming up next? +----------------------- +Enhancing the freehand drawing feature. diff --git a/v0.10.x/_sources/posts/2022/2022-08-23-week-10-mohamed.rst.txt b/v0.10.x/_sources/posts/2022/2022-08-23-week-10-mohamed.rst.txt new file mode 100644 index 000000000..cab7626d6 --- /dev/null +++ b/v0.10.x/_sources/posts/2022/2022-08-23-week-10-mohamed.rst.txt @@ -0,0 +1,51 @@ +Week 10: Supporting hierarchical animating +========================================== + +.. post:: August 23 2022 + :author: Mohamed Abouagour + :tags: google + :category: gsoc + + +What did you do this week? +-------------------------- + +- Implemented hierarchical order support for animations using matrices in this `PR`_. + +- Improved the API of a `PartialActor`_ by adding some methods to control the scales, positions and colors. + +- Added a new example of using the new hierarchical feature to animate an arm robot. + + .. raw:: html + + + +- Improved `vector_text`_ a little by adding options to control its direction. + + +What is coming up next week? +---------------------------- + +- Finish the hierarchical order animation support `PR`_. + +- Explain tutorials in more detail. See this `issue`_. + +- Fix issues discovered by Serge in this `review`_. + +- Fix ``lightColor0`` being `hard-set`_ to ``(1, 1, 1)``. Instead, find a way to get this property the same way other polygon-based actor gets it. + +- Try to get PRs and issues mentioned above merged, closed or ready for a final review. + + +Did you get stuck anywhere? +--------------------------- + +I didn't get stuck this week. + + +.. _`PR`: https://github.com/fury-gl/fury/pull/665 +.. _`PartialActor`: https://github.com/fury-gl/fury/pull/660 +.. _`vector_text`: https://github.com/fury-gl/fury/pull/661 +.. _`review`: https://github.com/fury-gl/fury/pull/647#pullrequestreview-1061261078 +.. _`issue`: https://github.com/fury-gl/fury/issues/664 +.. _`hard-set`: https://github.com/fury-gl/fury/blob/464b3dd3f5be5159f5f9617a2c7b6f7bd65c0c80/fury/actor.py#L2395 diff --git a/v0.10.x/_sources/posts/2022/2022-08-24-week-12-praneeth.rst.txt b/v0.10.x/_sources/posts/2022/2022-08-24-week-12-praneeth.rst.txt new file mode 100644 index 000000000..f12fa4548 --- /dev/null +++ b/v0.10.x/_sources/posts/2022/2022-08-24-week-12-praneeth.rst.txt @@ -0,0 +1,38 @@ +====================================================== +Week 12 - Fixing translating issues and updating tests +====================================================== + +.. post:: August 24 2022 + :author: Praneeth Shetty + :tags: google + :category: gsoc + + +What did you do this week? +-------------------------- +I started with updating the tests for PR `#623 `_ as some of the tests weren't covering all the aspects in the code. +Previously I was just creating the ``DrawShape`` and adding it to the scene but now I had to analyze the scene to see whether they were properly added or not. + +Then I moved on to PR `#653 `_ to resolve the clamping issue. As you can see below, the shapes overlappes when they move nearer to the panel border. + +.. image:: https://user-images.githubusercontent.com/64432063/187023615-d7c69904-4925-41b1-945d-b5993c20c862.gif + :width: 400 + :align: center + +To solve this, I am thinking of calculating the center of the group and clipping it according to the panel, which may give us the required result. I tried doing the same, and it worked partially. + +.. image:: https://user-images.githubusercontent.com/64432063/187023880-84e13dab-313b-49e4-9b06-df5465c9d762.gif + :width: 400 + :align: center + +As we can see above, the shapes are kind of clamping but there's some issue with positioning. It would be good to go once this is fixed. + +Along this, I tried to integrate shaders with the ``Rectangle2D`` but there's something which I am missing. When I tried executing that program, it executed successfully but I am not getting the desired output. I tried debugging the code as well using the `debug` flag on the `shader_to_actor` function but still, it doesn't throw any error. + +Did you get stuck anywhere? +--------------------------- +While updating the tests for PR `#623 `_ the quad shape wasn't getting analyzed by the `analyse_snapshot` method. I tried various approaches to fix it, but it didn't work. + +What is coming up next? +----------------------- +Merging the PRs `#623 `_, `#653 `_ and working on the freehand drawing. diff --git a/v0.10.x/_sources/posts/2022/2022-08-25-week-10-shivam.rst.txt b/v0.10.x/_sources/posts/2022/2022-08-25-week-10-shivam.rst.txt new file mode 100644 index 000000000..5ff7aed47 --- /dev/null +++ b/v0.10.x/_sources/posts/2022/2022-08-25-week-10-shivam.rst.txt @@ -0,0 +1,43 @@ +Week 10 - Multi-node skinning support +===================================== + +.. post:: August 25 2022 + :author: Shivam Anand + :tags: google + :category: gsoc + + +What did you do this week? +-------------------------- + +As we figured out that the ``SimpleSkin`` model is not animated as intended. This week I started working with that model; +I figured out that we need to apply the InverseBindMatrix to each timer callback. I had a hard time figuring out what inverse bind matrix actually does. +Here's a good `blog `_ that answers that. + +**In short: The InverseBindMatrix "undoes" any transformation that has already been applied to your model in its bind pose.** Note: Inverse bind matrix shouldn't be applied with weights. + +- I got the ``SimpleSkin`` model to work perfectly. Here's a preview: + + .. raw:: html + + + +- Support for multiple transformations is still missing. However ``RiggedSimple`` is also working fine, except that It doesn't interpolate translation and scaling matrices. + + .. raw:: html + + + + + +What is coming up next week? +---------------------------- + +- Adding tests and adding support for combining transformation matrices for the same timestamp. +- Write an Interpolator that applies skinning to the mesh internally. + + +Did you get stuck anywhere? +--------------------------- + +No, I didn't get stuck this week. diff --git a/v0.10.x/_sources/posts/2022/2022-08-30-week-11-mohamed.rst.txt b/v0.10.x/_sources/posts/2022/2022-08-30-week-11-mohamed.rst.txt new file mode 100644 index 000000000..dec1f633b --- /dev/null +++ b/v0.10.x/_sources/posts/2022/2022-08-30-week-11-mohamed.rst.txt @@ -0,0 +1,41 @@ +Week 11: Improving tutorials a little +===================================== + +.. post:: August 30 2022 + :author: Mohamed Abouagour + :tags: google + :category: gsoc + + +What did you do this week? +-------------------------- + +- Fixed some issues in the hierarchical order animation support `PR`_ that we discussed during last week's meeting (mostly naming issues). + +- Explained the introductory tutorial a little. But it is not suitable for beginners. So, I will spend time improving tutorials this week. + +- Added extrusion to `vector_text`_ to allow the z-scaling to be functional. + +- Fixed ``lightColor0`` being `hard-set`_ to ``(1, 1, 1)``. Instead, it's now using the ``Scene`` to set the lighting uniforms. + + +What is coming up next week? +---------------------------- + + +- Improve tutorials. + +- Find out how to get the ``Scene`` from the actor instead of manually assigning it. + +- If I have time, I will try to implement recording animation as GIF or as a video. + + +Did you get stuck anywhere? +--------------------------- + +I didn't get stuck this week. + + +.. _`PR`: https://github.com/fury-gl/fury/pull/665 +.. _`vector_text`: https://github.com/fury-gl/fury/pull/661 +.. _`hard-set`: https://github.com/fury-gl/fury/blob/464b3dd3f5be5159f5f9617a2c7b6f7bd65c0c80/fury/actor.py#L2395 diff --git a/v0.10.x/_sources/posts/2022/2022-08-31-week-11-shivam.rst.txt b/v0.10.x/_sources/posts/2022/2022-08-31-week-11-shivam.rst.txt new file mode 100644 index 000000000..6b984c4b0 --- /dev/null +++ b/v0.10.x/_sources/posts/2022/2022-08-31-week-11-shivam.rst.txt @@ -0,0 +1,37 @@ +Week 11 - Multiple transformations support and adding tests +=========================================================== + +.. post:: August 31 2022 + :author: Shivam Anand + :tags: google + :category: gsoc + +What did you do this week? +-------------------------- + +As decided last week, I added support for multiple animations at the same timestamp. But this didn't solve the animation problems of ``RiggedSimple`` model. + +- I figured out that I was not applying the global transform of joints in the skinning matrix causing the joints to move to a new position. I referred to this `answer by irradicator `_. + +- We had to invert the multiplication order (ie, ``np.dot(skin_mat, vertex)`` instead of ``np.dot(vertex, skin_mat)``) for this model. We still need to figure out from where we get the multiplication order of the two. + + .. raw:: html + + + +- I also tried to create a custom Interpolator that does all calculations required for vertex skinning. However, we couldn't get this working. I got a few suggestions from Mohamed in our meeting, I'll try to implement those. + +- Added tests for animations. + + +What is coming up next week? +---------------------------- + +- Adding more tests. +- Fixing the Interpolator. +- Order of multiplication in the skinning matrix. + +Did you get stuck anywhere? +--------------------------- + +No, I didn't get stuck this week. diff --git a/v0.10.x/_sources/posts/2022/2022-08-31-week-13-praneeth.rst.txt b/v0.10.x/_sources/posts/2022/2022-08-31-week-13-praneeth.rst.txt new file mode 100644 index 000000000..4b0d09392 --- /dev/null +++ b/v0.10.x/_sources/posts/2022/2022-08-31-week-13-praneeth.rst.txt @@ -0,0 +1,34 @@ +========================================== +Week 13 - Separating tests and fixing bugs +========================================== + +.. post:: August 31 2022 + :author: Praneeth Shetty + :tags: google + :category: gsoc + + +What did you do this week? +-------------------------- +This week I managed to fix the translation issue in PR `#653 `_. This was happening because of the calculation error while repositioning the shapes. Now it works as intended. + +.. image:: https://user-images.githubusercontent.com/64432063/187058183-840df649-163e-44dd-8104-27d6c2db87a9.gif + :width: 400 + :align: center + +Also, the PR `#623 `_ got merged as now the tests were passing after the update. + +As we are now adding new features to the DrawPanel, the current tests are becoming bigger and bigger. +Due to this creating, debugging, and managing tests are becoming harder. +So to keep things simple, separating the tests to validate individual parts and features of the DrawPanel. This was done in PR `#674 `_. + +Along this, there was a redundant parameter called `in_progress`, which was used to keep a check whether the shapes are added to the panel or not, but it was confusing, and discarding it didn't affect the codebase. So PR `#673 `_ removed that parameter and separated the two functions. + + +Did you get stuck anywhere? +--------------------------- +Debugging the issue in PR `#653 `_ took most of the time this week. I had to manually calculate and check whether the calculations were correct or not. + +What is coming up next? +----------------------- +Currently, the borders around the shapes are not actually the borders, they are the bounding box of that shape. So I have to find out some ways to highlight the shapes when selected by the user. diff --git a/v0.10.x/_sources/posts/2022/2022-09-07-week-14-praneeth.rst.txt b/v0.10.x/_sources/posts/2022/2022-09-07-week-14-praneeth.rst.txt new file mode 100644 index 000000000..c4d067b19 --- /dev/null +++ b/v0.10.x/_sources/posts/2022/2022-09-07-week-14-praneeth.rst.txt @@ -0,0 +1,41 @@ +========================================= +Week 14 - Updating DrawPanel architecture +========================================= + +.. post:: September 7 2022 + :author: Praneeth Shetty + :tags: google + :category: gsoc + + +What did you do this week? +-------------------------- +This week I continued updating the DrawShape and DrawPanel. + +So as we can see below, whenever we create, translate, or rotate the shapes on the panel, it sometimes overlaps the `mode_panel` or `mode_text` which are used to select and show the current mode respectively. + +.. image:: https://user-images.githubusercontent.com/64432063/188268649-65ea24f0-3f46-4545-8e52-e07513a94b9f.gif + :width: 400 + :align: center + +To resolve this, I created a PR `#678 `_ which moves the `mode_panel` and the `mode_text` to be on the borders of the panel. + +.. image:: https://user-images.githubusercontent.com/64432063/188268804-949ec656-7da3-4310-ba8b-7e4f0281faa1.gif + :width: 400 + :align: center + +Along this, there were some similar functionalities in the `Grouping Shapes PR `_ and the `DrawShape` due to which some lines of code were repeating. To remove this duplicacy I created a PR `#679 `_ to move these functions to the `helper.py` file. + +Then I tried different ways of highlighting the shapes, + +1. To create a copy of the shape and scale it in the background so that it looks like a border or highlighted edges. + +2. Add yellow color to the shape so that it looks brighter. + +Did you get stuck anywhere? +--------------------------- +No, I didn't get stuck this week. + +What is coming up next? +----------------------- +Working on these new PRs to get them merged. Implement a highlighting feature. diff --git a/v0.10.x/_sources/posts/2022/2022-09-08-week-12-shivam.rst.txt b/v0.10.x/_sources/posts/2022/2022-09-08-week-12-shivam.rst.txt new file mode 100644 index 000000000..a470242bb --- /dev/null +++ b/v0.10.x/_sources/posts/2022/2022-09-08-week-12-shivam.rst.txt @@ -0,0 +1,47 @@ +Week 12 - Adding skeleton as actors and fix global transformation +================================================================= + +.. post:: September 08 2022 + :author: Shivam Anand + :tags: google + :category: gsoc + + +What did you do this week? +-------------------------- +- I started this week by fixing the segmentation fault for the skinning test. I could not fix this as of now. + +- I imported the ``RiggedFigure`` model into the Blender and I was quite impressed with how it visualizes each bone. So, I created a function that creates an arrow actor in place of a bone, and by applying the correct transformation, we get the bones of a model in place. Here's a quick preview of bones in Blender vs bones in FURY: + +.. image:: https://user-images.githubusercontent.com/74976752/189194609-e55f6285-b5ed-4eb3-9e78-5fb462fb2dee.png + :width: 500 + :align: center + +.. image:: https://user-images.githubusercontent.com/74976752/189195853-5b1f8945-9822-48f5-8d55-f13e822a43a7.png + :width: 500 + :align: center + +- After having the bones actor, I noticed that some bones are not aligned correctly. It was happening due to multiplication of the same transformation matrix twice. + +- I also created a function that calculates the total transformation of a node, it eliminates the need to use ``timeline.get_value`` in ``get_skin_timeline`` function. + + +What is coming up next week? +---------------------------- + +- It seems like I fixed everything, but we are not getting the correct model at timestamp 0. We need to find the cause and fix it! + +- Cleaning the Simple Animation PR `#643`_, and merging it. + + +Did you get stuck anywhere? +--------------------------- + +- While applying the timeline, we were getting the identity matrix for timestamp 0.0s, it was set to a new value before. We figured this in our meeting that it's happening due to some model's animation not starting from 0.0s. + +.. image:: https://user-images.githubusercontent.com/74976752/189196234-b28f86f7-223b-40e4-94bf-2ec18d914487.png + :width: 400 + :align: center + + +.. _`#643`: https://github.com/fury-gl/fury/pull/643/ diff --git a/v0.10.x/_sources/posts/2022/2022-09-14-week-15-praneeth.rst.txt b/v0.10.x/_sources/posts/2022/2022-09-14-week-15-praneeth.rst.txt new file mode 100644 index 000000000..557c7fc8a --- /dev/null +++ b/v0.10.x/_sources/posts/2022/2022-09-14-week-15-praneeth.rst.txt @@ -0,0 +1,37 @@ +================================= +Week 15 - Highlighting DrawShapes +================================= + +.. post:: September 14 2022 + :author: Praneeth Shetty + :tags: google + :category: gsoc + + +What did you do this week? +-------------------------- +This week I started with highlighting the shapes. As discussed earlier, I had two ways, but while implementing them, I found out both ways aren't that good to continue with. +The first way in which we thought of creating the scaled shapes in the background had an issue with the stacking. The border(blue rectangle) and the shape(grey rectangle) both seem to look like different shapes just grouped together as shown below. + +.. image:: https://user-images.githubusercontent.com/64432063/192321622-964cef6e-f965-4a24-8dcf-0b899fe5e387.gif + :width: 400 + :align: center + +While playing around with the second way, which was to add yellow color to the shape to make it brighter, it was difficult to identify which shape was selected. Also sometimes instead of making it brighter the addition of color created a new color which again confused the user. +After discussing these issues my mentors suggested having a user-defined highlight color that will be shown whenever the shape is selected. + +.. image:: https://user-images.githubusercontent.com/64432063/192326416-4454718d-1dda-4a13-9f97-07387a50a580.gif + :width: 400 + :align: center + +Along this, we were also trying to integrate shaders to the Actor2D (i.e. the UI elements) but there were some issues with it. I used `this `_ shaders example as a starting point and just replaced the `utah` actor by Rectangle2D actor. This program executed successfully without any errors, but it didn't give the required output. + +So instead of wasting time searching for how it is done, we thought it would be great if we directly ask in the VTK discourse forum. For this, I had to create a minimalistic pure VTK code. You can check out my code as well as the post `here `_. + +Did you get stuck anywhere? +--------------------------- +No, I didn't get stuck this week. + +What is coming up next? +----------------------- +Working on the rotation slider and the polyline. diff --git a/v0.10.x/_sources/posts/2022/2022-09-15-week-13-blog.rst.txt b/v0.10.x/_sources/posts/2022/2022-09-15-week-13-blog.rst.txt new file mode 100644 index 000000000..3d8088c59 --- /dev/null +++ b/v0.10.x/_sources/posts/2022/2022-09-15-week-13-blog.rst.txt @@ -0,0 +1,43 @@ +Week 13 - Multi-bone skeletal animation support +=============================================== + +.. post:: September 15 2022 + :author: Shivam Anand + :tags: google + :category: gsoc + + +What did you do this week? +-------------------------- + +This week I fixed all the issues with skeletal animations, and we got to see our first render of skeletal animation :). + +- Implemented a hierarchical timeline system (i.e., one timeline for each bone, and the timeline will contain its parent timeline in a hierarchy). + +- I figured out that we don't need to apply the parent transform as we're applying it to the vertex data while forming the actor. So the skin matrix becomes +``SkinMatrix = InverseBindPose * BoneDeform`` where ``BoneDeform = CurrentBoneTransform * ParentBonetransform``. + +Here's a preview using the ``CesiumMan`` model: + + .. raw:: html + + + + +What is coming up next week? +---------------------------- + +- Add tests for simple animation PR `#643`_. + +- Multiple actor support for skeletal animation. + +- Take a look at Morphing. + + +Did you get stuck anywhere? +--------------------------- + +- No, I didn't get stuck this week. + + +.. _`#643`: https://github.com/fury-gl/fury/pull/643/ diff --git a/v0.10.x/_sources/posts/2022/2022-09-20-week-13-mohamed.rst.txt b/v0.10.x/_sources/posts/2022/2022-09-20-week-13-mohamed.rst.txt new file mode 100644 index 000000000..11f5eb6c2 --- /dev/null +++ b/v0.10.x/_sources/posts/2022/2022-09-20-week-13-mohamed.rst.txt @@ -0,0 +1,41 @@ +Week 13: Keyframes animation is now a bit easier in FURY +======================================================== + +.. post:: September 20 2022 + :author: Mohamed Abouagour + :tags: google + :category: gsoc + + +What did you do this week? +-------------------------- + +- Added the ability to have the ShowManager stored inside the Timeline. That way the user does not have to update and render the animations because it will be done internally. + +- Added a record method to the Timeline that records the animation and saves it as either GIF or MP4 (requires OpenCV). This record functionality has the option to show/hide the PlaybackPanel which makes it better than recording the animation using a third-party software. + + .. image:: https://user-images.githubusercontent.com/63170874/190892795-f47ceaf1-8dd0-4235-99be-2cf0aec323bb.gif + :width: 600 + :align: center + +- Fixed some issues that Serge mentioned while reviewing PR `#665`_. + + +What is coming up next week? +---------------------------- + +- Instead of adding the ShowManager to the Timeline, doing it the other way around is a better choice and makes the code more readable. + +- Add tests for the Timeline's record method. + +- Add tests for the billboard actor to test consistency among different approaches.. + + +Did you get stuck anywhere? +--------------------------- + +I didn't get stuck this week. + + + +.. _`#665`: https://github.com/fury-gl/fury/pull/665 diff --git a/v0.10.x/_sources/posts/2022/2022-09-21-week-16-praneeth.rst.txt b/v0.10.x/_sources/posts/2022/2022-09-21-week-16-praneeth.rst.txt new file mode 100644 index 000000000..3b3b715c7 --- /dev/null +++ b/v0.10.x/_sources/posts/2022/2022-09-21-week-16-praneeth.rst.txt @@ -0,0 +1,34 @@ +================================= +Week 16 - Working with Rotations! +================================= + +.. post:: September 21 2022 + :author: Praneeth Shetty + :tags: google + :category: gsoc + + +What did you do this week? +-------------------------- +Last week my mentors noticed that each `DrawShape` has its individual `rotation_slider` which increases redundancy and complexity in setting its visibility on and off. Instead, they suggested moving the `rotation_slider` to `DrawPanel` and keeping a common slider for all the shapes. + +PR `#688 `_ does the above mentioned thing. +There isn't any visual difference as everything is as it was earlier, just the code was modified a bit to make it work properly. + +After this, I started working with the rotation for the `Polyline` feature. For rotating the `Polyline`, I implemented something similar to what I had did while rotating the individual shapes. Firstly I calculate the bounding box and the center of the shape, then apply the rotation to the points through which the polyline was generated. + +`Polyline: `_ + +.. image:: https://user-images.githubusercontent.com/64432063/193308748-6bc14acb-b687-4d88-9c41-12991186a104.gif + :width: 400 + :align: center + +As we can see above the rotation seems correct but as earlier the shape is translating from its original center. This should be easy to fix. + +Did you get stuck anywhere? +--------------------------- +Instead of implementing the approaches for creating and managing the `Polyline`, I kept on thinking of various ideas on how I could do so, which wasted my time. I should have thought about some approaches and tried to implement them so that I would get an idea of whether things would work or not. + +What is coming up next? +----------------------- +Working on `Polyline` to make sure everything works fine. diff --git a/v0.10.x/_sources/posts/2022/2022-09-28-week-14-mohamed.rst.txt b/v0.10.x/_sources/posts/2022/2022-09-28-week-14-mohamed.rst.txt new file mode 100644 index 000000000..066943004 --- /dev/null +++ b/v0.10.x/_sources/posts/2022/2022-09-28-week-14-mohamed.rst.txt @@ -0,0 +1,38 @@ +Week 14: Keyframes animation is now a bit easier in FURY +======================================================== + +.. post:: September 28 2022 + :author: Mohamed Abouagour + :tags: google + :category: gsoc + + +What did you do this week? +-------------------------- + +- Separated the ``Timeline`` into a ``Timeline`` and an ``Animation``. So, instead of having the ``Timeline`` do everything. It's now more like doing animations in Blender and other 3D editing software where the timeline handles the playback of several animations `#694`_. + +- Added unit tests for the billboards based on geometry shader. + +- Tried to solve the issue with actors not being rendered when their positions are changed in the vertex shader. For now, I just found a way to force invoke the shader callbacks, but force rendering the actor itself still needs more investigation. + + +What is coming up next week? +---------------------------- + +- Add unit testing for the ``Animation``, document it well, and implement more properties suggested by Shivam (@xtanion). + +- Modify `Add Timelines to ShowManager directly`_ PR to allow adding ``Animation`` to the ``ShowManager`` as well. + +- Update tutorials to adapt to all the new changes in the ``animation`` module. + + +Did you get stuck anywhere? +--------------------------- + +- I got stuck trying to solve the issue mentioned above with actors not being rendered. + + + +.. _`#694`: https://github.com/fury-gl/fury/pull/694 +.. _`Add Timelines to ShowManager directly`: https://github.com/fury-gl/fury/pull/690 diff --git a/v0.10.x/_sources/posts/2022/2022-09-28-week-14-shivam.rst.txt b/v0.10.x/_sources/posts/2022/2022-09-28-week-14-shivam.rst.txt new file mode 100644 index 000000000..59aa644ec --- /dev/null +++ b/v0.10.x/_sources/posts/2022/2022-09-28-week-14-shivam.rst.txt @@ -0,0 +1,49 @@ +Week 14 - Morphing is here! +=========================== + +.. post:: September 28 2022 + :author: Shivam Anand + :tags: google + :category: gsoc + + +What did you do this week? +-------------------------- + +- This week, I started with multiple actor support in skinning and managed to do it + successfully. Here's the preview using the BrainStem model. + +.. raw:: html + + + +- Implementing multiple animation channels support (as seen in the ``Fox`` model). The ``get_skin_timelines()`` method now returns a dictionary of all animation channels with Timeline as their value. + +- We merged two PRs, `#689`_ (colors from Material) and `#643`_ (simple animations). + +- Added ability to load morphing information and create timelines from it. Here's a preview of the ``AnimatedMorphCube`` and ``AnimatedMorphSphere`` models: + +.. raw:: html + + + + +What is coming up next week? +---------------------------- + +- Cleaning and Rebasing Skinning animation PR `#685`_. + +- Creating a PR for morphing code. + +- Multi primitive (actor) support in morphing. + + +Did you get stuck anywhere? +--------------------------- + +- No, I didn't get stuck this week. + + +.. _`#643`: https://github.com/fury-gl/fury/pull/643/ +.. _`#689`: https://github.com/fury-gl/fury/pull/689/ +.. _`#685`: https://github.com/fury-gl/fury/pull/685/ diff --git a/v0.10.x/_sources/posts/2022/2022-09-7-week-12-mohamed.rst.txt b/v0.10.x/_sources/posts/2022/2022-09-7-week-12-mohamed.rst.txt new file mode 100644 index 000000000..2e72ce43c --- /dev/null +++ b/v0.10.x/_sources/posts/2022/2022-09-7-week-12-mohamed.rst.txt @@ -0,0 +1,33 @@ +Week 12: Adding new tutorials +============================= + +.. post:: September 7 2022 + :author: Mohamed Abouagour + :tags: google + :category: gsoc + + +What did you do this week? +-------------------------- + +- Restructured tutorials to be more readable and more focused on a specific topic. + +- Replaced the old animation introductory tutorial with a lot simpler one, and added tutorial to explain keyframes and interpolators. + +- Simplified setting lighting uniforms for the geometry-based-billboard actor by getting the ``Scene`` from the actor using ``actor.GetConsumer(scene_idx)``. + + +What is coming up next week? +---------------------------- + +- Allow the ``Timeline`` to take the ``ShowManager`` as an argument to reduce the amount of code the user has to write every time using FURY animations. + +- Fix some typos in the tutorials and write some info about ``Slerp``. + +- Find a way to fix the shader-callback problem of not being executed when the actor is out of the camera's frustum. + + +Did you get stuck anywhere? +--------------------------- + +I didn't get stuck this week. diff --git a/v0.10.x/_sources/posts/2023/2023-01-24-final-report-praneeth.rst.txt b/v0.10.x/_sources/posts/2023/2023-01-24-final-report-praneeth.rst.txt new file mode 100644 index 000000000..fdd6230bd --- /dev/null +++ b/v0.10.x/_sources/posts/2023/2023-01-24-final-report-praneeth.rst.txt @@ -0,0 +1,226 @@ +.. image:: https://developers.google.com/open-source/gsoc/resources/downloads/GSoC-logo-horizontal.svg + :height: 50 + :align: center + :target: https://summerofcode.withgoogle.com/programs/2022/projects/a47CQL2Z + +.. image:: https://www.python.org/static/community_logos/python-logo.png + :width: 40% + :target: https://summerofcode.withgoogle.com/programs/2022/organizations/python-software-foundation + +.. image:: https://python-gsoc.org/logos/FURY.png + :width: 25% + :target: https://fury.gl/latest/index.html + +Google Summer of Code Final Work Product +======================================== + +.. post:: January 24 2023 + :author: Praneeth Shetty + :tags: google + :category: gsoc + +- **Name:** Praneeth Shetty +- **Organisation:** Python Software Foundation +- **Sub-Organisation:** FURY +- **Project:** `FURY - Improve UI elements for drawing geometrical + shapes `_ + + +Proposed Objectives +------------------- + +- Visualization UI: + + - Drawing Geometrical Objects + - Moving Components + - Rotating Components + - Erasing Components + - Resizing Components + +- Stretch Goals: + + - Converting 2D shapes to 3D + +Objectives Completed +-------------------- + + +- **DrawPanel (previously known as Visualization UI)** + + ``DrawPanel`` is the parent component that contains and manages all the other sub-components to efficiently visualize the shapes. The main functions of the ``DrawPanel`` are capturing interactions from user, managing modes, drawing shapes and transforming them. The ``DrawPanel`` is mainly divided into three parts : + + i. **Main Panel** + It is the main background panel(``Panel2D``) on which the main interaction and visualization happen. Here user can interactively draw shapes, reposition and rotate them. This panel also defines the boundaries for the shapes. It can also be called as a container element as it contains all the shapes and other DrawPanel components. + ii. **Mode Panel** + It is a composite UI element consisting of the main panel(``Panel2D``) on which buttons(``Button2D``) are arranged which can toggle the current working mode. Each button has an icon associated with it which tries to depict the information about the mode. Here mode is nothing but the different channels which on selection can perform different tasks. Some of the modes present in the Mode Panel are discussed below: + - Selection: This mode is used to select an individual or group of shapes. + - Deletion: This mode is used to delete an individual or group of shapes. + - The modes mentioned below create an element on the Panel which is described below. + - Line + - Quad + - Circle + - Polyline + - Freehand drawing + - To activate any of these above mode the user has to click on the button with the respective icon present in the mode panel and then interact with the main panel. + iii. **Mode Text** It is a ``TextBlock2D`` which displays the current mode of the ``DrawPanel``. It automatically updates whenever the mode is changed. This helps the user to quickly identify which mode is he currently in. + + *Pull Requests:* + + - **Creating DrawPanel UI (Merged) :** + `https://github.com/fury-gl/fury/pull/599 `_ + + .. image:: https://user-images.githubusercontent.com/64432063/194766188-c6f83b75-82d1-455c-9be1-d2a1cada945a.png + :width: 400 + :align: center + +- **Drawing Shapes:** + + A new class called ``DrawShape`` was create to manage all the transformation and to handle the user interaction which are passed by the ``DrawPanel``. To create a shape the required mode can be selected from the mode panel and then on the left_mouse_click event the shape creation starts. Then to resize user needs to drag the mouse depending on how he wants the shape to be. These interactions follow WYSIWYG (What You See Is What You Get) principle. Currently, the following shapes are supported: + + 1. Line: Creates a line joining two points using ``Rectangle2D``. + 2. Quad: Creates a rectangle using ``Rectangle2D``. + 3. Circle: Create a Circle using ``Disk2D``. + 4. Polyline: Creates a chain of lines that can either end at the starting point and create a loop or remain an independent collection of lines. Individual line is created using ``Rectangle2D``. + + - **DrawPanel Feature: Polyline (Under Review) :** + `https://github.com/fury-gl/fury/pull/695 `__ + + 5. Freehand drawing: Here you can draw any freehand object something similar to doodling. Internally we use ``Polyline`` for doing this. + + - **DrawPanel Feature: Freehand Drawing (Under Review) :** + `https://github.com/fury-gl/fury/pull/696 `__ + + .. image:: https://user-images.githubusercontent.com/64432063/194773058-b074fde0-e2e1-4719-93e3-38a34032cd88.jpg + :width: 400 + :align: center + +- **Transforming Shapes:** + + Following transformation are supported by every ``DrawShape`` + + - **Translation** + + The translation is nothing but repositioning the shapes on the main panel. It is made sure that the shapes don't exceed the panel boundaries by clamping the new position between the panel bounds. All the UI elements have a center property which can be used to do the above-mentioned thing but the reference point of the Shape may change depending on how it was created. So to resolve this I created an interface that would calculate and return the bounding box data around the shape and which could be then used to reposition the shape on the panel. + + .. image:: https://user-images.githubusercontent.com/64432063/194772993-289e10bd-199d-4692-bcb0-5cccdb1b32fe.gif + :width: 400 + :align: center + + - **Rotation** + + Each ``DrawShape`` can be rotated from the center of that shape. Whenever you select a shape using the selection mode a rotation slider(RingSlider2D) appears at the lower right corner of the ``DrawPanel``. This rotation slider can be used to rotate the shapes by some specific angle which is displayed at the center of the slider. + + .. image:: https://user-images.githubusercontent.com/64432063/194773295-4303ec78-3f2b-44e5-8c85-ff01140a8c95.gif + :width: 400 + :align: center + + *Pull Requests:* + + - **DrawPanel Feature: Adding Rotation of shape from Center (Merged) :** + + `https://github.com/fury-gl/fury/pull/623 `__ + +- **Deleting Shapes:** + + Whenever we create anything it's never perfect we change, modify, and at last delete. Here too every DrawShape is never perfect so to delete the shapes we also have a delete option that can be chosen from the mode panel and by clicking the shape they are removed from the panel. + + .. image:: https://user-images.githubusercontent.com/64432063/194862464-387edc59-a942-4675-ab44-53c899e70e29.gif + :width: 400 + :align: center + +Other Objectives +---------------- + +- **Grouping Shapes** + + Many times we need to perform some actions on a group of shapes so here we are with the grouping feature using which you can group shapes together, reposition them, rotate them and delete them together. To activate grouping of shapes you have to be on selection mode then by holding **Ctrl** key select the required shapes and they will get highlighted. To remove shape from the group just hold the **Ctrl** and click the shape again it will get deselected. Then once everything is grouped you can use the normal transformation as normal i.e. for translation just drag the shapes around and for rotation the rotation slider appears at usual lower left corner which can be used. + + *Pull Requests:* + + - **DrawPanel Feature: Grouping Shapes (Under Review)** - `https://github.com/fury-gl/fury/pull/653 `__ + + .. image:: https://user-images.githubusercontent.com/64432063/194926770-e1031181-04c6-491b-89ca-275213060a13.gif + :width: 400 + :align: center + +- **Creating icons** + + As most of the things in the DrawPanel are visually seen, each mode also require some icons so that users easily understand the use of that mode, so to achieve this I have created some icons by using the pre-existing icons in the FURY. These icons are stored `here `__. Whenever FURY requires these icons they are fetched using the fetchers present in FURY. To fetch these new icons I created some new fetchers. + + *Pull Requests:* + + - **Adding new icons required for DrawPanel UI (Merged)** - `https://github.com/fury-gl/fury-data/pull/9 `__ + - **Creating a fetcher to fetch new icons (Merged)** - `https://github.com/fury-gl/fury/pull/609 `__ + - **Adding polyline icons (Merged)** - `https://github.com/fury-gl/fury-data/pull/10 `__ + - **Adding resize and freehand drawing icon (Merged)** - `https://github.com/fury-gl/fury-data/pull/11 `__ + - **Updating fetch_viz_new_icons to fetch new icons (Under Review)** - `https://github.com/fury-gl/fury/pull/701 `__ + + +- **Other PRs** + + - **Fixing ZeroDivisionError thrown by UI sliders when the value_range is zero (0) (Merged)**: `https://github.com/fury-gl/fury/pull/645 `__ + - **DrawPanel Update: Removing in_progress parameter while drawing shapes (Merged)**: `https://github.com/fury-gl/fury/pull/673 `__ + - **DrawPanel Update: Separating tests to test individual features (Merged)**: `https://github.com/fury-gl/fury/pull/674 `__ + - **DrawPanel Update: Repositioning the mode_panel and mode_text (Merged)**: `https://github.com/fury-gl/fury/pull/678 `__ + - **DrawPanel Update: Moving repetitive functions to helpers (Merged)**: `https://github.com/fury-gl/fury/pull/679 `__ + - **DrawPanel Update: Moving rotation_slider from DrawShape to DrawPanel (Under Review)**: `https://github.com/fury-gl/fury/pull/688 `__ + +Objectives in Progress +---------------------- + +- **Resizing Shapes:** + + Currently after the shape is created we can only transform it but we might need to resize it. To be able to resize I am currently using the borders of the shape itself. You can switch to resize mode and then select the shape. It would display the bounding box around the shape which act as interactive slider and resizes the shape as shown below. + + .. image:: https://user-images.githubusercontent.com/64432063/194775648-04c2fa7a-b22f-4dda-a73b-2f8161bb4f3a.gif + :width: 400 + :align: center + + - **DrawPanel Feature: Resizing Shapes (Under Development)**: `https://github.com/ganimtron-10/fury/blob/resize_shapes/fury/ui/elements.py `__ + +GSoC Weekly Blogs +----------------- + +- My blog posts can be found at `FURY website `__ + and `Python GSoC blog `__. + +Timeline +-------- + ++---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Date | Description | Blog Post Link | ++=====================+====================================================+===========================================================================================================================================================================================================+ +| Week 0(25-05-2022) | Pre-GSoC Journey | `FURY `__ - `Python `__ | ++---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 1(08-06-2022) | Laying the Foundation of DrawPanel UI | `FURY `__ - `Python `__ | ++---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 2(15-06-2022) | Improving DrawPanel UI | `FURY `__ - `Python `__ | ++---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 3(22-06-2022) | Dealing with Problems | `FURY `__ - `Python `__ | ++---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 4(29-06-2022) | Fixing the Clamping Issue | `FURY `__ - `Python `__ | ++---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 5(06-07-2022) | Working on new features | `FURY `__ - `Python `__ | ++---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 6(13-07-2022) | Supporting Rotation of the Shapes from the Center | `FURY `__ - `Python `__ | ++---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 7(20-07-2022) | Working on Rotation PR and Trying Freehand Drawing | `FURY `__ - `Python `__ | ++---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 8(27-07-2022) | Working on the polyline feature | `FURY `__ - `Python `__ | ++---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 9(03-08-2022) | Grouping and Transforming Shapes | `FURY `__ - `Python `__ | ++---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 10(10-08-2022) | Understanding Codes and Playing with Animation | `FURY `__ - `Python `__ | ++---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 11(17-08-2022) | Creating a base for Freehand Drawing | `FURY `__ - `Python `__ | ++---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 12(24-08-2022) | Fixing translating issues and updating tests | `FURY `__ - `Python `__ | ++---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 13(31-08-2022) | Separating tests and fixing bugs | `FURY `__ - `Python `__ | ++---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 14(07-09-2022) | Updating DrawPanel architecture | `FURY `__ - `Python `__ | ++---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 15(14-09-2022) | Highlighting DrawShapes | `FURY `__ - `Python `__ | ++---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 16(21-09-2022) | Working with Rotations! | `FURY `__ - `Python `__ | ++---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ diff --git a/v0.10.x/_sources/posts/2023/2023-01-29-final-report-mohamed.rst.txt b/v0.10.x/_sources/posts/2023/2023-01-29-final-report-mohamed.rst.txt new file mode 100644 index 000000000..68cf97c12 --- /dev/null +++ b/v0.10.x/_sources/posts/2023/2023-01-29-final-report-mohamed.rst.txt @@ -0,0 +1,265 @@ +.. role:: raw-html(raw) + :format: html + +.. raw:: html + +
gsoc
+ +.. raw:: html + +
+ + fury +
+ + + +Google Summer of Code Final Work Product +======================================== + +.. post:: January 29 2023 + :author: Mohamed Abouagour + :tags: google + :category: gsoc + +- **Name:** Mohamed Abouagour +- **Organisation:** Python Software Foundation +- **Sub-Organisation:** FURY +- **Project:** `FURY - Keyframe animations API `_ + + + +Proposed Objectives +------------------- + + +* Keyframe animations API + + * Basic playback functions, such as playing, pausing, and rewinding the timeline. + * Adding keyframes at a specific time for transformations of FURY actors and cameras such as translation, scale, rotation, color, and opacity. + * Implement quaternion-based interpolation (SLERP) + * Allow the camera to be interpolated by the keyframe system. + * Allow the creation and removal of actors from the scene according to the keyframes. + * Visualize the motion path of positional animation. + * Speed the animation using GLSL vertex and fragment shaders. + +Modified Objectives +------------------- + + +* Adding a playback panel for controlling the timeline. +* Billboard actor using the geometry shader. +* Hierarchical animation support. +* Animating primitives of the same Fury actor separately. +* Color interpolators. + +Objectives Completed +-------------------- + + +* + Keyframes Animation API + + + * ``Animation`` Class + * + The ``Animation`` class is the main part of the FURY animation module. It is responsible for keyframe animations for a single or a group of FURY actors. The ``Animation`` is able to handle multiple attributes and properties of Fury actors such as position, color, scale, rotation, and opacity. It is also capable of doing the following: + + + * Set animation keyframes and events. + * Animate custom properties. + * Support add-to-scene/remove-from-scene events. + * Can animate other animations (Hierarchical animation) + * Set or change the keyframes interpolation method. + * Visualize the motion path of the positional animation. + + + * ``Timeline`` Class + The ``Timeline`` is the player of FURY ``Animations``\ ; it controls the playback of one or more FURY animations. It also has the option to include a very useful playback panel to help control the playback of the animation. The ``Timeline`` can have a fixed length or get its duration from the animations added to it dynamically. It can loop, play once, change speed, play, pause, and stop. + + * + Keyframes Interpolators + Interpolation is also a core part of the keyframes animation. It is responsible for filling in the blanks between the keyframes so that we have transitional states between the set keyframes. Another factor is that interpolators must be super-optimized to interpolate data in a minimum amount of time as possible or else it would be the bottleneck that lags the animation. + The following interpolators have been implemented as a part of the keyframes animation API: + + + * Step Interpolator + * Linear Interpolator + * Spherical Linear Interpolator (Slerp) + * Spline Interpolator + * Cubic Spline Interpolator + * Cubic Bézier Interpolator + * Color Interpolators: + + * XYZ Color Interpolator + * Lab Color Interpolator + * HSV Color Interpolator + + .. image:: https://user-images.githubusercontent.com/63170874/217738142-2dba8f6a-f8ff-4231-babd-048055074cc0.gif + :align: center + :width: 560 + + + + .. image:: https://user-images.githubusercontent.com/63170874/190892795-f47ceaf1-8dd0-4235-99be-2cf0aec323bb.gif + :align: center + :width: 560 + + * Tutorials + Also included 11 tutorials demonstrating how the FURY keyframe animation API works and how to use it to make some interesting animations. These tutorial will be added soon to the FURY website. + Subjects explained in the tutorials are: + + * **Introduction** + * **Timeline** + * **Interpolators** + * **Camera Animation** + * **Hierarchical Animation** + * **Using Color Interpolators** + * **Using Bezier Interpolator** + * **Using Spline Interpolator** + * **Using time-based functions** + * **Creating Custom Interpolators** + * **Arm Robot Animation** + + *Pull Requests:* + + + * **Keyframe animations and interpolators (Merged):** https://github.com/fury-gl/fury/pull/647 + * **Separating the ``Timeline`` (Ready to be Merged):** https://github.com/fury-gl/fury/pull/694 + * **Timeline hierarchical transformation (Merged):** https://github.com/fury-gl/fury/pull/665 + * **Add Timelines to ShowManager directly (Ready to be Merged):** https://github.com/fury-gl/fury/pull/690 + * **Updating animation tutorials (Ready to be Merged):** https://github.com/fury-gl/fury/pull/680 + * **Record keyframe animation as GIF and MP4 (Under Development):** https://github.com/fury-gl/fury/pull/687 + +* + PlaybackPanel UI component + + At first, while in the early development stage of the FURY keyframe animation API, basic playback buttons were used to play, pause, and stop the animation. As the API kept growing, more controllers needed to be implemented, such as the time progress slider, the speed changer, and the loop toggle. And composing all of these controllers into a single UI element was inevitable. + While the PlaybackPanel is a main part of the ``Timeline``\ , the goal was to make it completely independent from the keyframes animation API so that it can be used for anything else, i.e. a video player actor or a continuous time simulation or any other time-dependent applications. + + + .. image:: https://user-images.githubusercontent.com/63170874/194377387-bfeeea2c-b4ee-4d26-82c0-b76c27fa0f90.png + :target: https://user-images.githubusercontent.com/63170874/194377387-bfeeea2c-b4ee-4d26-82c0-b76c27fa0f90.png + :alt: image + + + *Pull Requests:* + + + * **\ ``PlaybackPanel`` initial implementation (Merged):** https://github.com/fury-gl/fury/pull/647 + + * **Set position and width of the ``PlaybackPanel`` (Merged):** https://github.com/fury-gl/fury/pull/692 + + +* + Billboard actor using the geometry shader + Fury already has a billboard actor implemented using two triangles to construct the billboard. But the new approach uses only one vertex and the canvas of the billboard is generated by the geometry shader. This approach is faster in initialization since only the center is needed and no additional computations to generate the primitive on the CPU side. Also, animating these new billboards using the method mentioned above in the previous objective is way much faster, and faster is one of the reasons why we use billboards. + + *Pull Requests:* + + + * **billboards using geometry shader (Ready to be Merged):** https://github.com/fury-gl/fury/pull/631 + +Objectives in Progress +---------------------- + + +* + Animating primitives of the same FURY Actor separately + Animating FURY actors is not a problem and can be done easily using the FURY animation module. The problem appears when trying to animate a massive amount of actors, thousands or even hundreds of thousands of actors, it's impossible to do that using the animation module. Instead, primitives of the same actor can be animated by changing their vertices and then sending the new vertices buffer to the GPU. This also needs some discussion to find the cleanest way to implement it. + + *Pull Requests:* + + + * **Animating primitives of the same actor (Draft):** https://github.com/fury-gl/fury/pull/660 + * **Added primitives count to the polydata (Merged):** https://github.com/fury-gl/fury/pull/617 + +* + Speeding up the animation using GLSL shaders + Using the power of the GPU to help speed up the animations since some interpolators are relatively slow, such as the spline interpolator. Besides, morphing and skeletal animation would be tremendously optimized if they were computed on the GPU side! + + *Pull Requests:* + + + * **Adding shader support for doing the animations (Open):** https://github.com/fury-gl/fury/pull/702 + +Other Objectives +---------------- + + +* + Added more enhancements to the ``vector_text`` actor + Added the ability to change the direction of the ``vector_text`` actor, as well as giving it the option to follow the camera. Also added the option to extrude the text which makes it more like 3D text. + + *Pull Requests:* + + + * **Improving ``vector_text`` (Merged)** : https://github.com/fury-gl/fury/pull/661 + +* + Other PRs + + + * **Fixed multi_samples not being used (Merged)**\ : https://github.com/fury-gl/fury/pull/594 + * **Added an accurate way to calculate FPS (Merged)**\ : https://github.com/fury-gl/fury/pull/597 + * **Implemented two new hooks for UI sliders (Merged)**\ : https://github.com/fury-gl/fury/pull/634 + * **Fixed some old tutorials (Merged)**\ : https://github.com/fury-gl/fury/pull/591 + * **Returning the Timer id while initialization (Merged)**\ : https://github.com/fury-gl/fury/pull/598 + +* + GSoC Weekly Blogs + + + * My blog posts can be found on `the FURY website `_ and `the Python GSoC blog `_. + +Timeline +-------- + +.. list-table:: + :header-rows: 1 + + * - Date + - Description + - Blog Post Link + * - Week 0\ :raw-html:`
`\ (23-05-2022) + - My journey till getting accepted into GSoC22 + - `FURY `_ - `Python `_ + * - Week 1\ :raw-html:`
`\ (08-06-2022) + - Implementing a basic Keyframe animation API + - `FURY `_ - `Python `_ + * - Week 2\ :raw-html:`
`\ (28-06-2022) + - Implementing non-linear and color interpolators + - `FURY `_ - `Python `_ + * - Week 3\ :raw-html:`
`\ (04-07-2022) + - Redesigning the API,\ :raw-html:`
` Implementing cubic Bezier Interpolator,\ :raw-html:`
` and making progress on the GPU side! + - `FURY `_ - `Python `_ + * - Week 4\ :raw-html:`
`\ (11-07-2022) + - Camera animation, :raw-html:`
`\ interpolation in GLSL, and a single Timeline! + - `FURY `_ - `Python `_ + * - Week 5\ :raw-html:`
`\ (19-07-2022) + - Slerp implementation, :raw-html:`
`\ documenting the Timeline, and adding unit tests + - `FURY `_ - `Python `_ + * - Week 6\ :raw-html:`
`\ (25-07-2022) + - Fixing the Timeline issues and equipping it with\ :raw-html:`
` more features + - `FURY `_ - `Python `_ + * - Week 7\ :raw-html:`
`\ (01-08-2022) + - Billboard spheres and implementing interpolators\ :raw-html:`
` using closures + - `FURY `_ - `Python `_ + * - Week 8\ :raw-html:`
`\ (09-08-2022) + - Back to the shader-based version of the Timeline + - `FURY `_ - `Python `_ + * - Week 9\ :raw-html:`
`\ (16-08-2022) + - Animating primitives of the same actor + - `FURY `_ - `Python `_ + * - Week 10\ :raw-html:`
`\ (23-08-2022) + - Supporting hierarchical animating + - `FURY `_ - `Python `_ + * - Week 11\ :raw-html:`
`\ (30-08-2022) + - Improving tutorials a little + - `FURY `_ - `Python `_ + * - Week 12\ :raw-html:`
`\ (7-09-2022) + - Adding new tutorials + - `FURY `_ - `Python `_ + * - Week 13\ :raw-html:`
`\ (20-09-2022) + - Keyframes animation is now a bit easier in FURY + - `FURY `_ - `Python `_ diff --git a/v0.10.x/_sources/posts/2023/2023-01-29-final-report-shivam.rst.txt b/v0.10.x/_sources/posts/2023/2023-01-29-final-report-shivam.rst.txt new file mode 100644 index 000000000..4e4b5bbac --- /dev/null +++ b/v0.10.x/_sources/posts/2023/2023-01-29-final-report-shivam.rst.txt @@ -0,0 +1,314 @@ + +.. role:: raw-html(raw) + :format: html + +.. raw:: html + +
gsoc
+ +.. raw:: html + +
+ + fury +
+ + +Google Summer of Code Final Work Product +======================================== + +.. post:: January 29 2023 + :author: Shivam Anand + :tags: google + :category: gsoc + +- **Name:** Shivam Anand +- **Organisation:** Python Software Foundation +- **Sub-Organisation:** FURY +- **Project:** `FURY - glTF + Integration `__ + + +Proposed Objectives +------------------- + +- Ability to load glTF models + + - Should be able to load static glTF models + - Should be able to add model to the scene. + +- Exporting scene data as glTF file +- Materials & Textures + + - Textures + - PBRs + +- Animations + + - Simple Actor animations + - Skinning + - Morphing + +- Stretch Goals + + - Ability to load ``.glb`` files + +Objectives Completed +-------------------- + +Loading Static glTF models +************************** + +A glTF file is a JSON like file format containing required data for 3D scenes. VTK has two built-in glTF loaders. However, they lack ability to animate and apply materials. Added methods to load binary +data and create actors from them. These actors can be added directly +to the scene. The glTF class reads texture data from either +``base64`` encoded string or from the image file, and maps the +texture to the actor using the given UV data. It is capable of doing +the following: + +- Loading both ``gltf`` and ``glb`` files. Get actors from the + model. +- Applying textures and colors from materials. +- Setting cameras if the model contains multiple cameras. +- Apply normals (for a smoother surface). + +.. figure:: https://user-images.githubusercontent.com/74976752/174492510-b9f10816-3058-4a7b-a260-0627406354ba.png + :alt: image + + +*Pull Requests:* + +- **Importing glTF files: (Merged)** + https://github.com/fury-gl/fury/pull/600 +- **Loading glTF Demo (with textures) (Merged):** + https://github.com/fury-gl/fury/pull/600 + + +Exporting Scene as a glTF +************************* + + +The fury scene can contain multiple objects such as actors, cameras, +textures, etc. We need to get the primitive information (such as +Vertices, Triangles, UVs, Normals, etc.) from these objects and store +them into a ``.bin`` file. Added methods that export these +information to a ``.gltf`` or ``.glb`` file format. + +*Pull Requests:* + +- **Exporting scene as glTF: (Merged)** + https://github.com/fury-gl/fury/pull/630 +- **Exporting scene as glTF Tutorial: (Merged)** + https://github.com/fury-gl/fury/pull/630 + + +Simple Actor Animations +*********************** + +Added simple actor animations (translation, rotation & scale of +actors) support. The animation data (transformation and timestamp) is +stored in buffers. It converts the binary data to ndarrays and +creates a timleline for each animation in glTF animations. This +timeline contains actors an can be added to the scene. We can animate +the scene by updating timeline inside a timer callback. + +.. image:: https://user-images.githubusercontent.com/74976752/217645594-6054ea83-12e5-4868-b6a1-eee5a154bd26.gif + :width: 480 + :align: center + +*Pull Requests:* + +- **Simple Animations in glTF: (Merged)** + https://github.com/fury-gl/fury/pull/643 +- **Simple Animations in glTF Tutorial: (Merged)** + https://github.com/fury-gl/fury/pull/643 + + +Morphing in glTF +**************** + +glTF allows us to animate meshes using morph targets. A morph target +stores displacements or differences for certain mesh attributes. At +runtime, these differences may be added to the original mesh, with +different weights, to animate parts of the mesh. Added methods to +extract this information, update the timeline and apply morphing to +each actor in the scene. + +.. image:: https://user-images.githubusercontent.com/74976752/217645485-153ec403-6c87-4282-8907-30d921106b34.gif + :width: 480 + :align: center + +*Pull Requests:* + +- **Morphing support in glTF: (Under Review)** + https://github.com/fury-gl/fury/pull/700 +- **Morphing in glTF demo: (Under Review)** + https://github.com/fury-gl/fury/pull/700 + + +Skeletal Animations (Skining) +***************************** + +Another way of animating a glTF is by skinning. It allows the +geometry (vertices) of a mesh to be deformed based on the pose of a +skeleton. This is essential in order to give animated geometry. It +combines every parameter of a glTF file. While working with skinning, +we need to keep track of the parent-child hierarchy of +transformations. Vertex Skinning takes full advantage of newly +implemented ``Timeline`` & ``Animation`` modules to track +hierarchical transformation order. Though the current version of the +skinning implementation works with most of the glTF sample modes, It +struggles with models that have multiple actors (e.g. BrainStem). It +can be fixed by using the vertex shader to update the vertices. The +current implementation of skinning supports the following: + +- Multiple animation support +- Multiple node and multiple actor animation with textures +- Show or hide bones/skeleton of the model. + + +.. image:: https://user-images.githubusercontent.com/74976752/217645367-f901c6ed-ca20-40d6-92dd-f1cd8899ac7a.gif + :width: 480 + :align: center + +*Pull Requests:* + +- **Skinning support in glTF: (Under Review)** + https://github.com/fury-gl/fury/pull/685 +- **Skinning in glTF demo: (Under Review)** + https://github.com/fury-gl/fury/pull/685 + +Objectives in Progress +---------------------- + + +PBR and emission materials in glTF +********************************** + +The glTF format supports Physically based rendering also. PBR allow +renderers to display objects with a realistic appearance under +different lighting conditions, the shading model has to take the +physical properties of the object surface into account. There are +different representations of these physical material properties. One +that is frequently used is the metallic-roughness-model. We have +various material properties already in FURY, we need to apply it to +glTF models as well. + + +Skinning for models with no indices +*********************************** + +The glTF format supports non-indexed geometry (e.g., the ``Fox`` +model). We currently do not know how to render the model without +indices. I tried estimating it in this +`branch `__. +However, It fails to render in skinning. + +*Branch URL:* + +- **Rendering glTF with no indices: (in-progress)** + https://github.com/xtanion/fury/blob/gltf-indices-fix/fury/gltf.py + +Other Objectives +---------------- + + +Fetcher for importing glTF files from Khronos-glTF-Samples +********************************************************** + +The +`KhronosGroup/gltf-samples `__ +contain multiple glTF sample models to test a glTF viewer for free. +Implemented new methods in fetcher that can load all of these models +by (using type) asynchronously. The glTF fetcher is capable +of the following: + +- Downloading multiple models asynchronously. +- Get the path to the downloaded model using it - Download any model using the URL of the model. + +*Pull Requests:* + +- **Fetching glTF sample models from github: (Merged)** + https://github.com/fury-gl/fury/pull/602 +- **Fixing github API limit: (Merged)** + https://github.com/fury-gl/fury/pull/616 + + +Other Pull Requests +******************* + +- **Sphere actor uses repeat_primitive by default**: + `fury-gl/fury/#533 `__ +- **Cone actor uses repeat primitive by default**: + `fury-gl/fury/#547 `__ +- **Updated code of viz_network_animated to use fury.utils**: + `fury-gl/fury/#556 `__ +- **Added simulation for Tesseract**: + `fury-gl/fury/#559 `__ +- **GLTF actor colors from material** + `fury-gl/fury/#689 `__ + + +GSoC weekly blogs +***************** + +- My blog posts can be found on the `FURY + website `__ + and the `Python GSoC + blog `__. + +Timeline +-------- + + +.. list-table:: + :header-rows: 1 + + * - Date + - Description + - Blog Post Link + * - Week 0\ :raw-html:`
`\ (24-05-2022) + - My journey to GSoC 2022 + - `FURY `_ - `Python `_ + * - Week 1\ :raw-html:`
`\ (20-06-2022) + - A basic glTF Importer + - `FURY `_ - `Python `_ + * - Week 2\ :raw-html:`
`\ (29-06-2022) + - Improving Fetcher and Exporting glTF + - `FURY `_ - `Python `_ + * - Week 3\ :raw-html:`
`\ (04-07-2022) + - Fixing fetcher adding tests and docs + - `FURY `_ - `Python `_ + * - Week 4\ :raw-html:`
`\ (12-07-2022) + - Finalizing glTF loader + - `FURY `_ - `Python `_ + * - Week 5\ :raw-html:`
`\ (19-07-2022) + - Creating PR for glTF exporter and fixing the loader + - `FURY `_ - `Python `_ + * - Week 6\ :raw-html:`
`\ (25-07-2022) + - Extracting the animation data + - `FURY `_ - `Python `_ + * - Week 7\ :raw-html:`
`\ (01-08-2022) + - Fixing bugs in animations + - `FURY `_ - `Python `_ + * - Week 8\ :raw-html:`
`\ (09-08-2022) + - Fixing animation bugs + - `FURY `_ - `Python `_ + * - Week 9\ :raw-html:`
`\ (17-08-2022) + - First working skeletal animation prototype + - `FURY `_ - `Python `_ + * - Week 10\ :raw-html:`
`\ (25-08-2022) + - Multi-node skinning support + - `FURY `_ - `Python `_ + * - Week 11\ :raw-html:`
`\ (31-08-2022) + - Multiple transformations support and adding tests + - `FURY `_ - `Python `_ + * - Week 12\ :raw-html:`
`\ (08-09-2022) + - Adding skeleton as actors and fix global transformation + - `FURY `_ - `Python `_ + * - Week 13\ :raw-html:`
`\ (15-09-2022) + - Multi bone skeletal animations + - `FURY `_ - `Python `_ + * - Week 14\ :raw-html:`
`\ (28-09-2022) + - Morphing is here ! + - `FURY `_ - `Python `_ diff --git a/v0.10.x/_sources/posts/2023/2023-02-01-gsoc.rst.txt b/v0.10.x/_sources/posts/2023/2023-02-01-gsoc.rst.txt new file mode 100644 index 000000000..30a4eef21 --- /dev/null +++ b/v0.10.x/_sources/posts/2023/2023-02-01-gsoc.rst.txt @@ -0,0 +1,20 @@ +Contribute to FURY via Google Summer of Code 2023 +================================================= + +.. post:: February 1 2023 + :author: skoudoro + :tags: google + :category: gsoc + + +FURY is participating in the `Google Summer of Code 2023 `_ under the umbrella of the `Python Software Foundation `_. + +FURY is a free and open source software library for scientific visualization and 3D animations. FURY contains many tools for visualizing a series of scientific data including graph and imaging data. + +A list of project ideas and application info is on our `GitHub Wiki `_. + +If you are interested in talking to us about projects, applications join us to our `discord community `_ or drop us a line on our `mailing list `_. + +Be part of our community and Enjoy your summer of code! + +Serge K. diff --git a/v0.10.x/_sources/posts/2023/2023-04-14-release-announcement.rst.txt b/v0.10.x/_sources/posts/2023/2023-04-14-release-announcement.rst.txt new file mode 100644 index 000000000..43077b213 --- /dev/null +++ b/v0.10.x/_sources/posts/2023/2023-04-14-release-announcement.rst.txt @@ -0,0 +1,48 @@ +FURY 0.9.0 Released +=================== + +.. post:: April 15 2023 + :author: skoudoro + :tags: fury + :category: release + + +The FURY project is happy to announce the release of FURY 0.9.0! +FURY is a free and open source software library for scientific visualization and 3D animations. + +You can show your support by `adding a star `_ on FURY github project. + +This Release is mainly a maintenance release. The **major highlights** of this release are: + +.. include:: ../../release_notes/releasev0.9.0.rst + :start-after: -------------- + :end-before: Details + +.. note:: The complete release notes are available :ref:`here ` + +**To upgrade or install FURY** + +Run the following command in your terminal:: + + pip install --upgrade fury + +or:: + + conda install -c conda-forge fury + + +**Questions or suggestions?** + +For any questions go to http://fury.gl, or send an e-mail to fury@python.org +We can also join our `discord community `_ + +We would like to thanks to :ref:`all contributors ` for this release: + +.. include:: ../../release_notes/releasev0.9.0.rst + :start-after: commits. + :end-before: We closed + + +On behalf of the :ref:`FURY developers `, + +Serge K. diff --git a/v0.10.x/_sources/posts/2023/2023-05-29-week-0-joaodellagli.rst.txt b/v0.10.x/_sources/posts/2023/2023-05-29-week-0-joaodellagli.rst.txt new file mode 100644 index 000000000..ad3429d43 --- /dev/null +++ b/v0.10.x/_sources/posts/2023/2023-05-29-week-0-joaodellagli.rst.txt @@ -0,0 +1,35 @@ +The Beginning of Everything - Week 0 +==================================== + +.. post:: May 29, 2023 + :author: João Victor Dell Agli Floriano + :tags: google + :category: gsoc + +So it begins... +--------------- + +Hello everyone, welcome to the beginning of my journey through GSoC 2023! I would like to thank everyone involved for the opportunity provided, it is an honour to be working side by side with professionals and so many experienced people from around the world. + +The Community Bonding Period +---------------------------- + +During my community bonding period, I had the opportunity to meet my mentors and some people from the FURY team. It was a great time to learn about community guidelines and everything I will need to work with them during this summer. + +The Project's Goal +------------------ + +Briefly explaining this project, I plan to implement a real-time Kernel Density Estimation shader inside FURY library, based on `Filipi Nascimento's WebGL implementation `_. KDE, or Kernel Density Estimation, is a visualization technique that provides a good macro visualization of large and complex data sets, like point clouds, well summarizing their spatial distribution in smooth areas. I really think FURY will benefit from this as a scientific library, knowing it is a computer graphics library that originated in 2018 based on the Visualization Toolkit API (VTK), and has been improving since then. + +This Week's Goal +---------------- + +For all of this to work, the project needs one component working: the **KDE framebuffer**. As this `Khronos wiki page well explains `_: + +"A Framebuffer is a collection of buffers that can be used as the destination for rendering. OpenGL has two kinds of framebuffers: the `Default Framebuffer `_, +which is provided by the `OpenGL Context `_; and user-created framebuffers called `Framebuffer Objects `_ (FBOs). +The buffers for default framebuffers are part of the context and usually represent a window or display device. The buffers for FBOs reference images from either `Textures `_ or `Renderbuffers `_; they are never directly visible." + +Which means that a framebuffer is an object that stores data related to a frame. So the goal for this week is to investigate whether VTK, the API which FURY is written on, has a framebuffer object interface, and if it has, to understand how it works and how to use it for the project. + +Let's get to work! diff --git a/v0.10.x/_sources/posts/2023/2023-06-02-week-0-praneeth.rst.txt b/v0.10.x/_sources/posts/2023/2023-06-02-week-0-praneeth.rst.txt new file mode 100644 index 000000000..46c977795 --- /dev/null +++ b/v0.10.x/_sources/posts/2023/2023-06-02-week-0-praneeth.rst.txt @@ -0,0 +1,18 @@ +Week 0: Community Bounding Period +================================= + +.. post:: June 2, 2023 + :author: Praneeth Shetty + :tags: google + :category: gsoc + +GSoC 2023: Community Bonding Period +----------------------------------- + +Hello All! + +I'm thrilled to announce that I'll be participating in Google Summer of Code (GSoC) for yet another year. To catch a glimpse of my previous journey, check out my experiences `here `_. + +During the community bonding period, we had our first GSoC meet, where we got acquainted with the program's rules and regulations. It was an excellent opportunity to virtually meet my fellow contributors and discuss our upcoming projects. Excitement filled the air as we exchanged ideas and set goals for the summer ahead. + +Stay tuned for updates on my GSoC project as I share my progress, challenges, and breakthroughs along the way. I'm grateful for the opportunity to be part of this remarkable community. diff --git a/v0.10.x/_sources/posts/2023/2023-06-02-week-0-tvcastillod.rst.txt b/v0.10.x/_sources/posts/2023/2023-06-02-week-0-tvcastillod.rst.txt new file mode 100644 index 000000000..849714371 --- /dev/null +++ b/v0.10.x/_sources/posts/2023/2023-06-02-week-0-tvcastillod.rst.txt @@ -0,0 +1,27 @@ +Week 0: Community Bounding Period +================================= + +.. post:: June 2, 2023 + :author: Tania Castillo + :tags: google + :category: gsoc + +GSoC 2023: Community Bonding Period +----------------------------------- + +Hello everyone, my name is Tania Castillo, I am close to finishing my degree in Computer Science and I think this is a great opportunity to put my learning and skills into practice. I will be working with FURY on improving the visualization of DTI tensors and HARDI ODFs glyphs by using well-known techniques in computer graphics. + +What did I do this week? +------------------------ + +During the community bonding period, I had the opportunity to get to know better GSoC mentors and former contributors. I also had the first meeting with FURY mentors where I got to learn more about the dynamic of the program, important things to keep in mind while coding, and suggestions when making the PRs. We also receive some details on how to work with shaders which is something I have to take into account since I will use them to develop part of the project. In addition, I’ve been working on the first part of the project which consists of the creation of tensor ellipsoids using the raymarching technique and SDFs. + +What is coming up next? +----------------------- + +Since the advances I managed to make are in their most basic stage, I will be working this week on making changes and adjusting details for the implementation to follow FURY guidelines. In this way, I plan to submit my first PR for the project to start getting feedback and making improvements. I will also start working on the first tests for the ellipsoid actor I’m working on. + +Did I get stuck anywhere? +------------------------- + +For now, everything is going well, although I know I will probably run into some problems when reviewing and adjusting my code. We will see later this week. diff --git a/v0.10.x/_sources/posts/2023/2023-06-03-week-1-praneeth.rst.txt b/v0.10.x/_sources/posts/2023/2023-06-03-week-1-praneeth.rst.txt new file mode 100644 index 000000000..53edfb263 --- /dev/null +++ b/v0.10.x/_sources/posts/2023/2023-06-03-week-1-praneeth.rst.txt @@ -0,0 +1,41 @@ +Week 1: Working with SpinBox and TextBox Enhancements +===================================================== + +.. post:: June 3, 2023 + :author: Praneeth Shetty + :tags: google + :category: gsoc + +What did you do this week? +-------------------------- +This week, my focus was on reviewing pull requests (PRs) and issues related to the user interface (UI) of the project. I meticulously went through each PR and issue, identifying those specifically associated with UI improvements. To streamline the process, I categorized them accordingly under the UI category. One of the key tasks was PR `#499 `__, which involved the implementation of SpinBoxUI. After rebasing the PR, I identified an alignment issue with the textbox component. + +To resolve this issue, I started by investigating the root cause. I discovered that the alignment was initially based on the position of the parent UI, which caused the text to extend beyond the boundaries of the textbox. To rectify this, I devised a solution where I calculated the background size of the textbox and adjusted the text's position accordingly. By aligning the text with the calculated size, I ensured a proper and visually appealing alignment within the textbox. + +To provide a clear understanding of the improvement, I have prepared a comparison of the textbox alignment before and after the modifications. + +Before: + +.. image:: https://user-images.githubusercontent.com/64432063/243150149-30330be2-b529-47e9-850a-6e3a8bc03551.png + :height: 415 + :width: 376 + +After: + +.. image:: https://user-images.githubusercontent.com/64432063/243150735-86f85d6c-f9df-4092-abdf-248b6ec77c5e.png + :height: 415 + :width: 376 + + +Did you get stuck anywhere? +--------------------------- +Fortunately, I didn't encounter any significant challenges this week. + + +What is coming up next? +----------------------- +Looking ahead, here's what I have planned for the upcoming week: + +1. Completing PR `#790 `__ - Fixing Textbox Alignment +2. Wrapping up PR `#499 `__ - SpinBoxUI +3. Initiating PR `#576 `__ - Icon Flaw in ComboBox \ No newline at end of file diff --git a/v0.10.x/_sources/posts/2023/2023-06-05-week-1-joaodellagli.rst.txt b/v0.10.x/_sources/posts/2023/2023-06-05-week-1-joaodellagli.rst.txt new file mode 100644 index 000000000..405c75bbf --- /dev/null +++ b/v0.10.x/_sources/posts/2023/2023-06-05-week-1-joaodellagli.rst.txt @@ -0,0 +1,61 @@ +The FBO Saga - Week 1 +===================== + +.. post:: June 5, 2023 + :author: João Victor Dell Agli Floriano + :tags: google + :category: gsoc + + +This Past Week +-------------- + +As mentioned in the last week's blogpost, the goal for that week was to investigate VTK's Framebuffer Object framework. +An update on that is that indeed, VTK has one more low-level working `FBO class `_ that can be used inside FURY, however, +they come with some issues that I will explain further below. + + +My Current Problems +------------------- + +The problems I am having with these FBO implementations are first something related to how a FBO works, and second related to how VTK works. +In OpenGL, a custom user's FBO needs some things to be complete (usable): + +1. At least one buffer should be attached. This buffer can be the color, depth or stencil buffer. +2. If no color buffer will be attached then OpenGL needs to be warned no draw or read operations will be done to that buffer. Otherwise, there should be at least one color attachment. +3. All attachments should have their memory allocated. +4. Each buffer should have the same number of samples. + +My first problem relies on the third requirement. VTK's implementation of FBO requires a `vtkTextureObject `_ +as a texture attachment. I figured out how to work with this class, however, I cannot allocate memory for it, as its methods for it, `Allocate2D `_, `Create2D `_ and `Create2DFromRaw `_ +does not seem to work. Every time I try to use them, my program stops with no error message nor nothing. +For anyone interested in what is happening exactly, below is how I my tests are implemented: + +:: + +| color_texture = vtk.vtkTextureObject() # color texture declaration +| color_texture.Bind() # binding of the texture for operations +| color_texture.SetDataType(vtk.VTK_UNSIGNED_CHAR) # setting the datatype for unsigned char +| color_texture.SetInternalFormat(vtk.VTK_RGBA) # setting the format as RGBA +| color_texture.SetFormat(vtk.VTK_RGBA) +| color_texture.SetMinificationFilter(0) # setting the minfilter as linear +| color_texture.SetMagnificationFilter(0) # setting the magfilter as linear +| +| color_texture.Allocate2D(width, height, 4, vtk.VTK_UNSIGNED_CHAR) # here is where the code stops + +In contrast, for some reason, the methods for 3D textures, `Allocate3D `_ works just fine. +I could use it as a workaround, but I do not wish to, as this just does not make sense. + +My second problem relies on VTK. As VTK is a library that encapsulates some OpenGL functions in more palatable forms, it comes with some costs. +Working with FBOs is a more low-level work, that requires strict control of some OpenGL states and specific functions that would be simpler if it was the main API here. +However, some of this states and functions are all spread and implicit through VTK's complex classes and methods, which doubles the time expended to make some otherwise simple instructions, +as I first need to dig in lines and lines of VTK's documentation, and worse, the code itself. + + +What About Next Week? +--------------------- + +For this next week, I plan to investigate further on why the first problem is happening. If that is accomplished, then things will be more simple, as it will be a lot easier for my project to move forward as I will finally be able +to implement the more pythonic functions needed to finally render some kernel distributions onto my screen. + +Wish me luck! diff --git a/v0.10.x/_sources/posts/2023/2023-06-05-week-1-tvcastillod.rst.txt b/v0.10.x/_sources/posts/2023/2023-06-05-week-1-tvcastillod.rst.txt new file mode 100644 index 000000000..5f8aed6f4 --- /dev/null +++ b/v0.10.x/_sources/posts/2023/2023-06-05-week-1-tvcastillod.rst.txt @@ -0,0 +1,30 @@ +Week 1: Ellipsoid actor implemented with SDF +============================================ + +.. post:: June 5, 2023 + :author: Tania Castillo + :tags: google + :category: gsoc + +What did I do this week? +------------------------ + +`PR #791: Ellipsoid actor implemented with SDF `_ + +I made a first PR with the implementation of the ellipsoid actor defined with a SDF using raymarching. The current `sdf `_ actor allows the creation of ellipsoids, but it lacks control over their shape, and the displayed direction does not match the intended orientation. For this reason, a new actor just focused on ellipsoids was made, this one is defined by its axes (3x3 orthogonal matrix) and their corresponding lengths (3x1 vector), along with other attributes like color, opacity, and scale. The goal is to make an implementation that allows displaying a large amount of data, with good visual quality, and without compromising performance. I'm still working on this but here is a first glance of how it looks like: + +.. image:: https://user-images.githubusercontent.com/31288525/244503195-a626718f-4a13-4275-a2b7-6773823e553c.png + :width: 376 + :align: center + +This will be used later to create the tensor ellipsoids used on `tensor_slicer `_. + +What is coming up next? +----------------------- + +I need to talk to my mentors first but the idea is to start making improvements on the SDF definition and raymarching algorithm, I have already started looking for information about how I can do it, and if I get good ideas, I will compare if there is an improvement in performance respect to the implementation I have right now. I also need to keep working on tests, the most common way of doing it is to check the number of objects and colors displayed, but I would like to test other things related to performance. + +Did I get stuck anywhere? +------------------------- + +Not yet, I need to get feedback first to see if there is anything I need to review or correct. diff --git a/v0.10.x/_sources/posts/2023/2023-06-11-week-2-praneeth.rst.txt b/v0.10.x/_sources/posts/2023/2023-06-11-week-2-praneeth.rst.txt new file mode 100644 index 000000000..02216a477 --- /dev/null +++ b/v0.10.x/_sources/posts/2023/2023-06-11-week-2-praneeth.rst.txt @@ -0,0 +1,29 @@ +Week 2: Tackling Text Justification and Icon Flaw Issues +======================================================== + +.. post:: June 11, 2023 + :author: Praneeth Shetty + :tags: google + :category: gsoc + + +What did you do this week? +-------------------------- + +This week, I continued tweaking the text justification PR `#790 `_ and encountered a new issue when combining both **justification** and **vertical_justification**. The problem arose because the **vertical_justification** did not take into account the applied **justification**, resulting in unexpected behavior. I focused on resolving this issue by ensuring that both justifications work together correctly. Additionally, during the weekly meeting, we discussed the problem and decided to introduce new properties such as boundaries and padding to enhance the functionality of the text justification feature. + +Furthermore, I started working on PR `#576 `_, which aimed to address the flaw in the icon of the **combobox**. While investigating this issue, I discovered related problems and PRs, including `#562 `_, `#731 `_, and `#768 `_. The main challenge was related to the propagation of the **set_visibility** feature of the UI, causing the **combobox** to automatically open its options. To overcome this issue, I requested the author of PR `#768 `_ to rebase their pull request as it can be a solution for the issue. + +Did you get stuck anywhere? +--------------------------- + +A significant portion of my time was dedicated to resolving the text justification issue when both justification types were combined. It required careful analysis and adjustments to ensure the desired behavior. + +What is coming up next? +----------------------- + +For the upcoming week, I have the following plans: + +1. Work on modifying the text justification implementation to address any remaining issues and ensure compatibility with other features. +2. Begin the implementation of the scrollbar class from scratch to provide a robust and customizable scrollbar element. +3. Focus on completing the resolution of the icon flaw issue by collaborating with the relevant stakeholders and ensuring the necessary modifications are made. diff --git a/v0.10.x/_sources/posts/2023/2023-06-12-week-2-joaodellagli.rst.txt b/v0.10.x/_sources/posts/2023/2023-06-12-week-2-joaodellagli.rst.txt new file mode 100644 index 000000000..9f22c9358 --- /dev/null +++ b/v0.10.x/_sources/posts/2023/2023-06-12-week-2-joaodellagli.rst.txt @@ -0,0 +1,86 @@ +Week 2: The Importance of (good) Documentation +============================================== + +.. post:: June 12, 2023 + :author: João Victor Dell Agli Floriano + :tags: google + :category: gsoc + + +Hello everybody, welcome to the week 2 of this project! I must admit I thought this would be simpler than it is currently being, but I forgot that when it comes to dealing with computer graphics' applications, things never are. Below, some updates on what I have been up to for this past week.  + +This Last Week's Effort +----------------------- + +Last week, I was facing some issues with a VTK feature essential so I could move forward with my project: Framebuffer Objects. +As described in my :doc:`last blogpost <2023-06-05-week-1-joaodellagli>`, for some reason the 2D allocation methods for it weren't working. +In a meeting with my mentors, while we were discussing and searching through VTK's FramebufferObject and TextureObject documentation, and the code itself for the problem, +one TextureObject method caught my attention: `vtkTextureObject.SetContext() `_. + +Where the Problem Was +--------------------- +My last week's code was: + +:: + + color_texture = vtk.vtkTextureObject() # color texture declaration + color_texture.Bind() # binding of the texture for operations + + color_texture.SetDataType(vtk.VTK_UNSIGNED_CHAR) # setting the datatype for unsigned char + color_texture.SetInternalFormat(vtk.VTK_RGBA) # setting the format as RGBA + color_texture.SetFormat(vtk.VTK_RGBA) + color_texture.SetMinificationFilter(0) # setting the minfilter as linear + color_texture.SetMagnificationFilter(0) # setting the magfilter as linear + + color_texture.Allocate2D(width, height, 4, vtk.VTK_UNSIGNED_CHAR) # here is where the code stops + +But it turns out that to allocate the FBO's textures, of type vtkTextureObject, you need to also set the context where the texture object +will be present, so it lacked a line, that should be added after ``Bind()``: + +:: + + color_texture = vtk.vtkTextureObject() + color_texture.Bind() + + color_texture.SetContext(manager.window) # set the context where the texture object will be present + + color_texture.SetDataType(vtk.VTK_UNSIGNED_CHAR) + color_texture.SetInternalFormat(vtk.VTK_RGB) + color_texture.SetFormat(vtk.VTK_RGB) + color_texture.SetMinificationFilter(0) + color_texture.SetMagnificationFilter(0) + +The code worked fine. But as my last blogpost showed, ``Allocate3D()`` method worked just fine without a (visible) problem, why is that? +Well, in fact, it **didn't work**. If we check the code for the ``Allocate2D()`` and ``Allocate3D()``, one difference can be spotted: + + + +.. image:: https://raw.githubusercontent.com/JoaoDell/gsoc_assets/main/images/allocate-2d-3d.png + :align: center + :alt: Image comparing Allocate2D and Allocate3D methods + + + +While in ``Allocate2D()`` there is an ``assert(this->Context);``, in ``Allocate3D()`` the assertion is translated into: + +:: + + if(this->Context==nullptr) + { + vtkErrorMacro("No context specified. Cannot create texture."); + return false; + } + +This slight difference is significant: while in ``Allocate2D()`` the program immediately fails, in ``Allocate3D()`` the function is simply returned +**false**, with its error pushed to vtkErrorMacro. I could have realised that earlier if I were using vtkErrorMacro, but this difference in their +implementation made it harder for me and my mentors to realise what was happening. + + +This Week's Goals +----------------- +After making that work, this week's goal is to render something to the Framebuffer Object, now that is working. To do that, +first I will need to do some offscreen rendering to it, and afterwards render what it was drawn to its color attachment, the Texture Object I +was struggling to make work, into the screen, drawing its texture to a billboard. Also, I plan to start using vtkErrorMacro, as it seems like +the main error interface when working with VTK, and that may make my life easier. + +See you next week! \ No newline at end of file diff --git a/v0.10.x/_sources/posts/2023/2023-06-12-week-2-tvcastillod.rst.txt b/v0.10.x/_sources/posts/2023/2023-06-12-week-2-tvcastillod.rst.txt new file mode 100644 index 000000000..fb9ed7405 --- /dev/null +++ b/v0.10.x/_sources/posts/2023/2023-06-12-week-2-tvcastillod.rst.txt @@ -0,0 +1,25 @@ +Week 2: Making adjustments to the Ellipsoid Actor +================================================= + +.. post:: June 12, 2023 + :author: Tania Castillo + :tags: google + :category: gsoc + +What did I do this week? +------------------------ + +I made some minor adjustments to the last PR I submitted. Last time it was a draft since I was waiting for the weekly meeting to know how to proceed, but now it is ready. I am waiting for the review so I can make the necessary corrections and adjustments to merge this first PR soon. + +What is coming up next? +----------------------- + +As I receive feedback, I will continue to work on the `PR #791 `_ and make adjustments and changes as needed. That said, I will start working on another part of the project, which is the visualization of uncertainty. Without going into details (for now) what I have to do is: + +- Create a double_cone or dti_uncertainty actor. I'm going to work on the double cone made also with raymarching and SDF, since the implementation is pretty much the same as the ellipsoid I already have. +- Make a function that returns the level of the uncertainty given by the angle of the uncertainty cone we want to visualize. For this I need to double-check the maths behind the uncertainty calculation to make sure I'm getting the right results. + +Did I get stuck anywhere? +------------------------- + +Not exactly, but one of the things that were mentioned in the last meeting is that we should try to simplify the shader code as much as we can, that is, to break down the entire implementation into simple and easy-to-understand lines of code, which also allows the definition of functions that can be reused later on. I need to keep working on this, so I can make my code even more readable and fit the new shader structure. diff --git a/v0.10.x/_sources/posts/2023/2023-06-17-week-3-praneeth.rst.txt b/v0.10.x/_sources/posts/2023/2023-06-17-week-3-praneeth.rst.txt new file mode 100644 index 000000000..071a0aafa --- /dev/null +++ b/v0.10.x/_sources/posts/2023/2023-06-17-week-3-praneeth.rst.txt @@ -0,0 +1,34 @@ +Week 3: Resolving Combobox Icon Flaw and TextBox Justification +============================================================== + +.. post:: June 17, 2023 + :author: Praneeth Shetty + :tags: google + :category: gsoc + +What did you do this week? +-------------------------- + +This week, I tackled the **ComboBox2D** icon flaw, which was addressed using Pull Request (PR) `#576 `__. The problem arose when we added a **ComboBox2D** to the **TabUI**. The **TabUI** would propagate the ``set_visibility = true`` for all its child elements, causing the combobox to appear on the screen without the icon change. To fix this issue, PR `#768 `__ updated the ``set_visibility`` method of the UI class, ensuring that the icon change was applied correctly. + +.. figure:: https://user-images.githubusercontent.com/98275514/215267056-a0fd94d9-ae6d-4cf8-8475-ab95fe0ef303.png + :align: center + :alt: Combobox Icon + +Next, I focused on the textbox justification. As discussed in our meeting, I added a new property called **boundingbox** to the **TextBlock2D**. However, I encountered a problem when resizing the **TextBlock2D**. The ``vtkTextActor`` property would switch from ``SetTextScaleModeToNone`` to ``SetTextScaleModeToProp``, which would scale the font according to the position1 (lower left corner) and position2 (upper right corner) of the UI. This inconsistency in font scaling resulted in misaligned text actors. I spent some time investigating this issue, and you can find my progress in the ongoing PR `#803 `__. + +Additionally, I started working on creating a Scrollbar component by inheriting the **LineSlider2D**. I made adjustments to the position and other attributes to make it function as a scrollbar. However, I encountered some confusion regarding how to separate the scrollbar component from other elements and determine what should be included in the scrollbar itself. + +.. figure:: https://github.com/fury-gl/fury/assets/64432063/d9c8d60e-3ade-49ff-804a-fd0b340b0b24 + :align: center + :alt: Scrollbar + +Did you get stuck anywhere? +--------------------------- + +I faced a challenge while working on the text justification. It took me several days to identify the root cause of the occasional malfunctioning of the **TextBlock2D**. At last, I found out the reason behind the issue. + +What is coming up next? +----------------------- + +Next week, I have several tasks lined up. Firstly, I will be working on the **CardUI** PR `#398 `__. Additionally, I plan to complete the segregation of the scrollbar component, ensuring its independence and clarity. Lastly, I will be working on issue `#540 `__, which involves updating the use of the ``numpy_to_vtk_image_data`` utility function. \ No newline at end of file diff --git a/v0.10.x/_sources/posts/2023/2023-06-19-week-3-joaodellagli.rst.txt b/v0.10.x/_sources/posts/2023/2023-06-19-week-3-joaodellagli.rst.txt new file mode 100644 index 000000000..a043a22fa --- /dev/null +++ b/v0.10.x/_sources/posts/2023/2023-06-19-week-3-joaodellagli.rst.txt @@ -0,0 +1,40 @@ +Week 3: Watch Your Expectations +=============================== + +.. post:: June 19, 2023 + :author: João Victor Dell Agli Floriano + :tags: google + :category: gsoc + + +Hello everyone, it's time for another weekly blogpost! This week, +I will talk about how you should watch your expectations when working with any project. + +This Last Week's Effort +----------------------- +As I supposedly managed to make the texture allocation part working, this last week's goal was to render something to a FBO. Well, I could make +textures work, but what I wasn't expecting and later realised, was that the FBO setup not working. Below I will describe where I got stuck. + +Where the Problem Was +--------------------- +After getting the textures setup right, I was ready to render some color to the FBO. Well, I **was**, because I didn't expect +I would have another problem, this time, with the FBO setup. As described in my :doc:`week 1 blogpost <2023-06-05-week-1-joaodellagli>`, +a FBO needs some requirements to work. My current problem relies on the FBO method ``FBO.SetContext()``, that for some reason is not being able to generate the FBO. +Below, how the method is currently operating: + +.. image:: https://raw.githubusercontent.com/JoaoDell/gsoc_assets/main/images/setcontext.png + :align: center + :alt: Image showing the SetContext's VTK implementation + +Apparently, the method is stuck before the ``this->CreateFBO()``, that can be checked when we call ``FBO.GetFBOIndex()``, that returns a ``0`` value, +meaning the FBO was not generated by the ``glGenFramebuffers()`` function, that is inside the ``GetContext()`` method. + +This Week's Goals +----------------- +As I got stuck again with this simple step, talking with my mentors we concluded that a plan B is needed for my GSoC participation as +my current project is not having much progress. This plan B that I am gonna start working on this week involves working on `FURY Speed `_, +a FURY addon that aims to develop optimized functions and algorithms to help speed up graphical applications. The suggestion was to +work on a PR I submitted months ago, `#783 `_, in a way to integrate that into FURY Speed. +Also, I plan to keep working on my current project to find the solution I will need to make the FBO usage work. + +Let's get to work! \ No newline at end of file diff --git a/v0.10.x/_sources/posts/2023/2023-06-19-week-3-tvcastillod.rst.txt b/v0.10.x/_sources/posts/2023/2023-06-19-week-3-tvcastillod.rst.txt new file mode 100644 index 000000000..47cb8b17d --- /dev/null +++ b/v0.10.x/_sources/posts/2023/2023-06-19-week-3-tvcastillod.rst.txt @@ -0,0 +1,22 @@ +Week 3: Working on uncertainty and details of the first PR +========================================================== + +.. post:: June 19, 2023 + :author: Tania Castillo + :tags: google + :category: gsoc + +What did I do this week? +------------------------ + +I made some adjustments to the ellipsoid actor definition, now called *tensor*. This was something discussed in the weekly meeting as the coming changes are related to this actor, the idea now is to have a tensor actor that allows choosing between displaying the tensor ellipsoids or the uncertainty cones (later on). I also worked on the uncertainty calculation, and the cone SDF for the visualization, so I plan to do a WIP PR next to start getting feedback on this new addition. + +What is coming up next? +----------------------- + +As for the uncertainty calculation, other data is needed such as the noise variance and the design matrix (check `this `_ article for more details), I need to identify which should be the parameters for the function definition. I also have to work on the documentation, so the function and its purpose are clear. I plan to make some final adjustments related to the uncertainty so that the next PR is ready for submission this week. I also expect to make final changes to the first PR so that it can be merged soon. + +Did I get stuck anywhere? +------------------------- + +Not this week, I will wait for feedback to see if there is anything I need to review or correct. diff --git a/v0.10.x/_sources/posts/2023/2023-06-24-week-4-praneeth.rst.txt b/v0.10.x/_sources/posts/2023/2023-06-24-week-4-praneeth.rst.txt new file mode 100644 index 000000000..0777ef8ba --- /dev/null +++ b/v0.10.x/_sources/posts/2023/2023-06-24-week-4-praneeth.rst.txt @@ -0,0 +1,30 @@ +Week 4: Exam Preparations and Reviewing +======================================= + +.. post:: June 24, 2023 + :author: Praneeth Shetty + :tags: google + :category: gsoc + +What did I do this week? +------------------------ + +This week, amidst end-semester exams, I managed to accomplish a few notable tasks. Let's dive into the highlights: + +1. Merging **CardUI**: The PR `#398 `_ introduced the **CardUI** to the UI system of FURY. After a successful review and test check, it was merged into the codebase. + +2. Revisiting PR `#540 `_: I restarted working on PR `#540 `_ as I wasn't satisfied with the previous approach when I checked it for rebasing. I took the opportunity to update the code and ensure that the unit tests passed successfully. Although there are a few issues remaining in the tests, I am determined to resolve them and move forward with the implementation. This PR aims to improve the usage of the **numpy_to_vtk_image_data** utility function. + +3. Independent Scrollbar Consideration: We are currently evaluating the necessity of making the Scrollbar an independent element. Currently it is only used by the **ListBox2D**, we are exploring various use cases to determine if there are other scenarios where the Scrollbar can be employed independently. This evaluation will help us make an informed decision about its future implementation. + +4. PR Reviews: In the brief intervals between exams, I utilized the time to review two PRs: `#446 `_ - Resize panel and `#460 `_ - Tree UI. + +Did I get stuck anywhere? +------------------------- + +No, fortunately, I didn't encounter any major obstacles or challenges during my tasks this week. + +What is coming up next? +----------------------- + +Once the exams are over, I am eagerly looking forward to making a full comeback to development. My immediate plans include addressing the remaining issues in PR `#540 `_ and completing the pending tasks. I will also catch up on any missed discussions and sync up with the team to align our goals for the upcoming weeks. \ No newline at end of file diff --git a/v0.10.x/_sources/posts/2023/2023-06-26-week-4-joaodellagli.rst.txt b/v0.10.x/_sources/posts/2023/2023-06-26-week-4-joaodellagli.rst.txt new file mode 100644 index 000000000..97950b4eb --- /dev/null +++ b/v0.10.x/_sources/posts/2023/2023-06-26-week-4-joaodellagli.rst.txt @@ -0,0 +1,60 @@ +Week 4: Nothing is Ever Lost +============================ + +.. post:: June 26, 2023 + :author: João Victor Dell Agli Floriano + :tags: google + :category: gsoc + + +Welcome again to another weekly blogpost! Today, let's talk about the importance of guidance throughout a project. + +Last Week's Effort +----------------------- +So, last week my project was struggling with some supposedly simple in concept, yet intricate in execution issues. If you recall from +my :doc:`last blogpost <2023-06-19-week-3-joaodellagli>`, I could not manage to make the Framebuffer Object setup work, as its method, +``SetContext()``, wasn't being able to generate the FBO inside OpenGL. Well, after some (more) research about that as I also dived in my +plan B, that involved studying numba as a way to accelerate a data structure I implemented on my PR `#783 `_, +me and one of my mentors decided we needed a pair programming session, that finally happened on thursday. After that session, +we could finally understand what was going on. + +Where the Problem Was +--------------------- +Apparently, for the FBO generation to work, it is first needed to initialize the context interactor: + +:: + + FBO = vtk.vtkOpenGLFramebufferObject() + + manager.window.SetOffScreenRendering(True) # so the window doesn't show up, but important for later as well + manager.initialize() # missing part that made everything work + + FBO.SetContext(manager.window) # Sets the context for the FBO. Finally, it works + FBO.PopulateFramebuffer(width, height, True, 1, vtk.VTK_UNSIGNED_CHAR, False, 24, 0) # And now I could populate the FBO with textures + + +This simple missing line of code was responsible for ending weeks of suffer, as after that, I called: +:: + print("FBO of index:", FBO.GetFBOIndex()) + print("Number of color attachments:", FBO.GetNumberOfColorAttachments()) + +That outputted: +:: + FBO of index: 4 + Number of color attachments: 1 + +That means the FBO generation was successful! One explanation that seems reasonable to me on why was that happening is that, as it was +not initialized, the context was being passed ``null`` to the ``SetContext()`` method, that returned without any warning of what was happening. + +Here, I would like to point out how my mentor was **essential** to this solution to come: I had struggled for some time with that, and could +not find a way out, but a single session of synchronous pair programming where I could expose clearly my problem and talk to someone +way more experienced than I, someone designated for that, was my way out of this torment, so value your mentors! Thanks Bruno! + + +This Week's Goals +----------------- +Now, with the FBO working, I plan to finally *render* something to it. For this week, I plan to come back to my original plan and +experiment with simple shaders just as a proof of concept that the FBO will be really useful for this project. I hope the road is less +bumpier by now and I don't step on any other complicated problem. + +Wish me luck! \ No newline at end of file diff --git a/v0.10.x/_sources/posts/2023/2023-06-27-week-4-tvcastillod.rst.txt b/v0.10.x/_sources/posts/2023/2023-06-27-week-4-tvcastillod.rst.txt new file mode 100644 index 000000000..5fd4e8735 --- /dev/null +++ b/v0.10.x/_sources/posts/2023/2023-06-27-week-4-tvcastillod.rst.txt @@ -0,0 +1,30 @@ +Week 4: First draft of the DTI uncertainty visualization +======================================================== + +.. post:: June 27, 2023 + :author: Tania Castillo + :tags: google + :category: gsoc + +What did I do this week? +------------------------ + +`#PR 810: DTI uncertainty visualization `_ + +I made a second PR with the implementation of DTI uncertainty calculation and visualization. Below is an image of diffusion tensor ellipsoids and their associated uncertainty cones. + +.. image:: https://user-images.githubusercontent.com/31288525/254747296-09a8674e-bfc0-4b3f-820f-8a1b1ad8c5c9.png + :width: 530 + :align: center + +I had to use some **dipy** functions, specifically: `estimate_sigma `_ for the noise variance calculation, `design_matrix `_ to get the b-matrix, and `tensor_prediction `_ for the signal estimation. The details of this calculations can be found `here `_. + +What is coming up next? +----------------------- + +I will continue working on the uncertainty PR which is still in its early stage, I'm going to make a couple of adjustments to the description of the parameters and the actor, and keep working on based on the feedback I receive. There are also minor details to be discussed with my mentors about the first PR, which I hope to finish refining. + +Did I get stuck anywhere? +------------------------- + +It took me a while to make the PR because I had some problems with the uncertainty function definition. I tried to use the least amount of parameters for the function, since with data, bvals and bvecs it is possible to obtain the rest of the parameters needed to generate the cones, which led me to readjust some calculations from the base implementation I had, to keep everything working correctly. diff --git a/v0.10.x/_sources/posts/2023/2023-07-01-week-5-praneeth.rst.txt b/v0.10.x/_sources/posts/2023/2023-07-01-week-5-praneeth.rst.txt new file mode 100644 index 000000000..4563775ce --- /dev/null +++ b/v0.10.x/_sources/posts/2023/2023-07-01-week-5-praneeth.rst.txt @@ -0,0 +1,28 @@ +Week 5: Trying out PRs and Planning Ahead +========================================= + +.. post:: July 01, 2023 + :author: Praneeth Shetty + :tags: google + :category: gsoc + + +What did you do this week? +-------------------------- +Due to ongoing exams, my productivity was limited this week. However, I managed to find some time to explore and review a few PRs submitted by contributors: + +1. Ellipsoid PR `#791 `_: + This PR focuses on creating a new ellipsoid actor defined with SDF and raymarching techniques. + +2. Website Improvement PR `#812 `_: + This PR includes changes for the new compatibility section on the FURY home page. + +Towards the end of the week, I had a meeting with my mentor. We discussed the current status of ongoing PRs and identified action points to focus on in the upcoming weeks. This discussion provided clarity on the challenges faced with certain PRs and issues. + +Did you get stuck anywhere? +--------------------------- +Fortunately, I didn't encounter any major roadblocks or challenges that hindered my progress this week. + +What is coming up next? +------------------------ +With the action points provided by my mentor, I will be dedicating the next week to completing those tasks. \ No newline at end of file diff --git a/v0.10.x/_sources/posts/2023/2023-07-03-week-5-joaodellagli.rst.txt b/v0.10.x/_sources/posts/2023/2023-07-03-week-5-joaodellagli.rst.txt new file mode 100644 index 000000000..752ae0e35 --- /dev/null +++ b/v0.10.x/_sources/posts/2023/2023-07-03-week-5-joaodellagli.rst.txt @@ -0,0 +1,77 @@ +Week 5: All Roads Lead to Rome +============================== + +.. post:: July 03, 2023 + :author: João Victor Dell Agli Floriano + :tags: google + :category: gsoc + + +Hello everyone, time for another weekly blogpost! Today, we will talk about taking different paths to reach your objective. + +Last Week's Effort +------------------ +After having the FBO properly set up, the plan was to finally *render* something to it. Well, I wished for a less bumpy road +at my :doc:`last blogpost <2023-06-26-week-4-joaodellagli>` but as in this project things apparently tend to go wrong, +of course the same happened with this step. + + +Where the Problem Was +--------------------- +Days passed without anything being rendered to the FBO. The setup I was working on followed the simplest OpenGL pipeline of rendering to +an FBO: + +1. Setup the FBO +2. Attach a texture to it's color attachment +3. Setup the shader to be used in the FBO render and the shader to render the FBO's Color Attachment +4. Render to the FBO +5. Use the color attachment as texture attached to a billboard to render what was on the screen + +But it seems like this pipeline doesn't translate well into VTK. I paired again on wednesday with my mentors, Bruno and Filipi, to try to figure out +where the problem was, but after hours we could not find it. Wednesday passed and then thursday came, and with thursday, a solution: +Bruno didn't give up on the idea and dug deep on VTK's documentation until he found a workaround to do what we wanted, that was retrieving a +texture from what was rendered to the screen and pass it as a texture to render to the billboard. To do it, he figured out we needed to use +a different class, `vtkWindowToImageFilter `_, a class that has the specific +job of doing exactly what I described above. Below, the steps to do it: + +:: + + windowToImageFilter = vtk.vtkWindowToImageFilter() + windowToImageFilter.SetInput(scene.GetRenderWindow()) + windowToImageFilter.Update() + + texture = vtk.vtkTexture() + texture.SetInputConnection(windowToImageFilter.GetOutputPort()) + + # Bind the framebuffer texture to the desired actor + actor.SetTexture(texture) + +This is enough to bind to the desired actor a texture that corresponds to what was prior rendered to the screen. + + +This Week's Goals +----------------- +Having a solution to that, now its time to finally render some KDE's! This week's plans involve implementing the first version of a KDE +calculation. For anyone interested in understanding what a Kernel Density Estimation is, here is a brief summary from this +`Wikipedia page `_: + + + In statistics, kernel density estimation (KDE) is the application of kernel smoothing for probability density estimation, i.e., a + non-parametric method to estimate the probability density function of a random variable based on kernels as weights. KDE answers a + fundamental data smoothing problem where inferences about the population are made, based on a finite data sample. In some fields + such as signal processing and econometrics it is also termed the Parzen–Rosenblatt window method, after Emanuel Parzen and Murray + Rosenblatt, who are usually credited with independently creating it in its current form. One of the famous applications of + kernel density estimation is in estimating the class-conditional marginal densities of data when using a naive Bayes classifier, + which can improve its prediction accuracy. + +This complicated sentence can be translated into the below image: + +.. image:: https://raw.githubusercontent.com/JoaoDell/gsoc_assets/main/images/KDE_plot.png + :align: center + :alt: KDE plot of 100 random points + +That is what a KDE plot of 100 random points looks like. The greener the area, the greater the density of points. The plan is to implement +something like that with the tools we now have available. + +Let's get to work! + diff --git a/v0.10.x/_sources/posts/2023/2023-07-03-week-5-tvcastillod.rst.txt b/v0.10.x/_sources/posts/2023/2023-07-03-week-5-tvcastillod.rst.txt new file mode 100644 index 000000000..abbcda0f1 --- /dev/null +++ b/v0.10.x/_sources/posts/2023/2023-07-03-week-5-tvcastillod.rst.txt @@ -0,0 +1,22 @@ +Week 5: Preparing the data for the Ellipsoid tutorial +===================================================== + +.. post:: July 03, 2023 + :author: Tania Castillo + :tags: google + :category: gsoc + +What did I do this week? +------------------------ + +During the weekly meeting with my mentors, there was a small discussion over the naming of the actor and its usage. On the one hand, although the purpose of the actor is to visualize diffusion tensor ellipsoids, the idea is that it can also be used for any other type of visualization that requires the use of ellipsoids, so in the end, we decided to keep the name *ellipsoid* as it is more generic. On the other hand, as there is already an actor made for the purpose of tensor visualization, namely `tensor_slicer `_, it might not be obvious how and why one would use this new ellipsoid actor for this purpose, thus it was proposed to make a tutorial that can clarify this. The main difference between both actors relies on the quality and the amount of data that can be displayed, so the idea is to show the difference between both alternatives so the user can choose which one to use depending on their needs. To prepare the tutorial the first step was to `add the data `_ I will use on `fury-data `_ so I can then fetch and load the datasets I need to work on the tutorial. + +What is coming up next? +----------------------- + +I need `#PR 791 `_ to be reviewed by my GSoC fellows at FURY, so I will address their comments, and additionally make adjustments on `#PR 810 `_ based on the feedback I receive. I will also start working on the tutorial, the idea is to show the use that can be made of the ellipsoid actor in the visualization of diffusion tensor ellipsoids, compared to the *tensor_slicer* actor. I plan to create a WIP PR to start getting feedback on the general structure of the tutorial and the way everything will be explained. + +Did I get stuck anywhere? +------------------------- + +I did not encounter any obstacles this week. diff --git a/v0.10.x/_sources/posts/2023/2023-07-08-week-6-praneeth.rst.txt b/v0.10.x/_sources/posts/2023/2023-07-08-week-6-praneeth.rst.txt new file mode 100644 index 000000000..402a137f0 --- /dev/null +++ b/v0.10.x/_sources/posts/2023/2023-07-08-week-6-praneeth.rst.txt @@ -0,0 +1,26 @@ +Week 6: BoundingBox for TextBlock2D! +==================================== + +.. post:: July 08, 2023 + :author: Praneeth Shetty + :tags: google + :category: gsoc + + +What did you do this week? +-------------------------- +This week, I worked on improving the **TextBlock2D** component in the UI system. I started from scratch to address alignment and scaling issues. When resizing the **TextBlock2D**, the text alignment and justification with the background rectangle were inconsistent. To resolve this, I introduced a new "boundingbox" property that calculates the text bounding box based on its content. Additionally, I separated the scaling mode from the resizing action with the new "auto_font_scale" property, enabling automatic font scaling according to the bounding box. This will provide better alignment, justified text, and smoother font scaling for the **TextBlock2D** component. Try it out at `PR #803 `_. + +.. image:: https://github.com/fury-gl/fury/assets/64432063/94212105-7259-48da-8fdc-41ee987bda84 + :align: center + :alt: TextBlock2D will different justifications + +As discussed last week, we also made a decision regarding the scrollbar. After exploring different use cases, we concluded that creating an independent scrollbar is not necessary at the moment. Therefore, we will close the related pull requests. You can find out more about it in the discussion `here `_. + +Did you get stuck anywhere? +--------------------------- +Implementing the bounding box feature took some extra time as I needed to carefully consider its impact on other UI elements that rely on the **TextBlock2D** component. + +What is coming up next? +----------------------- +Next, I will focus on completing the TextBlock2D Bounding Box PR, which will also indirectly finalize the Spinbox PR. diff --git a/v0.10.x/_sources/posts/2023/2023-07-10-week-6-joaodellagli.rst.txt b/v0.10.x/_sources/posts/2023/2023-07-10-week-6-joaodellagli.rst.txt new file mode 100644 index 000000000..e9335c541 --- /dev/null +++ b/v0.10.x/_sources/posts/2023/2023-07-10-week-6-joaodellagli.rst.txt @@ -0,0 +1,63 @@ +Week 6: Things are Starting to Build Up +======================================= + +.. post:: July 10, 2023 + :author: João Victor Dell Agli Floriano + :tags: google + :category: gsoc + + +Hello everyone, time for a other weekly blogpost! Today, I will show you my current progress on my project and latest activities. + +What I did Last Week +-------------------- +Last week I had the goal to implement KDE rendering to the screen (if you want to understand what this is, check my :doc:`last blogpost <2023-07-03-week-5-joaodellagli>`_). +After some days diving into the code, I finally managed to do it: + +.. image:: https://raw.githubusercontent.com/JoaoDell/gsoc_assets/main/images/buffer_compose.png + :align: center + :alt: KDE render to a billboard + +This render may seem clean and working, but the code isn't exactly like that. For this to work, some tricks and work arounds needed to +be done, as I will describe in the section below. + +Also, I reviewed the shader part of Tania's PR `#791 `_, that implement ellipsoid actors inside +FURY. It was my first review of a PR that isn't a blogpost, so it was an interesting experience and I hope I can get better at it. + +It is important as well to point out that I had to dedicate myself to finishing my graduation capstone project's presentation that I will attend +to this week, so I had limited time to polish my code, which I plan to do better this week. + +Where the Problem Was +--------------------- +The KDE render basically works rendering the KDE of a point to a texture and summing that texture to the next render. For this to work, +the texture, rendered to a billboard, needs to be the same size of the screen, otherwise the captured texture will include the black background. +The problem I faced with that is that the billboard scaling isn't exactly well defined, so I had to guess for a fixed screen size +(in this example, I worked with *600x600*) what scaling value made the billboard fit exactly inside the screen (it's *3.4*). That is far from ideal as I +will need to modularize this behavior inside a function that needs to work for every case, so I will need to figure out a way to fix that +for every screen size. For that, I have two options: + +1. Find the scaling factor function that makes the billboard fit into any screen size. +2. Figure out how the scaling works inside the billboard actor to understand if it needs to be refactored. + +The first seems ok to do, but it is kind of a work around as well. The second one is a good general solution, but it is a more delicate one, +as it deals with how the billboard works and already existing applications of it may suffer problems if the scaling is changed. +I will see what is better talking with my mentors. + +Another problem I faced (that is already fixed) relied on shaders. I didn't fully understood how shaders work inside FURY so I was +using my own fragment shader implementation, replacing the already existing one completely. That was working, but I was having an issue +with the texture coordinates of the rendering texture. As I completely replaced the fragment shader, I had to pass custom texture coordinates +to it, resulting in distorted textures that ruined the calculations. Those issues motivated me to learn the shaders API, which allowed me +to use the right texture coordinates and finally render the results you see above. + + +This Week's Goals +----------------- +For this week, I plan to try a different approach Filipi, one of my mentors, told me to do. This approach was supposed to be the original +one, but a communication failure lead to this path I am currently in. This approach renders each KDE calculation into its own billboard, +and those are rendered together with additive blending. After this first pass, this render is captured into a texture and then rendered to +another big billboard. + +Also, I plan to refactor my draft PR `#804 `_ to make it more understandable, as its description still dates back to the time I was using the +flawed Framebuffer implementation, and my fellow GSoC contributors will eventually review it, and to do so, they will need to understand it. + +Wish me luck! \ No newline at end of file diff --git a/v0.10.x/_sources/posts/2023/2023-07-10-week-6-tvcastillod.rst.txt b/v0.10.x/_sources/posts/2023/2023-07-10-week-6-tvcastillod.rst.txt new file mode 100644 index 000000000..2dbd613e5 --- /dev/null +++ b/v0.10.x/_sources/posts/2023/2023-07-10-week-6-tvcastillod.rst.txt @@ -0,0 +1,26 @@ +Week 6: First draft of the Ellipsoid tutorial +============================================= + +.. post:: July 10, 2023 + :author: Tania Castillo + :tags: google + :category: gsoc + +What did I do this week? +------------------------ + +`#PR 818: Tutorial on using ellipsoid actor to visualize tensor ellipsoids for DTI `_ + +I created the PR for the tutorial that will show the use that can be made of the *ellipsoid* actor in the visualization of diffusion tensor ellipsoids. It is still in its most basic stage, but the structure that I have thought of for now consists of: displaying a slice using *tensor_slicer* with spheres of 100, 200, and 724 vertices, and using *ellipsoid* actor, and show a comparison of the visual quality of the tensor ellipsoids. Then, display a ROI using both actors and a whole brain using the *ellipsoid* actor, to show that this new actor gives the possibility to display more data. + +I also submitted the `uncertainty PR `_ for review, in order to start making the necessary corrections. + +What is coming up next? +----------------------- + +I need `#PR 791 `_ to be merged first, but meanwhile, I will start working on the explanation of the tutorial, since I already have the code structure and the idea of what I want to illustrate. I will discuss further work with my mentors at the upcoming meeting, so I can organize myself better and plan how I'm going to address the pending parts of my project. + +Did I get stuck anywhere? +------------------------- + +I found no major difficulties this week. diff --git a/v0.10.x/_sources/posts/2023/2023-07-15-week-7-praneeth.rst.txt b/v0.10.x/_sources/posts/2023/2023-07-15-week-7-praneeth.rst.txt new file mode 100644 index 000000000..db375bd7c --- /dev/null +++ b/v0.10.x/_sources/posts/2023/2023-07-15-week-7-praneeth.rst.txt @@ -0,0 +1,36 @@ +Week 7: Sowing the seeds for TreeUI +=================================== + +.. post:: July 15, 2023 + :author: Praneeth Shetty + :tags: google + :category: gsoc + + +What did you do this week? +-------------------------- +This week, I focused on completing the **TextBlock2D** Bounding Box feature. However, the tests were failing due to automatic background resizing based on content and improper text actor alignment during setup. I encountered difficulties while positioning the text, which caused the text to appear offset and led to test failures. + +Text background greater than the actual maximum size: + +.. image:: https://github.com/fury-gl/fury/assets/64432063/aaf4a764-4480-4f96-9adf-29d9e28135a6 + :align: center + :alt: Text background greater than the actual maximum size in ComboBox2D + +Text offset from center: + +.. image:: https://github.com/fury-gl/fury/assets/64432063/0a3bc1e6-a566-4c08-9ca4-a191525b9c97 + :align: center + :alt: Text offset from center in RingSlider2D + +Additionally, I reviewed PR `#814 `_ and noticed that after PR `#769 `_, all demos and examples were merged into a single folder, which affected the paths used in the Scientific Domain Section. To address this, I created PR `#820 `_ to redirect the links to the correct path. + +As I faced issues with the **TextBlock2D** PR, I took the opportunity to rebase and continue working on the **TreeUI** PR since there were no updates from the author. + +Did you get stuck anywhere? +--------------------------- +While fixing the issues with the tests for the **TextBlock2D** bounding box, I encountered a weird behavior in text positioning when using the center alignment. The output varied depending on the sequence of repositioning which we are still investigating. + +What is coming up next? +----------------------- +I will continue working on the **TreeUI** and resolve the **TextBlock2D** error to ensure both PRs progress smoothly. \ No newline at end of file diff --git a/v0.10.x/_sources/posts/2023/2023-07-17-week-7-joaodellagli.rst.txt b/v0.10.x/_sources/posts/2023/2023-07-17-week-7-joaodellagli.rst.txt new file mode 100644 index 000000000..9237ec1d7 --- /dev/null +++ b/v0.10.x/_sources/posts/2023/2023-07-17-week-7-joaodellagli.rst.txt @@ -0,0 +1,65 @@ +Week 7: Experimentation Done +============================ + +.. post:: July 17, 2023 + :author: João Victor Dell Agli Floriano + :tags: google + :category: gsoc + +Hello everyone, welcome to another weekly blogpost! Let's talk about the current status of my project (spoiler: it is beautiful). + +Last Week's Effort +------------------ +Having accomplished a KDE rendering to a billboard last week, I was then tasked with trying a different approach to how the +rendering was done. So, to recap, below was how I was doing it: + +1. Render one point's KDE offscreen to a single billboard, passing its position and sigma to the fragment shader as uniforms. +2. Capture the last rendering's screen as a texture. +3. Render the next point's KDE, and sum it up with the last rendering's texture. +4. Do this until the end of the points. +5. Capture the final render screen as a texture. +6. Apply post processing effects (colormapping). +7. Render the result to the screen. + +This approach was good, but it had some later limitations and issues that would probably take more processing time and attention to details (correct matrix +transformations, etc) than the ideal. The different idea is pretty similar, but with some differences: + +1. Activate additive blending in OpenGL. +2. Render each point's KDE to its own billboard, with position defined by the point's position, all together in one pass. +3. Capture the rendered screen as a texture. +4. Pass this texture to a billboard. +5. Apply post processing effects (colormapping). +6. Render the result to the screen. + +So I needed to basically do that. + +Was it Hard? +------------ +Fortunately, it wasn't so hard to do it in the end. Following those steps turned out pretty smooth, and after some days, +I had the below result: + +.. image:: https://raw.githubusercontent.com/JoaoDell/gsoc_assets/main/images/final_2d_plot.png + :align: center + :alt: Final 2D KDE render + +This is a 2D KDE render of random 1000 points. For this I used the *"viridis"* colormap from `matplotlib`. Some details worth noting: + +* For this to work, I have implemented three texture helper functions: `window_to_texture()`, `texture_to_actor()` and `colormap_to_texture()`. The first one captures a window and pass it as a texture to an actor, the second one passes an imported texture to an actor, and the last one passes a colormap, prior passed as an array, as a texture to an actor. +* The colormap is directly get from `matplotlib`, available in its `colormaps` object. +* This was only a 2D flatten plot. At first, I could not figure out how to make the connection between the offscreen interactor and the onscreen one, so rotating and moving around the render was not happening. After some ponder and talk to my mentors, they told me to use *callback* functions inside the interactor, and after doing that, I managed to make the 3D render work, which had the following result: + +.. image:: https://raw.githubusercontent.com/JoaoDell/gsoc_assets/main/images/3d_kde_gif.gif + :align: center + :alt: 3D KDE render + +After those results, I refactored my PR `#804 `_ to better fit its current status, and it is +now ready for review. Success! + + +This Week's Goals +----------------- +After finishing the first iteration of my experimental program, the next step is to work on an API for KDE rendering. I plan to meet +with my mentors and talk about the details of this API, so expect an update next week. Also, I plan to take a better look on my fellow GSoC FURY +contributors work so when their PRs are ready for review, I will have to be better prepared for it. + +Let's get to work! \ No newline at end of file diff --git a/v0.10.x/_sources/posts/2023/2023-07-17-week-7-tvcastillod.rst.txt b/v0.10.x/_sources/posts/2023/2023-07-17-week-7-tvcastillod.rst.txt new file mode 100644 index 000000000..99bff5fec --- /dev/null +++ b/v0.10.x/_sources/posts/2023/2023-07-17-week-7-tvcastillod.rst.txt @@ -0,0 +1,24 @@ +Week 7: Adjustments on the Uncertainty Cones visualization +========================================================== + +.. post:: July 17, 2023 + :author: Tania Castillo + :tags: google + :category: gsoc + +What did I do this week? +------------------------ + +I was told to refactor some parts of the uncertainty PR, since I was relying too much on **dipy** functions which is not good because it makes maintenance more difficult as **dipy** requires **FURY** for some functionalities. So I did some adjustments on the uncertainty function parameters and the corresponding tests, hopefully I managed to get with the most appropriate definition but I need to receive a first feedback to see how much I have to adjust the implementation. As I had to delete some relevant code lines inside the uncertainty calculation which consisted of preprocessing the data in order to define the necessary variables for the uncertainty formula, I was also suggested to make a tutorial of this new feature, so I can explain in detail how to obtain and adjust the necessary information, before passing it to the actor, and in general how and what is the purpose of this new function. + +I also continued working on the ellipsoid tutorial, which I hope to finish this week so that I can ask for a first revision. + +What is coming up next? +----------------------- + +I will finish defining some details of the tutorial so that it is ready for review, and now I will start working on the tutorial related to the uncertainty, while I receive feedback on the other PRs. Also, as preparation for the next step I will start exploring on how to address visualization of spherical harmonics for ODF glyphs visualization, I found that a previous GSoC participant at FURY started working on that and also did several work with raymarching and SDF (:doc:`here is a summary of the work <../2020/2020-08-24-final-work-lenix>`), so I will take a deeper look on that to see if I can get something useful I can start with. + +Did I get stuck anywhere? +------------------------- + +Not this week, but I foresee some problems with the uncertainty PR, we will see how it goes. diff --git a/v0.10.x/_sources/posts/2023/2023-07-22-week-8-praneeth.rst.txt b/v0.10.x/_sources/posts/2023/2023-07-22-week-8-praneeth.rst.txt new file mode 100644 index 000000000..c921698cc --- /dev/null +++ b/v0.10.x/_sources/posts/2023/2023-07-22-week-8-praneeth.rst.txt @@ -0,0 +1,27 @@ +Week 8: Another week with TextBlockUI +===================================== + +.. post:: July 22, 2023 + :author: Praneeth Shetty + :tags: google + :category: gsoc + +What did you do this week? +-------------------------- +This week, I delved deeper into the **TextBlock2D** Bounding Box PR to address the challenges with tests and offsetting issues. In a pair programming session with my mentor, we discovered that the offsetting background problem stemmed from the dynamic nature of the bounding box. The issue arose when the **RingSlider2D** component began with an initial text size larger than the current text, which changed as the value was adjusted between 0-100%. This resulted in problems with offsetting and shrinking the bounding box. To resolve this, we decided to make the dynamic bounding box an optional feature. + +Now, the **TextBlock2D** component offers three main features: + +1. Completely static background +2. Dynamic bounding box scaled according to the text +3. Font scaling based on the bounding box + +After tweaking and testing, all the features work seamlessly. + +Did you get stuck anywhere? +---------------------------- +The pair programming session with my mentor proved to be immensely helpful, as it guided me through the whole week. + +What is coming up next? +------------------------ +I will dedicate time to further enhancing the **TreeUI**. My focus will be on updating tree nodes and ensuring proper node positioning during movement. \ No newline at end of file diff --git a/v0.10.x/_sources/posts/2023/2023-07-24-week-8-joaodellagli.rst.txt b/v0.10.x/_sources/posts/2023/2023-07-24-week-8-joaodellagli.rst.txt new file mode 100644 index 000000000..a3b7af50d --- /dev/null +++ b/v0.10.x/_sources/posts/2023/2023-07-24-week-8-joaodellagli.rst.txt @@ -0,0 +1,127 @@ +Week 8: The Birth of a Versatile API +==================================== + +.. post:: July 24, 2023 + :author: João Victor Dell Agli Floriano + :tags: google + :category: gsoc + + +Hello everyone, it's time for another weekly blogpost! Today, I am going to tell you all about how is the KDE API development going, and +to show you the potential this holds for the future! + +Last Week's Effort +------------------ +Last week I told you how I managed to render some KDE renders to the screen, both in 2D and 3D, as you may check by my last blogpost. +My new task was, as I had this example working, to start the API development. In a meeting with Bruno, one of my mentors, we debated +on how could this work, reaching two options: + +1. Implement the KDE in a single, simple actor. +2. Implement a KDE rendering manager, as a class. + +The first one would have the advantage of being simple and pretty straightforward, as a user would only need to call the actor and have +it working on their hands, having the tradeoff of leaving some important steps for a clean API hidden and static. These steps I mention +are related to how this rendering works, as I have previously :doc:`showed you <2023-07-03-week-5-joaodellagli>`, it relies on post-processing effects, +which need an offscreen rendering, that for example are done by the *callback functions*. + +In short, these functions are instructions the user gives to the interactor to run inside the interaction loop. Inside FURY there are tree +types of callbacks passed to the window interactor: + +1. **Timer Callbacks**: Added to the window interactor, they are a set of instructions that will be called from time to time, with interval defined by the user. +2. **Window Callbacks**: Added directly to the window, they are a set of instructions called whenever an specific event is triggered. +3. **Interactor Callbacks**: Added to the window interactor, they are a set of instructions called whenever an specific interaction, for example a mouse left-click, is triggered. + +In this API, I will be using the *Interactor Callback*, set by the ``window.add_iren_callback()`` function, that will be called whenever a *Render* +interaction is detected, and needs to be first passed to the onscreen manager. + +These details are more complicated, and would need, for example, for the user to pass the onscreen manager to the ``actor.kde()`` function. +Also, in the case of a kde actor not being used anymore and being declared, the callback then passed would still exist inside the manager and +be called even when the kde actor is not on screen anymore, which is not ideal. + +Knowing these problems, we thought of a second option, that would have the advantage of not leaving those details and steps behind. It has +the tradeoff of maybe complicating things as it would need to be called after calling the effects manager, but as I will show you below, +it is not that complicated *at all*. + +I also reviewed my fellow GSoC contributors PR's as well, PR `#810 `_ and +`#803 `_. Bruno told me to take a look as well on `Conventional Commits `_ , a way to standardize +commits by prefixes, so I did that as well. + +So how did it go? +----------------- + +Well, the implemented manager class is named ``EffectManager()`` and to initialize it you only need to pass the onscreen manager. +The onscreen manager is the standard FURY window manager you would use in a normal FURY-based program: + +.. code-block:: python + + # Onscreen manager setup + from fury import window + + scene = window.Scene() + + onscreen_manager = window.ShowManager(scene, "demo", (width, height)) + + effects = EffectManager(onscreen_manager) + +After that, to render a KDE calculation of points to the screen, you need only to call its ``kde()`` function: + +.. code-block:: python + + kde_actor = effects.kde(center, points, sigmas, scale = 10.0, colormap = "inferno") + # Those last two are optional + +Pass it to the onscreen manager scene: + +.. code-block:: python + + onscreen_manager.scene.add(kde_actor) + +And to start it, as usual: + +.. code-block:: python + + onscreen_manager.start() + +As simple as that. This three lines of code output the same result as I showed you last week, this time, with different sigmas for each +point: + +.. image:: https://raw.githubusercontent.com/JoaoDell/gsoc_assets/main/images/3d_kde_gif.gif + :align: center + :alt: 3D KDE render + +After having that working, I experimented beyond. See, as I previously said, we are dealing here with *post-processing effects*, with KDE +being only one of the many existing ones, as this `Wikipedia Page `_ on post processing shows. +Knowing that, I tried one of the first filters I learned, the Laplacian one. This filter is, as its name hints, applying the +`Discrete Laplace Operator `_ in an image. This filter shows sudden changes of value, a +good way to detect borders. The process is the same as the kde actor, requiring only the actor you want to apply the filter to. +Below, the result I got from applying that to a box actor: + +.. image:: https://raw.githubusercontent.com/JoaoDell/gsoc_assets/main/images/laplacian1.gif + :align: center + :alt: Laplacian filter applied to a cube object. + +Something I found important to leave as an option was filter compositing. What if an user wanted to, for example, apply one laplacian filter +after another? Well, the example below shows that is possible as well: + +.. image:: https://raw.githubusercontent.com/JoaoDell/gsoc_assets/main/images/laplacian2.gif + :align: center + :alt: Double laplacian application on the box actor. + +It still needs some tweaks and suffers from some bugs, but it works! Those represent important progress as it shows the versatility this +API may present. I have also already implemented `grayscale` and `3x3 gaussian blur` as well: + +.. image:: https://raw.githubusercontent.com/JoaoDell/gsoc_assets/main/images/gaussian_blur.png + :align: center + :alt: 3x3 Gaussian Blur filter applied to a cube. + +.. image:: https://raw.githubusercontent.com/JoaoDell/gsoc_assets/main/images/grayscale.png + :align: center + :alt: Grayscale filter applied to a cube. + +This Week's Goals +----------------- +My plans for this week are to keep working and polishing the API, mainly the KDE part, so it can be ready for a first review. +When that is ready, I plan to experiment with more filters and make this more dynamic, maybe implementing a way to apply custom kernel +transformations, passed by the user, to the rendering process. This has been a really exciting journey and I am getting happy with the results! + +Wish me luck! \ No newline at end of file diff --git a/v0.10.x/_sources/posts/2023/2023-07-25-week-8-tvcastillod.rst.txt b/v0.10.x/_sources/posts/2023/2023-07-25-week-8-tvcastillod.rst.txt new file mode 100644 index 000000000..277aa4303 --- /dev/null +++ b/v0.10.x/_sources/posts/2023/2023-07-25-week-8-tvcastillod.rst.txt @@ -0,0 +1,22 @@ +Week 8: Working on Ellipsoid Tutorial and exploring SH +====================================================== + +.. post:: July 25, 2023 + :author: Tania Castillo + :tags: google + :category: gsoc + +What did I do this week? +------------------------ + +I mainly worked on the ellipsoid actor tutorial, as `PR #791 `_ is finally merged, so I was able to complete the tutorial by adding my implementation. In addition, during the weekly meeting, I received a good overview of the next issue I will be working on, which is using raymarching SDFs to display spherical harmonics (SH) for visualizing ODF glyphs for DTI. I got several ideas and resources which I can start experimenting with, such as `Shadertoy `_ and some base implementations from other FURY contributors. The main drawback when creating these objects is the amount of data required to create them, because depending on the SH order, the number of parameters that the function receives may vary, also unlike the tensors, which are represented only with a 3x3 matrix, here we could have more than 9 values associated with a single glyph, so passing the information from python to the shaders is not so trivial, besides requiring more resources as there is more information that needs to be processed. Some ideas I received were using matrixes instead of vectors, using templating, or even using texture to pass the data. I started to explore these options further, as well as to review in more detail the existing implementations of SH with raymarching, in order to understand them better. + +What is coming up next? +----------------------- + +I currently have two PRs under review, so I will address the comments I receive and update them accordingly. I also will continue to explore and start working on the implementation of these objects so that I can start making adjustments and further discuss possible improvements to the implementation I will make. + +Did I get stuck anywhere? +------------------------- + +Fortunately, I did not encounter any drawbacks this week. diff --git a/v0.10.x/_sources/posts/2023/2023-07-29-week-9-praneeth.rst.txt b/v0.10.x/_sources/posts/2023/2023-07-29-week-9-praneeth.rst.txt new file mode 100644 index 000000000..478a53e5e --- /dev/null +++ b/v0.10.x/_sources/posts/2023/2023-07-29-week-9-praneeth.rst.txt @@ -0,0 +1,25 @@ +Week 9: TextBlock2D is Finally Merged! +====================================== + +.. post:: July 29, 2023 + :author: Praneeth Shetty + :tags: google + :category: gsoc + +What did you do this week? +-------------------------- +Continuing from the previous week, it seemed like we were almost done with the *TextBlock2D*, but there remained a final task of addressing conflicting issues. Being a core part of the UI, *TextBlock2D* had a few compatibility problems with certain other UI elements. + +The default behavior of *TextBox2D* now includes a dynamic bounding box, which scales automatically based on the contained text. Users can customize this option through a simple flag setting. However, this change affected some UI elements like *Combobox2d*, which relied on the default textbox size. Consequently, I had to make updates to ensure compatibility. Additionally, the default initialization of the *TextBlock2D* was completely static, which led to the possibility of the text extending beyond the background and failing certain tests. To tackle this, I made adjustments to the overflow helper function in the *test_elements.py* file. After a few tweaks and issue resolutions, the PR was ready for review and was successfully merged after passing the review process. + +.. image:: https://user-images.githubusercontent.com/64432063/258603191-d540105a-0612-450e-8ae3-ca8aa87916e6.gif + :align: center + :alt: TextBlock2D with different attributes + +Did you get stuck anywhere? +---------------------------- +I encountered some peculiar test failures that were indirectly related to the *TextBlock2D* which at first glance didn't came up. Although after some debugging and a thorough line-by-line analysis, I managed to identify and resolve them. + +What is coming up next? +------------------------ +My next priority will be completing the *SpinBoxUI* now that the *TextBlock2D* is fixed and successfully integrated. \ No newline at end of file diff --git a/v0.10.x/_sources/posts/2023/2023-07-31-week-9-joaodellagli.rst.txt b/v0.10.x/_sources/posts/2023/2023-07-31-week-9-joaodellagli.rst.txt new file mode 100644 index 000000000..d02d9fd2a --- /dev/null +++ b/v0.10.x/_sources/posts/2023/2023-07-31-week-9-joaodellagli.rst.txt @@ -0,0 +1,116 @@ +Week 9: It is Polishing Time! +============================= + +.. post:: July 31, 2023 + :author: João Victor Dell Agli Floriano + :tags: google + :category: gsoc + + +Hello everyone, it's time for another weekly blogpost! Today, I am going to update you on my project's latest changes. + +Last Week's Effort +------------------ +After having finished a first draft of the API that will be used for the KDE rendering, and showing how it could be used +for other post-processing effects, my goal was to clean the code and try some details that would add to it so it could be better +complete. Having that in mind, I invested in three work fronts: + +1. Fixing some bugs related to the rendering more than one post-processing effect actor. +2. Experimenting with other rendering kernels (I was using the *gaussian* one only). +3. Completing the KDE render by renormalizing the values in relation to the number of points (one of the core KDE details). + +Both three turned out more complicated than it initially seemed, as I will show below. + +So how did it go? +----------------- +The first one I did on monday-tuesday, and I had to deal with some issues regarding scaling and repositioning. Due to implementation +choices, the final post-processed effects were rendered either bigger than they were in reality, or out of their original place. +After some time dedicated to finding the root of the problems, I could fix the scaling issue, however I realised I would need to, +probably, rethink the way the API was implemented. As this general post-processing effects is a side-project that comes as a consequence of +my main one, I decided to leave that investment to another time, as I would need to guarantee the quality of the second. + +The second was an easy and rather interesting part of my week, as I just needed to setup new kernel shaders. Based on +`scikit-learn KDE documentation `_, I could successfully implement the following kernels: + +* Gaussian + +.. math:: + K(x, y) = e^{\frac{-(x^2 + y^2)}{2\sigma^2}} + +* Tophat + +.. math:: + K(x, y) = 1.0, \ \ |x^2 + y^2| < \sigma + +* Epanechnikov + +.. math:: + K(x, y) = 1 - \frac{x^2 + y^2}{\sigma^2} + +* Exponential + +.. math:: + K(x, y) = e^{\frac{-|x^2 + y^2|}{\sigma}} + +* Linear + +.. math:: + K(x, y) = 1 - \frac{|x^2 + y^2|}{\sigma}, \ \ |x^2 + y^2| < \sigma + +* Cosine + +.. math:: + K(x, y) = cos(\frac{\pi|x^2 + y^2|}{2\sigma}) + +That outputted the following (beautiful) results for a set of 1000 random points with random sigmas: + +.. image:: https://raw.githubusercontent.com/JoaoDell/gsoc_assets/main/images/kernels.png + :align: center + :alt: Different kernel approaches + + +The third one is still being a trickier challenge. If you recall from my first blogposts, I spent something around *one month* trying to setup +float framebuffer objects to FURY with VTK so I could use them in my project. After spending all of that time with no results, +me and Bruno, my mentor, :doc:`found a way <2023-07-03-week-5-joaodellagli.rst>` to do what we wanted to do, but using a different VTK class, +`vtkWindowToImageFilter `_. Well, it was a good workaround back then and +it lead me all the way here, however now it is costing a price. The float framebuffers were an important part of the project because they +would allow us to pass *32-bit float information* from one shader to another, which would be important as they would allow the densities to +have higher precision and more fidelity to the calculations. When rendering a KDE of a given set of points, we use the below function: + +.. math:: + KDE(x, y) = \frac{1}{n} \sum_{i = 0}^n K(x, y) + +If the number of points :math:`n` is big enough, some KDE results will be really low. This presents a real problem to our implementation because, without +the float framebuffers, it is currently only being possible to pass *8-bit unsigned char* information, that only allows 256 values. +This is far from ideal, as low values would have alone densities low enough to disappear. This presented a problem as to renormalize the +densities, I was retrieving the texture to the CPU, calculating its minimum and maximum values, and passing to the fragment shader as uniforms +for the renormalization, which didn't work if the maximum values calculated were zero. + +One solution I thought to solve that was a really heavy workaround: if an unsigned float is 32-bit and I have exactly 4 8-bit +unsigned chars, why not try to pack this float into these 4 chars? Well, this is an interesting approach which I figured out is already an +old one, being reported in `GPU Gems's chapter 12 `_. +Unfortunately I haven't tried yet this implementation yet, and went for one I thought myself, which haven't exactly worked. I also tried +this implementation from `Aras Pranckevičius' website `_, which seems +to be working, even though not perfectly: + +.. image:: https://raw.githubusercontent.com/JoaoDell/gsoc_assets/main/images/noisy%20kde.png + :align: center + :alt: Noisy float to RGBA encoding + +As you can see, this implementation is *really noisy*. I think this has to deal with floating point rounding errors, so to try to mitigate +that, I experimented applying a *13x13 gaussian blur* to it. Below, what I got from that: + +.. image:: https://raw.githubusercontent.com/JoaoDell/gsoc_assets/main/images/blurred_kde.png + :align: center + :alt: Blurred KDE result + +That looks way better, even though not ideal yet. + +This Week's Goals +----------------- +Talking with my mentors, we decided it was better if I focused on the version without the renormalization for now, as it was already +done and running fine. So for this week, I plan to clean my PR to finally have it ready for a first review, and maybe add to it a little +UI tool to control the intensity of the densities. That should take me some time and discussion, but I hope for it to be ready by the +end of the week. + +Let's get to work! diff --git a/v0.10.x/_sources/posts/2023/2023-07-31-week-9-tvcastillod.rst.txt b/v0.10.x/_sources/posts/2023/2023-07-31-week-9-tvcastillod.rst.txt new file mode 100644 index 000000000..3c8549ee1 --- /dev/null +++ b/v0.10.x/_sources/posts/2023/2023-07-31-week-9-tvcastillod.rst.txt @@ -0,0 +1,26 @@ +Week 9: Tutorial done and polishing DTI uncertainty +=================================================== + +.. post:: July 31, 2023 + :author: Tania Castillo + :tags: google + :category: gsoc + +What did I do this week? +------------------------ + +I addressed the comments from the tutorial of `PR #818 `_ related to how to display specific visualizations I wanted to make. I was suggested to use *ShowManager* to handle the zoom of the scene and also to use *GridUI* to display several actors at the same time for a visual quality comparison of the tensors. Below are some images generated for the tutorial that is almost done. + +.. image:: https://user-images.githubusercontent.com/31288525/260906510-d422e7b4-3ba3-4de6-bfd0-09c04bec8876.png + :width: 600 + :align: center + +What is coming up next? +----------------------- + +There are some issues with the tests of the uncertainty implementation, specifically a segmentation problem that has to be with the shaders, so I expect to correct the problem by next week. + +Did I get stuck anywhere? +------------------------- + +I'm still thinking about how to approach the implementation of the spherical harmonics for ODF glyphs. Most of the implementations I have found are static so my task would be to try to parametrize the existing functions, so I can pass data from Python to the shaders properly so that I can obtain the same result as the current *odf_slicer*. diff --git a/v0.10.x/_sources/posts/2023/2023-08-05-week-10-praneeth.rst.txt b/v0.10.x/_sources/posts/2023/2023-08-05-week-10-praneeth.rst.txt new file mode 100644 index 000000000..4dfeff75b --- /dev/null +++ b/v0.10.x/_sources/posts/2023/2023-08-05-week-10-praneeth.rst.txt @@ -0,0 +1,21 @@ +Week 10: Its time for a Spin-Box! +================================= + +.. post:: August 05, 2023 + :author: Praneeth Shetty + :tags: google + :category: gsoc + +What did you do this week? +-------------------------- +This week, my focus shifted to the ``SpinBoxUI`` after wrapping up work on ``TextBlock2D``. ``SpinBoxUI`` is a component that allows users to select a value by spinning through a range. To ensure a smooth transition, I made adjustments in ``SpinBoxUI`` to align it with the recent updates in ``TextBlock2D``. To make things even clearer and more user-friendly, I initiated a continuous code improvement process. I introduced setters and getters that enable easier customization of ``TextBlock2D``'s new features, such as **auto_font_scale** and **dynamic_bbox**. These tools simplify the process of adjusting these settings, and you can see the ongoing changes in pull request `#830 `_. + +Simultaneously, I worked on improving the ``FileDialog`` component. Since the ``FileDialog`` PR was based on an older version, it required updates to match the recent developments in ``TextBlock2D``. This involved restructuring the code and making sure that everything worked smoothly together. You can checkout the progress here at PR `#832 `_. + +Did you get stuck anywhere? +--------------------------- +Thankfully, this week was quite smooth sailing without any major roadblocks. + +What is coming up next? +----------------------- +Looking ahead, my plan is to finalize the integration of the updated ``TextBlock`` and ``SpinBoxUI`` components. This entails making sure that everything works seamlessly together and is ready for the next stages of development. \ No newline at end of file diff --git a/v0.10.x/_sources/posts/2023/2023-08-07-week-10-joaodellagli.rst.txt b/v0.10.x/_sources/posts/2023/2023-08-07-week-10-joaodellagli.rst.txt new file mode 100644 index 000000000..51beb1e9f --- /dev/null +++ b/v0.10.x/_sources/posts/2023/2023-08-07-week-10-joaodellagli.rst.txt @@ -0,0 +1,37 @@ +Week 10: Ready for Review! +========================== + +.. post:: August 07, 2023 + :author: João Victor Dell Agli Floriano + :tags: google + :category: gsoc + +Hello everyone, it's time for another weekly blogpost! + +Last Week's Effort +------------------ +After talking with my mentors, I was tasked with getting my API PR `#826 `_ ready for review, +as it still needed some polishing, and the most important of all, it needed its tests working, as this was something I haven't invested time since its creation. +Having that in mind, I have spent the whole week cleaning whatever needed, writing the tests, and also writing a simple example of its +usage. I also tried implementing a little piece of UI so the user could control the intensity of the bandwidth of the KDE render, but +I had a little problem I will talk about below. + + +So how did it go? +----------------- +Fortunately, for the cleaning part, I didn't have any trouble, and my PR is finally ready for review! The most complicated part was to write the tests, as this is something that +requires attention to understand what needs to be tested, exactly. As for the UI part, I managed to have a slider working for the +intensity, however, it was crashing the whole program for a reason, so I decided to leave this idea behind for now. +Below, an example of how this should work: + +.. image:: https://raw.githubusercontent.com/JoaoDell/gsoc_assets/main/images/slider.gif + :align: center + :alt: Buggy slider for the intensity control of the bandwidth of the KDE + +This Week's Goals +----------------- +After a meeting with my mentors, we decided that this week's focus should be on finding a good usage example of the KDE rendering feature, +to have it as a showcase of the capability of this API. Also, they hinted me some changes that need to be done regarding the API, so I +will also invest some time on refactoring it. + +Wish me luck! \ No newline at end of file diff --git a/v0.10.x/_sources/posts/2023/2023-08-08-week-10-tvcastillod.rst.txt b/v0.10.x/_sources/posts/2023/2023-08-08-week-10-tvcastillod.rst.txt new file mode 100644 index 000000000..660dc6366 --- /dev/null +++ b/v0.10.x/_sources/posts/2023/2023-08-08-week-10-tvcastillod.rst.txt @@ -0,0 +1,28 @@ +Week 10 : Start of SH implementation experiments +================================================ + +.. post:: August 08, 2023 + :author: Tania Castillo + :tags: google + :category: gsoc + +What did I do this week? +------------------------ + +I started formally working on SH implementation. I was told to start first doing a simple program where I can modify in real-time the order :math:`l` and degree :math:`m`, parameters corresponding to the `Spherical Harmonics function `_ :math:`Y^m_l(\theta,\phi)=`, based on `previous work `_. That is just one part of the final ODF calculation, but here is what a first experimental script looks like. + +.. image:: https://user-images.githubusercontent.com/31288525/260910073-10b0edd4-40e3-495c-85ad-79993aef3b19.png + :width: 600 + :align: center + +I did it in order to make sure it was visually correct and also to understand better how those 2 parameters are related and need to be incorporated into the final calculation. There is one issue at first sight that needs to be addressed, and that is the scaling, since for SH with a degree near 0, the object gets out of bounds. + +What is coming up next? +----------------------- + +I will keep polishing details from my current open PRs, hopefully, I will get another PR merged before the last GSoC week. + +Did I get stuck anywhere? +------------------------- + +Not sure about how to use the current implementation I have to get similar visualizations made with *odf_slicer*, since the parameters that the function receive are different, so I need to take a deeper look and see where it might be the connection or if I should make some adjustments on the parameters. diff --git a/v0.10.x/_sources/posts/2023/2023-08-12-week-11-praneeth.rst.txt b/v0.10.x/_sources/posts/2023/2023-08-12-week-11-praneeth.rst.txt new file mode 100644 index 000000000..4fd8efca0 --- /dev/null +++ b/v0.10.x/_sources/posts/2023/2023-08-12-week-11-praneeth.rst.txt @@ -0,0 +1,34 @@ +Week 11: Bye Bye SpinBox +======================== + +.. post:: August 12, 2023 + :author: Praneeth Shetty + :tags: google + :category: gsoc + + +What did you do this week? +-------------------------- +Building upon the progress of the previous week, a major milestone was reached with the merging of PR `#830 `_. This PR added essential "getters" and "setters" for the new features of ``TextBlock``, making it easier to handle changes. This, in turn, facilitated the integration of ``SpinBoxUI`` with the updated ``TextBlock``. + +However, while working on ``SpinBoxUI``, a critical issue emerged. As ``SpinBoxUI`` allows users to input characters and symbols into an editable textbox, it posed a risk of program crashes due to invalid inputs. To counter this, I introduced a validation check to ensure that the input was a valid number. If valid, the input was converted; otherwise, it reverted to the previous value. After thorough testing and review, PR `#499 `_ was successfully merged. + +.. image:: https://user-images.githubusercontent.com/64432063/261409747-511e535b-185c-4e70-aaa8-5296c93e5344.gif + :align: center + :width: 500 + :alt: SpinBoxUI + +Meanwhile, a concern with the textbox's behavior was identified when ``SpinBoxUI`` was scaled to a larger size. Specifically, the text occasionally touched the top or bottom boundary, creating an overflow appearance. Although initial solutions were attempted, the complexity of the issue required further consideration. This issue has been documented in more detail in Issue `#838 `_, where it is marked as a low-priority item. + +.. figure:: https://user-images.githubusercontent.com/64432063/133194003-53e2dac6-31e0-444e-b7f1-a9e71545f560.jpeg + :align: center + :alt: TextBlock2D text positioning issue + + +Did you get stuck anywhere? +--------------------------- +The challenge of the week centered around addressing the textbox's overflow behavior in ``SpinBoxUI``. + +What is coming up next? +----------------------- +Looking ahead, the focus remains on refining the FileDialog component, as the significant progress with ``TextBlock`` and ``SpinBoxUI`` prepares us to shift attention to other aspects of development. diff --git a/v0.10.x/_sources/posts/2023/2023-08-14-week-11-joaodellagli.rst.txt b/v0.10.x/_sources/posts/2023/2023-08-14-week-11-joaodellagli.rst.txt new file mode 100644 index 000000000..fd5c9dace --- /dev/null +++ b/v0.10.x/_sources/posts/2023/2023-08-14-week-11-joaodellagli.rst.txt @@ -0,0 +1,86 @@ +Week 11: A Refactor is Sometimes Needed +======================================= + +.. post:: August 14, 2023 + :author: João Victor Dell Agli Floriano + :tags: google + :category: gsoc + +Hello everyone, it's time for another weekly blogpost! Today I am going to share some updates on the API refactoring +I was working on with my mentors. + +Last Week's Effort +------------------ +As I shared with you :doc:`last week <2023-08-07-week-10-joaodellagli>`, the first draft of my API was finally ready for review, as +I finished tweaking some remaining details missing. I was tasked with finding a good example of the usage of the tools we proposed, +and I started to do that, however after testing it with some examples, I figured out some significant bugs were to be fixed. Also, +after some reviews and hints from some of my mentors and other GSoC contributors, we realised that some refactoring should be done, +mainly focused on avoiding bad API usage from the user. + +So how did it go? +----------------- +Initially, I thought only one bug was the source of the issues the rendering presented, but it turned out to be two, which I will +explain further. + +The first bug was related to scaling and misalignment of the KDE render. The render of the points being post-processed was not only +with sizes different from the original set size, but it was also misaligned, making it appear in positions different from the points' +original ones. After some time spent, I figured out the bug was related to the texture coordinates I was using. Before, this is how +my fragment shader looked: + +.. code-block:: C + + vec2 res_factor = vec2(res.y/res.x, 1.0); + vec2 tex_coords = res_factor*normalizedVertexMCVSOutput.xy*0.5 + 0.5; + float intensity = texture(screenTexture, tex_coords).r; + +It turns out using this texture coordinates for *this case* was not the best choice, as even though it matches the fragment positions, +the idea here was to render the offscreen window, which has the same size as the onscreen one, to the billboard actor. With that in mind, +I realised the best choice was using texture coordinates that matched the whole screen positions, coordinates that were derived from the +``gl_FragCoord.xy``, being the division of that by the resolution of the screen, for normalization. Below, the change made: + +.. code-block:: C + + vec2 tex_coords = gl_FragCoord.xy/res; + float intensity = texture(screenTexture, tex_coords).r; + +This change worked initially, although with some problems, that later revealed the resolution of the offscreen window needed to be +updated inside the callback function as well. Fixing that, it was perfectly aligned and scaled! + +The second bug was related with the handling of the bandwidth, former sigma parameter. I realised I wasn't dealing properly with the option of the user passing only +one single bandwidth value being passed, so when trying that, only the first point was being rendered. I also fixed that and it worked, +so cheers! + +As I previously said, the bugs were not the only details I spent my time on last week. Being reviewed, the API design, even +though simple, showed itself vulnerable to bad usage from the user side, requiring some changes. The changes suggested by mentors were, +to, basically, take the ``kde`` method out of the ``EffectManager`` class, and create a new class from it inside an ``effects`` module, +like it was a special effects class. With this change, the KDE setup would go from: + +.. code-block:: python + + em = EffectManager(show_manager) + + kde_actor = em.kde(...) + + show_manager.scene.add(kde_actor) + +To: + +.. code-block:: python + + em = EffectManager(show_manager) + + kde_effect = KDE(...) + + em.add(kde_effect) + +Not a gain in line shortening, however, a gain in security, as preventing users from misusing the kde_actor. Something worth noting is +that I learned how to use the ``functools.partial`` function, that allowed me to partially call the callback function with only some +parameters passed. + + +This Week's Goals +----------------- +Having that refactoring made, now I am awaiting for a second review so we could finally wrap it up and merge the first stage of this API. +With that being done, I will write the final report and wrap this all up. + +Let's get to work! diff --git a/v0.10.x/_sources/posts/2023/2023-08-16-week-11-tvcastillod.rst.txt b/v0.10.x/_sources/posts/2023/2023-08-16-week-11-tvcastillod.rst.txt new file mode 100644 index 000000000..503fbed41 --- /dev/null +++ b/v0.10.x/_sources/posts/2023/2023-08-16-week-11-tvcastillod.rst.txt @@ -0,0 +1,32 @@ +Week 11 : Adjusting ODF implementation and looking for solutions on issues found +================================================================================ + +.. post:: August 16, 2023 + :author: Tania Castillo + :tags: google + :category: gsoc + +What did I do this week? +------------------------ + +I continued to experiment with the ODF glyph implementation. Thanks to one of my mentors I figured out how to get the missing data corresponding to the SH coefficients :math:`a^l_m` part of the function :math:`f(\theta, \phi)` described `here `_. I also was told to make sure to implement the correct SH basis since there are different definitions from the literature, I have to focus now in the one proposed by Descoteaux, described in `this paper `_, which is labeled in *dipy* as *descoteaux07*. To do this I had to make a small adjustment to the base implementation that I took as a reference, from which I obtained a first result using SH of order 4. + +.. image:: https://user-images.githubusercontent.com/31288525/260909561-fd90033c-018a-465b-bd16-3586bb31ca36.png + :width: 600 + :align: center + +It appears that the results on the shape are about the same, except for the direction, but there is still work to be done. + +What is coming up next? +----------------------- + +For now, there are 3 things I will continue to work on: + +- The color and lighting. As these objects present curvatures with quite a bit of detail in some cases, this is something that requires more specific lighting work, in addition to having now not only one color but a color map. +- The scaling. This is something I still don't know how to deal with. I had to adjust it manually for now, but the idea is to find a relationship between the coefficients and the final object size so it can be automatically scaled, or maybe there is a proper way to pre-process this data before passing it to the shaders to get the right result at once. +- How to pass the information of the coefficients efficiently. Right now I'm creating one actor per glyph since I'm using a uniform array to pass the coefficients, but the idea is to pass all the data at once. I found several ideas `here `_ of how to pass a list of values to the fragment shader directly, I just need to explore deeper how this can be done on **FURY**, and see which option is most suitable. + +Did I get stuck anywhere? +------------------------- + +All the points mentioned above are things that I tried to fix, however, it is something that I need to look at in much more detail and that I know is going to take me some time to understand and test before I get to the expected result. I hope to get some ideas from my mentors and fellow GSoC contributors on how I can proceed to deal with each of the problems. diff --git a/v0.10.x/_sources/posts/2023/2023-08-19-week-12-praneeth.rst.txt b/v0.10.x/_sources/posts/2023/2023-08-19-week-12-praneeth.rst.txt new file mode 100644 index 000000000..d34b54ad0 --- /dev/null +++ b/v0.10.x/_sources/posts/2023/2023-08-19-week-12-praneeth.rst.txt @@ -0,0 +1,53 @@ +Week 12: FileDialog Quest Begins! +================================= + +.. post:: August 19, 2023 + :author: Praneeth Shetty + :tags: google + :category: gsoc + + +What did you do this week? +-------------------------- +During this week, I initiated my work on the ``FileDialog`` PR, which had been started by Soham. The initial version of the ``FileDialog`` can be found at `#294 `_. To start, I focused on rebasing the PR. Since this PR was based on an older version, there were some updates to the overall UI structure that needed to be addressed for compatibility. While handling this, I identified a set of issues that I documented in the current PR `#832 `_. These mainly revolved around: + +1. Resizing ``FileDialog`` and related components. +2. Rectifying the text overflow problem. +3. Dealing with a ``ZeroDivisionError``. +4. Fixing the positioning of items in the ``ListBox2D``. + +I systematically approached each of these challenges: + +**Resizing FileMenu and Related Components:** This was a fairly complex task since it involved intricate dependencies, such as the ``FileDialog`` relying on the ``FileMenu``, which, in turn, was dependent on ``ListBox2D`` and ``Panel2D`` resizing. To make the process manageable, I decided to progress incrementally in a separate PR a bit later. + +**Text Overflow Issue:** The problem with text overflow was rooted in our previous approach, which involved executing these actions only when the ``TextBlock2D`` had a scene property. Although this approach suited the previous version of ``TextBlock2D``, the recent refactoring led to the removal of this property. The scene was previously utilized to determine the text actor's size. However, we had new methodologies to calculate these sizes, which are detailed in `#803 `_. + +.. image:: https://github.com/fury-gl/fury/assets/64432063/b001f9d3-a5e8-45ad-8605-85df595b5654 + :align: center + :alt: Text Overflow Before + +.. image:: https://github.com/fury-gl/fury/assets/64432063/d3c9c3a3-e601-45ab-8975-2b1e98acf1d3 + :align: center + :alt: Text Overflow After + +**Addressing ZeroDivisionError:** The ``ZeroDivisionError`` emerged when the total number of values was the same as the number of slots. The issue lay in the separation of these values for calculating the scrollbar's height parameter. Unfortunately, this calculation error occurred when this would return us zero while updating the scrollbar. To counter this, I implemented a conditional check to ascertain whether the value is zero or not. + +**Correcting ``ListBox2D`` Item Positioning:** Another challenge I encountered related to the improper positioning of ``ListBox2D`` item's background. When a slot was not visible, its background was resized to zero, and visibility was set to off. Consequently, during the calculation of updated positions, the height was considered zero, leading to mispositioning. I resolved this by refraining from resizing and solely toggling visibility, achieving the desired result. + +.. image:: https://github.com/fury-gl/fury/assets/64432063/e2805934-b037-47fd-872c-0b284b298d3c + :align: center + :alt: ListBox2D mispositioning Before + +.. image:: https://github.com/fury-gl/fury/assets/64432063/3bc1aabb-bb79-4e26-817d-a2a2ddd20ea3 + :align: center + :alt: Fixed ListBox2D mispositioning + +Did you get stuck anywhere? +--------------------------- +Among the challenges I faced, one notable instance involved addressing the visibility issue in ``TreeUI``. Despite my attempts at various solutions, none yielded the desired outcome. The ``TreeUI`` exhibited either full visibility or no visibility at all. In this situation, I sought guidance from my mentor to find a viable solution. + + +What is coming up next? +----------------------- +The ``FileDialog`` implementation is nearly finalized, and my plan is to work on any review, feedback or suggestions that might arise. Following this, I will shift my attention towards addressing the ``TreeUI``. + diff --git a/v0.10.x/_sources/posts/2023/2023-08-21-joaodellagli-final-report.rst.txt b/v0.10.x/_sources/posts/2023/2023-08-21-joaodellagli-final-report.rst.txt new file mode 100644 index 000000000..33650149a --- /dev/null +++ b/v0.10.x/_sources/posts/2023/2023-08-21-joaodellagli-final-report.rst.txt @@ -0,0 +1,360 @@ +.. image:: https://developers.google.com/open-source/gsoc/resources/downloads/GSoC-logo-horizontal.svg + :height: 40 + :target: https://summerofcode.withgoogle.com/programs/2023/projects/ED0203De + +.. image:: https://www.python.org/static/img/python-logo@2x.png + :height: 40 + :target: https://summerofcode.withgoogle.com/programs/2023/organizations/python-software-foundation + +.. image:: https://python-gsoc.org/logos/fury_logo.png + :width: 40 + :target: https://fury.gl/latest/index.html + + + +Google Summer of Code Final Work Product +======================================== + +.. post:: August 21 2023 + :author: João Victor Dell Agli Floriano + :tags: google + :category: gsoc + +- **Name:** João Victor Dell Agli Floriano +- **Organisation:** Python Software Foundation +- **Sub-Organisation:** FURY +- **Project:** `FURY - Project 2. Fast 3D kernel-based density rendering using billboards. `_ + + +Abstract +-------- +This project had the goal to implement 3D Kernel Density Estimation rendering to FURY. Kernel Density Estimation, or KDE, is a +statistical method that uses kernel smoothing for modeling and estimating the density distribution of a set of points defined +inside a given region. For its graphical implementation, it was used post-processing techniques such as offscreen rendering to +framebuffers and colormap post-processing as tools to achieve the desired results. This was completed with a functional basic KDE +rendering result, that relies on a solid and easy-to-use API, as well as some additional features. + +Proposed Objectives +------------------- + +- **First Phase** : Implement framebuffer usage in FURY + * Investigate the usage of float framebuffers inside FURY's environment. + * Implement a float framebuffer API. + +- **Second Phase** : Shader-framebuffer integration + * Implement a shader that uses a colormap to render framebuffers. + * Escalate this rendering for composing multiple framebuffers. + +- **Third Phase** : KDE Calculations + * Investigate KDE calculation for point-cloud datasets. + * Implement KDE calculation inside the framebuffer rendering shaders. + * Test KDE for multiple datasets. + +Objectives Completed +-------------------- + +- **Implement framebuffer usage in FURY** + The first phase, addressed from *May/29* to *July/07*, started with the investigation of + `VTK's Framebuffer Object `_, a vital part of this project, to understand + how to use it properly. + + Framebuffer Objects, abbreviated as FBOs, are the key to post-processing effects in OpenGL, as they are used to render things offscreen and save the resulting image to a texture + that will be later used to apply the desired post-processing effects within the object's `fragment shader `_ + rendered to screen, in this case, a `billboard `_. In the case of the + `Kernel Density Estimation `_ post-processing effect, we need a special kind of FBO, one that stores textures' + values as floats, different from the standard 8-bit unsigned int storage. This is necessary because the KDE rendering involves rendering every KDE point calculation + to separate billboards, rendered to the same scene, which will have their intensities, divided by the number of points rendered, blended with + `OpenGL Additive Blending `_, and if a relative big number of points are rendered at the + same time, 32-bit float precision is needed to guarantee that small-intensity values will not be capped to zero, and disappear. + + After a month going through VTK's FBO documentation and weeks spent trying different approaches to this method, it would not work + properly, as some details seemed to be missing from the documentation, and asking the community haven't solved the problem as well. + Reporting that to my mentors, which unsuccessfully tried themselves to make it work, they decided it was better if another path was taken, using + `VTK's WindowToImageFilter `_ method as a workaround, described + in this `blogpost `_. This method helped the development of + three new functions to FURY, *window_to_texture()*, *texture_to_actor()* and *colormap_to_texture()*, that allow the passing of + different kinds of textures to FURY's actor's shaders, the first one to capture a window and pass it as a texture to an actor, + the second one to pass an external texture to an actor, and the third one to specifically pass a colormap as a texture to an + actor. It is important to say that *WindowToImageFilter()* is not the ideal way to make it work, as this method does not seem to + support float textures. However, a workaround to that is currently being worked on, as I will describe later on. + + *Pull Requests:* + + - **KDE Rendering Experimental Program (Needs major revision):** `https://github.com/fury-gl/fury/pull/804 `_ + + The result of this whole FBO and WindowToImageFilter experimentation is well documented in PR + `#804 `_ that implements an experimental version of a KDE rendering program. + The future of this PR, as discussed with my mentors, is to be better documented to be used as an example for developers on + how to develop features in FURY with the tools used, and it shall be done soon. + +- **Shader-framebuffer integration** + The second phase, which initially was thought of as "Implement a shader that uses a colormap to render framebuffers" and "Escalate this + rendering for composing multiple framebuffers" was actually a pretty simple phase that could be addressed in one week, *July/10* + to *July/17*, done at the same time as the third phase goal, documented in this + `blogpost `_. As FURY already had a tool for generating and + using colormaps, they were simply connected to the shader part of the program as textures, with the functions explained above. + Below, is the result of the *matplotlib viridis* colormap passed to a simple gaussian KDE render: + + .. image:: https://raw.githubusercontent.com/JoaoDell/gsoc_assets/main/images/final_2d_plot.png + :align: center + :alt: Final 2D plot + + That is also included in PR `#804 `_. Having the 2D plot ready, some time was taken to + figure out how to enable a 3D render, that includes rotation and other movement around the set rendered, which was solved by + learning about the callback properties that exist inside *VTK*. Callbacks are ways to enable code execution inside the VTK rendering + loop, enclosed inside *vtkRenderWindowInteractor.start()*. If it is desired to add a piece of code that, for example, passes a time + variable to the fragment shader over time, a callback function can be declared: + + .. code-block:: python + + from fury import window + t = 0 + showm = window.ShowManager(...) + + def callback_function: + t += 0.01 + pass_shader_uniforms_to_fs(t, "t") + + showm.add_iren_callback(callback_function, "RenderEvent") + + The piece of code above created a function that updates the time variable *t* in every *"RenderEvent"*, and passes it to the + fragment shader. With that property, the camera and some other parameters could be updated, which enabled 3D visualization, that + then, outputted the following result, using *matplotlib inferno* colormap: + + .. image:: https://raw.githubusercontent.com/JoaoDell/gsoc_assets/main/images/3d_kde_gif.gif + :align: center + :alt: 3D Render gif + +- **KDE Calculations** (ongoing) + As said before, the second and third phases were done simultaneously, so after having a way to capture the window and use it as a + texture ready, the colormap ready, and an initial KDE render ready, all it was needed to do was to improve the KDE calculations. + As this `Wikipedia page `_ explains, a KDE calculation is to estimate an + abstract density around a set of points defined inside a given region with a kernel, that is a function that models the density + around a point based on its associated distribution :math:`\sigma`. + + A well-known kernel is, for example, the **Gaussian Kernel**, that says that the density around a point :math:`p` with distribution + :math:`\sigma` is defined as: + + .. math:: + + GK_{\textbf{p}, \sigma} (\textbf{x}) = e^{-\frac{1}{2}\frac{||\textbf{x} - \textbf{p}||^2}{\sigma^2}} + + Using that kernel, we can calculate the KDE of a set of points :math:`P` with associated distributions :math:`S` calculating their individual + Gaussian distributions, summing them up and dividing them by the total number of points :math:`n`: + + .. math:: + + KDE(A, S)=\frac{1}{n}\sum_{i = 0}^{n}GK(x, p_{i}, \sigma_{i}) + + So I dove into implementing all of that into the offscreen rendering part, and that is when the lack of a float framebuffer would + charge its cost. As it can be seen above, just calculating each point's density isn't the whole part, as I also need to divide + everyone by the total number of points :math:`n`, and then sum them all. The problem is that, if the number of points its big enough, + the individual densities will be really low, and that would not be a problem for a 32-bit precision float framebuffer, but that is + *definitely* a problem for a 8-bit integer framebuffer, as small enough values will simply underflow and disappear. That issue is + currently under investigation, and some solutions have already being presented, as I will show in the **Objectives in Progress** + section. + + Apart from that, after having the experimental program ready, I focused on modularizing it into a functional and simple API + (without the :math:`n` division for now), and I could get a good set of results from that. The API I first developed implemented the + *EffectManager* class, responsible for managing all of the behind-the-scenes steps necessary for the kde render to work, + encapsulated inside the *ÈffectManager.kde()* method. It had the following look: + + .. code-block:: python + from fury.effect_manager import EffectManager + from fury import window + + showm = window.ShowManager(...) + + # KDE rendering setup + em = EffectManager(showm) + kde_actor = em.kde(...) + # End of KDE rendering setup + + showmn.scene.add(kde_actor) + + showm.start() + + Those straightforward instructions, that hid several lines of code and setup, could manage to output the following result: + + .. image:: https://raw.githubusercontent.com/JoaoDell/gsoc_assets/main/images/fianl_3d_plot.png + :align: center + :alt: API 3D KDE plot + + And this was not the only feature I had implemented for this API, as the use of *WindowToImageFilter* method opened doors for a + whole new world for FURY: The world of post-processing effects. With this features setup, I managed to implement a *gaussian blur* + effect, a *grayscale* effect and a *Laplacian* effect for calculating "borders": + + .. image:: https://raw.githubusercontent.com/JoaoDell/gsoc_assets/main/images/gaussian_blur.png + :align: center + :alt: Gaussian Blur effect + + .. image:: https://raw.githubusercontent.com/JoaoDell/gsoc_assets/main/images/grayscale.png + :align: center + :alt: Grayscale effect + + .. image:: https://raw.githubusercontent.com/JoaoDell/gsoc_assets/main/images/laplacian1.gif + :align: center + :alt: Laplacian effect + + As this wasn't the initial goal of the project and I still had several issues to deal with, I have decided to leave these features as a + future addition. + + Talking with my mentors, we realized that the first KDE API, even though simple, could lead to bad usage from users, as the + *em.kde()* method, that outputted a *FURY actor*, had dependencies different from any other object of its kind, making it a new + class of actors, which could lead to confusion and bad handling. After some pair programming sessions, they instructed me to take + a similar, but different road from what I was doing, turning the kde actor into a new class, the *KDE* class. This class would + have almost the same set of instructions present in the prior method, but it would break them in a way it would only be completely + set up after being passed to the *EffectManager* via its add function. Below, how the refactoring handles it: + + .. code-block:: python + + from fury.effects import EffectManager, KDE + from fury import window + + showm = window.ShowManager(...) + + # KDE rendering setup + em = EffectManager(showm) + kde_effect = KDE(...) + em.add(kde_effect) + # End of KDE rendering setup + + showm.start() + + Which outputted the same results as shown above. It may have cost some simplicity as we are now one line farther from having it + working, but it is more explicit in telling the user this is not just a normal actor. + + Another detail I worked on was the kernel variety. The Gaussian Kernel isn't the only one available to model density distributions, + there are several others that can do that job, as it can be seen in this `scikit-learn piece of documentation `_ + and this `Wikipedia page on kernels `_. Based on the scikit-learn KDE + implementation, I worked on implementing the following kernels inside our API, that can be chosen as a parameter when calling the + *KDE* class: + + * Cosine + * Epanechnikov + * Exponential + * Gaussian + * Linear + * Tophat + + Below, the comparison between them using the same set of points and bandwidths: + + .. image:: https://raw.githubusercontent.com/JoaoDell/gsoc_assets/main/images/kernels.png + :align: center + :alt: Comparison between the six implemented kernels + + + *Pull Requests*: + + - **First Stage of the KDE Rendering API (will be merged soon)**: `https://github.com/fury-gl/fury/pull/826 `_ + + All of this work culminated in PR `#826 `_, that proposes to add the first stage of + this API (there are some details yet to be completed, like the :math:`n` division) to FURY. This PR added the described API, and also + proposed some minor changes to some already existing FURY functions related to callbacks, changes necessary for this and other + future applications that would use it to work. It also added the six kernels described, and a simple documented example on how + to use this feature. + +Other Objectives +---------------- + +- **Stretch Goals** : SDE Implementation, Network/Graph visualization using SDE/KDE, Tutorials + * Investigate SDE calculation for surface datasets. + * Implement SDE calculation inside the framebuffer rendering shaders. + * Test SDE for multiple datasets. + * Develop comprehensive tutorials that explain SDE concepts and FURY API usage. + * Create practical, scenario-based tutorials using real datasets and/or simulations. + +Objectives in Progress +---------------------- + +- **KDE Calculations** (ongoing) + The KDE rendering, even though almost complete, have the $n$ division, an important step, missing, as this normalization allows colormaps + to cover the whole range o values rendered. The lack of a float FBO made a big difference in the project, as the search for a functional implementation of it not only delayed the project, but it is vital for + the correct calculations to work. + + For the last part, a workaround thought was to try an approach I later figured out is an old one, as it can be check in + `GPU Gems 12.3.3 section `_: + If I need 32-bit float precision and I got 4 8-bit integer precision available, why not trying to pack this float into this RGBA + texture? I have first tried to do one myself, but it didn't work for some reason, so I tried `Aras Pranckevičius `_ + implementation, that does the following: + + .. code-block:: GLSL + + vec4 float_to_rgba(float value) { + vec4 bitEnc = vec4(1.,256.,65536.0,16777216.0); + vec4 enc = bitEnc * value; + enc = fract(enc); + enc -= enc.yzww * vec2(1./255., 0.).xxxy; + return enc; + } + + That initially worked, but for some reason I am still trying to understand, it is resulting in a really noisy texture: + + .. image:: https://raw.githubusercontent.com/JoaoDell/gsoc_assets/main/images/noisy%20kde.png + :align: center + :alt: Noisy KDE render + + One way to try to mitigate that while is to pass this by a gaussian blur filter, to try to smooth out the result: + + .. image:: https://raw.githubusercontent.com/JoaoDell/gsoc_assets/main/images/blurred_kde.png + :align: center + :alt: Blurred result + + But it is not an ideal solution as well, as it may lead to distortions in the actual density values, depending on the application of + the KDE. Now, my goal is to first find the root of the noise problem, and then, if that does not work, try to make the gaussian filter + work. + + Another detail that would be a good addition to the API is UI controls. Filipi, one of my mentors, told me it would be a good feature + if the user could control the intensities of the bandwidths for a better structural visualization of the render, and knowing FURY already + have a good set of `UI elements `_, I just needed to integrate + that into my program via callbacks. I tried implementing an intensity slider. However, for some reason, it is making the program crash + randomly, for reasons I still don't know, so that is another issue under investigation. Below, we show a first version of that feature, + which was working before the crashes: + + .. image:: https://raw.githubusercontent.com/JoaoDell/gsoc_assets/main/images/slider.gif + :align: center + :alt: Slider for bandwidths + + *Pull Requests* + + - **UI intensity slider for the KDE rendering API (draft)**: `https://github.com/fury-gl/fury/pull/849 `_ + - **Post-processing effects for FURY Effects API (draft)**: `https://github.com/fury-gl/fury/pull/850 `_ + + +GSoC Weekly Blogs +----------------- + +- My blog posts can be found at `FURY website `_ and `Python GSoC blog `_. + +Timeline +-------- + ++---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Date | Description | Blog Post Link | ++=====================+====================================================+===========================================================================================================================================================================================================+ +| Week 0 (29-05-2023) | The Beginning of Everything | `FURY `__ - `Python `__ | ++---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 1 (05-06-2022) | The FBO Saga | `FURY `__ - `Python `__ | ++---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 2 (12-06-2022) | The Importance of (good) Documentation | `FURY `__ - `Python `__ | ++---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 3 (19-06-2022) | Watch Your Expectations | `FURY `__ - `Python `__ | ++---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 4 (26-06-2022) | Nothing is Ever Lost | `FURY `__ - `Python `__ | ++---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 5 (03-07-2022) | All Roads Lead to Rome | `FURY `__ - `Python `__ | ++---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 6 (10-07-2022) | Things are Starting to Build Up | `FURY `__ - `Python `__ | ++---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 7 (17-07-2022) | Experimentation Done | `FURY `__ - `Python `__ | ++---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 8 (24-07-2022) | The Birth of a Versatile API | `FURY `__ - `Python `__ | ++---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 9 (31-07-2022) | It is Polishing Time! | `FURY `__ - `Python `__ | ++---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 10 (07-08-2022)| Ready for Review! | `FURY `__ - `Python `__ | ++---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 11 (14-08-2022)| A Refactor is Sometimes Needed | `FURY `__ - `Python `__ | ++---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 12 (21-08-2022)| Now That is (almost) a Wrap! | `FURY `__ - `Python `__ | ++---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ diff --git a/v0.10.x/_sources/posts/2023/2023-08-21-week-12-joaodellagli.rst.txt b/v0.10.x/_sources/posts/2023/2023-08-21-week-12-joaodellagli.rst.txt new file mode 100644 index 000000000..83ad86cf4 --- /dev/null +++ b/v0.10.x/_sources/posts/2023/2023-08-21-week-12-joaodellagli.rst.txt @@ -0,0 +1,39 @@ +Week 12: Now That is (almost) a Wrap! +===================================== + +.. post:: August 21, 2023 + :author: João Victor Dell Agli Floriano + :tags: google + :category: gsoc + +Hello everyone, it's time for another GSoC blogpost! Today, I am going to talk about some minor details I worked on last week on my +project. + +Last Week's Effort +------------------ +After the API refactoring was done last week, I focused on addressing the reviews I would get from it. The first issues I addressed was related to +style, as there were some minor details my GSoC contributors pointed out that needed change. Also, I have addressed an issue I was having +with the `typed hint` of one of my functions. Filipi, my mentor, showed me there is a way to have more than one typed hint in the same parameter, +all I needed to do was to use the `Union` class from the `typing` module, as shown below: + +.. code-block:: python + + from typing import Union as tUnion + from numpy import ndarray + + def function(variable : tUnion(float, np.ndarray)): + pass + +Using that, I could set the typedhint of the `bandwidth` variable to `float` and `np.ndarray`. + +So how did it go? +----------------- +All went fine with no difficult at all, thankfully. + +The Next Steps +-------------- +My next plans are, after having PR `#826 `_ merged, to work on the float encoding issue described in +:doc:`this blogpost<2023-07-31-week-9-joaodellagli>`. Also, I plan to tackle the UI idea once again, to see if I can finally give the user +a way to control the intensities of the distributions. + +Wish me luck! diff --git a/v0.10.x/_sources/posts/2023/2023-08-24-final-report-tvcastillod.rst.txt b/v0.10.x/_sources/posts/2023/2023-08-24-final-report-tvcastillod.rst.txt new file mode 100644 index 000000000..a1d730e1b --- /dev/null +++ b/v0.10.x/_sources/posts/2023/2023-08-24-final-report-tvcastillod.rst.txt @@ -0,0 +1,174 @@ +.. image:: https://developers.google.com/open-source/gsoc/resources/downloads/GSoC-logo-horizontal.svg + :height: 50 + :align: center + :target: https://summerofcode.withgoogle.com/programs/2023/projects/ymwnLwtT + +.. image:: https://www.python.org/static/community_logos/python-logo.png + :width: 40% + :target: https://summerofcode.withgoogle.com/programs/2023/organizations/python-software-foundation + +.. image:: https://python-gsoc.org/logos/FURY.png + :width: 25% + :target: https://fury.gl/latest/index.html + +Google Summer of Code Final Work Product +======================================== + +.. post:: August 24 2023 + :author: Tania Castillo + :tags: google + :category: gsoc + +- **Name:** Tania Castillo +- **Organisation:** Python Software Foundation +- **Sub-Organisation:** FURY +- **Project:** `SDF-based uncertainty representation for dMRI glyphs `_ + + +Abstract +-------------------- +Diffusion Magnetic Resonance Imaging (dMRI) is a non-invasive imaging technique used by neuroscientists to measure the diffusion of water molecules in biological tissue. The directional information is reconstructed using either a Diffusion Tensor Imaging (DTI) or High Angular Resolution Diffusion Imaging (HARDI) based model, which is graphically represented as tensors and Orientation Distribution Functions (ODF). Traditional rendering engines discretize Tensor and ODF surfaces using triangles or quadrilateral polygons, making their visual quality depending on the number of polygons used to build the 3D mesh, which might compromise real-time display performance. This project proposes a methodological approach to further improve the visualization of DTI tensors and HARDI ODFs glyphs by using well-established techniques in the field of computer graphics, such as geometry amplification, billboarding, signed distance functions (SDFs), and ray marching. + + +Proposed Objectives +------------------- + +- Implement a parallelized version of computer-generated billboards using geometry shaders for amplification. +- Model the mathematical functions that express the geometry of ellipsoid glyphs and implement them using Ray Marching techniques. +- Model the mathematical functions that express the geometry of ODF glyphs and implement them using Ray Marching techniques. +- Use SDF properties and techniques to represent the uncertainty of dMRI reconstruction models. + + +Objectives Completed +-------------------- + +Ellipsoid actor implemented with SDF +************************************ + +A first approach for tensor glyph generation has been made, using ray marching and SDF applied to a box. The current implementation (``tensor_slicer``) requires a sphere with a specific number of vertices to be deformed. Based on this model, a sphere with more vertices is needed to get a higher resolution. Because the ray marching technique does not use polygonal meshes, it is possible to define perfectly smooth surfaces and still obtain a fast rendering. + +Details of the implementation: + +- *Vertex shader pre-calculations*: Some minor calculations are done in the vertex shader. One, corresponding to the eigenvalues constraining and min-max normalization, are to avoid incorrect visualizations when the difference between the eigenvalues is too large. And the other is related to the tensor matrix calculation given by the diffusion tensor definition :math:`T = R^{−1}\Lambda R`, where :math:`R` is a rotation matrix that transforms the standard basis onto the eigenvector basis, and :math:`\Lambda` is the diagonal matrix of eigenvalues [4]_. +- *Ellipsoid SDF definition*: The definition of the SDF is done in the fragment shader inside the ``map`` function, which is used later for the ray marching algorithm and the normals calculation. We define the SDF more simply by transforming a sphere into an ellipsoid, considering that the SDF of a sphere is easily computed and the definition of a tensor gives us a linear transformation of a given geometry. Also, as scaling is not a rigid body transformation, we multiply the final result by a factor to compensate for the difference, which gave us the SDF of the ellipsoid defined as ``sdSphere(tensorMatrix * (position - centerMCVSOutput), scaleVSOutput*0.48) * scFactor``. +- *Ray marching algorithm and lighting*: For the ray marching algorithm, a small value of 20 was taken as the maximum distance since we apply the technique to each individual object and not all at the same time. Additionally, we set the convergence precision to 0.001. We use the central differences method to compute the normals necessary for the scene’s illumination, besides the Blinn-Phong lighting technique, which is high-quality and computationally cheap. +- *Visualization example*: Below is a detailed visualization of the ellipsoids created from this new implementation. + +.. image:: https://user-images.githubusercontent.com/31288525/244503195-a626718f-4a13-4275-a2b7-6773823e553c.png + :width: 376 + :align: center + +This implementation does show a better quality in the displayed glyphs, and supports the display of a large amount of data, as seen in the image below. For this reason, a tutorial was made to justify in more detail the value of this new implementation. Below are some images generated for the tutorial. + +.. image:: https://user-images.githubusercontent.com/31288525/260906510-d422e7b4-3ba3-4de6-bfd0-09c04bec8876.png + :width: 600 + :align: center + +*Pull Requests:* + +- **Ellipsoid actor implemented with SDF (Merged)** https://github.com/fury-gl/fury/pull/791 +- **Tutorial on using ellipsoid actor to visualize tensor ellipsoids for DTI (Merged)** https://github.com/fury-gl/fury/pull/818 + +**Future work:** In line with one of the initial objectives, it is expected to implement billboards later on to improve the performance, i.e., higher frame rate and less memory usage for the tensor ellipsoid creation. In addition to looking for ways to optimize the naive ray marching algorithm and the definition of SDFs. + +Objectives in Progress +---------------------- + +DTI uncertainty visualization +***************************** + +The DTI visualization pipeline is fairly complex, as a level of uncertainty arises, which, if visualized, helps to assess the model's accuracy. This measure is not currently implemented, and even though there are several methods to calculate and visualize the uncertainty in the DTI model, because of its simplicity and visual representation, we considered Matrix Perturbation Analysis (MPA) proposed by Basser [1]_. This measurement is visualized as double cones representing the variance of the main direction of diffusion, for which the ray marching technique was also used to create these objects. + +Details of the implementation: + +- *Source of uncertainty*: The method of MPA arises from the susceptibility of DTI to dMRI noise present in diffusion-weighted images (DWIs), and also because the model is inherently statistical, making the tensor estimation and other derived quantities to be random variables [1]_. For this reason, this method focus on the premise that image noise produces a random perturbation in the diffusion tensor estimation, and therefore in the calculation of eigenvalues and eigenvectors, particularly in the first eigenvector associated with the main diffusion direction. +- *Mathematical equation*: The description of the perturbation of the principal eigenvector is given by math formula where :math:`\Delta D` corresponds to the estimated perturbation matrix of :math:`D` given by the diagonal elements of the covariance matrix :math:`\Sigma_{\alpha} \approx (B^T\Sigma^{−1}_{e}B)^{−1}`, where :math:`\Sigma_{e}` is the covariance matrix of the error e, defined as a diagonal matrix made with the diagonal elements of :math:`(\Sigma^{−1}_{e}) = ⟨S(b)⟩^2 / \sigma^{2}_{\eta}`. Then, to get the angle :math:`\theta` between the perturbed principal eigenvector of :math:`D`, :math:`\varepsilon_1 + \Delta\varepsilon_1`, and the estimated eigenvector :math:`\varepsilon_1`, it can be approximated by :math:`\theta = \tan^{−1}( \| \Delta\varepsilon_1 \|)` [2]_. Taking into account the above, we define the function ``main_dir_uncertainty(evals, evecs, signal, sigma, b_matrix)`` that calculates the uncertainty of the eigenvector associated to the main direction of diffusion. +- *Double cone SDF definition*: The final SDF is composed by the union of 2 separately cones using the definition taken from this list of `distance functions `_, in this way we have the SDF for the double cone defined as ``opUnion(sdCone(p,a,h), sdCone(-p,a,h)) * scaleVSOutput`` +- *Visualization example*: Below is a demo of how this new feature is intended to be used, an image of diffusion tensor ellipsoids and their associated uncertainty cones. + +.. image:: https://user-images.githubusercontent.com/31288525/254747296-09a8674e-bfc0-4b3f-820f-8a1b1ad8c5c9.png + :width: 610 + :align: center + +The implementation is almost complete, but as it is a new addition that includes mathematical calculations and for which there is no direct reference for comparison, it requires a more detail review before it can be incorporated. + +*Pull Request:* + +- **DTI uncertainty visualization (Under Review)** https://github.com/fury-gl/fury/pull/810 + +**Future work:** A tutorial will be made explaining in more detail how to calculate the parameters needed for the uncertainty cones using **dipy** functions, specifically: `estimate_sigma `_ for the noise variance calculation, `design_matrix `_ to get the b-matrix, and `tensor_prediction `_ for the signal estimation. Additionally, when the ODF implementation is complete, uncertainty for this other reconstruction model is expected to be added, using semitransparent glyphs representing the mean directional information proposed by Tournier [3]_. + +ODF actor implemented with SDF +****************************** + +HARDI-based techniques require more images than DTI, however, they model the diffusion directions as probability distribution functions (PDFs), and the fitted values are returned as orientation distribution functions (ODFs). ODFs are more diffusion sensitive than the diffusion tensor and, therefore, can determine the structure of multi-directional voxels very common in the white matter regions of the brain [3]_. The current actor to display this kind of glyphs is the ``odf_slicer`` which, given an array of spherical harmonics (SH) coefficients renders a grid of ODFs, which are created from a sphere with a specific number of vertices that fit the data. + +For the application of this model using the same SDF ray marching techniques, we need the data of the SH coefficients, which are used to calculate the orientation distribution function (ODF) described `here `_. Different SH bases can be used, but for this first approach we focus on ``descoteaux07`` (as labeled in dipy). After performing the necessary calculations, we obtain an approximate result of the current implementation of FURY, as seen below. + +.. image:: https://user-images.githubusercontent.com/31288525/260909561-fd90033c-018a-465b-bd16-3586bb31ca36.png + :width: 580 + :align: center + +With a first implementation we start to solve some issues related to direction, color, and data handling, to obtain exactly the same results as the current implementation. + +Details on the issues: + +- *The direction and the scaling*: When the shape of the ODF is more sphere-like, the size of the glyph is smaller, so for the moment it needs to be adjusted manually, but the idea is to find a relationship between the coefficients and the final object size so it can be automatically scaled. Additionally, as seen in the image, the direction does not match. To fix this, an adjustment in the calculation of the spherical coordinates can be made, or pass the direction information directly. +- *Pass the coefficients data efficiently*: I'm currently creating one actor per glyph since I'm using a *uniform* array to pass the coefficients, but the idea is to pass all the data simultaneously. The first idea is to encode the coefficients data through a texture and retrieve them in the fragment shader. +- *The colormapping and the lighting*: As these objects present curvatures with quite a bit of detail in some cases, this requires more specific lighting work, in addition to having now not only one color but a color map. This can also be done with texture, but it is necessary to see in more detail how to adjust the texture to the glyph's shape. + +More details on current progress can be seen in blogpost of `week 11 `_ and `week 12 `_. + +*Working branch:* + +- **ODF implementation (Under Development)** + https://github.com/tvcastillod/fury/tree/SH-for-ODF-impl + + +GSoC Weekly Blogs +----------------- + +- My blog posts can be found on the `FURY website `__ and the `Python GSoC blog `__. + + +Timeline +-------- + ++---------------------+------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Date | Description | Blog Post Link | ++=====================+========================================================================+==========================================================================================================================================================================+ +| Week 0(02-06-2022) | Community Bounding Period | `FURY `__ - `Python `__ | ++---------------------+------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 1(05-06-2022) | Ellipsoid actor implemented with SDF | `FURY `__ - `Python `__ | ++---------------------+------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 2(12-06-2022) | Making adjustments to the Ellipsoid Actor | `FURY `__ - `Python `__ | ++---------------------+------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 3(19-06-2022) | Working on uncertainty and details of the first PR | `FURY `__ - `Python `__ | ++---------------------+------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 4(27-06-2022) | First draft of the DTI uncertainty visualization | `FURY `__ - `Python `__ | ++---------------------+------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 5(03-07-2022) | Preparing the data for the Ellipsoid tutorial | `FURY `__ - `Python `__ | ++---------------------+------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 6(10-07-2022) | First draft of the Ellipsoid tutorial | `FURY `__ - `Python `__ | ++---------------------+------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 7(17-07-2022) | Adjustments on the Uncertainty Cones visualization | `FURY `__ - `Python `__ | ++---------------------+------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 8(25-07-2022) | Working on Ellipsoid Tutorial and exploring SH | `FURY `__ - `Python `__ | ++---------------------+------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 9(31-07-2022) | Tutorial done and polishing DTI uncertainty | `FURY `__ - `Python `__ | ++---------------------+------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 10(08-08-2022) | Start of SH implementation experiments | `FURY `__ - `Python `__ | ++---------------------+------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 11(16-08-2022) | Adjusting ODF implementation and looking for solutions on issues found | `FURY `__ - `Python `__ | ++---------------------+------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 12(24-08-2022) | Experimenting with ODFs implementation | `FURY `__ - `Python `__ | ++---------------------+------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + + +References +---------- + +.. [1] Basser, P. J. (1997). Quantifying errors in fiber direction and diffusion tensor field maps resulting from MR noise. In 5th Scientific Meeting of the ISMRM (Vol. 1740). +.. [2] Chang, L. C., Koay, C. G., Pierpaoli, C., & Basser, P. J. (2007). Variance of estimated DTI‐derived parameters via first‐order perturbation methods. Magnetic Resonance in Medicine: An Official Journal of the International Society for Magnetic Resonance in Medicine, 57(1), 141-149. +.. [3] J-Donald Tournier, Fernando Calamante, David G Gadian, and Alan Connelly. Direct estimation of the fiber orientation density function from diffusion-weighted mri data using spherical deconvolution. Neuroimage, 23(3):1176–1185, 2004. +.. [4] Gordon Kindlmann. Superquadric tensor glyphs. In Proceedings of the Sixth Joint Eurographics-IEEE TCVG conference on Visualization, pages 147–154, 2004. diff --git a/v0.10.x/_sources/posts/2023/2023-08-24-week-12-tvcastillod.rst.txt b/v0.10.x/_sources/posts/2023/2023-08-24-week-12-tvcastillod.rst.txt new file mode 100644 index 000000000..7a97e8cd4 --- /dev/null +++ b/v0.10.x/_sources/posts/2023/2023-08-24-week-12-tvcastillod.rst.txt @@ -0,0 +1,46 @@ +Week 12 : Experimenting with ODFs implementation +================================================ + +.. post:: August 24, 2023 + :author: Tania Castillo + :tags: google + :category: gsoc + +What did I do this week? +------------------------ + +There were different issues I needed to address for the ODF implementation. Even though I could not solve any of them completely, I did check each of the issues and made some progress. All the work in progress is being recorded in the following branch `SH-for-ODF-impl `_, which when ready will be associated with a well-structured PR. + +First, about the scaling, I was suggested to check Generalized Fractional Anisotropy **gfa** metric to adjust the scaling depending on the shape of the ODF glyph, i.e., the less the **gfa** the more sphere-shaped and smaller, so I had to associate a greater scaling for those. However, this did not work very well as I was unable to define an appropriate scale relation that would give an equitable result for each glyph. For this reason, I opted to use peak values which are extracted from the ODFs, setting the scales as 1/peak_value*0.4 and I got a more uniformly sized glyph without the need of setting it manually. That is a temporal solution as I would like to see better why this happens and if possible do the adjustment inside the shader instead of a precalculation. + +Second, for the direction, I made a small adjustment to the spherical coordinates which affected the direction of the ODF glyph. As you can see below, + +.. image:: https://user-images.githubusercontent.com/31288525/263122770-b9ee19d2-d82b-4d7f-a5bb-1cbbf5907049.png + :width: 400 + :align: center + +All the glyphs are aligned over the y-axis but not over the z-axis, to correct this I precalculated the main direction of each glyph using peaks and passed it to the shader as a *vec3*, then used *vec2vecrotmat* to align the main axis vector of the ODF to the required direction vector, the only problem with this is that not all the glyps are equally aligned to the axis, i.e., the first 3 glyphs are aligned with the x-axis but the last one is aligned with the y-axis, so the final rotation gives a different result for that one. + +.. image:: https://user-images.githubusercontent.com/31288525/263122752-b2aa696f-62a5-4b09-b8dd-0cb1ec49431c.png + :width: 400 + :align: center + +As with the first small adjustment of the coordinates the direction was partially correct, I need to double check the theta, phi and r definitions to see if I can get the right direction without the need of the additional data of direction. Also, there might be a way to get the specific rotation angles associated to each individual glyph from the data associated with the ODFs. + +Third, about passing the coefficients data through textures, I understand better now how to pass textures to the shaders but I still have problems understanding how to retrieve the data inside the shader. I used `this base implementation `_, suggested by one of my mentors, to store the data as a `texture cubemap `_, "a texture, where each mipmap level consists of six 2D images which must be square. The 6 images represent the faces of a cube". I had 4x15 coefficients and inside the function, a grid of RGB colors is made so then it can be mapped as a texture. To check if was passing the data correctly, I used the same value, .5, for all the textures, so then I could pick a random texel get a specific color (gray), and pass it as *fragOutput0* to see if the value was correct. However, it didn't appear to work correctly as I couldn't get the expected color. To get the specific color I used `texture(sampler, P) `_ which samples texels from the texture bound to sampler at texture coordinate P. Now, what I still need to figure out is which should be the corresponding texture coordinate. I have tried with random coordinates, as they are supposed to correspond to a point on the cube and since the information I have encoded in the texture is all the same, I assumed that I would get the expected result for any set of values. It might be a problem with the data normalization, or maybe there is something failing on the texture definition, but I need to review it in more detail to see where is the problem. + +Lastly, about the colormapping, I created the texture based on a generic colormap from `matplotlib `_. I was able to give some color to the glyph but it does not match correctly its shape. Some adjustment must be done regarding the texels, as the colormap is mapped on a cube, but I need it to fit the shape of the glyph correctly. + +.. image:: https://user-images.githubusercontent.com/31288525/263122760-7d1fff5e-7787-473c-8053-ea69f3009fb4.png + :width: 250 + :align: center + +What is coming up next? +----------------------- + +I will continue to explore more on how to handle textures so I can solve the issues related to the coefficient data and colormapping. Also, take a deeper look at the SH implementation and check what is the information needed to adjust the main direction of the ODF correctly. + +Did I get stuck anywhere? +------------------------- + +As I mentioned I had some drawbacks in understanding the use of textures and how to retrieve the data inside the shaders. This is a topic that might take some time to manage properly but if I can master it and understand it better, it is a tool that can be useful later. Additionally, there are details of the SH implementation that I still need to understand and explore better in order to make sure I get exactly the same result as the current *odf_slicer* implementation. diff --git a/v0.10.x/_sources/posts/2023/2023-08-25-final-report-praneeth.rst.txt b/v0.10.x/_sources/posts/2023/2023-08-25-final-report-praneeth.rst.txt new file mode 100644 index 000000000..0209ba61b --- /dev/null +++ b/v0.10.x/_sources/posts/2023/2023-08-25-final-report-praneeth.rst.txt @@ -0,0 +1,216 @@ +.. image:: https://developers.google.com/open-source/gsoc/resources/downloads/GSoC-logo-horizontal.svg + :height: 50 + :align: center + :target: https://summerofcode.withgoogle.com/programs/2023/projects/BqfBWfwS + +.. image:: https://www.python.org/static/community_logos/python-logo.png + :width: 40% + :target: https://summerofcode.withgoogle.com/programs/2023/organizations/python-software-foundation + +.. image:: https://python-gsoc.org/logos/FURY.png + :width: 25% + :target: https://fury.gl/latest/index.html + +Google Summer of Code Final Work Product +======================================== + +.. post:: August 25 2023 + :author: Praneeth Shetty + :tags: google + :category: gsoc + +- **Name:** Praneeth Shetty +- **Organisation:** Python Software Foundation +- **Sub-Organisation:** FURY +- **Project:** `FURY - Update user interface widget + Explore new UI Framework `_ + + +Proposed Objectives +------------------- + +- SpinBoxUI +- Scrollbar as Independent Element +- FileDialog +- TreeUI +- AccordionUI +- ColorPickerUI + +- Stretch Goals: + - Exploring new UI Framework + - Implementing Borders for UI elements + +Objectives Completed +-------------------- + + +- **SpinBoxUI:** + The ``SpinBoxUI`` element is essential for user interfaces as it allows users to pick a numeric value from a set range. While we had an active pull request (PR) to add this element, updates in the main code caused conflicts and required further changes for added features. At one point, we noticed that text alignment wasn't centered properly within the box due to a flaw. To fix this, we began a PR to adjust the alignment, but it turned into a larger refactoring of the ``TextBlock2D``, a core component connected to various parts. This was a complex task that needed careful handling. After sorting out the ``TextBlock2D``, we returned to the ``SpinBoxUI`` and made a few tweaks. Once we were confident with the changes, the PR was successfully merged after thorough review and testing. + + **Pull Requests:** + - **SpinBoxUI (Merged)** - https://github.com/fury-gl/fury/pull/499 + + .. image:: https://user-images.githubusercontent.com/64432063/263165327-c0b19cdc-9ebd-433a-8ff1-99e706a76508.gif + :height: 500 + :align: center + :alt: SpinBoxUI + + + +- **`TextBlock2D` Refactoring:** + This was a significant aspect of the GSoC period and occupied a substantial portion of the timeline. The process began when we observed misaligned text in the ``SpinBoxUI``, as previously discussed. The root cause of the alignment issue was the mispositioning of the text actor concerning the background actor. The text actor's independent repositioning based on justification conflicted with the static position of the background actor, leading to the alignment problem. + + To address this, the initial focus was on resolving the justification issue. However, as the work progressed, we recognized that solely adjusting justification would not suffice. The alignment was inherently linked to the UI's size, which was currently retrieved only when a valid scene was present. This approach lacked scalability and efficiency, as it constrained size retrieval to scene availability. + + To overcome these challenges, we devised a solution involving the creation of a bounding box around the ``TextBlock2D``. This bounding box would encapsulate the size information, enabling proper text alignment. This endeavor spanned several weeks of development, culminating in a finalized solution that underwent rigorous testing before being merged. + + As a result of this refactoring effort, the ``TextBlock2D`` now offers three distinct modes: + + 1. **Fully Static Background:** This mode requires background setup during initialization. + 2. **Dynamic Background:** The background dynamically scales based on the text content. + 3. **Auto Font Scale Mode:** The font within the background box automatically scales to fill the available space. + + An issue has been identified with ``TextBlock2D`` where its text actor aligns with the top boundary of the background actor, especially noticeable with letters like "g," "y," and "j". These letters extend beyond the baseline of standard alphabets, causing the text box to shift upwards. + + However, resolving this matter is complex. Adjusting the text's position might lead to it touching the bottom boundary, especially in font scale mode, resulting in unexpected positioning and transformations. To address this, the plan is to defer discussions about this matter until after GSoC, allowing for thorough consideration and solutions. + + For more detailed insights into the individual steps and nuances of this process, you can refer to the comprehensive weekly blog post provided below. It delves into the entire journey of this ``TextBlock2D`` refactoring effort. + + **Pull Requests:** + - **Fixing Justification Issue - 1st Draft (Closed)** - https://github.com/fury-gl/fury/pull/790 + - **Adding BoundingBox and fixing Justificaiton (Merged)** - https://github.com/fury-gl/fury/pull/803 + - **Adding getters and setter for properties (Merged)** - https://github.com/fury-gl/fury/pull/830 + - **Text Offset PR (Closed)** - https://github.com/fury-gl/fury/pull/837 + + + .. image:: https://user-images.githubusercontent.com/64432063/258603191-d540105a-0612-450e-8ae3-ca8aa87916e6.gif + :height: 500 + :align: center + :alt: TextBlock2D Feature Demo + + .. image:: https://github-production-user-asset-6210df.s3.amazonaws.com/64432063/254652569-94212105-7259-48da-8fdc-41ee987bda84.png + :height: 500 + :align: center + :alt: TextBlock2D All Justification + +- **ScrollbarUI as Independent Element:** + We initially planned to make the scrollbar independent based on PR `#16 `_. The main goal was to avoid redundancy by not rewriting the scrollbar code for each element that requires it, such as the ``FileMenu2D``. However, upon further analysis, we realized that elements like the ``FileMenu2D`` and others utilize the ``Listbox2D``, which already includes an integrated scrollbar. We also examined other UI libraries and found that they also have independent scrollbars but lack a proper use case. Typically, display containers like ``Listbox2D`` are directly used instead of utilizing an independent scrollbar. + + Based on these findings, we have decided to close all related issues and pull requests for now. If the need arises in the future, we can revisit this topic. + + **Topic:** - https://github.com/fury-gl/fury/discussions/816 + + +Other Objectives +---------------- + +- **Reviewing & Merging:** + In this phase, my focus was not on specific coding but rather on facilitating the completion of ongoing PRs. Here are two instances where I played a role: + + 1. **CardUI PR:** + I assisted with the ``CardUI`` PR by aiding in the rebase process and reviewing the changes. The CardUI is a simple UI element consisting of an image and a description, designed to function like a flash card. I worked closely with my mentor to ensure a smooth rebase and review process. + + 2. **ComboBox Issue:** + There was an issue with the ``ComboBox2D`` functionality, where adding it to a ``TabUI`` caused all elements to open simultaneously, which shouldn't be the case. I tested various PRs addressing this problem and identified a suitable solution. I then helped the lead in reviewing the PR that fixed the issue, which was successfully merged. + + **Pull Requests:** + - **CardUI (Merged)** - https://github.com/fury-gl/fury/pull/398 + - **ComboBox Flaw (Merged)** - https://github.com/fury-gl/fury/pull/768 + + + .. image:: https://user-images.githubusercontent.com/54466356/112532305-b090ef80-8dce-11eb-90a0-8d06eed55993.png + :height: 500 + :align: center + :alt: CardUI + + +- **Updating Broken Website Links:** + I addressed an issue with malfunctioning links in the Scientific Section of the website. The problem emerged from alterations introduced in PR `#769 `_. These changes consolidated demos and examples into a unified "auto_examples" folder, and a toml file was utilized to retrieve this data and construct examples. However, this led to challenges with the paths employed in website generation. My responsibility was to rectify these links, ensuring they accurately direct users to the intended content. + + **Pull Requests:** + - **Updating Broken Links (Merged)** - https://github.com/fury-gl/fury/pull/820 + + +Objectives in Progress +---------------------- + +- **FileDialogUI:** + An existing ``FileDialog`` PR by Soham (`#294 `_) was worked upon. The primary task was to rebase the PR to match the current UI structure, resolving compatibility concerns with the older base. In PR `#832 `_, we detailed issues encompassing resizing ``FileDialog`` and components, addressing text overflow, fixing ``ZeroDivisionError``, and correcting ``ListBox2D`` item positioning. The PR is complete with comprehensive testing and documentation. Presently, it's undergoing review, and upon approval, it will be prepared for integration. + + **Pull Requests:** + - **Soham's FileDialog (Closed)** - https://github.com/fury-gl/fury/pull/294 + - **FileDialogUI (Under Review)** - https://github.com/fury-gl/fury/pull/832 + + + .. image:: https://user-images.githubusercontent.com/64432063/263189092-6b0891d5-f0ef-4185-8b17-c7104f1a7d60.gif + :height: 500 + :align: center + :alt: FileDialogUI + + +- **TreeUI:** + Continuing Antriksh's initial PR for ``TreeUI`` posed some challenges. Antriksh had set the foundation, and I picked up from there. The main issue was with the visibility of TreeUI due to updates in the ``set_visibility`` method of ``Panel2D``. These updates affected how ``TreeUI`` was displayed, and after investigating the actors involved, it was clear that the visibility features had changed. This took some time to figure out, and I had a helpful pair programming session with my mentor, Serge, to narrow down the problem. Now, I've updated the code to address this issue. However, I'm still a bit cautious about potential future problems. The PR is now ready for review. + + **Pull Requests:** + - **TreeUI (In Progress)** - https://github.com/fury-gl/fury/pull/821 + + + .. image:: https://user-images.githubusercontent.com/64432063/263237308-70e77ba0-1ce8-449e-a79c-d5e0fbb58b45.gif + :height: 500 + :align: center + :alt: TreeUI + +GSoC Weekly Blogs +----------------- + +- My blog posts can be found at `FURY website `__ + and `Python GSoC blog `__. + +Timeline +-------- + +.. list-table:: + :widths: 40 40 20 + :header-rows: 1 + + * - Date + - Description + - Blog Post Link + * - Week 0 (27-05-2023) + - Community Bounding Period + - `FURY `_ - `Python `_ + * - Week 1 (03-06-2023) + - Working with SpinBox and TextBox Enhancements + - `FURY `_ - `Python `_ + * - Week 2 (10-06-2023) + - Tackling Text Justification and Icon Flaw Issues + - `FURY `_ - `Python `_ + * - Week 3 (17-06-2023) + - Resolving Combobox Icon Flaw and TextBox Justification + - `FURY `_ - `Python `_ + * - Week 4 (24-06-2023) + - Exam Preparations and Reviewing + - `FURY `_ - `Python `_ + * - Week 5 (01-07-2023) + - Trying out PRs and Planning Ahead + - `FURY `_ - `Python `_ + * - Week 6 (08-07-2023) + - BoundingBox for TextBlock2D! + - `FURY `_ - `Python `_ + * - Week 7 (15-07-2023) + - Sowing the seeds for TreeUI + - `FURY `_ - `Python `_ + * - Week 8 (22-07-2023) + - Another week with TextBlockUI + - `FURY `_ - `Python `_ + * - Week 9 (29-07-2023) + - TextBlock2D is Finally Merged! + - `FURY `_ - `Python `_ + * - Week 10 (05-08-2023) + - Its time for a Spin-Box! + - `FURY `_ - `Python `_ + * - Week 11 (12-08-2023) + - Bye Bye SpinBox + - `FURY `_ - `Python `_ + * - Week 12 (19-08-2023) + - FileDialog Quest Begins! + - `FURY `_ - `Python `_ diff --git a/v0.10.x/_sources/reference/fury.actor.rst.txt b/v0.10.x/_sources/reference/fury.actor.rst.txt new file mode 100644 index 000000000..adfc9fc9d --- /dev/null +++ b/v0.10.x/_sources/reference/fury.actor.rst.txt @@ -0,0 +1,290 @@ +.. AUTO-GENERATED FILE -- DO NOT EDIT! + +:mod:`actor` +============ +.. automodule:: fury.actor + +.. currentmodule:: fury.actor +.. autosummary:: + + Container + slicer + surface + contour_from_roi + contour_from_label + streamtube + line + scalar_bar + axes + odf_slicer + tensor_slicer + peak_slicer + peak + dot + dots + point + sphere + cylinder + disk + square + rectangle + box + cube + arrow + cone + triangularprism + rhombicuboctahedron + pentagonalprism + octagonalprism + frustum + superquadric + billboard + vector_text + label + text_3d + grid + figure + texture + texture_update + texture_on_sphere + texture_2d + sdf + markers + ellipsoid + uncertainty_cone + + +.. currentmodule:: fury.actor + + +:class:`Container` +~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: Container + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + +slicer +~~~~~~ + +.. autofunction:: slicer + +surface +~~~~~~~ + +.. autofunction:: surface + +contour_from_roi +~~~~~~~~~~~~~~~~ + +.. autofunction:: contour_from_roi + +contour_from_label +~~~~~~~~~~~~~~~~~~ + +.. autofunction:: contour_from_label + +streamtube +~~~~~~~~~~ + +.. autofunction:: streamtube + +line +~~~~ + +.. autofunction:: line + +scalar_bar +~~~~~~~~~~ + +.. autofunction:: scalar_bar + +axes +~~~~ + +.. autofunction:: axes + +odf_slicer +~~~~~~~~~~ + +.. autofunction:: odf_slicer + +tensor_slicer +~~~~~~~~~~~~~ + +.. autofunction:: tensor_slicer + +peak_slicer +~~~~~~~~~~~ + +.. autofunction:: peak_slicer + +peak +~~~~ + +.. autofunction:: peak + +dot +~~~ + +.. autofunction:: dot + +dots +~~~~ + +.. autofunction:: dots + +point +~~~~~ + +.. autofunction:: point + +sphere +~~~~~~ + +.. autofunction:: sphere + +cylinder +~~~~~~~~ + +.. autofunction:: cylinder + +disk +~~~~ + +.. autofunction:: disk + +square +~~~~~~ + +.. autofunction:: square + +rectangle +~~~~~~~~~ + +.. autofunction:: rectangle + +box +~~~ + +.. autofunction:: box + +cube +~~~~ + +.. autofunction:: cube + +arrow +~~~~~ + +.. autofunction:: arrow + +cone +~~~~ + +.. autofunction:: cone + +triangularprism +~~~~~~~~~~~~~~~ + +.. autofunction:: triangularprism + +rhombicuboctahedron +~~~~~~~~~~~~~~~~~~~ + +.. autofunction:: rhombicuboctahedron + +pentagonalprism +~~~~~~~~~~~~~~~ + +.. autofunction:: pentagonalprism + +octagonalprism +~~~~~~~~~~~~~~ + +.. autofunction:: octagonalprism + +frustum +~~~~~~~ + +.. autofunction:: frustum + +superquadric +~~~~~~~~~~~~ + +.. autofunction:: superquadric + +billboard +~~~~~~~~~ + +.. autofunction:: billboard + +vector_text +~~~~~~~~~~~ + +.. autofunction:: vector_text + +label +~~~~~ + +.. autofunction:: label + +text_3d +~~~~~~~ + +.. autofunction:: text_3d + +grid +~~~~ + +.. autofunction:: grid + +figure +~~~~~~ + +.. autofunction:: figure + +texture +~~~~~~~ + +.. autofunction:: texture + +texture_update +~~~~~~~~~~~~~~ + +.. autofunction:: texture_update + +texture_on_sphere +~~~~~~~~~~~~~~~~~ + +.. autofunction:: texture_on_sphere + +texture_2d +~~~~~~~~~~ + +.. autofunction:: texture_2d + +sdf +~~~ + +.. autofunction:: sdf + +markers +~~~~~~~ + +.. autofunction:: markers + +ellipsoid +~~~~~~~~~ + +.. autofunction:: ellipsoid + +uncertainty_cone +~~~~~~~~~~~~~~~~ + +.. autofunction:: uncertainty_cone + diff --git a/v0.10.x/_sources/reference/fury.actors.rst.txt b/v0.10.x/_sources/reference/fury.actors.rst.txt new file mode 100644 index 000000000..5c9227836 --- /dev/null +++ b/v0.10.x/_sources/reference/fury.actors.rst.txt @@ -0,0 +1,96 @@ +.. AUTO-GENERATED FILE -- DO NOT EDIT! + +:mod:`actors` +============= +.. automodule:: fury.actors + +.. currentmodule:: fury.actors +.. autosummary:: + + +.. AUTO-GENERATED FILE -- DO NOT EDIT! + +Module: :mod:`actors.odf_slicer` +-------------------------------- +.. automodule:: fury.actors.odf_slicer + +.. currentmodule:: fury.actors.odf_slicer +.. autosummary:: + + OdfSlicerActor + +.. AUTO-GENERATED FILE -- DO NOT EDIT! + +Module: :mod:`actors.peak` +-------------------------- +.. automodule:: fury.actors.peak + +.. currentmodule:: fury.actors.peak +.. autosummary:: + + PeakActor + +.. AUTO-GENERATED FILE -- DO NOT EDIT! + +Module: :mod:`actors.tensor` +---------------------------- +.. automodule:: fury.actors.tensor + +.. currentmodule:: fury.actors.tensor +.. autosummary:: + + tensor_ellipsoid + double_cone + main_dir_uncertainty + + +.. currentmodule:: fury.actors + + +.. currentmodule:: fury.actors.odf_slicer + + +:class:`OdfSlicerActor` +~~~~~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: OdfSlicerActor + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +.. currentmodule:: fury.actors.peak + + +:class:`PeakActor` +~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: PeakActor + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +.. currentmodule:: fury.actors.tensor + +tensor_ellipsoid +~~~~~~~~~~~~~~~~ + +.. autofunction:: tensor_ellipsoid + +double_cone +~~~~~~~~~~~ + +.. autofunction:: double_cone + +main_dir_uncertainty +~~~~~~~~~~~~~~~~~~~~ + +.. autofunction:: main_dir_uncertainty + diff --git a/v0.10.x/_sources/reference/fury.animation.rst.txt b/v0.10.x/_sources/reference/fury.animation.rst.txt new file mode 100644 index 000000000..8bf3d6045 --- /dev/null +++ b/v0.10.x/_sources/reference/fury.animation.rst.txt @@ -0,0 +1,212 @@ +.. AUTO-GENERATED FILE -- DO NOT EDIT! + +:mod:`animation` +================ +.. automodule:: fury.animation + +.. currentmodule:: fury.animation +.. autosummary:: + + +.. AUTO-GENERATED FILE -- DO NOT EDIT! + +Module: :mod:`animation.animation` +---------------------------------- +.. automodule:: fury.animation.animation + +.. currentmodule:: fury.animation.animation +.. autosummary:: + + Animation + CameraAnimation + +.. AUTO-GENERATED FILE -- DO NOT EDIT! + +Module: :mod:`animation.helpers` +-------------------------------- +.. automodule:: fury.animation.helpers + +.. currentmodule:: fury.animation.helpers +.. autosummary:: + + get_previous_timestamp + get_next_timestamp + get_timestamps_from_keyframes + get_values_from_keyframes + get_time_tau + lerp + euclidean_distances + +.. AUTO-GENERATED FILE -- DO NOT EDIT! + +Module: :mod:`animation.interpolator` +------------------------------------- +.. automodule:: fury.animation.interpolator + +.. currentmodule:: fury.animation.interpolator +.. autosummary:: + + spline_interpolator + cubic_spline_interpolator + step_interpolator + linear_interpolator + cubic_bezier_interpolator + slerp + color_interpolator + hsv_color_interpolator + lab_color_interpolator + xyz_color_interpolator + tan_cubic_spline_interpolator + +.. AUTO-GENERATED FILE -- DO NOT EDIT! + +Module: :mod:`animation.timeline` +--------------------------------- +.. automodule:: fury.animation.timeline + +.. currentmodule:: fury.animation.timeline +.. autosummary:: + + Timeline + + +.. currentmodule:: fury.animation + + +.. currentmodule:: fury.animation.animation + + +:class:`Animation` +~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: Animation + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`CameraAnimation` +~~~~~~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: CameraAnimation + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +.. currentmodule:: fury.animation.helpers + +get_previous_timestamp +~~~~~~~~~~~~~~~~~~~~~~ + +.. autofunction:: get_previous_timestamp + +get_next_timestamp +~~~~~~~~~~~~~~~~~~ + +.. autofunction:: get_next_timestamp + +get_timestamps_from_keyframes +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. autofunction:: get_timestamps_from_keyframes + +get_values_from_keyframes +~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. autofunction:: get_values_from_keyframes + +get_time_tau +~~~~~~~~~~~~ + +.. autofunction:: get_time_tau + +lerp +~~~~ + +.. autofunction:: lerp + +euclidean_distances +~~~~~~~~~~~~~~~~~~~ + +.. autofunction:: euclidean_distances + + +.. currentmodule:: fury.animation.interpolator + +spline_interpolator +~~~~~~~~~~~~~~~~~~~ + +.. autofunction:: spline_interpolator + +cubic_spline_interpolator +~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. autofunction:: cubic_spline_interpolator + +step_interpolator +~~~~~~~~~~~~~~~~~ + +.. autofunction:: step_interpolator + +linear_interpolator +~~~~~~~~~~~~~~~~~~~ + +.. autofunction:: linear_interpolator + +cubic_bezier_interpolator +~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. autofunction:: cubic_bezier_interpolator + +slerp +~~~~~ + +.. autofunction:: slerp + +color_interpolator +~~~~~~~~~~~~~~~~~~ + +.. autofunction:: color_interpolator + +hsv_color_interpolator +~~~~~~~~~~~~~~~~~~~~~~ + +.. autofunction:: hsv_color_interpolator + +lab_color_interpolator +~~~~~~~~~~~~~~~~~~~~~~ + +.. autofunction:: lab_color_interpolator + +xyz_color_interpolator +~~~~~~~~~~~~~~~~~~~~~~ + +.. autofunction:: xyz_color_interpolator + +tan_cubic_spline_interpolator +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. autofunction:: tan_cubic_spline_interpolator + + +.. currentmodule:: fury.animation.timeline + + +:class:`Timeline` +~~~~~~~~~~~~~~~~~ + + +.. autoclass:: Timeline + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + diff --git a/v0.10.x/_sources/reference/fury.colormap.rst.txt b/v0.10.x/_sources/reference/fury.colormap.rst.txt new file mode 100644 index 000000000..8a7e935f4 --- /dev/null +++ b/v0.10.x/_sources/reference/fury.colormap.rst.txt @@ -0,0 +1,139 @@ +.. AUTO-GENERATED FILE -- DO NOT EDIT! + +:mod:`colormap` +=============== +.. automodule:: fury.colormap + +.. currentmodule:: fury.colormap +.. autosummary:: + + colormap_lookup_table + cc + ss + boys2rgb + orient2rgb + line_colors + get_cmap + create_colormap + distinguishable_colormap + hex_to_rgb + rgb2hsv + hsv2rgb + xyz_from_rgb + rgb_from_xyz + xyz2rgb + rgb2xyz + get_xyz_coords + xyz2lab + lab2xyz + rgb2lab + lab2rgb + + +.. currentmodule:: fury.colormap + +colormap_lookup_table +~~~~~~~~~~~~~~~~~~~~~ + +.. autofunction:: colormap_lookup_table + +cc +~~ + +.. autofunction:: cc + +ss +~~ + +.. autofunction:: ss + +boys2rgb +~~~~~~~~ + +.. autofunction:: boys2rgb + +orient2rgb +~~~~~~~~~~ + +.. autofunction:: orient2rgb + +line_colors +~~~~~~~~~~~ + +.. autofunction:: line_colors + +get_cmap +~~~~~~~~ + +.. autofunction:: get_cmap + +create_colormap +~~~~~~~~~~~~~~~ + +.. autofunction:: create_colormap + +distinguishable_colormap +~~~~~~~~~~~~~~~~~~~~~~~~ + +.. autofunction:: distinguishable_colormap + +hex_to_rgb +~~~~~~~~~~ + +.. autofunction:: hex_to_rgb + +rgb2hsv +~~~~~~~ + +.. autofunction:: rgb2hsv + +hsv2rgb +~~~~~~~ + +.. autofunction:: hsv2rgb + +xyz_from_rgb +~~~~~~~~~~~~ + +.. autofunction:: xyz_from_rgb + +rgb_from_xyz +~~~~~~~~~~~~ + +.. autofunction:: rgb_from_xyz + +xyz2rgb +~~~~~~~ + +.. autofunction:: xyz2rgb + +rgb2xyz +~~~~~~~ + +.. autofunction:: rgb2xyz + +get_xyz_coords +~~~~~~~~~~~~~~ + +.. autofunction:: get_xyz_coords + +xyz2lab +~~~~~~~ + +.. autofunction:: xyz2lab + +lab2xyz +~~~~~~~ + +.. autofunction:: lab2xyz + +rgb2lab +~~~~~~~ + +.. autofunction:: rgb2lab + +lab2rgb +~~~~~~~ + +.. autofunction:: lab2rgb + diff --git a/v0.10.x/_sources/reference/fury.convert.rst.txt b/v0.10.x/_sources/reference/fury.convert.rst.txt new file mode 100644 index 000000000..9c1b1c5fd --- /dev/null +++ b/v0.10.x/_sources/reference/fury.convert.rst.txt @@ -0,0 +1,19 @@ +.. AUTO-GENERATED FILE -- DO NOT EDIT! + +:mod:`convert` +============== +.. automodule:: fury.convert + +.. currentmodule:: fury.convert +.. autosummary:: + + matplotlib_figure_to_numpy + + +.. currentmodule:: fury.convert + +matplotlib_figure_to_numpy +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. autofunction:: matplotlib_figure_to_numpy + diff --git a/v0.10.x/_sources/reference/fury.data.rst.txt b/v0.10.x/_sources/reference/fury.data.rst.txt new file mode 100644 index 000000000..5fd76215c --- /dev/null +++ b/v0.10.x/_sources/reference/fury.data.rst.txt @@ -0,0 +1,146 @@ +.. AUTO-GENERATED FILE -- DO NOT EDIT! + +:mod:`data` +=========== +.. automodule:: fury.data + +.. currentmodule:: fury.data +.. autosummary:: + + DATA_DIR + +.. AUTO-GENERATED FILE -- DO NOT EDIT! + +Module: :mod:`data.fetcher` +--------------------------- +.. automodule:: fury.data.fetcher + +.. currentmodule:: fury.data.fetcher +.. autosummary:: + + update_progressbar + copyfileobj_withprogress + check_sha + fetch_data + fetch_gltf + fetch_viz_cubemaps + fetch_viz_icons + fetch_viz_new_icons + fetch_viz_wiki_nw + fetch_viz_models + fetch_viz_dmri + fetch_viz_textures + read_viz_cubemap + read_viz_icons + read_viz_models + read_viz_textures + read_viz_dmri + read_viz_gltf + list_gltf_sample_models + + +.. currentmodule:: fury.data + +DATA_DIR +~~~~~~~~ + +.. autofunction:: DATA_DIR + + +.. currentmodule:: fury.data.fetcher + +update_progressbar +~~~~~~~~~~~~~~~~~~ + +.. autofunction:: update_progressbar + +copyfileobj_withprogress +~~~~~~~~~~~~~~~~~~~~~~~~ + +.. autofunction:: copyfileobj_withprogress + +check_sha +~~~~~~~~~ + +.. autofunction:: check_sha + +fetch_data +~~~~~~~~~~ + +.. autofunction:: fetch_data + +fetch_gltf +~~~~~~~~~~ + +.. autofunction:: fetch_gltf + +fetch_viz_cubemaps +~~~~~~~~~~~~~~~~~~ + +.. autofunction:: fetch_viz_cubemaps + +fetch_viz_icons +~~~~~~~~~~~~~~~ + +.. autofunction:: fetch_viz_icons + +fetch_viz_new_icons +~~~~~~~~~~~~~~~~~~~ + +.. autofunction:: fetch_viz_new_icons + +fetch_viz_wiki_nw +~~~~~~~~~~~~~~~~~ + +.. autofunction:: fetch_viz_wiki_nw + +fetch_viz_models +~~~~~~~~~~~~~~~~ + +.. autofunction:: fetch_viz_models + +fetch_viz_dmri +~~~~~~~~~~~~~~ + +.. autofunction:: fetch_viz_dmri + +fetch_viz_textures +~~~~~~~~~~~~~~~~~~ + +.. autofunction:: fetch_viz_textures + +read_viz_cubemap +~~~~~~~~~~~~~~~~ + +.. autofunction:: read_viz_cubemap + +read_viz_icons +~~~~~~~~~~~~~~ + +.. autofunction:: read_viz_icons + +read_viz_models +~~~~~~~~~~~~~~~ + +.. autofunction:: read_viz_models + +read_viz_textures +~~~~~~~~~~~~~~~~~ + +.. autofunction:: read_viz_textures + +read_viz_dmri +~~~~~~~~~~~~~ + +.. autofunction:: read_viz_dmri + +read_viz_gltf +~~~~~~~~~~~~~ + +.. autofunction:: read_viz_gltf + +list_gltf_sample_models +~~~~~~~~~~~~~~~~~~~~~~~ + +.. autofunction:: list_gltf_sample_models + diff --git a/v0.10.x/_sources/reference/fury.decorators.rst.txt b/v0.10.x/_sources/reference/fury.decorators.rst.txt new file mode 100644 index 000000000..d8ab29174 --- /dev/null +++ b/v0.10.x/_sources/reference/fury.decorators.rst.txt @@ -0,0 +1,25 @@ +.. AUTO-GENERATED FILE -- DO NOT EDIT! + +:mod:`decorators` +================= +.. automodule:: fury.decorators + +.. currentmodule:: fury.decorators +.. autosummary:: + + SKIP_RE + doctest_skip_parser + + +.. currentmodule:: fury.decorators + +SKIP_RE +~~~~~~~ + +.. autofunction:: SKIP_RE + +doctest_skip_parser +~~~~~~~~~~~~~~~~~~~ + +.. autofunction:: doctest_skip_parser + diff --git a/v0.10.x/_sources/reference/fury.deprecator.rst.txt b/v0.10.x/_sources/reference/fury.deprecator.rst.txt new file mode 100644 index 000000000..25ae709c6 --- /dev/null +++ b/v0.10.x/_sources/reference/fury.deprecator.rst.txt @@ -0,0 +1,69 @@ +.. AUTO-GENERATED FILE -- DO NOT EDIT! + +:mod:`deprecator` +================= +.. automodule:: fury.deprecator + +.. currentmodule:: fury.deprecator +.. autosummary:: + + ExpiredDeprecationError + ArgsDeprecationWarning + _LEADING_WHITE + cmp_pkg_version + is_bad_version + deprecate_with_version + deprecated_params + + +.. currentmodule:: fury.deprecator + + +:class:`ExpiredDeprecationError` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: ExpiredDeprecationError + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`ArgsDeprecationWarning` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: ArgsDeprecationWarning + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + +_LEADING_WHITE +~~~~~~~~~~~~~~ + +.. autofunction:: _LEADING_WHITE + +cmp_pkg_version +~~~~~~~~~~~~~~~ + +.. autofunction:: cmp_pkg_version + +is_bad_version +~~~~~~~~~~~~~~ + +.. autofunction:: is_bad_version + +deprecate_with_version +~~~~~~~~~~~~~~~~~~~~~~ + +.. autofunction:: deprecate_with_version + +deprecated_params +~~~~~~~~~~~~~~~~~ + +.. autofunction:: deprecated_params + diff --git a/v0.10.x/_sources/reference/fury.gltf.rst.txt b/v0.10.x/_sources/reference/fury.gltf.rst.txt new file mode 100644 index 000000000..67f9cf9a2 --- /dev/null +++ b/v0.10.x/_sources/reference/fury.gltf.rst.txt @@ -0,0 +1,86 @@ +.. AUTO-GENERATED FILE -- DO NOT EDIT! + +:mod:`gltf` +=========== +.. automodule:: fury.gltf + +.. currentmodule:: fury.gltf +.. autosummary:: + + glTF + export_scene + write_scene + write_node + write_mesh + write_camera + get_prim + write_material + write_accessor + write_bufferview + write_buffer + + +.. currentmodule:: fury.gltf + + +:class:`glTF` +~~~~~~~~~~~~~ + + +.. autoclass:: glTF + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + +export_scene +~~~~~~~~~~~~ + +.. autofunction:: export_scene + +write_scene +~~~~~~~~~~~ + +.. autofunction:: write_scene + +write_node +~~~~~~~~~~ + +.. autofunction:: write_node + +write_mesh +~~~~~~~~~~ + +.. autofunction:: write_mesh + +write_camera +~~~~~~~~~~~~ + +.. autofunction:: write_camera + +get_prim +~~~~~~~~ + +.. autofunction:: get_prim + +write_material +~~~~~~~~~~~~~~ + +.. autofunction:: write_material + +write_accessor +~~~~~~~~~~~~~~ + +.. autofunction:: write_accessor + +write_bufferview +~~~~~~~~~~~~~~~~ + +.. autofunction:: write_bufferview + +write_buffer +~~~~~~~~~~~~ + +.. autofunction:: write_buffer + diff --git a/v0.10.x/_sources/reference/fury.io.rst.txt b/v0.10.x/_sources/reference/fury.io.rst.txt new file mode 100644 index 000000000..08a70aadb --- /dev/null +++ b/v0.10.x/_sources/reference/fury.io.rst.txt @@ -0,0 +1,55 @@ +.. AUTO-GENERATED FILE -- DO NOT EDIT! + +:mod:`io` +========= +.. automodule:: fury.io + +.. currentmodule:: fury.io +.. autosummary:: + + load_cubemap_texture + load_image + load_text + save_image + load_polydata + save_polydata + load_sprite_sheet + + +.. currentmodule:: fury.io + +load_cubemap_texture +~~~~~~~~~~~~~~~~~~~~ + +.. autofunction:: load_cubemap_texture + +load_image +~~~~~~~~~~ + +.. autofunction:: load_image + +load_text +~~~~~~~~~ + +.. autofunction:: load_text + +save_image +~~~~~~~~~~ + +.. autofunction:: save_image + +load_polydata +~~~~~~~~~~~~~ + +.. autofunction:: load_polydata + +save_polydata +~~~~~~~~~~~~~ + +.. autofunction:: save_polydata + +load_sprite_sheet +~~~~~~~~~~~~~~~~~ + +.. autofunction:: load_sprite_sheet + diff --git a/v0.10.x/_sources/reference/fury.layout.rst.txt b/v0.10.x/_sources/reference/fury.layout.rst.txt new file mode 100644 index 000000000..bc5ecfb30 --- /dev/null +++ b/v0.10.x/_sources/reference/fury.layout.rst.txt @@ -0,0 +1,104 @@ +.. AUTO-GENERATED FILE -- DO NOT EDIT! + +:mod:`layout` +============= +.. automodule:: fury.layout + +.. currentmodule:: fury.layout +.. autosummary:: + + Layout + GridLayout + HorizontalLayout + VerticalLayout + XLayout + YLayout + ZLayout + + +.. currentmodule:: fury.layout + + +:class:`Layout` +~~~~~~~~~~~~~~~ + + +.. autoclass:: Layout + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`GridLayout` +~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: GridLayout + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`HorizontalLayout` +~~~~~~~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: HorizontalLayout + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`VerticalLayout` +~~~~~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: VerticalLayout + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`XLayout` +~~~~~~~~~~~~~~~~ + + +.. autoclass:: XLayout + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`YLayout` +~~~~~~~~~~~~~~~~ + + +.. autoclass:: YLayout + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`ZLayout` +~~~~~~~~~~~~~~~~ + + +.. autoclass:: ZLayout + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + diff --git a/v0.10.x/_sources/reference/fury.lib.rst.txt b/v0.10.x/_sources/reference/fury.lib.rst.txt new file mode 100644 index 000000000..041613209 --- /dev/null +++ b/v0.10.x/_sources/reference/fury.lib.rst.txt @@ -0,0 +1,1397 @@ +.. AUTO-GENERATED FILE -- DO NOT EDIT! + +:mod:`lib` +========== +.. automodule:: fury.lib + +.. currentmodule:: fury.lib +.. autosummary:: + + Command + LookupTable + Points + IdTypeArray + FloatArray + DoubleArray + StringArray + UnsignedCharArray + AlgorithmOutput + Renderer + Skybox + Volume + Actor2D + Actor + RenderWindow + RenderWindowInteractor + InteractorEventRecorder + WindowToImageFilter + InteractorStyle + PropPicker + PointPicker + CellPicker + WorldPointPicker + HardwareSelector + ImageActor + PolyDataMapper + PolyDataMapper2D + Assembly + DataSetMapper + Texture + TexturedActor2D + Follower + TextActor + TextActor3D + Property2D + Camera + VectorText + LODActor + ScalarBarActor + OpenGLRenderer + Shader + InteractorStyleImage + InteractorStyleTrackballActor + InteractorStyleTrackballCamera + InteractorStyleUser + CleanPolyData + PolyDataNormals + ContourFilter + TubeFilter + Glyph3D + TriangleFilter + SplineFilter + TransformPolyDataFilter + RenderLargeImage + LoopSubdivisionFilter + ButterflySubdivisionFilter + OutlineFilter + LinearExtrusionFilter + TextureMapToPlane + SphereSource + CylinderSource + ArrowSource + ConeSource + DiskSource + TexturedSphereSource + RegularPolygonSource + PolyData + ImageData + DataObject + CellArray + PolyVertex + UnstructuredGrid + Polygon + DataObject + Molecule + DataSetAttributes + Transform + Matrix4x4 + Matrix3x3 + ImageFlip + ImageReslice + ImageMapToColors + ImageReader2Factory + PNGReader + BMPReader + JPEGReader + TIFFReader + PLYReader + STLReader + OBJReader + MNIObjectReader + PolyDataReader + XMLPolyDataReader + PNGWriter + BMPWriter + JPEGWriter + TIFFWriter + PLYWriter + STLWriter + MNIObjectWriter + PolyDataWriter + XMLPolyDataWriter + SimpleBondPerceiver + ProteinRibbonFilter + PeriodicTable + OpenGLMoleculeMapper + VTK_VERSION + + +.. currentmodule:: fury.lib + + +:class:`Command` +~~~~~~~~~~~~~~~~ + + +.. autoclass:: Command + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`LookupTable` +~~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: LookupTable + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`Points` +~~~~~~~~~~~~~~~ + + +.. autoclass:: Points + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`IdTypeArray` +~~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: IdTypeArray + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`FloatArray` +~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: FloatArray + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`DoubleArray` +~~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: DoubleArray + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`StringArray` +~~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: StringArray + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`UnsignedCharArray` +~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: UnsignedCharArray + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`AlgorithmOutput` +~~~~~~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: AlgorithmOutput + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`Renderer` +~~~~~~~~~~~~~~~~~ + + +.. autoclass:: Renderer + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`Skybox` +~~~~~~~~~~~~~~~ + + +.. autoclass:: Skybox + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`Volume` +~~~~~~~~~~~~~~~ + + +.. autoclass:: Volume + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`Actor2D` +~~~~~~~~~~~~~~~~ + + +.. autoclass:: Actor2D + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`Actor` +~~~~~~~~~~~~~~ + + +.. autoclass:: Actor + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`RenderWindow` +~~~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: RenderWindow + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`RenderWindowInteractor` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: RenderWindowInteractor + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`InteractorEventRecorder` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: InteractorEventRecorder + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`WindowToImageFilter` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: WindowToImageFilter + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`InteractorStyle` +~~~~~~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: InteractorStyle + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`PropPicker` +~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: PropPicker + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`PointPicker` +~~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: PointPicker + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`CellPicker` +~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: CellPicker + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`WorldPointPicker` +~~~~~~~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: WorldPointPicker + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`HardwareSelector` +~~~~~~~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: HardwareSelector + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`ImageActor` +~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: ImageActor + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`PolyDataMapper` +~~~~~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: PolyDataMapper + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`PolyDataMapper2D` +~~~~~~~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: PolyDataMapper2D + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`Assembly` +~~~~~~~~~~~~~~~~~ + + +.. autoclass:: Assembly + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`DataSetMapper` +~~~~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: DataSetMapper + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`Texture` +~~~~~~~~~~~~~~~~ + + +.. autoclass:: Texture + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`TexturedActor2D` +~~~~~~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: TexturedActor2D + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`Follower` +~~~~~~~~~~~~~~~~~ + + +.. autoclass:: Follower + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`TextActor` +~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: TextActor + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`TextActor3D` +~~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: TextActor3D + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`Property2D` +~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: Property2D + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`Camera` +~~~~~~~~~~~~~~~ + + +.. autoclass:: Camera + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`VectorText` +~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: VectorText + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`LODActor` +~~~~~~~~~~~~~~~~~ + + +.. autoclass:: LODActor + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`ScalarBarActor` +~~~~~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: ScalarBarActor + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`OpenGLRenderer` +~~~~~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: OpenGLRenderer + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`Shader` +~~~~~~~~~~~~~~~ + + +.. autoclass:: Shader + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`InteractorStyleImage` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: InteractorStyleImage + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`InteractorStyleTrackballActor` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: InteractorStyleTrackballActor + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`InteractorStyleTrackballCamera` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: InteractorStyleTrackballCamera + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`InteractorStyleUser` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: InteractorStyleUser + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`CleanPolyData` +~~~~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: CleanPolyData + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`PolyDataNormals` +~~~~~~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: PolyDataNormals + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`ContourFilter` +~~~~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: ContourFilter + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`TubeFilter` +~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: TubeFilter + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`Glyph3D` +~~~~~~~~~~~~~~~~ + + +.. autoclass:: Glyph3D + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`TriangleFilter` +~~~~~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: TriangleFilter + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`SplineFilter` +~~~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: SplineFilter + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`TransformPolyDataFilter` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: TransformPolyDataFilter + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`RenderLargeImage` +~~~~~~~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: RenderLargeImage + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`LoopSubdivisionFilter` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: LoopSubdivisionFilter + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`ButterflySubdivisionFilter` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: ButterflySubdivisionFilter + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`OutlineFilter` +~~~~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: OutlineFilter + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`LinearExtrusionFilter` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: LinearExtrusionFilter + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`TextureMapToPlane` +~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: TextureMapToPlane + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`SphereSource` +~~~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: SphereSource + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`CylinderSource` +~~~~~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: CylinderSource + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`ArrowSource` +~~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: ArrowSource + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`ConeSource` +~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: ConeSource + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`DiskSource` +~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: DiskSource + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`TexturedSphereSource` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: TexturedSphereSource + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`RegularPolygonSource` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: RegularPolygonSource + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`PolyData` +~~~~~~~~~~~~~~~~~ + + +.. autoclass:: PolyData + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`ImageData` +~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: ImageData + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`DataObject` +~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: DataObject + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`CellArray` +~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: CellArray + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`PolyVertex` +~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: PolyVertex + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`UnstructuredGrid` +~~~~~~~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: UnstructuredGrid + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`Polygon` +~~~~~~~~~~~~~~~~ + + +.. autoclass:: Polygon + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`DataObject` +~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: DataObject + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`Molecule` +~~~~~~~~~~~~~~~~~ + + +.. autoclass:: Molecule + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`DataSetAttributes` +~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: DataSetAttributes + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`Transform` +~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: Transform + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`Matrix4x4` +~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: Matrix4x4 + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`Matrix3x3` +~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: Matrix3x3 + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`ImageFlip` +~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: ImageFlip + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`ImageReslice` +~~~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: ImageReslice + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`ImageMapToColors` +~~~~~~~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: ImageMapToColors + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`ImageReader2Factory` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: ImageReader2Factory + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`PNGReader` +~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: PNGReader + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`BMPReader` +~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: BMPReader + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`JPEGReader` +~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: JPEGReader + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`TIFFReader` +~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: TIFFReader + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`PLYReader` +~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: PLYReader + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`STLReader` +~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: STLReader + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`OBJReader` +~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: OBJReader + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`MNIObjectReader` +~~~~~~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: MNIObjectReader + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`PolyDataReader` +~~~~~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: PolyDataReader + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`XMLPolyDataReader` +~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: XMLPolyDataReader + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`PNGWriter` +~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: PNGWriter + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`BMPWriter` +~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: BMPWriter + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`JPEGWriter` +~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: JPEGWriter + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`TIFFWriter` +~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: TIFFWriter + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`PLYWriter` +~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: PLYWriter + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`STLWriter` +~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: STLWriter + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`MNIObjectWriter` +~~~~~~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: MNIObjectWriter + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`PolyDataWriter` +~~~~~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: PolyDataWriter + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`XMLPolyDataWriter` +~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: XMLPolyDataWriter + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`SimpleBondPerceiver` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: SimpleBondPerceiver + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`ProteinRibbonFilter` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: ProteinRibbonFilter + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`PeriodicTable` +~~~~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: PeriodicTable + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`OpenGLMoleculeMapper` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: OpenGLMoleculeMapper + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + +VTK_VERSION +~~~~~~~~~~~ + +.. autofunction:: VTK_VERSION + diff --git a/v0.10.x/_sources/reference/fury.material.rst.txt b/v0.10.x/_sources/reference/fury.material.rst.txt new file mode 100644 index 000000000..7330077ce --- /dev/null +++ b/v0.10.x/_sources/reference/fury.material.rst.txt @@ -0,0 +1,31 @@ +.. AUTO-GENERATED FILE -- DO NOT EDIT! + +:mod:`material` +=============== +.. automodule:: fury.material + +.. currentmodule:: fury.material +.. autosummary:: + + manifest_pbr + manifest_principled + manifest_standard + + +.. currentmodule:: fury.material + +manifest_pbr +~~~~~~~~~~~~ + +.. autofunction:: manifest_pbr + +manifest_principled +~~~~~~~~~~~~~~~~~~~ + +.. autofunction:: manifest_principled + +manifest_standard +~~~~~~~~~~~~~~~~~ + +.. autofunction:: manifest_standard + diff --git a/v0.10.x/_sources/reference/fury.molecular.rst.txt b/v0.10.x/_sources/reference/fury.molecular.rst.txt new file mode 100644 index 000000000..564b7acc4 --- /dev/null +++ b/v0.10.x/_sources/reference/fury.molecular.rst.txt @@ -0,0 +1,147 @@ +.. AUTO-GENERATED FILE -- DO NOT EDIT! + +:mod:`molecular` +================ +.. automodule:: fury.molecular + +.. currentmodule:: fury.molecular +.. autosummary:: + + Molecule + PTable + add_atom + add_bond + get_atomic_number + set_atomic_number + get_atomic_position + set_atomic_position + get_bond_order + set_bond_order + get_all_atomic_numbers + get_all_bond_orders + get_all_atomic_positions + deep_copy_molecule + compute_bonding + sphere_cpk + ball_stick + stick + ribbon + bounding_box + + +.. currentmodule:: fury.molecular + + +:class:`Molecule` +~~~~~~~~~~~~~~~~~ + + +.. autoclass:: Molecule + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`PTable` +~~~~~~~~~~~~~~~ + + +.. autoclass:: PTable + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + +add_atom +~~~~~~~~ + +.. autofunction:: add_atom + +add_bond +~~~~~~~~ + +.. autofunction:: add_bond + +get_atomic_number +~~~~~~~~~~~~~~~~~ + +.. autofunction:: get_atomic_number + +set_atomic_number +~~~~~~~~~~~~~~~~~ + +.. autofunction:: set_atomic_number + +get_atomic_position +~~~~~~~~~~~~~~~~~~~ + +.. autofunction:: get_atomic_position + +set_atomic_position +~~~~~~~~~~~~~~~~~~~ + +.. autofunction:: set_atomic_position + +get_bond_order +~~~~~~~~~~~~~~ + +.. autofunction:: get_bond_order + +set_bond_order +~~~~~~~~~~~~~~ + +.. autofunction:: set_bond_order + +get_all_atomic_numbers +~~~~~~~~~~~~~~~~~~~~~~ + +.. autofunction:: get_all_atomic_numbers + +get_all_bond_orders +~~~~~~~~~~~~~~~~~~~ + +.. autofunction:: get_all_bond_orders + +get_all_atomic_positions +~~~~~~~~~~~~~~~~~~~~~~~~ + +.. autofunction:: get_all_atomic_positions + +deep_copy_molecule +~~~~~~~~~~~~~~~~~~ + +.. autofunction:: deep_copy_molecule + +compute_bonding +~~~~~~~~~~~~~~~ + +.. autofunction:: compute_bonding + +sphere_cpk +~~~~~~~~~~ + +.. autofunction:: sphere_cpk + +ball_stick +~~~~~~~~~~ + +.. autofunction:: ball_stick + +stick +~~~~~ + +.. autofunction:: stick + +ribbon +~~~~~~ + +.. autofunction:: ribbon + +bounding_box +~~~~~~~~~~~~ + +.. autofunction:: bounding_box + diff --git a/v0.10.x/_sources/reference/fury.pick.rst.txt b/v0.10.x/_sources/reference/fury.pick.rst.txt new file mode 100644 index 000000000..2b3540229 --- /dev/null +++ b/v0.10.x/_sources/reference/fury.pick.rst.txt @@ -0,0 +1,39 @@ +.. AUTO-GENERATED FILE -- DO NOT EDIT! + +:mod:`pick` +=========== +.. automodule:: fury.pick + +.. currentmodule:: fury.pick +.. autosummary:: + + PickingManager + SelectionManager + + +.. currentmodule:: fury.pick + + +:class:`PickingManager` +~~~~~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: PickingManager + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`SelectionManager` +~~~~~~~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: SelectionManager + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + diff --git a/v0.10.x/_sources/reference/fury.pkg_info.rst.txt b/v0.10.x/_sources/reference/fury.pkg_info.rst.txt new file mode 100644 index 000000000..3c0ae6cc9 --- /dev/null +++ b/v0.10.x/_sources/reference/fury.pkg_info.rst.txt @@ -0,0 +1,19 @@ +.. AUTO-GENERATED FILE -- DO NOT EDIT! + +:mod:`pkg_info` +=============== +.. automodule:: fury.pkg_info + +.. currentmodule:: fury.pkg_info +.. autosummary:: + + pkg_commit_hash + + +.. currentmodule:: fury.pkg_info + +pkg_commit_hash +~~~~~~~~~~~~~~~ + +.. autofunction:: pkg_commit_hash + diff --git a/v0.10.x/_sources/reference/fury.primitive.rst.txt b/v0.10.x/_sources/reference/fury.primitive.rst.txt new file mode 100644 index 000000000..edd4b886e --- /dev/null +++ b/v0.10.x/_sources/reference/fury.primitive.rst.txt @@ -0,0 +1,121 @@ +.. AUTO-GENERATED FILE -- DO NOT EDIT! + +:mod:`primitive` +================ +.. automodule:: fury.primitive + +.. currentmodule:: fury.primitive +.. autosummary:: + + faces_from_sphere_vertices + repeat_primitive_function + repeat_primitive + prim_square + prim_box + prim_sphere + prim_superquadric + prim_tetrahedron + prim_icosahedron + prim_rhombicuboctahedron + prim_star + prim_triangularprism + prim_pentagonalprism + prim_octagonalprism + prim_frustum + prim_cylinder + prim_arrow + prim_cone + + +.. currentmodule:: fury.primitive + +faces_from_sphere_vertices +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. autofunction:: faces_from_sphere_vertices + +repeat_primitive_function +~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. autofunction:: repeat_primitive_function + +repeat_primitive +~~~~~~~~~~~~~~~~ + +.. autofunction:: repeat_primitive + +prim_square +~~~~~~~~~~~ + +.. autofunction:: prim_square + +prim_box +~~~~~~~~ + +.. autofunction:: prim_box + +prim_sphere +~~~~~~~~~~~ + +.. autofunction:: prim_sphere + +prim_superquadric +~~~~~~~~~~~~~~~~~ + +.. autofunction:: prim_superquadric + +prim_tetrahedron +~~~~~~~~~~~~~~~~ + +.. autofunction:: prim_tetrahedron + +prim_icosahedron +~~~~~~~~~~~~~~~~ + +.. autofunction:: prim_icosahedron + +prim_rhombicuboctahedron +~~~~~~~~~~~~~~~~~~~~~~~~ + +.. autofunction:: prim_rhombicuboctahedron + +prim_star +~~~~~~~~~ + +.. autofunction:: prim_star + +prim_triangularprism +~~~~~~~~~~~~~~~~~~~~ + +.. autofunction:: prim_triangularprism + +prim_pentagonalprism +~~~~~~~~~~~~~~~~~~~~ + +.. autofunction:: prim_pentagonalprism + +prim_octagonalprism +~~~~~~~~~~~~~~~~~~~ + +.. autofunction:: prim_octagonalprism + +prim_frustum +~~~~~~~~~~~~ + +.. autofunction:: prim_frustum + +prim_cylinder +~~~~~~~~~~~~~ + +.. autofunction:: prim_cylinder + +prim_arrow +~~~~~~~~~~ + +.. autofunction:: prim_arrow + +prim_cone +~~~~~~~~~ + +.. autofunction:: prim_cone + diff --git a/v0.10.x/_sources/reference/fury.rst.txt b/v0.10.x/_sources/reference/fury.rst.txt new file mode 100644 index 000000000..f2e49f37b --- /dev/null +++ b/v0.10.x/_sources/reference/fury.rst.txt @@ -0,0 +1,31 @@ +.. AUTO-GENERATED FILE -- DO NOT EDIT! + +:mod:`fury` +=========== +.. automodule:: fury + +.. currentmodule:: fury +.. autosummary:: + + get_info + enable_warnings + disable_warnings + + +.. currentmodule:: fury + +get_info +~~~~~~~~ + +.. autofunction:: get_info + +enable_warnings +~~~~~~~~~~~~~~~ + +.. autofunction:: enable_warnings + +disable_warnings +~~~~~~~~~~~~~~~~ + +.. autofunction:: disable_warnings + diff --git a/v0.10.x/_sources/reference/fury.shaders.rst.txt b/v0.10.x/_sources/reference/fury.shaders.rst.txt new file mode 100644 index 000000000..5a6454f55 --- /dev/null +++ b/v0.10.x/_sources/reference/fury.shaders.rst.txt @@ -0,0 +1,86 @@ +.. AUTO-GENERATED FILE -- DO NOT EDIT! + +:mod:`shaders` +============== +.. automodule:: fury.shaders + +.. currentmodule:: fury.shaders +.. autosummary:: + + +.. AUTO-GENERATED FILE -- DO NOT EDIT! + +Module: :mod:`shaders.base` +--------------------------- +.. automodule:: fury.shaders.base + +.. currentmodule:: fury.shaders.base +.. autosummary:: + + SHADERS_DIR + compose_shader + import_fury_shader + load_shader + load + shader_to_actor + replace_shader_in_actor + add_shader_callback + shader_apply_effects + attribute_to_actor + + +.. currentmodule:: fury.shaders + + +.. currentmodule:: fury.shaders.base + +SHADERS_DIR +~~~~~~~~~~~ + +.. autofunction:: SHADERS_DIR + +compose_shader +~~~~~~~~~~~~~~ + +.. autofunction:: compose_shader + +import_fury_shader +~~~~~~~~~~~~~~~~~~ + +.. autofunction:: import_fury_shader + +load_shader +~~~~~~~~~~~ + +.. autofunction:: load_shader + +load +~~~~ + +.. autofunction:: load + +shader_to_actor +~~~~~~~~~~~~~~~ + +.. autofunction:: shader_to_actor + +replace_shader_in_actor +~~~~~~~~~~~~~~~~~~~~~~~ + +.. autofunction:: replace_shader_in_actor + +add_shader_callback +~~~~~~~~~~~~~~~~~~~ + +.. autofunction:: add_shader_callback + +shader_apply_effects +~~~~~~~~~~~~~~~~~~~~ + +.. autofunction:: shader_apply_effects + +attribute_to_actor +~~~~~~~~~~~~~~~~~~ + +.. autofunction:: attribute_to_actor + diff --git a/v0.10.x/_sources/reference/fury.stream.rst.txt b/v0.10.x/_sources/reference/fury.stream.rst.txt new file mode 100644 index 000000000..8316326cf --- /dev/null +++ b/v0.10.x/_sources/reference/fury.stream.rst.txt @@ -0,0 +1,383 @@ +.. AUTO-GENERATED FILE -- DO NOT EDIT! + +:mod:`stream` +============= +.. automodule:: fury.stream + +.. currentmodule:: fury.stream +.. autosummary:: + + +.. AUTO-GENERATED FILE -- DO NOT EDIT! + +Module: :mod:`stream.client` +---------------------------- +.. automodule:: fury.stream.client + +.. currentmodule:: fury.stream.client +.. autosummary:: + + FuryStreamClient + FuryStreamInteraction + callback_stream_client + interaction_callback + +.. AUTO-GENERATED FILE -- DO NOT EDIT! + +Module: :mod:`stream.constants` +------------------------------- +.. automodule:: fury.stream.constants + +.. currentmodule:: fury.stream.constants +.. autosummary:: + + _CQUEUE_EVENT_IDs + _CQUEUE_INDEX_INFO + _CQUEUE + +.. AUTO-GENERATED FILE -- DO NOT EDIT! + +Module: :mod:`stream.server` +---------------------------- +.. automodule:: fury.stream.server + +.. currentmodule:: fury.stream.server +.. autosummary:: + + +.. AUTO-GENERATED FILE -- DO NOT EDIT! + +Module: :mod:`stream.server.async_app` +-------------------------------------- +.. automodule:: fury.stream.server.async_app + +.. currentmodule:: fury.stream.server.async_app +.. autosummary:: + + pcs + set_weel + set_mouse + set_mouse_click + get_app + +.. AUTO-GENERATED FILE -- DO NOT EDIT! + +Module: :mod:`stream.server.main` +--------------------------------- +.. automodule:: fury.stream.server.main + +.. currentmodule:: fury.stream.server.main +.. autosummary:: + + RTCServer + web_server_raw_array + web_server + +.. AUTO-GENERATED FILE -- DO NOT EDIT! + +Module: :mod:`stream.tools` +--------------------------- +.. automodule:: fury.stream.tools + +.. currentmodule:: fury.stream.tools +.. autosummary:: + + GenericMultiDimensionalBuffer + RawArrayMultiDimensionalBuffer + SharedMemMultiDimensionalBuffer + GenericCircularQueue + ArrayCircularQueue + SharedMemCircularQueue + GenericImageBufferManager + RawArrayImageBufferManager + SharedMemImageBufferManager + IntervalTimerThreading + IntervalTimer + remove_shm_from_resource_tracker + +.. AUTO-GENERATED FILE -- DO NOT EDIT! + +Module: :mod:`stream.widget` +---------------------------- +.. automodule:: fury.stream.widget + +.. currentmodule:: fury.stream.widget +.. autosummary:: + + Widget + check_port_is_available + + +.. currentmodule:: fury.stream + + +.. currentmodule:: fury.stream.client + + +:class:`FuryStreamClient` +~~~~~~~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: FuryStreamClient + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`FuryStreamInteraction` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: FuryStreamInteraction + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + +callback_stream_client +~~~~~~~~~~~~~~~~~~~~~~ + +.. autofunction:: callback_stream_client + +interaction_callback +~~~~~~~~~~~~~~~~~~~~ + +.. autofunction:: interaction_callback + + +.. currentmodule:: fury.stream.constants + +_CQUEUE_EVENT_IDs +~~~~~~~~~~~~~~~~~ + +.. autofunction:: _CQUEUE_EVENT_IDs + +_CQUEUE_INDEX_INFO +~~~~~~~~~~~~~~~~~~ + +.. autofunction:: _CQUEUE_INDEX_INFO + +_CQUEUE +~~~~~~~ + +.. autofunction:: _CQUEUE + + +.. currentmodule:: fury.stream.server + + +.. currentmodule:: fury.stream.server.async_app + +pcs +~~~ + +.. autofunction:: pcs + +set_weel +~~~~~~~~ + +.. autofunction:: set_weel + +set_mouse +~~~~~~~~~ + +.. autofunction:: set_mouse + +set_mouse_click +~~~~~~~~~~~~~~~ + +.. autofunction:: set_mouse_click + +get_app +~~~~~~~ + +.. autofunction:: get_app + + +.. currentmodule:: fury.stream.server.main + + +:class:`RTCServer` +~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: RTCServer + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + +web_server_raw_array +~~~~~~~~~~~~~~~~~~~~ + +.. autofunction:: web_server_raw_array + +web_server +~~~~~~~~~~ + +.. autofunction:: web_server + + +.. currentmodule:: fury.stream.tools + + +:class:`GenericMultiDimensionalBuffer` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: GenericMultiDimensionalBuffer + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`RawArrayMultiDimensionalBuffer` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: RawArrayMultiDimensionalBuffer + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`SharedMemMultiDimensionalBuffer` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: SharedMemMultiDimensionalBuffer + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`GenericCircularQueue` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: GenericCircularQueue + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`ArrayCircularQueue` +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: ArrayCircularQueue + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`SharedMemCircularQueue` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: SharedMemCircularQueue + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`GenericImageBufferManager` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: GenericImageBufferManager + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`RawArrayImageBufferManager` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: RawArrayImageBufferManager + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`SharedMemImageBufferManager` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: SharedMemImageBufferManager + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`IntervalTimerThreading` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: IntervalTimerThreading + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`IntervalTimer` +~~~~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: IntervalTimer + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + +remove_shm_from_resource_tracker +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. autofunction:: remove_shm_from_resource_tracker + + +.. currentmodule:: fury.stream.widget + + +:class:`Widget` +~~~~~~~~~~~~~~~ + + +.. autoclass:: Widget + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + +check_port_is_available +~~~~~~~~~~~~~~~~~~~~~~~ + +.. autofunction:: check_port_is_available + diff --git a/v0.10.x/_sources/reference/fury.transform.rst.txt b/v0.10.x/_sources/reference/fury.transform.rst.txt new file mode 100644 index 000000000..5fe3fd709 --- /dev/null +++ b/v0.10.x/_sources/reference/fury.transform.rst.txt @@ -0,0 +1,67 @@ +.. AUTO-GENERATED FILE -- DO NOT EDIT! + +:mod:`transform` +================ +.. automodule:: fury.transform + +.. currentmodule:: fury.transform +.. autosummary:: + + _TUPLE2AXES + euler_matrix + sphere2cart + cart2sphere + translate + rotate + scale + apply_transformation + transform_from_matrix + + +.. currentmodule:: fury.transform + +_TUPLE2AXES +~~~~~~~~~~~ + +.. autofunction:: _TUPLE2AXES + +euler_matrix +~~~~~~~~~~~~ + +.. autofunction:: euler_matrix + +sphere2cart +~~~~~~~~~~~ + +.. autofunction:: sphere2cart + +cart2sphere +~~~~~~~~~~~ + +.. autofunction:: cart2sphere + +translate +~~~~~~~~~ + +.. autofunction:: translate + +rotate +~~~~~~ + +.. autofunction:: rotate + +scale +~~~~~ + +.. autofunction:: scale + +apply_transformation +~~~~~~~~~~~~~~~~~~~~ + +.. autofunction:: apply_transformation + +transform_from_matrix +~~~~~~~~~~~~~~~~~~~~~ + +.. autofunction:: transform_from_matrix + diff --git a/v0.10.x/_sources/reference/fury.ui.rst.txt b/v0.10.x/_sources/reference/fury.ui.rst.txt new file mode 100644 index 000000000..3b1d3d0bc --- /dev/null +++ b/v0.10.x/_sources/reference/fury.ui.rst.txt @@ -0,0 +1,446 @@ +.. AUTO-GENERATED FILE -- DO NOT EDIT! + +:mod:`ui` +========= +.. automodule:: fury.ui + +.. currentmodule:: fury.ui +.. autosummary:: + + +.. AUTO-GENERATED FILE -- DO NOT EDIT! + +Module: :mod:`ui.containers` +---------------------------- +.. automodule:: fury.ui.containers + +.. currentmodule:: fury.ui.containers +.. autosummary:: + + Panel2D + TabPanel2D + TabUI + ImageContainer2D + GridUI + +.. AUTO-GENERATED FILE -- DO NOT EDIT! + +Module: :mod:`ui.core` +---------------------- +.. automodule:: fury.ui.core + +.. currentmodule:: fury.ui.core +.. autosummary:: + + UI + Rectangle2D + Disk2D + TextBlock2D + Button2D + +.. AUTO-GENERATED FILE -- DO NOT EDIT! + +Module: :mod:`ui.elements` +-------------------------- +.. automodule:: fury.ui.elements + +.. currentmodule:: fury.ui.elements +.. autosummary:: + + TextBox2D + LineSlider2D + LineDoubleSlider2D + RingSlider2D + RangeSlider + Option + Checkbox + RadioButton + ComboBox2D + ListBox2D + ListBoxItem2D + FileMenu2D + DrawShape + DrawPanel + PlaybackPanel + Card2D + SpinBox + +.. AUTO-GENERATED FILE -- DO NOT EDIT! + +Module: :mod:`ui.helpers` +------------------------- +.. automodule:: fury.ui.helpers + +.. currentmodule:: fury.ui.helpers +.. autosummary:: + + clip_overflow + wrap_overflow + check_overflow + cal_bounding_box_2d + rotate_2d + + +.. currentmodule:: fury.ui + + +.. currentmodule:: fury.ui.containers + + +:class:`Panel2D` +~~~~~~~~~~~~~~~~ + + +.. autoclass:: Panel2D + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`TabPanel2D` +~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: TabPanel2D + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`TabUI` +~~~~~~~~~~~~~~ + + +.. autoclass:: TabUI + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`ImageContainer2D` +~~~~~~~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: ImageContainer2D + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`GridUI` +~~~~~~~~~~~~~~~ + + +.. autoclass:: GridUI + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +.. currentmodule:: fury.ui.core + + +:class:`UI` +~~~~~~~~~~~ + + +.. autoclass:: UI + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`Rectangle2D` +~~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: Rectangle2D + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`Disk2D` +~~~~~~~~~~~~~~~ + + +.. autoclass:: Disk2D + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`TextBlock2D` +~~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: TextBlock2D + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`Button2D` +~~~~~~~~~~~~~~~~~ + + +.. autoclass:: Button2D + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +.. currentmodule:: fury.ui.elements + + +:class:`TextBox2D` +~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: TextBox2D + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`LineSlider2D` +~~~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: LineSlider2D + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`LineDoubleSlider2D` +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: LineDoubleSlider2D + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`RingSlider2D` +~~~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: RingSlider2D + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`RangeSlider` +~~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: RangeSlider + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`Option` +~~~~~~~~~~~~~~~ + + +.. autoclass:: Option + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`Checkbox` +~~~~~~~~~~~~~~~~~ + + +.. autoclass:: Checkbox + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`RadioButton` +~~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: RadioButton + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`ComboBox2D` +~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: ComboBox2D + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`ListBox2D` +~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: ListBox2D + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`ListBoxItem2D` +~~~~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: ListBoxItem2D + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`FileMenu2D` +~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: FileMenu2D + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`DrawShape` +~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: DrawShape + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`DrawPanel` +~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: DrawPanel + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`PlaybackPanel` +~~~~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: PlaybackPanel + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`Card2D` +~~~~~~~~~~~~~~~ + + +.. autoclass:: Card2D + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`SpinBox` +~~~~~~~~~~~~~~~~ + + +.. autoclass:: SpinBox + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +.. currentmodule:: fury.ui.helpers + +clip_overflow +~~~~~~~~~~~~~ + +.. autofunction:: clip_overflow + +wrap_overflow +~~~~~~~~~~~~~ + +.. autofunction:: wrap_overflow + +check_overflow +~~~~~~~~~~~~~~ + +.. autofunction:: check_overflow + +cal_bounding_box_2d +~~~~~~~~~~~~~~~~~~~ + +.. autofunction:: cal_bounding_box_2d + +rotate_2d +~~~~~~~~~ + +.. autofunction:: rotate_2d + diff --git a/v0.10.x/_sources/reference/fury.utils.rst.txt b/v0.10.x/_sources/reference/fury.utils.rst.txt new file mode 100644 index 000000000..6ee861545 --- /dev/null +++ b/v0.10.x/_sources/reference/fury.utils.rst.txt @@ -0,0 +1,397 @@ +.. AUTO-GENERATED FILE -- DO NOT EDIT! + +:mod:`utils` +============ +.. automodule:: fury.utils + +.. currentmodule:: fury.utils +.. autosummary:: + + remove_observer_from_actor + set_input + numpy_to_vtk_points + numpy_to_vtk_colors + numpy_to_vtk_cells + numpy_to_vtk_image_data + map_coordinates_3d_4d + lines_to_vtk_polydata + get_polydata_lines + get_polydata_triangles + get_polydata_vertices + get_polydata_tcoord + get_polydata_normals + get_polydata_tangents + get_polydata_colors + get_polydata_field + add_polydata_numeric_field + set_polydata_primitives_count + get_polydata_primitives_count + primitives_count_to_actor + primitives_count_from_actor + set_polydata_triangles + set_polydata_vertices + set_polydata_normals + set_polydata_tangents + set_polydata_colors + set_polydata_tcoords + update_polydata_normals + get_polymapper_from_polydata + get_actor_from_polymapper + get_actor_from_polydata + get_actor_from_primitive + repeat_sources + apply_affine_to_actor + apply_affine + asbytes + vtk_matrix_to_numpy + numpy_to_vtk_matrix + get_bounding_box_sizes + get_grid_cells_position + shallow_copy + rotate + rgb_to_vtk + normalize_v3 + normals_from_v_f + tangents_from_direction_of_anisotropy + triangle_order + change_vertices_order + fix_winding_order + vertices_from_actor + colors_from_actor + normals_from_actor + tangents_from_actor + array_from_actor + normals_to_actor + tangents_to_actor + compute_bounds + update_actor + get_bounds + represent_actor_as_wireframe + update_surface_actor_colors + color_check + is_ui + set_actor_origin + + +.. currentmodule:: fury.utils + +remove_observer_from_actor +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. autofunction:: remove_observer_from_actor + +set_input +~~~~~~~~~ + +.. autofunction:: set_input + +numpy_to_vtk_points +~~~~~~~~~~~~~~~~~~~ + +.. autofunction:: numpy_to_vtk_points + +numpy_to_vtk_colors +~~~~~~~~~~~~~~~~~~~ + +.. autofunction:: numpy_to_vtk_colors + +numpy_to_vtk_cells +~~~~~~~~~~~~~~~~~~ + +.. autofunction:: numpy_to_vtk_cells + +numpy_to_vtk_image_data +~~~~~~~~~~~~~~~~~~~~~~~ + +.. autofunction:: numpy_to_vtk_image_data + +map_coordinates_3d_4d +~~~~~~~~~~~~~~~~~~~~~ + +.. autofunction:: map_coordinates_3d_4d + +lines_to_vtk_polydata +~~~~~~~~~~~~~~~~~~~~~ + +.. autofunction:: lines_to_vtk_polydata + +get_polydata_lines +~~~~~~~~~~~~~~~~~~ + +.. autofunction:: get_polydata_lines + +get_polydata_triangles +~~~~~~~~~~~~~~~~~~~~~~ + +.. autofunction:: get_polydata_triangles + +get_polydata_vertices +~~~~~~~~~~~~~~~~~~~~~ + +.. autofunction:: get_polydata_vertices + +get_polydata_tcoord +~~~~~~~~~~~~~~~~~~~ + +.. autofunction:: get_polydata_tcoord + +get_polydata_normals +~~~~~~~~~~~~~~~~~~~~ + +.. autofunction:: get_polydata_normals + +get_polydata_tangents +~~~~~~~~~~~~~~~~~~~~~ + +.. autofunction:: get_polydata_tangents + +get_polydata_colors +~~~~~~~~~~~~~~~~~~~ + +.. autofunction:: get_polydata_colors + +get_polydata_field +~~~~~~~~~~~~~~~~~~ + +.. autofunction:: get_polydata_field + +add_polydata_numeric_field +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. autofunction:: add_polydata_numeric_field + +set_polydata_primitives_count +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. autofunction:: set_polydata_primitives_count + +get_polydata_primitives_count +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. autofunction:: get_polydata_primitives_count + +primitives_count_to_actor +~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. autofunction:: primitives_count_to_actor + +primitives_count_from_actor +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. autofunction:: primitives_count_from_actor + +set_polydata_triangles +~~~~~~~~~~~~~~~~~~~~~~ + +.. autofunction:: set_polydata_triangles + +set_polydata_vertices +~~~~~~~~~~~~~~~~~~~~~ + +.. autofunction:: set_polydata_vertices + +set_polydata_normals +~~~~~~~~~~~~~~~~~~~~ + +.. autofunction:: set_polydata_normals + +set_polydata_tangents +~~~~~~~~~~~~~~~~~~~~~ + +.. autofunction:: set_polydata_tangents + +set_polydata_colors +~~~~~~~~~~~~~~~~~~~ + +.. autofunction:: set_polydata_colors + +set_polydata_tcoords +~~~~~~~~~~~~~~~~~~~~ + +.. autofunction:: set_polydata_tcoords + +update_polydata_normals +~~~~~~~~~~~~~~~~~~~~~~~ + +.. autofunction:: update_polydata_normals + +get_polymapper_from_polydata +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. autofunction:: get_polymapper_from_polydata + +get_actor_from_polymapper +~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. autofunction:: get_actor_from_polymapper + +get_actor_from_polydata +~~~~~~~~~~~~~~~~~~~~~~~ + +.. autofunction:: get_actor_from_polydata + +get_actor_from_primitive +~~~~~~~~~~~~~~~~~~~~~~~~ + +.. autofunction:: get_actor_from_primitive + +repeat_sources +~~~~~~~~~~~~~~ + +.. autofunction:: repeat_sources + +apply_affine_to_actor +~~~~~~~~~~~~~~~~~~~~~ + +.. autofunction:: apply_affine_to_actor + +apply_affine +~~~~~~~~~~~~ + +.. autofunction:: apply_affine + +asbytes +~~~~~~~ + +.. autofunction:: asbytes + +vtk_matrix_to_numpy +~~~~~~~~~~~~~~~~~~~ + +.. autofunction:: vtk_matrix_to_numpy + +numpy_to_vtk_matrix +~~~~~~~~~~~~~~~~~~~ + +.. autofunction:: numpy_to_vtk_matrix + +get_bounding_box_sizes +~~~~~~~~~~~~~~~~~~~~~~ + +.. autofunction:: get_bounding_box_sizes + +get_grid_cells_position +~~~~~~~~~~~~~~~~~~~~~~~ + +.. autofunction:: get_grid_cells_position + +shallow_copy +~~~~~~~~~~~~ + +.. autofunction:: shallow_copy + +rotate +~~~~~~ + +.. autofunction:: rotate + +rgb_to_vtk +~~~~~~~~~~ + +.. autofunction:: rgb_to_vtk + +normalize_v3 +~~~~~~~~~~~~ + +.. autofunction:: normalize_v3 + +normals_from_v_f +~~~~~~~~~~~~~~~~ + +.. autofunction:: normals_from_v_f + +tangents_from_direction_of_anisotropy +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. autofunction:: tangents_from_direction_of_anisotropy + +triangle_order +~~~~~~~~~~~~~~ + +.. autofunction:: triangle_order + +change_vertices_order +~~~~~~~~~~~~~~~~~~~~~ + +.. autofunction:: change_vertices_order + +fix_winding_order +~~~~~~~~~~~~~~~~~ + +.. autofunction:: fix_winding_order + +vertices_from_actor +~~~~~~~~~~~~~~~~~~~ + +.. autofunction:: vertices_from_actor + +colors_from_actor +~~~~~~~~~~~~~~~~~ + +.. autofunction:: colors_from_actor + +normals_from_actor +~~~~~~~~~~~~~~~~~~ + +.. autofunction:: normals_from_actor + +tangents_from_actor +~~~~~~~~~~~~~~~~~~~ + +.. autofunction:: tangents_from_actor + +array_from_actor +~~~~~~~~~~~~~~~~ + +.. autofunction:: array_from_actor + +normals_to_actor +~~~~~~~~~~~~~~~~ + +.. autofunction:: normals_to_actor + +tangents_to_actor +~~~~~~~~~~~~~~~~~ + +.. autofunction:: tangents_to_actor + +compute_bounds +~~~~~~~~~~~~~~ + +.. autofunction:: compute_bounds + +update_actor +~~~~~~~~~~~~ + +.. autofunction:: update_actor + +get_bounds +~~~~~~~~~~ + +.. autofunction:: get_bounds + +represent_actor_as_wireframe +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. autofunction:: represent_actor_as_wireframe + +update_surface_actor_colors +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. autofunction:: update_surface_actor_colors + +color_check +~~~~~~~~~~~ + +.. autofunction:: color_check + +is_ui +~~~~~ + +.. autofunction:: is_ui + +set_actor_origin +~~~~~~~~~~~~~~~~ + +.. autofunction:: set_actor_origin + diff --git a/v0.10.x/_sources/reference/fury.window.rst.txt b/v0.10.x/_sources/reference/fury.window.rst.txt new file mode 100644 index 000000000..4a99c01b6 --- /dev/null +++ b/v0.10.x/_sources/reference/fury.window.rst.txt @@ -0,0 +1,153 @@ +.. AUTO-GENERATED FILE -- DO NOT EDIT! + +:mod:`window` +============= +.. automodule:: fury.window + +.. currentmodule:: fury.window +.. autosummary:: + + Scene + ShowManager + show + record + antialiasing + snapshot + analyze_scene + analyze_snapshot + enable_stereo + gl_get_current_state + gl_reset_blend + gl_enable_depth + gl_disable_depth + gl_enable_blend + gl_disable_blend + gl_set_additive_blending + gl_set_additive_blending_white_background + gl_set_normal_blending + gl_set_multiplicative_blending + gl_set_subtractive_blending + release_context + + +.. currentmodule:: fury.window + + +:class:`Scene` +~~~~~~~~~~~~~~ + + +.. autoclass:: Scene + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + + +:class:`ShowManager` +~~~~~~~~~~~~~~~~~~~~ + + +.. autoclass:: ShowManager + :members: + :undoc-members: + :show-inheritance: + + .. automethod:: __init__ + +show +~~~~ + +.. autofunction:: show + +record +~~~~~~ + +.. autofunction:: record + +antialiasing +~~~~~~~~~~~~ + +.. autofunction:: antialiasing + +snapshot +~~~~~~~~ + +.. autofunction:: snapshot + +analyze_scene +~~~~~~~~~~~~~ + +.. autofunction:: analyze_scene + +analyze_snapshot +~~~~~~~~~~~~~~~~ + +.. autofunction:: analyze_snapshot + +enable_stereo +~~~~~~~~~~~~~ + +.. autofunction:: enable_stereo + +gl_get_current_state +~~~~~~~~~~~~~~~~~~~~ + +.. autofunction:: gl_get_current_state + +gl_reset_blend +~~~~~~~~~~~~~~ + +.. autofunction:: gl_reset_blend + +gl_enable_depth +~~~~~~~~~~~~~~~ + +.. autofunction:: gl_enable_depth + +gl_disable_depth +~~~~~~~~~~~~~~~~ + +.. autofunction:: gl_disable_depth + +gl_enable_blend +~~~~~~~~~~~~~~~ + +.. autofunction:: gl_enable_blend + +gl_disable_blend +~~~~~~~~~~~~~~~~ + +.. autofunction:: gl_disable_blend + +gl_set_additive_blending +~~~~~~~~~~~~~~~~~~~~~~~~ + +.. autofunction:: gl_set_additive_blending + +gl_set_additive_blending_white_background +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. autofunction:: gl_set_additive_blending_white_background + +gl_set_normal_blending +~~~~~~~~~~~~~~~~~~~~~~ + +.. autofunction:: gl_set_normal_blending + +gl_set_multiplicative_blending +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. autofunction:: gl_set_multiplicative_blending + +gl_set_subtractive_blending +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. autofunction:: gl_set_subtractive_blending + +release_context +~~~~~~~~~~~~~~~ + +.. autofunction:: release_context + diff --git a/v0.10.x/_sources/reference/index.rst.txt b/v0.10.x/_sources/reference/index.rst.txt new file mode 100644 index 000000000..8a8585aa3 --- /dev/null +++ b/v0.10.x/_sources/reference/index.rst.txt @@ -0,0 +1,31 @@ +.. AUTO-GENERATED FILE -- DO NOT EDIT! + +API Reference +============= + +.. toctree:: + + fury.rst + fury.actor.rst + fury.actors.rst + fury.animation.rst + fury.colormap.rst + fury.convert.rst + fury.data.rst + fury.decorators.rst + fury.deprecator.rst + fury.gltf.rst + fury.io.rst + fury.layout.rst + fury.lib.rst + fury.material.rst + fury.molecular.rst + fury.pick.rst + fury.pkg_info.rst + fury.primitive.rst + fury.shaders.rst + fury.stream.rst + fury.transform.rst + fury.ui.rst + fury.utils.rst + fury.window.rst diff --git a/v0.10.x/_sources/release-history.rst.txt b/v0.10.x/_sources/release-history.rst.txt new file mode 100644 index 000000000..78a1e25b9 --- /dev/null +++ b/v0.10.x/_sources/release-history.rst.txt @@ -0,0 +1,24 @@ +=============== +Release History +=============== + +For a full list of the features implemented in the most recent release cycle, check out the release notes. + +.. toctree:: + :maxdepth: 1 + + release_notes/releasev0.10.0 + release_notes/releasev0.9.0 + release_notes/releasev0.8.0 + release_notes/releasev0.7.1 + release_notes/releasev0.7.0 + release_notes/releasev0.6.1 + release_notes/releasev0.6.0 + release_notes/releasev0.5.1 + release_notes/releasev0.4.0 + release_notes/releasev0.3.0 + release_notes/releasev0.2.0 + release_notes/releasev0.1.4 + release_notes/releasev0.1.3 + release_notes/releasev0.1.1 + release_notes/releasev0.1.0 diff --git a/v0.10.x/_sources/release_notes/releasev0.1.0.rst.txt b/v0.10.x/_sources/release_notes/releasev0.1.0.rst.txt new file mode 100644 index 000000000..2a914bf24 --- /dev/null +++ b/v0.10.x/_sources/release_notes/releasev0.1.0.rst.txt @@ -0,0 +1,18 @@ +.. _releasev0.1.0: + +================================== + Release notes v0.1.0 (2018-09-21) +================================== + +Quick Overview +-------------- + +This initial release is a split from DIPY. It contains: + +* from ``dipy.viz.actors`` to ``fury.actors`` +* from ``dipy.viz.window`` to ``fury.window`` +* from ``dipy.viz.ui`` to ``fury.ui`` +* from ``dipy.viz.widget`` to ``fury.widget`` +* from ``dipy.viz.interactor`` to ``fury.interactor`` +* from ``dipy.viz.colormap`` to ``fury.colormap`` +* from ``dipy.viz.utils`` to ``fury.utils`` diff --git a/v0.10.x/_sources/release_notes/releasev0.1.1.rst.txt b/v0.10.x/_sources/release_notes/releasev0.1.1.rst.txt new file mode 100644 index 000000000..1551cc094 --- /dev/null +++ b/v0.10.x/_sources/release_notes/releasev0.1.1.rst.txt @@ -0,0 +1,14 @@ +.. _releasev0.1.1: + +================================== + Release notes v0.1.1 (2018-10-29) +================================== + +Quick Overview +-------------- + +This is a maintenance release + +* Fix error on python 2.7 +* Travis integration +* Documentation integration diff --git a/v0.10.x/_sources/release_notes/releasev0.1.3.rst.txt b/v0.10.x/_sources/release_notes/releasev0.1.3.rst.txt new file mode 100644 index 000000000..3d2e7e238 --- /dev/null +++ b/v0.10.x/_sources/release_notes/releasev0.1.3.rst.txt @@ -0,0 +1,13 @@ +.. _releasev0.1.3: + +============================================= + Release notes v0.1.2 and v0.1.3 (2018-10-31) +============================================= + +Quick Overview +-------------- + +This is a maintenance release + +* Update setup.py +* Remove dependence on requirements.txt diff --git a/v0.10.x/_sources/release_notes/releasev0.1.4.rst.txt b/v0.10.x/_sources/release_notes/releasev0.1.4.rst.txt new file mode 100644 index 000000000..9a6b46769 --- /dev/null +++ b/v0.10.x/_sources/release_notes/releasev0.1.4.rst.txt @@ -0,0 +1,13 @@ +.. _releasev0.1.4: + +================================== + Release notes v0.1.4 (2018-11-26) +================================== + +Quick Overview +-------------- + +This is a maintenance release + +* Add vtk.utils.color on window package +* Update Readme, codecov, travis... diff --git a/v0.10.x/_sources/release_notes/releasev0.10.0.rst.txt b/v0.10.x/_sources/release_notes/releasev0.10.0.rst.txt new file mode 100644 index 000000000..308082bfe --- /dev/null +++ b/v0.10.x/_sources/release_notes/releasev0.10.0.rst.txt @@ -0,0 +1,177 @@ +.. _releasev0.10.0: + +=================================== + Release notes v0.10.0 (2024/02/28) +=================================== + +Quick Overview +-------------- + +* Uncertainty Visualization added. +* New actors added. +* Many UI components updated. +* Multiple tutorials added and updated. +* Documentation updated. +* Website updated. + + +Details +------- + +GitHub stats for 2023/04/15 - 2024/02/27 (tag: v0.9.0) + +These lists are automatically generated, and may be incomplete or contain duplicates. + +The following 11 authors contributed 382 commits. + +* Antriksh Misri +* Dwij Raj Hari +* Eleftherios Garyfallidis +* Joao Victor Dell Agli +* Maharshi Gor +* Praneeth Shetty +* Robin Roy +* Serge Koudoro +* Tania Castillo +* dependabot[bot] +* maharshigor + + +We closed a total of 129 issues, 54 pull requests and 75 regular issues; +this is the full list (generated with the script +:file:`tools/github_stats.py`): + +Pull Requests (54): + +* :ghpull:`810`: DTI uncertainty visualization +* :ghpull:`861`: Added/Modified docstrings for 3 actor.py functions +* :ghpull:`863`: UI Bug fixes for Horizon +* :ghpull:`866`: build(deps): bump the actions group with 6 updates +* :ghpull:`865`: Fix ci +* :ghpull:`845`: GSoC: Final Report +* :ghpull:`847`: GSoC: Adding Final Report 23 +* :ghpull:`848`: Added Final Report +* :ghpull:`852`: add Code of conduct +* :ghpull:`846`: Added blogpost week 12 +* :ghpull:`844`: GSoC: Week 12 Blogpost +* :ghpull:`843`: GSoC: Adding Week 12 Blogpost +* :ghpull:`842`: GSoC: Week 11 Blogpost +* :ghpull:`839`: GSoC: Adding Week 10 Blogpost +* :ghpull:`840`: Added blogposts week 8, 9, 10, 11 +* :ghpull:`841`: GSoC: Adding Week 11 Blogpost +* :ghpull:`831`: GSoC: Week 9 Blogpost +* :ghpull:`833`: GSoC: Adding Week 9 Blogpost +* :ghpull:`836`: GSoC: Week 10 Blogpost +* :ghpull:`499`: Adding `SpinBoxUI` to the `UI` module +* :ghpull:`818`: Tutorial on using ellipsoid actor to visualize tensor ellipsoids for DTI +* :ghpull:`834`: citation section added +* :ghpull:`830`: UI: Adding getters and setters for the `TextBlock2D` properties +* :ghpull:`829`: GSoC: Adding Week 8 Blogpost +* :ghpull:`828`: GSoC: Week 8 Blogpost +* :ghpull:`803`: UI: Adding Bounding Box & Fixing Alignment issue in TextBlock2D +* :ghpull:`814`: physics-simulation done +* :ghpull:`827`: Added blogpost week 4, 5, 6, 7 +* :ghpull:`822`: GSoC: Week 7 Blogpost +* :ghpull:`823`: GSoC: Adding Week 6 - 7 Blogpost +* :ghpull:`791`: Ellipsoid actor implemented with SDF +* :ghpull:`817`: GSoC: Adding Week 5 Blogpost +* :ghpull:`820`: Updating broken links in the Scientific Domain Section +* :ghpull:`819`: GSoC: Week 6 Blogpost +* :ghpull:`815`: Week 5 blogpost +* :ghpull:`812`: Feature/compatible software +* :ghpull:`811`: GSoC: Adding Week 4 Blogpost +* :ghpull:`809`: Week 4 Blogpost +* :ghpull:`807`: Added blogpost week 3 +* :ghpull:`806`: Week 3 Blogpost +* :ghpull:`805`: GSoC: Adding Week3 Blogpost +* :ghpull:`398`: feat: added a Card2D widget to UI +* :ghpull:`800`: Week2 Blogpost +* :ghpull:`802`: Added blogpost week 2 +* :ghpull:`801`: [fix] update deprecated Test +* :ghpull:`799`: Adding Week2 BlogPost +* :ghpull:`798`: Added blogpost week 1 +* :ghpull:`768`: Overload set_visibility for Panel2D and Combobox2D +* :ghpull:`797`: Week 1 blogpost +* :ghpull:`796`: Adding Week1 Blogpost +* :ghpull:`792`: Adding week 0 blogpost +* :ghpull:`789`: Added blogpost week 0 +* :ghpull:`788`: Adding Week0 Blogpost +* :ghpull:`629`: Release preparation 0.9.0 + +Issues (75): + +* :ghissue:`810`: DTI uncertainty visualization +* :ghissue:`861`: Added/Modified docstrings for 3 actor.py functions +* :ghissue:`863`: UI Bug fixes for Horizon +* :ghissue:`866`: build(deps): bump the actions group with 6 updates +* :ghissue:`864`: Missing files for sprite test +* :ghissue:`865`: Fix ci +* :ghissue:`845`: GSoC: Final Report +* :ghissue:`847`: GSoC: Adding Final Report 23 +* :ghissue:`848`: Added Final Report +* :ghissue:`425`: WIP: Cube Axes Actor. +* :ghissue:`852`: add Code of conduct +* :ghissue:`846`: Added blogpost week 12 +* :ghissue:`844`: GSoC: Week 12 Blogpost +* :ghissue:`843`: GSoC: Adding Week 12 Blogpost +* :ghissue:`842`: GSoC: Week 11 Blogpost +* :ghissue:`397`: Card2D UI widget +* :ghissue:`839`: GSoC: Adding Week 10 Blogpost +* :ghissue:`840`: Added blogposts week 8, 9, 10, 11 +* :ghissue:`841`: GSoC: Adding Week 11 Blogpost +* :ghissue:`837`: UI: Adding Text Offset to contain text into the Background +* :ghissue:`831`: GSoC: Week 9 Blogpost +* :ghissue:`833`: GSoC: Adding Week 9 Blogpost +* :ghissue:`836`: GSoC: Week 10 Blogpost +* :ghissue:`499`: Adding `SpinBoxUI` to the `UI` module +* :ghissue:`818`: Tutorial on using ellipsoid actor to visualize tensor ellipsoids for DTI +* :ghissue:`834`: citation section added +* :ghissue:`830`: UI: Adding getters and setters for the `TextBlock2D` properties +* :ghissue:`294`: File Dialog UI component +* :ghissue:`829`: GSoC: Adding Week 8 Blogpost +* :ghissue:`828`: GSoC: Week 8 Blogpost +* :ghissue:`803`: UI: Adding Bounding Box & Fixing Alignment issue in TextBlock2D +* :ghissue:`814`: physics-simulation done +* :ghissue:`827`: Added blogpost week 4, 5, 6, 7 +* :ghissue:`822`: GSoC: Week 7 Blogpost +* :ghissue:`823`: GSoC: Adding Week 6 - 7 Blogpost +* :ghissue:`825`: [WIP] KDE Rendering API +* :ghissue:`824`: [WIP] KDE Rendering API +* :ghissue:`791`: Ellipsoid actor implemented with SDF +* :ghissue:`817`: GSoC: Adding Week 5 Blogpost +* :ghissue:`820`: Updating broken links in the Scientific Domain Section +* :ghissue:`819`: GSoC: Week 6 Blogpost +* :ghissue:`815`: Week 5 blogpost +* :ghissue:`460`: [WIP] Adding `Tree2D` to the UI sub-module +* :ghissue:`592`: Creating ScrollBar as a separate UI element +* :ghissue:`285`: Separation of Scrollbars as a standalone API. +* :ghissue:`222`: Attempt to refactor scrolling in FileMenu2D +* :ghissue:`812`: Feature/compatible software +* :ghissue:`811`: GSoC: Adding Week 4 Blogpost +* :ghissue:`809`: Week 4 Blogpost +* :ghissue:`808`: sponsors added +* :ghissue:`807`: Added blogpost week 3 +* :ghissue:`806`: Week 3 Blogpost +* :ghissue:`805`: GSoC: Adding Week3 Blogpost +* :ghissue:`402`: ImageContainer2D renders RGB .png images in black and white +* :ghissue:`398`: feat: added a Card2D widget to UI +* :ghissue:`800`: Week2 Blogpost +* :ghissue:`802`: Added blogpost week 2 +* :ghissue:`801`: [fix] update deprecated Test +* :ghissue:`799`: Adding Week2 BlogPost +* :ghissue:`794`: FURY dependencies aren't accurate in the README +* :ghissue:`790`: Fixing `TextBlock2D` justification issue +* :ghissue:`798`: Added blogpost week 1 +* :ghissue:`576`: Resolving icon flaw in comboBox2D +* :ghissue:`731`: Clicking the tab of a ComboBox2D opens dropdown without changing icon +* :ghissue:`562`: drop_down_menu icon flaw in ComboBox2D +* :ghissue:`768`: Overload set_visibility for Panel2D and Combobox2D +* :ghissue:`797`: Week 1 blogpost +* :ghissue:`796`: Adding Week1 Blogpost +* :ghissue:`792`: Adding week 0 blogpost +* :ghissue:`789`: Added blogpost week 0 +* :ghissue:`787`: Segmentation Fault while plotting (diffusion tractography) images on a non-interactive remote cluster +* :ghissue:`788`: Adding Week0 Blogpost +* :ghissue:`448`: Added the watcher class to UI +* :ghissue:`774`: WIP: Double arrow actor and a few utility functions +* :ghissue:`629`: Release preparation 0.9.0 diff --git a/v0.10.x/_sources/release_notes/releasev0.2.0.rst.txt b/v0.10.x/_sources/release_notes/releasev0.2.0.rst.txt new file mode 100644 index 000000000..4542994bf --- /dev/null +++ b/v0.10.x/_sources/release_notes/releasev0.2.0.rst.txt @@ -0,0 +1,98 @@ +.. _releasev0.2.0: + +================================== + Release notes v0.2.0 (2019-03-08) +================================== + +Quick Overview +-------------- +* Replace ``fury.window.Renderer`` by ``fury.window.Scene`` +* Add stereo support +* Add GridUI object +* Increase tests coverage and code quality + +Details +------- + +GitHub stats for 2018/11/26 - 2019/03/08 (tag: v0.1.4) + +These lists are automatically generated, and may be incomplete or contain duplicates. + +The following 5 authors contributed 186 commits. + +* David Reagan +* Eleftherios Garyfallidis +* Jon Haitz Legarreta Gorroño +* Marc-Alexandre Côté +* Serge Koudoro + + +We closed a total of 60 issues, 20 pull requests and 40 regular issues; +this is the full list (generated with the script +:file:`ext/github_tools.py`): + +Pull Requests (20): + +* :ghpull:`61`: [Fix] fetch github api from documentation +* :ghpull:`55`: Add stereo rendering support +* :ghpull:`50`: [NF] Doc version +* :ghpull:`60`: backward compatibilities +* :ghpull:`59`: [NF] Add get_info function +* :ghpull:`58`: Tests addition +* :ghpull:`57`: Add tests to utils module +* :ghpull:`52`: [Fix] add filterwarnings +* :ghpull:`56`: Increase Codacy rank +* :ghpull:`32`: The grid - add actors in a grid and interact with each one of them independently +* :ghpull:`47`: BUG: Fix `TensorSlicerActor` actor opacity property not being enforced. +* :ghpull:`48`: ENH: Exercise the `PeakSlicerActor` `opacity` explicitly. +* :ghpull:`43`: BUG: Fix `peaks_slicer` actor properties not being enforced. +* :ghpull:`44`: BUG: Fix elementwise comparison deprecation warning. +* :ghpull:`42`: [Fix] viz_surface +* :ghpull:`40`: Re-enable transparency test, change colors +* :ghpull:`39`: removing widget module +* :ghpull:`21`: Add depth_cue and fake_tube to simulate tubes with lines +* :ghpull:`30`: Add doc generation on Travis +* :ghpull:`28`: Renaming Renderer to Scene + +Issues (40): + +* :ghissue:`61`: [Fix] fetch github api from documentation +* :ghissue:`55`: Add stereo rendering support +* :ghissue:`50`: [NF] Doc version +* :ghissue:`60`: backward compatibilities +* :ghissue:`59`: [NF] Add get_info function +* :ghissue:`58`: Tests addition +* :ghissue:`8`: dipy.viz.colormap crash on single fibers +* :ghissue:`57`: Add tests to utils module +* :ghissue:`52`: [Fix] add filterwarnings +* :ghissue:`46`: Hide/Ignore numpy_vtk support warning +* :ghissue:`56`: Increase Codacy rank +* :ghissue:`32`: The grid - add actors in a grid and interact with each one of them independently +* :ghissue:`49`: Add a Codacy badge to README.rst +* :ghissue:`47`: BUG: Fix `TensorSlicerActor` actor opacity property not being enforced. +* :ghissue:`48`: ENH: Exercise the `PeakSlicerActor` `opacity` explicitly. +* :ghissue:`43`: BUG: Fix `peaks_slicer` actor properties not being enforced. +* :ghissue:`22`: Peak slicer doesn't honor linewidth parameter +* :ghissue:`37`: Fix DeprecationWarning +* :ghissue:`44`: BUG: Fix elementwise comparison deprecation warning. +* :ghissue:`45`: Change Miniconda version +* :ghissue:`42`: [Fix] viz_surface +* :ghissue:`41`: module 'fury.window' has no attribute 'Scene' +* :ghissue:`6`: VTK and Python 3 support in fvtk +* :ghissue:`40`: Re-enable transparency test, change colors +* :ghissue:`2`: Dipy visualization (fvtk) crash when saving series of images +* :ghissue:`4`: fvtk contour function ignores voxsz parameter +* :ghissue:`1`: fvtk.label won't show up if called twice +* :ghissue:`39`: removing widget module +* :ghissue:`21`: Add depth_cue and fake_tube to simulate tubes with lines +* :ghissue:`3`: Dipy visualization with missing (?) affine parameter +* :ghissue:`5`: How to resolve python-vtk6 link issues in Ubuntu +* :ghissue:`29`: Added surface function +* :ghissue:`30`: Add doc generation on Travis +* :ghissue:`23`: DOC: sphinx_gallery master branch is required +* :ghissue:`28`: Renaming Renderer to Scene +* :ghissue:`26`: Rename Renderer to Scene +* :ghissue:`24`: VTK dependency on installation +* :ghissue:`11`: Reorienting peak_slicer and ODF_slicer +* :ghissue:`14`: dipy test failed on mac osx sierra with ananoda python. +* :ghissue:`17`: dipy test failed on mac osx sierra with ananoda python. diff --git a/v0.10.x/_sources/release_notes/releasev0.3.0.rst.txt b/v0.10.x/_sources/release_notes/releasev0.3.0.rst.txt new file mode 100644 index 000000000..f9bc69c4e --- /dev/null +++ b/v0.10.x/_sources/release_notes/releasev0.3.0.rst.txt @@ -0,0 +1,79 @@ +.. _releasev0.3.0: + +========================================= + Release notes v0.3.0 (2019-08-02) +========================================= + +Quick Overview +-------------- +* Add cone actor and update odf actor +* Add Appveyor CI and update MacOS CI +* Update Documentation, examples and tutorials +* Increase tests coverage and code quality + +Details +------- + +GitHub stats for 2019/03/08 - 2019/08/02 (tag: v0.2.0) + +These lists are automatically generated, and may be incomplete or contain duplicates. + +The following 7 authors contributed 164 commits. + +* Ariel Rokem +* Eleftherios Garyfallidis +* Guillaume Favelier +* Kevin Sitek +* Prashil +* Scott Trinkle +* Serge Koudoro + + +We closed a total of 39 issues, 15 pull requests and 24 regular issues; +this is the full list (generated with the script +:file:`tools/github_stats.py`): + +Pull Requests (15): + +* :ghpull:`91`: [Doc] add installation instruction +* :ghpull:`53`: [Fix] resolution limit +* :ghpull:`89`: [Fix] cmap when not have matplotlib +* :ghpull:`88`: Updates and corrections in slicer and ui +* :ghpull:`69`: Add middle button callback +* :ghpull:`86`: Fixes a typo in the viz_ui tutorial. +* :ghpull:`83`: Remove issue template +* :ghpull:`87`: TEST: updated order transparency issue for vtk 8.2.0 +* :ghpull:`80`: Add cones as glyphs +* :ghpull:`73`: Add appveyor +* :ghpull:`72`: Update OSX bots on Travis +* :ghpull:`68`: Allow Str for Grid Caption +* :ghpull:`67`: [Fix] Update doc management +* :ghpull:`62`: Directional color odfs +* :ghpull:`31`: new surface function + +Issues (24): + +* :ghissue:`91`: [Doc] add installation instruction +* :ghissue:`36`: Tests Documentation +* :ghissue:`53`: [Fix] resolution limit +* :ghissue:`13`: window.record() resolution limit +* :ghissue:`89`: [Fix] cmap when not have matplotlib +* :ghissue:`90`: [Fix] dtype problem for x64 machine +* :ghissue:`88`: Updates and corrections in slicer and ui +* :ghissue:`69`: Add middle button callback +* :ghissue:`86`: Fixes a typo in the viz_ui tutorial. +* :ghissue:`84`: Test_order_transparent failed with VTK 8.2.0 +* :ghissue:`83`: Remove issue template +* :ghissue:`87`: TEST: updated order transparency issue for vtk 8.2.0 +* :ghissue:`85`: Save from active window? +* :ghissue:`79`: add link to fury example gallery in sphinx-gallery readme +* :ghissue:`80`: Add cones as glyphs +* :ghissue:`73`: Add appveyor +* :ghissue:`72`: Update OSX bots on Travis +* :ghissue:`18`: Improve unit tests +* :ghissue:`63`: Improve doc generation +* :ghissue:`68`: Allow Str for Grid Caption +* :ghissue:`67`: [Fix] Update doc management +* :ghissue:`62`: Directional color odfs +* :ghissue:`65`: Directed Arrows +* :ghissue:`31`: new surface function diff --git a/v0.10.x/_sources/release_notes/releasev0.4.0.rst.txt b/v0.10.x/_sources/release_notes/releasev0.4.0.rst.txt new file mode 100644 index 000000000..ca1717bce --- /dev/null +++ b/v0.10.x/_sources/release_notes/releasev0.4.0.rst.txt @@ -0,0 +1,72 @@ +.. _releasev0.4.0: + +========================================= + Release notes v0.4.0 (2019-10-29) +========================================= + +Quick Overview +-------------- + +* Enable Anti aliasing and frame rate features +* Add multiples actors (arrow, box, ...) +* Glyph extensions +* Remove Nose dependency +* Replace Appveyor by Azure pipeline for Windows +* Update Documentation, examples and tutorials +* Increase tests coverage and code quality + +Details +------- +GitHub stats for 2019/08/02 - 2019/10/29 (tag: v0.3.0) + +These lists are automatically generated, and may be incomplete or contain duplicates. + +The following 4 authors contributed 169 commits. + +* Eleftherios Garyfallidis +* Etienne St-Onge +* Javier Guaje +* Serge Koudoro + + +We closed a total of 32 issues, 15 pull requests and 17 regular issues; +this is the full list (generated with the script +:file:`tools/github_stats.py`): + +Pull Requests (15): + +* :ghpull:`109`: Show frame rate and enable anti-aliasing +* :ghpull:`112`: Use glyph for several actors +* :ghpull:`110`: Experimental work +* :ghpull:`107`: Increase coverage for test_actors +* :ghpull:`106`: [Fix] doc generation +* :ghpull:`104`: Made it simpler to change color in ListBox +* :ghpull:`105`: Replacing appveyor by Azure +* :ghpull:`103`: Remove nose dependency +* :ghpull:`101`: Update travis +* :ghpull:`102`: from assert to npt_assert_equal +* :ghpull:`98`: [Fix] layout with small cells +* :ghpull:`97`: Bug fix for double slider +* :ghpull:`100`: fix snapshot when size is not square +* :ghpull:`92`: [Fix] update travis to manage pip +* :ghpull:`94`: [miniconda] move to https + +Issues (17): + +* :ghissue:`109`: Show frame rate and enable anti-aliasing +* :ghissue:`112`: Use glyph for several actors +* :ghissue:`66`: Directed Arrows +* :ghissue:`110`: Experimental work +* :ghissue:`107`: Increase coverage for test_actors +* :ghissue:`106`: [Fix] doc generation +* :ghissue:`104`: Made it simpler to change color in ListBox +* :ghissue:`105`: Replacing appveyor by Azure +* :ghissue:`103`: Remove nose dependency +* :ghissue:`101`: Update travis +* :ghissue:`102`: from assert to npt_assert_equal +* :ghissue:`98`: [Fix] layout with small cells +* :ghissue:`97`: Bug fix for double slider +* :ghissue:`96`: Double slider handles not at right position when window starts +* :ghissue:`100`: fix snapshot when size is not square +* :ghissue:`92`: [Fix] update travis to manage pip +* :ghissue:`94`: [miniconda] move to https diff --git a/v0.10.x/_sources/release_notes/releasev0.5.1.rst.txt b/v0.10.x/_sources/release_notes/releasev0.5.1.rst.txt new file mode 100644 index 000000000..008692bad --- /dev/null +++ b/v0.10.x/_sources/release_notes/releasev0.5.1.rst.txt @@ -0,0 +1,210 @@ +.. _releasev0.5.1: + +========================================= + Release notes v0.5.1 (2020-04-01) +========================================= + +Quick Overview +-------------- + +* Remove python 2 compatibility +* Added texture management +* Added multiples primitives. +* Added multiples actors (contour_from_label, billboard...) +* Huge improvement of multiple UI (RangeSlider, ...) +* Improved security (from md5 to sha256) +* Large documentation update, examples and tutorials +* Increased tests coverage and code quality + +Details +------- +GitHub stats for 2019/10/29 - 2020/04/02 (tag: v0.4.0) + +These lists are automatically generated, and may be incomplete or contain duplicates. + +The following 20 authors contributed 407 commits. + +* ChenCheng0630 +* Devanshu Modi +* Eleftherios Garyfallidis +* Etienne St-Onge +* Filipi Nascimento Silva +* Gottipati Gautam +* Javier Guaje +* Jon Haitz Legarreta Gorroño +* Liam Donohue +* Marc-Alexandre Côté +* Marssis +* Naman Bansal +* Nasim +* Saransh Jain +* Serge Koudoro +* Shreyas Bhujbal +* Soham Biswas +* Vivek Choudhary +* ibrahimAnis +* lenixlobo + + +We closed a total of 153 issues, 49 pull requests and 104 regular issues; +this is the full list (generated with the script +:file:`tools/github_stats.py`): + +Pull Requests (49): + +* :ghpull:`227`: [Fix] update streamlines default color +* :ghpull:`210`: Added contour_from_label method +* :ghpull:`225`: update tutorial folder structure +* :ghpull:`223`: [Fix] sphere winding issue +* :ghpull:`218`: Changed options attribute from list to dict and updated respective tests +* :ghpull:`220`: bumping scipy version to 1.2.0 +* :ghpull:`213`: Utils vtk +* :ghpull:`215`: Remove more than one actors at once +* :ghpull:`207`: updated fetcher +* :ghpull:`206`: [FIX] avoid in-place replacements +* :ghpull:`203`: Namanb009 windowtitlefix +* :ghpull:`204`: Vertical Layout for RangeSlider +* :ghpull:`190`: Add initial state to checkbox +* :ghpull:`201`: [FIX] icons flipping +* :ghpull:`181`: Vertical Layout for LineDoubleSlider2D +* :ghpull:`198`: Utils test and winding order algorithm +* :ghpull:`192`: Tetrahedron, Icosahedron primitives +* :ghpull:`189`: Added dynamic text positioning +* :ghpull:`194`: [FIX] Update superquadrics test +* :ghpull:`182`: [Doc] Reshape the documentation +* :ghpull:`177`: [Fix] Flipping during save +* :ghpull:`191`: DOC: Fix `actor.line` parameter type and add `optional` keyword +* :ghpull:`173`: Fixing Text Overflow of ListBox2D +* :ghpull:`167`: Animated Network Visualization Example +* :ghpull:`165`: Vertical Layout for LineSlider2D +* :ghpull:`154`: Added Shader tutorial +* :ghpull:`153`: Sep viz ui +* :ghpull:`132`: Add Billboard actor +* :ghpull:`164`: Documentation +* :ghpull:`163`: Spelling error +* :ghpull:`157`: Corrected Disk2D comments +* :ghpull:`148`: Replace md5 by sha 256 +* :ghpull:`145`: DOC: Fix `io:load_image` and `io:save_image` docstrings +* :ghpull:`144`: STYLE: Change examples `README` file extension to reStructuredText +* :ghpull:`143`: STYLE: Improve the requirements' files' style. +* :ghpull:`139`: [Fix] some docstring for doc generation +* :ghpull:`140`: [DOC] Add demo for showing an network +* :ghpull:`136`: Started new tutorial about using normals to make spiky spheres +* :ghpull:`134`: Add event parameter on add_window_callback method in ShowManager class. +* :ghpull:`129`: update loading and saving IO for polydata +* :ghpull:`131`: Add Superquadric primitives and actors +* :ghpull:`130`: Adding Sphere primitives +* :ghpull:`128`: Update Deprecated function +* :ghpull:`126`: Add basic primitives +* :ghpull:`125`: Add Deprecated decorator +* :ghpull:`124`: Texture utilities and actors +* :ghpull:`118`: Remove python2 compatibility +* :ghpull:`120`: Replace pickle with JSON for "events_counts" dict serialization +* :ghpull:`115`: Release 0.4.0 preparation + +Issues (104): + +* :ghissue:`150`: Re-compute Bounds in Slicer +* :ghissue:`227`: [Fix] update streamlines default color +* :ghissue:`135`: Backward compatibilities problem with streamtube +* :ghissue:`77`: contour_from_label +* :ghissue:`210`: Added contour_from_label method +* :ghissue:`225`: update tutorial folder structure +* :ghissue:`223`: [Fix] sphere winding issue +* :ghissue:`137`: Issues with provided spheres +* :ghissue:`152`: Improve checkbox options cases +* :ghissue:`218`: Changed options attribute from list to dict and updated respective tests +* :ghissue:`76`: Improve Checkbox options access +* :ghissue:`219`: Issue occur when I Start testing the project +* :ghissue:`220`: bumping scipy version to 1.2.0 +* :ghissue:`217`: Transformed options attribute from list to dict and updated respective tests +* :ghissue:`213`: Utils vtk +* :ghissue:`179`: Utility functions are needed for getting numpy arrays from actors +* :ghissue:`212`: Namanb009 issue 133 fix +* :ghissue:`214`: Namanb009 Remove multiple actors +* :ghissue:`215`: Remove more than one actors at once +* :ghissue:`211`: Namanb009 hexadecimal color support +* :ghissue:`187`: New utility functions are added in utils.py and tests are added in te… +* :ghissue:`209`: Namanb009 viz_ui.py does not show render window when run +* :ghissue:`207`: updated fetcher +* :ghissue:`206`: [FIX] avoid in-place replacements +* :ghissue:`203`: Namanb009 windowtitlefix +* :ghissue:`202`: Window Title name does not change +* :ghissue:`204`: Vertical Layout for RangeSlider +* :ghissue:`190`: Add initial state to checkbox +* :ghissue:`75`: Improve Checkbox initialisation +* :ghissue:`201`: [FIX] icons flipping +* :ghissue:`199`: Loading of Inverted icons using read_viz_icons +* :ghissue:`181`: Vertical Layout for LineDoubleSlider2D +* :ghissue:`175`: LineDoubleSlider2D vertical layout +* :ghissue:`198`: Utils test and winding order algorithm +* :ghissue:`192`: Tetrahedron, Icosahedron primitives +* :ghissue:`189`: Added dynamic text positioning +* :ghissue:`176`: Allowing to change text position on Sliders +* :ghissue:`185`: NF: winding order in utils +* :ghissue:`170`: NF: adding primitive stars, 3D stars, rhombi. +* :ghissue:`195`: Added dynamic text position on sliders +* :ghissue:`194`: [FIX] Update superquadrics test +* :ghissue:`171`: bug-in-image 0.1 +* :ghissue:`182`: [Doc] Reshape the documentation +* :ghissue:`156`: Test Case File Updated +* :ghissue:`155`: There are libraries we have to install not mentioned in the requirement.txt file to run the test case. +* :ghissue:`122`: Documentation not being rendered correctly +* :ghissue:`177`: [Fix] Flipping during save +* :ghissue:`160`: Saved Images are vertically Inverted +* :ghissue:`193`: Merge pull request #2 from fury-gl/master +* :ghissue:`191`: DOC: Fix `actor.line` parameter type and add `optional` keyword +* :ghissue:`178`: changed text position +* :ghissue:`188`: Added dynamic text positioning +* :ghissue:`173`: Fixing Text Overflow of ListBox2D +* :ghissue:`15`: viz.ui.ListBoxItem2D text overflow +* :ghissue:`166`: Build Native File Dialogs +* :ghissue:`180`: Native File Dialog Text Overflow Issue +* :ghissue:`186`: add name +* :ghissue:`184`: Added winding order algorithm to utils +* :ghissue:`183`: Added star2D and 3D, rhombicuboctahedron to tests_primitive +* :ghissue:`54`: generating directed arrows +* :ghissue:`174`: List box text overflow +* :ghissue:`167`: Animated Network Visualization Example +* :ghissue:`165`: Vertical Layout for LineSlider2D +* :ghissue:`108`: Slider vertical layout +* :ghissue:`172`: window.show() is giving Attribute error. +* :ghissue:`154`: Added Shader tutorial +* :ghissue:`151`: Prim shapes +* :ghissue:`162`: Winding order 2 +* :ghissue:`168`: Prim test +* :ghissue:`158`: nose is missing +* :ghissue:`71`: viz_ui.py example needs expansion +* :ghissue:`153`: Sep viz ui +* :ghissue:`132`: Add Billboard actor +* :ghissue:`164`: Documentation +* :ghissue:`163`: Spelling error +* :ghissue:`161`: Merge pull request #1 from fury-gl/master +* :ghissue:`157`: Corrected Disk2D comments +* :ghissue:`121`: Replace md5 by sha2 or sha3 for security issue +* :ghissue:`148`: Replace md5 by sha 256 +* :ghissue:`147`: update md5 to sha256 +* :ghissue:`146`: Shapes +* :ghissue:`145`: DOC: Fix `io:load_image` and `io:save_image` docstrings +* :ghissue:`144`: STYLE: Change examples `README` file extension to reStructuredText +* :ghissue:`142`: STYLE: Change examples `README` file extension to markdown +* :ghissue:`143`: STYLE: Improve the requirements' files' style. +* :ghissue:`139`: [Fix] some docstring for doc generation +* :ghissue:`140`: [DOC] Add demo for showing an network +* :ghissue:`136`: Started new tutorial about using normals to make spiky spheres +* :ghissue:`134`: Add event parameter on add_window_callback method in ShowManager class. +* :ghissue:`81`: Add superquadric function in actor.py +* :ghissue:`129`: update loading and saving IO for polydata +* :ghissue:`131`: Add Superquadric primitives and actors +* :ghissue:`130`: Adding Sphere primitives +* :ghissue:`128`: Update Deprecated function +* :ghissue:`126`: Add basic primitives +* :ghissue:`125`: Add Deprecated decorator +* :ghissue:`124`: Texture utilities and actors +* :ghissue:`99`: [WIP] Adding util to get Numpy 3D array of RGBA values +* :ghissue:`118`: Remove python2 compatibility +* :ghissue:`117`: Remove compatibility with python 2 +* :ghissue:`123`: WIP: Texture support +* :ghissue:`119`: Improve data Serialization +* :ghissue:`120`: Replace pickle with JSON for "events_counts" dict serialization +* :ghissue:`115`: Release 0.4.0 preparation diff --git a/v0.10.x/_sources/release_notes/releasev0.6.0.rst.txt b/v0.10.x/_sources/release_notes/releasev0.6.0.rst.txt new file mode 100644 index 000000000..8622cbfa0 --- /dev/null +++ b/v0.10.x/_sources/release_notes/releasev0.6.0.rst.txt @@ -0,0 +1,108 @@ +.. _releasev0.6.0: + +========================================= + Release notes v0.6.0 (2020-07-20) +========================================= + +Quick Overview +-------------- + +* Added new features: Picking and double-click callback. +* Added Signed Distance Field actor. +* Added a new UI ComboBox. +* Added multiples primitives (Rhombocuboctahedron, ...). +* Huge improvement of multiple UIs and actors. +* Fixed Compatibility with VTK9. +* Large documentation update, examples and tutorials (5 new). +* Added a blog system. +* Increased tests coverage and code quality. + +Details +------- + +GitHub stats for 2020/04/09 - 2020/07/20 (tag: v0.5.1) + +These lists are automatically generated, and may be incomplete or contain duplicates. + +The following 9 authors contributed 266 commits. + +* Eleftherios Garyfallidis +* Liam Donohue +* Marc-Alexandre Côté +* Melina Raglin +* Naman Bansal +* Serge Koudoro +* Soham Biswas +* Tushar +* Lenix Lobo + + +We closed a total of 60 issues, 25 pull requests and 35 regular issues; +this is the full list (generated with the script +:file:`tools/github_stats.py`): + +Pull Requests (25): + +* :ghpull:`241`: Adding a Blog system to fury +* :ghpull:`268`: Clip Text Overflow +* :ghpull:`267`: SDF tutorial +* :ghpull:`250`: SDF based FURY actors +* :ghpull:`246`: ComboBox UI tutorial +* :ghpull:`265`: Adding new Earth coordinates tutorial +* :ghpull:`240`: ComboBox2D UI element +* :ghpull:`169`: Use primitive for box, cube, square, rectangle actors +* :ghpull:`262`: Solar System Tutorial +* :ghpull:`248`: Setting Bounding Box for TextBlock2D +* :ghpull:`263`: [NF] Deprecated parameters +* :ghpull:`127`: [CI] add Python 3.8 +* :ghpull:`255`: Let VTK delete timers on exit. +* :ghpull:`233`: Picking API and picking tutorial +* :ghpull:`261`: Adding Earth Animation Tutorial +* :ghpull:`249`: Octagonal Prism and Frustum Square Pyramid +* :ghpull:`258`: Updating test of order_transparency for compatibility with vtk 9 +* :ghpull:`259`: Updated Step 3 in README.rst +* :ghpull:`231`: Adding Double Click Callback +* :ghpull:`256`: Install ssl certificate for azure pipeline windows +* :ghpull:`245`: [FIX] Compatibility with VTK 9 +* :ghpull:`244`: Added new texture tutorial +* :ghpull:`235`: Function to use Hexadecimal color code in Colormap +* :ghpull:`238`: Added Rhombocuboctahedron, 2D and 3D star to primitive +* :ghpull:`237`: update copyright years + +Issues (35): + +* :ghissue:`241`: Adding a Blog system to fury +* :ghissue:`268`: Clip Text Overflow +* :ghissue:`264`: Re-implementation of Text Overflow in ListBox2D +* :ghissue:`267`: SDF tutorial +* :ghissue:`247`: PR idea: create SDF alternatives to FURY primitive actors +* :ghissue:`250`: SDF based FURY actors +* :ghissue:`246`: ComboBox UI tutorial +* :ghissue:`265`: Adding new Earth coordinates tutorial +* :ghissue:`240`: ComboBox2D UI element +* :ghissue:`169`: Use primitive for box, cube, square, rectangle actors +* :ghissue:`138`: Box, cone etc. to work similarly to superquadric +* :ghissue:`262`: Solar System Tutorial +* :ghissue:`248`: Setting Bounding Box for TextBlock2D +* :ghissue:`263`: [NF] Deprecated parameters +* :ghissue:`127`: [CI] add Python 3.8 +* :ghissue:`51`: Improvements from VTK 8.2.0? +* :ghissue:`255`: Let VTK delete timers on exit. +* :ghissue:`253`: Programs with timers hang on exit. [VTK9] [Linux] +* :ghissue:`233`: Picking API and picking tutorial +* :ghissue:`261`: Adding Earth Animation Tutorial +* :ghissue:`249`: Octagonal Prism and Frustum Square Pyramid +* :ghissue:`258`: Updating test of order_transparency for compatibility with vtk 9 +* :ghissue:`254`: unexpected order transparent behavior [VTK9] [Ubuntu 18.04] +* :ghissue:`259`: Updated Step 3 in README.rst +* :ghissue:`251`: Developer installation instructions should describe -e option +* :ghissue:`226`: Adding double-click event +* :ghissue:`231`: Adding double-click Callback +* :ghissue:`256`: Install ssl certificate for azure pipeline windows +* :ghissue:`245`: [FIX] Compatibility with VTK 9 +* :ghissue:`244`: Added new texture tutorial +* :ghissue:`235`: Function to use Hexadecimal color code in Colormap +* :ghissue:`238`: Added Rhombocuboctahedron, 2D and 3D star to primitive +* :ghissue:`197`: Added Rhombocuboctahedron, 2D and 3D star to primitive +* :ghissue:`237`: update copyright years +* :ghissue:`216`: Utiltiy function to use Hexadecimal color code diff --git a/v0.10.x/_sources/release_notes/releasev0.6.1.rst.txt b/v0.10.x/_sources/release_notes/releasev0.6.1.rst.txt new file mode 100644 index 000000000..e5889fd85 --- /dev/null +++ b/v0.10.x/_sources/release_notes/releasev0.6.1.rst.txt @@ -0,0 +1,86 @@ +.. _releasev0.6.1: + +=================================== + Release notes v0.6.1 (2020-08-20) +=================================== + +Quick Overview +-------------- + +* Added Shaders Manager. +* Standardized colors across API. +* Added a new UI Tab. +* Added Physics Engine Tutorial. +* Large documentation update, examples and tutorials (4 new). +* Increased tests coverage and code quality. + +Details +------- + +GitHub stats for 2020/07/21 - 2020/08/20 (tag: v0.6.0) + +These lists are automatically generated, and may be incomplete or contain duplicates. + +The following 8 authors contributed 164 commits. + +* Eleftherios Garyfallidis +* Javier Guaje +* Lenix Lobo +* Melina Raglin +* Nasim Anousheh +* Serge Koudoro +* Soham Biswas +* Vivek Choudhary + + +We closed a total of 42 issues, 15 pull requests and 27 regular issues; +this is the full list (generated with the script +:file:`tools/github_stats.py`): + +Pull Requests (15): + +* :ghpull:`288`: Shader manager +* :ghpull:`292`: Disable VTK Warnings on release version +* :ghpull:`289`: Rename parameter scale to scales +* :ghpull:`287`: Add Physics simulation examples. +* :ghpull:`284`: Colliding particles in the box +* :ghpull:`275`: Tab UI tutorial +* :ghpull:`208`: Added tutorial for RadioButton and CheckBox UI +* :ghpull:`281`: Radio checkbox tutorial using Fury API +* :ghpull:`283`: Standardize colors across API +* :ghpull:`282`: Standardize Colors array name +* :ghpull:`252`: Tab ui +* :ghpull:`279`: Decreasing the size of the sun in solarsystem tutorial +* :ghpull:`273`: Python GSoC Weekly blogs +* :ghpull:`276`: Update Deprecated test +* :ghpull:`272`: Python GSoC Blogs upto 19th July 2020 + +Issues (27): + +* :ghissue:`260`: Changes to shader API in VTK 9 +* :ghissue:`116`: Update Shader system +* :ghissue:`288`: Shader manager +* :ghissue:`292`: Disable VTK Warnings on release version +* :ghissue:`270`: Disable VTK Warnings on release version +* :ghissue:`289`: Rename parameter scale to scales +* :ghissue:`236`: Pybullet examples +* :ghissue:`287`: Add Physics simulation examples. +* :ghissue:`205`: Create a tutorial for checkbox/radiobutton UI +* :ghissue:`284`: Colliding particles in the box +* :ghissue:`275`: Tab UI tutorial +* :ghissue:`208`: Added tutorial for RadioButton and CheckBox UI +* :ghissue:`281`: Radio checkbox tutorial using Fury API +* :ghissue:`283`: Standardize colors across API +* :ghissue:`269`: Fixed bug in tutorial with accessing colors for latest release +* :ghissue:`242`: Standardize colors across API +* :ghissue:`243`: Single Color in Primitive Does Not Work +* :ghissue:`271`: Some issues with actor.box after release 0.6.0 +* :ghissue:`282`: Standardize Colors array name +* :ghissue:`280`: Unable to extract colors from a Box +* :ghissue:`252`: Tab ui +* :ghissue:`279`: Decreasing the size of the sun in solarsystem tutorial +* :ghissue:`278`: Changing Size of Sun in viz_solar_system.py Tutorial +* :ghissue:`273`: Python GSoC Weekly blogs +* :ghissue:`277`: Sun +* :ghissue:`276`: Update Deprecated test +* :ghissue:`272`: Python GSoC Blogs upto 19th July 2020 diff --git a/v0.10.x/_sources/release_notes/releasev0.7.0.rst.txt b/v0.10.x/_sources/release_notes/releasev0.7.0.rst.txt new file mode 100644 index 000000000..aea083f81 --- /dev/null +++ b/v0.10.x/_sources/release_notes/releasev0.7.0.rst.txt @@ -0,0 +1,151 @@ +.. _releasev0.7.0: + +=================================== + Release notes v0.7.0 (2021/03/13) +=================================== + +Quick Overview +-------------- + +* New SDF actors added. +* Materials module added. +* ODF slicer actor performance improved. +* New primitive (Cylinder) added. +* Compatibility with VTK 9 added. +* Five new demos added. +* Large Documentation Update. +* Migration from Travis to Github Action. + + +Details +------- + +GitHub stats for 2020/08/20 - 2021/03/13 (tag: v0.6.1) + +These lists are automatically generated, and may be incomplete or contain duplicates. + +The following 14 authors contributed 195 commits. + +* Eleftherios Garyfallidis +* Serge Koudoro +* Charles Poirier +* Javier Guaje +* Soham Biswas +* Sajag Swami +* Lenix Lobo +* Pietro Astolfi +* Sanjay Marreddi +* Tushar +* ganimtron-10 +* haran2001 +* Aju100 +* Aman Soni + + +We closed a total of 98 issues, 37 pull requests and 61 regular issues; +this is the full list (generated with the script +:file:`tools/github_stats.py`): + +Pull Requests (37): + +* :ghpull:`388`: added simulation for brownian motion +* :ghpull:`389`: ENH: peaks_slicer option for asymmetric peaks visualization +* :ghpull:`370`: Materials module including Physically Based Rendering (PBR) +* :ghpull:`385`: fixed the example for superquadric function +* :ghpull:`387`: [fix] Propagate update_actor +* :ghpull:`382`: Added an sdf for rendering a Capsule actor +* :ghpull:`383`: Minor documentation fix +* :ghpull:`376`: Added animations for some electromagnetic phenomena +* :ghpull:`374`: ENH: Refactor actor.odf_slicer for increased performances +* :ghpull:`373`: Updated actor.py +* :ghpull:`368`: Solving The Minor Documentation Error +* :ghpull:`343`: Adding physics engine integration docs +* :ghpull:`353`: fix: Minor docs changes +* :ghpull:`346`: Fix the sdf bug by checking the arguments passed +* :ghpull:`351`: Opacity bug fix for point and sphere actors +* :ghpull:`350`: modelsuzanne to suzanne +* :ghpull:`348`: Added center forwarding in billboard shaders. +* :ghpull:`341`: Add Option to generate the documentation without examples +* :ghpull:`342`: From Travis to Github Actions +* :ghpull:`339`: Update Readme information +* :ghpull:`340`: Pass OAuth token through header +* :ghpull:`337`: Add support for clipping side in clip_overflow_text +* :ghpull:`336`: Update UI tutorials. +* :ghpull:`334`: Added Domino-Simulation-file for Review +* :ghpull:`332`: Fixing UI warnings +* :ghpull:`328`: Added cylinder primitive +* :ghpull:`329`: [FIX] Force LUT to be RGB +* :ghpull:`286`: GSoC blogs for Third Evaluation. +* :ghpull:`319`: fixed discord icon bug in documentation +* :ghpull:`311`: Remove python35 from Travis +* :ghpull:`307`: Fixed translating and scaling issues on billboard and SDF actors +* :ghpull:`304`: Blogs for the final review +* :ghpull:`306`: merged basic UI and advanced UI tutorials into one +* :ghpull:`302`: moved physics tutorials to examples under the heading 'Integrate physics using pybullet' +* :ghpull:`303`: FIX vtp reader +* :ghpull:`300`: BF: Out should be varying and alpha is not passed to shader +* :ghpull:`295`: Update fetcher + +Issues (61): + +* :ghissue:`388`: added simulation for brownian motion +* :ghissue:`389`: ENH: peaks_slicer option for asymmetric peaks visualization +* :ghissue:`370`: Materials module including Physically Based Rendering (PBR) +* :ghissue:`385`: fixed the example for superquadric function +* :ghissue:`387`: [fix] Propagate update_actor +* :ghissue:`382`: Added an sdf for rendering a Capsule actor +* :ghissue:`383`: Minor documentation fix +* :ghissue:`376`: Added animations for some electromagnetic phenomena +* :ghissue:`374`: ENH: Refactor actor.odf_slicer for increased performances +* :ghissue:`364`: New Animated Network Demo/Example +* :ghissue:`379`: Merge pull request #2 from fury-gl/master +* :ghissue:`361`: Closes #352 +* :ghissue:`373`: Updated actor.py +* :ghissue:`372`: Ellipsoid primitive needs to be added in the comment section of sdf actor. +* :ghissue:`369`: Added Special Character Support +* :ghissue:`363`: Minor error in documentation of create_colormap function +* :ghissue:`368`: Solving The Minor Documentation Error +* :ghissue:`366`: added special character support for TextBox2D +* :ghissue:`357`: Patches: vulnerable code that can lead to RCE +* :ghissue:`359`: unwanted objects rendering randomly +* :ghissue:`343`: Adding physics engine integration docs +* :ghissue:`312`: Adding Physics Integration Docs to FURY's Website +* :ghissue:`353`: fix: Minor docs changes +* :ghissue:`346`: Fix the sdf bug by checking the arguments passed +* :ghissue:`310`: Rendering bug in SDF actor when not all primitives are defined +* :ghissue:`351`: Opacity bug fix for point and sphere actors +* :ghissue:`335`: _opacity argument for point doesn't seem to work +* :ghissue:`345`: Fixes the opacity bug for sphere and point actors (unit tests are included) +* :ghissue:`350`: modelsuzanne to suzanne +* :ghissue:`348`: Added center forwarding in billboard shaders. +* :ghissue:`341`: Add Option to generate the documentation without examples +* :ghissue:`342`: From Travis to Github Actions +* :ghissue:`338`: From travis (pricing model changed) to github Actions ? +* :ghissue:`339`: Update Readme information +* :ghissue:`340`: Pass OAuth token through header +* :ghissue:`315`: Deprecation notice for authentication via URL query parameters +* :ghissue:`337`: Add support for clipping side in clip_overflow_text +* :ghissue:`308`: Clipping overflowing text from the left. +* :ghissue:`336`: Update UI tutorials. +* :ghissue:`334`: Added Domino-Simulation-file for Review +* :ghissue:`309`: Domino Physics Simulation +* :ghissue:`333`: Unable to set up the project locally for python 32bit system +* :ghissue:`332`: Fixing UI warnings +* :ghissue:`239`: Superquadric Slicer +* :ghissue:`328`: Added cylinder primitive +* :ghissue:`318`: Cylinder primitive generation +* :ghissue:`329`: [FIX] Force LUT to be RGB +* :ghissue:`286`: GSoC blogs for Third Evaluation. +* :ghissue:`319`: fixed discord icon bug in documentation +* :ghissue:`313`: Discord icon should appear in doc too +* :ghissue:`311`: Remove python35 from Travis +* :ghissue:`307`: Fixed translating and scaling issues on billboard and SDF actors +* :ghissue:`274`: SDF rendering bug for low scale values +* :ghissue:`304`: Blogs for the final review +* :ghissue:`306`: merged basic UI and advanced UI tutorials into one +* :ghissue:`297`: Update Demos/tutorial +* :ghissue:`302`: moved physics tutorials to examples under the heading 'Integrate physics using pybullet' +* :ghissue:`298`: Wrecking Ball Simulation +* :ghissue:`303`: FIX vtp reader +* :ghissue:`300`: BF: Out should be varying and alpha is not passed to shader +* :ghissue:`295`: Update fetcher diff --git a/v0.10.x/_sources/release_notes/releasev0.7.1.rst.txt b/v0.10.x/_sources/release_notes/releasev0.7.1.rst.txt new file mode 100644 index 000000000..95b997e07 --- /dev/null +++ b/v0.10.x/_sources/release_notes/releasev0.7.1.rst.txt @@ -0,0 +1,142 @@ +.. _releasev0.7.1: + +================================== + Release notes v0.7.1 (2021/08/03) +================================== + +Quick Overview +-------------- + +* FURY paper added. +* Fast selection of multiple objects added. +* UI refactored. +* Tests coverage increased. +* New actor (Marker) added. +* New primitive (Triangular Prism) added. +* Demos added and updated. +* Large Documentation Update. + + +Details +------- + +GitHub stats for 2021/03/13 - 2021/08/03 (tag: v0.7.0) + +These lists are automatically generated, and may be incomplete or contain duplicates. + +The following 15 authors contributed 211 commits. + +* Amit Chaudhari +* Antriksh Misri +* Bruno Messias +* Daniel S. Katz +* Eleftherios Garyfallidis +* Gurdit Siyan +* Javier Guaje +* Jhalak Gupta +* LoopThrough-i-j +* MIHIR +* Praneeth Shetty +* Sajag Swami +* Serge Koudoro +* Hariharan Ayappane + + +We closed a total of 89 issues, 35 pull requests and 54 regular issues; +this is the full list (generated with the script +:file:`tools/github_stats.py`): + +Pull Requests (35): + +* :ghpull:`475`: Gsoc blog 2021 +* :ghpull:`476`: Google Summer of Code blog posts +* :ghpull:`477`: added blog posts for GSoC'21 +* :ghpull:`442`: added method to wrap overflowing text +* :ghpull:`441`: Added border support in Panel2D +* :ghpull:`466`: two more small bib changes +* :ghpull:`464`: Paper Dan's Comments +* :ghpull:`459`: extracted Button2D class from `elements` to `core` +* :ghpull:`430`: Surface actor colormap fix +* :ghpull:`456`: Updated about documentation +* :ghpull:`455`: Fixed bibtex +* :ghpull:`454`: Added missing DOIs and URLs +* :ghpull:`451`: Typo fix +* :ghpull:`447`: UI refactoring +* :ghpull:`438`: Fast selection of multiple objects in 3D using GPU acceleration +* :ghpull:`420`: added an example about graph-tool and nested stochastic block model +* :ghpull:`422`: This allow to draw markers using shaders +* :ghpull:`444`: Remove deprecated functions +* :ghpull:`440`: added support for URL image in ImageContainer2D +* :ghpull:`356`: Render a video on an actor. +* :ghpull:`436`: [Fix] Update Azure pipeline for windows +* :ghpull:`434`: WIP: added tests for layout module +* :ghpull:`426`: Allows to define the priority of a shader_callback and obtain the vtkEventId +* :ghpull:`394`: Fixed warnings in test_utils.py +* :ghpull:`415`: update sk orcid +* :ghpull:`413`: add nanohub doi +* :ghpull:`412`: fix paper doi +* :ghpull:`386`: FURY paper for Journal of Open Source Software (JOSS) +* :ghpull:`371`: Textbox2d special character support +* :ghpull:`408`: Updating the Missing Parenthesis +* :ghpull:`406`: Removed unused library in FURY tutorial +* :ghpull:`405`: Updating Redirecting Issues in Readme +* :ghpull:`399`: Resolve warnings #317 & and Fix Issue: #355 +* :ghpull:`393`: added primitive and actor for triangular prism, added tests too +* :ghpull:`396`: #317 Fixing Warnings during test : test_actors.py + +Issues (54): + +* :ghissue:`407`: UI Textbox background doesn't resize according to text in it. +* :ghissue:`421`: Implementing the Resizing of Listbox +* :ghissue:`416`: Fixing the Resizing Background issue of TextBox2D UI. +* :ghissue:`475`: Gsoc blog 2021 +* :ghissue:`476`: Google Summer of Code blog posts +* :ghissue:`477`: added blog posts for GSoC'21 +* :ghissue:`442`: added method to wrap overflowing text +* :ghissue:`441`: Added border support in Panel2D +* :ghissue:`466`: two more small bib changes +* :ghissue:`464`: Paper Dan's Comments +* :ghissue:`445`: [WIP] Example to show how to render multiple bonds +* :ghissue:`410`: added BulletList to UI +* :ghissue:`459`: extracted Button2D class from `elements` to `core` +* :ghissue:`429`: Colormap not working as intended with surface actor +* :ghissue:`430`: Surface actor colormap fix +* :ghissue:`450`: Issue with references related to JOSS review +* :ghissue:`456`: Updated about documentation +* :ghissue:`455`: Fixed bibtex +* :ghissue:`454`: Added missing DOIs and URLs +* :ghissue:`453`: Add missing DOIs and URLs +* :ghissue:`451`: Typo fix +* :ghissue:`439`: [WIP] Space filling model +* :ghissue:`447`: UI refactoring +* :ghissue:`438`: Fast selection of multiple objects in 3D using GPU acceleration +* :ghissue:`420`: added an example about graph-tool and nested stochastic block model +* :ghissue:`422`: This allow to draw markers using shaders +* :ghissue:`444`: Remove deprecated functions +* :ghissue:`440`: added support for URL image in ImageContainer2D +* :ghissue:`356`: Render a video on an actor. +* :ghissue:`436`: [Fix] Update Azure pipeline for windows +* :ghissue:`434`: WIP: added tests for layout module +* :ghissue:`403`: Creating test for layout module +* :ghissue:`411`: Added Layout test file +* :ghissue:`426`: Allows to define the priority of a shader_callback and obtain the vtkEventId +* :ghissue:`417`: Fixing pep issues +* :ghissue:`394`: Fixed warnings in test_utils.py +* :ghissue:`415`: update sk orcid +* :ghissue:`414`: Duplicate ORCIDs in the JOSS paper +* :ghissue:`413`: add nanohub doi +* :ghissue:`412`: fix paper doi +* :ghissue:`386`: FURY paper for Journal of Open Source Software (JOSS) +* :ghissue:`371`: Textbox2d special character support +* :ghissue:`409`: Segmentation Fault When Running Fury Tests +* :ghissue:`408`: Updating the Missing Parenthesis +* :ghissue:`406`: Removed unused library in FURY tutorial +* :ghissue:`405`: Updating Redirecting Issues in Readme +* :ghissue:`375`: Visuals for some parametric 2D functions +* :ghissue:`317`: Track and fix warnings during tests. +* :ghissue:`355`: [Vulnerability Bug] Used blacklisted dangerous function call that can lead to RCE +* :ghissue:`399`: Resolve warnings #317 & and Fix Issue: #355 +* :ghissue:`393`: added primitive and actor for triangular prism, added tests too +* :ghissue:`395`: FURY installation conflict +* :ghissue:`396`: #317 Fixing Warnings during test : test_actors.py +* :ghissue:`358`: Updated io.py diff --git a/v0.10.x/_sources/release_notes/releasev0.8.0.rst.txt b/v0.10.x/_sources/release_notes/releasev0.8.0.rst.txt new file mode 100644 index 000000000..d1b4b4e34 --- /dev/null +++ b/v0.10.x/_sources/release_notes/releasev0.8.0.rst.txt @@ -0,0 +1,134 @@ +.. _releasev0.8.0: + +================================== + Release notes v0.8.0 (2022/01/31) +================================== + +Quick Overview +-------------- + +* New Physically Based Rendering (PBR) added. It includes anisotropic rotation and index of refraction among other material properties. +* New Principled BRDF shader unique to FURY added. BRDF stands for bidirectional reflectance distribution function. +* VTK 9.1.0 defined as minimum version. +* Continuous Integration (CI) platform updated. +* New actors added (Rhombicuboctahedron, Pentagonal Prism). +* New UI layouts added (Vertical and Horizontal). +* New module fury.molecular added. +* New module fury.lib added. Module improved loading speed. +* Demos added and updated. +* Documentation updated. + + +Details +------- + +GitHub stats for 2021/08/03 - 2022/01/28 (tag: v0.7.1) + +These lists are automatically generated, and may be incomplete or contain duplicates. + +The following 12 authors contributed 500 commits. + +* Anand Shivam +* Antriksh Misri +* Bruno Messias +* Eleftherios Garyfallidis +* Javier Guaje +* Marc-Alexandre Côté +* Meha Bhalodiya +* Praneeth Shetty +* PrayasJ +* Sajag Swami +* Serge Koudoro +* Shivam Anand + + +We closed a total of 81 issues, 34 pull requests and 47 regular issues; +this is the full list (generated with the script +:file:`tools/github_stats.py`): + +Pull Requests (34): + +* :ghpull:`523`: Adding Anisotropy and Clear coat to PBR material +* :ghpull:`536`: Remove VTK_9_PLUS flag +* :ghpull:`535`: [ENH] Add missing shaders block +* :ghpull:`532`: Remove and replace vtkactor from docstring +* :ghpull:`503`: devmessias gsoc posts part 2: weeks 09, 10 and 11 +* :ghpull:`534`: [FIX] remove update_user_matrix from text3d +* :ghpull:`527`: [FIX] Allow sphere actor to use faces/vertices without casting issues. In addition, update versioning system (versioneer). +* :ghpull:`509`: adding `numpy_to_vtk_image_data` method to utility +* :ghpull:`507`: Deprecate and rename label to vector_text +* :ghpull:`524`: [WIP] Add debugging CI Tools +* :ghpull:`521`: Snapshot flipping bug fix +* :ghpull:`520`: Added rotation along the axis in Solar System Animations example +* :ghpull:`518`: Pytest patch +* :ghpull:`519`: Principled material +* :ghpull:`515`: Changing how we do things with our test suite. +* :ghpull:`516`: Adding Rhombicuboctahedron actor +* :ghpull:`514`: [FIX] Radio button and checkbox tests +* :ghpull:`513`: [FIX] Mesa installation +* :ghpull:`506`: update tutorial import +* :ghpull:`504`: Update molecular module import +* :ghpull:`470`: Update the way we import external libraries by using only the necessary modules +* :ghpull:`452`: Molecular module +* :ghpull:`491`: Method to process and load sprite sheets +* :ghpull:`496`: Added GSoC blog posts for remaining weeks +* :ghpull:`498`: Fix disk position outside the slider line +* :ghpull:`488`: Fix material docstrings, improved standard parameters and improved materials application support +* :ghpull:`449`: Add python3.9 for our CI's +* :ghpull:`493`: GSoC blogs 2021 +* :ghpull:`474`: Add primitive and actor for pentagonal prism with test +* :ghpull:`362`: Animated Surfaces +* :ghpull:`433`: Peak representation improvements +* :ghpull:`432`: Fine-tuning of the OpenGL state +* :ghpull:`479`: Added Vertical Layout to `layout` module +* :ghpull:`480`: Added Horizontal Layout to `layout` module + +Issues (47): + +* :ghissue:`523`: Adding Anisotropy and Clear coat to PBR material +* :ghissue:`536`: Remove VTK_9_PLUS flag +* :ghissue:`535`: [ENH] Add missing shaders block +* :ghissue:`532`: Remove and replace vtkactor from docstring +* :ghissue:`503`: devmessias gsoc posts part 2: weeks 09, 10 and 11 +* :ghissue:`534`: [FIX] remove update_user_matrix from text3d +* :ghissue:`526`: Text justification in vtkTextActor3D +* :ghissue:`500`: Adding a utility function to convert a numpy array to vtkImageData +* :ghissue:`527`: [FIX] Allow sphere actor to use faces/vertices without casting issues. In addition, update versioning system (versioneer). +* :ghissue:`400`: Sphere actor does not appear when vertices and faces are used +* :ghissue:`509`: adding `numpy_to_vtk_image_data` method to utility +* :ghissue:`431`: Deprecation warning raised in from `utils.numpy_to_vtk_cells` +* :ghissue:`457`: Improve loading speed using partial imports +* :ghissue:`468`: Remove all vtk calls from tutorials and demos +* :ghissue:`507`: Deprecate and rename label to vector_text +* :ghissue:`524`: [WIP] Add debugging CI Tools +* :ghissue:`521`: Snapshot flipping bug fix +* :ghissue:`467`: Window snapshot inverts the displayed scene +* :ghissue:`520`: Added rotation along the axis in Solar System Animations example +* :ghissue:`505`: want a highlight feature +* :ghissue:`518`: Pytest patch +* :ghissue:`519`: Principled material +* :ghissue:`515`: Changing how we do things with our test suite. +* :ghissue:`512`: Flocking-simulation using boid rules +* :ghissue:`516`: Adding Rhombicuboctahedron actor +* :ghissue:`514`: [FIX] Radio button and checkbox tests +* :ghissue:`513`: [FIX] Mesa installation +* :ghissue:`511`: Flocking-simulation using boid rules +* :ghissue:`506`: update tutorial import +* :ghissue:`504`: Update molecular module import +* :ghissue:`404`: Parametric functions- actor, primitives +* :ghissue:`470`: Update the way we import external libraries by using only the necessary modules +* :ghissue:`452`: Molecular module +* :ghissue:`469`: Mismatch in parameter and docstring in manifest_standard() in material module +* :ghissue:`491`: Method to process and load sprite sheets +* :ghissue:`496`: Added GSoC blog posts for remaining weeks +* :ghissue:`498`: Fix disk position outside the slider line +* :ghissue:`488`: Fix material docstrings, improved standard parameters and improved materials application support +* :ghissue:`449`: Add python3.9 for our CI's +* :ghissue:`493`: GSoC blogs 2021 +* :ghissue:`474`: Add primitive and actor for pentagonal prism with test +* :ghissue:`362`: Animated Surfaces +* :ghissue:`324`: Animate a wave function +* :ghissue:`433`: Peak representation improvements +* :ghissue:`432`: Fine-tuning of the OpenGL state +* :ghissue:`479`: Added Vertical Layout to `layout` module +* :ghissue:`480`: Added Horizontal Layout to `layout` module diff --git a/v0.10.x/_sources/release_notes/releasev0.9.0.rst.txt b/v0.10.x/_sources/release_notes/releasev0.9.0.rst.txt new file mode 100644 index 000000000..4c21bb4f2 --- /dev/null +++ b/v0.10.x/_sources/release_notes/releasev0.9.0.rst.txt @@ -0,0 +1,443 @@ +.. _releasev0.9.0: + +=================================== + Release notes v0.9.0 (2023/04/15) +=================================== + +Quick Overview +-------------- + +* New Streaming System added. +* Large improvement of Signed Distance Functions actors (SDF). +* Continuous Integration (CI) platform updated. Migrate Windows CI from Azure to Github Actions +* Migration from setuptools to hatching. versioning system updated also. +* New module fury.animation added. +* New module fury.gltf added. Module to support glTF 2.0. +* Multiple tutorials added and updated. +* Documentation updated. +* Website updated. + + +Details +------- + +GitHub stats for 2022/01/31 - 2023/04/14 (tag: v0.8.0) + +These lists are automatically generated, and may be incomplete or contain duplicates. + +The following 24 authors contributed 1835 commits. + +* Anand Shivam +* Antriksh Misri +* Bruno Messias +* Dwij Raj Hari +* Eleftherios Garyfallidis +* Filipi Nascimento Silva +* Francois Rheault +* Frank Cerasoli +* Javier Guaje +* Johny Daras +* Mohamed Agour +* Nasim Anousheh +* Praneeth Shetty +* Rohit Kharsan +* Sara Hamza +* Serge Koudoro +* Siddharth Gautam +* Soham Biswas +* Sreekar Chigurupati +* Tania Castillo +* Zhiwen Shi +* maharshigor +* sailesh +* sparshg + + +We closed a total of 379 issues, 166 pull requests and 213 regular issues; +this is the full list (generated with the script +:file:`tools/github_stats.py`): + +Pull Requests (166): + +* :ghpull:`687`: Record keyframe animation as GIF and MP4 +* :ghpull:`782`: Add Codespell and update codecov +* :ghpull:`587`: Billboard tutorial +* :ghpull:`781`: Tab customization +* :ghpull:`779`: versions-corrected +* :ghpull:`741`: Remove unneeded multithreading call +* :ghpull:`778`: TabUI collapsing/expanding improvements +* :ghpull:`777`: Remove alias keyword on documentation +* :ghpull:`771`: add one condition in `repeat_primitive` to handle direction [-1, 0, 0], issue #770 +* :ghpull:`766`: Cylinder repeat primitive +* :ghpull:`769`: Merge Demo and examples +* :ghpull:`767`: Update Peak actor shader +* :ghpull:`677`: Cylindrical billboard implementation +* :ghpull:`765`: add instruction about how to get Suzanne model +* :ghpull:`764`: ComboBox2D drop_down_button mouse callback was inside for loop +* :ghpull:`748`: some fixs and ex addition in docstrings in actor.py +* :ghpull:`754`: update viz_roi_contour.py +* :ghpull:`760`: update deprecated function get.data() to get.fdata() +* :ghpull:`761`: add instruction of how to download suzanne model for getting started page +* :ghpull:`762`: update the deprecated get_data() to get_fdata in viz_roi_contour.py in the demo section. +* :ghpull:`756`: Triangle strips 2 Triangles +* :ghpull:`747`: Connected the sliders to the right directions +* :ghpull:`744`: Update initialize management +* :ghpull:`710`: Principled update +* :ghpull:`688`: DrawPanel Update: Moving rotation_slider from `DrawShape` to `DrawPanel` +* :ghpull:`734`: Added GSoC'22 Final Report +* :ghpull:`736`: Adding GSoC'22 final report +* :ghpull:`727`: Feature/scientific domains +* :ghpull:`478`: Resolving GridUI caption error +* :ghpull:`502`: Multithreading support and examples +* :ghpull:`740`: Multithreading example simplified and refactored +* :ghpull:`739`: added a check for operating system before executing the tput command through popen in fury/data/fetcher.py update_progressbar() function +* :ghpull:`737`: remove object keyword from class +* :ghpull:`726`: Adding GSoC'22 Final Report +* :ghpull:`735`: Add precommit +* :ghpull:`728`: Fix flipped images in load, save, and snapshot +* :ghpull:`730`: Update CI and add pyproject.toml +* :ghpull:`729`: Fix links in CONTRIBUTING.rst +* :ghpull:`725`: Improve Doc management + quick fix +* :ghpull:`724`: Feature/community page +* :ghpull:`721`: Fix: Color changes on docs pages fixed +* :ghpull:`723`: Update CI's +* :ghpull:`722`: Fix failing tests due to last numpy release +* :ghpull:`719`: Logo changes +* :ghpull:`718`: Home page mobile friendly +* :ghpull:`717`: Scientific domains enhancement +* :ghpull:`680`: Updating animation tutorials +* :ghpull:`690`: Add Timelines to ShowManager directly +* :ghpull:`694`: Separating the Timeline into Timeline and Animation +* :ghpull:`712`: Fix: segfault created by record method +* :ghpull:`706`: fix: double render call with timeline obj causes a seg fault +* :ghpull:`700`: Adding morphing support in `gltf.py` +* :ghpull:`697`: Adding week 14 blog +* :ghpull:`693`: Adding Week 15 Blogpost +* :ghpull:`701`: Updating `fetch_viz_new_icons` to fetch new icons +* :ghpull:`685`: glTF skinning animation implementation +* :ghpull:`699`: Adding Week 16 Blogpost +* :ghpull:`698`: Added blog post for week 14 +* :ghpull:`667`: [WIP] Remove initialize call from multiple places +* :ghpull:`689`: GLTF actor colors from material +* :ghpull:`643`: [WIP] Adding ability to load glTF animations +* :ghpull:`665`: Timeline hierarchical transformation and fixing some issues +* :ghpull:`686`: Adding week 13 blog post +* :ghpull:`684`: Adding Week 14 Blogpost +* :ghpull:`692`: Set position and width of the `PlaybackPanel` +* :ghpull:`691`: Added week 13 post +* :ghpull:`683`: Adding Week 13 Blogpost +* :ghpull:`682`: Adding week 12 blog post +* :ghpull:`681`: Added blog post for week 12 +* :ghpull:`672`: Adding Week 12 Blogpost +* :ghpull:`678`: DrawPanel Update: Repositioning the `mode_panel` and `mode_text` +* :ghpull:`661`: Improving `vector_text` +* :ghpull:`679`: DrawPanel Update: Moving repetitive functions to helpers +* :ghpull:`674`: DrawPanel Update: Separating tests to test individual features +* :ghpull:`675`: Week 11 blog post +* :ghpull:`673`: DrawPanel Update: Removing `in_progress` parameter while drawing shapes +* :ghpull:`676`: Adding week 11 blog post +* :ghpull:`671`: Adding Week 11 Blogpost +* :ghpull:`623`: DrawPanel Feature: Adding Rotation of shape from Center +* :ghpull:`670`: Adding week 10 blog post +* :ghpull:`666`: Adding Week 10 Blogpost +* :ghpull:`669`: Added blog post for week 10 +* :ghpull:`647`: Keyframe animations and interpolators +* :ghpull:`620`: Tutorial on making a primitive using polygons and SDF +* :ghpull:`630`: Adding function to export scenes as glTF +* :ghpull:`663`: Adding week 9 blog post +* :ghpull:`656`: Week 8 blog post +* :ghpull:`662`: Week 9 blog post +* :ghpull:`654`: Adding Week 9 Blogpost +* :ghpull:`659`: Adding week 8 blog post +* :ghpull:`650`: Adding Week 8 Blogpost +* :ghpull:`655`: Fix test skybox +* :ghpull:`645`: Fixing `ZeroDivisionError` thrown by UI sliders when the `value_range` is zero (0) +* :ghpull:`648`: Adding week 7 blog post +* :ghpull:`649`: Added week 7 blog post +* :ghpull:`646`: Adding Week 7 Blogpost +* :ghpull:`641`: Week 6 blog post +* :ghpull:`644`: Adding week 6 blog post +* :ghpull:`638`: Adding Week 6 Blogpost +* :ghpull:`639`: Migrate Windows from Azure to GHA +* :ghpull:`634`: Prevented calling `on_change` when slider value is set without user intervention +* :ghpull:`637`: Adding week 5 blog post +* :ghpull:`632`: Bugfix: Visibility issues with ListBox2D +* :ghpull:`610`: Add DPI support for window snapshots +* :ghpull:`633`: Added week 5 blog post +* :ghpull:`617`: Added primitives count to the the Actor's polydata +* :ghpull:`624`: Adding Week 5 BlogPost +* :ghpull:`627`: Adding week 4 blog post +* :ghpull:`625`: Added week 4 blog post +* :ghpull:`600`: Adding support for importing simple glTF files +* :ghpull:`622`: Adding week 3 blog post +* :ghpull:`619`: Week 3 blog post. +* :ghpull:`621`: Adding Week 4 Blogpost +* :ghpull:`616`: Fixing API limits reached issue in gltf fetcher +* :ghpull:`611`: Adding Week 3 BlogPost +* :ghpull:`614`: Added week 2 blog +* :ghpull:`615`: Added blog post for week 2 +* :ghpull:`607`: Adding Week 2 Blog Post +* :ghpull:`599`: Creating `DrawPanel` UI +* :ghpull:`606`: Added week 1 post +* :ghpull:`608`: Adding week 1 blog post +* :ghpull:`597`: Added an accurate way to get the FPS for the showManager +* :ghpull:`605`: Adding Week1 Blog Post +* :ghpull:`501`: Creating an `off_focus` hook in `TextBox2D` +* :ghpull:`602`: Added support for fetching gltf samples +* :ghpull:`609`: Creating a fetcher to fetch new icons +* :ghpull:`601`: Updating author's name in README +* :ghpull:`593`: Support empty ArraySequence in saving (for empty vtk) +* :ghpull:`598`: Timer id is returned after creating the timer. +* :ghpull:`581`: Keep original dtype for offsets in vtk format +* :ghpull:`595`: changed `use_primitive` to false by default +* :ghpull:`589`: First blog: GSoC +* :ghpull:`586`: Added my first blog post +* :ghpull:`594`: Fixed multi_samples not being used. +* :ghpull:`591`: Fixed some old tutorials. +* :ghpull:`590`: Adding Pre-GSoC Journey Blog Post +* :ghpull:`584`: Changing dot actor +* :ghpull:`582`: Deprecation of the function shaders.load +* :ghpull:`580`: Update website +* :ghpull:`437`: FURY Streaming System Proposal +* :ghpull:`574`: symmetric parameter for peak +* :ghpull:`561`: Shader API improvements +* :ghpull:`533`: Sphere actor uses repeat_primitive by default +* :ghpull:`577`: Added play/pause buttons +* :ghpull:`443`: Adapt GridLayout to work with UI +* :ghpull:`570`: Function to save screenshots with magnification factor +* :ghpull:`486`: Added `x,y,z` layouts to the layout module. +* :ghpull:`547`: Cone actor uses `repeat_primitive` by default +* :ghpull:`552`: Modified Arrow actor to use repeat primitive by default +* :ghpull:`555`: Fixed the rotation matrix in repeat_primitive. +* :ghpull:`569`: Add new example/demo: three-dimensional fractals +* :ghpull:`572`: Fixed the static path in configuration file for docs +* :ghpull:`571`: Fix vertex order in prim_tetrahedron +* :ghpull:`567`: Replace theme in requirements/docs.txt +* :ghpull:`566`: Update Website Footer +* :ghpull:`551`: Fixed #550 : Added necessary alignment between glyph creation and ac… +* :ghpull:`559`: Added simulation for Tesseract +* :ghpull:`556`: Updated code of `viz_network_animated` to use `fury.utils` +* :ghpull:`565`: Minor documentation fixes +* :ghpull:`563`: New website changes +* :ghpull:`564`: Record should not make the window appear +* :ghpull:`557`: Check to see if file exists before opening +* :ghpull:`560`: Force mesa update +* :ghpull:`544`: Improve setuptools +* :ghpull:`542`: Re-enabling nearly all under investigation tests +* :ghpull:`537`: Add OpenGL flags for offscreen rendering + +Issues (213): + +* :ghissue:`713`: The docs generation fails with pyData theme v0.11.0 +* :ghissue:`687`: Record keyframe animation as GIF and MP4 +* :ghissue:`782`: Add Codespell and update codecov +* :ghissue:`587`: Billboard tutorial +* :ghissue:`781`: Tab customization +* :ghissue:`779`: versions-corrected +* :ghissue:`741`: Remove unneeded multithreading call +* :ghissue:`776`: TabUI collapsing/expanding improvements +* :ghissue:`778`: TabUI collapsing/expanding improvements +* :ghissue:`777`: Remove alias keyword on documentation +* :ghissue:`770`: Directions of arrow actor do not change in `repeat_primitive = False` method (VTK) +* :ghissue:`732`: [WIP] integrating latex to fury +* :ghissue:`771`: add one condition in `repeat_primitive` to handle direction [-1, 0, 0], issue #770 +* :ghissue:`766`: Cylinder repeat primitive +* :ghissue:`769`: Merge Demo and examples +* :ghissue:`772`: test for peak_slicer() cannot pass +* :ghissue:`767`: Update Peak actor shader +* :ghissue:`82`: GLTF 2.0 +* :ghissue:`354`: Some Typos & Grammatical Errors to be fixed in WIKI GSOC 2021 +* :ghissue:`677`: Cylindrical billboard implementation +* :ghissue:`765`: add instruction about how to get Suzanne model +* :ghissue:`764`: ComboBox2D drop_down_button mouse callback was inside for loop +* :ghissue:`748`: some fixs and ex addition in docstrings in actor.py +* :ghissue:`754`: update viz_roi_contour.py +* :ghissue:`760`: update deprecated function get.data() to get.fdata() +* :ghissue:`761`: add instruction of how to download suzanne model for getting started page +* :ghissue:`762`: update the deprecated get_data() to get_fdata in viz_roi_contour.py in the demo section. +* :ghissue:`756`: Triangle strips 2 Triangles +* :ghissue:`708`: Strips to triangles +* :ghissue:`747`: Connected the sliders to the right directions +* :ghissue:`745`: Getting error in installation +* :ghissue:`743`: Missing fury.animation +* :ghissue:`709`: Commented the self.initialize +* :ghissue:`744`: Update initialize management +* :ghissue:`710`: Principled update +* :ghissue:`688`: DrawPanel Update: Moving rotation_slider from `DrawShape` to `DrawPanel` +* :ghissue:`734`: Added GSoC'22 Final Report +* :ghissue:`736`: Adding GSoC'22 final report +* :ghissue:`727`: Feature/scientific domains +* :ghissue:`463`: `GridUI` throws error when captions are `None` +* :ghissue:`478`: Resolving GridUI caption error +* :ghissue:`502`: Multithreading support and examples +* :ghissue:`740`: Multithreading example simplified and refactored +* :ghissue:`738`: Download progress bar tries to use the tput command to determine the width of the terminal to adjust the width of the progress bar, however, when run on windows, this leaves an error message +* :ghissue:`739`: added a check for operating system before executing the tput command through popen in fury/data/fetcher.py update_progressbar() function +* :ghissue:`737`: remove object keyword from class +* :ghissue:`726`: Adding GSoC'22 Final Report +* :ghissue:`735`: Add precommit +* :ghissue:`664`: Improve animation module tutorial +* :ghissue:`720`: fix image load flip issue +* :ghissue:`642`: Textures are inverted in the tutorials +* :ghissue:`728`: Fix flipped images in load, save, and snapshot +* :ghissue:`730`: Update CI and add pyproject.toml +* :ghissue:`729`: Fix links in CONTRIBUTING.rst +* :ghissue:`725`: Improve Doc management + quick fix +* :ghissue:`724`: Feature/community page +* :ghissue:`721`: Fix: Color changes on docs pages fixed +* :ghissue:`316`: Build a sphinx theme +* :ghissue:`714`: Earth coordinates tutorial example upsidedown +* :ghissue:`723`: Update CI's +* :ghissue:`722`: Fix failing tests due to last numpy release +* :ghissue:`719`: Logo changes +* :ghissue:`718`: Home page mobile friendly +* :ghissue:`717`: Scientific domains enhancement +* :ghissue:`680`: Updating animation tutorials +* :ghissue:`716`: tensor_slicer function has an issue with sphere argument +* :ghissue:`690`: Add Timelines to ShowManager directly +* :ghissue:`694`: Separating the Timeline into Timeline and Animation +* :ghissue:`603`: UI tests are failing in Ubuntu OS due to a "segmentation error" +* :ghissue:`712`: Fix: segfault created by record method +* :ghissue:`705`: [BUG] Segmentation fault error caused by Morph Stress Test +* :ghissue:`706`: fix: double render call with timeline obj causes a seg fault +* :ghissue:`435`: Fury/VTK Streaming: webrtc/rtmp +* :ghissue:`704`: seg fault investigation +* :ghissue:`700`: Adding morphing support in `gltf.py` +* :ghissue:`697`: Adding week 14 blog +* :ghissue:`693`: Adding Week 15 Blogpost +* :ghissue:`701`: Updating `fetch_viz_new_icons` to fetch new icons +* :ghissue:`685`: glTF skinning animation implementation +* :ghissue:`699`: Adding Week 16 Blogpost +* :ghissue:`698`: Added blog post for week 14 +* :ghissue:`667`: [WIP] Remove initialize call from multiple places +* :ghissue:`689`: GLTF actor colors from material +* :ghissue:`643`: [WIP] Adding ability to load glTF animations +* :ghissue:`665`: Timeline hierarchical transformation and fixing some issues +* :ghissue:`686`: Adding week 13 blog post +* :ghissue:`684`: Adding Week 14 Blogpost +* :ghissue:`692`: Set position and width of the `PlaybackPanel` +* :ghissue:`691`: Added week 13 post +* :ghissue:`683`: Adding Week 13 Blogpost +* :ghissue:`682`: Adding week 12 blog post +* :ghissue:`681`: Added blog post for week 12 +* :ghissue:`672`: Adding Week 12 Blogpost +* :ghissue:`678`: DrawPanel Update: Repositioning the `mode_panel` and `mode_text` +* :ghissue:`661`: Improving `vector_text` +* :ghissue:`679`: DrawPanel Update: Moving repetitive functions to helpers +* :ghissue:`674`: DrawPanel Update: Separating tests to test individual features +* :ghissue:`675`: Week 11 blog post +* :ghissue:`673`: DrawPanel Update: Removing `in_progress` parameter while drawing shapes +* :ghissue:`676`: Adding week 11 blog post +* :ghissue:`671`: Adding Week 11 Blogpost +* :ghissue:`623`: DrawPanel Feature: Adding Rotation of shape from Center +* :ghissue:`670`: Adding week 10 blog post +* :ghissue:`666`: Adding Week 10 Blogpost +* :ghissue:`669`: Added blog post for week 10 +* :ghissue:`419`: Controlling Fury windows by HTC VIVE +* :ghissue:`647`: Keyframe animations and interpolators +* :ghissue:`620`: Tutorial on making a primitive using polygons and SDF +* :ghissue:`630`: Adding function to export scenes as glTF +* :ghissue:`663`: Adding week 9 blog post +* :ghissue:`656`: Week 8 blog post +* :ghissue:`662`: Week 9 blog post +* :ghissue:`654`: Adding Week 9 Blogpost +* :ghissue:`659`: Adding week 8 blog post +* :ghissue:`650`: Adding Week 8 Blogpost +* :ghissue:`655`: Fix test skybox +* :ghissue:`645`: Fixing `ZeroDivisionError` thrown by UI sliders when the `value_range` is zero (0) +* :ghissue:`657`: Put text next to a roi +* :ghissue:`626`: Keyframe animation with camera support +* :ghissue:`648`: Adding week 7 blog post +* :ghissue:`649`: Added week 7 blog post +* :ghissue:`646`: Adding Week 7 Blogpost +* :ghissue:`641`: Week 6 blog post +* :ghissue:`644`: Adding week 6 blog post +* :ghissue:`638`: Adding Week 6 Blogpost +* :ghissue:`639`: Migrate Windows from Azure to GHA +* :ghissue:`618`: Theme issues when docs compiled with latest sphinx-theme version +* :ghissue:`634`: Prevented calling `on_change` when slider value is set without user intervention +* :ghissue:`637`: Adding week 5 blog post +* :ghissue:`632`: Bugfix: Visibility issues with ListBox2D +* :ghissue:`418`: ListBox2D has resizing issues when added into TabUI +* :ghissue:`610`: Add DPI support for window snapshots +* :ghissue:`612`: [WIP] Implemented a functional prototype of the keyframes animation API +* :ghissue:`613`: [WIP] Added three tutorials to test the animation system and the interpolators +* :ghissue:`633`: Added week 5 blog post +* :ghissue:`617`: Added primitives count to the the Actor's polydata +* :ghissue:`624`: Adding Week 5 BlogPost +* :ghissue:`627`: Adding week 4 blog post +* :ghissue:`625`: Added week 4 blog post +* :ghissue:`600`: Adding support for importing simple glTF files +* :ghissue:`622`: Adding week 3 blog post +* :ghissue:`619`: Week 3 blog post. +* :ghissue:`621`: Adding Week 4 Blogpost +* :ghissue:`616`: Fixing API limits reached issue in gltf fetcher +* :ghissue:`611`: Adding Week 3 BlogPost +* :ghissue:`614`: Added week 2 blog +* :ghissue:`615`: Added blog post for week 2 +* :ghissue:`607`: Adding Week 2 Blog Post +* :ghissue:`599`: Creating `DrawPanel` UI +* :ghissue:`606`: Added week 1 post +* :ghissue:`608`: Adding week 1 blog post +* :ghissue:`597`: Added an accurate way to get the FPS for the showManager +* :ghissue:`605`: Adding Week1 Blog Post +* :ghissue:`501`: Creating an `off_focus` hook in `TextBox2D` +* :ghissue:`602`: Added support for fetching gltf samples +* :ghissue:`609`: Creating a fetcher to fetch new icons +* :ghissue:`553`: Refresh code of all tutorials and demos +* :ghissue:`601`: Updating author's name in README +* :ghissue:`593`: Support empty ArraySequence in saving (for empty vtk) +* :ghissue:`598`: Timer id is returned after creating the timer. +* :ghissue:`581`: Keep original dtype for offsets in vtk format +* :ghissue:`588`: Fixed Sphere Creation Error on viz_pbr_interactive Tutorial +* :ghissue:`596`: Segmentation Faults when running Fury demos +* :ghissue:`585`: Double requirement given for Pillow in default.txt +* :ghissue:`595`: changed `use_primitive` to false by default +* :ghissue:`589`: First blog: GSoC +* :ghissue:`525`: Implemented vtkBillboardTextActor +* :ghissue:`586`: Added my first blog post +* :ghissue:`594`: Fixed multi_samples not being used. +* :ghissue:`591`: Fixed some old tutorials. +* :ghissue:`590`: Adding Pre-GSoC Journey Blog Post +* :ghissue:`584`: Changing dot actor +* :ghissue:`582`: Deprecation of the function shaders.load +* :ghissue:`580`: Update website +* :ghissue:`575`: Button and footer changes in docs +* :ghissue:`437`: FURY Streaming System Proposal +* :ghissue:`574`: symmetric parameter for peak +* :ghissue:`561`: Shader API improvements +* :ghissue:`546`: No replacement option for Geometry Shaders +* :ghissue:`533`: Sphere actor uses repeat_primitive by default +* :ghissue:`528`: Sphere actor needs to use repeat_primitives by default +* :ghissue:`577`: Added play/pause buttons +* :ghissue:`443`: Adapt GridLayout to work with UI +* :ghissue:`570`: Function to save screenshots with magnification factor +* :ghissue:`486`: Added `x,y,z` layouts to the layout module. +* :ghissue:`547`: Cone actor uses `repeat_primitive` by default +* :ghissue:`529`: Cone actor needs to use repeat_primitives by default +* :ghissue:`530`: Arrow actor needs to use repeat_primitives by default +* :ghissue:`552`: Modified Arrow actor to use repeat primitive by default +* :ghissue:`545`: Fix some tests in `test_material.py` +* :ghissue:`554`: The rotation done by repeat_primitive function is not working as it should. +* :ghissue:`555`: Fixed the rotation matrix in repeat_primitive. +* :ghissue:`573`: Segmentation Fault +* :ghissue:`569`: Add new example/demo: three-dimensional fractals +* :ghissue:`572`: Fixed the static path in configuration file for docs +* :ghissue:`571`: Fix vertex order in prim_tetrahedron +* :ghissue:`567`: Replace theme in requirements/docs.txt +* :ghissue:`566`: Update Website Footer +* :ghissue:`550`: Cylinder direction not unique. +* :ghissue:`551`: Fixed #550 : Added necessary alignment between glyph creation and ac… +* :ghissue:`541`: Allow offscreen rendering in window.record. +* :ghissue:`548`: Black window on screen on "window.record". +* :ghissue:`559`: Added simulation for Tesseract +* :ghissue:`556`: Updated code of `viz_network_animated` to use `fury.utils` +* :ghissue:`565`: Minor documentation fixes +* :ghissue:`563`: New website changes +* :ghissue:`564`: Record should not make the window appear +* :ghissue:`557`: Check to see if file exists before opening +* :ghissue:`560`: Force mesa update +* :ghissue:`549`: Add time step to brownian animation and velocity components to helica… +* :ghissue:`544`: Improve setuptools +* :ghissue:`542`: Re-enabling nearly all under investigation tests +* :ghissue:`537`: Add OpenGL flags for offscreen rendering diff --git a/v0.10.x/_sources/sg_execution_times.rst.txt b/v0.10.x/_sources/sg_execution_times.rst.txt new file mode 100644 index 000000000..21d26cdf2 --- /dev/null +++ b/v0.10.x/_sources/sg_execution_times.rst.txt @@ -0,0 +1,262 @@ + +:orphan: + +.. _sphx_glr_sg_execution_times: + + +Computation times +================= +**00:00.591** total execution time for 76 files **from all galleries**: + +.. container:: + + .. raw:: html + + + + + + + + .. list-table:: + :header-rows: 1 + :class: table table-striped sg-datatable + + * - Example + - Time + - Mem (MB) + * - :ref:`sphx_glr_auto_examples_17_pybullet_viz_chain.py` (``../examples_revamped/17_pybullet/viz_chain.py``) + - 00:00.591 + - 0.0 + * - :ref:`sphx_glr_auto_examples_01_introductory_viz_arrow.py` (``../examples_revamped/01_introductory/viz_arrow.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_01_introductory_viz_cone.py` (``../examples_revamped/01_introductory/viz_cone.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_01_introductory_viz_earth_animation.py` (``../examples_revamped/01_introductory/viz_earth_animation.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_01_introductory_viz_earth_coordinates.py` (``../examples_revamped/01_introductory/viz_earth_coordinates.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_01_introductory_viz_gltf.py` (``../examples_revamped/01_introductory/viz_gltf.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_01_introductory_viz_gltf_animated.py` (``../examples_revamped/01_introductory/viz_gltf_animated.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_01_introductory_viz_gltf_export.py` (``../examples_revamped/01_introductory/viz_gltf_export.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_01_introductory_viz_morphing.py` (``../examples_revamped/01_introductory/viz_morphing.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_01_introductory_viz_multithread.py` (``../examples_revamped/01_introductory/viz_multithread.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_01_introductory_viz_picking.py` (``../examples_revamped/01_introductory/viz_picking.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_01_introductory_viz_selection.py` (``../examples_revamped/01_introductory/viz_selection.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_01_introductory_viz_skinning.py` (``../examples_revamped/01_introductory/viz_skinning.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_01_introductory_viz_slice.py` (``../examples_revamped/01_introductory/viz_slice.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_01_introductory_viz_solar_system.py` (``../examples_revamped/01_introductory/viz_solar_system.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_01_introductory_viz_sphere.py` (``../examples_revamped/01_introductory/viz_sphere.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_01_introductory_viz_spiky.py` (``../examples_revamped/01_introductory/viz_spiky.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_01_introductory_viz_surfaces.py` (``../examples_revamped/01_introductory/viz_surfaces.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_01_introductory_viz_texture.py` (``../examples_revamped/01_introductory/viz_texture.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_01_introductory_viz_timers.py` (``../examples_revamped/01_introductory/viz_timers.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_04_demos_collision-particles.py` (``../examples_revamped/04_demos/collision-particles.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_04_demos_viz_advanced.py` (``../examples_revamped/04_demos/viz_advanced.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_04_demos_viz_animated_surfaces.py` (``../examples_revamped/04_demos/viz_animated_surfaces.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_04_demos_viz_brownian_motion.py` (``../examples_revamped/04_demos/viz_brownian_motion.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_04_demos_viz_bundles.py` (``../examples_revamped/04_demos/viz_bundles.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_04_demos_viz_dt_ellipsoids.py` (``../examples_revamped/04_demos/viz_dt_ellipsoids.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_04_demos_viz_emwave_animation.py` (``../examples_revamped/04_demos/viz_emwave_animation.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_04_demos_viz_fiber_odf.py` (``../examples_revamped/04_demos/viz_fiber_odf.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_04_demos_viz_fine_tuning_gl_context.py` (``../examples_revamped/04_demos/viz_fine_tuning_gl_context.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_04_demos_viz_fractals.py` (``../examples_revamped/04_demos/viz_fractals.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_04_demos_viz_helical_motion.py` (``../examples_revamped/04_demos/viz_helical_motion.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_04_demos_viz_markers.py` (``../examples_revamped/04_demos/viz_markers.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_04_demos_viz_network.py` (``../examples_revamped/04_demos/viz_network.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_04_demos_viz_network_animated.py` (``../examples_revamped/04_demos/viz_network_animated.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_04_demos_viz_pbr_interactive.py` (``../examples_revamped/04_demos/viz_pbr_interactive.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_04_demos_viz_play_video.py` (``../examples_revamped/04_demos/viz_play_video.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_04_demos_viz_roi_contour.py` (``../examples_revamped/04_demos/viz_roi_contour.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_04_demos_viz_tesseract.py` (``../examples_revamped/04_demos/viz_tesseract.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_07_ui_viz_buttons.py` (``../examples_revamped/07_ui/viz_buttons.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_07_ui_viz_card.py` (``../examples_revamped/07_ui/viz_card.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_07_ui_viz_card_sprite_sheet.py` (``../examples_revamped/07_ui/viz_card_sprite_sheet.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_07_ui_viz_check_boxes.py` (``../examples_revamped/07_ui/viz_check_boxes.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_07_ui_viz_combobox.py` (``../examples_revamped/07_ui/viz_combobox.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_07_ui_viz_drawpanel.py` (``../examples_revamped/07_ui/viz_drawpanel.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_07_ui_viz_layout.py` (``../examples_revamped/07_ui/viz_layout.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_07_ui_viz_radio_buttons.py` (``../examples_revamped/07_ui/viz_radio_buttons.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_07_ui_viz_shapes.py` (``../examples_revamped/07_ui/viz_shapes.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_07_ui_viz_spinbox.py` (``../examples_revamped/07_ui/viz_spinbox.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_07_ui_viz_tab.py` (``../examples_revamped/07_ui/viz_tab.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_07_ui_viz_ui.py` (``../examples_revamped/07_ui/viz_ui.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_07_ui_viz_ui_listbox.py` (``../examples_revamped/07_ui/viz_ui_listbox.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_07_ui_viz_ui_slider.py` (``../examples_revamped/07_ui/viz_ui_slider.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_10_animation_viz_bezier_interpolator.py` (``../examples_revamped/10_animation/viz_bezier_interpolator.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_10_animation_viz_camera.py` (``../examples_revamped/10_animation/viz_camera.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_10_animation_viz_color_interpolators.py` (``../examples_revamped/10_animation/viz_color_interpolators.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_10_animation_viz_custom_interpolator.py` (``../examples_revamped/10_animation/viz_custom_interpolator.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_10_animation_viz_hierarchical_animation.py` (``../examples_revamped/10_animation/viz_hierarchical_animation.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_10_animation_viz_interpolators.py` (``../examples_revamped/10_animation/viz_interpolators.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_10_animation_viz_introduction.py` (``../examples_revamped/10_animation/viz_introduction.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_10_animation_viz_robot_arm_animation.py` (``../examples_revamped/10_animation/viz_robot_arm_animation.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_10_animation_viz_spline_interpolator.py` (``../examples_revamped/10_animation/viz_spline_interpolator.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_10_animation_viz_timeline.py` (``../examples_revamped/10_animation/viz_timeline.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_10_animation_viz_using_time_equations.py` (``../examples_revamped/10_animation/viz_using_time_equations.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_13_shaders_viz_billboard_sdf_spheres.py` (``../examples_revamped/13_shaders/viz_billboard_sdf_spheres.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_13_shaders_viz_pbr_spheres.py` (``../examples_revamped/13_shaders/viz_pbr_spheres.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_13_shaders_viz_principled_spheres.py` (``../examples_revamped/13_shaders/viz_principled_spheres.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_13_shaders_viz_sdf_cylinder.py` (``../examples_revamped/13_shaders/viz_sdf_cylinder.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_13_shaders_viz_sdfactor.py` (``../examples_revamped/13_shaders/viz_sdfactor.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_13_shaders_viz_shader.py` (``../examples_revamped/13_shaders/viz_shader.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_17_pybullet_viz_ball_collide.py` (``../examples_revamped/17_pybullet/viz_ball_collide.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_17_pybullet_viz_brick_wall.py` (``../examples_revamped/17_pybullet/viz_brick_wall.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_17_pybullet_viz_domino.py` (``../examples_revamped/17_pybullet/viz_domino.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_17_pybullet_viz_wrecking_ball.py` (``../examples_revamped/17_pybullet/viz_wrecking_ball.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_20_stream_viz_interaction.py` (``../examples_revamped/20_stream/viz_interaction.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_20_stream_viz_no_interaction.py` (``../examples_revamped/20_stream/viz_no_interaction.py``) + - 00:00.000 + - 0.0 + * - :ref:`sphx_glr_auto_examples_20_stream_viz_widget.py` (``../examples_revamped/20_stream/viz_widget.py``) + - 00:00.000 + - 0.0 diff --git a/v0.10.x/_sources/symlink/contributing.rst.txt b/v0.10.x/_sources/symlink/contributing.rst.txt new file mode 100644 index 000000000..b1cd2f37d --- /dev/null +++ b/v0.10.x/_sources/symlink/contributing.rst.txt @@ -0,0 +1 @@ +.. include:: ../../../CONTRIBUTING.rst diff --git a/v0.10.x/_sources/symlink/license.rst.txt b/v0.10.x/_sources/symlink/license.rst.txt new file mode 100644 index 000000000..2c4b9f7e8 --- /dev/null +++ b/v0.10.x/_sources/symlink/license.rst.txt @@ -0,0 +1,5 @@ +======= +License +======= + +.. include:: ../../../LICENSE diff --git a/v0.10.x/_static/basic.css b/v0.10.x/_static/basic.css new file mode 100644 index 000000000..e760386bd --- /dev/null +++ b/v0.10.x/_static/basic.css @@ -0,0 +1,925 @@ +/* + * basic.css + * ~~~~~~~~~ + * + * Sphinx stylesheet -- basic theme. + * + * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/* -- main layout ----------------------------------------------------------- */ + +div.clearer { + clear: both; +} + +div.section::after { + display: block; + content: ''; + clear: left; +} + +/* -- relbar ---------------------------------------------------------------- */ + +div.related { + width: 100%; + font-size: 90%; +} + +div.related h3 { + display: none; +} + +div.related ul { + margin: 0; + padding: 0 0 0 10px; + list-style: none; +} + +div.related li { + display: inline; +} + +div.related li.right { + float: right; + margin-right: 5px; +} + +/* -- sidebar --------------------------------------------------------------- */ + +div.sphinxsidebarwrapper { + padding: 10px 5px 0 10px; +} + +div.sphinxsidebar { + float: left; + width: 270px; + margin-left: -100%; + font-size: 90%; + word-wrap: break-word; + overflow-wrap : break-word; +} + +div.sphinxsidebar ul { + list-style: none; +} + +div.sphinxsidebar ul ul, +div.sphinxsidebar ul.want-points { + margin-left: 20px; + list-style: square; +} + +div.sphinxsidebar ul ul { + margin-top: 0; + margin-bottom: 0; +} + +div.sphinxsidebar form { + margin-top: 10px; +} + +div.sphinxsidebar input { + border: 1px solid #98dbcc; + font-family: sans-serif; + font-size: 1em; +} + +div.sphinxsidebar #searchbox form.search { + overflow: hidden; +} + +div.sphinxsidebar #searchbox input[type="text"] { + float: left; + width: 80%; + padding: 0.25em; + box-sizing: border-box; +} + +div.sphinxsidebar #searchbox input[type="submit"] { + float: left; + width: 20%; + border-left: none; + padding: 0.25em; + box-sizing: border-box; +} + + +img { + border: 0; + max-width: 100%; +} + +/* -- search page ----------------------------------------------------------- */ + +ul.search { + margin: 10px 0 0 20px; + padding: 0; +} + +ul.search li { + padding: 5px 0 5px 20px; + background-image: url(file.png); + background-repeat: no-repeat; + background-position: 0 7px; +} + +ul.search li a { + font-weight: bold; +} + +ul.search li p.context { + color: #888; + margin: 2px 0 0 30px; + text-align: left; +} + +ul.keywordmatches li.goodmatch a { + font-weight: bold; +} + +/* -- index page ------------------------------------------------------------ */ + +table.contentstable { + width: 90%; + margin-left: auto; + margin-right: auto; +} + +table.contentstable p.biglink { + line-height: 150%; +} + +a.biglink { + font-size: 1.3em; +} + +span.linkdescr { + font-style: italic; + padding-top: 5px; + font-size: 90%; +} + +/* -- general index --------------------------------------------------------- */ + +table.indextable { + width: 100%; +} + +table.indextable td { + text-align: left; + vertical-align: top; +} + +table.indextable ul { + margin-top: 0; + margin-bottom: 0; + list-style-type: none; +} + +table.indextable > tbody > tr > td > ul { + padding-left: 0em; +} + +table.indextable tr.pcap { + height: 10px; +} + +table.indextable tr.cap { + margin-top: 10px; + background-color: #f2f2f2; +} + +img.toggler { + margin-right: 3px; + margin-top: 3px; + cursor: pointer; +} + +div.modindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +div.genindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +/* -- domain module index --------------------------------------------------- */ + +table.modindextable td { + padding: 2px; + border-collapse: collapse; +} + +/* -- general body styles --------------------------------------------------- */ + +div.body { + min-width: 360px; + max-width: 800px; +} + +div.body p, div.body dd, div.body li, div.body blockquote { + -moz-hyphens: auto; + -ms-hyphens: auto; + -webkit-hyphens: auto; + hyphens: auto; +} + +a.headerlink { + visibility: hidden; +} + +a:visited { + color: #551A8B; +} + +h1:hover > a.headerlink, +h2:hover > a.headerlink, +h3:hover > a.headerlink, +h4:hover > a.headerlink, +h5:hover > a.headerlink, +h6:hover > a.headerlink, +dt:hover > a.headerlink, +caption:hover > a.headerlink, +p.caption:hover > a.headerlink, +div.code-block-caption:hover > a.headerlink { + visibility: visible; +} + +div.body p.caption { + text-align: inherit; +} + +div.body td { + text-align: left; +} + +.first { + margin-top: 0 !important; +} + +p.rubric { + margin-top: 30px; + font-weight: bold; +} + +img.align-left, figure.align-left, .figure.align-left, object.align-left { + clear: left; + float: left; + margin-right: 1em; +} + +img.align-right, figure.align-right, .figure.align-right, object.align-right { + clear: right; + float: right; + margin-left: 1em; +} + +img.align-center, figure.align-center, .figure.align-center, object.align-center { + display: block; + margin-left: auto; + margin-right: auto; +} + +img.align-default, figure.align-default, .figure.align-default { + display: block; + margin-left: auto; + margin-right: auto; +} + +.align-left { + text-align: left; +} + +.align-center { + text-align: center; +} + +.align-default { + text-align: center; +} + +.align-right { + text-align: right; +} + +/* -- sidebars -------------------------------------------------------------- */ + +div.sidebar, +aside.sidebar { + margin: 0 0 0.5em 1em; + border: 1px solid #ddb; + padding: 7px; + background-color: #ffe; + width: 40%; + float: right; + clear: right; + overflow-x: auto; +} + +p.sidebar-title { + font-weight: bold; +} + +nav.contents, +aside.topic, +div.admonition, div.topic, blockquote { + clear: left; +} + +/* -- topics ---------------------------------------------------------------- */ + +nav.contents, +aside.topic, +div.topic { + border: 1px solid #ccc; + padding: 7px; + margin: 10px 0 10px 0; +} + +p.topic-title { + font-size: 1.1em; + font-weight: bold; + margin-top: 10px; +} + +/* -- admonitions ----------------------------------------------------------- */ + +div.admonition { + margin-top: 10px; + margin-bottom: 10px; + padding: 7px; +} + +div.admonition dt { + font-weight: bold; +} + +p.admonition-title { + margin: 0px 10px 5px 0px; + font-weight: bold; +} + +div.body p.centered { + text-align: center; + margin-top: 25px; +} + +/* -- content of sidebars/topics/admonitions -------------------------------- */ + +div.sidebar > :last-child, +aside.sidebar > :last-child, +nav.contents > :last-child, +aside.topic > :last-child, +div.topic > :last-child, +div.admonition > :last-child { + margin-bottom: 0; +} + +div.sidebar::after, +aside.sidebar::after, +nav.contents::after, +aside.topic::after, +div.topic::after, +div.admonition::after, +blockquote::after { + display: block; + content: ''; + clear: both; +} + +/* -- tables ---------------------------------------------------------------- */ + +table.docutils { + margin-top: 10px; + margin-bottom: 10px; + border: 0; + border-collapse: collapse; +} + +table.align-center { + margin-left: auto; + margin-right: auto; +} + +table.align-default { + margin-left: auto; + margin-right: auto; +} + +table caption span.caption-number { + font-style: italic; +} + +table caption span.caption-text { +} + +table.docutils td, table.docutils th { + padding: 1px 8px 1px 5px; + border-top: 0; + border-left: 0; + border-right: 0; + border-bottom: 1px solid #aaa; +} + +th { + text-align: left; + padding-right: 5px; +} + +table.citation { + border-left: solid 1px gray; + margin-left: 1px; +} + +table.citation td { + border-bottom: none; +} + +th > :first-child, +td > :first-child { + margin-top: 0px; +} + +th > :last-child, +td > :last-child { + margin-bottom: 0px; +} + +/* -- figures --------------------------------------------------------------- */ + +div.figure, figure { + margin: 0.5em; + padding: 0.5em; +} + +div.figure p.caption, figcaption { + padding: 0.3em; +} + +div.figure p.caption span.caption-number, +figcaption span.caption-number { + font-style: italic; +} + +div.figure p.caption span.caption-text, +figcaption span.caption-text { +} + +/* -- field list styles ----------------------------------------------------- */ + +table.field-list td, table.field-list th { + border: 0 !important; +} + +.field-list ul { + margin: 0; + padding-left: 1em; +} + +.field-list p { + margin: 0; +} + +.field-name { + -moz-hyphens: manual; + -ms-hyphens: manual; + -webkit-hyphens: manual; + hyphens: manual; +} + +/* -- hlist styles ---------------------------------------------------------- */ + +table.hlist { + margin: 1em 0; +} + +table.hlist td { + vertical-align: top; +} + +/* -- object description styles --------------------------------------------- */ + +.sig { + font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; +} + +.sig-name, code.descname { + background-color: transparent; + font-weight: bold; +} + +.sig-name { + font-size: 1.1em; +} + +code.descname { + font-size: 1.2em; +} + +.sig-prename, code.descclassname { + background-color: transparent; +} + +.optional { + font-size: 1.3em; +} + +.sig-paren { + font-size: larger; +} + +.sig-param.n { + font-style: italic; +} + +/* C++ specific styling */ + +.sig-inline.c-texpr, +.sig-inline.cpp-texpr { + font-family: unset; +} + +.sig.c .k, .sig.c .kt, +.sig.cpp .k, .sig.cpp .kt { + color: #0033B3; +} + +.sig.c .m, +.sig.cpp .m { + color: #1750EB; +} + +.sig.c .s, .sig.c .sc, +.sig.cpp .s, .sig.cpp .sc { + color: #067D17; +} + + +/* -- other body styles ----------------------------------------------------- */ + +ol.arabic { + list-style: decimal; +} + +ol.loweralpha { + list-style: lower-alpha; +} + +ol.upperalpha { + list-style: upper-alpha; +} + +ol.lowerroman { + list-style: lower-roman; +} + +ol.upperroman { + list-style: upper-roman; +} + +:not(li) > ol > li:first-child > :first-child, +:not(li) > ul > li:first-child > :first-child { + margin-top: 0px; +} + +:not(li) > ol > li:last-child > :last-child, +:not(li) > ul > li:last-child > :last-child { + margin-bottom: 0px; +} + +ol.simple ol p, +ol.simple ul p, +ul.simple ol p, +ul.simple ul p { + margin-top: 0; +} + +ol.simple > li:not(:first-child) > p, +ul.simple > li:not(:first-child) > p { + margin-top: 0; +} + +ol.simple p, +ul.simple p { + margin-bottom: 0; +} + +aside.footnote > span, +div.citation > span { + float: left; +} +aside.footnote > span:last-of-type, +div.citation > span:last-of-type { + padding-right: 0.5em; +} +aside.footnote > p { + margin-left: 2em; +} +div.citation > p { + margin-left: 4em; +} +aside.footnote > p:last-of-type, +div.citation > p:last-of-type { + margin-bottom: 0em; +} +aside.footnote > p:last-of-type:after, +div.citation > p:last-of-type:after { + content: ""; + clear: both; +} + +dl.field-list { + display: grid; + grid-template-columns: fit-content(30%) auto; +} + +dl.field-list > dt { + font-weight: bold; + word-break: break-word; + padding-left: 0.5em; + padding-right: 5px; +} + +dl.field-list > dd { + padding-left: 0.5em; + margin-top: 0em; + margin-left: 0em; + margin-bottom: 0em; +} + +dl { + margin-bottom: 15px; +} + +dd > :first-child { + margin-top: 0px; +} + +dd ul, dd table { + margin-bottom: 10px; +} + +dd { + margin-top: 3px; + margin-bottom: 10px; + margin-left: 30px; +} + +.sig dd { + margin-top: 0px; + margin-bottom: 0px; +} + +.sig dl { + margin-top: 0px; + margin-bottom: 0px; +} + +dl > dd:last-child, +dl > dd:last-child > :last-child { + margin-bottom: 0; +} + +dt:target, span.highlighted { + background-color: #fbe54e; +} + +rect.highlighted { + fill: #fbe54e; +} + +dl.glossary dt { + font-weight: bold; + font-size: 1.1em; +} + +.versionmodified { + font-style: italic; +} + +.system-message { + background-color: #fda; + padding: 5px; + border: 3px solid red; +} + +.footnote:target { + background-color: #ffa; +} + +.line-block { + display: block; + margin-top: 1em; + margin-bottom: 1em; +} + +.line-block .line-block { + margin-top: 0; + margin-bottom: 0; + margin-left: 1.5em; +} + +.guilabel, .menuselection { + font-family: sans-serif; +} + +.accelerator { + text-decoration: underline; +} + +.classifier { + font-style: oblique; +} + +.classifier:before { + font-style: normal; + margin: 0 0.5em; + content: ":"; + display: inline-block; +} + +abbr, acronym { + border-bottom: dotted 1px; + cursor: help; +} + +.translated { + background-color: rgba(207, 255, 207, 0.2) +} + +.untranslated { + background-color: rgba(255, 207, 207, 0.2) +} + +/* -- code displays --------------------------------------------------------- */ + +pre { + overflow: auto; + overflow-y: hidden; /* fixes display issues on Chrome browsers */ +} + +pre, div[class*="highlight-"] { + clear: both; +} + +span.pre { + -moz-hyphens: none; + -ms-hyphens: none; + -webkit-hyphens: none; + hyphens: none; + white-space: nowrap; +} + +div[class*="highlight-"] { + margin: 1em 0; +} + +td.linenos pre { + border: 0; + background-color: transparent; + color: #aaa; +} + +table.highlighttable { + display: block; +} + +table.highlighttable tbody { + display: block; +} + +table.highlighttable tr { + display: flex; +} + +table.highlighttable td { + margin: 0; + padding: 0; +} + +table.highlighttable td.linenos { + padding-right: 0.5em; +} + +table.highlighttable td.code { + flex: 1; + overflow: hidden; +} + +.highlight .hll { + display: block; +} + +div.highlight pre, +table.highlighttable pre { + margin: 0; +} + +div.code-block-caption + div { + margin-top: 0; +} + +div.code-block-caption { + margin-top: 1em; + padding: 2px 5px; + font-size: small; +} + +div.code-block-caption code { + background-color: transparent; +} + +table.highlighttable td.linenos, +span.linenos, +div.highlight span.gp { /* gp: Generic.Prompt */ + user-select: none; + -webkit-user-select: text; /* Safari fallback only */ + -webkit-user-select: none; /* Chrome/Safari */ + -moz-user-select: none; /* Firefox */ + -ms-user-select: none; /* IE10+ */ +} + +div.code-block-caption span.caption-number { + padding: 0.1em 0.3em; + font-style: italic; +} + +div.code-block-caption span.caption-text { +} + +div.literal-block-wrapper { + margin: 1em 0; +} + +code.xref, a code { + background-color: transparent; + font-weight: bold; +} + +h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { + background-color: transparent; +} + +.viewcode-link { + float: right; +} + +.viewcode-back { + float: right; + font-family: sans-serif; +} + +div.viewcode-block:target { + margin: -1px -10px; + padding: 0 10px; +} + +/* -- math display ---------------------------------------------------------- */ + +img.math { + vertical-align: middle; +} + +div.body div.math p { + text-align: center; +} + +span.eqno { + float: right; +} + +span.eqno a.headerlink { + position: absolute; + z-index: 1; +} + +div.math:hover a.headerlink { + visibility: visible; +} + +/* -- printout stylesheet --------------------------------------------------- */ + +@media print { + div.document, + div.documentwrapper, + div.bodywrapper { + margin: 0 !important; + width: 100%; + } + + div.sphinxsidebar, + div.related, + div.footer, + #top-link { + display: none; + } +} \ No newline at end of file diff --git a/v0.10.x/_static/binder_badge_logo.svg b/v0.10.x/_static/binder_badge_logo.svg new file mode 100644 index 000000000..327f6b639 --- /dev/null +++ b/v0.10.x/_static/binder_badge_logo.svg @@ -0,0 +1 @@ + launchlaunchbinderbinder \ No newline at end of file diff --git a/v0.10.x/_static/broken_example.png b/v0.10.x/_static/broken_example.png new file mode 100644 index 000000000..4fea24e7d Binary files /dev/null and b/v0.10.x/_static/broken_example.png differ diff --git a/v0.10.x/_static/check-solid.svg b/v0.10.x/_static/check-solid.svg new file mode 100644 index 000000000..92fad4b5c --- /dev/null +++ b/v0.10.x/_static/check-solid.svg @@ -0,0 +1,4 @@ + + + + diff --git a/v0.10.x/_static/clipboard.min.js b/v0.10.x/_static/clipboard.min.js new file mode 100644 index 000000000..54b3c4638 --- /dev/null +++ b/v0.10.x/_static/clipboard.min.js @@ -0,0 +1,7 @@ +/*! + * clipboard.js v2.0.8 + * https://clipboardjs.com/ + * + * Licensed MIT © Zeno Rocha + */ +!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.ClipboardJS=e():t.ClipboardJS=e()}(this,function(){return n={686:function(t,e,n){"use strict";n.d(e,{default:function(){return o}});var e=n(279),i=n.n(e),e=n(370),u=n.n(e),e=n(817),c=n.n(e);function a(t){try{return document.execCommand(t)}catch(t){return}}var f=function(t){t=c()(t);return a("cut"),t};var l=function(t){var e,n,o,r=1 + + + + diff --git a/v0.10.x/_static/copybutton.css b/v0.10.x/_static/copybutton.css new file mode 100644 index 000000000..f1916ec7d --- /dev/null +++ b/v0.10.x/_static/copybutton.css @@ -0,0 +1,94 @@ +/* Copy buttons */ +button.copybtn { + position: absolute; + display: flex; + top: .3em; + right: .3em; + width: 1.7em; + height: 1.7em; + opacity: 0; + transition: opacity 0.3s, border .3s, background-color .3s; + user-select: none; + padding: 0; + border: none; + outline: none; + border-radius: 0.4em; + /* The colors that GitHub uses */ + border: #1b1f2426 1px solid; + background-color: #f6f8fa; + color: #57606a; +} + +button.copybtn.success { + border-color: #22863a; + color: #22863a; +} + +button.copybtn svg { + stroke: currentColor; + width: 1.5em; + height: 1.5em; + padding: 0.1em; +} + +div.highlight { + position: relative; +} + +/* Show the copybutton */ +.highlight:hover button.copybtn, button.copybtn.success { + opacity: 1; +} + +.highlight button.copybtn:hover { + background-color: rgb(235, 235, 235); +} + +.highlight button.copybtn:active { + background-color: rgb(187, 187, 187); +} + +/** + * A minimal CSS-only tooltip copied from: + * https://codepen.io/mildrenben/pen/rVBrpK + * + * To use, write HTML like the following: + * + *

Short

+ */ + .o-tooltip--left { + position: relative; + } + + .o-tooltip--left:after { + opacity: 0; + visibility: hidden; + position: absolute; + content: attr(data-tooltip); + padding: .2em; + font-size: .8em; + left: -.2em; + background: grey; + color: white; + white-space: nowrap; + z-index: 2; + border-radius: 2px; + transform: translateX(-102%) translateY(0); + transition: opacity 0.2s cubic-bezier(0.64, 0.09, 0.08, 1), transform 0.2s cubic-bezier(0.64, 0.09, 0.08, 1); +} + +.o-tooltip--left:hover:after { + display: block; + opacity: 1; + visibility: visible; + transform: translateX(-100%) translateY(0); + transition: opacity 0.2s cubic-bezier(0.64, 0.09, 0.08, 1), transform 0.2s cubic-bezier(0.64, 0.09, 0.08, 1); + transition-delay: .5s; +} + +/* By default the copy button shouldn't show up when printing a page */ +@media print { + button.copybtn { + display: none; + } +} diff --git a/v0.10.x/_static/copybutton.js b/v0.10.x/_static/copybutton.js new file mode 100644 index 000000000..2ea7ff3e2 --- /dev/null +++ b/v0.10.x/_static/copybutton.js @@ -0,0 +1,248 @@ +// Localization support +const messages = { + 'en': { + 'copy': 'Copy', + 'copy_to_clipboard': 'Copy to clipboard', + 'copy_success': 'Copied!', + 'copy_failure': 'Failed to copy', + }, + 'es' : { + 'copy': 'Copiar', + 'copy_to_clipboard': 'Copiar al portapapeles', + 'copy_success': '¡Copiado!', + 'copy_failure': 'Error al copiar', + }, + 'de' : { + 'copy': 'Kopieren', + 'copy_to_clipboard': 'In die Zwischenablage kopieren', + 'copy_success': 'Kopiert!', + 'copy_failure': 'Fehler beim Kopieren', + }, + 'fr' : { + 'copy': 'Copier', + 'copy_to_clipboard': 'Copier dans le presse-papier', + 'copy_success': 'Copié !', + 'copy_failure': 'Échec de la copie', + }, + 'ru': { + 'copy': 'Скопировать', + 'copy_to_clipboard': 'Скопировать в буфер', + 'copy_success': 'Скопировано!', + 'copy_failure': 'Не удалось скопировать', + }, + 'zh-CN': { + 'copy': '复制', + 'copy_to_clipboard': '复制到剪贴板', + 'copy_success': '复制成功!', + 'copy_failure': '复制失败', + }, + 'it' : { + 'copy': 'Copiare', + 'copy_to_clipboard': 'Copiato negli appunti', + 'copy_success': 'Copiato!', + 'copy_failure': 'Errore durante la copia', + } +} + +let locale = 'en' +if( document.documentElement.lang !== undefined + && messages[document.documentElement.lang] !== undefined ) { + locale = document.documentElement.lang +} + +let doc_url_root = DOCUMENTATION_OPTIONS.URL_ROOT; +if (doc_url_root == '#') { + doc_url_root = ''; +} + +/** + * SVG files for our copy buttons + */ +let iconCheck = ` + ${messages[locale]['copy_success']} + + +` + +// If the user specified their own SVG use that, otherwise use the default +let iconCopy = ``; +if (!iconCopy) { + iconCopy = ` + ${messages[locale]['copy_to_clipboard']} + + + +` +} + +/** + * Set up copy/paste for code blocks + */ + +const runWhenDOMLoaded = cb => { + if (document.readyState != 'loading') { + cb() + } else if (document.addEventListener) { + document.addEventListener('DOMContentLoaded', cb) + } else { + document.attachEvent('onreadystatechange', function() { + if (document.readyState == 'complete') cb() + }) + } +} + +const codeCellId = index => `codecell${index}` + +// Clears selected text since ClipboardJS will select the text when copying +const clearSelection = () => { + if (window.getSelection) { + window.getSelection().removeAllRanges() + } else if (document.selection) { + document.selection.empty() + } +} + +// Changes tooltip text for a moment, then changes it back +// We want the timeout of our `success` class to be a bit shorter than the +// tooltip and icon change, so that we can hide the icon before changing back. +var timeoutIcon = 2000; +var timeoutSuccessClass = 1500; + +const temporarilyChangeTooltip = (el, oldText, newText) => { + el.setAttribute('data-tooltip', newText) + el.classList.add('success') + // Remove success a little bit sooner than we change the tooltip + // So that we can use CSS to hide the copybutton first + setTimeout(() => el.classList.remove('success'), timeoutSuccessClass) + setTimeout(() => el.setAttribute('data-tooltip', oldText), timeoutIcon) +} + +// Changes the copy button icon for two seconds, then changes it back +const temporarilyChangeIcon = (el) => { + el.innerHTML = iconCheck; + setTimeout(() => {el.innerHTML = iconCopy}, timeoutIcon) +} + +const addCopyButtonToCodeCells = () => { + // If ClipboardJS hasn't loaded, wait a bit and try again. This + // happens because we load ClipboardJS asynchronously. + if (window.ClipboardJS === undefined) { + setTimeout(addCopyButtonToCodeCells, 250) + return + } + + // Add copybuttons to all of our code cells + const COPYBUTTON_SELECTOR = 'div.highlight pre'; + const codeCells = document.querySelectorAll(COPYBUTTON_SELECTOR) + codeCells.forEach((codeCell, index) => { + const id = codeCellId(index) + codeCell.setAttribute('id', id) + + const clipboardButton = id => + `` + codeCell.insertAdjacentHTML('afterend', clipboardButton(id)) + }) + +function escapeRegExp(string) { + return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string +} + +/** + * Removes excluded text from a Node. + * + * @param {Node} target Node to filter. + * @param {string} exclude CSS selector of nodes to exclude. + * @returns {DOMString} Text from `target` with text removed. + */ +function filterText(target, exclude) { + const clone = target.cloneNode(true); // clone as to not modify the live DOM + if (exclude) { + // remove excluded nodes + clone.querySelectorAll(exclude).forEach(node => node.remove()); + } + return clone.innerText; +} + +// Callback when a copy button is clicked. Will be passed the node that was clicked +// should then grab the text and replace pieces of text that shouldn't be used in output +function formatCopyText(textContent, copybuttonPromptText, isRegexp = false, onlyCopyPromptLines = true, removePrompts = true, copyEmptyLines = true, lineContinuationChar = "", hereDocDelim = "") { + var regexp; + var match; + + // Do we check for line continuation characters and "HERE-documents"? + var useLineCont = !!lineContinuationChar + var useHereDoc = !!hereDocDelim + + // create regexp to capture prompt and remaining line + if (isRegexp) { + regexp = new RegExp('^(' + copybuttonPromptText + ')(.*)') + } else { + regexp = new RegExp('^(' + escapeRegExp(copybuttonPromptText) + ')(.*)') + } + + const outputLines = []; + var promptFound = false; + var gotLineCont = false; + var gotHereDoc = false; + const lineGotPrompt = []; + for (const line of textContent.split('\n')) { + match = line.match(regexp) + if (match || gotLineCont || gotHereDoc) { + promptFound = regexp.test(line) + lineGotPrompt.push(promptFound) + if (removePrompts && promptFound) { + outputLines.push(match[2]) + } else { + outputLines.push(line) + } + gotLineCont = line.endsWith(lineContinuationChar) & useLineCont + if (line.includes(hereDocDelim) & useHereDoc) + gotHereDoc = !gotHereDoc + } else if (!onlyCopyPromptLines) { + outputLines.push(line) + } else if (copyEmptyLines && line.trim() === '') { + outputLines.push(line) + } + } + + // If no lines with the prompt were found then just use original lines + if (lineGotPrompt.some(v => v === true)) { + textContent = outputLines.join('\n'); + } + + // Remove a trailing newline to avoid auto-running when pasting + if (textContent.endsWith("\n")) { + textContent = textContent.slice(0, -1) + } + return textContent +} + + +var copyTargetText = (trigger) => { + var target = document.querySelector(trigger.attributes['data-clipboard-target'].value); + + // get filtered text + let exclude = '.linenos'; + + let text = filterText(target, exclude); + return formatCopyText(text, '', false, true, true, true, '', '') +} + + // Initialize with a callback so we can modify the text before copy + const clipboard = new ClipboardJS('.copybtn', {text: copyTargetText}) + + // Update UI with error/success messages + clipboard.on('success', event => { + clearSelection() + temporarilyChangeTooltip(event.trigger, messages[locale]['copy'], messages[locale]['copy_success']) + temporarilyChangeIcon(event.trigger) + }) + + clipboard.on('error', event => { + temporarilyChangeTooltip(event.trigger, messages[locale]['copy'], messages[locale]['copy_failure']) + }) +} + +runWhenDOMLoaded(addCopyButtonToCodeCells) \ No newline at end of file diff --git a/v0.10.x/_static/copybutton_funcs.js b/v0.10.x/_static/copybutton_funcs.js new file mode 100644 index 000000000..dbe1aaad7 --- /dev/null +++ b/v0.10.x/_static/copybutton_funcs.js @@ -0,0 +1,73 @@ +function escapeRegExp(string) { + return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string +} + +/** + * Removes excluded text from a Node. + * + * @param {Node} target Node to filter. + * @param {string} exclude CSS selector of nodes to exclude. + * @returns {DOMString} Text from `target` with text removed. + */ +export function filterText(target, exclude) { + const clone = target.cloneNode(true); // clone as to not modify the live DOM + if (exclude) { + // remove excluded nodes + clone.querySelectorAll(exclude).forEach(node => node.remove()); + } + return clone.innerText; +} + +// Callback when a copy button is clicked. Will be passed the node that was clicked +// should then grab the text and replace pieces of text that shouldn't be used in output +export function formatCopyText(textContent, copybuttonPromptText, isRegexp = false, onlyCopyPromptLines = true, removePrompts = true, copyEmptyLines = true, lineContinuationChar = "", hereDocDelim = "") { + var regexp; + var match; + + // Do we check for line continuation characters and "HERE-documents"? + var useLineCont = !!lineContinuationChar + var useHereDoc = !!hereDocDelim + + // create regexp to capture prompt and remaining line + if (isRegexp) { + regexp = new RegExp('^(' + copybuttonPromptText + ')(.*)') + } else { + regexp = new RegExp('^(' + escapeRegExp(copybuttonPromptText) + ')(.*)') + } + + const outputLines = []; + var promptFound = false; + var gotLineCont = false; + var gotHereDoc = false; + const lineGotPrompt = []; + for (const line of textContent.split('\n')) { + match = line.match(regexp) + if (match || gotLineCont || gotHereDoc) { + promptFound = regexp.test(line) + lineGotPrompt.push(promptFound) + if (removePrompts && promptFound) { + outputLines.push(match[2]) + } else { + outputLines.push(line) + } + gotLineCont = line.endsWith(lineContinuationChar) & useLineCont + if (line.includes(hereDocDelim) & useHereDoc) + gotHereDoc = !gotHereDoc + } else if (!onlyCopyPromptLines) { + outputLines.push(line) + } else if (copyEmptyLines && line.trim() === '') { + outputLines.push(line) + } + } + + // If no lines with the prompt were found then just use original lines + if (lineGotPrompt.some(v => v === true)) { + textContent = outputLines.join('\n'); + } + + // Remove a trailing newline to avoid auto-running when pasting + if (textContent.endsWith("\n")) { + textContent = textContent.slice(0, -1) + } + return textContent +} diff --git a/v0.10.x/_static/css/blog.css b/v0.10.x/_static/css/blog.css new file mode 100644 index 000000000..07a2e540e --- /dev/null +++ b/v0.10.x/_static/css/blog.css @@ -0,0 +1,6 @@ +ul.ablog-archive {list-style: none; overflow: auto; margin-left: 0px} +ul.ablog-archive li {float: left; margin-right: 5px; font-size: 80%} +ul.postlist a {font-style: italic;} +ul.postlist-style-disc {list-style-type: disc;} +ul.postlist-style-none {list-style-type: none;} +ul.postlist-style-circle {list-style-type: circle;} diff --git a/v0.10.x/_static/css/community.css b/v0.10.x/_static/css/community.css new file mode 100644 index 000000000..eab64d108 --- /dev/null +++ b/v0.10.x/_static/css/community.css @@ -0,0 +1,32 @@ +/* CSS for showing community */ +.join-us__container { + display: flex; +} + +.join-us__icon-background { + width: 46px; + height: 46px; + border-radius: 50%; + + display: flex; + justify-content: center; + align-items: center; + + background-color: rgba(153, 0, 0, 0.1); + box-shadow: rgba(99, 99, 99, 0.2) 0px 2px 8px 0px; + transition: all 0.2s ease; + + text-decoration: none !important; + margin-right: 16px; + +} + +.join-us__icon-background:hover { + box-shadow: rgba(153, 0, 0, 0.3) 0px 8px 24px; +} + +.join-us__icon { + font-size: 22px; + color: rgb(153, 0, 0); + transition: all 0.2s ease; +} diff --git a/v0.10.x/_static/css/comp-soft.css b/v0.10.x/_static/css/comp-soft.css new file mode 100644 index 000000000..7198f8892 --- /dev/null +++ b/v0.10.x/_static/css/comp-soft.css @@ -0,0 +1,76 @@ +.comp-soft-wrapper { + + width: 700px; + margin: 0 auto; + + --s: 150px; /* size */ + --m: 8px; /* margin */ + --f: calc(1.732 * var(--s) + 4 * var(--m) - 1px); +} + +@media (max-width: 767px) { + .comp-soft-wrapper { + + width: 100vw; + margin: 0 auto; + } +} + +.comp-soft-section { + width: 100vw; + background-color: var(--colorPrimaryDark); + padding: 50px 0; +} + +.comp-soft-title { + display: flex; + justify-content: center; + width: 100%; + margin-bottom: 20px; + + letter-spacing: 1.5px; + font-size: 27px; + font-weight: bold; + + color: white; +} + +.comp-soft-container { + display: flex; + justify-content: center; +} + +@media (max-width: 767px) { + .comp-soft-container { + flex-wrap: wrap; + justify-content: space-evenly; + } +} + +.comp-soft-container .comp-soft { + width: var(--s); + min-width: var(--s); + margin: var(--m) var(--m) 0; + height: var(--s); + font-size:initial; + border-radius: 50%; + background: white; + box-shadow: rgba(0, 0, 0, 0.24) 0px 3px 8px; +} + +@media (max-width: 767px) { + .comp-soft-container .comp-soft { + margin: var(--m); + } +} + +.comp-soft-image-holder { + display: flex; + align-items: center; + height: var(--s); + justify-content: center; +} + +.comp-soft-image-holder img { + max-width: 80%; +} \ No newline at end of file diff --git a/v0.10.x/_static/css/custom.css b/v0.10.x/_static/css/custom.css new file mode 100644 index 000000000..fa3fbba39 --- /dev/null +++ b/v0.10.x/_static/css/custom.css @@ -0,0 +1,163 @@ +/* Provided by Sphinx's 'basic' theme, and included in the final set of assets */ +@import "../basic.css"; + +/* Adding css of different pages */ +@import "./community.css"; + +/* Providing common css files */ +@import "./navbar.css"; + + +:root { + /***************************************************************************** + * Theme config + **/ + --pst-header-height: 60px; + + /***************************************************************************** + * Font size + **/ + --pst-font-size-base: 15px; /* base font size - applied at body / html level */ + + /* heading font sizes */ + --pst-font-size-h1: 36px; + --pst-font-size-h2: 32px; + --pst-font-size-h3: 26px; + --pst-font-size-h4: 21px; + --pst-font-size-h5: 18px; + --pst-font-size-h6: 16px; + + /* smaller then heading font sizes*/ + --pst-font-size-milli: 12px; + + --pst-sidebar-font-size: 0.9em; + --pst-sidebar-caption-font-size: 0.9em; + + /***************************************************************************** + * Font family + **/ + /* These are adapted from https://systemfontstack.com/ */ + --pst-font-family-base-system: -apple-system, BlinkMacSystemFont, Segoe UI, + "Helvetica Neue", Arial, sans-serif, Apple Color Emoji, Segoe UI Emoji, + Segoe UI Symbol; + --pst-font-family-monospace-system: "SFMono-Regular", Menlo, Consolas, Monaco, + Liberation Mono, Lucida Console, monospace; + + --pst-font-family-base: var(--pst-font-family-base-system); + --pst-font-family-heading: var(--pst-font-family-base); + --pst-font-family-monospace: var(--pst-font-family-monospace-system); + + /***************************************************************************** + * Color + * + * Colors are defined in rgb string way, "red, green, blue" + **/ + /* --pst-color-primary: 19, 6, 84; */ + --pst-color-primary: 153, 0, 0; + --pst-color-success: 40, 167, 69; + --pst-color-info: 0, 123, 255; /*23, 162, 184;*/ + --pst-color-warning: 255, 193, 7; + --pst-color-danger: 220, 53, 69; + --pst-color-text-base: 51, 51, 51; + + --pst-color-h1: var(--pst-color-primary); + --pst-color-h2: var(--pst-color-primary); + --pst-color-h3: var(--pst-color-text-base); + --pst-color-h4: var(--pst-color-text-base); + --pst-color-h5: var(--pst-color-text-base); + --pst-color-h6: var(--pst-color-text-base); + --pst-color-paragraph: var(--pst-color-text-base); + --pst-color-link: 153, 0, 0; + --pst-color-link-hover: 227, 46, 0; + --pst-color-headerlink: 198, 15, 15; + --pst-color-headerlink-hover: 255, 255, 255; + --pst-color-preformatted-text: 34, 34, 34; + --pst-color-preformatted-background: 250, 250, 250; + --pst-color-inline-code: 232, 62, 140; + + --pst-color-active-navigation: 19, 6, 84; + --pst-color-navbar-link: 153, 0, 0; + --pst-color-navbar-link-hover: 77, 171, 207; + --pst-color-navbar-link-active: var(--pst-color-active-navigation); + --pst-color-sidebar-link: 77, 77, 77; + --pst-color-sidebar-link-hover: 153, 0, 0; + --pst-color-sidebar-link-active: var(--pst-color-active-navigation); + --pst-color-sidebar-expander-background-hover: 244, 244, 244; + --pst-color-sidebar-caption: 77, 77, 77; + --pst-color-toc-link: 119, 117, 122; + --pst-color-toc-link-hover: 77, 171, 207; + --pst-color-toc-link-active: var(--pst-color-active-navigation); + + /***************************************************************************** + * Icon + **/ + + /* font awesome icons*/ + --pst-icon-check-circle: "\f058"; + --pst-icon-info-circle: "\f05a"; + --pst-icon-exclamation-triangle: "\f071"; + --pst-icon-exclamation-circle: "\f06a"; + --pst-icon-times-circle: "\f057"; + --pst-icon-lightbulb: "\f0eb"; + + /***************************************************************************** + * Admonitions + **/ + + --pst-color-admonition-default: var(--pst-color-info); + --pst-color-admonition-note: var(--pst-color-info); + --pst-color-admonition-attention: var(--pst-color-warning); + --pst-color-admonition-caution: var(--pst-color-warning); + --pst-color-admonition-warning: var(--pst-color-warning); + --pst-color-admonition-danger: var(--pst-color-danger); + --pst-color-admonition-error: var(--pst-color-danger); + --pst-color-admonition-hint: var(--pst-color-success); + --pst-color-admonition-tip: var(--pst-color-success); + --pst-color-admonition-important: var(--pst-color-success); + + --pst-icon-admonition-default: var(--pst-icon-info-circle); + --pst-icon-admonition-note: var(--pst-icon-info-circle); + --pst-icon-admonition-attention: var(--pst-icon-exclamation-circle); + --pst-icon-admonition-caution: var(--pst-icon-exclamation-triangle); + --pst-icon-admonition-warning: var(--pst-icon-exclamation-triangle); + --pst-icon-admonition-danger: var(--pst-icon-exclamation-triangle); + --pst-icon-admonition-error: var(--pst-icon-times-circle); + --pst-icon-admonition-hint: var(--pst-icon-lightbulb); + --pst-icon-admonition-tip: var(--pst-icon-lightbulb); + --pst-icon-admonition-important: var(--pst-icon-exclamation-circle); + + /***************************************************************************** + * versionmodified + **/ + + --pst-color-versionmodified-default: var(--pst-color-info); + --pst-color-versionmodified-added: var(--pst-color-success); + --pst-color-versionmodified-changed: var(--pst-color-warning); + --pst-color-versionmodified-deprecated: var(--pst-color-danger); + + --pst-icon-versionmodified-default: var(--pst-icon-exclamation-circle); + --pst-icon-versionmodified-added: var(--pst-icon-exclamation-circle); + --pst-icon-versionmodified-changed: var(--pst-icon-exclamation-circle); + --pst-icon-versionmodified-deprecated: var(--pst-icon-exclamation-circle); +} +html[data-theme="light"] { + --pst-color-primary: rgb(153, 0, 0); + --pst-color-success: rgb(40, 167, 69); + --pst-color-info: rgb(0, 123, 255); /*23, 162, 184;*/ + --pst-color-warning: rgb(255, 193, 7); + --pst-color-danger: rgb(220, 53, 69); + --pst-color-text-base: rgb(51, 51, 51); + + --pst-color-link: rgb(153, 0, 0); + --pst-color-link-hover: rgb(227, 46, 0); + --pst-color-headerlink: rgb(198, 15, 15); + --pst-color-headerlink-hover: rgb(255, 255, 255); + --pst-color-preformatted-text: rgb(34, 34, 34); + --pst-color-preformatted-background: rgb(250, 250, 250); + --pst-color-inline-code: rgb(232, 62, 140); + + --pst-color-active-navigation: rgb(19, 6, 84); + --pst-color-navbar-link: rgb(153, 0, 0); + --pst-color-navbar-link-hover: rgb(77, 171, 207); + +} diff --git a/v0.10.x/_static/css/custom_github.css b/v0.10.x/_static/css/custom_github.css new file mode 100644 index 000000000..e1843c4fb --- /dev/null +++ b/v0.10.x/_static/css/custom_github.css @@ -0,0 +1,209 @@ +/* +Github +*/ + +#github_visualization_main_container { + font-family: Arial, Helvetica, sans-serif; +} + +/* basic stats styles */ +.github_visualization_basic_stats_container { + display: block; + overflow: auto; +} + +.github_visualization_basic_stats { + background: rgb(255, 255, 255); + box-shadow: rgba(99, 99, 99, 0.2) 0px 2px 8px 0px; + font-weight: bold; + margin: 1.4%; + width: 47.2%; + float: left; + min-width: 50px; + font-family: Arial, Helvetica, sans-serif; + -webkit-box-sizing: border-box; /* Safari/Chrome, other WebKit */ + -moz-box-sizing: border-box; /* Firefox, other Gecko */ + box-sizing: border-box; /* Opera/IE 8+ */ + + border-radius: 12.5px; +} + +.stat_holder { + display: flex; + align-items: center; + + position: relative; + overflow: hidden; + + padding: 4%; + +} + +.stat_holder:hover .basic_stat_icon_holder { + box-shadow: rgba(153, 0, 0, 0.1) 0px 8px 24px; +} + +.stat_holder:hover .background_icon { + color: rgba(153, 0, 0, 0.3); +} + +.stat_holder:hover .stat-value { + color: rgba(40, 167, 69); +} + +.stat-value { + font-size: 2em; + font-family: Arial, Helvetica, sans-serif; + font-weight: bold; + color: rgba(40, 167, 69, 0.8); + transition: all 0.2s ease; +} + +.background_icon { + position: absolute; + font-size: 8em; + + top: 7px; + right: -45px; + + color: rgba(153, 0, 0, 0.04); + transition: all 0.2s ease; +} + +.basic_stat_icon { + font-size: 22px; + color: rgb(153, 0, 0); +} + +.basic_stat_icon_holder { + height: 46px; + width: 46px; + + border-radius: 50%; + + background-color: rgba(153, 0, 0, 0.1); + box-shadow: rgba(99, 99, 99, 0.2) 0px 2px 8px 0px; + + display: flex; + justify-content: center; + align-items: center; + + margin-right: 20px; + transition: all 0.2s ease; +} + +/* contributors styles */ + +#github_visualization_contributors_wrapper { + display: block; + overflow: hidden; + margin-top: 20px; +} + +.github_visualization_contributor_info { + padding: 2%; + margin: 0.6%; + width: 32%; + float: left; + -webkit-box-sizing: border-box; /* Safari/Chrome, other WebKit */ + -moz-box-sizing: border-box; /* Firefox, other Gecko */ + box-sizing: border-box; /* Opera/IE 8+ */ + transition: all 0.4s; +} + +.github_visualization_contributor_info:hover +.github_visualization_contributor_img { + width: 10em; + height: 10em; +} + +.github_visualization_contributor_img_holder { + width: 10em; + height: 10em; + border-radius: 50%; + margin: 0 auto; + display: flex; + justify-content: center; + align-items: center; + background-color: rgba(153, 0, 0, 0.1); + transition: all 0.5s ease; +} + +.github_visualization_contributor_img { + width: 8em; + height: 8em; + border-radius: 50%; + margin: 0 auto; + display: block; + transition: all 0.5s ease; +} + +@keyframes imgloader { + 0% { opacity: 0.1; } + 50% { opacity: 0.3; } + 100% { opacity: 0.1; } +} +.img-loading { + width: 8em; + height: 8em; + background: url('../images/default_avatar.png') center; + background-size: cover; + opacity: 0.2; + transition: all 0.5s ease; + animation-name: imgloader; + animation-duration: 2s; + animation-timing-function: linear; + animation-delay: 0s; + animation-iteration-count: infinite; +} + +.github_visualization_contributor_name { + display: block; + text-align: center; + padding-top: 1em; + font-size: 1.1em; + font-weight: 600; + color: #515151; +} + +.github_visualization_contributor_commits { + display: block; + text-align: center; +} + +.github_visualization_contributor_additions { + color: #409340; + width: 48%; + padding: 1%; + text-align: right; + display: block; + float: left; +} + +.github_visualization_contributor_deletions { + color: #d45a5a; + width: 48%; + padding: 1%; + text-align: left; + float: left; + display: block; +} + +@media (max-width: 768px) { + .github_visualization_basic_stats { + width: 98.8%; + } + + .github_visualization_contributor_info { + width: 48.8%; + } + +} + + +@media (max-width: 400px) { + .github_visualization_contributor_info { + width: 98.8%; + } + +} diff --git a/v0.10.x/_static/css/fury.css b/v0.10.x/_static/css/fury.css new file mode 100644 index 000000000..7c261bc6e --- /dev/null +++ b/v0.10.x/_static/css/fury.css @@ -0,0 +1,1532 @@ +html, +body, +div, +span, +applet, +object, +iframe, +h1, +h2, +h3, +h4, +h5, +h6, +p, +blockquote, +pre, +a, +abbr, +acronym, +address, +big, +cite, +code, +del, +dfn, +em, +img, +ins, +kbd, +q, +s, +samp, +small, +strike, +strong, +sub, +sup, +tt, +var, +dl, +dt, +dd, +ol, +ul, +li, +fieldset, +form, +label, +legend, +table, +caption, +tbody, +tfoot, +thead, +tr, +th, +td { + margin: 0; + padding: 0; + border: 0; + outline: 0; + font-weight: inherit; + font-style: inherit; + font-family: inherit; + font-size: 100%; + vertical-align: baseline; +} +body { + line-height: 1; + color: #000; + background: #fff; +} +ol, +ul { + list-style: none; +} +table { + border-collapse: separate; + border-spacing: 0; + vertical-align: middle; +} +caption, +th, +td { + text-align: left; + font-weight: normal; + vertical-align: middle; +} +a img { + border: none; +} +html { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} +*, +*:before, +*:after { + -webkit-box-sizing: inherit; + -moz-box-sizing: inherit; + box-sizing: inherit; +} +button::-moz-focus-inner, +input[type="reset"]::-moz-focus-inner, +input[type="button"]::-moz-focus-inner, +input[type="submit"]::-moz-focus-inner { + padding: 0; + margin: 0; + border: 0; +} +input, +button, +select { + margin: 0; + padding: 0; + border: 0; +} + +@media screen { + html, + body { + height: 100%; + overflow: hidden; + } +} +body { + background: #990000; /*171f26;*/ + font-size: 15px; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + color: #444; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + position: relative; +} +.wrapper:before, +.wrapper:after { + content: ""; + display: table; +} +.wrapper:after { + clear: both; +} +@media screen { + .wrapper { + max-width: 1200px; + margin: 0 auto; + } +} +.inner:before, +#article-toc-inner:before, +.inner:after, +#article-toc-inner:after { + content: ""; + display: table; +} +.inner:after, +#article-toc-inner:after { + clear: both; +} +@media screen { + .inner, + #article-toc-inner { + padding: 0 20px; + } +} +#content-wrap { + background: #fff; + border-top: 1px solid #161d24; + border-bottom: 1px solid #161d24; + margin: -1px 0; +} +#header { + position: relative; + padding: 10px 0; +} +@media print { + #header { + display: none; + } +} +#header-inner { + display: -webkit-box; + display: -moz-box; + display: -webkit-flex; + display: -ms-flexbox; + display: box; + display: flex; + -webkit-box-orient: horizontal; + -moz-box-orient: horizontal; + -webkit-box-lines: single; + -moz-box-lines: single; + -webkit-flex-flow: row nowrap; + -ms-flex-flow: row nowrap; + flex-flow: row nowrap; + -webkit-box-align: center; + -moz-box-align: center; + -ms-flex-align: center; + -webkit-align-items: center; + align-items: center; +} +@media screen and (max-width: 768px) { + #header-inner { + -webkit-box-pack: center; + -moz-box-pack: center; + -ms-flex-pack: center; + -webkit-justify-content: center; + justify-content: center; + } +} +#logo-wrap { + -webkit-box-flex: 1; + -moz-box-flex: 1; + box-flex: 1; + -webkit-flex: 0 50px; + -ms-flex: 0 50px; + flex: 0 50px; +} +#logo { + text-indent: 101%; + white-space: nowrap; + overflow: hidden; + background: url("/vtk-js/logo.svg"); + width: 50px; + height: 50px; + -webkit-background-size: 50px 50px; + -moz-background-size: 50px 50px; + background-size: 50px 50px; + display: block; +} +#main-nav { + display: none; + -webkit-box-flex: 1; + -moz-box-flex: 1; + box-flex: 1; + -webkit-flex: 1 auto; + -ms-flex: 1 auto; + flex: 1 auto; + padding-left: 20px; +} +@media screen and (min-width: 769px) { + #main-nav { + display: block; + } +} +.main-nav-link { + color: #fff; + text-decoration: none; + line-height: 50px; + opacity: 0.7; + -webkit-transition: 0.2s; + -moz-transition: 0.2s; + -ms-transition: 0.2s; + transition: 0.2s; + font-family: Lato, "Helvetica Neue", Helvetica, Arial, sans-serif; + display: inline-block; + padding: 0 15px; +} +.main-nav-link:hover { + opacity: 1; + color: #fff; /*1094e8;*/ +} +#search-input-wrap { + display: none; + padding-left: 6px; + padding-bottom: 8px; + border-bottom: 1px solid #999; +} +#search-input-wrap.on { + display: inline-block; +} +#search-input-icon { + color: #fff; + padding-right: 0.5em; + display: inline-block; + opacity: 0.7; +} +#search-input { + background: none; + font-size: inherit; + font-family: Lato, "Helvetica Neue", Helvetica, Arial, sans-serif; + color: #fff; + outline: none; + -webkit-appearance: none; +} +#lang-select-wrap { + display: none; + position: relative; +} +@media screen and (min-width: 769px) { + #lang-select-wrap { + display: block; + } +} +#lang-select-label { + color: #fff; + opacity: 0.7; + font-family: Lato, "Helvetica Neue", Helvetica, Arial, sans-serif; + line-height: 50px; +} +#lang-select-label span { + padding-left: 8px; +} +#lang-select-label i { + opacity: 0.7; +} +#lang-select { + opacity: 0; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + -webkit-appearance: menulist-button; + font-size: inherit; +} +#banner { + color: rgba(255,255,255,0.8); + text-align: center; +} +#banner-title { + padding-top: 20px; + font-size: 40px; + line-height: 1.15; + font-weight: 300; + font-family: Lato, "Helvetica Neue", Helvetica, Arial, sans-serif; +} +@media screen and (min-width: 769px) { + #banner-title { + padding-top: 40px; + font-size: 45px; + } +} +#banner-start { + text-align: center; + padding: 40px 0; +} +@media screen and (min-width: 769px) { + #banner-start { + padding: 40px 0; + font-size: 18px; + } +} +#banner-start-command { + background: #aa0000; + font-family: "Source Code Pro", Monaco, Menlo, Consolas, monospace; + display: inline-block; + padding: 15px 20px; +} +#banner-start-command:before { + content: "$"; + opacity: 0.5; + padding-right: 10px; +} +#banner-start-link { + color: #fff; + background: #01426A; /*#0e83cd;*/; + display: inline-block; + padding: 15px; + text-decoration: none; + -webkit-transition: 0.2s; + -moz-transition: 0.2s; + -ms-transition: 0.2s; + transition: 0.2s; +} +#banner-start-link:hover { + background: #1094e8; +} +#banner-share { + display: none; + padding-bottom: 60px; +} +@media screen and (min-width: 769px) { + #banner-share { + display: block; + } +} +#intro-feature-list { + padding-top: 20px; + display: -webkit-box; + display: -moz-box; + display: -webkit-flex; + display: -ms-flexbox; + display: box; + display: flex; + -webkit-box-orient: vertical; + -moz-box-orient: vertical; + -webkit-flex-flow: column; + -ms-flex-flow: column; + flex-flow: column; +} +@media screen and (min-width: 769px) { + #intro-feature-list { + -webkit-box-orient: horizontal; + -moz-box-orient: horizontal; + -webkit-box-lines: multiple; + -moz-box-lines: multiple; + -webkit-flex-flow: row wrap; + -ms-flex-flow: row wrap; + flex-flow: row wrap; + } +} +.intro-feature-wrap { + padding-top: 20px; +} +@media screen and (min-width: 769px) { + .intro-feature-wrap { + -webkit-box-flex: 1; + -moz-box-flex: 1; + box-flex: 1; + -webkit-flex: 0 0 50%; + -ms-flex: 0 0 50%; + flex: 0 0 50%; + padding-top: 50px; + } +} +.intro-feature { + position: relative; + text-align: center; +} +@media screen and (min-width: 769px) { + .intro-feature { + text-align: left; + padding-left: 70px; + } +} +.intro-feature-icon { + color: #01426A; /*#0e83cd;*/; + font-size: 36px; + padding-bottom: 26px; + text-align: center; +} +@media screen and (min-width: 769px) { + .intro-feature-icon { + position: absolute; + top: 0; + left: 20px; + font-size: 24px; + width: 24px; + } +} +.intro-feature-title { + color: #01426A; /*#0e83cd;*/; + font-family: Lato, "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 24px; +} +.intro-feature-desc { + margin: 1.6em 0; + line-height: 1.6em; +} +#intro-cmd-wrap { + max-width: 700px; + background: #eee; + padding: 15px 0; + margin: 25px -20px 0; +} +@media screen and (min-width: 769px) { + #intro-cmd-wrap { + margin: 50px auto 0; + } +} +.intro-cmd-item { + font-size: 16px; + font-family: "Source Code Pro", Monaco, Menlo, Consolas, monospace; + line-height: 2; + padding: 0 30px; +} +.intro-cmd-item:before { + content: "$"; + color: #01426A; /*#0e83cd;*/; + padding-right: 15px; +} +#intro-get-started-wrap { + text-align: center; +} +#intro-get-started-link { + font-size: 18px; + font-family: Lato, "Helvetica Neue", Helvetica, Arial, sans-serif; + display: inline-block; + color: #01426A; /*#0e83cd;*/ + text-decoration: none; + margin: 40px 0; + border: 3px solid; + border-color: #006298; /* #25a1f0;*/ + padding: 12px 24px; + position: relative; + -webkit-transition: 0.2s; + -moz-transition: 0.2s; + -ms-transition: 0.2s; + transition: 0.2s; +} +#intro-get-started-link:hover { + background: #006298; /* #25a1f0;*/; + color: #fff; +} +.link { + color: #01426A; /*#0e83cd;*/; + text-decoration: none; + -webkit-transition: 0.2s; + -moz-transition: 0.2s; + -ms-transition: 0.2s; + transition: 0.2s; +} +.link:hover { + color: #1094e8; +} +#sidebar { + width: 220px; + float: left; + padding-bottom: 40px; + opacity: 0.8; + margin-left: -220px; + display: none; +} +@media screen and (min-width: 769px) { + #sidebar { + display: block; + } +} +.sidebar-title { + margin-top: 40px; + padding: 10px 0; + font-family: Lato, "Helvetica Neue", Helvetica, Arial, sans-serif; + font-weight: bold; + color: #01426A; /*#0e83cd;*/; + display: inline-block; + border-top: 1px solid #e3e3e3; + line-height: 1; +} +.sidebar-link, +.toc-link { + font-family: Lato, "Helvetica Neue", Helvetica, Arial, sans-serif; + display: block; + color: #444; + text-decoration: none; + padding: 7px 0; + line-height: 1; + position: relative; + width: 100%; + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; +} +.sidebar-link.current, +.toc-link.current { + color: #01426A; /*#0e83cd;*/; +} +.sidebar-link:hover, +.toc-link:hover { + color: #1094e8; +} +#content { + position: relative; +} +#content:before, +#content:after { + content: ""; + display: table; +} +#content:after { + clear: both; +} +#content-inner:before, +#content-inner:after { + content: ""; + display: table; +} +#content-inner:after { + clear: both; +} +@media screen and (min-width: 769px) { + #content-inner { + margin-left: 220px; + } +} +@media screen and (min-width: 769px) { + .article-container { + float: right; + width: 100%; + } +} +.article-inner:before, +.article-inner:after { + content: ""; + display: table; +} +.article-inner:after { + clear: both; +} +@media screen and (min-width: 769px) { + .article-inner { + margin-right: 220px; + } +} +.article { + float: left; + width: 100%; + padding: 40px 0; +} +@media print { + .article { + padding: 0; + } +} +#article-toc { + display: none; + float: right; + width: 220px; + margin-right: -220px; + opacity: 0.8; +} +@media screen and (min-width: 769px) { + #article-toc { + display: block; + } +} +#article-toc.fixed { + position: absolute; + top: 0; + bottom: 0; + right: 220px; +} +#article-toc-inner { + overflow-x: hidden; + overflow-y: auto; + width: 220px; +} +.fixed #article-toc-inner { + position: fixed; + top: 0; + bottom: 0; +} +.toc-child { + padding-left: 1em; + font-size: 0.9em; +} +#article-toc-top { + margin-top: 2em; + font-size: 0.9em; + text-decoration: none; + color: #444; + display: block; + margin-bottom: 40px; + font-family: Lato, "Helvetica Neue", Helvetica, Arial, sans-serif; +} +#article-toc-top:hover { + color: #1094e8; +} +.article-header { + padding-bottom: 20px; +} +.article-header:before, +.article-header:after { + content: ""; + display: table; +} +.article-header:after { + clear: both; +} +.article-title { + float: left; + font-family: Lato, "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 36px; + font-weight: 300; + text-decoration: none; + color: #444; + -webkit-transition: 0.2s; + -moz-transition: 0.2s; + -ms-transition: 0.2s; + transition: 0.2s; +} +a.article-title:hover { + color: #1094e8; +} +.post .article-title { + float: none; +} +.article-date { + color: #999; + text-decoration: none; + display: inline-block; + margin-top: 1em; +} +.article-date:hover { + color: #1094e8; +} +.article-edit-link { + float: right; + color: #bbb; + font-size: 24px; + line-height: 36px; + -webkit-transition: 0.2s; + -moz-transition: 0.2s; + -ms-transition: 0.2s; + transition: 0.2s; + display: none; +} +.article-edit-link:hover { + color: #1094e8; +} +@media screen and (min-width: 769px) { + .article-edit-link { + display: block; + } +} +.article-anchor { + margin-left: 10px; + display: none; +} +.article-anchor:before { + content: "#"; +} +@media print { + .article-anchor { + display: none !important; + } +} +.article-heading:hover .article-anchor { + display: inline-block; +} +.article-content { + line-height: 1.6em; + color: #444; +} +@media print { + .article-content { + font-size: 12pt; + } +} +.article-content p, +.article-content ol, +.article-content ul, +.article-content dl, +.article-content table, +.article-content blockquote, +.article-content iframe, +.article-content .highlight { + margin: 1em 0; +} +.article-content h1 { + font-size: 2em; +} +.article-content h2 { + font-size: 1.5em; +} +.article-content h3 { + font-size: 1.3em; +} +.article-content h1, +.article-content h2, +.article-content h3, +.article-content h4, +.article-content h5, +.article-content h6 { + line-height: 1em; + font-weight: bold; + margin: 1em 0; +} +.article-content a { + color: #01426A; /*#0e83cd;*/; + text-decoration: none; +} +.article-content a:hover { + color: #1094e8; + text-decoration: underline; +} +@media print { + .article-content a { + color: #444; + text-decoration: underline; + } + .article-content a:after { + content: " (" attr(href) ")"; + font-size: 80%; + } +} +.article-content strong { + font-weight: bold; +} +.article-content em { + font-style: italic; +} +.article-content ul, +.article-content ol, +.article-content dl { + margin-left: 20px; +} +.article-content ul ul, +.article-content ol ul, +.article-content dl ul, +.article-content ul ol, +.article-content ol ol, +.article-content dl ol, +.article-content ul dl, +.article-content ol dl, +.article-content dl dl { + margin-top: 0; + margin-bottom: 0; +} +.article-content ul { + list-style: disc; +} +.article-content ol { + list-style: decimal; +} +.article-content dl { + list-style: square; +} +.article-content li p { + margin: 0; +} +.article-content li table, +.article-content li blockquote, +.article-content li iframe, +.article-content li .highlight { + margin: 1em 0; +} +.article-content img, +.article-content video { + max-width: 100%; +} +.article-content blockquote { + padding: 0 20px; + position: relative; + border: 1px solid #e3e3e3; + border-left: 5px solid #ddd; +} +.article-content blockquote footer { + margin: 1em 0; + font-style: italic; +} +.article-content blockquote footer cite:before { + content: "—"; + padding: 0 0.3em; +} +.article-content blockquote footer cite a { + color: color-grey; +} +.article-content .note.tip { + border-left-color: #fa0; +} +.article-content .note.info { + border-left-color: #0af; +} +.article-content .note.warn { + border-left-color: #f00; +} +.article-content .note-title { + margin: 1em 0; + display: block; + font-size: 1.3em; + font-weight: bold; +} +.article-content table { + max-width: 100%; + border: 1px solid #e3e3e3; +} +.article-content table th { + font-weight: bold; +} +.article-content table th, +.article-content table td { + padding: 5px 15px; +} +.article-content table tr:nth-child(2n) { + background: #eee; +} +.article-footer { + margin: 1em 0; + border-top: 1px solid #e3e3e3; + text-align: center; + color: #999; + line-height: 1em; + padding-top: 1em; + position: relative; +} +.article-footer:before, +.article-footer:after { + content: ""; + display: table; +} +.article-footer:after { + clear: both; +} +@media print { + .article-footer { + display: none; + } +} +.article-footer-prev, +.article-footer-next { + color: #01426A; /*#0e83cd;*/; + text-decoration: none; + font-weight: bold; + font-family: Lato, "Helvetica Neue", Helvetica, Arial, sans-serif; + text-transform: uppercase; + position: absolute; +} +.article-footer-prev:hover, +.article-footer-next:hover { + color: #1094e8; +} +@media print { + .article-footer-prev, + .article-footer-next { + display: none; + } +} +.article-footer-prev span, +.article-footer-next span { + padding: 0 6px; +} +.article-footer-prev { + left: 0; +} +.article-footer-next { + right: 0; +} +.article-footer-updated { + font-size: 0.9em; +} +@media print { + #comments { + display: none; + } +} +.post { + margin: 0 auto; + float: none; +} +@media screen { + .post { + max-width: 800px; + } +} +#plugin-list-header { + margin: 40px 0; +} +#plugin-list-header:before, +#plugin-list-header:after { + content: ""; + display: table; +} +#plugin-list-header:after { + clear: both; +} +#plugin-list-title { + font-family: Lato, "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 36px; + font-weight: 300; + line-height: 1; + float: left; +} +#plugin-list-count { + color: #999; + padding-top: 1em; + text-align: right; +} +@media screen and (min-width: 769px) { + #plugin-list-count { + float: right; + line-height: 40px; + padding-top: 0; + padding-right: 15px; + } +} +#plugin-search-input { + font-size: 16px; + font-family: inherit; + -webkit-appearance: none; + border: 1px solid #e3e3e3; + padding: 10px 10px; + width: 100%; + margin-top: 25px; +} +@media screen and (min-width: 769px) { + #plugin-search-input { + float: right; + width: 50%; + margin-top: 0; + } +} +#plugin-list { + margin: 40px -20px; + display: -webkit-box; + display: -moz-box; + display: -webkit-flex; + display: -ms-flexbox; + display: box; + display: flex; + -webkit-box-orient: vertical; + -moz-box-orient: vertical; + -webkit-flex-flow: column; + -ms-flex-flow: column; + flex-flow: column; +} +@media screen and (min-width: 480px) { + #plugin-list { + -webkit-box-orient: horizontal; + -moz-box-orient: horizontal; + -webkit-box-lines: multiple; + -moz-box-lines: multiple; + -webkit-flex-flow: row wrap; + -ms-flex-flow: row wrap; + flex-flow: row wrap; + } +} +.plugin { + display: none; + padding: 20px; +} +@media screen and (min-width: 480px) { + .plugin { + -webkit-box-flex: 1; + -moz-box-flex: 1; + box-flex: 1; + -webkit-flex: 0 0 50%; + -ms-flex: 0 0 50%; + flex: 0 0 50%; + } +} +@media screen and (min-width: 769px) { + .plugin { + -webkit-box-flex: 1; + -moz-box-flex: 1; + box-flex: 1; + -webkit-flex: 0 0 33.333333333333336%; + -ms-flex: 0 0 33.333333333333336%; + flex: 0 0 33.333333333333336%; + } +} +.plugin.on { + display: block; +} +.plugin-name { + font-family: Lato, "Helvetica Neue", Helvetica, Arial, sans-serif; + font-weight: bold; + color: #01426A; /*#0e83cd;*/; + font-size: 20px; + text-decoration: none; + line-height: 1; +} +.plugin-name:hover { + color: #1094e8; +} +.plugin-desc { + line-height: 1.6em; + margin: 1em 0; +} +.plugin-tag-list { + line-height: 1.3; +} +.plugin-tag-list:before, +.plugin-tag-list:after { + content: ""; + display: table; +} +.plugin-tag-list:after { + clear: both; +} +.plugin-tag { + color: #999; + font-size: 0.9em; + text-decoration: none; + float: left; + margin-right: 10px; +} +.plugin-tag:hover { + color: #1094e8; +} +.plugin-tag:before { + content: "#"; +} +.plugin-screenshot { + margin-bottom: 15px; + position: relative; + padding-top: 62.5%; + height: 0; + overflow: hidden; +} +.plugin-screenshot-img { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: auto; +} +.plugin-preview-link { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: rgba(0,0,0,0.7); + color: #fff; + text-align: center; + opacity: 0; + -webkit-transition: 0.15s; + -moz-transition: 0.15s; + -ms-transition: 0.15s; + transition: 0.15s; +} +.plugin-preview-link:hover { + opacity: 1; +} +.plugin-preview-link:hover .fa { + opacity: 1; + -webkit-transform: scale(1); + -moz-transform: scale(1); + -ms-transform: scale(1); + transform: scale(1); +} +.plugin-preview-link .fa { + position: absolute; + top: 0; + left: 0; + bottom: 0; + right: 0; + margin: auto; + font-size: 50px; + width: 50px; + height: 50px; + opacity: 0; + -webkit-transform: scale(6); + -moz-transform: scale(6); + -ms-transform: scale(6); + transform: scale(6); + -webkit-transition: 0.2s; + -moz-transition: 0.2s; + -ms-transition: 0.2s; + transition: 0.2s; + -webkit-transition-delay: 0.15s; + -moz-transition-delay: 0.15s; + -ms-transition-delay: 0.15s; + transition-delay: 0.15s; +} +.archive-post { + padding: 1em 0; + border-top: 1px solid #e3e3e3; +} +.archive-post:last-child { + padding-bottom: 40px; +} +.archive-post-link { + display: block; + color: #444; + text-decoration: none; + line-height: 1.6em; +} +.archive-post-link:before, +.archive-post-link:after { + content: ""; + display: table; +} +.archive-post-link:after { + clear: both; +} +.archive-post-link:hover { + color: #1094e8; +} +.archive-post-title { + font-family: Lato, "Helvetica Neue", Helvetica, Arial, sans-serif; + float: left; + font-weight: bold; +} +.archive-post-date { + color: #999; + float: right; + font-size: 0.9em; +} +#mobile-nav { + position: fixed; + top: 0; + width: 260px; + left: -260px; + height: 100%; + background: #990000; /*171f26;*/ + -webkit-transition: 0.4s; + -moz-transition: 0.4s; + -ms-transition: 0.4s; + transition: 0.4s; + font-family: Lato, "Helvetica Neue", Helvetica, Arial, sans-serif; +} +.mobile-nav-on #mobile-nav { + -webkit-transform: translateX(100%); + -moz-transform: translateX(100%); + -ms-transform: translateX(100%); + transform: translateX(100%); +} +#mobile-nav-inner { + overflow-y: auto; + padding: 10px 0; + position: absolute; + top: 0; + bottom: 40px; + left: 0; + right: 0; + -webkit-overflow-scrolling: touch; +} +#mobile-nav-toggle { + position: absolute; + top: 0; + bottom: 0; + left: 20px; + width: 25px; + height: 20px; + margin: auto; + opacity: 0.5; + cursor: pointer; + -webkit-transition: 0.2s; + -moz-transition: 0.2s; + -ms-transition: 0.2s; + transition: 0.2s; +} +#mobile-nav-toggle:active, +.mobile-nav-on #mobile-nav-toggle { + opacity: 1; +} +@media screen and (min-width: 769px) { + #mobile-nav-toggle { + display: none; + } +} +.mobile-nav-toggle-bar { + background: #fff; + position: absolute; + left: 0; + width: 100%; + height: 2px; + -webkit-transition: 0.4s; + -moz-transition: 0.4s; + -ms-transition: 0.4s; + transition: 0.4s; + -webkit-transform-origin: 0; + -moz-transform-origin: 0; + -ms-transform-origin: 0; + transform-origin: 0; + border-radius: 2px; +} +.mobile-nav-toggle-bar:first-child { + top: 0; +} +.mobile-nav-on .mobile-nav-toggle-bar:first-child { + -webkit-transform: rotate(45deg); + -moz-transform: rotate(45deg); + -ms-transform: rotate(45deg); + transform: rotate(45deg); +} +.mobile-nav-toggle-bar:nth-child(2) { + top: 9px; +} +.mobile-nav-on .mobile-nav-toggle-bar:nth-child(2) { + opacity: 0; +} +.mobile-nav-toggle-bar:last-child { + top: 18px; +} +.mobile-nav-on .mobile-nav-toggle-bar:last-child { + -webkit-transform: rotate(-45deg); + -moz-transform: rotate(-45deg); + -ms-transform: rotate(-45deg); + transform: rotate(-45deg); +} +.mobile-nav-link { + color: #fff; + text-decoration: none; + display: block; + padding: 10px 15px; + line-height: 1; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} +.mobile-nav-title { + color: #01426A; /*#0e83cd;*/; + font-weight: bold; + padding: 10px 15px; + line-height: 1; + display: block; + border-top: 1px solid #444; + margin-top: 10px; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} +#mobile-lang-select-wrap { + position: absolute; + bottom: 0; + left: 0; + width: 100%; + background: #990000; /*171f26; */ + border-top: 1px solid #444; +} +#mobile-lang-select-label { + line-height: 40px; + color: #fff; + padding: 10px 15px; +} +#mobile-lang-select-label i { + opacity: 0.7; +} +#mobile-lang-select-label span { + padding-left: 8px; +} +#mobile-lang-select { + -webkit-appearance: menulist-button; + opacity: 0; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; +} +#container { + -webkit-transition: 0.4s; + -moz-transition: 0.4s; + -ms-transition: 0.4s; + transition: 0.4s; + height: 100%; + overflow: auto; + -webkit-overflow-scrolling: touch; +} +.mobile-nav-on #container { + -webkit-transform: translateX(260px); + -moz-transform: translateX(260px); + -ms-transform: translateX(260px); + transform: translateX(260px); + overflow: hidden; +} +#mobile-nav-dimmer { + position: absolute; + top: 0; + left: 100%; + width: 100%; + height: 100%; + background: #000; + opacity: 0; + -webkit-transition: opacity 0.4s, -webkit-transform 0s 0.4s; + -moz-transition: opacity 0.4s, -moz-transform 0s 0.4s; + -ms-transition: opacity 0.4s, -ms-transform 0s 0.4s; + transition: opacity 0.4s, transform 0s 0.4s; +} +.mobile-nav-on #mobile-nav-dimmer { + opacity: 0.7; + -webkit-transform: translateX(-100%); + -moz-transform: translateX(-100%); + -ms-transform: translateX(-100%); + transform: translateX(-100%); + -webkit-transition: opacity 0.4s; + -moz-transition: opacity 0.4s; + -ms-transition: opacity 0.4s; + transition: opacity 0.4s; +} +#footer { + padding: 40px 0; + color: rgba(255,255,255,0.6); + font-family: Lato, "Helvetica Neue", Helvetica, Arial, sans-serif; + position: relative; + background: #990000; /*171f26; */ + text-align: center; +} +#footer:before, +#footer:after { + content: ""; + display: table; +} +#footer:after { + clear: both; +} +@media screen and (min-width: 769px) { + #footer { + text-align: left; + } +} +@media print { + #footer { + display: none; + } +} +#footer a { + color: inherit; + text-decoration: none; + -webkit-transition: 0.2s; + -moz-transition: 0.2s; + -ms-transition: 0.2s; + transition: 0.2s; +} +#footer a:hover { + color: #fff; +} +#footer-copyright { + line-height: 1.4; +} +@media screen and (min-width: 769px) { + #footer-copyright { + float: left; + } +} +#footer-copyright a { + font-weight: bold; +} +#footer-links { + margin-top: 1em; +} +@media screen and (min-width: 769px) { + #footer-links { + float: right; + margin-top: 0; + } +} +.footer-link { + font-size: 30px; + margin-left: 20px; +} +.footer-link:first-child { + margin-left: 0; +} +pre, +code { + font-family: "Source Code Pro", Monaco, Menlo, Consolas, monospace; + color: #4d4d4c; + background: #eee; + font-size: 0.95em; +} +code { + padding: 0 5px; +} +pre { + padding: 10px 15px; + line-height: 22px; +} +pre code { + border: none; + display: block; + padding: 0; +} +.highlight { + background: #eee; + padding: 10px 15px; + color: #4d4d4c; + overflow: auto; + margin: 0; +} +.highlight table { + margin: 0 !important; + border: 0; +} +.highlight table th, +.highlight table td { + padding: 0; +} +.highlight figcaption { + margin: -5px 0 5px; + font-size: 0.9em; + color: #999; +} +.highlight figcaption:before, +.highlight figcaption:after { + content: ""; + display: table; +} +.highlight figcaption:after { + clear: both; +} +.highlight figcaption a { + float: right; +} +.highlight pre { + padding: 0; + border: none; + background: none; +} +.highlight .line { + height: 22px; +} +pre .comment, +pre .title { + color: #8e908c; +} +pre .variable, +pre .attribute, +pre .tag, +pre .regexp, +pre .ruby .constant, +pre .xml .tag .title, +pre .xml .pi, +pre .xml .doctype, +pre .html .doctype, +pre .css .id, +pre .css .class, +pre .css .pseudo { + color: #c82829; +} +pre .number, +pre .preprocessor, +pre .built_in, +pre .literal, +pre .params, +pre .constant { + color: #f5871f; +} +pre .class, +pre .ruby .class .title, +pre .css .rules .attribute { + color: #718c00; +} +pre .string, +pre .value, +pre .inheritance, +pre .header, +pre .ruby .symbol, +pre .xml .cdata { + color: #718c00; +} +pre .css .hexcolor { + color: #3e999f; +} +pre .function, +pre .python .decorator, +pre .python .title, +pre .ruby .function .title, +pre .ruby .title .keyword, +pre .perl .sub, +pre .javascript .title, +pre .coffeescript .title { + color: #4271ae; +} +pre .keyword, +pre .javascript .function { + color: #8959a8; +} diff --git a/v0.10.x/_static/css/main.css b/v0.10.x/_static/css/main.css new file mode 100644 index 000000000..14475cbcc --- /dev/null +++ b/v0.10.x/_static/css/main.css @@ -0,0 +1,13 @@ +#footer h5 { + padding-left: 10px; + border-left: 3px solid white; + color: white; +} + +#footer ul { + padding-left: 0px; +} + +.footer-link { + font-size: smaller; +} diff --git a/v0.10.x/_static/css/navbar.css b/v0.10.x/_static/css/navbar.css new file mode 100644 index 000000000..ab752a350 --- /dev/null +++ b/v0.10.x/_static/css/navbar.css @@ -0,0 +1,31 @@ +/* Introducing a new css file for handling navbar css */ + +/* We will be refractoring all the css of navbar and have single source of truth */ + +@import "../vendor/vars.css"; + + +/* Introduces the color change and highlight */ +.bd-header .navbar-nav li a.nav-link, +.search-button, +.navbar-item { + color: var(--colorPrimaryDark); +} + +.bd-header .navbar-nav li a.nav-link:hover, +.search-button:hover, +.navbar-item:hover { + color: var(--colorPrimaryLight); +} + +/* To remove highlight for logo text */ +.navbar-item:hover #navbar-logo-text { + color: var(--colorPrimaryDark); +} + +/* For mobile version color handling */ +@media screen and (max-width: 960px) { + .navbar-nav li a { + color: var(--colorPrimaryDark); + } +} diff --git a/v0.10.x/_static/css/sponsors.css b/v0.10.x/_static/css/sponsors.css new file mode 100644 index 000000000..0ef833868 --- /dev/null +++ b/v0.10.x/_static/css/sponsors.css @@ -0,0 +1,58 @@ +.sponsors-wrapper { + margin: 50px 0; + width: 100%; +} + +.sponsors-title { + display: flex; + justify-content: center; + width: 100%; + margin-bottom: 20px; + + letter-spacing: 1.5px; + font-size: 27px; + font-weight: bold; +} + +.sponsors { + display: flex; + flex-direction: row; + justify-content: center; + align-items: center; +} + +@media (max-width: 767px) { + .sponsors { + flex-direction: column; + } +} + +.sponsors-logo { + width: 220px; + height: 200px; + + padding: 0 10px; + + display: flex; + align-items: center; +} + +.cite { + color: var(--colorPrimaryDark); + font-weight: 600; +} + +.cite-wrapper { + padding: 20px; + max-width: 1152px; + margin: 40px auto 0; + border-radius: 10px; + border: 3px solid var(--colorPrimaryDark); + box-shadow: rgba(0, 0, 0, 0.24) 0px 3px 8px; +} + +@media (max-width: 767px) { + .cite-wrapper { + margin: 20px 20px 0; + } +} \ No newline at end of file diff --git a/v0.10.x/_static/css/util.css b/v0.10.x/_static/css/util.css new file mode 100644 index 000000000..abdd6032e --- /dev/null +++ b/v0.10.x/_static/css/util.css @@ -0,0 +1,2964 @@ + + +/*////////////////////////////////////////////////////////////////// +[ REBOOT ]*/ +*, *:before, *:after { + margin: 0px; + padding: 0px; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} + +body, html { + font-family: Arial, sans-serif; + font-size: 15px; + color: #666666; + + height: 100%; + background-color: #fff; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} + +/*---------------------------------------------*/ +a:focus {outline: none;} +a:hover {text-decoration: none;} + +/* ------------------------------------ */ +h1,h2,h3,h4,h5,h6,p {margin: 0px;} + +ul, li { + margin: 0px; + list-style-type: none; +} + + +/* ------------------------------------ */ +input, textarea, label { + display: block; + outline: none; + border: none; +} + +/* ------------------------------------ */ +button { + outline: none; + border: none; + background: transparent; + cursor: pointer; +} +button:focus {outline: none;} + +iframe {border: none;} + +.mobile-view, .non-mobile-view { + display: none; +} + +/* For only mobile view */ +@media screen and (max-width: 450px) { + .mobile-view { + display: block; + } +} + +/* For non mobile view*/ +@media screen and (min-width: 768px) { + .non-mobile-view { + display: block; + } +} + + +/*////////////////////////////////////////////////////////////////// +[ FONT SIZE ]*/ +.fs-1 {font-size: 1px;} +.fs-2 {font-size: 2px;} +.fs-3 {font-size: 3px;} +.fs-4 {font-size: 4px;} +.fs-5 {font-size: 5px;} +.fs-6 {font-size: 6px;} +.fs-7 {font-size: 7px;} +.fs-8 {font-size: 8px;} +.fs-9 {font-size: 9px;} +.fs-10 {font-size: 10px;} +.fs-11 {font-size: 11px;} +.fs-12 {font-size: 12px;} +.fs-13 {font-size: 13px;} +.fs-14 {font-size: 14px;} +.fs-15 {font-size: 15px;} +.fs-16 {font-size: 16px;} +.fs-17 {font-size: 17px;} +.fs-18 {font-size: 18px;} +.fs-19 {font-size: 19px;} +.fs-20 {font-size: 20px;} +.fs-21 {font-size: 21px;} +.fs-22 {font-size: 22px;} +.fs-23 {font-size: 23px;} +.fs-24 {font-size: 24px;} +.fs-25 {font-size: 25px;} +.fs-26 {font-size: 26px;} +.fs-27 {font-size: 27px;} +.fs-28 {font-size: 28px;} +.fs-29 {font-size: 29px;} +.fs-30 {font-size: 30px;} +.fs-31 {font-size: 31px;} +.fs-32 {font-size: 32px;} +.fs-33 {font-size: 33px;} +.fs-34 {font-size: 34px;} +.fs-35 {font-size: 35px;} +.fs-36 {font-size: 36px;} +.fs-37 {font-size: 37px;} +.fs-38 {font-size: 38px;} +.fs-39 {font-size: 39px;} +.fs-40 {font-size: 40px;} +.fs-41 {font-size: 41px;} +.fs-42 {font-size: 42px;} +.fs-43 {font-size: 43px;} +.fs-44 {font-size: 44px;} +.fs-45 {font-size: 45px;} +.fs-46 {font-size: 46px;} +.fs-47 {font-size: 47px;} +.fs-48 {font-size: 48px;} +.fs-49 {font-size: 49px;} +.fs-50 {font-size: 50px;} +.fs-51 {font-size: 51px;} +.fs-52 {font-size: 52px;} +.fs-53 {font-size: 53px;} +.fs-54 {font-size: 54px;} +.fs-55 {font-size: 55px;} +.fs-56 {font-size: 56px;} +.fs-57 {font-size: 57px;} +.fs-58 {font-size: 58px;} +.fs-59 {font-size: 59px;} +.fs-60 {font-size: 60px;} +.fs-61 {font-size: 61px;} +.fs-62 {font-size: 62px;} +.fs-63 {font-size: 63px;} +.fs-64 {font-size: 64px;} +.fs-65 {font-size: 65px;} +.fs-66 {font-size: 66px;} +.fs-67 {font-size: 67px;} +.fs-68 {font-size: 68px;} +.fs-69 {font-size: 69px;} +.fs-70 {font-size: 70px;} +.fs-71 {font-size: 71px;} +.fs-72 {font-size: 72px;} +.fs-73 {font-size: 73px;} +.fs-74 {font-size: 74px;} +.fs-75 {font-size: 75px;} +.fs-76 {font-size: 76px;} +.fs-77 {font-size: 77px;} +.fs-78 {font-size: 78px;} +.fs-79 {font-size: 79px;} +.fs-80 {font-size: 80px;} +.fs-81 {font-size: 81px;} +.fs-82 {font-size: 82px;} +.fs-83 {font-size: 83px;} +.fs-84 {font-size: 84px;} +.fs-85 {font-size: 85px;} +.fs-86 {font-size: 86px;} +.fs-87 {font-size: 87px;} +.fs-88 {font-size: 88px;} +.fs-89 {font-size: 89px;} +.fs-90 {font-size: 90px;} +.fs-91 {font-size: 91px;} +.fs-92 {font-size: 92px;} +.fs-93 {font-size: 93px;} +.fs-94 {font-size: 94px;} +.fs-95 {font-size: 95px;} +.fs-96 {font-size: 96px;} +.fs-97 {font-size: 97px;} +.fs-98 {font-size: 98px;} +.fs-99 {font-size: 99px;} +.fs-100 {font-size: 100px;} +.fs-101 {font-size: 101px;} +.fs-102 {font-size: 102px;} +.fs-103 {font-size: 103px;} +.fs-104 {font-size: 104px;} +.fs-105 {font-size: 105px;} +.fs-106 {font-size: 106px;} +.fs-107 {font-size: 107px;} +.fs-108 {font-size: 108px;} +.fs-109 {font-size: 109px;} +.fs-110 {font-size: 110px;} +.fs-111 {font-size: 111px;} +.fs-112 {font-size: 112px;} +.fs-113 {font-size: 113px;} +.fs-114 {font-size: 114px;} +.fs-115 {font-size: 115px;} +.fs-116 {font-size: 116px;} +.fs-117 {font-size: 117px;} +.fs-118 {font-size: 118px;} +.fs-119 {font-size: 119px;} +.fs-120 {font-size: 120px;} +.fs-121 {font-size: 121px;} +.fs-122 {font-size: 122px;} +.fs-123 {font-size: 123px;} +.fs-124 {font-size: 124px;} +.fs-125 {font-size: 125px;} +.fs-126 {font-size: 126px;} +.fs-127 {font-size: 127px;} +.fs-128 {font-size: 128px;} +.fs-129 {font-size: 129px;} +.fs-130 {font-size: 130px;} +.fs-131 {font-size: 131px;} +.fs-132 {font-size: 132px;} +.fs-133 {font-size: 133px;} +.fs-134 {font-size: 134px;} +.fs-135 {font-size: 135px;} +.fs-136 {font-size: 136px;} +.fs-137 {font-size: 137px;} +.fs-138 {font-size: 138px;} +.fs-139 {font-size: 139px;} +.fs-140 {font-size: 140px;} +.fs-141 {font-size: 141px;} +.fs-142 {font-size: 142px;} +.fs-143 {font-size: 143px;} +.fs-144 {font-size: 144px;} +.fs-145 {font-size: 145px;} +.fs-146 {font-size: 146px;} +.fs-147 {font-size: 147px;} +.fs-148 {font-size: 148px;} +.fs-149 {font-size: 149px;} +.fs-150 {font-size: 150px;} +.fs-151 {font-size: 151px;} +.fs-152 {font-size: 152px;} +.fs-153 {font-size: 153px;} +.fs-154 {font-size: 154px;} +.fs-155 {font-size: 155px;} +.fs-156 {font-size: 156px;} +.fs-157 {font-size: 157px;} +.fs-158 {font-size: 158px;} +.fs-159 {font-size: 159px;} +.fs-160 {font-size: 160px;} +.fs-161 {font-size: 161px;} +.fs-162 {font-size: 162px;} +.fs-163 {font-size: 163px;} +.fs-164 {font-size: 164px;} +.fs-165 {font-size: 165px;} +.fs-166 {font-size: 166px;} +.fs-167 {font-size: 167px;} +.fs-168 {font-size: 168px;} +.fs-169 {font-size: 169px;} +.fs-170 {font-size: 170px;} +.fs-171 {font-size: 171px;} +.fs-172 {font-size: 172px;} +.fs-173 {font-size: 173px;} +.fs-174 {font-size: 174px;} +.fs-175 {font-size: 175px;} +.fs-176 {font-size: 176px;} +.fs-177 {font-size: 177px;} +.fs-178 {font-size: 178px;} +.fs-179 {font-size: 179px;} +.fs-180 {font-size: 180px;} +.fs-181 {font-size: 181px;} +.fs-182 {font-size: 182px;} +.fs-183 {font-size: 183px;} +.fs-184 {font-size: 184px;} +.fs-185 {font-size: 185px;} +.fs-186 {font-size: 186px;} +.fs-187 {font-size: 187px;} +.fs-188 {font-size: 188px;} +.fs-189 {font-size: 189px;} +.fs-190 {font-size: 190px;} +.fs-191 {font-size: 191px;} +.fs-192 {font-size: 192px;} +.fs-193 {font-size: 193px;} +.fs-194 {font-size: 194px;} +.fs-195 {font-size: 195px;} +.fs-196 {font-size: 196px;} +.fs-197 {font-size: 197px;} +.fs-198 {font-size: 198px;} +.fs-199 {font-size: 199px;} +.fs-200 {font-size: 200px;} + +/*////////////////////////////////////////////////////////////////// +[ PADDING ]*/ +.p-t-0 {padding-top: 0px;} +.p-t-1 {padding-top: 1px;} +.p-t-2 {padding-top: 2px;} +.p-t-3 {padding-top: 3px;} +.p-t-4 {padding-top: 4px;} +.p-t-5 {padding-top: 5px;} +.p-t-6 {padding-top: 6px;} +.p-t-7 {padding-top: 7px;} +.p-t-8 {padding-top: 8px;} +.p-t-9 {padding-top: 9px;} +.p-t-10 {padding-top: 10px;} +.p-t-11 {padding-top: 11px;} +.p-t-12 {padding-top: 12px;} +.p-t-13 {padding-top: 13px;} +.p-t-14 {padding-top: 14px;} +.p-t-15 {padding-top: 15px;} +.p-t-16 {padding-top: 16px;} +.p-t-17 {padding-top: 17px;} +.p-t-18 {padding-top: 18px;} +.p-t-19 {padding-top: 19px;} +.p-t-20 {padding-top: 20px;} +.p-t-21 {padding-top: 21px;} +.p-t-22 {padding-top: 22px;} +.p-t-23 {padding-top: 23px;} +.p-t-24 {padding-top: 24px;} +.p-t-25 {padding-top: 25px;} +.p-t-26 {padding-top: 26px;} +.p-t-27 {padding-top: 27px;} +.p-t-28 {padding-top: 28px;} +.p-t-29 {padding-top: 29px;} +.p-t-30 {padding-top: 30px;} +.p-t-31 {padding-top: 31px;} +.p-t-32 {padding-top: 32px;} +.p-t-33 {padding-top: 33px;} +.p-t-34 {padding-top: 34px;} +.p-t-35 {padding-top: 35px;} +.p-t-36 {padding-top: 36px;} +.p-t-37 {padding-top: 37px;} +.p-t-38 {padding-top: 38px;} +.p-t-39 {padding-top: 39px;} +.p-t-40 {padding-top: 40px;} +.p-t-41 {padding-top: 41px;} +.p-t-42 {padding-top: 42px;} +.p-t-43 {padding-top: 43px;} +.p-t-44 {padding-top: 44px;} +.p-t-45 {padding-top: 45px;} +.p-t-46 {padding-top: 46px;} +.p-t-47 {padding-top: 47px;} +.p-t-48 {padding-top: 48px;} +.p-t-49 {padding-top: 49px;} +.p-t-50 {padding-top: 50px;} +.p-t-51 {padding-top: 51px;} +.p-t-52 {padding-top: 52px;} +.p-t-53 {padding-top: 53px;} +.p-t-54 {padding-top: 54px;} +.p-t-55 {padding-top: 55px;} +.p-t-56 {padding-top: 56px;} +.p-t-57 {padding-top: 57px;} +.p-t-58 {padding-top: 58px;} +.p-t-59 {padding-top: 59px;} +.p-t-60 {padding-top: 60px;} +.p-t-61 {padding-top: 61px;} +.p-t-62 {padding-top: 62px;} +.p-t-63 {padding-top: 63px;} +.p-t-64 {padding-top: 64px;} +.p-t-65 {padding-top: 65px;} +.p-t-66 {padding-top: 66px;} +.p-t-67 {padding-top: 67px;} +.p-t-68 {padding-top: 68px;} +.p-t-69 {padding-top: 69px;} +.p-t-70 {padding-top: 70px;} +.p-t-71 {padding-top: 71px;} +.p-t-72 {padding-top: 72px;} +.p-t-73 {padding-top: 73px;} +.p-t-74 {padding-top: 74px;} +.p-t-75 {padding-top: 75px;} +.p-t-76 {padding-top: 76px;} +.p-t-77 {padding-top: 77px;} +.p-t-78 {padding-top: 78px;} +.p-t-79 {padding-top: 79px;} +.p-t-80 {padding-top: 80px;} +.p-t-81 {padding-top: 81px;} +.p-t-82 {padding-top: 82px;} +.p-t-83 {padding-top: 83px;} +.p-t-84 {padding-top: 84px;} +.p-t-85 {padding-top: 85px;} +.p-t-86 {padding-top: 86px;} +.p-t-87 {padding-top: 87px;} +.p-t-88 {padding-top: 88px;} +.p-t-89 {padding-top: 89px;} +.p-t-90 {padding-top: 90px;} +.p-t-91 {padding-top: 91px;} +.p-t-92 {padding-top: 92px;} +.p-t-93 {padding-top: 93px;} +.p-t-94 {padding-top: 94px;} +.p-t-95 {padding-top: 95px;} +.p-t-96 {padding-top: 96px;} +.p-t-97 {padding-top: 97px;} +.p-t-98 {padding-top: 98px;} +.p-t-99 {padding-top: 99px;} +.p-t-100 {padding-top: 100px;} +.p-t-101 {padding-top: 101px;} +.p-t-102 {padding-top: 102px;} +.p-t-103 {padding-top: 103px;} +.p-t-104 {padding-top: 104px;} +.p-t-105 {padding-top: 105px;} +.p-t-106 {padding-top: 106px;} +.p-t-107 {padding-top: 107px;} +.p-t-108 {padding-top: 108px;} +.p-t-109 {padding-top: 109px;} +.p-t-110 {padding-top: 110px;} +.p-t-111 {padding-top: 111px;} +.p-t-112 {padding-top: 112px;} +.p-t-113 {padding-top: 113px;} +.p-t-114 {padding-top: 114px;} +.p-t-115 {padding-top: 115px;} +.p-t-116 {padding-top: 116px;} +.p-t-117 {padding-top: 117px;} +.p-t-118 {padding-top: 118px;} +.p-t-119 {padding-top: 119px;} +.p-t-120 {padding-top: 120px;} +.p-t-121 {padding-top: 121px;} +.p-t-122 {padding-top: 122px;} +.p-t-123 {padding-top: 123px;} +.p-t-124 {padding-top: 124px;} +.p-t-125 {padding-top: 125px;} +.p-t-126 {padding-top: 126px;} +.p-t-127 {padding-top: 127px;} +.p-t-128 {padding-top: 128px;} +.p-t-129 {padding-top: 129px;} +.p-t-130 {padding-top: 130px;} +.p-t-131 {padding-top: 131px;} +.p-t-132 {padding-top: 132px;} +.p-t-133 {padding-top: 133px;} +.p-t-134 {padding-top: 134px;} +.p-t-135 {padding-top: 135px;} +.p-t-136 {padding-top: 136px;} +.p-t-137 {padding-top: 137px;} +.p-t-138 {padding-top: 138px;} +.p-t-139 {padding-top: 139px;} +.p-t-140 {padding-top: 140px;} +.p-t-141 {padding-top: 141px;} +.p-t-142 {padding-top: 142px;} +.p-t-143 {padding-top: 143px;} +.p-t-144 {padding-top: 144px;} +.p-t-145 {padding-top: 145px;} +.p-t-146 {padding-top: 146px;} +.p-t-147 {padding-top: 147px;} +.p-t-148 {padding-top: 148px;} +.p-t-149 {padding-top: 149px;} +.p-t-150 {padding-top: 150px;} +.p-t-151 {padding-top: 151px;} +.p-t-152 {padding-top: 152px;} +.p-t-153 {padding-top: 153px;} +.p-t-154 {padding-top: 154px;} +.p-t-155 {padding-top: 155px;} +.p-t-156 {padding-top: 156px;} +.p-t-157 {padding-top: 157px;} +.p-t-158 {padding-top: 158px;} +.p-t-159 {padding-top: 159px;} +.p-t-160 {padding-top: 160px;} +.p-t-161 {padding-top: 161px;} +.p-t-162 {padding-top: 162px;} +.p-t-163 {padding-top: 163px;} +.p-t-164 {padding-top: 164px;} +.p-t-165 {padding-top: 165px;} +.p-t-166 {padding-top: 166px;} +.p-t-167 {padding-top: 167px;} +.p-t-168 {padding-top: 168px;} +.p-t-169 {padding-top: 169px;} +.p-t-170 {padding-top: 170px;} +.p-t-171 {padding-top: 171px;} +.p-t-172 {padding-top: 172px;} +.p-t-173 {padding-top: 173px;} +.p-t-174 {padding-top: 174px;} +.p-t-175 {padding-top: 175px;} +.p-t-176 {padding-top: 176px;} +.p-t-177 {padding-top: 177px;} +.p-t-178 {padding-top: 178px;} +.p-t-179 {padding-top: 179px;} +.p-t-180 {padding-top: 180px;} +.p-t-181 {padding-top: 181px;} +.p-t-182 {padding-top: 182px;} +.p-t-183 {padding-top: 183px;} +.p-t-184 {padding-top: 184px;} +.p-t-185 {padding-top: 185px;} +.p-t-186 {padding-top: 186px;} +.p-t-187 {padding-top: 187px;} +.p-t-188 {padding-top: 188px;} +.p-t-189 {padding-top: 189px;} +.p-t-190 {padding-top: 190px;} +.p-t-191 {padding-top: 191px;} +.p-t-192 {padding-top: 192px;} +.p-t-193 {padding-top: 193px;} +.p-t-194 {padding-top: 194px;} +.p-t-195 {padding-top: 195px;} +.p-t-196 {padding-top: 196px;} +.p-t-197 {padding-top: 197px;} +.p-t-198 {padding-top: 198px;} +.p-t-199 {padding-top: 199px;} +.p-t-200 {padding-top: 200px;} +.p-t-201 {padding-top: 201px;} +.p-t-202 {padding-top: 202px;} +.p-t-203 {padding-top: 203px;} +.p-t-204 {padding-top: 204px;} +.p-t-205 {padding-top: 205px;} +.p-t-206 {padding-top: 206px;} +.p-t-207 {padding-top: 207px;} +.p-t-208 {padding-top: 208px;} +.p-t-209 {padding-top: 209px;} +.p-t-210 {padding-top: 210px;} +.p-t-211 {padding-top: 211px;} +.p-t-212 {padding-top: 212px;} +.p-t-213 {padding-top: 213px;} +.p-t-214 {padding-top: 214px;} +.p-t-215 {padding-top: 215px;} +.p-t-216 {padding-top: 216px;} +.p-t-217 {padding-top: 217px;} +.p-t-218 {padding-top: 218px;} +.p-t-219 {padding-top: 219px;} +.p-t-220 {padding-top: 220px;} +.p-t-221 {padding-top: 221px;} +.p-t-222 {padding-top: 222px;} +.p-t-223 {padding-top: 223px;} +.p-t-224 {padding-top: 224px;} +.p-t-225 {padding-top: 225px;} +.p-t-226 {padding-top: 226px;} +.p-t-227 {padding-top: 227px;} +.p-t-228 {padding-top: 228px;} +.p-t-229 {padding-top: 229px;} +.p-t-230 {padding-top: 230px;} +.p-t-231 {padding-top: 231px;} +.p-t-232 {padding-top: 232px;} +.p-t-233 {padding-top: 233px;} +.p-t-234 {padding-top: 234px;} +.p-t-235 {padding-top: 235px;} +.p-t-236 {padding-top: 236px;} +.p-t-237 {padding-top: 237px;} +.p-t-238 {padding-top: 238px;} +.p-t-239 {padding-top: 239px;} +.p-t-240 {padding-top: 240px;} +.p-t-241 {padding-top: 241px;} +.p-t-242 {padding-top: 242px;} +.p-t-243 {padding-top: 243px;} +.p-t-244 {padding-top: 244px;} +.p-t-245 {padding-top: 245px;} +.p-t-246 {padding-top: 246px;} +.p-t-247 {padding-top: 247px;} +.p-t-248 {padding-top: 248px;} +.p-t-249 {padding-top: 249px;} +.p-t-250 {padding-top: 250px;} +.p-b-0 {padding-bottom: 0px;} +.p-b-1 {padding-bottom: 1px;} +.p-b-2 {padding-bottom: 2px;} +.p-b-3 {padding-bottom: 3px;} +.p-b-4 {padding-bottom: 4px;} +.p-b-5 {padding-bottom: 5px;} +.p-b-6 {padding-bottom: 6px;} +.p-b-7 {padding-bottom: 7px;} +.p-b-8 {padding-bottom: 8px;} +.p-b-9 {padding-bottom: 9px;} +.p-b-10 {padding-bottom: 10px;} +.p-b-11 {padding-bottom: 11px;} +.p-b-12 {padding-bottom: 12px;} +.p-b-13 {padding-bottom: 13px;} +.p-b-14 {padding-bottom: 14px;} +.p-b-15 {padding-bottom: 15px;} +.p-b-16 {padding-bottom: 16px;} +.p-b-17 {padding-bottom: 17px;} +.p-b-18 {padding-bottom: 18px;} +.p-b-19 {padding-bottom: 19px;} +.p-b-20 {padding-bottom: 20px;} +.p-b-21 {padding-bottom: 21px;} +.p-b-22 {padding-bottom: 22px;} +.p-b-23 {padding-bottom: 23px;} +.p-b-24 {padding-bottom: 24px;} +.p-b-25 {padding-bottom: 25px;} +.p-b-26 {padding-bottom: 26px;} +.p-b-27 {padding-bottom: 27px;} +.p-b-28 {padding-bottom: 28px;} +.p-b-29 {padding-bottom: 29px;} +.p-b-30 {padding-bottom: 30px;} +.p-b-31 {padding-bottom: 31px;} +.p-b-32 {padding-bottom: 32px;} +.p-b-33 {padding-bottom: 33px;} +.p-b-34 {padding-bottom: 34px;} +.p-b-35 {padding-bottom: 35px;} +.p-b-36 {padding-bottom: 36px;} +.p-b-37 {padding-bottom: 37px;} +.p-b-38 {padding-bottom: 38px;} +.p-b-39 {padding-bottom: 39px;} +.p-b-40 {padding-bottom: 40px;} +.p-b-41 {padding-bottom: 41px;} +.p-b-42 {padding-bottom: 42px;} +.p-b-43 {padding-bottom: 43px;} +.p-b-44 {padding-bottom: 44px;} +.p-b-45 {padding-bottom: 45px;} +.p-b-46 {padding-bottom: 46px;} +.p-b-47 {padding-bottom: 47px;} +.p-b-48 {padding-bottom: 48px;} +.p-b-49 {padding-bottom: 49px;} +.p-b-50 {padding-bottom: 50px;} +.p-b-51 {padding-bottom: 51px;} +.p-b-52 {padding-bottom: 52px;} +.p-b-53 {padding-bottom: 53px;} +.p-b-54 {padding-bottom: 54px;} +.p-b-55 {padding-bottom: 55px;} +.p-b-56 {padding-bottom: 56px;} +.p-b-57 {padding-bottom: 57px;} +.p-b-58 {padding-bottom: 58px;} +.p-b-59 {padding-bottom: 59px;} +.p-b-60 {padding-bottom: 60px;} +.p-b-61 {padding-bottom: 61px;} +.p-b-62 {padding-bottom: 62px;} +.p-b-63 {padding-bottom: 63px;} +.p-b-64 {padding-bottom: 64px;} +.p-b-65 {padding-bottom: 65px;} +.p-b-66 {padding-bottom: 66px;} +.p-b-67 {padding-bottom: 67px;} +.p-b-68 {padding-bottom: 68px;} +.p-b-69 {padding-bottom: 69px;} +.p-b-70 {padding-bottom: 70px;} +.p-b-71 {padding-bottom: 71px;} +.p-b-72 {padding-bottom: 72px;} +.p-b-73 {padding-bottom: 73px;} +.p-b-74 {padding-bottom: 74px;} +.p-b-75 {padding-bottom: 75px;} +.p-b-76 {padding-bottom: 76px;} +.p-b-77 {padding-bottom: 77px;} +.p-b-78 {padding-bottom: 78px;} +.p-b-79 {padding-bottom: 79px;} +.p-b-80 {padding-bottom: 80px;} +.p-b-81 {padding-bottom: 81px;} +.p-b-82 {padding-bottom: 82px;} +.p-b-83 {padding-bottom: 83px;} +.p-b-84 {padding-bottom: 84px;} +.p-b-85 {padding-bottom: 85px;} +.p-b-86 {padding-bottom: 86px;} +.p-b-87 {padding-bottom: 87px;} +.p-b-88 {padding-bottom: 88px;} +.p-b-89 {padding-bottom: 89px;} +.p-b-90 {padding-bottom: 90px;} +.p-b-91 {padding-bottom: 91px;} +.p-b-92 {padding-bottom: 92px;} +.p-b-93 {padding-bottom: 93px;} +.p-b-94 {padding-bottom: 94px;} +.p-b-95 {padding-bottom: 95px;} +.p-b-96 {padding-bottom: 96px;} +.p-b-97 {padding-bottom: 97px;} +.p-b-98 {padding-bottom: 98px;} +.p-b-99 {padding-bottom: 99px;} +.p-b-100 {padding-bottom: 100px;} +.p-b-101 {padding-bottom: 101px;} +.p-b-102 {padding-bottom: 102px;} +.p-b-103 {padding-bottom: 103px;} +.p-b-104 {padding-bottom: 104px;} +.p-b-105 {padding-bottom: 105px;} +.p-b-106 {padding-bottom: 106px;} +.p-b-107 {padding-bottom: 107px;} +.p-b-108 {padding-bottom: 108px;} +.p-b-109 {padding-bottom: 109px;} +.p-b-110 {padding-bottom: 110px;} +.p-b-111 {padding-bottom: 111px;} +.p-b-112 {padding-bottom: 112px;} +.p-b-113 {padding-bottom: 113px;} +.p-b-114 {padding-bottom: 114px;} +.p-b-115 {padding-bottom: 115px;} +.p-b-116 {padding-bottom: 116px;} +.p-b-117 {padding-bottom: 117px;} +.p-b-118 {padding-bottom: 118px;} +.p-b-119 {padding-bottom: 119px;} +.p-b-120 {padding-bottom: 120px;} +.p-b-121 {padding-bottom: 121px;} +.p-b-122 {padding-bottom: 122px;} +.p-b-123 {padding-bottom: 123px;} +.p-b-124 {padding-bottom: 124px;} +.p-b-125 {padding-bottom: 125px;} +.p-b-126 {padding-bottom: 126px;} +.p-b-127 {padding-bottom: 127px;} +.p-b-128 {padding-bottom: 128px;} +.p-b-129 {padding-bottom: 129px;} +.p-b-130 {padding-bottom: 130px;} +.p-b-131 {padding-bottom: 131px;} +.p-b-132 {padding-bottom: 132px;} +.p-b-133 {padding-bottom: 133px;} +.p-b-134 {padding-bottom: 134px;} +.p-b-135 {padding-bottom: 135px;} +.p-b-136 {padding-bottom: 136px;} +.p-b-137 {padding-bottom: 137px;} +.p-b-138 {padding-bottom: 138px;} +.p-b-139 {padding-bottom: 139px;} +.p-b-140 {padding-bottom: 140px;} +.p-b-141 {padding-bottom: 141px;} +.p-b-142 {padding-bottom: 142px;} +.p-b-143 {padding-bottom: 143px;} +.p-b-144 {padding-bottom: 144px;} +.p-b-145 {padding-bottom: 145px;} +.p-b-146 {padding-bottom: 146px;} +.p-b-147 {padding-bottom: 147px;} +.p-b-148 {padding-bottom: 148px;} +.p-b-149 {padding-bottom: 149px;} +.p-b-150 {padding-bottom: 150px;} +.p-b-151 {padding-bottom: 151px;} +.p-b-152 {padding-bottom: 152px;} +.p-b-153 {padding-bottom: 153px;} +.p-b-154 {padding-bottom: 154px;} +.p-b-155 {padding-bottom: 155px;} +.p-b-156 {padding-bottom: 156px;} +.p-b-157 {padding-bottom: 157px;} +.p-b-158 {padding-bottom: 158px;} +.p-b-159 {padding-bottom: 159px;} +.p-b-160 {padding-bottom: 160px;} +.p-b-161 {padding-bottom: 161px;} +.p-b-162 {padding-bottom: 162px;} +.p-b-163 {padding-bottom: 163px;} +.p-b-164 {padding-bottom: 164px;} +.p-b-165 {padding-bottom: 165px;} +.p-b-166 {padding-bottom: 166px;} +.p-b-167 {padding-bottom: 167px;} +.p-b-168 {padding-bottom: 168px;} +.p-b-169 {padding-bottom: 169px;} +.p-b-170 {padding-bottom: 170px;} +.p-b-171 {padding-bottom: 171px;} +.p-b-172 {padding-bottom: 172px;} +.p-b-173 {padding-bottom: 173px;} +.p-b-174 {padding-bottom: 174px;} +.p-b-175 {padding-bottom: 175px;} +.p-b-176 {padding-bottom: 176px;} +.p-b-177 {padding-bottom: 177px;} +.p-b-178 {padding-bottom: 178px;} +.p-b-179 {padding-bottom: 179px;} +.p-b-180 {padding-bottom: 180px;} +.p-b-181 {padding-bottom: 181px;} +.p-b-182 {padding-bottom: 182px;} +.p-b-183 {padding-bottom: 183px;} +.p-b-184 {padding-bottom: 184px;} +.p-b-185 {padding-bottom: 185px;} +.p-b-186 {padding-bottom: 186px;} +.p-b-187 {padding-bottom: 187px;} +.p-b-188 {padding-bottom: 188px;} +.p-b-189 {padding-bottom: 189px;} +.p-b-190 {padding-bottom: 190px;} +.p-b-191 {padding-bottom: 191px;} +.p-b-192 {padding-bottom: 192px;} +.p-b-193 {padding-bottom: 193px;} +.p-b-194 {padding-bottom: 194px;} +.p-b-195 {padding-bottom: 195px;} +.p-b-196 {padding-bottom: 196px;} +.p-b-197 {padding-bottom: 197px;} +.p-b-198 {padding-bottom: 198px;} +.p-b-199 {padding-bottom: 199px;} +.p-b-200 {padding-bottom: 200px;} +.p-b-201 {padding-bottom: 201px;} +.p-b-202 {padding-bottom: 202px;} +.p-b-203 {padding-bottom: 203px;} +.p-b-204 {padding-bottom: 204px;} +.p-b-205 {padding-bottom: 205px;} +.p-b-206 {padding-bottom: 206px;} +.p-b-207 {padding-bottom: 207px;} +.p-b-208 {padding-bottom: 208px;} +.p-b-209 {padding-bottom: 209px;} +.p-b-210 {padding-bottom: 210px;} +.p-b-211 {padding-bottom: 211px;} +.p-b-212 {padding-bottom: 212px;} +.p-b-213 {padding-bottom: 213px;} +.p-b-214 {padding-bottom: 214px;} +.p-b-215 {padding-bottom: 215px;} +.p-b-216 {padding-bottom: 216px;} +.p-b-217 {padding-bottom: 217px;} +.p-b-218 {padding-bottom: 218px;} +.p-b-219 {padding-bottom: 219px;} +.p-b-220 {padding-bottom: 220px;} +.p-b-221 {padding-bottom: 221px;} +.p-b-222 {padding-bottom: 222px;} +.p-b-223 {padding-bottom: 223px;} +.p-b-224 {padding-bottom: 224px;} +.p-b-225 {padding-bottom: 225px;} +.p-b-226 {padding-bottom: 226px;} +.p-b-227 {padding-bottom: 227px;} +.p-b-228 {padding-bottom: 228px;} +.p-b-229 {padding-bottom: 229px;} +.p-b-230 {padding-bottom: 230px;} +.p-b-231 {padding-bottom: 231px;} +.p-b-232 {padding-bottom: 232px;} +.p-b-233 {padding-bottom: 233px;} +.p-b-234 {padding-bottom: 234px;} +.p-b-235 {padding-bottom: 235px;} +.p-b-236 {padding-bottom: 236px;} +.p-b-237 {padding-bottom: 237px;} +.p-b-238 {padding-bottom: 238px;} +.p-b-239 {padding-bottom: 239px;} +.p-b-240 {padding-bottom: 240px;} +.p-b-241 {padding-bottom: 241px;} +.p-b-242 {padding-bottom: 242px;} +.p-b-243 {padding-bottom: 243px;} +.p-b-244 {padding-bottom: 244px;} +.p-b-245 {padding-bottom: 245px;} +.p-b-246 {padding-bottom: 246px;} +.p-b-247 {padding-bottom: 247px;} +.p-b-248 {padding-bottom: 248px;} +.p-b-249 {padding-bottom: 249px;} +.p-b-250 {padding-bottom: 250px;} +.p-l-0 {padding-left: 0px;} +.p-l-1 {padding-left: 1px;} +.p-l-2 {padding-left: 2px;} +.p-l-3 {padding-left: 3px;} +.p-l-4 {padding-left: 4px;} +.p-l-5 {padding-left: 5px;} +.p-l-6 {padding-left: 6px;} +.p-l-7 {padding-left: 7px;} +.p-l-8 {padding-left: 8px;} +.p-l-9 {padding-left: 9px;} +.p-l-10 {padding-left: 10px;} +.p-l-11 {padding-left: 11px;} +.p-l-12 {padding-left: 12px;} +.p-l-13 {padding-left: 13px;} +.p-l-14 {padding-left: 14px;} +.p-l-15 {padding-left: 15px;} +.p-l-16 {padding-left: 16px;} +.p-l-17 {padding-left: 17px;} +.p-l-18 {padding-left: 18px;} +.p-l-19 {padding-left: 19px;} +.p-l-20 {padding-left: 20px;} +.p-l-21 {padding-left: 21px;} +.p-l-22 {padding-left: 22px;} +.p-l-23 {padding-left: 23px;} +.p-l-24 {padding-left: 24px;} +.p-l-25 {padding-left: 25px;} +.p-l-26 {padding-left: 26px;} +.p-l-27 {padding-left: 27px;} +.p-l-28 {padding-left: 28px;} +.p-l-29 {padding-left: 29px;} +.p-l-30 {padding-left: 30px;} +.p-l-31 {padding-left: 31px;} +.p-l-32 {padding-left: 32px;} +.p-l-33 {padding-left: 33px;} +.p-l-34 {padding-left: 34px;} +.p-l-35 {padding-left: 35px;} +.p-l-36 {padding-left: 36px;} +.p-l-37 {padding-left: 37px;} +.p-l-38 {padding-left: 38px;} +.p-l-39 {padding-left: 39px;} +.p-l-40 {padding-left: 40px;} +.p-l-41 {padding-left: 41px;} +.p-l-42 {padding-left: 42px;} +.p-l-43 {padding-left: 43px;} +.p-l-44 {padding-left: 44px;} +.p-l-45 {padding-left: 45px;} +.p-l-46 {padding-left: 46px;} +.p-l-47 {padding-left: 47px;} +.p-l-48 {padding-left: 48px;} +.p-l-49 {padding-left: 49px;} +.p-l-50 {padding-left: 50px;} +.p-l-51 {padding-left: 51px;} +.p-l-52 {padding-left: 52px;} +.p-l-53 {padding-left: 53px;} +.p-l-54 {padding-left: 54px;} +.p-l-55 {padding-left: 55px;} +.p-l-56 {padding-left: 56px;} +.p-l-57 {padding-left: 57px;} +.p-l-58 {padding-left: 58px;} +.p-l-59 {padding-left: 59px;} +.p-l-60 {padding-left: 60px;} +.p-l-61 {padding-left: 61px;} +.p-l-62 {padding-left: 62px;} +.p-l-63 {padding-left: 63px;} +.p-l-64 {padding-left: 64px;} +.p-l-65 {padding-left: 65px;} +.p-l-66 {padding-left: 66px;} +.p-l-67 {padding-left: 67px;} +.p-l-68 {padding-left: 68px;} +.p-l-69 {padding-left: 69px;} +.p-l-70 {padding-left: 70px;} +.p-l-71 {padding-left: 71px;} +.p-l-72 {padding-left: 72px;} +.p-l-73 {padding-left: 73px;} +.p-l-74 {padding-left: 74px;} +.p-l-75 {padding-left: 75px;} +.p-l-76 {padding-left: 76px;} +.p-l-77 {padding-left: 77px;} +.p-l-78 {padding-left: 78px;} +.p-l-79 {padding-left: 79px;} +.p-l-80 {padding-left: 80px;} +.p-l-81 {padding-left: 81px;} +.p-l-82 {padding-left: 82px;} +.p-l-83 {padding-left: 83px;} +.p-l-84 {padding-left: 84px;} +.p-l-85 {padding-left: 85px;} +.p-l-86 {padding-left: 86px;} +.p-l-87 {padding-left: 87px;} +.p-l-88 {padding-left: 88px;} +.p-l-89 {padding-left: 89px;} +.p-l-90 {padding-left: 90px;} +.p-l-91 {padding-left: 91px;} +.p-l-92 {padding-left: 92px;} +.p-l-93 {padding-left: 93px;} +.p-l-94 {padding-left: 94px;} +.p-l-95 {padding-left: 95px;} +.p-l-96 {padding-left: 96px;} +.p-l-97 {padding-left: 97px;} +.p-l-98 {padding-left: 98px;} +.p-l-99 {padding-left: 99px;} +.p-l-100 {padding-left: 100px;} +.p-l-101 {padding-left: 101px;} +.p-l-102 {padding-left: 102px;} +.p-l-103 {padding-left: 103px;} +.p-l-104 {padding-left: 104px;} +.p-l-105 {padding-left: 105px;} +.p-l-106 {padding-left: 106px;} +.p-l-107 {padding-left: 107px;} +.p-l-108 {padding-left: 108px;} +.p-l-109 {padding-left: 109px;} +.p-l-110 {padding-left: 110px;} +.p-l-111 {padding-left: 111px;} +.p-l-112 {padding-left: 112px;} +.p-l-113 {padding-left: 113px;} +.p-l-114 {padding-left: 114px;} +.p-l-115 {padding-left: 115px;} +.p-l-116 {padding-left: 116px;} +.p-l-117 {padding-left: 117px;} +.p-l-118 {padding-left: 118px;} +.p-l-119 {padding-left: 119px;} +.p-l-120 {padding-left: 120px;} +.p-l-121 {padding-left: 121px;} +.p-l-122 {padding-left: 122px;} +.p-l-123 {padding-left: 123px;} +.p-l-124 {padding-left: 124px;} +.p-l-125 {padding-left: 125px;} +.p-l-126 {padding-left: 126px;} +.p-l-127 {padding-left: 127px;} +.p-l-128 {padding-left: 128px;} +.p-l-129 {padding-left: 129px;} +.p-l-130 {padding-left: 130px;} +.p-l-131 {padding-left: 131px;} +.p-l-132 {padding-left: 132px;} +.p-l-133 {padding-left: 133px;} +.p-l-134 {padding-left: 134px;} +.p-l-135 {padding-left: 135px;} +.p-l-136 {padding-left: 136px;} +.p-l-137 {padding-left: 137px;} +.p-l-138 {padding-left: 138px;} +.p-l-139 {padding-left: 139px;} +.p-l-140 {padding-left: 140px;} +.p-l-141 {padding-left: 141px;} +.p-l-142 {padding-left: 142px;} +.p-l-143 {padding-left: 143px;} +.p-l-144 {padding-left: 144px;} +.p-l-145 {padding-left: 145px;} +.p-l-146 {padding-left: 146px;} +.p-l-147 {padding-left: 147px;} +.p-l-148 {padding-left: 148px;} +.p-l-149 {padding-left: 149px;} +.p-l-150 {padding-left: 150px;} +.p-l-151 {padding-left: 151px;} +.p-l-152 {padding-left: 152px;} +.p-l-153 {padding-left: 153px;} +.p-l-154 {padding-left: 154px;} +.p-l-155 {padding-left: 155px;} +.p-l-156 {padding-left: 156px;} +.p-l-157 {padding-left: 157px;} +.p-l-158 {padding-left: 158px;} +.p-l-159 {padding-left: 159px;} +.p-l-160 {padding-left: 160px;} +.p-l-161 {padding-left: 161px;} +.p-l-162 {padding-left: 162px;} +.p-l-163 {padding-left: 163px;} +.p-l-164 {padding-left: 164px;} +.p-l-165 {padding-left: 165px;} +.p-l-166 {padding-left: 166px;} +.p-l-167 {padding-left: 167px;} +.p-l-168 {padding-left: 168px;} +.p-l-169 {padding-left: 169px;} +.p-l-170 {padding-left: 170px;} +.p-l-171 {padding-left: 171px;} +.p-l-172 {padding-left: 172px;} +.p-l-173 {padding-left: 173px;} +.p-l-174 {padding-left: 174px;} +.p-l-175 {padding-left: 175px;} +.p-l-176 {padding-left: 176px;} +.p-l-177 {padding-left: 177px;} +.p-l-178 {padding-left: 178px;} +.p-l-179 {padding-left: 179px;} +.p-l-180 {padding-left: 180px;} +.p-l-181 {padding-left: 181px;} +.p-l-182 {padding-left: 182px;} +.p-l-183 {padding-left: 183px;} +.p-l-184 {padding-left: 184px;} +.p-l-185 {padding-left: 185px;} +.p-l-186 {padding-left: 186px;} +.p-l-187 {padding-left: 187px;} +.p-l-188 {padding-left: 188px;} +.p-l-189 {padding-left: 189px;} +.p-l-190 {padding-left: 190px;} +.p-l-191 {padding-left: 191px;} +.p-l-192 {padding-left: 192px;} +.p-l-193 {padding-left: 193px;} +.p-l-194 {padding-left: 194px;} +.p-l-195 {padding-left: 195px;} +.p-l-196 {padding-left: 196px;} +.p-l-197 {padding-left: 197px;} +.p-l-198 {padding-left: 198px;} +.p-l-199 {padding-left: 199px;} +.p-l-200 {padding-left: 200px;} +.p-l-201 {padding-left: 201px;} +.p-l-202 {padding-left: 202px;} +.p-l-203 {padding-left: 203px;} +.p-l-204 {padding-left: 204px;} +.p-l-205 {padding-left: 205px;} +.p-l-206 {padding-left: 206px;} +.p-l-207 {padding-left: 207px;} +.p-l-208 {padding-left: 208px;} +.p-l-209 {padding-left: 209px;} +.p-l-210 {padding-left: 210px;} +.p-l-211 {padding-left: 211px;} +.p-l-212 {padding-left: 212px;} +.p-l-213 {padding-left: 213px;} +.p-l-214 {padding-left: 214px;} +.p-l-215 {padding-left: 215px;} +.p-l-216 {padding-left: 216px;} +.p-l-217 {padding-left: 217px;} +.p-l-218 {padding-left: 218px;} +.p-l-219 {padding-left: 219px;} +.p-l-220 {padding-left: 220px;} +.p-l-221 {padding-left: 221px;} +.p-l-222 {padding-left: 222px;} +.p-l-223 {padding-left: 223px;} +.p-l-224 {padding-left: 224px;} +.p-l-225 {padding-left: 225px;} +.p-l-226 {padding-left: 226px;} +.p-l-227 {padding-left: 227px;} +.p-l-228 {padding-left: 228px;} +.p-l-229 {padding-left: 229px;} +.p-l-230 {padding-left: 230px;} +.p-l-231 {padding-left: 231px;} +.p-l-232 {padding-left: 232px;} +.p-l-233 {padding-left: 233px;} +.p-l-234 {padding-left: 234px;} +.p-l-235 {padding-left: 235px;} +.p-l-236 {padding-left: 236px;} +.p-l-237 {padding-left: 237px;} +.p-l-238 {padding-left: 238px;} +.p-l-239 {padding-left: 239px;} +.p-l-240 {padding-left: 240px;} +.p-l-241 {padding-left: 241px;} +.p-l-242 {padding-left: 242px;} +.p-l-243 {padding-left: 243px;} +.p-l-244 {padding-left: 244px;} +.p-l-245 {padding-left: 245px;} +.p-l-246 {padding-left: 246px;} +.p-l-247 {padding-left: 247px;} +.p-l-248 {padding-left: 248px;} +.p-l-249 {padding-left: 249px;} +.p-l-250 {padding-left: 250px;} +.p-r-0 {padding-right: 0px;} +.p-r-1 {padding-right: 1px;} +.p-r-2 {padding-right: 2px;} +.p-r-3 {padding-right: 3px;} +.p-r-4 {padding-right: 4px;} +.p-r-5 {padding-right: 5px;} +.p-r-6 {padding-right: 6px;} +.p-r-7 {padding-right: 7px;} +.p-r-8 {padding-right: 8px;} +.p-r-9 {padding-right: 9px;} +.p-r-10 {padding-right: 10px;} +.p-r-11 {padding-right: 11px;} +.p-r-12 {padding-right: 12px;} +.p-r-13 {padding-right: 13px;} +.p-r-14 {padding-right: 14px;} +.p-r-15 {padding-right: 15px;} +.p-r-16 {padding-right: 16px;} +.p-r-17 {padding-right: 17px;} +.p-r-18 {padding-right: 18px;} +.p-r-19 {padding-right: 19px;} +.p-r-20 {padding-right: 20px;} +.p-r-21 {padding-right: 21px;} +.p-r-22 {padding-right: 22px;} +.p-r-23 {padding-right: 23px;} +.p-r-24 {padding-right: 24px;} +.p-r-25 {padding-right: 25px;} +.p-r-26 {padding-right: 26px;} +.p-r-27 {padding-right: 27px;} +.p-r-28 {padding-right: 28px;} +.p-r-29 {padding-right: 29px;} +.p-r-30 {padding-right: 30px;} +.p-r-31 {padding-right: 31px;} +.p-r-32 {padding-right: 32px;} +.p-r-33 {padding-right: 33px;} +.p-r-34 {padding-right: 34px;} +.p-r-35 {padding-right: 35px;} +.p-r-36 {padding-right: 36px;} +.p-r-37 {padding-right: 37px;} +.p-r-38 {padding-right: 38px;} +.p-r-39 {padding-right: 39px;} +.p-r-40 {padding-right: 40px;} +.p-r-41 {padding-right: 41px;} +.p-r-42 {padding-right: 42px;} +.p-r-43 {padding-right: 43px;} +.p-r-44 {padding-right: 44px;} +.p-r-45 {padding-right: 45px;} +.p-r-46 {padding-right: 46px;} +.p-r-47 {padding-right: 47px;} +.p-r-48 {padding-right: 48px;} +.p-r-49 {padding-right: 49px;} +.p-r-50 {padding-right: 50px;} +.p-r-51 {padding-right: 51px;} +.p-r-52 {padding-right: 52px;} +.p-r-53 {padding-right: 53px;} +.p-r-54 {padding-right: 54px;} +.p-r-55 {padding-right: 55px;} +.p-r-56 {padding-right: 56px;} +.p-r-57 {padding-right: 57px;} +.p-r-58 {padding-right: 58px;} +.p-r-59 {padding-right: 59px;} +.p-r-60 {padding-right: 60px;} +.p-r-61 {padding-right: 61px;} +.p-r-62 {padding-right: 62px;} +.p-r-63 {padding-right: 63px;} +.p-r-64 {padding-right: 64px;} +.p-r-65 {padding-right: 65px;} +.p-r-66 {padding-right: 66px;} +.p-r-67 {padding-right: 67px;} +.p-r-68 {padding-right: 68px;} +.p-r-69 {padding-right: 69px;} +.p-r-70 {padding-right: 70px;} +.p-r-71 {padding-right: 71px;} +.p-r-72 {padding-right: 72px;} +.p-r-73 {padding-right: 73px;} +.p-r-74 {padding-right: 74px;} +.p-r-75 {padding-right: 75px;} +.p-r-76 {padding-right: 76px;} +.p-r-77 {padding-right: 77px;} +.p-r-78 {padding-right: 78px;} +.p-r-79 {padding-right: 79px;} +.p-r-80 {padding-right: 80px;} +.p-r-81 {padding-right: 81px;} +.p-r-82 {padding-right: 82px;} +.p-r-83 {padding-right: 83px;} +.p-r-84 {padding-right: 84px;} +.p-r-85 {padding-right: 85px;} +.p-r-86 {padding-right: 86px;} +.p-r-87 {padding-right: 87px;} +.p-r-88 {padding-right: 88px;} +.p-r-89 {padding-right: 89px;} +.p-r-90 {padding-right: 90px;} +.p-r-91 {padding-right: 91px;} +.p-r-92 {padding-right: 92px;} +.p-r-93 {padding-right: 93px;} +.p-r-94 {padding-right: 94px;} +.p-r-95 {padding-right: 95px;} +.p-r-96 {padding-right: 96px;} +.p-r-97 {padding-right: 97px;} +.p-r-98 {padding-right: 98px;} +.p-r-99 {padding-right: 99px;} +.p-r-100 {padding-right: 100px;} +.p-r-101 {padding-right: 101px;} +.p-r-102 {padding-right: 102px;} +.p-r-103 {padding-right: 103px;} +.p-r-104 {padding-right: 104px;} +.p-r-105 {padding-right: 105px;} +.p-r-106 {padding-right: 106px;} +.p-r-107 {padding-right: 107px;} +.p-r-108 {padding-right: 108px;} +.p-r-109 {padding-right: 109px;} +.p-r-110 {padding-right: 110px;} +.p-r-111 {padding-right: 111px;} +.p-r-112 {padding-right: 112px;} +.p-r-113 {padding-right: 113px;} +.p-r-114 {padding-right: 114px;} +.p-r-115 {padding-right: 115px;} +.p-r-116 {padding-right: 116px;} +.p-r-117 {padding-right: 117px;} +.p-r-118 {padding-right: 118px;} +.p-r-119 {padding-right: 119px;} +.p-r-120 {padding-right: 120px;} +.p-r-121 {padding-right: 121px;} +.p-r-122 {padding-right: 122px;} +.p-r-123 {padding-right: 123px;} +.p-r-124 {padding-right: 124px;} +.p-r-125 {padding-right: 125px;} +.p-r-126 {padding-right: 126px;} +.p-r-127 {padding-right: 127px;} +.p-r-128 {padding-right: 128px;} +.p-r-129 {padding-right: 129px;} +.p-r-130 {padding-right: 130px;} +.p-r-131 {padding-right: 131px;} +.p-r-132 {padding-right: 132px;} +.p-r-133 {padding-right: 133px;} +.p-r-134 {padding-right: 134px;} +.p-r-135 {padding-right: 135px;} +.p-r-136 {padding-right: 136px;} +.p-r-137 {padding-right: 137px;} +.p-r-138 {padding-right: 138px;} +.p-r-139 {padding-right: 139px;} +.p-r-140 {padding-right: 140px;} +.p-r-141 {padding-right: 141px;} +.p-r-142 {padding-right: 142px;} +.p-r-143 {padding-right: 143px;} +.p-r-144 {padding-right: 144px;} +.p-r-145 {padding-right: 145px;} +.p-r-146 {padding-right: 146px;} +.p-r-147 {padding-right: 147px;} +.p-r-148 {padding-right: 148px;} +.p-r-149 {padding-right: 149px;} +.p-r-150 {padding-right: 150px;} +.p-r-151 {padding-right: 151px;} +.p-r-152 {padding-right: 152px;} +.p-r-153 {padding-right: 153px;} +.p-r-154 {padding-right: 154px;} +.p-r-155 {padding-right: 155px;} +.p-r-156 {padding-right: 156px;} +.p-r-157 {padding-right: 157px;} +.p-r-158 {padding-right: 158px;} +.p-r-159 {padding-right: 159px;} +.p-r-160 {padding-right: 160px;} +.p-r-161 {padding-right: 161px;} +.p-r-162 {padding-right: 162px;} +.p-r-163 {padding-right: 163px;} +.p-r-164 {padding-right: 164px;} +.p-r-165 {padding-right: 165px;} +.p-r-166 {padding-right: 166px;} +.p-r-167 {padding-right: 167px;} +.p-r-168 {padding-right: 168px;} +.p-r-169 {padding-right: 169px;} +.p-r-170 {padding-right: 170px;} +.p-r-171 {padding-right: 171px;} +.p-r-172 {padding-right: 172px;} +.p-r-173 {padding-right: 173px;} +.p-r-174 {padding-right: 174px;} +.p-r-175 {padding-right: 175px;} +.p-r-176 {padding-right: 176px;} +.p-r-177 {padding-right: 177px;} +.p-r-178 {padding-right: 178px;} +.p-r-179 {padding-right: 179px;} +.p-r-180 {padding-right: 180px;} +.p-r-181 {padding-right: 181px;} +.p-r-182 {padding-right: 182px;} +.p-r-183 {padding-right: 183px;} +.p-r-184 {padding-right: 184px;} +.p-r-185 {padding-right: 185px;} +.p-r-186 {padding-right: 186px;} +.p-r-187 {padding-right: 187px;} +.p-r-188 {padding-right: 188px;} +.p-r-189 {padding-right: 189px;} +.p-r-190 {padding-right: 190px;} +.p-r-191 {padding-right: 191px;} +.p-r-192 {padding-right: 192px;} +.p-r-193 {padding-right: 193px;} +.p-r-194 {padding-right: 194px;} +.p-r-195 {padding-right: 195px;} +.p-r-196 {padding-right: 196px;} +.p-r-197 {padding-right: 197px;} +.p-r-198 {padding-right: 198px;} +.p-r-199 {padding-right: 199px;} +.p-r-200 {padding-right: 200px;} +.p-r-201 {padding-right: 201px;} +.p-r-202 {padding-right: 202px;} +.p-r-203 {padding-right: 203px;} +.p-r-204 {padding-right: 204px;} +.p-r-205 {padding-right: 205px;} +.p-r-206 {padding-right: 206px;} +.p-r-207 {padding-right: 207px;} +.p-r-208 {padding-right: 208px;} +.p-r-209 {padding-right: 209px;} +.p-r-210 {padding-right: 210px;} +.p-r-211 {padding-right: 211px;} +.p-r-212 {padding-right: 212px;} +.p-r-213 {padding-right: 213px;} +.p-r-214 {padding-right: 214px;} +.p-r-215 {padding-right: 215px;} +.p-r-216 {padding-right: 216px;} +.p-r-217 {padding-right: 217px;} +.p-r-218 {padding-right: 218px;} +.p-r-219 {padding-right: 219px;} +.p-r-220 {padding-right: 220px;} +.p-r-221 {padding-right: 221px;} +.p-r-222 {padding-right: 222px;} +.p-r-223 {padding-right: 223px;} +.p-r-224 {padding-right: 224px;} +.p-r-225 {padding-right: 225px;} +.p-r-226 {padding-right: 226px;} +.p-r-227 {padding-right: 227px;} +.p-r-228 {padding-right: 228px;} +.p-r-229 {padding-right: 229px;} +.p-r-230 {padding-right: 230px;} +.p-r-231 {padding-right: 231px;} +.p-r-232 {padding-right: 232px;} +.p-r-233 {padding-right: 233px;} +.p-r-234 {padding-right: 234px;} +.p-r-235 {padding-right: 235px;} +.p-r-236 {padding-right: 236px;} +.p-r-237 {padding-right: 237px;} +.p-r-238 {padding-right: 238px;} +.p-r-239 {padding-right: 239px;} +.p-r-240 {padding-right: 240px;} +.p-r-241 {padding-right: 241px;} +.p-r-242 {padding-right: 242px;} +.p-r-243 {padding-right: 243px;} +.p-r-244 {padding-right: 244px;} +.p-r-245 {padding-right: 245px;} +.p-r-246 {padding-right: 246px;} +.p-r-247 {padding-right: 247px;} +.p-r-248 {padding-right: 248px;} +.p-r-249 {padding-right: 249px;} +.p-r-250 {padding-right: 250px;} + +/*////////////////////////////////////////////////////////////////// +[ MARGIN ]*/ +.m-t-0 {margin-top: 0px;} +.m-t-1 {margin-top: 1px;} +.m-t-2 {margin-top: 2px;} +.m-t-3 {margin-top: 3px;} +.m-t-4 {margin-top: 4px;} +.m-t-5 {margin-top: 5px;} +.m-t-6 {margin-top: 6px;} +.m-t-7 {margin-top: 7px;} +.m-t-8 {margin-top: 8px;} +.m-t-9 {margin-top: 9px;} +.m-t-10 {margin-top: 10px;} +.m-t-11 {margin-top: 11px;} +.m-t-12 {margin-top: 12px;} +.m-t-13 {margin-top: 13px;} +.m-t-14 {margin-top: 14px;} +.m-t-15 {margin-top: 15px;} +.m-t-16 {margin-top: 16px;} +.m-t-17 {margin-top: 17px;} +.m-t-18 {margin-top: 18px;} +.m-t-19 {margin-top: 19px;} +.m-t-20 {margin-top: 20px;} +.m-t-21 {margin-top: 21px;} +.m-t-22 {margin-top: 22px;} +.m-t-23 {margin-top: 23px;} +.m-t-24 {margin-top: 24px;} +.m-t-25 {margin-top: 25px;} +.m-t-26 {margin-top: 26px;} +.m-t-27 {margin-top: 27px;} +.m-t-28 {margin-top: 28px;} +.m-t-29 {margin-top: 29px;} +.m-t-30 {margin-top: 30px;} +.m-t-31 {margin-top: 31px;} +.m-t-32 {margin-top: 32px;} +.m-t-33 {margin-top: 33px;} +.m-t-34 {margin-top: 34px;} +.m-t-35 {margin-top: 35px;} +.m-t-36 {margin-top: 36px;} +.m-t-37 {margin-top: 37px;} +.m-t-38 {margin-top: 38px;} +.m-t-39 {margin-top: 39px;} +.m-t-40 {margin-top: 40px;} +.m-t-41 {margin-top: 41px;} +.m-t-42 {margin-top: 42px;} +.m-t-43 {margin-top: 43px;} +.m-t-44 {margin-top: 44px;} +.m-t-45 {margin-top: 45px;} +.m-t-46 {margin-top: 46px;} +.m-t-47 {margin-top: 47px;} +.m-t-48 {margin-top: 48px;} +.m-t-49 {margin-top: 49px;} +.m-t-50 {margin-top: 50px;} +.m-t-51 {margin-top: 51px;} +.m-t-52 {margin-top: 52px;} +.m-t-53 {margin-top: 53px;} +.m-t-54 {margin-top: 54px;} +.m-t-55 {margin-top: 55px;} +.m-t-56 {margin-top: 56px;} +.m-t-57 {margin-top: 57px;} +.m-t-58 {margin-top: 58px;} +.m-t-59 {margin-top: 59px;} +.m-t-60 {margin-top: 60px;} +.m-t-61 {margin-top: 61px;} +.m-t-62 {margin-top: 62px;} +.m-t-63 {margin-top: 63px;} +.m-t-64 {margin-top: 64px;} +.m-t-65 {margin-top: 65px;} +.m-t-66 {margin-top: 66px;} +.m-t-67 {margin-top: 67px;} +.m-t-68 {margin-top: 68px;} +.m-t-69 {margin-top: 69px;} +.m-t-70 {margin-top: 70px;} +.m-t-71 {margin-top: 71px;} +.m-t-72 {margin-top: 72px;} +.m-t-73 {margin-top: 73px;} +.m-t-74 {margin-top: 74px;} +.m-t-75 {margin-top: 75px;} +.m-t-76 {margin-top: 76px;} +.m-t-77 {margin-top: 77px;} +.m-t-78 {margin-top: 78px;} +.m-t-79 {margin-top: 79px;} +.m-t-80 {margin-top: 80px;} +.m-t-81 {margin-top: 81px;} +.m-t-82 {margin-top: 82px;} +.m-t-83 {margin-top: 83px;} +.m-t-84 {margin-top: 84px;} +.m-t-85 {margin-top: 85px;} +.m-t-86 {margin-top: 86px;} +.m-t-87 {margin-top: 87px;} +.m-t-88 {margin-top: 88px;} +.m-t-89 {margin-top: 89px;} +.m-t-90 {margin-top: 90px;} +.m-t-91 {margin-top: 91px;} +.m-t-92 {margin-top: 92px;} +.m-t-93 {margin-top: 93px;} +.m-t-94 {margin-top: 94px;} +.m-t-95 {margin-top: 95px;} +.m-t-96 {margin-top: 96px;} +.m-t-97 {margin-top: 97px;} +.m-t-98 {margin-top: 98px;} +.m-t-99 {margin-top: 99px;} +.m-t-100 {margin-top: 100px;} +.m-t-101 {margin-top: 101px;} +.m-t-102 {margin-top: 102px;} +.m-t-103 {margin-top: 103px;} +.m-t-104 {margin-top: 104px;} +.m-t-105 {margin-top: 105px;} +.m-t-106 {margin-top: 106px;} +.m-t-107 {margin-top: 107px;} +.m-t-108 {margin-top: 108px;} +.m-t-109 {margin-top: 109px;} +.m-t-110 {margin-top: 110px;} +.m-t-111 {margin-top: 111px;} +.m-t-112 {margin-top: 112px;} +.m-t-113 {margin-top: 113px;} +.m-t-114 {margin-top: 114px;} +.m-t-115 {margin-top: 115px;} +.m-t-116 {margin-top: 116px;} +.m-t-117 {margin-top: 117px;} +.m-t-118 {margin-top: 118px;} +.m-t-119 {margin-top: 119px;} +.m-t-120 {margin-top: 120px;} +.m-t-121 {margin-top: 121px;} +.m-t-122 {margin-top: 122px;} +.m-t-123 {margin-top: 123px;} +.m-t-124 {margin-top: 124px;} +.m-t-125 {margin-top: 125px;} +.m-t-126 {margin-top: 126px;} +.m-t-127 {margin-top: 127px;} +.m-t-128 {margin-top: 128px;} +.m-t-129 {margin-top: 129px;} +.m-t-130 {margin-top: 130px;} +.m-t-131 {margin-top: 131px;} +.m-t-132 {margin-top: 132px;} +.m-t-133 {margin-top: 133px;} +.m-t-134 {margin-top: 134px;} +.m-t-135 {margin-top: 135px;} +.m-t-136 {margin-top: 136px;} +.m-t-137 {margin-top: 137px;} +.m-t-138 {margin-top: 138px;} +.m-t-139 {margin-top: 139px;} +.m-t-140 {margin-top: 140px;} +.m-t-141 {margin-top: 141px;} +.m-t-142 {margin-top: 142px;} +.m-t-143 {margin-top: 143px;} +.m-t-144 {margin-top: 144px;} +.m-t-145 {margin-top: 145px;} +.m-t-146 {margin-top: 146px;} +.m-t-147 {margin-top: 147px;} +.m-t-148 {margin-top: 148px;} +.m-t-149 {margin-top: 149px;} +.m-t-150 {margin-top: 150px;} +.m-t-151 {margin-top: 151px;} +.m-t-152 {margin-top: 152px;} +.m-t-153 {margin-top: 153px;} +.m-t-154 {margin-top: 154px;} +.m-t-155 {margin-top: 155px;} +.m-t-156 {margin-top: 156px;} +.m-t-157 {margin-top: 157px;} +.m-t-158 {margin-top: 158px;} +.m-t-159 {margin-top: 159px;} +.m-t-160 {margin-top: 160px;} +.m-t-161 {margin-top: 161px;} +.m-t-162 {margin-top: 162px;} +.m-t-163 {margin-top: 163px;} +.m-t-164 {margin-top: 164px;} +.m-t-165 {margin-top: 165px;} +.m-t-166 {margin-top: 166px;} +.m-t-167 {margin-top: 167px;} +.m-t-168 {margin-top: 168px;} +.m-t-169 {margin-top: 169px;} +.m-t-170 {margin-top: 170px;} +.m-t-171 {margin-top: 171px;} +.m-t-172 {margin-top: 172px;} +.m-t-173 {margin-top: 173px;} +.m-t-174 {margin-top: 174px;} +.m-t-175 {margin-top: 175px;} +.m-t-176 {margin-top: 176px;} +.m-t-177 {margin-top: 177px;} +.m-t-178 {margin-top: 178px;} +.m-t-179 {margin-top: 179px;} +.m-t-180 {margin-top: 180px;} +.m-t-181 {margin-top: 181px;} +.m-t-182 {margin-top: 182px;} +.m-t-183 {margin-top: 183px;} +.m-t-184 {margin-top: 184px;} +.m-t-185 {margin-top: 185px;} +.m-t-186 {margin-top: 186px;} +.m-t-187 {margin-top: 187px;} +.m-t-188 {margin-top: 188px;} +.m-t-189 {margin-top: 189px;} +.m-t-190 {margin-top: 190px;} +.m-t-191 {margin-top: 191px;} +.m-t-192 {margin-top: 192px;} +.m-t-193 {margin-top: 193px;} +.m-t-194 {margin-top: 194px;} +.m-t-195 {margin-top: 195px;} +.m-t-196 {margin-top: 196px;} +.m-t-197 {margin-top: 197px;} +.m-t-198 {margin-top: 198px;} +.m-t-199 {margin-top: 199px;} +.m-t-200 {margin-top: 200px;} +.m-t-201 {margin-top: 201px;} +.m-t-202 {margin-top: 202px;} +.m-t-203 {margin-top: 203px;} +.m-t-204 {margin-top: 204px;} +.m-t-205 {margin-top: 205px;} +.m-t-206 {margin-top: 206px;} +.m-t-207 {margin-top: 207px;} +.m-t-208 {margin-top: 208px;} +.m-t-209 {margin-top: 209px;} +.m-t-210 {margin-top: 210px;} +.m-t-211 {margin-top: 211px;} +.m-t-212 {margin-top: 212px;} +.m-t-213 {margin-top: 213px;} +.m-t-214 {margin-top: 214px;} +.m-t-215 {margin-top: 215px;} +.m-t-216 {margin-top: 216px;} +.m-t-217 {margin-top: 217px;} +.m-t-218 {margin-top: 218px;} +.m-t-219 {margin-top: 219px;} +.m-t-220 {margin-top: 220px;} +.m-t-221 {margin-top: 221px;} +.m-t-222 {margin-top: 222px;} +.m-t-223 {margin-top: 223px;} +.m-t-224 {margin-top: 224px;} +.m-t-225 {margin-top: 225px;} +.m-t-226 {margin-top: 226px;} +.m-t-227 {margin-top: 227px;} +.m-t-228 {margin-top: 228px;} +.m-t-229 {margin-top: 229px;} +.m-t-230 {margin-top: 230px;} +.m-t-231 {margin-top: 231px;} +.m-t-232 {margin-top: 232px;} +.m-t-233 {margin-top: 233px;} +.m-t-234 {margin-top: 234px;} +.m-t-235 {margin-top: 235px;} +.m-t-236 {margin-top: 236px;} +.m-t-237 {margin-top: 237px;} +.m-t-238 {margin-top: 238px;} +.m-t-239 {margin-top: 239px;} +.m-t-240 {margin-top: 240px;} +.m-t-241 {margin-top: 241px;} +.m-t-242 {margin-top: 242px;} +.m-t-243 {margin-top: 243px;} +.m-t-244 {margin-top: 244px;} +.m-t-245 {margin-top: 245px;} +.m-t-246 {margin-top: 246px;} +.m-t-247 {margin-top: 247px;} +.m-t-248 {margin-top: 248px;} +.m-t-249 {margin-top: 249px;} +.m-t-250 {margin-top: 250px;} +.m-b-0 {margin-bottom: 0px;} +.m-b-1 {margin-bottom: 1px;} +.m-b-2 {margin-bottom: 2px;} +.m-b-3 {margin-bottom: 3px;} +.m-b-4 {margin-bottom: 4px;} +.m-b-5 {margin-bottom: 5px;} +.m-b-6 {margin-bottom: 6px;} +.m-b-7 {margin-bottom: 7px;} +.m-b-8 {margin-bottom: 8px;} +.m-b-9 {margin-bottom: 9px;} +.m-b-10 {margin-bottom: 10px;} +.m-b-11 {margin-bottom: 11px;} +.m-b-12 {margin-bottom: 12px;} +.m-b-13 {margin-bottom: 13px;} +.m-b-14 {margin-bottom: 14px;} +.m-b-15 {margin-bottom: 15px;} +.m-b-16 {margin-bottom: 16px;} +.m-b-17 {margin-bottom: 17px;} +.m-b-18 {margin-bottom: 18px;} +.m-b-19 {margin-bottom: 19px;} +.m-b-20 {margin-bottom: 20px;} +.m-b-21 {margin-bottom: 21px;} +.m-b-22 {margin-bottom: 22px;} +.m-b-23 {margin-bottom: 23px;} +.m-b-24 {margin-bottom: 24px;} +.m-b-25 {margin-bottom: 25px;} +.m-b-26 {margin-bottom: 26px;} +.m-b-27 {margin-bottom: 27px;} +.m-b-28 {margin-bottom: 28px;} +.m-b-29 {margin-bottom: 29px;} +.m-b-30 {margin-bottom: 30px;} +.m-b-31 {margin-bottom: 31px;} +.m-b-32 {margin-bottom: 32px;} +.m-b-33 {margin-bottom: 33px;} +.m-b-34 {margin-bottom: 34px;} +.m-b-35 {margin-bottom: 35px;} +.m-b-36 {margin-bottom: 36px;} +.m-b-37 {margin-bottom: 37px;} +.m-b-38 {margin-bottom: 38px;} +.m-b-39 {margin-bottom: 39px;} +.m-b-40 {margin-bottom: 40px;} +.m-b-41 {margin-bottom: 41px;} +.m-b-42 {margin-bottom: 42px;} +.m-b-43 {margin-bottom: 43px;} +.m-b-44 {margin-bottom: 44px;} +.m-b-45 {margin-bottom: 45px;} +.m-b-46 {margin-bottom: 46px;} +.m-b-47 {margin-bottom: 47px;} +.m-b-48 {margin-bottom: 48px;} +.m-b-49 {margin-bottom: 49px;} +.m-b-50 {margin-bottom: 50px;} +.m-b-51 {margin-bottom: 51px;} +.m-b-52 {margin-bottom: 52px;} +.m-b-53 {margin-bottom: 53px;} +.m-b-54 {margin-bottom: 54px;} +.m-b-55 {margin-bottom: 55px;} +.m-b-56 {margin-bottom: 56px;} +.m-b-57 {margin-bottom: 57px;} +.m-b-58 {margin-bottom: 58px;} +.m-b-59 {margin-bottom: 59px;} +.m-b-60 {margin-bottom: 60px;} +.m-b-61 {margin-bottom: 61px;} +.m-b-62 {margin-bottom: 62px;} +.m-b-63 {margin-bottom: 63px;} +.m-b-64 {margin-bottom: 64px;} +.m-b-65 {margin-bottom: 65px;} +.m-b-66 {margin-bottom: 66px;} +.m-b-67 {margin-bottom: 67px;} +.m-b-68 {margin-bottom: 68px;} +.m-b-69 {margin-bottom: 69px;} +.m-b-70 {margin-bottom: 70px;} +.m-b-71 {margin-bottom: 71px;} +.m-b-72 {margin-bottom: 72px;} +.m-b-73 {margin-bottom: 73px;} +.m-b-74 {margin-bottom: 74px;} +.m-b-75 {margin-bottom: 75px;} +.m-b-76 {margin-bottom: 76px;} +.m-b-77 {margin-bottom: 77px;} +.m-b-78 {margin-bottom: 78px;} +.m-b-79 {margin-bottom: 79px;} +.m-b-80 {margin-bottom: 80px;} +.m-b-81 {margin-bottom: 81px;} +.m-b-82 {margin-bottom: 82px;} +.m-b-83 {margin-bottom: 83px;} +.m-b-84 {margin-bottom: 84px;} +.m-b-85 {margin-bottom: 85px;} +.m-b-86 {margin-bottom: 86px;} +.m-b-87 {margin-bottom: 87px;} +.m-b-88 {margin-bottom: 88px;} +.m-b-89 {margin-bottom: 89px;} +.m-b-90 {margin-bottom: 90px;} +.m-b-91 {margin-bottom: 91px;} +.m-b-92 {margin-bottom: 92px;} +.m-b-93 {margin-bottom: 93px;} +.m-b-94 {margin-bottom: 94px;} +.m-b-95 {margin-bottom: 95px;} +.m-b-96 {margin-bottom: 96px;} +.m-b-97 {margin-bottom: 97px;} +.m-b-98 {margin-bottom: 98px;} +.m-b-99 {margin-bottom: 99px;} +.m-b-100 {margin-bottom: 100px;} +.m-b-101 {margin-bottom: 101px;} +.m-b-102 {margin-bottom: 102px;} +.m-b-103 {margin-bottom: 103px;} +.m-b-104 {margin-bottom: 104px;} +.m-b-105 {margin-bottom: 105px;} +.m-b-106 {margin-bottom: 106px;} +.m-b-107 {margin-bottom: 107px;} +.m-b-108 {margin-bottom: 108px;} +.m-b-109 {margin-bottom: 109px;} +.m-b-110 {margin-bottom: 110px;} +.m-b-111 {margin-bottom: 111px;} +.m-b-112 {margin-bottom: 112px;} +.m-b-113 {margin-bottom: 113px;} +.m-b-114 {margin-bottom: 114px;} +.m-b-115 {margin-bottom: 115px;} +.m-b-116 {margin-bottom: 116px;} +.m-b-117 {margin-bottom: 117px;} +.m-b-118 {margin-bottom: 118px;} +.m-b-119 {margin-bottom: 119px;} +.m-b-120 {margin-bottom: 120px;} +.m-b-121 {margin-bottom: 121px;} +.m-b-122 {margin-bottom: 122px;} +.m-b-123 {margin-bottom: 123px;} +.m-b-124 {margin-bottom: 124px;} +.m-b-125 {margin-bottom: 125px;} +.m-b-126 {margin-bottom: 126px;} +.m-b-127 {margin-bottom: 127px;} +.m-b-128 {margin-bottom: 128px;} +.m-b-129 {margin-bottom: 129px;} +.m-b-130 {margin-bottom: 130px;} +.m-b-131 {margin-bottom: 131px;} +.m-b-132 {margin-bottom: 132px;} +.m-b-133 {margin-bottom: 133px;} +.m-b-134 {margin-bottom: 134px;} +.m-b-135 {margin-bottom: 135px;} +.m-b-136 {margin-bottom: 136px;} +.m-b-137 {margin-bottom: 137px;} +.m-b-138 {margin-bottom: 138px;} +.m-b-139 {margin-bottom: 139px;} +.m-b-140 {margin-bottom: 140px;} +.m-b-141 {margin-bottom: 141px;} +.m-b-142 {margin-bottom: 142px;} +.m-b-143 {margin-bottom: 143px;} +.m-b-144 {margin-bottom: 144px;} +.m-b-145 {margin-bottom: 145px;} +.m-b-146 {margin-bottom: 146px;} +.m-b-147 {margin-bottom: 147px;} +.m-b-148 {margin-bottom: 148px;} +.m-b-149 {margin-bottom: 149px;} +.m-b-150 {margin-bottom: 150px;} +.m-b-151 {margin-bottom: 151px;} +.m-b-152 {margin-bottom: 152px;} +.m-b-153 {margin-bottom: 153px;} +.m-b-154 {margin-bottom: 154px;} +.m-b-155 {margin-bottom: 155px;} +.m-b-156 {margin-bottom: 156px;} +.m-b-157 {margin-bottom: 157px;} +.m-b-158 {margin-bottom: 158px;} +.m-b-159 {margin-bottom: 159px;} +.m-b-160 {margin-bottom: 160px;} +.m-b-161 {margin-bottom: 161px;} +.m-b-162 {margin-bottom: 162px;} +.m-b-163 {margin-bottom: 163px;} +.m-b-164 {margin-bottom: 164px;} +.m-b-165 {margin-bottom: 165px;} +.m-b-166 {margin-bottom: 166px;} +.m-b-167 {margin-bottom: 167px;} +.m-b-168 {margin-bottom: 168px;} +.m-b-169 {margin-bottom: 169px;} +.m-b-170 {margin-bottom: 170px;} +.m-b-171 {margin-bottom: 171px;} +.m-b-172 {margin-bottom: 172px;} +.m-b-173 {margin-bottom: 173px;} +.m-b-174 {margin-bottom: 174px;} +.m-b-175 {margin-bottom: 175px;} +.m-b-176 {margin-bottom: 176px;} +.m-b-177 {margin-bottom: 177px;} +.m-b-178 {margin-bottom: 178px;} +.m-b-179 {margin-bottom: 179px;} +.m-b-180 {margin-bottom: 180px;} +.m-b-181 {margin-bottom: 181px;} +.m-b-182 {margin-bottom: 182px;} +.m-b-183 {margin-bottom: 183px;} +.m-b-184 {margin-bottom: 184px;} +.m-b-185 {margin-bottom: 185px;} +.m-b-186 {margin-bottom: 186px;} +.m-b-187 {margin-bottom: 187px;} +.m-b-188 {margin-bottom: 188px;} +.m-b-189 {margin-bottom: 189px;} +.m-b-190 {margin-bottom: 190px;} +.m-b-191 {margin-bottom: 191px;} +.m-b-192 {margin-bottom: 192px;} +.m-b-193 {margin-bottom: 193px;} +.m-b-194 {margin-bottom: 194px;} +.m-b-195 {margin-bottom: 195px;} +.m-b-196 {margin-bottom: 196px;} +.m-b-197 {margin-bottom: 197px;} +.m-b-198 {margin-bottom: 198px;} +.m-b-199 {margin-bottom: 199px;} +.m-b-200 {margin-bottom: 200px;} +.m-b-201 {margin-bottom: 201px;} +.m-b-202 {margin-bottom: 202px;} +.m-b-203 {margin-bottom: 203px;} +.m-b-204 {margin-bottom: 204px;} +.m-b-205 {margin-bottom: 205px;} +.m-b-206 {margin-bottom: 206px;} +.m-b-207 {margin-bottom: 207px;} +.m-b-208 {margin-bottom: 208px;} +.m-b-209 {margin-bottom: 209px;} +.m-b-210 {margin-bottom: 210px;} +.m-b-211 {margin-bottom: 211px;} +.m-b-212 {margin-bottom: 212px;} +.m-b-213 {margin-bottom: 213px;} +.m-b-214 {margin-bottom: 214px;} +.m-b-215 {margin-bottom: 215px;} +.m-b-216 {margin-bottom: 216px;} +.m-b-217 {margin-bottom: 217px;} +.m-b-218 {margin-bottom: 218px;} +.m-b-219 {margin-bottom: 219px;} +.m-b-220 {margin-bottom: 220px;} +.m-b-221 {margin-bottom: 221px;} +.m-b-222 {margin-bottom: 222px;} +.m-b-223 {margin-bottom: 223px;} +.m-b-224 {margin-bottom: 224px;} +.m-b-225 {margin-bottom: 225px;} +.m-b-226 {margin-bottom: 226px;} +.m-b-227 {margin-bottom: 227px;} +.m-b-228 {margin-bottom: 228px;} +.m-b-229 {margin-bottom: 229px;} +.m-b-230 {margin-bottom: 230px;} +.m-b-231 {margin-bottom: 231px;} +.m-b-232 {margin-bottom: 232px;} +.m-b-233 {margin-bottom: 233px;} +.m-b-234 {margin-bottom: 234px;} +.m-b-235 {margin-bottom: 235px;} +.m-b-236 {margin-bottom: 236px;} +.m-b-237 {margin-bottom: 237px;} +.m-b-238 {margin-bottom: 238px;} +.m-b-239 {margin-bottom: 239px;} +.m-b-240 {margin-bottom: 240px;} +.m-b-241 {margin-bottom: 241px;} +.m-b-242 {margin-bottom: 242px;} +.m-b-243 {margin-bottom: 243px;} +.m-b-244 {margin-bottom: 244px;} +.m-b-245 {margin-bottom: 245px;} +.m-b-246 {margin-bottom: 246px;} +.m-b-247 {margin-bottom: 247px;} +.m-b-248 {margin-bottom: 248px;} +.m-b-249 {margin-bottom: 249px;} +.m-b-250 {margin-bottom: 250px;} +.m-l-0 {margin-left: 0px;} +.m-l-1 {margin-left: 1px;} +.m-l-2 {margin-left: 2px;} +.m-l-3 {margin-left: 3px;} +.m-l-4 {margin-left: 4px;} +.m-l-5 {margin-left: 5px;} +.m-l-6 {margin-left: 6px;} +.m-l-7 {margin-left: 7px;} +.m-l-8 {margin-left: 8px;} +.m-l-9 {margin-left: 9px;} +.m-l-10 {margin-left: 10px;} +.m-l-11 {margin-left: 11px;} +.m-l-12 {margin-left: 12px;} +.m-l-13 {margin-left: 13px;} +.m-l-14 {margin-left: 14px;} +.m-l-15 {margin-left: 15px;} +.m-l-16 {margin-left: 16px;} +.m-l-17 {margin-left: 17px;} +.m-l-18 {margin-left: 18px;} +.m-l-19 {margin-left: 19px;} +.m-l-20 {margin-left: 20px;} +.m-l-21 {margin-left: 21px;} +.m-l-22 {margin-left: 22px;} +.m-l-23 {margin-left: 23px;} +.m-l-24 {margin-left: 24px;} +.m-l-25 {margin-left: 25px;} +.m-l-26 {margin-left: 26px;} +.m-l-27 {margin-left: 27px;} +.m-l-28 {margin-left: 28px;} +.m-l-29 {margin-left: 29px;} +.m-l-30 {margin-left: 30px;} +.m-l-31 {margin-left: 31px;} +.m-l-32 {margin-left: 32px;} +.m-l-33 {margin-left: 33px;} +.m-l-34 {margin-left: 34px;} +.m-l-35 {margin-left: 35px;} +.m-l-36 {margin-left: 36px;} +.m-l-37 {margin-left: 37px;} +.m-l-38 {margin-left: 38px;} +.m-l-39 {margin-left: 39px;} +.m-l-40 {margin-left: 40px;} +.m-l-41 {margin-left: 41px;} +.m-l-42 {margin-left: 42px;} +.m-l-43 {margin-left: 43px;} +.m-l-44 {margin-left: 44px;} +.m-l-45 {margin-left: 45px;} +.m-l-46 {margin-left: 46px;} +.m-l-47 {margin-left: 47px;} +.m-l-48 {margin-left: 48px;} +.m-l-49 {margin-left: 49px;} +.m-l-50 {margin-left: 50px;} +.m-l-51 {margin-left: 51px;} +.m-l-52 {margin-left: 52px;} +.m-l-53 {margin-left: 53px;} +.m-l-54 {margin-left: 54px;} +.m-l-55 {margin-left: 55px;} +.m-l-56 {margin-left: 56px;} +.m-l-57 {margin-left: 57px;} +.m-l-58 {margin-left: 58px;} +.m-l-59 {margin-left: 59px;} +.m-l-60 {margin-left: 60px;} +.m-l-61 {margin-left: 61px;} +.m-l-62 {margin-left: 62px;} +.m-l-63 {margin-left: 63px;} +.m-l-64 {margin-left: 64px;} +.m-l-65 {margin-left: 65px;} +.m-l-66 {margin-left: 66px;} +.m-l-67 {margin-left: 67px;} +.m-l-68 {margin-left: 68px;} +.m-l-69 {margin-left: 69px;} +.m-l-70 {margin-left: 70px;} +.m-l-71 {margin-left: 71px;} +.m-l-72 {margin-left: 72px;} +.m-l-73 {margin-left: 73px;} +.m-l-74 {margin-left: 74px;} +.m-l-75 {margin-left: 75px;} +.m-l-76 {margin-left: 76px;} +.m-l-77 {margin-left: 77px;} +.m-l-78 {margin-left: 78px;} +.m-l-79 {margin-left: 79px;} +.m-l-80 {margin-left: 80px;} +.m-l-81 {margin-left: 81px;} +.m-l-82 {margin-left: 82px;} +.m-l-83 {margin-left: 83px;} +.m-l-84 {margin-left: 84px;} +.m-l-85 {margin-left: 85px;} +.m-l-86 {margin-left: 86px;} +.m-l-87 {margin-left: 87px;} +.m-l-88 {margin-left: 88px;} +.m-l-89 {margin-left: 89px;} +.m-l-90 {margin-left: 90px;} +.m-l-91 {margin-left: 91px;} +.m-l-92 {margin-left: 92px;} +.m-l-93 {margin-left: 93px;} +.m-l-94 {margin-left: 94px;} +.m-l-95 {margin-left: 95px;} +.m-l-96 {margin-left: 96px;} +.m-l-97 {margin-left: 97px;} +.m-l-98 {margin-left: 98px;} +.m-l-99 {margin-left: 99px;} +.m-l-100 {margin-left: 100px;} +.m-l-101 {margin-left: 101px;} +.m-l-102 {margin-left: 102px;} +.m-l-103 {margin-left: 103px;} +.m-l-104 {margin-left: 104px;} +.m-l-105 {margin-left: 105px;} +.m-l-106 {margin-left: 106px;} +.m-l-107 {margin-left: 107px;} +.m-l-108 {margin-left: 108px;} +.m-l-109 {margin-left: 109px;} +.m-l-110 {margin-left: 110px;} +.m-l-111 {margin-left: 111px;} +.m-l-112 {margin-left: 112px;} +.m-l-113 {margin-left: 113px;} +.m-l-114 {margin-left: 114px;} +.m-l-115 {margin-left: 115px;} +.m-l-116 {margin-left: 116px;} +.m-l-117 {margin-left: 117px;} +.m-l-118 {margin-left: 118px;} +.m-l-119 {margin-left: 119px;} +.m-l-120 {margin-left: 120px;} +.m-l-121 {margin-left: 121px;} +.m-l-122 {margin-left: 122px;} +.m-l-123 {margin-left: 123px;} +.m-l-124 {margin-left: 124px;} +.m-l-125 {margin-left: 125px;} +.m-l-126 {margin-left: 126px;} +.m-l-127 {margin-left: 127px;} +.m-l-128 {margin-left: 128px;} +.m-l-129 {margin-left: 129px;} +.m-l-130 {margin-left: 130px;} +.m-l-131 {margin-left: 131px;} +.m-l-132 {margin-left: 132px;} +.m-l-133 {margin-left: 133px;} +.m-l-134 {margin-left: 134px;} +.m-l-135 {margin-left: 135px;} +.m-l-136 {margin-left: 136px;} +.m-l-137 {margin-left: 137px;} +.m-l-138 {margin-left: 138px;} +.m-l-139 {margin-left: 139px;} +.m-l-140 {margin-left: 140px;} +.m-l-141 {margin-left: 141px;} +.m-l-142 {margin-left: 142px;} +.m-l-143 {margin-left: 143px;} +.m-l-144 {margin-left: 144px;} +.m-l-145 {margin-left: 145px;} +.m-l-146 {margin-left: 146px;} +.m-l-147 {margin-left: 147px;} +.m-l-148 {margin-left: 148px;} +.m-l-149 {margin-left: 149px;} +.m-l-150 {margin-left: 150px;} +.m-l-151 {margin-left: 151px;} +.m-l-152 {margin-left: 152px;} +.m-l-153 {margin-left: 153px;} +.m-l-154 {margin-left: 154px;} +.m-l-155 {margin-left: 155px;} +.m-l-156 {margin-left: 156px;} +.m-l-157 {margin-left: 157px;} +.m-l-158 {margin-left: 158px;} +.m-l-159 {margin-left: 159px;} +.m-l-160 {margin-left: 160px;} +.m-l-161 {margin-left: 161px;} +.m-l-162 {margin-left: 162px;} +.m-l-163 {margin-left: 163px;} +.m-l-164 {margin-left: 164px;} +.m-l-165 {margin-left: 165px;} +.m-l-166 {margin-left: 166px;} +.m-l-167 {margin-left: 167px;} +.m-l-168 {margin-left: 168px;} +.m-l-169 {margin-left: 169px;} +.m-l-170 {margin-left: 170px;} +.m-l-171 {margin-left: 171px;} +.m-l-172 {margin-left: 172px;} +.m-l-173 {margin-left: 173px;} +.m-l-174 {margin-left: 174px;} +.m-l-175 {margin-left: 175px;} +.m-l-176 {margin-left: 176px;} +.m-l-177 {margin-left: 177px;} +.m-l-178 {margin-left: 178px;} +.m-l-179 {margin-left: 179px;} +.m-l-180 {margin-left: 180px;} +.m-l-181 {margin-left: 181px;} +.m-l-182 {margin-left: 182px;} +.m-l-183 {margin-left: 183px;} +.m-l-184 {margin-left: 184px;} +.m-l-185 {margin-left: 185px;} +.m-l-186 {margin-left: 186px;} +.m-l-187 {margin-left: 187px;} +.m-l-188 {margin-left: 188px;} +.m-l-189 {margin-left: 189px;} +.m-l-190 {margin-left: 190px;} +.m-l-191 {margin-left: 191px;} +.m-l-192 {margin-left: 192px;} +.m-l-193 {margin-left: 193px;} +.m-l-194 {margin-left: 194px;} +.m-l-195 {margin-left: 195px;} +.m-l-196 {margin-left: 196px;} +.m-l-197 {margin-left: 197px;} +.m-l-198 {margin-left: 198px;} +.m-l-199 {margin-left: 199px;} +.m-l-200 {margin-left: 200px;} +.m-l-201 {margin-left: 201px;} +.m-l-202 {margin-left: 202px;} +.m-l-203 {margin-left: 203px;} +.m-l-204 {margin-left: 204px;} +.m-l-205 {margin-left: 205px;} +.m-l-206 {margin-left: 206px;} +.m-l-207 {margin-left: 207px;} +.m-l-208 {margin-left: 208px;} +.m-l-209 {margin-left: 209px;} +.m-l-210 {margin-left: 210px;} +.m-l-211 {margin-left: 211px;} +.m-l-212 {margin-left: 212px;} +.m-l-213 {margin-left: 213px;} +.m-l-214 {margin-left: 214px;} +.m-l-215 {margin-left: 215px;} +.m-l-216 {margin-left: 216px;} +.m-l-217 {margin-left: 217px;} +.m-l-218 {margin-left: 218px;} +.m-l-219 {margin-left: 219px;} +.m-l-220 {margin-left: 220px;} +.m-l-221 {margin-left: 221px;} +.m-l-222 {margin-left: 222px;} +.m-l-223 {margin-left: 223px;} +.m-l-224 {margin-left: 224px;} +.m-l-225 {margin-left: 225px;} +.m-l-226 {margin-left: 226px;} +.m-l-227 {margin-left: 227px;} +.m-l-228 {margin-left: 228px;} +.m-l-229 {margin-left: 229px;} +.m-l-230 {margin-left: 230px;} +.m-l-231 {margin-left: 231px;} +.m-l-232 {margin-left: 232px;} +.m-l-233 {margin-left: 233px;} +.m-l-234 {margin-left: 234px;} +.m-l-235 {margin-left: 235px;} +.m-l-236 {margin-left: 236px;} +.m-l-237 {margin-left: 237px;} +.m-l-238 {margin-left: 238px;} +.m-l-239 {margin-left: 239px;} +.m-l-240 {margin-left: 240px;} +.m-l-241 {margin-left: 241px;} +.m-l-242 {margin-left: 242px;} +.m-l-243 {margin-left: 243px;} +.m-l-244 {margin-left: 244px;} +.m-l-245 {margin-left: 245px;} +.m-l-246 {margin-left: 246px;} +.m-l-247 {margin-left: 247px;} +.m-l-248 {margin-left: 248px;} +.m-l-249 {margin-left: 249px;} +.m-l-250 {margin-left: 250px;} +.m-r-0 {margin-right: 0px;} +.m-r-1 {margin-right: 1px;} +.m-r-2 {margin-right: 2px;} +.m-r-3 {margin-right: 3px;} +.m-r-4 {margin-right: 4px;} +.m-r-5 {margin-right: 5px;} +.m-r-6 {margin-right: 6px;} +.m-r-7 {margin-right: 7px;} +.m-r-8 {margin-right: 8px;} +.m-r-9 {margin-right: 9px;} +.m-r-10 {margin-right: 10px;} +.m-r-11 {margin-right: 11px;} +.m-r-12 {margin-right: 12px;} +.m-r-13 {margin-right: 13px;} +.m-r-14 {margin-right: 14px;} +.m-r-15 {margin-right: 15px;} +.m-r-16 {margin-right: 16px;} +.m-r-17 {margin-right: 17px;} +.m-r-18 {margin-right: 18px;} +.m-r-19 {margin-right: 19px;} +.m-r-20 {margin-right: 20px;} +.m-r-21 {margin-right: 21px;} +.m-r-22 {margin-right: 22px;} +.m-r-23 {margin-right: 23px;} +.m-r-24 {margin-right: 24px;} +.m-r-25 {margin-right: 25px;} +.m-r-26 {margin-right: 26px;} +.m-r-27 {margin-right: 27px;} +.m-r-28 {margin-right: 28px;} +.m-r-29 {margin-right: 29px;} +.m-r-30 {margin-right: 30px;} +.m-r-31 {margin-right: 31px;} +.m-r-32 {margin-right: 32px;} +.m-r-33 {margin-right: 33px;} +.m-r-34 {margin-right: 34px;} +.m-r-35 {margin-right: 35px;} +.m-r-36 {margin-right: 36px;} +.m-r-37 {margin-right: 37px;} +.m-r-38 {margin-right: 38px;} +.m-r-39 {margin-right: 39px;} +.m-r-40 {margin-right: 40px;} +.m-r-41 {margin-right: 41px;} +.m-r-42 {margin-right: 42px;} +.m-r-43 {margin-right: 43px;} +.m-r-44 {margin-right: 44px;} +.m-r-45 {margin-right: 45px;} +.m-r-46 {margin-right: 46px;} +.m-r-47 {margin-right: 47px;} +.m-r-48 {margin-right: 48px;} +.m-r-49 {margin-right: 49px;} +.m-r-50 {margin-right: 50px;} +.m-r-51 {margin-right: 51px;} +.m-r-52 {margin-right: 52px;} +.m-r-53 {margin-right: 53px;} +.m-r-54 {margin-right: 54px;} +.m-r-55 {margin-right: 55px;} +.m-r-56 {margin-right: 56px;} +.m-r-57 {margin-right: 57px;} +.m-r-58 {margin-right: 58px;} +.m-r-59 {margin-right: 59px;} +.m-r-60 {margin-right: 60px;} +.m-r-61 {margin-right: 61px;} +.m-r-62 {margin-right: 62px;} +.m-r-63 {margin-right: 63px;} +.m-r-64 {margin-right: 64px;} +.m-r-65 {margin-right: 65px;} +.m-r-66 {margin-right: 66px;} +.m-r-67 {margin-right: 67px;} +.m-r-68 {margin-right: 68px;} +.m-r-69 {margin-right: 69px;} +.m-r-70 {margin-right: 70px;} +.m-r-71 {margin-right: 71px;} +.m-r-72 {margin-right: 72px;} +.m-r-73 {margin-right: 73px;} +.m-r-74 {margin-right: 74px;} +.m-r-75 {margin-right: 75px;} +.m-r-76 {margin-right: 76px;} +.m-r-77 {margin-right: 77px;} +.m-r-78 {margin-right: 78px;} +.m-r-79 {margin-right: 79px;} +.m-r-80 {margin-right: 80px;} +.m-r-81 {margin-right: 81px;} +.m-r-82 {margin-right: 82px;} +.m-r-83 {margin-right: 83px;} +.m-r-84 {margin-right: 84px;} +.m-r-85 {margin-right: 85px;} +.m-r-86 {margin-right: 86px;} +.m-r-87 {margin-right: 87px;} +.m-r-88 {margin-right: 88px;} +.m-r-89 {margin-right: 89px;} +.m-r-90 {margin-right: 90px;} +.m-r-91 {margin-right: 91px;} +.m-r-92 {margin-right: 92px;} +.m-r-93 {margin-right: 93px;} +.m-r-94 {margin-right: 94px;} +.m-r-95 {margin-right: 95px;} +.m-r-96 {margin-right: 96px;} +.m-r-97 {margin-right: 97px;} +.m-r-98 {margin-right: 98px;} +.m-r-99 {margin-right: 99px;} +.m-r-100 {margin-right: 100px;} +.m-r-101 {margin-right: 101px;} +.m-r-102 {margin-right: 102px;} +.m-r-103 {margin-right: 103px;} +.m-r-104 {margin-right: 104px;} +.m-r-105 {margin-right: 105px;} +.m-r-106 {margin-right: 106px;} +.m-r-107 {margin-right: 107px;} +.m-r-108 {margin-right: 108px;} +.m-r-109 {margin-right: 109px;} +.m-r-110 {margin-right: 110px;} +.m-r-111 {margin-right: 111px;} +.m-r-112 {margin-right: 112px;} +.m-r-113 {margin-right: 113px;} +.m-r-114 {margin-right: 114px;} +.m-r-115 {margin-right: 115px;} +.m-r-116 {margin-right: 116px;} +.m-r-117 {margin-right: 117px;} +.m-r-118 {margin-right: 118px;} +.m-r-119 {margin-right: 119px;} +.m-r-120 {margin-right: 120px;} +.m-r-121 {margin-right: 121px;} +.m-r-122 {margin-right: 122px;} +.m-r-123 {margin-right: 123px;} +.m-r-124 {margin-right: 124px;} +.m-r-125 {margin-right: 125px;} +.m-r-126 {margin-right: 126px;} +.m-r-127 {margin-right: 127px;} +.m-r-128 {margin-right: 128px;} +.m-r-129 {margin-right: 129px;} +.m-r-130 {margin-right: 130px;} +.m-r-131 {margin-right: 131px;} +.m-r-132 {margin-right: 132px;} +.m-r-133 {margin-right: 133px;} +.m-r-134 {margin-right: 134px;} +.m-r-135 {margin-right: 135px;} +.m-r-136 {margin-right: 136px;} +.m-r-137 {margin-right: 137px;} +.m-r-138 {margin-right: 138px;} +.m-r-139 {margin-right: 139px;} +.m-r-140 {margin-right: 140px;} +.m-r-141 {margin-right: 141px;} +.m-r-142 {margin-right: 142px;} +.m-r-143 {margin-right: 143px;} +.m-r-144 {margin-right: 144px;} +.m-r-145 {margin-right: 145px;} +.m-r-146 {margin-right: 146px;} +.m-r-147 {margin-right: 147px;} +.m-r-148 {margin-right: 148px;} +.m-r-149 {margin-right: 149px;} +.m-r-150 {margin-right: 150px;} +.m-r-151 {margin-right: 151px;} +.m-r-152 {margin-right: 152px;} +.m-r-153 {margin-right: 153px;} +.m-r-154 {margin-right: 154px;} +.m-r-155 {margin-right: 155px;} +.m-r-156 {margin-right: 156px;} +.m-r-157 {margin-right: 157px;} +.m-r-158 {margin-right: 158px;} +.m-r-159 {margin-right: 159px;} +.m-r-160 {margin-right: 160px;} +.m-r-161 {margin-right: 161px;} +.m-r-162 {margin-right: 162px;} +.m-r-163 {margin-right: 163px;} +.m-r-164 {margin-right: 164px;} +.m-r-165 {margin-right: 165px;} +.m-r-166 {margin-right: 166px;} +.m-r-167 {margin-right: 167px;} +.m-r-168 {margin-right: 168px;} +.m-r-169 {margin-right: 169px;} +.m-r-170 {margin-right: 170px;} +.m-r-171 {margin-right: 171px;} +.m-r-172 {margin-right: 172px;} +.m-r-173 {margin-right: 173px;} +.m-r-174 {margin-right: 174px;} +.m-r-175 {margin-right: 175px;} +.m-r-176 {margin-right: 176px;} +.m-r-177 {margin-right: 177px;} +.m-r-178 {margin-right: 178px;} +.m-r-179 {margin-right: 179px;} +.m-r-180 {margin-right: 180px;} +.m-r-181 {margin-right: 181px;} +.m-r-182 {margin-right: 182px;} +.m-r-183 {margin-right: 183px;} +.m-r-184 {margin-right: 184px;} +.m-r-185 {margin-right: 185px;} +.m-r-186 {margin-right: 186px;} +.m-r-187 {margin-right: 187px;} +.m-r-188 {margin-right: 188px;} +.m-r-189 {margin-right: 189px;} +.m-r-190 {margin-right: 190px;} +.m-r-191 {margin-right: 191px;} +.m-r-192 {margin-right: 192px;} +.m-r-193 {margin-right: 193px;} +.m-r-194 {margin-right: 194px;} +.m-r-195 {margin-right: 195px;} +.m-r-196 {margin-right: 196px;} +.m-r-197 {margin-right: 197px;} +.m-r-198 {margin-right: 198px;} +.m-r-199 {margin-right: 199px;} +.m-r-200 {margin-right: 200px;} +.m-r-201 {margin-right: 201px;} +.m-r-202 {margin-right: 202px;} +.m-r-203 {margin-right: 203px;} +.m-r-204 {margin-right: 204px;} +.m-r-205 {margin-right: 205px;} +.m-r-206 {margin-right: 206px;} +.m-r-207 {margin-right: 207px;} +.m-r-208 {margin-right: 208px;} +.m-r-209 {margin-right: 209px;} +.m-r-210 {margin-right: 210px;} +.m-r-211 {margin-right: 211px;} +.m-r-212 {margin-right: 212px;} +.m-r-213 {margin-right: 213px;} +.m-r-214 {margin-right: 214px;} +.m-r-215 {margin-right: 215px;} +.m-r-216 {margin-right: 216px;} +.m-r-217 {margin-right: 217px;} +.m-r-218 {margin-right: 218px;} +.m-r-219 {margin-right: 219px;} +.m-r-220 {margin-right: 220px;} +.m-r-221 {margin-right: 221px;} +.m-r-222 {margin-right: 222px;} +.m-r-223 {margin-right: 223px;} +.m-r-224 {margin-right: 224px;} +.m-r-225 {margin-right: 225px;} +.m-r-226 {margin-right: 226px;} +.m-r-227 {margin-right: 227px;} +.m-r-228 {margin-right: 228px;} +.m-r-229 {margin-right: 229px;} +.m-r-230 {margin-right: 230px;} +.m-r-231 {margin-right: 231px;} +.m-r-232 {margin-right: 232px;} +.m-r-233 {margin-right: 233px;} +.m-r-234 {margin-right: 234px;} +.m-r-235 {margin-right: 235px;} +.m-r-236 {margin-right: 236px;} +.m-r-237 {margin-right: 237px;} +.m-r-238 {margin-right: 238px;} +.m-r-239 {margin-right: 239px;} +.m-r-240 {margin-right: 240px;} +.m-r-241 {margin-right: 241px;} +.m-r-242 {margin-right: 242px;} +.m-r-243 {margin-right: 243px;} +.m-r-244 {margin-right: 244px;} +.m-r-245 {margin-right: 245px;} +.m-r-246 {margin-right: 246px;} +.m-r-247 {margin-right: 247px;} +.m-r-248 {margin-right: 248px;} +.m-r-249 {margin-right: 249px;} +.m-r-250 {margin-right: 250px;} +.m-l-auto {margin-left: auto;} +.m-r-auto {margin-right: auto;} +.m-lr-auto { + margin-left: auto; + margin-right: auto; +} + + + +/*////////////////////////////////////////////////////////////////// +[ TEXT ]*/ +.color-white {color: white;} +.color-black {color: black;} +.color-yellow {color: #ffc000;} +.color-orange {color: #fc7f0c;} +.color-red {color: #e84b3a;} +.color-grey {color: #474747;} +.color-limestone {color: #ACA39A;} +.color-dipy {color: #fc7f0c;} +.color-momentz {color: #005F95;} + + +/*------------------------------------------------------------------ +[ Line height ]*/ +.lh-1-0 {line-height: 1.0;} +.lh-1-1 {line-height: 1.1;} +.lh-1-2 {line-height: 1.2;} +.lh-1-3 {line-height: 1.3;} +.lh-1-4 {line-height: 1.4;} +.lh-1-5 {line-height: 1.5;} +.lh-1-6 {line-height: 1.6;} +.lh-1-7 {line-height: 1.7;} +.lh-1-8 {line-height: 1.8;} +.lh-1-9 {line-height: 1.9;} +.lh-2-0 {line-height: 2.0;} +.lh-2-1 {line-height: 2.1;} +.lh-2-2 {line-height: 2.2;} +.lh-2-3 {line-height: 2.3;} +.lh-2-4 {line-height: 2.4;} +.lh-2-5 {line-height: 2.5;} +.lh-2-6 {line-height: 2.6;} +.lh-2-7 {line-height: 2.7;} +.lh-2-8 {line-height: 2.8;} +.lh-2-9 {line-height: 2.9;} +.lh-3-0 {line-height: 3.0;} + +/* ------------------------------------ */ +.txt-center {text-align: center;} +.txt-left {text-align: left;} +.txt-right {text-align: right;} +.txt-middle {vertical-align: middle;} + + + +/*////////////////////////////////////////////////////////////////// +[ SIZE ]*/ + +.size-full { + width: 100%; + height: 100%; +} +.w-full {width: 100%;} +.h-full {height: 100%;} +.max-w-full {max-width: 100%;} +.max-h-full {max-height: 100%;} +.min-w-full {min-width: 100%;} +.min-h-full {min-height: 100%;} + + + +/*////////////////////////////////////////////////////////////////// +[ BACKGROUND ]*/ +.bgwhite {background-color: white;} +.bgblack {background-color: black;} +.bgyellow {background-color: #ffc000;} +.bgorange {background-color: #fc7f0c;} +.bgred {background-color: #e84b3a;} +.bggrey {background-color: #474747;} +.bglimestone {background-color: #ACA39A;} + + + +/*////////////////////////////////////////////////////////////////// +[ PSEUDO ]*/ + +/*------------------------------------------------------------------ +[ Hover ]*/ +.hov-img-zoom { + display: block; + overflow: hidden; +} +.hov-img-zoom img{ + width: 100%; + -webkit-transition: all 0.6s; + -o-transition: all 0.6s; + -moz-transition: all 0.6s; + transition: all 0.6s; +} +.hov-img-zoom:hover img { + -webkit-transform: scale(1.1); + -moz-transform: scale(1.1); + -ms-transform: scale(1.1); + -o-transform: scale(1.1); + transform: scale(1.1); +} + + + +/*////////////////////////////////////////////////////////////////// +[ EFFECT ]*/ + +.pointer {cursor: pointer;} + +/*------------------------------------------------------------------ +[ Opacity ]*/ +.op-00 {opacity: 0;} +.op-01 {opacity: 0.1;} +.op-02 {opacity: 0.2;} +.op-03 {opacity: 0.3;} +.op-04 {opacity: 0.4;} +.op-05 {opacity: 0.5;} +.op-06 {opacity: 0.6;} +.op-07 {opacity: 0.7;} +.op-08 {opacity: 0.8;} +.op-09 {opacity: 0.9;} +.op-10 {opacity: 1;} + + +/*------------------------------------------------------------------ +[ Wrap Picture ]*/ +.wrap-pic-w img {width: 100%;} +.wrap-pic-max-w img {max-width: 100%;} + +/* ------------------------------------ */ +.wrap-pic-h img {height: 100%;} +.wrap-pic-max-h img {max-height: 100%;} + +/* ------------------------------------ */ +.wrap-pic-cir { + border-radius: 50%; + overflow: hidden; +} +.wrap-pic-cir img { + width: 100%; +} + +/*------------------------------------------------------------------ +[ ]*/ +.bo-cir {border-radius: 50%;} + +.of-hidden {overflow: hidden;} + +.visible-false {visibility: hidden;} +.visible-true {visibility: visible;} + + +/*------------------------------------------------------------------ +[ Transition ]*/ +.trans-01 { + -webkit-transition: all 0.1s; + -o-transition: all 0.1s; + -moz-transition: all 0.1s; + transition: all 0.1s; +} +.trans-02 { + -webkit-transition: all 0.2s; + -o-transition: all 0.2s; + -moz-transition: all 0.2s; + transition: all 0.2s; +} +.trans-03 { + -webkit-transition: all 0.3s; + -o-transition: all 0.3s; + -moz-transition: all 0.3s; + transition: all 0.3s; +} +.trans-04 { + -webkit-transition: all 0.4s; + -o-transition: all 0.4s; + -moz-transition: all 0.4s; + transition: all 0.4s; +} +.trans-05 { + -webkit-transition: all 0.5s; + -o-transition: all 0.5s; + -moz-transition: all 0.5s; + transition: all 0.5s; +} +.trans-06 { + -webkit-transition: all 0.6s; + -o-transition: all 0.6s; + -moz-transition: all 0.6s; + transition: all 0.6s; +} +.trans-07 { + -webkit-transition: all 0.7s; + -o-transition: all 0.7s; + -moz-transition: all 0.7s; + transition: all 0.7s; +} +.trans-08 { + -webkit-transition: all 0.8s; + -o-transition: all 0.8s; + -moz-transition: all 0.8s; + transition: all 0.8s; +} +.trans-09 { + -webkit-transition: all 0.9s; + -o-transition: all 0.9s; + -moz-transition: all 0.9s; + transition: all 0.9s; +} +.trans-10 { + -webkit-transition: all 1s; + -o-transition: all 1s; + -moz-transition: all 1s; + transition: all 1s; +} + + + +/*////////////////////////////////////////////////////////////////// +[ POSITION ]*/ + +/*------------------------------------------------------------------ +[ Display ]*/ +.dis-none {display: none;} +.dis-block {display: block;} +.dis-inline {display: inline;} +.dis-inline-block {display: inline-block;} + +.flex-w, +.flex-l, +.flex-r, +.flex-c, +.flex-sa, +.flex-sb, +.flex-t, +.flex-b, +.flex-m, +.flex-str, +.flex-c-m, +.flex-c-t, +.flex-c-b, +.flex-c-str, +.flex-l-m, +.flex-r-m, +.flex-sa-m, +.flex-sb-m, +.flex-col-l, +.flex-col-r, +.flex-col-c, +.flex-col-str, +.flex-col-t, +.flex-col-b, +.flex-col-m, +.flex-col-sb, +.flex-col-sa, +.flex-col-c-m, +.flex-col-l-m, +.flex-col-r-m, +.flex-col-str-m, +.flex-col-c-t, +.flex-col-c-b, +.flex-col-c-sb, +.flex-col-c-sa, +.flex-row, +.flex-row-rev, +.flex-col, +.flex-col-rev, +.dis-flex { + display: -webkit-box; + display: -webkit-flex; + display: -moz-box; + display: -ms-flexbox; + display: flex; +} + +/*------------------------------------------------------------------ +[ Position ]*/ +.pos-relative {position: relative;} +.pos-absolute {position: absolute;} +.pos-fixed {position: fixed;} + +/*------------------------------------------------------------------ +[ Float ]*/ +.float-l {float: left;} +.float-r {float: right;} + + +/*------------------------------------------------------------------ +[ Top Bottom Left Right ]*/ +.top-0 {top: 0;} +.bottom-0 {bottom: 0;} +.left-0 {left: 0;} +.right-0 {right: 0;} + +.top-auto {top: auto;} +.bottom-auto {bottom: auto;} +.left-auto {left: auto;} +.right-auto {right: auto;} + + +/*------------------------------------------------------------------ +[ Flex ]*/ +/* ------------------------------------ */ +.flex-w { + -webkit-flex-wrap: wrap; + -moz-flex-wrap: wrap; + -ms-flex-wrap: wrap; + -o-flex-wrap: wrap; + flex-wrap: wrap; +} + +/* ------------------------------------ */ +.flex-l { + justify-content: flex-start; +} + +.flex-r { + justify-content: flex-end; +} + +.flex-c { + justify-content: center; +} + +.flex-sa { + justify-content: space-around; +} + +.flex-sb { + justify-content: space-between; +} + +/* ------------------------------------ */ +.flex-t { + -ms-align-items: flex-start; + align-items: flex-start; +} + +.flex-b { + -ms-align-items: flex-end; + align-items: flex-end; +} + +.flex-m { + -ms-align-items: center; + align-items: center; +} + +.flex-str { + -ms-align-items: stretch; + align-items: stretch; +} + + +/* ------------------------------------ */ +.flex-c-m { + justify-content: center; + -ms-align-items: center; + align-items: center; +} + +.flex-c-t { + justify-content: center; + -ms-align-items: flex-start; + align-items: flex-start; +} + +.flex-c-b { + justify-content: center; + -ms-align-items: flex-end; + align-items: flex-end; +} + +.flex-c-str { + justify-content: center; + -ms-align-items: stretch; + align-items: stretch; +} + +.flex-l-m { + justify-content: flex-start; + -ms-align-items: center; + align-items: center; +} + +.flex-r-m { + justify-content: flex-end; + -ms-align-items: center; + align-items: center; +} + +.flex-sa-m { + justify-content: space-around; + -ms-align-items: center; + align-items: center; +} + +.flex-sb-m { + justify-content: space-between; + -ms-align-items: center; + align-items: center; +} + +/* ------------------------------------ */ +.flex-col-l { + -ms-align-items: flex-start; + align-items: flex-start; +} + +.flex-col-r { + -ms-align-items: flex-end; + align-items: flex-end; +} + +.flex-col-c { + -ms-align-items: center; + align-items: center; +} + +.flex-col-str { + -ms-align-items: stretch; + align-items: stretch; +} + +/*---------------------------------------------*/ +.flex-col-t { + justify-content: flex-start; +} + +.flex-col-b { + justify-content: flex-end; +} + +.flex-col-m { + justify-content: center; +} + +.flex-col-sb { + justify-content: space-between; +} + +.flex-col-sa { + justify-content: space-around; +} + +/*---------------------------------------------*/ +.flex-col-c-m { + -ms-align-items: center; + align-items: center; + justify-content: center; +} + +.flex-col-l-m { + -ms-align-items: flex-start; + align-items: flex-start; + justify-content: center; +} + +.flex-col-r-m { + -ms-align-items: flex-end; + align-items: flex-end; + justify-content: center; +} + +.flex-col-str-m { + -ms-align-items: stretch; + align-items: stretch; + justify-content: center; +} + + +.flex-col-c-t { + justify-content: flex-start; + -ms-align-items: center; + align-items: center; +} + +.flex-col-c-b { + justify-content: flex-end; + -ms-align-items: center; + align-items: center; +} + +.flex-col-c-sb { + justify-content: space-between; + -ms-align-items: center; + align-items: center; +} + +.flex-col-c-sa { + justify-content: space-around; + -ms-align-items: center; + align-items: center; +} + + +/* ------------------------------------ */ +.flex-row { + -webkit-flex-direction: row; + -moz-flex-direction: row; + -ms-flex-direction: row; + -o-flex-direction: row; + flex-direction: row; +} + +.flex-row-rev { + -webkit-flex-direction: row-reverse; + -moz-flex-direction: row-reverse; + -ms-flex-direction: row-reverse; + -o-flex-direction: row-reverse; + flex-direction: row-reverse; +} + +.flex-col-l, +.flex-col-r, +.flex-col-c, +.flex-col-str, +.flex-col-t, +.flex-col-b, +.flex-col-m, +.flex-col-sb, +.flex-col-sa, +.flex-col-c-m, +.flex-col-l-m, +.flex-col-r-m, +.flex-col-str-m, +.flex-col-c-t, +.flex-col-c-b, +.flex-col-c-sb, +.flex-col-c-sa, +.flex-col { + -webkit-flex-direction: column; + -moz-flex-direction: column; + -ms-flex-direction: column; + -o-flex-direction: column; + flex-direction: column; +} + +.flex-col-rev { + -webkit-flex-direction: column-reverse; + -moz-flex-direction: column-reverse; + -ms-flex-direction: column-reverse; + -o-flex-direction: column-reverse; + flex-direction: column-reverse; +} + + +/*------------------------------------------------------------------ +[ Absolute ]*/ +.ab-c-m { + position: absolute; + top: 50%; + left: 50%; + -webkit-transform: translate(-50%, -50%); + -moz-transform: translate(-50%, -50%); + -ms-transform: translate(-50%, -50%); + -o-transform: translate(-50%, -50%); + transform: translate(-50%, -50%); +} + +.ab-c-t { + position: absolute; + top: 0px; + left: 50%; + -webkit-transform: translateX(-50%); + -moz-transform: translateX(-50%); + -ms-transform: translateX(-50%); + -o-transform: translateX(-50%); + transform: translateX(-50%); +} + +.ab-c-b { + position: absolute; + bottom: 0px; + left: 50%; + -webkit-transform: translateX(-50%); + -moz-transform: translateX(-50%); + -ms-transform: translateX(-50%); + -o-transform: translateX(-50%); + transform: translateX(-50%); +} + +.ab-l-m { + position: absolute; + left: 0px; + top: 50%; + -webkit-transform: translateY(-50%); + -moz-transform: translateY(-50%); + -ms-transform: translateY(-50%); + -o-transform: translateY(-50%); + transform: translateY(-50%); +} + +.ab-r-m { + position: absolute; + right: 0px; + top: 50%; + -webkit-transform: translateY(-50%); + -moz-transform: translateY(-50%); + -ms-transform: translateY(-50%); + -o-transform: translateY(-50%); + transform: translateY(-50%); +} + +.ab-t-l { + position: absolute; + left: 0px; + top: 0px; +} + +.ab-t-r { + position: absolute; + right: 0px; + top: 0px; +} + +.ab-b-l { + position: absolute; + left: 0px; + bottom: 0px; +} + +.ab-b-r { + position: absolute; + right: 0px; + bottom: 0px; +} + +/* Grid */ +.grid { + display: grid; +} + +/* Gaps */ +.g-gap-2 { + grid-gap: 2em; +} + +/* Columns */ +.g-col-3 { + grid-template-columns: repeat(3, 1fr); +} +.g-col-2 { + grid-template-columns: repeat(2, 1fr); +} + +/* Rows */ +.g-row-2 { + grid-template-rows: repeat(2, 1fr); +} + +/* Spans */ +.g-span-2 { + grid-column: span 2; +} + +/* Mobile section */ +@media only screen and (max-width: 600px) { + /* Columns */ + .g-m-col-2 { + grid-template-columns: repeat(2, 1fr); + } + .g-m-col-1 { + grid-template-columns: repeat(1, 1fr); + } + + /* Rows */ + .g-m-rows-3 { + grid-template-rows: repeat(3, 1fr); + } +} \ No newline at end of file diff --git a/v0.10.x/_static/doctools.js b/v0.10.x/_static/doctools.js new file mode 100644 index 000000000..d06a71d75 --- /dev/null +++ b/v0.10.x/_static/doctools.js @@ -0,0 +1,156 @@ +/* + * doctools.js + * ~~~~~~~~~~~ + * + * Base JavaScript utilities for all Sphinx HTML documentation. + * + * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ +"use strict"; + +const BLACKLISTED_KEY_CONTROL_ELEMENTS = new Set([ + "TEXTAREA", + "INPUT", + "SELECT", + "BUTTON", +]); + +const _ready = (callback) => { + if (document.readyState !== "loading") { + callback(); + } else { + document.addEventListener("DOMContentLoaded", callback); + } +}; + +/** + * Small JavaScript module for the documentation. + */ +const Documentation = { + init: () => { + Documentation.initDomainIndexTable(); + Documentation.initOnKeyListeners(); + }, + + /** + * i18n support + */ + TRANSLATIONS: {}, + PLURAL_EXPR: (n) => (n === 1 ? 0 : 1), + LOCALE: "unknown", + + // gettext and ngettext don't access this so that the functions + // can safely bound to a different name (_ = Documentation.gettext) + gettext: (string) => { + const translated = Documentation.TRANSLATIONS[string]; + switch (typeof translated) { + case "undefined": + return string; // no translation + case "string": + return translated; // translation exists + default: + return translated[0]; // (singular, plural) translation tuple exists + } + }, + + ngettext: (singular, plural, n) => { + const translated = Documentation.TRANSLATIONS[singular]; + if (typeof translated !== "undefined") + return translated[Documentation.PLURAL_EXPR(n)]; + return n === 1 ? singular : plural; + }, + + addTranslations: (catalog) => { + Object.assign(Documentation.TRANSLATIONS, catalog.messages); + Documentation.PLURAL_EXPR = new Function( + "n", + `return (${catalog.plural_expr})` + ); + Documentation.LOCALE = catalog.locale; + }, + + /** + * helper function to focus on search bar + */ + focusSearchBar: () => { + document.querySelectorAll("input[name=q]")[0]?.focus(); + }, + + /** + * Initialise the domain index toggle buttons + */ + initDomainIndexTable: () => { + const toggler = (el) => { + const idNumber = el.id.substr(7); + const toggledRows = document.querySelectorAll(`tr.cg-${idNumber}`); + if (el.src.substr(-9) === "minus.png") { + el.src = `${el.src.substr(0, el.src.length - 9)}plus.png`; + toggledRows.forEach((el) => (el.style.display = "none")); + } else { + el.src = `${el.src.substr(0, el.src.length - 8)}minus.png`; + toggledRows.forEach((el) => (el.style.display = "")); + } + }; + + const togglerElements = document.querySelectorAll("img.toggler"); + togglerElements.forEach((el) => + el.addEventListener("click", (event) => toggler(event.currentTarget)) + ); + togglerElements.forEach((el) => (el.style.display = "")); + if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) togglerElements.forEach(toggler); + }, + + initOnKeyListeners: () => { + // only install a listener if it is really needed + if ( + !DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS && + !DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS + ) + return; + + document.addEventListener("keydown", (event) => { + // bail for input elements + if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return; + // bail with special keys + if (event.altKey || event.ctrlKey || event.metaKey) return; + + if (!event.shiftKey) { + switch (event.key) { + case "ArrowLeft": + if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; + + const prevLink = document.querySelector('link[rel="prev"]'); + if (prevLink && prevLink.href) { + window.location.href = prevLink.href; + event.preventDefault(); + } + break; + case "ArrowRight": + if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; + + const nextLink = document.querySelector('link[rel="next"]'); + if (nextLink && nextLink.href) { + window.location.href = nextLink.href; + event.preventDefault(); + } + break; + } + } + + // some keyboard layouts may need Shift to get / + switch (event.key) { + case "/": + if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) break; + Documentation.focusSearchBar(); + event.preventDefault(); + } + }); + }, +}; + +// quick alias for translations +const _ = Documentation.gettext; + +_ready(Documentation.init); diff --git a/v0.10.x/_static/documentation_options.js b/v0.10.x/_static/documentation_options.js new file mode 100644 index 000000000..c16289453 --- /dev/null +++ b/v0.10.x/_static/documentation_options.js @@ -0,0 +1,13 @@ +const DOCUMENTATION_OPTIONS = { + VERSION: '0.10.0', + LANGUAGE: 'en', + COLLAPSE_INDEX: false, + BUILDER: 'html', + FILE_SUFFIX: '.html', + LINK_SUFFIX: '.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt', + NAVIGATION_WITH_KEYS: true, + SHOW_SEARCH_SUMMARY: true, + ENABLE_SEARCH_SHORTCUTS: true, +}; \ No newline at end of file diff --git a/v0.10.x/_static/file.png b/v0.10.x/_static/file.png new file mode 100644 index 000000000..a858a410e Binary files /dev/null and b/v0.10.x/_static/file.png differ diff --git a/v0.10.x/_static/images/4.gif b/v0.10.x/_static/images/4.gif new file mode 100644 index 000000000..b030a0fd1 Binary files /dev/null and b/v0.10.x/_static/images/4.gif differ diff --git a/v0.10.x/_static/images/brain.gif b/v0.10.x/_static/images/brain.gif new file mode 100644 index 000000000..f5cc6fc91 Binary files /dev/null and b/v0.10.x/_static/images/brain.gif differ diff --git a/v0.10.x/_static/images/comp-soft/adobedimension.jpg b/v0.10.x/_static/images/comp-soft/adobedimension.jpg new file mode 100644 index 000000000..cbb339845 Binary files /dev/null and b/v0.10.x/_static/images/comp-soft/adobedimension.jpg differ diff --git a/v0.10.x/_static/images/comp-soft/autodesk.jpg b/v0.10.x/_static/images/comp-soft/autodesk.jpg new file mode 100644 index 000000000..72d55404d Binary files /dev/null and b/v0.10.x/_static/images/comp-soft/autodesk.jpg differ diff --git a/v0.10.x/_static/images/comp-soft/blender.jpg b/v0.10.x/_static/images/comp-soft/blender.jpg new file mode 100644 index 000000000..b0f987c5a Binary files /dev/null and b/v0.10.x/_static/images/comp-soft/blender.jpg differ diff --git a/v0.10.x/_static/images/comp-soft/houdini.jpg b/v0.10.x/_static/images/comp-soft/houdini.jpg new file mode 100644 index 000000000..91b3b7946 Binary files /dev/null and b/v0.10.x/_static/images/comp-soft/houdini.jpg differ diff --git a/v0.10.x/_static/images/comp-soft/modo.jpg b/v0.10.x/_static/images/comp-soft/modo.jpg new file mode 100644 index 000000000..f11efe06a Binary files /dev/null and b/v0.10.x/_static/images/comp-soft/modo.jpg differ diff --git a/v0.10.x/_static/images/comp-soft/sketchup.jpg b/v0.10.x/_static/images/comp-soft/sketchup.jpg new file mode 100644 index 000000000..98403594c Binary files /dev/null and b/v0.10.x/_static/images/comp-soft/sketchup.jpg differ diff --git a/v0.10.x/_static/images/comp-soft/unity.jpg b/v0.10.x/_static/images/comp-soft/unity.jpg new file mode 100644 index 000000000..feb5c92cc Binary files /dev/null and b/v0.10.x/_static/images/comp-soft/unity.jpg differ diff --git a/v0.10.x/_static/images/home-page-opener.mp4 b/v0.10.x/_static/images/home-page-opener.mp4 new file mode 100644 index 000000000..d14e33cc9 Binary files /dev/null and b/v0.10.x/_static/images/home-page-opener.mp4 differ diff --git a/v0.10.x/_static/images/horse.gif b/v0.10.x/_static/images/horse.gif new file mode 100644 index 000000000..3299d95bd Binary files /dev/null and b/v0.10.x/_static/images/horse.gif differ diff --git a/v0.10.x/_static/images/logo.ico b/v0.10.x/_static/images/logo.ico new file mode 100644 index 000000000..29aa62945 Binary files /dev/null and b/v0.10.x/_static/images/logo.ico differ diff --git a/v0.10.x/_static/images/logo.svg b/v0.10.x/_static/images/logo.svg new file mode 100644 index 000000000..1bf58639e --- /dev/null +++ b/v0.10.x/_static/images/logo.svg @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/v0.10.x/_static/images/physical.gif b/v0.10.x/_static/images/physical.gif new file mode 100644 index 000000000..7b94ae058 Binary files /dev/null and b/v0.10.x/_static/images/physical.gif differ diff --git a/v0.10.x/_static/images/promo1.jpg b/v0.10.x/_static/images/promo1.jpg new file mode 100644 index 000000000..f8e74aaef Binary files /dev/null and b/v0.10.x/_static/images/promo1.jpg differ diff --git a/v0.10.x/_static/images/promo2.jpg b/v0.10.x/_static/images/promo2.jpg new file mode 100644 index 000000000..651f1f067 Binary files /dev/null and b/v0.10.x/_static/images/promo2.jpg differ diff --git a/v0.10.x/_static/images/promo3.jpg b/v0.10.x/_static/images/promo3.jpg new file mode 100644 index 000000000..409729b84 Binary files /dev/null and b/v0.10.x/_static/images/promo3.jpg differ diff --git a/v0.10.x/_static/images/sc-dom/aerospace.svg b/v0.10.x/_static/images/sc-dom/aerospace.svg new file mode 100644 index 000000000..546e0e79a --- /dev/null +++ b/v0.10.x/_static/images/sc-dom/aerospace.svg @@ -0,0 +1 @@ + diff --git a/v0.10.x/_static/images/sc-dom/astronomy.svg b/v0.10.x/_static/images/sc-dom/astronomy.svg new file mode 100644 index 000000000..553371d44 --- /dev/null +++ b/v0.10.x/_static/images/sc-dom/astronomy.svg @@ -0,0 +1 @@ +planet-saturn-space diff --git a/v0.10.x/_static/images/sc-dom/biology.svg b/v0.10.x/_static/images/sc-dom/biology.svg new file mode 100644 index 000000000..492b30c12 --- /dev/null +++ b/v0.10.x/_static/images/sc-dom/biology.svg @@ -0,0 +1 @@ + diff --git a/v0.10.x/_static/images/sc-dom/chemistry.svg b/v0.10.x/_static/images/sc-dom/chemistry.svg new file mode 100644 index 000000000..20c05bf1e --- /dev/null +++ b/v0.10.x/_static/images/sc-dom/chemistry.svg @@ -0,0 +1 @@ +lab diff --git a/v0.10.x/_static/images/sc-dom/data-science.svg b/v0.10.x/_static/images/sc-dom/data-science.svg new file mode 100644 index 000000000..53c55e084 --- /dev/null +++ b/v0.10.x/_static/images/sc-dom/data-science.svg @@ -0,0 +1 @@ +generate-report diff --git a/v0.10.x/_static/images/sc-dom/engineering.svg b/v0.10.x/_static/images/sc-dom/engineering.svg new file mode 100644 index 000000000..2e1d0e9ab --- /dev/null +++ b/v0.10.x/_static/images/sc-dom/engineering.svg @@ -0,0 +1 @@ + diff --git a/v0.10.x/_static/images/sc-dom/maths.svg b/v0.10.x/_static/images/sc-dom/maths.svg new file mode 100644 index 000000000..f939866b0 --- /dev/null +++ b/v0.10.x/_static/images/sc-dom/maths.svg @@ -0,0 +1 @@ + diff --git a/v0.10.x/_static/images/sc-dom/network.svg b/v0.10.x/_static/images/sc-dom/network.svg new file mode 100644 index 000000000..f29f4009c --- /dev/null +++ b/v0.10.x/_static/images/sc-dom/network.svg @@ -0,0 +1 @@ + diff --git a/v0.10.x/_static/images/sc-dom/physics.svg b/v0.10.x/_static/images/sc-dom/physics.svg new file mode 100644 index 000000000..fbb484081 --- /dev/null +++ b/v0.10.x/_static/images/sc-dom/physics.svg @@ -0,0 +1 @@ + diff --git a/v0.10.x/_static/images/sc-dom/popup/aerospace.gif b/v0.10.x/_static/images/sc-dom/popup/aerospace.gif new file mode 100644 index 000000000..4add62b7c Binary files /dev/null and b/v0.10.x/_static/images/sc-dom/popup/aerospace.gif differ diff --git a/v0.10.x/_static/images/sc-dom/popup/astronomy.gif b/v0.10.x/_static/images/sc-dom/popup/astronomy.gif new file mode 100644 index 000000000..d338eb00c Binary files /dev/null and b/v0.10.x/_static/images/sc-dom/popup/astronomy.gif differ diff --git a/v0.10.x/_static/images/sc-dom/popup/biology.gif b/v0.10.x/_static/images/sc-dom/popup/biology.gif new file mode 100644 index 000000000..e60b22c3a Binary files /dev/null and b/v0.10.x/_static/images/sc-dom/popup/biology.gif differ diff --git a/v0.10.x/_static/images/sc-dom/popup/chemistry.gif b/v0.10.x/_static/images/sc-dom/popup/chemistry.gif new file mode 100644 index 000000000..6ffdb160b Binary files /dev/null and b/v0.10.x/_static/images/sc-dom/popup/chemistry.gif differ diff --git a/v0.10.x/_static/images/sc-dom/popup/data-science.gif b/v0.10.x/_static/images/sc-dom/popup/data-science.gif new file mode 100644 index 000000000..f88ae462e Binary files /dev/null and b/v0.10.x/_static/images/sc-dom/popup/data-science.gif differ diff --git a/v0.10.x/_static/images/sc-dom/popup/engineering.gif b/v0.10.x/_static/images/sc-dom/popup/engineering.gif new file mode 100644 index 000000000..c6504416f Binary files /dev/null and b/v0.10.x/_static/images/sc-dom/popup/engineering.gif differ diff --git a/v0.10.x/_static/images/sc-dom/popup/mathematics.gif b/v0.10.x/_static/images/sc-dom/popup/mathematics.gif new file mode 100644 index 000000000..333def764 Binary files /dev/null and b/v0.10.x/_static/images/sc-dom/popup/mathematics.gif differ diff --git a/v0.10.x/_static/images/sc-dom/popup/network-science.gif b/v0.10.x/_static/images/sc-dom/popup/network-science.gif new file mode 100644 index 000000000..5f524407b Binary files /dev/null and b/v0.10.x/_static/images/sc-dom/popup/network-science.gif differ diff --git a/v0.10.x/_static/images/sc-dom/popup/physics.gif b/v0.10.x/_static/images/sc-dom/popup/physics.gif new file mode 100644 index 000000000..99ecb081e Binary files /dev/null and b/v0.10.x/_static/images/sc-dom/popup/physics.gif differ diff --git a/v0.10.x/_static/images/sponsors/gsoc.jpg b/v0.10.x/_static/images/sponsors/gsoc.jpg new file mode 100644 index 000000000..f1f4132aa Binary files /dev/null and b/v0.10.x/_static/images/sponsors/gsoc.jpg differ diff --git a/v0.10.x/_static/images/sponsors/iu.jpg b/v0.10.x/_static/images/sponsors/iu.jpg new file mode 100644 index 000000000..5a2bf5454 Binary files /dev/null and b/v0.10.x/_static/images/sponsors/iu.jpg differ diff --git a/v0.10.x/_static/images/sponsors/luddy.jpg b/v0.10.x/_static/images/sponsors/luddy.jpg new file mode 100644 index 000000000..8efd0e2ac Binary files /dev/null and b/v0.10.x/_static/images/sponsors/luddy.jpg differ diff --git a/v0.10.x/_static/images/suzanne.png b/v0.10.x/_static/images/suzanne.png new file mode 100644 index 000000000..e0c85c0da Binary files /dev/null and b/v0.10.x/_static/images/suzanne.png differ diff --git a/v0.10.x/_static/images/text-logo.png b/v0.10.x/_static/images/text-logo.png new file mode 100644 index 000000000..18356691a Binary files /dev/null and b/v0.10.x/_static/images/text-logo.png differ diff --git a/v0.10.x/_static/js/fresh.js b/v0.10.x/_static/js/fresh.js new file mode 100644 index 000000000..da1dc30dd --- /dev/null +++ b/v0.10.x/_static/js/fresh.js @@ -0,0 +1,143 @@ +//Preloader +$(window).on('load', function() { // makes sure the whole site is loaded + $('#status').fadeOut(); // will first fade out the loading animation + $('#preloader').delay(350).fadeOut('slow'); // will fade out the white DIV that covers the website. + $('body').delay(350).css({'overflow':'visible'}); +}) + +$(document).ready(function(){ + //Mobile menu toggle + if ($('.navbar-burger').length) { + $('.navbar-burger').on("click", function(){ + + var menu_id = $(this).attr('data-target'); + $(this).toggleClass('is-active'); + $("#"+menu_id).toggleClass('is-active'); + $('.navbar.is-light').toggleClass('is-dark-mobile') + }); + } + + //Animate left hamburger icon and open sidebar + $('.menu-icon-trigger').on("click", function(e){ + e.preventDefault(); + $('.menu-icon-wrapper').toggleClass('open'); + $('.sidebar').toggleClass('is-active'); + }); + + //Close sidebar + $('.sidebar-close').on("click", function() { + $('.sidebar').removeClass('is-active'); + $('.menu-icon-wrapper').removeClass('open'); + }) + + //Sidebar menu + if ($('.sidebar').length) { + $(".sidebar-menu > li.have-children > a").on("click", function(i){ + i.preventDefault(); + if( ! $(this).parent().hasClass("active") ){ + $(".sidebar-menu li ul").slideUp(); + $(this).next().slideToggle(); + $(".sidebar-menu li").removeClass("active"); + $(this).parent().addClass("active"); + } + else{ + $(this).next().slideToggle(); + $(".sidebar-menu li").removeClass("active"); + } + }); + } + + //Navbar Clone + if ($('#navbar-clone').length) { + $(window).on("scroll", function() { // this will work when your window scrolled. + var height = $(window).scrollTop(); //getting the scrolling height of window + if(height > 50) { + $("#navbar-clone").addClass('is-active'); + } else{ + $("#navbar-clone").removeClass('is-active'); + } + }); + } + + //Init feather icons + feather.replace(); + + //reveal elements on scroll so animations trigger the right way + var $window = $(window), + win_height_padded = $window.height() * 1.1, + isTouch = Modernizr.touch; + + $window.on('scroll', revealOnScroll); + + function revealOnScroll() { + var scrolled = $window.scrollTop(); + $(".revealOnScroll:not(.animated)").each(function () { + var $this = $(this), + offsetTop = $this.offset().top; + + if (scrolled + win_height_padded > offsetTop) { + if ($this.data('timeout')) { + window.setTimeout(function(){ + $this.addClass('animated ' + $this.data('animation')); + }, parseInt($this.data('timeout'),10)); + } else { + $this.addClass('animated ' + $this.data('animation')); + } + } + }); + } + + // Back to Top button behaviour + var pxShow = 600; + var scrollSpeed = 500; + $(window).on("scroll", function() { + if ($(window).scrollTop() >= pxShow) { + $("#backtotop").addClass('visible'); + } else { + $("#backtotop").removeClass('visible'); + } + }); + $('#backtotop a').on('click', function() { + $('html, body').animate({ + scrollTop: 0 + }, scrollSpeed); + return false; + }); + + // Select all links with hashes + $('a[href*="#"]') + // Remove links that don't actually link to anything + .not('[href="#"]') + .not('[href="#0"]') + .on("click", function(event) { + // On-page links + if ( + location.pathname.replace(/^\//, '') == this.pathname.replace(/^\//, '') + && + location.hostname == this.hostname + ) { + // Figure out element to scroll to + var target = $(this.hash); + target = target.length ? target : $('[name=' + this.hash.slice(1) + ']'); + // Does a scroll target exist? + if (target.length) { + // Only prevent default if animation is actually gonna happen + event.preventDefault(); + $('html, body').animate({ + scrollTop: target.offset().top + }, 550, function() { + // Callback after animation + // Must change focus! + var $target = $(target); + $target.focus(); + if ($target.is(":focus")) { // Checking if the target was focused + return false; + } else { + $target.attr('tabindex','-1'); // Adding tabindex for elements not focusable + $target.focus(); // Set focus again + }; + }); + } + } + }); +}) diff --git a/v0.10.x/_static/js/fury.js b/v0.10.x/_static/js/fury.js new file mode 100644 index 000000000..8161d2ff9 --- /dev/null +++ b/v0.10.x/_static/js/fury.js @@ -0,0 +1,58 @@ +(function(){ + var TxtRotate = function(el, toRotate, period) { + this.toRotate = toRotate; + this.el = el; + this.loopNum = 0; + this.period = parseInt(period, 10) || 2000; + this.txt = ''; + this.tick(); + this.isDeleting = false; + }; + + TxtRotate.prototype.tick = function() { + var i = this.loopNum % this.toRotate.length; + var fullTxt = this.toRotate[i]; + + if (this.isDeleting) { + this.txt = fullTxt.substring(0, this.txt.length - 1); + } else { + this.txt = fullTxt.substring(0, this.txt.length + 1); + } + + this.el.innerHTML = ''+this.txt+''; + + var that = this; + var delta = 300 - Math.random() * 100; + + if (this.isDeleting) { delta /= 2; } + + if (!this.isDeleting && this.txt === fullTxt) { + delta = this.period; + this.isDeleting = true; + } else if (this.isDeleting && this.txt === '') { + this.isDeleting = false; + this.loopNum++; + delta = 500; + } + + setTimeout(function() { + that.tick(); + }, delta); + }; + + window.onload = function() { + var elements = document.getElementsByClassName('txt-rotate'); + for (var i=0; i'; + + var that = this; + var delta = 300 - Math.random() * 100; + + if (this.isDeleting) { delta /= 2; } + + if (!this.isDeleting && this.txt === fullTxt) { + delta = this.period; + this.isDeleting = true; + } else if (this.isDeleting && this.txt === '') { + this.isDeleting = false; + this.loopNum++; + delta = 500; + } + + setTimeout(function() { + that.tick(); + }, delta); + }; + + window.onload = function() { + var elements = document.getElementsByClassName('txt-rotate'); + for (var i=0; i 0) { + $(classes).map(function(idx, el) { + const title = el.textContent; + // transforms title into snake-case + const elTitle = title.replace(/\W/g, '-').toLowerCase(); + // Gets the element type (e.g. h2, h3) + const elType = $(el).get(0).tagName; + // Adds snake-case title as an id attribute to target element + $(el).attr('id', elTitle); + shortcutsTarget.append(`
${title}
`); + + $(`#${elTitle}-shortcut`).click(function() { + $([document.documentElement, document.body]).animate({ + scrollTop: $(`#${elTitle}`).offset().top-60 + }, 1000); + }) + }); + } + + // Removes the shortcuts container if no shortcuts exist. + // Also removes the 'Get Help' link. + if ($('#shortcuts div').length < 1) { + $('.shortcuts-container').css('display', 'none'); + } +} diff --git a/v0.10.x/_static/jupyterlite_badge_logo.svg b/v0.10.x/_static/jupyterlite_badge_logo.svg new file mode 100644 index 000000000..5de36d7fd --- /dev/null +++ b/v0.10.x/_static/jupyterlite_badge_logo.svg @@ -0,0 +1,3 @@ + + +launchlaunchlitelite \ No newline at end of file diff --git a/v0.10.x/_static/language_data.js b/v0.10.x/_static/language_data.js new file mode 100644 index 000000000..250f5665f --- /dev/null +++ b/v0.10.x/_static/language_data.js @@ -0,0 +1,199 @@ +/* + * language_data.js + * ~~~~~~~~~~~~~~~~ + * + * This script contains the language-specific data used by searchtools.js, + * namely the list of stopwords, stemmer, scorer and splitter. + * + * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +var stopwords = ["a", "and", "are", "as", "at", "be", "but", "by", "for", "if", "in", "into", "is", "it", "near", "no", "not", "of", "on", "or", "such", "that", "the", "their", "then", "there", "these", "they", "this", "to", "was", "will", "with"]; + + +/* Non-minified version is copied as a separate JS file, is available */ + +/** + * Porter Stemmer + */ +var Stemmer = function() { + + var step2list = { + ational: 'ate', + tional: 'tion', + enci: 'ence', + anci: 'ance', + izer: 'ize', + bli: 'ble', + alli: 'al', + entli: 'ent', + eli: 'e', + ousli: 'ous', + ization: 'ize', + ation: 'ate', + ator: 'ate', + alism: 'al', + iveness: 'ive', + fulness: 'ful', + ousness: 'ous', + aliti: 'al', + iviti: 'ive', + biliti: 'ble', + logi: 'log' + }; + + var step3list = { + icate: 'ic', + ative: '', + alize: 'al', + iciti: 'ic', + ical: 'ic', + ful: '', + ness: '' + }; + + var c = "[^aeiou]"; // consonant + var v = "[aeiouy]"; // vowel + var C = c + "[^aeiouy]*"; // consonant sequence + var V = v + "[aeiou]*"; // vowel sequence + + var mgr0 = "^(" + C + ")?" + V + C; // [C]VC... is m>0 + var meq1 = "^(" + C + ")?" + V + C + "(" + V + ")?$"; // [C]VC[V] is m=1 + var mgr1 = "^(" + C + ")?" + V + C + V + C; // [C]VCVC... is m>1 + var s_v = "^(" + C + ")?" + v; // vowel in stem + + this.stemWord = function (w) { + var stem; + var suffix; + var firstch; + var origword = w; + + if (w.length < 3) + return w; + + var re; + var re2; + var re3; + var re4; + + firstch = w.substr(0,1); + if (firstch == "y") + w = firstch.toUpperCase() + w.substr(1); + + // Step 1a + re = /^(.+?)(ss|i)es$/; + re2 = /^(.+?)([^s])s$/; + + if (re.test(w)) + w = w.replace(re,"$1$2"); + else if (re2.test(w)) + w = w.replace(re2,"$1$2"); + + // Step 1b + re = /^(.+?)eed$/; + re2 = /^(.+?)(ed|ing)$/; + if (re.test(w)) { + var fp = re.exec(w); + re = new RegExp(mgr0); + if (re.test(fp[1])) { + re = /.$/; + w = w.replace(re,""); + } + } + else if (re2.test(w)) { + var fp = re2.exec(w); + stem = fp[1]; + re2 = new RegExp(s_v); + if (re2.test(stem)) { + w = stem; + re2 = /(at|bl|iz)$/; + re3 = new RegExp("([^aeiouylsz])\\1$"); + re4 = new RegExp("^" + C + v + "[^aeiouwxy]$"); + if (re2.test(w)) + w = w + "e"; + else if (re3.test(w)) { + re = /.$/; + w = w.replace(re,""); + } + else if (re4.test(w)) + w = w + "e"; + } + } + + // Step 1c + re = /^(.+?)y$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(s_v); + if (re.test(stem)) + w = stem + "i"; + } + + // Step 2 + re = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + suffix = fp[2]; + re = new RegExp(mgr0); + if (re.test(stem)) + w = stem + step2list[suffix]; + } + + // Step 3 + re = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + suffix = fp[2]; + re = new RegExp(mgr0); + if (re.test(stem)) + w = stem + step3list[suffix]; + } + + // Step 4 + re = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/; + re2 = /^(.+?)(s|t)(ion)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(mgr1); + if (re.test(stem)) + w = stem; + } + else if (re2.test(w)) { + var fp = re2.exec(w); + stem = fp[1] + fp[2]; + re2 = new RegExp(mgr1); + if (re2.test(stem)) + w = stem; + } + + // Step 5 + re = /^(.+?)e$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(mgr1); + re2 = new RegExp(meq1); + re3 = new RegExp("^" + C + v + "[^aeiouwxy]$"); + if (re.test(stem) || (re2.test(stem) && !(re3.test(stem)))) + w = stem; + } + re = /ll$/; + re2 = new RegExp(mgr1); + if (re.test(w) && re2.test(w)) { + re = /.$/; + w = w.replace(re,""); + } + + // and turn initial Y back to y + if (firstch == "y") + w = firstch.toLowerCase() + w.substr(1); + return w; + } +} + diff --git a/v0.10.x/_static/logo.ico b/v0.10.x/_static/logo.ico new file mode 100644 index 000000000..29aa62945 Binary files /dev/null and b/v0.10.x/_static/logo.ico differ diff --git a/v0.10.x/_static/logo.svg b/v0.10.x/_static/logo.svg new file mode 100644 index 000000000..1bf58639e --- /dev/null +++ b/v0.10.x/_static/logo.svg @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/v0.10.x/_static/minus.png b/v0.10.x/_static/minus.png new file mode 100644 index 000000000..d96755fda Binary files /dev/null and b/v0.10.x/_static/minus.png differ diff --git a/v0.10.x/_static/no_image.png b/v0.10.x/_static/no_image.png new file mode 100644 index 000000000..8c2d48d5d Binary files /dev/null and b/v0.10.x/_static/no_image.png differ diff --git a/v0.10.x/_static/plot_directive.css b/v0.10.x/_static/plot_directive.css new file mode 100644 index 000000000..d45593c93 --- /dev/null +++ b/v0.10.x/_static/plot_directive.css @@ -0,0 +1,16 @@ +/* + * plot_directive.css + * ~~~~~~~~~~~~ + * + * Stylesheet controlling images created using the `plot` directive within + * Sphinx. + * + * :copyright: Copyright 2020-* by the Matplotlib development team. + * :license: Matplotlib, see LICENSE for details. + * + */ + +img.plot-directive { + border: 0; + max-width: 100%; +} diff --git a/v0.10.x/_static/plus.png b/v0.10.x/_static/plus.png new file mode 100644 index 000000000..7107cec93 Binary files /dev/null and b/v0.10.x/_static/plus.png differ diff --git a/v0.10.x/_static/pygments.css b/v0.10.x/_static/pygments.css new file mode 100644 index 000000000..d92c4cddd --- /dev/null +++ b/v0.10.x/_static/pygments.css @@ -0,0 +1,169 @@ +html[data-theme="light"] .highlight pre { line-height: 125%; } +html[data-theme="light"] .highlight td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } +html[data-theme="light"] .highlight span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } +html[data-theme="light"] .highlight td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +html[data-theme="light"] .highlight span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +html[data-theme="light"] .highlight .hll { background-color: #ffffcc } +html[data-theme="light"] .highlight { background: #f8f8f8; } +html[data-theme="light"] .highlight .c { color: #8f5902; font-style: italic } /* Comment */ +html[data-theme="light"] .highlight .err { color: #a40000; border: 1px solid #ef2929 } /* Error */ +html[data-theme="light"] .highlight .g { color: #000000 } /* Generic */ +html[data-theme="light"] .highlight .k { color: #204a87; font-weight: bold } /* Keyword */ +html[data-theme="light"] .highlight .l { color: #000000 } /* Literal */ +html[data-theme="light"] .highlight .n { color: #000000 } /* Name */ +html[data-theme="light"] .highlight .o { color: #ce5c00; font-weight: bold } /* Operator */ +html[data-theme="light"] .highlight .x { color: #000000 } /* Other */ +html[data-theme="light"] .highlight .p { color: #000000; font-weight: bold } /* Punctuation */ +html[data-theme="light"] .highlight .ch { color: #8f5902; font-style: italic } /* Comment.Hashbang */ +html[data-theme="light"] .highlight .cm { color: #8f5902; font-style: italic } /* Comment.Multiline */ +html[data-theme="light"] .highlight .cp { color: #8f5902; font-style: italic } /* Comment.Preproc */ +html[data-theme="light"] .highlight .cpf { color: #8f5902; font-style: italic } /* Comment.PreprocFile */ +html[data-theme="light"] .highlight .c1 { color: #8f5902; font-style: italic } /* Comment.Single */ +html[data-theme="light"] .highlight .cs { color: #8f5902; font-style: italic } /* Comment.Special */ +html[data-theme="light"] .highlight .gd { color: #a40000 } /* Generic.Deleted */ +html[data-theme="light"] .highlight .ge { color: #000000; font-style: italic } /* Generic.Emph */ +html[data-theme="light"] .highlight .ges { color: #000000; font-weight: bold; font-style: italic } /* Generic.EmphStrong */ +html[data-theme="light"] .highlight .gr { color: #ef2929 } /* Generic.Error */ +html[data-theme="light"] .highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */ +html[data-theme="light"] .highlight .gi { color: #00A000 } /* Generic.Inserted */ +html[data-theme="light"] .highlight .go { color: #000000; font-style: italic } /* Generic.Output */ +html[data-theme="light"] .highlight .gp { color: #8f5902 } /* Generic.Prompt */ +html[data-theme="light"] .highlight .gs { color: #000000; font-weight: bold } /* Generic.Strong */ +html[data-theme="light"] .highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ +html[data-theme="light"] .highlight .gt { color: #a40000; font-weight: bold } /* Generic.Traceback */ +html[data-theme="light"] .highlight .kc { color: #204a87; font-weight: bold } /* Keyword.Constant */ +html[data-theme="light"] .highlight .kd { color: #204a87; font-weight: bold } /* Keyword.Declaration */ +html[data-theme="light"] .highlight .kn { color: #204a87; font-weight: bold } /* Keyword.Namespace */ +html[data-theme="light"] .highlight .kp { color: #204a87; font-weight: bold } /* Keyword.Pseudo */ +html[data-theme="light"] .highlight .kr { color: #204a87; font-weight: bold } /* Keyword.Reserved */ +html[data-theme="light"] .highlight .kt { color: #204a87; font-weight: bold } /* Keyword.Type */ +html[data-theme="light"] .highlight .ld { color: #000000 } /* Literal.Date */ +html[data-theme="light"] .highlight .m { color: #0000cf; font-weight: bold } /* Literal.Number */ +html[data-theme="light"] .highlight .s { color: #4e9a06 } /* Literal.String */ +html[data-theme="light"] .highlight .na { color: #c4a000 } /* Name.Attribute */ +html[data-theme="light"] .highlight .nb { color: #204a87 } /* Name.Builtin */ +html[data-theme="light"] .highlight .nc { color: #000000 } /* Name.Class */ +html[data-theme="light"] .highlight .no { color: #000000 } /* Name.Constant */ +html[data-theme="light"] .highlight .nd { color: #5c35cc; font-weight: bold } /* Name.Decorator */ +html[data-theme="light"] .highlight .ni { color: #ce5c00 } /* Name.Entity */ +html[data-theme="light"] .highlight .ne { color: #cc0000; font-weight: bold } /* Name.Exception */ +html[data-theme="light"] .highlight .nf { color: #000000 } /* Name.Function */ +html[data-theme="light"] .highlight .nl { color: #f57900 } /* Name.Label */ +html[data-theme="light"] .highlight .nn { color: #000000 } /* Name.Namespace */ +html[data-theme="light"] .highlight .nx { color: #000000 } /* Name.Other */ +html[data-theme="light"] .highlight .py { color: #000000 } /* Name.Property */ +html[data-theme="light"] .highlight .nt { color: #204a87; font-weight: bold } /* Name.Tag */ +html[data-theme="light"] .highlight .nv { color: #000000 } /* Name.Variable */ +html[data-theme="light"] .highlight .ow { color: #204a87; font-weight: bold } /* Operator.Word */ +html[data-theme="light"] .highlight .pm { color: #000000; font-weight: bold } /* Punctuation.Marker */ +html[data-theme="light"] .highlight .w { color: #f8f8f8 } /* Text.Whitespace */ +html[data-theme="light"] .highlight .mb { color: #0000cf; font-weight: bold } /* Literal.Number.Bin */ +html[data-theme="light"] .highlight .mf { color: #0000cf; font-weight: bold } /* Literal.Number.Float */ +html[data-theme="light"] .highlight .mh { color: #0000cf; font-weight: bold } /* Literal.Number.Hex */ +html[data-theme="light"] .highlight .mi { color: #0000cf; font-weight: bold } /* Literal.Number.Integer */ +html[data-theme="light"] .highlight .mo { color: #0000cf; font-weight: bold } /* Literal.Number.Oct */ +html[data-theme="light"] .highlight .sa { color: #4e9a06 } /* Literal.String.Affix */ +html[data-theme="light"] .highlight .sb { color: #4e9a06 } /* Literal.String.Backtick */ +html[data-theme="light"] .highlight .sc { color: #4e9a06 } /* Literal.String.Char */ +html[data-theme="light"] .highlight .dl { color: #4e9a06 } /* Literal.String.Delimiter */ +html[data-theme="light"] .highlight .sd { color: #8f5902; font-style: italic } /* Literal.String.Doc */ +html[data-theme="light"] .highlight .s2 { color: #4e9a06 } /* Literal.String.Double */ +html[data-theme="light"] .highlight .se { color: #4e9a06 } /* Literal.String.Escape */ +html[data-theme="light"] .highlight .sh { color: #4e9a06 } /* Literal.String.Heredoc */ +html[data-theme="light"] .highlight .si { color: #4e9a06 } /* Literal.String.Interpol */ +html[data-theme="light"] .highlight .sx { color: #4e9a06 } /* Literal.String.Other */ +html[data-theme="light"] .highlight .sr { color: #4e9a06 } /* Literal.String.Regex */ +html[data-theme="light"] .highlight .s1 { color: #4e9a06 } /* Literal.String.Single */ +html[data-theme="light"] .highlight .ss { color: #4e9a06 } /* Literal.String.Symbol */ +html[data-theme="light"] .highlight .bp { color: #3465a4 } /* Name.Builtin.Pseudo */ +html[data-theme="light"] .highlight .fm { color: #000000 } /* Name.Function.Magic */ +html[data-theme="light"] .highlight .vc { color: #000000 } /* Name.Variable.Class */ +html[data-theme="light"] .highlight .vg { color: #000000 } /* Name.Variable.Global */ +html[data-theme="light"] .highlight .vi { color: #000000 } /* Name.Variable.Instance */ +html[data-theme="light"] .highlight .vm { color: #000000 } /* Name.Variable.Magic */ +html[data-theme="light"] .highlight .il { color: #0000cf; font-weight: bold } /* Literal.Number.Integer.Long */ +html[data-theme="dark"] .highlight pre { line-height: 125%; } +html[data-theme="dark"] .highlight td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } +html[data-theme="dark"] .highlight span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } +html[data-theme="dark"] .highlight td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +html[data-theme="dark"] .highlight span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +html[data-theme="dark"] .highlight .hll { background-color: #49483e } +html[data-theme="dark"] .highlight { background: #272822; color: #f8f8f2 } +html[data-theme="dark"] .highlight .c { color: #959077 } /* Comment */ +html[data-theme="dark"] .highlight .err { color: #ed007e; background-color: #1e0010 } /* Error */ +html[data-theme="dark"] .highlight .esc { color: #f8f8f2 } /* Escape */ +html[data-theme="dark"] .highlight .g { color: #f8f8f2 } /* Generic */ +html[data-theme="dark"] .highlight .k { color: #66d9ef } /* Keyword */ +html[data-theme="dark"] .highlight .l { color: #ae81ff } /* Literal */ +html[data-theme="dark"] .highlight .n { color: #f8f8f2 } /* Name */ +html[data-theme="dark"] .highlight .o { color: #ff4689 } /* Operator */ +html[data-theme="dark"] .highlight .x { color: #f8f8f2 } /* Other */ +html[data-theme="dark"] .highlight .p { color: #f8f8f2 } /* Punctuation */ +html[data-theme="dark"] .highlight .ch { color: #959077 } /* Comment.Hashbang */ +html[data-theme="dark"] .highlight .cm { color: #959077 } /* Comment.Multiline */ +html[data-theme="dark"] .highlight .cp { color: #959077 } /* Comment.Preproc */ +html[data-theme="dark"] .highlight .cpf { color: #959077 } /* Comment.PreprocFile */ +html[data-theme="dark"] .highlight .c1 { color: #959077 } /* Comment.Single */ +html[data-theme="dark"] .highlight .cs { color: #959077 } /* Comment.Special */ +html[data-theme="dark"] .highlight .gd { color: #ff4689 } /* Generic.Deleted */ +html[data-theme="dark"] .highlight .ge { color: #f8f8f2; font-style: italic } /* Generic.Emph */ +html[data-theme="dark"] .highlight .ges { color: #f8f8f2; font-weight: bold; font-style: italic } /* Generic.EmphStrong */ +html[data-theme="dark"] .highlight .gr { color: #f8f8f2 } /* Generic.Error */ +html[data-theme="dark"] .highlight .gh { color: #f8f8f2 } /* Generic.Heading */ +html[data-theme="dark"] .highlight .gi { color: #a6e22e } /* Generic.Inserted */ +html[data-theme="dark"] .highlight .go { color: #66d9ef } /* Generic.Output */ +html[data-theme="dark"] .highlight .gp { color: #ff4689; font-weight: bold } /* Generic.Prompt */ +html[data-theme="dark"] .highlight .gs { color: #f8f8f2; font-weight: bold } /* Generic.Strong */ +html[data-theme="dark"] .highlight .gu { color: #959077 } /* Generic.Subheading */ +html[data-theme="dark"] .highlight .gt { color: #f8f8f2 } /* Generic.Traceback */ +html[data-theme="dark"] .highlight .kc { color: #66d9ef } /* Keyword.Constant */ +html[data-theme="dark"] .highlight .kd { color: #66d9ef } /* Keyword.Declaration */ +html[data-theme="dark"] .highlight .kn { color: #ff4689 } /* Keyword.Namespace */ +html[data-theme="dark"] .highlight .kp { color: #66d9ef } /* Keyword.Pseudo */ +html[data-theme="dark"] .highlight .kr { color: #66d9ef } /* Keyword.Reserved */ +html[data-theme="dark"] .highlight .kt { color: #66d9ef } /* Keyword.Type */ +html[data-theme="dark"] .highlight .ld { color: #e6db74 } /* Literal.Date */ +html[data-theme="dark"] .highlight .m { color: #ae81ff } /* Literal.Number */ +html[data-theme="dark"] .highlight .s { color: #e6db74 } /* Literal.String */ +html[data-theme="dark"] .highlight .na { color: #a6e22e } /* Name.Attribute */ +html[data-theme="dark"] .highlight .nb { color: #f8f8f2 } /* Name.Builtin */ +html[data-theme="dark"] .highlight .nc { color: #a6e22e } /* Name.Class */ +html[data-theme="dark"] .highlight .no { color: #66d9ef } /* Name.Constant */ +html[data-theme="dark"] .highlight .nd { color: #a6e22e } /* Name.Decorator */ +html[data-theme="dark"] .highlight .ni { color: #f8f8f2 } /* Name.Entity */ +html[data-theme="dark"] .highlight .ne { color: #a6e22e } /* Name.Exception */ +html[data-theme="dark"] .highlight .nf { color: #a6e22e } /* Name.Function */ +html[data-theme="dark"] .highlight .nl { color: #f8f8f2 } /* Name.Label */ +html[data-theme="dark"] .highlight .nn { color: #f8f8f2 } /* Name.Namespace */ +html[data-theme="dark"] .highlight .nx { color: #a6e22e } /* Name.Other */ +html[data-theme="dark"] .highlight .py { color: #f8f8f2 } /* Name.Property */ +html[data-theme="dark"] .highlight .nt { color: #ff4689 } /* Name.Tag */ +html[data-theme="dark"] .highlight .nv { color: #f8f8f2 } /* Name.Variable */ +html[data-theme="dark"] .highlight .ow { color: #ff4689 } /* Operator.Word */ +html[data-theme="dark"] .highlight .pm { color: #f8f8f2 } /* Punctuation.Marker */ +html[data-theme="dark"] .highlight .w { color: #f8f8f2 } /* Text.Whitespace */ +html[data-theme="dark"] .highlight .mb { color: #ae81ff } /* Literal.Number.Bin */ +html[data-theme="dark"] .highlight .mf { color: #ae81ff } /* Literal.Number.Float */ +html[data-theme="dark"] .highlight .mh { color: #ae81ff } /* Literal.Number.Hex */ +html[data-theme="dark"] .highlight .mi { color: #ae81ff } /* Literal.Number.Integer */ +html[data-theme="dark"] .highlight .mo { color: #ae81ff } /* Literal.Number.Oct */ +html[data-theme="dark"] .highlight .sa { color: #e6db74 } /* Literal.String.Affix */ +html[data-theme="dark"] .highlight .sb { color: #e6db74 } /* Literal.String.Backtick */ +html[data-theme="dark"] .highlight .sc { color: #e6db74 } /* Literal.String.Char */ +html[data-theme="dark"] .highlight .dl { color: #e6db74 } /* Literal.String.Delimiter */ +html[data-theme="dark"] .highlight .sd { color: #e6db74 } /* Literal.String.Doc */ +html[data-theme="dark"] .highlight .s2 { color: #e6db74 } /* Literal.String.Double */ +html[data-theme="dark"] .highlight .se { color: #ae81ff } /* Literal.String.Escape */ +html[data-theme="dark"] .highlight .sh { color: #e6db74 } /* Literal.String.Heredoc */ +html[data-theme="dark"] .highlight .si { color: #e6db74 } /* Literal.String.Interpol */ +html[data-theme="dark"] .highlight .sx { color: #e6db74 } /* Literal.String.Other */ +html[data-theme="dark"] .highlight .sr { color: #e6db74 } /* Literal.String.Regex */ +html[data-theme="dark"] .highlight .s1 { color: #e6db74 } /* Literal.String.Single */ +html[data-theme="dark"] .highlight .ss { color: #e6db74 } /* Literal.String.Symbol */ +html[data-theme="dark"] .highlight .bp { color: #f8f8f2 } /* Name.Builtin.Pseudo */ +html[data-theme="dark"] .highlight .fm { color: #a6e22e } /* Name.Function.Magic */ +html[data-theme="dark"] .highlight .vc { color: #f8f8f2 } /* Name.Variable.Class */ +html[data-theme="dark"] .highlight .vg { color: #f8f8f2 } /* Name.Variable.Global */ +html[data-theme="dark"] .highlight .vi { color: #f8f8f2 } /* Name.Variable.Instance */ +html[data-theme="dark"] .highlight .vm { color: #f8f8f2 } /* Name.Variable.Magic */ +html[data-theme="dark"] .highlight .il { color: #ae81ff } /* Literal.Number.Integer.Long */ \ No newline at end of file diff --git a/v0.10.x/_static/scripts/bootstrap.js b/v0.10.x/_static/scripts/bootstrap.js new file mode 100644 index 000000000..4ec783e71 --- /dev/null +++ b/v0.10.x/_static/scripts/bootstrap.js @@ -0,0 +1,32 @@ +!function(t){var e={};function n(i){if(e[i])return e[i].exports;var o=e[i]={i:i,l:!1,exports:{}};return t[i].call(o.exports,o,o.exports,n),o.l=!0,o.exports}n.m=t,n.c=e,n.d=function(t,e,i){n.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:i})},n.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},n.t=function(t,e){if(1&e&&(t=n(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var i=Object.create(null);if(n.r(i),Object.defineProperty(i,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var o in t)n.d(i,o,function(e){return t[e]}.bind(null,o));return i},n.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return n.d(e,"a",e),e},n.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},n.p="",n(n.s=5)}([function(t,e){t.exports=jQuery},function(t,e,n){"use strict";n.r(e),function(t){ +/**! + * @fileOverview Kickass library to create and place poppers near their reference elements. + * @version 1.16.1 + * @license + * Copyright (c) 2016 Federico Zivolo and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +var n="undefined"!=typeof window&&"undefined"!=typeof document&&"undefined"!=typeof navigator,i=function(){for(var t=["Edge","Trident","Firefox"],e=0;e=0)return 1;return 0}();var o=n&&window.Promise?function(t){var e=!1;return function(){e||(e=!0,window.Promise.resolve().then((function(){e=!1,t()})))}}:function(t){var e=!1;return function(){e||(e=!0,setTimeout((function(){e=!1,t()}),i))}};function r(t){return t&&"[object Function]"==={}.toString.call(t)}function a(t,e){if(1!==t.nodeType)return[];var n=t.ownerDocument.defaultView.getComputedStyle(t,null);return e?n[e]:n}function s(t){return"HTML"===t.nodeName?t:t.parentNode||t.host}function l(t){if(!t)return document.body;switch(t.nodeName){case"HTML":case"BODY":return t.ownerDocument.body;case"#document":return t.body}var e=a(t),n=e.overflow,i=e.overflowX,o=e.overflowY;return/(auto|scroll|overlay)/.test(n+o+i)?t:l(s(t))}function u(t){return t&&t.referenceNode?t.referenceNode:t}var f=n&&!(!window.MSInputMethodContext||!document.documentMode),d=n&&/MSIE 10/.test(navigator.userAgent);function c(t){return 11===t?f:10===t?d:f||d}function h(t){if(!t)return document.documentElement;for(var e=c(10)?document.body:null,n=t.offsetParent||null;n===e&&t.nextElementSibling;)n=(t=t.nextElementSibling).offsetParent;var i=n&&n.nodeName;return i&&"BODY"!==i&&"HTML"!==i?-1!==["TH","TD","TABLE"].indexOf(n.nodeName)&&"static"===a(n,"position")?h(n):n:t?t.ownerDocument.documentElement:document.documentElement}function p(t){return null!==t.parentNode?p(t.parentNode):t}function m(t,e){if(!(t&&t.nodeType&&e&&e.nodeType))return document.documentElement;var n=t.compareDocumentPosition(e)&Node.DOCUMENT_POSITION_FOLLOWING,i=n?t:e,o=n?e:t,r=document.createRange();r.setStart(i,0),r.setEnd(o,0);var a,s,l=r.commonAncestorContainer;if(t!==l&&e!==l||i.contains(o))return"BODY"===(s=(a=l).nodeName)||"HTML"!==s&&h(a.firstElementChild)!==a?h(l):l;var u=p(t);return u.host?m(u.host,e):m(t,p(e).host)}function g(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"top",n="top"===e?"scrollTop":"scrollLeft",i=t.nodeName;if("BODY"===i||"HTML"===i){var o=t.ownerDocument.documentElement,r=t.ownerDocument.scrollingElement||o;return r[n]}return t[n]}function v(t,e){var n=arguments.length>2&&void 0!==arguments[2]&&arguments[2],i=g(e,"top"),o=g(e,"left"),r=n?-1:1;return t.top+=i*r,t.bottom+=i*r,t.left+=o*r,t.right+=o*r,t}function _(t,e){var n="x"===e?"Left":"Top",i="Left"===n?"Right":"Bottom";return parseFloat(t["border"+n+"Width"])+parseFloat(t["border"+i+"Width"])}function b(t,e,n,i){return Math.max(e["offset"+t],e["scroll"+t],n["client"+t],n["offset"+t],n["scroll"+t],c(10)?parseInt(n["offset"+t])+parseInt(i["margin"+("Height"===t?"Top":"Left")])+parseInt(i["margin"+("Height"===t?"Bottom":"Right")]):0)}function y(t){var e=t.body,n=t.documentElement,i=c(10)&&getComputedStyle(n);return{height:b("Height",e,n,i),width:b("Width",e,n,i)}}var w=function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")},E=function(){function t(t,e){for(var n=0;n2&&void 0!==arguments[2]&&arguments[2],i=c(10),o="HTML"===e.nodeName,r=N(t),s=N(e),u=l(t),f=a(e),d=parseFloat(f.borderTopWidth),h=parseFloat(f.borderLeftWidth);n&&o&&(s.top=Math.max(s.top,0),s.left=Math.max(s.left,0));var p=S({top:r.top-s.top-d,left:r.left-s.left-h,width:r.width,height:r.height});if(p.marginTop=0,p.marginLeft=0,!i&&o){var m=parseFloat(f.marginTop),g=parseFloat(f.marginLeft);p.top-=d-m,p.bottom-=d-m,p.left-=h-g,p.right-=h-g,p.marginTop=m,p.marginLeft=g}return(i&&!n?e.contains(u):e===u&&"BODY"!==u.nodeName)&&(p=v(p,e)),p}function k(t){var e=arguments.length>1&&void 0!==arguments[1]&&arguments[1],n=t.ownerDocument.documentElement,i=D(t,n),o=Math.max(n.clientWidth,window.innerWidth||0),r=Math.max(n.clientHeight,window.innerHeight||0),a=e?0:g(n),s=e?0:g(n,"left"),l={top:a-i.top+i.marginTop,left:s-i.left+i.marginLeft,width:o,height:r};return S(l)}function A(t){var e=t.nodeName;if("BODY"===e||"HTML"===e)return!1;if("fixed"===a(t,"position"))return!0;var n=s(t);return!!n&&A(n)}function O(t){if(!t||!t.parentElement||c())return document.documentElement;for(var e=t.parentElement;e&&"none"===a(e,"transform");)e=e.parentElement;return e||document.documentElement}function I(t,e,n,i){var o=arguments.length>4&&void 0!==arguments[4]&&arguments[4],r={top:0,left:0},a=o?O(t):m(t,u(e));if("viewport"===i)r=k(a,o);else{var f=void 0;"scrollParent"===i?"BODY"===(f=l(s(e))).nodeName&&(f=t.ownerDocument.documentElement):f="window"===i?t.ownerDocument.documentElement:i;var d=D(f,a,o);if("HTML"!==f.nodeName||A(a))r=d;else{var c=y(t.ownerDocument),h=c.height,p=c.width;r.top+=d.top-d.marginTop,r.bottom=h+d.top,r.left+=d.left-d.marginLeft,r.right=p+d.left}}var g="number"==typeof(n=n||0);return r.left+=g?n:n.left||0,r.top+=g?n:n.top||0,r.right-=g?n:n.right||0,r.bottom-=g?n:n.bottom||0,r}function x(t){return t.width*t.height}function j(t,e,n,i,o){var r=arguments.length>5&&void 0!==arguments[5]?arguments[5]:0;if(-1===t.indexOf("auto"))return t;var a=I(n,i,r,o),s={top:{width:a.width,height:e.top-a.top},right:{width:a.right-e.right,height:a.height},bottom:{width:a.width,height:a.bottom-e.bottom},left:{width:e.left-a.left,height:a.height}},l=Object.keys(s).map((function(t){return C({key:t},s[t],{area:x(s[t])})})).sort((function(t,e){return e.area-t.area})),u=l.filter((function(t){var e=t.width,i=t.height;return e>=n.clientWidth&&i>=n.clientHeight})),f=u.length>0?u[0].key:l[0].key,d=t.split("-")[1];return f+(d?"-"+d:"")}function L(t,e,n){var i=arguments.length>3&&void 0!==arguments[3]?arguments[3]:null,o=i?O(e):m(e,u(n));return D(n,o,i)}function P(t){var e=t.ownerDocument.defaultView.getComputedStyle(t),n=parseFloat(e.marginTop||0)+parseFloat(e.marginBottom||0),i=parseFloat(e.marginLeft||0)+parseFloat(e.marginRight||0);return{width:t.offsetWidth+i,height:t.offsetHeight+n}}function F(t){var e={left:"right",right:"left",bottom:"top",top:"bottom"};return t.replace(/left|right|bottom|top/g,(function(t){return e[t]}))}function R(t,e,n){n=n.split("-")[0];var i=P(t),o={width:i.width,height:i.height},r=-1!==["right","left"].indexOf(n),a=r?"top":"left",s=r?"left":"top",l=r?"height":"width",u=r?"width":"height";return o[a]=e[a]+e[l]/2-i[l]/2,o[s]=n===s?e[s]-i[u]:e[F(s)],o}function M(t,e){return Array.prototype.find?t.find(e):t.filter(e)[0]}function H(t,e,n){return(void 0===n?t:t.slice(0,function(t,e,n){if(Array.prototype.findIndex)return t.findIndex((function(t){return t[e]===n}));var i=M(t,(function(t){return t[e]===n}));return t.indexOf(i)}(t,"name",n))).forEach((function(t){t.function&&console.warn("`modifier.function` is deprecated, use `modifier.fn`!");var n=t.function||t.fn;t.enabled&&r(n)&&(e.offsets.popper=S(e.offsets.popper),e.offsets.reference=S(e.offsets.reference),e=n(e,t))})),e}function B(){if(!this.state.isDestroyed){var t={instance:this,styles:{},arrowStyles:{},attributes:{},flipped:!1,offsets:{}};t.offsets.reference=L(this.state,this.popper,this.reference,this.options.positionFixed),t.placement=j(this.options.placement,t.offsets.reference,this.popper,this.reference,this.options.modifiers.flip.boundariesElement,this.options.modifiers.flip.padding),t.originalPlacement=t.placement,t.positionFixed=this.options.positionFixed,t.offsets.popper=R(this.popper,t.offsets.reference,t.placement),t.offsets.popper.position=this.options.positionFixed?"fixed":"absolute",t=H(this.modifiers,t),this.state.isCreated?this.options.onUpdate(t):(this.state.isCreated=!0,this.options.onCreate(t))}}function q(t,e){return t.some((function(t){var n=t.name;return t.enabled&&n===e}))}function Q(t){for(var e=[!1,"ms","Webkit","Moz","O"],n=t.charAt(0).toUpperCase()+t.slice(1),i=0;i1&&void 0!==arguments[1]&&arguments[1],n=Z.indexOf(t),i=Z.slice(n+1).concat(Z.slice(0,n));return e?i.reverse():i}var et="flip",nt="clockwise",it="counterclockwise";function ot(t,e,n,i){var o=[0,0],r=-1!==["right","left"].indexOf(i),a=t.split(/(\+|\-)/).map((function(t){return t.trim()})),s=a.indexOf(M(a,(function(t){return-1!==t.search(/,|\s/)})));a[s]&&-1===a[s].indexOf(",")&&console.warn("Offsets separated by white space(s) are deprecated, use a comma (,) instead.");var l=/\s*,\s*|\s+/,u=-1!==s?[a.slice(0,s).concat([a[s].split(l)[0]]),[a[s].split(l)[1]].concat(a.slice(s+1))]:[a];return(u=u.map((function(t,i){var o=(1===i?!r:r)?"height":"width",a=!1;return t.reduce((function(t,e){return""===t[t.length-1]&&-1!==["+","-"].indexOf(e)?(t[t.length-1]=e,a=!0,t):a?(t[t.length-1]+=e,a=!1,t):t.concat(e)}),[]).map((function(t){return function(t,e,n,i){var o=t.match(/((?:\-|\+)?\d*\.?\d*)(.*)/),r=+o[1],a=o[2];if(!r)return t;if(0===a.indexOf("%")){var s=void 0;switch(a){case"%p":s=n;break;case"%":case"%r":default:s=i}return S(s)[e]/100*r}if("vh"===a||"vw"===a){return("vh"===a?Math.max(document.documentElement.clientHeight,window.innerHeight||0):Math.max(document.documentElement.clientWidth,window.innerWidth||0))/100*r}return r}(t,o,e,n)}))}))).forEach((function(t,e){t.forEach((function(n,i){K(n)&&(o[e]+=n*("-"===t[i-1]?-1:1))}))})),o}var rt={placement:"bottom",positionFixed:!1,eventsEnabled:!0,removeOnDestroy:!1,onCreate:function(){},onUpdate:function(){},modifiers:{shift:{order:100,enabled:!0,fn:function(t){var e=t.placement,n=e.split("-")[0],i=e.split("-")[1];if(i){var o=t.offsets,r=o.reference,a=o.popper,s=-1!==["bottom","top"].indexOf(n),l=s?"left":"top",u=s?"width":"height",f={start:T({},l,r[l]),end:T({},l,r[l]+r[u]-a[u])};t.offsets.popper=C({},a,f[i])}return t}},offset:{order:200,enabled:!0,fn:function(t,e){var n=e.offset,i=t.placement,o=t.offsets,r=o.popper,a=o.reference,s=i.split("-")[0],l=void 0;return l=K(+n)?[+n,0]:ot(n,r,a,s),"left"===s?(r.top+=l[0],r.left-=l[1]):"right"===s?(r.top+=l[0],r.left+=l[1]):"top"===s?(r.left+=l[0],r.top-=l[1]):"bottom"===s&&(r.left+=l[0],r.top+=l[1]),t.popper=r,t},offset:0},preventOverflow:{order:300,enabled:!0,fn:function(t,e){var n=e.boundariesElement||h(t.instance.popper);t.instance.reference===n&&(n=h(n));var i=Q("transform"),o=t.instance.popper.style,r=o.top,a=o.left,s=o[i];o.top="",o.left="",o[i]="";var l=I(t.instance.popper,t.instance.reference,e.padding,n,t.positionFixed);o.top=r,o.left=a,o[i]=s,e.boundaries=l;var u=e.priority,f=t.offsets.popper,d={primary:function(t){var n=f[t];return f[t]l[t]&&!e.escapeWithReference&&(i=Math.min(f[n],l[t]-("right"===t?f.width:f.height))),T({},n,i)}};return u.forEach((function(t){var e=-1!==["left","top"].indexOf(t)?"primary":"secondary";f=C({},f,d[e](t))})),t.offsets.popper=f,t},priority:["left","right","top","bottom"],padding:5,boundariesElement:"scrollParent"},keepTogether:{order:400,enabled:!0,fn:function(t){var e=t.offsets,n=e.popper,i=e.reference,o=t.placement.split("-")[0],r=Math.floor,a=-1!==["top","bottom"].indexOf(o),s=a?"right":"bottom",l=a?"left":"top",u=a?"width":"height";return n[s]r(i[s])&&(t.offsets.popper[l]=r(i[s])),t}},arrow:{order:500,enabled:!0,fn:function(t,e){var n;if(!G(t.instance.modifiers,"arrow","keepTogether"))return t;var i=e.element;if("string"==typeof i){if(!(i=t.instance.popper.querySelector(i)))return t}else if(!t.instance.popper.contains(i))return console.warn("WARNING: `arrow.element` must be child of its popper element!"),t;var o=t.placement.split("-")[0],r=t.offsets,s=r.popper,l=r.reference,u=-1!==["left","right"].indexOf(o),f=u?"height":"width",d=u?"Top":"Left",c=d.toLowerCase(),h=u?"left":"top",p=u?"bottom":"right",m=P(i)[f];l[p]-ms[p]&&(t.offsets.popper[c]+=l[c]+m-s[p]),t.offsets.popper=S(t.offsets.popper);var g=l[c]+l[f]/2-m/2,v=a(t.instance.popper),_=parseFloat(v["margin"+d]),b=parseFloat(v["border"+d+"Width"]),y=g-t.offsets.popper[c]-_-b;return y=Math.max(Math.min(s[f]-m,y),0),t.arrowElement=i,t.offsets.arrow=(T(n={},c,Math.round(y)),T(n,h,""),n),t},element:"[x-arrow]"},flip:{order:600,enabled:!0,fn:function(t,e){if(q(t.instance.modifiers,"inner"))return t;if(t.flipped&&t.placement===t.originalPlacement)return t;var n=I(t.instance.popper,t.instance.reference,e.padding,e.boundariesElement,t.positionFixed),i=t.placement.split("-")[0],o=F(i),r=t.placement.split("-")[1]||"",a=[];switch(e.behavior){case et:a=[i,o];break;case nt:a=tt(i);break;case it:a=tt(i,!0);break;default:a=e.behavior}return a.forEach((function(s,l){if(i!==s||a.length===l+1)return t;i=t.placement.split("-")[0],o=F(i);var u=t.offsets.popper,f=t.offsets.reference,d=Math.floor,c="left"===i&&d(u.right)>d(f.left)||"right"===i&&d(u.left)d(f.top)||"bottom"===i&&d(u.top)d(n.right),m=d(u.top)d(n.bottom),v="left"===i&&h||"right"===i&&p||"top"===i&&m||"bottom"===i&&g,_=-1!==["top","bottom"].indexOf(i),b=!!e.flipVariations&&(_&&"start"===r&&h||_&&"end"===r&&p||!_&&"start"===r&&m||!_&&"end"===r&&g),y=!!e.flipVariationsByContent&&(_&&"start"===r&&p||_&&"end"===r&&h||!_&&"start"===r&&g||!_&&"end"===r&&m),w=b||y;(c||v||w)&&(t.flipped=!0,(c||v)&&(i=a[l+1]),w&&(r=function(t){return"end"===t?"start":"start"===t?"end":t}(r)),t.placement=i+(r?"-"+r:""),t.offsets.popper=C({},t.offsets.popper,R(t.instance.popper,t.offsets.reference,t.placement)),t=H(t.instance.modifiers,t,"flip"))})),t},behavior:"flip",padding:5,boundariesElement:"viewport",flipVariations:!1,flipVariationsByContent:!1},inner:{order:700,enabled:!1,fn:function(t){var e=t.placement,n=e.split("-")[0],i=t.offsets,o=i.popper,r=i.reference,a=-1!==["left","right"].indexOf(n),s=-1===["top","left"].indexOf(n);return o[a?"left":"top"]=r[n]-(s?o[a?"width":"height"]:0),t.placement=F(e),t.offsets.popper=S(o),t}},hide:{order:800,enabled:!0,fn:function(t){if(!G(t.instance.modifiers,"hide","preventOverflow"))return t;var e=t.offsets.reference,n=M(t.instance.modifiers,(function(t){return"preventOverflow"===t.name})).boundaries;if(e.bottomn.right||e.top>n.bottom||e.right2&&void 0!==arguments[2]?arguments[2]:{};w(this,t),this.scheduleUpdate=function(){return requestAnimationFrame(i.update)},this.update=o(this.update.bind(this)),this.options=C({},t.Defaults,a),this.state={isDestroyed:!1,isCreated:!1,scrollParents:[]},this.reference=e&&e.jquery?e[0]:e,this.popper=n&&n.jquery?n[0]:n,this.options.modifiers={},Object.keys(C({},t.Defaults.modifiers,a.modifiers)).forEach((function(e){i.options.modifiers[e]=C({},t.Defaults.modifiers[e]||{},a.modifiers?a.modifiers[e]:{})})),this.modifiers=Object.keys(this.options.modifiers).map((function(t){return C({name:t},i.options.modifiers[t])})).sort((function(t,e){return t.order-e.order})),this.modifiers.forEach((function(t){t.enabled&&r(t.onLoad)&&t.onLoad(i.reference,i.popper,i.options,t,i.state)})),this.update();var s=this.options.eventsEnabled;s&&this.enableEventListeners(),this.state.eventsEnabled=s}return E(t,[{key:"update",value:function(){return B.call(this)}},{key:"destroy",value:function(){return W.call(this)}},{key:"enableEventListeners",value:function(){return Y.call(this)}},{key:"disableEventListeners",value:function(){return z.call(this)}}]),t}();at.Utils=("undefined"!=typeof window?window:t).PopperUtils,at.placements=J,at.Defaults=rt,e.default=at}.call(this,n(3))},function(t,e,n){ +/*! + * Bootstrap v4.6.1 (https://getbootstrap.com/) + * Copyright 2011-2021 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors) + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + */ +!function(t,e,n){"use strict";function i(t){return t&&"object"==typeof t&&"default"in t?t:{default:t}}var o=i(e),r=i(n);function a(t,e){for(var n=0;n=4)throw new Error("Bootstrap's JavaScript requires at least jQuery v1.9.1 but less than v4.0.0")}};d.jQueryDetection(),o.default.fn.emulateTransitionEnd=f,o.default.event.special[d.TRANSITION_END]={bindType:"transitionend",delegateType:"transitionend",handle:function(t){if(o.default(t.target).is(this))return t.handleObj.handler.apply(this,arguments)}};var c=o.default.fn.alert,h=function(){function t(t){this._element=t}var e=t.prototype;return e.close=function(t){var e=this._element;t&&(e=this._getRootElement(t)),this._triggerCloseEvent(e).isDefaultPrevented()||this._removeElement(e)},e.dispose=function(){o.default.removeData(this._element,"bs.alert"),this._element=null},e._getRootElement=function(t){var e=d.getSelectorFromElement(t),n=!1;return e&&(n=document.querySelector(e)),n||(n=o.default(t).closest(".alert")[0]),n},e._triggerCloseEvent=function(t){var e=o.default.Event("close.bs.alert");return o.default(t).trigger(e),e},e._removeElement=function(t){var e=this;if(o.default(t).removeClass("show"),o.default(t).hasClass("fade")){var n=d.getTransitionDurationFromElement(t);o.default(t).one(d.TRANSITION_END,(function(n){return e._destroyElement(t,n)})).emulateTransitionEnd(n)}else this._destroyElement(t)},e._destroyElement=function(t){o.default(t).detach().trigger("closed.bs.alert").remove()},t._jQueryInterface=function(e){return this.each((function(){var n=o.default(this),i=n.data("bs.alert");i||(i=new t(this),n.data("bs.alert",i)),"close"===e&&i[e](this)}))},t._handleDismiss=function(t){return function(e){e&&e.preventDefault(),t.close(this)}},s(t,null,[{key:"VERSION",get:function(){return"4.6.1"}}]),t}();o.default(document).on("click.bs.alert.data-api",'[data-dismiss="alert"]',h._handleDismiss(new h)),o.default.fn.alert=h._jQueryInterface,o.default.fn.alert.Constructor=h,o.default.fn.alert.noConflict=function(){return o.default.fn.alert=c,h._jQueryInterface};var p=o.default.fn.button,m=function(){function t(t){this._element=t,this.shouldAvoidTriggerChange=!1}var e=t.prototype;return e.toggle=function(){var t=!0,e=!0,n=o.default(this._element).closest('[data-toggle="buttons"]')[0];if(n){var i=this._element.querySelector('input:not([type="hidden"])');if(i){if("radio"===i.type)if(i.checked&&this._element.classList.contains("active"))t=!1;else{var r=n.querySelector(".active");r&&o.default(r).removeClass("active")}t&&("checkbox"!==i.type&&"radio"!==i.type||(i.checked=!this._element.classList.contains("active")),this.shouldAvoidTriggerChange||o.default(i).trigger("change")),i.focus(),e=!1}}this._element.hasAttribute("disabled")||this._element.classList.contains("disabled")||(e&&this._element.setAttribute("aria-pressed",!this._element.classList.contains("active")),t&&o.default(this._element).toggleClass("active"))},e.dispose=function(){o.default.removeData(this._element,"bs.button"),this._element=null},t._jQueryInterface=function(e,n){return this.each((function(){var i=o.default(this),r=i.data("bs.button");r||(r=new t(this),i.data("bs.button",r)),r.shouldAvoidTriggerChange=n,"toggle"===e&&r[e]()}))},s(t,null,[{key:"VERSION",get:function(){return"4.6.1"}}]),t}();o.default(document).on("click.bs.button.data-api",'[data-toggle^="button"]',(function(t){var e=t.target,n=e;if(o.default(e).hasClass("btn")||(e=o.default(e).closest(".btn")[0]),!e||e.hasAttribute("disabled")||e.classList.contains("disabled"))t.preventDefault();else{var i=e.querySelector('input:not([type="hidden"])');if(i&&(i.hasAttribute("disabled")||i.classList.contains("disabled")))return void t.preventDefault();"INPUT"!==n.tagName&&"LABEL"===e.tagName||m._jQueryInterface.call(o.default(e),"toggle","INPUT"===n.tagName)}})).on("focus.bs.button.data-api blur.bs.button.data-api",'[data-toggle^="button"]',(function(t){var e=o.default(t.target).closest(".btn")[0];o.default(e).toggleClass("focus",/^focus(in)?$/.test(t.type))})),o.default(window).on("load.bs.button.data-api",(function(){for(var t=[].slice.call(document.querySelectorAll('[data-toggle="buttons"] .btn')),e=0,n=t.length;e0,this._pointerEvent=Boolean(window.PointerEvent||window.MSPointerEvent),this._addEventListeners()}var e=t.prototype;return e.next=function(){this._isSliding||this._slide("next")},e.nextWhenVisible=function(){var t=o.default(this._element);!document.hidden&&t.is(":visible")&&"hidden"!==t.css("visibility")&&this.next()},e.prev=function(){this._isSliding||this._slide("prev")},e.pause=function(t){t||(this._isPaused=!0),this._element.querySelector(".carousel-item-next, .carousel-item-prev")&&(d.triggerTransitionEnd(this._element),this.cycle(!0)),clearInterval(this._interval),this._interval=null},e.cycle=function(t){t||(this._isPaused=!1),this._interval&&(clearInterval(this._interval),this._interval=null),this._config.interval&&!this._isPaused&&(this._updateInterval(),this._interval=setInterval((document.visibilityState?this.nextWhenVisible:this.next).bind(this),this._config.interval))},e.to=function(t){var e=this;this._activeElement=this._element.querySelector(".active.carousel-item");var n=this._getItemIndex(this._activeElement);if(!(t>this._items.length-1||t<0))if(this._isSliding)o.default(this._element).one("slid.bs.carousel",(function(){return e.to(t)}));else{if(n===t)return this.pause(),void this.cycle();var i=t>n?"next":"prev";this._slide(i,this._items[t])}},e.dispose=function(){o.default(this._element).off(v),o.default.removeData(this._element,"bs.carousel"),this._items=null,this._config=null,this._element=null,this._interval=null,this._isPaused=null,this._isSliding=null,this._activeElement=null,this._indicatorsElement=null},e._getConfig=function(t){return t=l({},b,t),d.typeCheckConfig(g,t,y),t},e._handleSwipe=function(){var t=Math.abs(this.touchDeltaX);if(!(t<=40)){var e=t/this.touchDeltaX;this.touchDeltaX=0,e>0&&this.prev(),e<0&&this.next()}},e._addEventListeners=function(){var t=this;this._config.keyboard&&o.default(this._element).on("keydown.bs.carousel",(function(e){return t._keydown(e)})),"hover"===this._config.pause&&o.default(this._element).on("mouseenter.bs.carousel",(function(e){return t.pause(e)})).on("mouseleave.bs.carousel",(function(e){return t.cycle(e)})),this._config.touch&&this._addTouchEventListeners()},e._addTouchEventListeners=function(){var t=this;if(this._touchSupported){var e=function(e){t._pointerEvent&&w[e.originalEvent.pointerType.toUpperCase()]?t.touchStartX=e.originalEvent.clientX:t._pointerEvent||(t.touchStartX=e.originalEvent.touches[0].clientX)},n=function(e){t._pointerEvent&&w[e.originalEvent.pointerType.toUpperCase()]&&(t.touchDeltaX=e.originalEvent.clientX-t.touchStartX),t._handleSwipe(),"hover"===t._config.pause&&(t.pause(),t.touchTimeout&&clearTimeout(t.touchTimeout),t.touchTimeout=setTimeout((function(e){return t.cycle(e)}),500+t._config.interval))};o.default(this._element.querySelectorAll(".carousel-item img")).on("dragstart.bs.carousel",(function(t){return t.preventDefault()})),this._pointerEvent?(o.default(this._element).on("pointerdown.bs.carousel",(function(t){return e(t)})),o.default(this._element).on("pointerup.bs.carousel",(function(t){return n(t)})),this._element.classList.add("pointer-event")):(o.default(this._element).on("touchstart.bs.carousel",(function(t){return e(t)})),o.default(this._element).on("touchmove.bs.carousel",(function(e){return function(e){t.touchDeltaX=e.originalEvent.touches&&e.originalEvent.touches.length>1?0:e.originalEvent.touches[0].clientX-t.touchStartX}(e)})),o.default(this._element).on("touchend.bs.carousel",(function(t){return n(t)})))}},e._keydown=function(t){if(!/input|textarea/i.test(t.target.tagName))switch(t.which){case 37:t.preventDefault(),this.prev();break;case 39:t.preventDefault(),this.next()}},e._getItemIndex=function(t){return this._items=t&&t.parentNode?[].slice.call(t.parentNode.querySelectorAll(".carousel-item")):[],this._items.indexOf(t)},e._getItemByDirection=function(t,e){var n="next"===t,i="prev"===t,o=this._getItemIndex(e),r=this._items.length-1;if((i&&0===o||n&&o===r)&&!this._config.wrap)return e;var a=(o+("prev"===t?-1:1))%this._items.length;return-1===a?this._items[this._items.length-1]:this._items[a]},e._triggerSlideEvent=function(t,e){var n=this._getItemIndex(t),i=this._getItemIndex(this._element.querySelector(".active.carousel-item")),r=o.default.Event("slide.bs.carousel",{relatedTarget:t,direction:e,from:i,to:n});return o.default(this._element).trigger(r),r},e._setActiveIndicatorElement=function(t){if(this._indicatorsElement){var e=[].slice.call(this._indicatorsElement.querySelectorAll(".active"));o.default(e).removeClass("active");var n=this._indicatorsElement.children[this._getItemIndex(t)];n&&o.default(n).addClass("active")}},e._updateInterval=function(){var t=this._activeElement||this._element.querySelector(".active.carousel-item");if(t){var e=parseInt(t.getAttribute("data-interval"),10);e?(this._config.defaultInterval=this._config.defaultInterval||this._config.interval,this._config.interval=e):this._config.interval=this._config.defaultInterval||this._config.interval}},e._slide=function(t,e){var n,i,r,a=this,s=this._element.querySelector(".active.carousel-item"),l=this._getItemIndex(s),u=e||s&&this._getItemByDirection(t,s),f=this._getItemIndex(u),c=Boolean(this._interval);if("next"===t?(n="carousel-item-left",i="carousel-item-next",r="left"):(n="carousel-item-right",i="carousel-item-prev",r="right"),u&&o.default(u).hasClass("active"))this._isSliding=!1;else if(!this._triggerSlideEvent(u,r).isDefaultPrevented()&&s&&u){this._isSliding=!0,c&&this.pause(),this._setActiveIndicatorElement(u),this._activeElement=u;var h=o.default.Event("slid.bs.carousel",{relatedTarget:u,direction:r,from:l,to:f});if(o.default(this._element).hasClass("slide")){o.default(u).addClass(i),d.reflow(u),o.default(s).addClass(n),o.default(u).addClass(n);var p=d.getTransitionDurationFromElement(s);o.default(s).one(d.TRANSITION_END,(function(){o.default(u).removeClass(n+" "+i).addClass("active"),o.default(s).removeClass("active "+i+" "+n),a._isSliding=!1,setTimeout((function(){return o.default(a._element).trigger(h)}),0)})).emulateTransitionEnd(p)}else o.default(s).removeClass("active"),o.default(u).addClass("active"),this._isSliding=!1,o.default(this._element).trigger(h);c&&this.cycle()}},t._jQueryInterface=function(e){return this.each((function(){var n=o.default(this).data("bs.carousel"),i=l({},b,o.default(this).data());"object"==typeof e&&(i=l({},i,e));var r="string"==typeof e?e:i.slide;if(n||(n=new t(this,i),o.default(this).data("bs.carousel",n)),"number"==typeof e)n.to(e);else if("string"==typeof r){if(void 0===n[r])throw new TypeError('No method named "'+r+'"');n[r]()}else i.interval&&i.ride&&(n.pause(),n.cycle())}))},t._dataApiClickHandler=function(e){var n=d.getSelectorFromElement(this);if(n){var i=o.default(n)[0];if(i&&o.default(i).hasClass("carousel")){var r=l({},o.default(i).data(),o.default(this).data()),a=this.getAttribute("data-slide-to");a&&(r.interval=!1),t._jQueryInterface.call(o.default(i),r),a&&o.default(i).data("bs.carousel").to(a),e.preventDefault()}}},s(t,null,[{key:"VERSION",get:function(){return"4.6.1"}},{key:"Default",get:function(){return b}}]),t}();o.default(document).on("click.bs.carousel.data-api","[data-slide], [data-slide-to]",E._dataApiClickHandler),o.default(window).on("load.bs.carousel.data-api",(function(){for(var t=[].slice.call(document.querySelectorAll('[data-ride="carousel"]')),e=0,n=t.length;e0&&(this._selector=a,this._triggerArray.push(r))}this._parent=this._config.parent?this._getParent():null,this._config.parent||this._addAriaAndCollapsedClass(this._element,this._triggerArray),this._config.toggle&&this.toggle()}var e=t.prototype;return e.toggle=function(){o.default(this._element).hasClass("show")?this.hide():this.show()},e.show=function(){var e,n,i=this;if(!(this._isTransitioning||o.default(this._element).hasClass("show")||(this._parent&&0===(e=[].slice.call(this._parent.querySelectorAll(".show, .collapsing")).filter((function(t){return"string"==typeof i._config.parent?t.getAttribute("data-parent")===i._config.parent:t.classList.contains("collapse")}))).length&&(e=null),e&&(n=o.default(e).not(this._selector).data("bs.collapse"))&&n._isTransitioning))){var r=o.default.Event("show.bs.collapse");if(o.default(this._element).trigger(r),!r.isDefaultPrevented()){e&&(t._jQueryInterface.call(o.default(e).not(this._selector),"hide"),n||o.default(e).data("bs.collapse",null));var a=this._getDimension();o.default(this._element).removeClass("collapse").addClass("collapsing"),this._element.style[a]=0,this._triggerArray.length&&o.default(this._triggerArray).removeClass("collapsed").attr("aria-expanded",!0),this.setTransitioning(!0);var s="scroll"+(a[0].toUpperCase()+a.slice(1)),l=d.getTransitionDurationFromElement(this._element);o.default(this._element).one(d.TRANSITION_END,(function(){o.default(i._element).removeClass("collapsing").addClass("collapse show"),i._element.style[a]="",i.setTransitioning(!1),o.default(i._element).trigger("shown.bs.collapse")})).emulateTransitionEnd(l),this._element.style[a]=this._element[s]+"px"}}},e.hide=function(){var t=this;if(!this._isTransitioning&&o.default(this._element).hasClass("show")){var e=o.default.Event("hide.bs.collapse");if(o.default(this._element).trigger(e),!e.isDefaultPrevented()){var n=this._getDimension();this._element.style[n]=this._element.getBoundingClientRect()[n]+"px",d.reflow(this._element),o.default(this._element).addClass("collapsing").removeClass("collapse show");var i=this._triggerArray.length;if(i>0)for(var r=0;r0},e._getOffset=function(){var t=this,e={};return"function"==typeof this._config.offset?e.fn=function(e){return e.offsets=l({},e.offsets,t._config.offset(e.offsets,t._element)),e}:e.offset=this._config.offset,e},e._getPopperConfig=function(){var t={placement:this._getPlacement(),modifiers:{offset:this._getOffset(),flip:{enabled:this._config.flip},preventOverflow:{boundariesElement:this._config.boundary}}};return"static"===this._config.display&&(t.modifiers.applyStyle={enabled:!1}),l({},t,this._config.popperConfig)},t._jQueryInterface=function(e){return this.each((function(){var n=o.default(this).data("bs.dropdown");if(n||(n=new t(this,"object"==typeof e?e:null),o.default(this).data("bs.dropdown",n)),"string"==typeof e){if(void 0===n[e])throw new TypeError('No method named "'+e+'"');n[e]()}}))},t._clearMenus=function(e){if(!e||3!==e.which&&("keyup"!==e.type||9===e.which))for(var n=[].slice.call(document.querySelectorAll('[data-toggle="dropdown"]')),i=0,r=n.length;i0&&a--,40===e.which&&adocument.documentElement.clientHeight;n||(this._element.style.overflowY="hidden"),this._element.classList.add("modal-static");var i=d.getTransitionDurationFromElement(this._dialog);o.default(this._element).off(d.TRANSITION_END),o.default(this._element).one(d.TRANSITION_END,(function(){t._element.classList.remove("modal-static"),n||o.default(t._element).one(d.TRANSITION_END,(function(){t._element.style.overflowY=""})).emulateTransitionEnd(t._element,i)})).emulateTransitionEnd(i),this._element.focus()}},e._showElement=function(t){var e=this,n=o.default(this._element).hasClass("fade"),i=this._dialog?this._dialog.querySelector(".modal-body"):null;this._element.parentNode&&this._element.parentNode.nodeType===Node.ELEMENT_NODE||document.body.appendChild(this._element),this._element.style.display="block",this._element.removeAttribute("aria-hidden"),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),o.default(this._dialog).hasClass("modal-dialog-scrollable")&&i?i.scrollTop=0:this._element.scrollTop=0,n&&d.reflow(this._element),o.default(this._element).addClass("show"),this._config.focus&&this._enforceFocus();var r=o.default.Event("shown.bs.modal",{relatedTarget:t}),a=function(){e._config.focus&&e._element.focus(),e._isTransitioning=!1,o.default(e._element).trigger(r)};if(n){var s=d.getTransitionDurationFromElement(this._dialog);o.default(this._dialog).one(d.TRANSITION_END,a).emulateTransitionEnd(s)}else a()},e._enforceFocus=function(){var t=this;o.default(document).off("focusin.bs.modal").on("focusin.bs.modal",(function(e){document!==e.target&&t._element!==e.target&&0===o.default(t._element).has(e.target).length&&t._element.focus()}))},e._setEscapeEvent=function(){var t=this;this._isShown?o.default(this._element).on("keydown.dismiss.bs.modal",(function(e){t._config.keyboard&&27===e.which?(e.preventDefault(),t.hide()):t._config.keyboard||27!==e.which||t._triggerBackdropTransition()})):this._isShown||o.default(this._element).off("keydown.dismiss.bs.modal")},e._setResizeEvent=function(){var t=this;this._isShown?o.default(window).on("resize.bs.modal",(function(e){return t.handleUpdate(e)})):o.default(window).off("resize.bs.modal")},e._hideModal=function(){var t=this;this._element.style.display="none",this._element.setAttribute("aria-hidden",!0),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._isTransitioning=!1,this._showBackdrop((function(){o.default(document.body).removeClass("modal-open"),t._resetAdjustments(),t._resetScrollbar(),o.default(t._element).trigger("hidden.bs.modal")}))},e._removeBackdrop=function(){this._backdrop&&(o.default(this._backdrop).remove(),this._backdrop=null)},e._showBackdrop=function(t){var e=this,n=o.default(this._element).hasClass("fade")?"fade":"";if(this._isShown&&this._config.backdrop){if(this._backdrop=document.createElement("div"),this._backdrop.className="modal-backdrop",n&&this._backdrop.classList.add(n),o.default(this._backdrop).appendTo(document.body),o.default(this._element).on("click.dismiss.bs.modal",(function(t){e._ignoreBackdropClick?e._ignoreBackdropClick=!1:t.target===t.currentTarget&&("static"===e._config.backdrop?e._triggerBackdropTransition():e.hide())})),n&&d.reflow(this._backdrop),o.default(this._backdrop).addClass("show"),!t)return;if(!n)return void t();var i=d.getTransitionDurationFromElement(this._backdrop);o.default(this._backdrop).one(d.TRANSITION_END,t).emulateTransitionEnd(i)}else if(!this._isShown&&this._backdrop){o.default(this._backdrop).removeClass("show");var r=function(){e._removeBackdrop(),t&&t()};if(o.default(this._element).hasClass("fade")){var a=d.getTransitionDurationFromElement(this._backdrop);o.default(this._backdrop).one(d.TRANSITION_END,r).emulateTransitionEnd(a)}else r()}else t&&t()},e._adjustDialog=function(){var t=this._element.scrollHeight>document.documentElement.clientHeight;!this._isBodyOverflowing&&t&&(this._element.style.paddingLeft=this._scrollbarWidth+"px"),this._isBodyOverflowing&&!t&&(this._element.style.paddingRight=this._scrollbarWidth+"px")},e._resetAdjustments=function(){this._element.style.paddingLeft="",this._element.style.paddingRight=""},e._checkScrollbar=function(){var t=document.body.getBoundingClientRect();this._isBodyOverflowing=Math.round(t.left+t.right)
',trigger:"hover focus",title:"",delay:0,html:!1,selector:!1,placement:"top",offset:0,container:!1,fallbackPlacement:"flip",boundary:"scrollParent",customClass:"",sanitize:!0,sanitizeFn:null,whiteList:H,popperConfig:null},X={animation:"boolean",template:"string",title:"(string|element|function)",trigger:"string",delay:"(number|object)",html:"boolean",selector:"(string|boolean)",placement:"(string|function)",offset:"(number|string|function)",container:"(string|element|boolean)",fallbackPlacement:"(string|array)",boundary:"(string|element)",customClass:"(string|function)",sanitize:"boolean",sanitizeFn:"(null|function)",whiteList:"object",popperConfig:"(null|object)"},$={HIDE:"hide.bs.tooltip",HIDDEN:"hidden.bs.tooltip",SHOW:"show.bs.tooltip",SHOWN:"shown.bs.tooltip",INSERTED:"inserted.bs.tooltip",CLICK:"click.bs.tooltip",FOCUSIN:"focusin.bs.tooltip",FOCUSOUT:"focusout.bs.tooltip",MOUSEENTER:"mouseenter.bs.tooltip",MOUSELEAVE:"mouseleave.bs.tooltip"},G=function(){function t(t,e){if(void 0===r.default)throw new TypeError("Bootstrap's tooltips require Popper (https://popper.js.org)");this._isEnabled=!0,this._timeout=0,this._hoverState="",this._activeTrigger={},this._popper=null,this.element=t,this.config=this._getConfig(e),this.tip=null,this._setListeners()}var e=t.prototype;return e.enable=function(){this._isEnabled=!0},e.disable=function(){this._isEnabled=!1},e.toggleEnabled=function(){this._isEnabled=!this._isEnabled},e.toggle=function(t){if(this._isEnabled)if(t){var e=this.constructor.DATA_KEY,n=o.default(t.currentTarget).data(e);n||(n=new this.constructor(t.currentTarget,this._getDelegateConfig()),o.default(t.currentTarget).data(e,n)),n._activeTrigger.click=!n._activeTrigger.click,n._isWithActiveTrigger()?n._enter(null,n):n._leave(null,n)}else{if(o.default(this.getTipElement()).hasClass("show"))return void this._leave(null,this);this._enter(null,this)}},e.dispose=function(){clearTimeout(this._timeout),o.default.removeData(this.element,this.constructor.DATA_KEY),o.default(this.element).off(this.constructor.EVENT_KEY),o.default(this.element).closest(".modal").off("hide.bs.modal",this._hideModalHandler),this.tip&&o.default(this.tip).remove(),this._isEnabled=null,this._timeout=null,this._hoverState=null,this._activeTrigger=null,this._popper&&this._popper.destroy(),this._popper=null,this.element=null,this.config=null,this.tip=null},e.show=function(){var t=this;if("none"===o.default(this.element).css("display"))throw new Error("Please use show on visible elements");var e=o.default.Event(this.constructor.Event.SHOW);if(this.isWithContent()&&this._isEnabled){o.default(this.element).trigger(e);var n=d.findShadowRoot(this.element),i=o.default.contains(null!==n?n:this.element.ownerDocument.documentElement,this.element);if(e.isDefaultPrevented()||!i)return;var a=this.getTipElement(),s=d.getUID(this.constructor.NAME);a.setAttribute("id",s),this.element.setAttribute("aria-describedby",s),this.setContent(),this.config.animation&&o.default(a).addClass("fade");var l="function"==typeof this.config.placement?this.config.placement.call(this,a,this.element):this.config.placement,u=this._getAttachment(l);this.addAttachmentClass(u);var f=this._getContainer();o.default(a).data(this.constructor.DATA_KEY,this),o.default.contains(this.element.ownerDocument.documentElement,this.tip)||o.default(a).appendTo(f),o.default(this.element).trigger(this.constructor.Event.INSERTED),this._popper=new r.default(this.element,a,this._getPopperConfig(u)),o.default(a).addClass("show"),o.default(a).addClass(this.config.customClass),"ontouchstart"in document.documentElement&&o.default(document.body).children().on("mouseover",null,o.default.noop);var c=function(){t.config.animation&&t._fixTransition();var e=t._hoverState;t._hoverState=null,o.default(t.element).trigger(t.constructor.Event.SHOWN),"out"===e&&t._leave(null,t)};if(o.default(this.tip).hasClass("fade")){var h=d.getTransitionDurationFromElement(this.tip);o.default(this.tip).one(d.TRANSITION_END,c).emulateTransitionEnd(h)}else c()}},e.hide=function(t){var e=this,n=this.getTipElement(),i=o.default.Event(this.constructor.Event.HIDE),r=function(){"show"!==e._hoverState&&n.parentNode&&n.parentNode.removeChild(n),e._cleanTipClass(),e.element.removeAttribute("aria-describedby"),o.default(e.element).trigger(e.constructor.Event.HIDDEN),null!==e._popper&&e._popper.destroy(),t&&t()};if(o.default(this.element).trigger(i),!i.isDefaultPrevented()){if(o.default(n).removeClass("show"),"ontouchstart"in document.documentElement&&o.default(document.body).children().off("mouseover",null,o.default.noop),this._activeTrigger.click=!1,this._activeTrigger.focus=!1,this._activeTrigger.hover=!1,o.default(this.tip).hasClass("fade")){var a=d.getTransitionDurationFromElement(n);o.default(n).one(d.TRANSITION_END,r).emulateTransitionEnd(a)}else r();this._hoverState=""}},e.update=function(){null!==this._popper&&this._popper.scheduleUpdate()},e.isWithContent=function(){return Boolean(this.getTitle())},e.addAttachmentClass=function(t){o.default(this.getTipElement()).addClass("bs-tooltip-"+t)},e.getTipElement=function(){return this.tip=this.tip||o.default(this.config.template)[0],this.tip},e.setContent=function(){var t=this.getTipElement();this.setElementContent(o.default(t.querySelectorAll(".tooltip-inner")),this.getTitle()),o.default(t).removeClass("fade show")},e.setElementContent=function(t,e){"object"!=typeof e||!e.nodeType&&!e.jquery?this.config.html?(this.config.sanitize&&(e=Q(e,this.config.whiteList,this.config.sanitizeFn)),t.html(e)):t.text(e):this.config.html?o.default(e).parent().is(t)||t.empty().append(e):t.text(o.default(e).text())},e.getTitle=function(){var t=this.element.getAttribute("data-original-title");return t||(t="function"==typeof this.config.title?this.config.title.call(this.element):this.config.title),t},e._getPopperConfig=function(t){var e=this;return l({},{placement:t,modifiers:{offset:this._getOffset(),flip:{behavior:this.config.fallbackPlacement},arrow:{element:".arrow"},preventOverflow:{boundariesElement:this.config.boundary}},onCreate:function(t){t.originalPlacement!==t.placement&&e._handlePopperPlacementChange(t)},onUpdate:function(t){return e._handlePopperPlacementChange(t)}},this.config.popperConfig)},e._getOffset=function(){var t=this,e={};return"function"==typeof this.config.offset?e.fn=function(e){return e.offsets=l({},e.offsets,t.config.offset(e.offsets,t.element)),e}:e.offset=this.config.offset,e},e._getContainer=function(){return!1===this.config.container?document.body:d.isElement(this.config.container)?o.default(this.config.container):o.default(document).find(this.config.container)},e._getAttachment=function(t){return z[t.toUpperCase()]},e._setListeners=function(){var t=this;this.config.trigger.split(" ").forEach((function(e){if("click"===e)o.default(t.element).on(t.constructor.Event.CLICK,t.config.selector,(function(e){return t.toggle(e)}));else if("manual"!==e){var n="hover"===e?t.constructor.Event.MOUSEENTER:t.constructor.Event.FOCUSIN,i="hover"===e?t.constructor.Event.MOUSELEAVE:t.constructor.Event.FOCUSOUT;o.default(t.element).on(n,t.config.selector,(function(e){return t._enter(e)})).on(i,t.config.selector,(function(e){return t._leave(e)}))}})),this._hideModalHandler=function(){t.element&&t.hide()},o.default(this.element).closest(".modal").on("hide.bs.modal",this._hideModalHandler),this.config.selector?this.config=l({},this.config,{trigger:"manual",selector:""}):this._fixTitle()},e._fixTitle=function(){var t=typeof this.element.getAttribute("data-original-title");(this.element.getAttribute("title")||"string"!==t)&&(this.element.setAttribute("data-original-title",this.element.getAttribute("title")||""),this.element.setAttribute("title",""))},e._enter=function(t,e){var n=this.constructor.DATA_KEY;(e=e||o.default(t.currentTarget).data(n))||(e=new this.constructor(t.currentTarget,this._getDelegateConfig()),o.default(t.currentTarget).data(n,e)),t&&(e._activeTrigger["focusin"===t.type?"focus":"hover"]=!0),o.default(e.getTipElement()).hasClass("show")||"show"===e._hoverState?e._hoverState="show":(clearTimeout(e._timeout),e._hoverState="show",e.config.delay&&e.config.delay.show?e._timeout=setTimeout((function(){"show"===e._hoverState&&e.show()}),e.config.delay.show):e.show())},e._leave=function(t,e){var n=this.constructor.DATA_KEY;(e=e||o.default(t.currentTarget).data(n))||(e=new this.constructor(t.currentTarget,this._getDelegateConfig()),o.default(t.currentTarget).data(n,e)),t&&(e._activeTrigger["focusout"===t.type?"focus":"hover"]=!1),e._isWithActiveTrigger()||(clearTimeout(e._timeout),e._hoverState="out",e.config.delay&&e.config.delay.hide?e._timeout=setTimeout((function(){"out"===e._hoverState&&e.hide()}),e.config.delay.hide):e.hide())},e._isWithActiveTrigger=function(){for(var t in this._activeTrigger)if(this._activeTrigger[t])return!0;return!1},e._getConfig=function(t){var e=o.default(this.element).data();return Object.keys(e).forEach((function(t){-1!==Y.indexOf(t)&&delete e[t]})),"number"==typeof(t=l({},this.constructor.Default,e,"object"==typeof t&&t?t:{})).delay&&(t.delay={show:t.delay,hide:t.delay}),"number"==typeof t.title&&(t.title=t.title.toString()),"number"==typeof t.content&&(t.content=t.content.toString()),d.typeCheckConfig(W,t,this.constructor.DefaultType),t.sanitize&&(t.template=Q(t.template,t.whiteList,t.sanitizeFn)),t},e._getDelegateConfig=function(){var t={};if(this.config)for(var e in this.config)this.constructor.Default[e]!==this.config[e]&&(t[e]=this.config[e]);return t},e._cleanTipClass=function(){var t=o.default(this.getTipElement()),e=t.attr("class").match(V);null!==e&&e.length&&t.removeClass(e.join(""))},e._handlePopperPlacementChange=function(t){this.tip=t.instance.popper,this._cleanTipClass(),this.addAttachmentClass(this._getAttachment(t.placement))},e._fixTransition=function(){var t=this.getTipElement(),e=this.config.animation;null===t.getAttribute("x-placement")&&(o.default(t).removeClass("fade"),this.config.animation=!1,this.hide(),this.show(),this.config.animation=e)},t._jQueryInterface=function(e){return this.each((function(){var n=o.default(this),i=n.data("bs.tooltip"),r="object"==typeof e&&e;if((i||!/dispose|hide/.test(e))&&(i||(i=new t(this,r),n.data("bs.tooltip",i)),"string"==typeof e)){if(void 0===i[e])throw new TypeError('No method named "'+e+'"');i[e]()}}))},s(t,null,[{key:"VERSION",get:function(){return"4.6.1"}},{key:"Default",get:function(){return K}},{key:"NAME",get:function(){return W}},{key:"DATA_KEY",get:function(){return"bs.tooltip"}},{key:"Event",get:function(){return $}},{key:"EVENT_KEY",get:function(){return".bs.tooltip"}},{key:"DefaultType",get:function(){return X}}]),t}();o.default.fn[W]=G._jQueryInterface,o.default.fn[W].Constructor=G,o.default.fn[W].noConflict=function(){return o.default.fn[W]=U,G._jQueryInterface};var J="popover",Z=o.default.fn[J],tt=new RegExp("(^|\\s)bs-popover\\S+","g"),et=l({},G.Default,{placement:"right",trigger:"click",content:"",template:''}),nt=l({},G.DefaultType,{content:"(string|element|function)"}),it={HIDE:"hide.bs.popover",HIDDEN:"hidden.bs.popover",SHOW:"show.bs.popover",SHOWN:"shown.bs.popover",INSERTED:"inserted.bs.popover",CLICK:"click.bs.popover",FOCUSIN:"focusin.bs.popover",FOCUSOUT:"focusout.bs.popover",MOUSEENTER:"mouseenter.bs.popover",MOUSELEAVE:"mouseleave.bs.popover"},ot=function(t){var e,n;function i(){return t.apply(this,arguments)||this}n=t,(e=i).prototype=Object.create(n.prototype),e.prototype.constructor=e,u(e,n);var r=i.prototype;return r.isWithContent=function(){return this.getTitle()||this._getContent()},r.addAttachmentClass=function(t){o.default(this.getTipElement()).addClass("bs-popover-"+t)},r.getTipElement=function(){return this.tip=this.tip||o.default(this.config.template)[0],this.tip},r.setContent=function(){var t=o.default(this.getTipElement());this.setElementContent(t.find(".popover-header"),this.getTitle());var e=this._getContent();"function"==typeof e&&(e=e.call(this.element)),this.setElementContent(t.find(".popover-body"),e),t.removeClass("fade show")},r._getContent=function(){return this.element.getAttribute("data-content")||this.config.content},r._cleanTipClass=function(){var t=o.default(this.getTipElement()),e=t.attr("class").match(tt);null!==e&&e.length>0&&t.removeClass(e.join(""))},i._jQueryInterface=function(t){return this.each((function(){var e=o.default(this).data("bs.popover"),n="object"==typeof t?t:null;if((e||!/dispose|hide/.test(t))&&(e||(e=new i(this,n),o.default(this).data("bs.popover",e)),"string"==typeof t)){if(void 0===e[t])throw new TypeError('No method named "'+t+'"');e[t]()}}))},s(i,null,[{key:"VERSION",get:function(){return"4.6.1"}},{key:"Default",get:function(){return et}},{key:"NAME",get:function(){return J}},{key:"DATA_KEY",get:function(){return"bs.popover"}},{key:"Event",get:function(){return it}},{key:"EVENT_KEY",get:function(){return".bs.popover"}},{key:"DefaultType",get:function(){return nt}}]),i}(G);o.default.fn[J]=ot._jQueryInterface,o.default.fn[J].Constructor=ot,o.default.fn[J].noConflict=function(){return o.default.fn[J]=Z,ot._jQueryInterface};var rt="scrollspy",at=o.default.fn[rt],st={offset:10,method:"auto",target:""},lt={offset:"number",method:"string",target:"(string|element)"},ut=function(){function t(t,e){var n=this;this._element=t,this._scrollElement="BODY"===t.tagName?window:t,this._config=this._getConfig(e),this._selector=this._config.target+" .nav-link,"+this._config.target+" .list-group-item,"+this._config.target+" .dropdown-item",this._offsets=[],this._targets=[],this._activeTarget=null,this._scrollHeight=0,o.default(this._scrollElement).on("scroll.bs.scrollspy",(function(t){return n._process(t)})),this.refresh(),this._process()}var e=t.prototype;return e.refresh=function(){var t=this,e=this._scrollElement===this._scrollElement.window?"offset":"position",n="auto"===this._config.method?e:this._config.method,i="position"===n?this._getScrollTop():0;this._offsets=[],this._targets=[],this._scrollHeight=this._getScrollHeight(),[].slice.call(document.querySelectorAll(this._selector)).map((function(t){var e,r=d.getSelectorFromElement(t);if(r&&(e=document.querySelector(r)),e){var a=e.getBoundingClientRect();if(a.width||a.height)return[o.default(e)[n]().top+i,r]}return null})).filter((function(t){return t})).sort((function(t,e){return t[0]-e[0]})).forEach((function(e){t._offsets.push(e[0]),t._targets.push(e[1])}))},e.dispose=function(){o.default.removeData(this._element,"bs.scrollspy"),o.default(this._scrollElement).off(".bs.scrollspy"),this._element=null,this._scrollElement=null,this._config=null,this._selector=null,this._offsets=null,this._targets=null,this._activeTarget=null,this._scrollHeight=null},e._getConfig=function(t){if("string"!=typeof(t=l({},st,"object"==typeof t&&t?t:{})).target&&d.isElement(t.target)){var e=o.default(t.target).attr("id");e||(e=d.getUID(rt),o.default(t.target).attr("id",e)),t.target="#"+e}return d.typeCheckConfig(rt,t,lt),t},e._getScrollTop=function(){return this._scrollElement===window?this._scrollElement.pageYOffset:this._scrollElement.scrollTop},e._getScrollHeight=function(){return this._scrollElement.scrollHeight||Math.max(document.body.scrollHeight,document.documentElement.scrollHeight)},e._getOffsetHeight=function(){return this._scrollElement===window?window.innerHeight:this._scrollElement.getBoundingClientRect().height},e._process=function(){var t=this._getScrollTop()+this._config.offset,e=this._getScrollHeight(),n=this._config.offset+e-this._getOffsetHeight();if(this._scrollHeight!==e&&this.refresh(),t>=n){var i=this._targets[this._targets.length-1];this._activeTarget!==i&&this._activate(i)}else{if(this._activeTarget&&t0)return this._activeTarget=null,void this._clear();for(var o=this._offsets.length;o--;)this._activeTarget!==this._targets[o]&&t>=this._offsets[o]&&(void 0===this._offsets[o+1]||t li > .active":".active";n=(n=o.default.makeArray(o.default(i).find(a)))[n.length-1]}var s=o.default.Event("hide.bs.tab",{relatedTarget:this._element}),l=o.default.Event("show.bs.tab",{relatedTarget:n});if(n&&o.default(n).trigger(s),o.default(this._element).trigger(l),!l.isDefaultPrevented()&&!s.isDefaultPrevented()){r&&(e=document.querySelector(r)),this._activate(this._element,i);var u=function(){var e=o.default.Event("hidden.bs.tab",{relatedTarget:t._element}),i=o.default.Event("shown.bs.tab",{relatedTarget:n});o.default(n).trigger(e),o.default(t._element).trigger(i)};e?this._activate(e,e.parentNode,u):u()}}},e.dispose=function(){o.default.removeData(this._element,"bs.tab"),this._element=null},e._activate=function(t,e,n){var i=this,r=(!e||"UL"!==e.nodeName&&"OL"!==e.nodeName?o.default(e).children(".active"):o.default(e).find("> li > .active"))[0],a=n&&r&&o.default(r).hasClass("fade"),s=function(){return i._transitionComplete(t,r,n)};if(r&&a){var l=d.getTransitionDurationFromElement(r);o.default(r).removeClass("show").one(d.TRANSITION_END,s).emulateTransitionEnd(l)}else s()},e._transitionComplete=function(t,e,n){if(e){o.default(e).removeClass("active");var i=o.default(e.parentNode).find("> .dropdown-menu .active")[0];i&&o.default(i).removeClass("active"),"tab"===e.getAttribute("role")&&e.setAttribute("aria-selected",!1)}o.default(t).addClass("active"),"tab"===t.getAttribute("role")&&t.setAttribute("aria-selected",!0),d.reflow(t),t.classList.contains("fade")&&t.classList.add("show");var r=t.parentNode;if(r&&"LI"===r.nodeName&&(r=r.parentNode),r&&o.default(r).hasClass("dropdown-menu")){var a=o.default(t).closest(".dropdown")[0];if(a){var s=[].slice.call(a.querySelectorAll(".dropdown-toggle"));o.default(s).addClass("active")}t.setAttribute("aria-expanded",!0)}n&&n()},t._jQueryInterface=function(e){return this.each((function(){var n=o.default(this),i=n.data("bs.tab");if(i||(i=new t(this),n.data("bs.tab",i)),"string"==typeof e){if(void 0===i[e])throw new TypeError('No method named "'+e+'"');i[e]()}}))},s(t,null,[{key:"VERSION",get:function(){return"4.6.1"}}]),t}();o.default(document).on("click.bs.tab.data-api",'[data-toggle="tab"], [data-toggle="pill"], [data-toggle="list"]',(function(t){t.preventDefault(),dt._jQueryInterface.call(o.default(this),"show")})),o.default.fn.tab=dt._jQueryInterface,o.default.fn.tab.Constructor=dt,o.default.fn.tab.noConflict=function(){return o.default.fn.tab=ft,dt._jQueryInterface};var ct="toast",ht=o.default.fn[ct],pt={animation:!0,autohide:!0,delay:500},mt={animation:"boolean",autohide:"boolean",delay:"number"},gt=function(){function t(t,e){this._element=t,this._config=this._getConfig(e),this._timeout=null,this._setListeners()}var e=t.prototype;return e.show=function(){var t=this,e=o.default.Event("show.bs.toast");if(o.default(this._element).trigger(e),!e.isDefaultPrevented()){this._clearTimeout(),this._config.animation&&this._element.classList.add("fade");var n=function(){t._element.classList.remove("showing"),t._element.classList.add("show"),o.default(t._element).trigger("shown.bs.toast"),t._config.autohide&&(t._timeout=setTimeout((function(){t.hide()}),t._config.delay))};if(this._element.classList.remove("hide"),d.reflow(this._element),this._element.classList.add("showing"),this._config.animation){var i=d.getTransitionDurationFromElement(this._element);o.default(this._element).one(d.TRANSITION_END,n).emulateTransitionEnd(i)}else n()}},e.hide=function(){if(this._element.classList.contains("show")){var t=o.default.Event("hide.bs.toast");o.default(this._element).trigger(t),t.isDefaultPrevented()||this._close()}},e.dispose=function(){this._clearTimeout(),this._element.classList.contains("show")&&this._element.classList.remove("show"),o.default(this._element).off("click.dismiss.bs.toast"),o.default.removeData(this._element,"bs.toast"),this._element=null,this._config=null},e._getConfig=function(t){return t=l({},pt,o.default(this._element).data(),"object"==typeof t&&t?t:{}),d.typeCheckConfig(ct,t,this.constructor.DefaultType),t},e._setListeners=function(){var t=this;o.default(this._element).on("click.dismiss.bs.toast",'[data-dismiss="toast"]',(function(){return t.hide()}))},e._close=function(){var t=this,e=function(){t._element.classList.add("hide"),o.default(t._element).trigger("hidden.bs.toast")};if(this._element.classList.remove("show"),this._config.animation){var n=d.getTransitionDurationFromElement(this._element);o.default(this._element).one(d.TRANSITION_END,e).emulateTransitionEnd(n)}else e()},e._clearTimeout=function(){clearTimeout(this._timeout),this._timeout=null},t._jQueryInterface=function(e){return this.each((function(){var n=o.default(this),i=n.data("bs.toast");if(i||(i=new t(this,"object"==typeof e&&e),n.data("bs.toast",i)),"string"==typeof e){if(void 0===i[e])throw new TypeError('No method named "'+e+'"');i[e](this)}}))},s(t,null,[{key:"VERSION",get:function(){return"4.6.1"}},{key:"DefaultType",get:function(){return mt}},{key:"Default",get:function(){return pt}}]),t}();o.default.fn[ct]=gt._jQueryInterface,o.default.fn[ct].Constructor=gt,o.default.fn[ct].noConflict=function(){return o.default.fn[ct]=ht,gt._jQueryInterface},t.Alert=h,t.Button=m,t.Carousel=E,t.Collapse=D,t.Dropdown=j,t.Modal=R,t.Popover=ot,t.Scrollspy=ut,t.Tab=dt,t.Toast=gt,t.Tooltip=G,t.Util=d,Object.defineProperty(t,"__esModule",{value:!0})}(e,n(0),n(1))},function(t,e){var n;n=function(){return this}();try{n=n||new Function("return this")()}catch(t){"object"==typeof window&&(n=window)}t.exports=n},,function(t,e,n){"use strict";n.r(e);n(0),n(2),n.p;$('[data-toggle="tooltip"]').tooltip({delay:{show:500,hide:100}})}]); \ No newline at end of file diff --git a/v0.10.x/_static/scripts/pydata-sphinx-theme.js b/v0.10.x/_static/scripts/pydata-sphinx-theme.js new file mode 100644 index 000000000..04d3cd802 --- /dev/null +++ b/v0.10.x/_static/scripts/pydata-sphinx-theme.js @@ -0,0 +1 @@ +!function(e){var t={};function o(n){if(t[n])return t[n].exports;var r=t[n]={i:n,l:!1,exports:{}};return e[n].call(r.exports,r,r.exports,o),r.l=!0,r.exports}o.m=e,o.c=t,o.d=function(e,t,n){o.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},o.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},o.t=function(e,t){if(1&t&&(e=o(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(o.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var r in e)o.d(n,r,function(t){return e[t]}.bind(null,r));return n},o.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return o.d(t,"a",t),t},o.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},o.p="",o(o.s=4)}([function(e,t){e.exports=jQuery},,,,function(e,t,o){"use strict";o.r(t);o(0),o.p;var n=window.matchMedia("(prefers-color-scheme: dark)");function r(e){document.documentElement.dataset.theme=n.matches?"dark":"light"}function a(e){"light"!==e&&"dark"!==e&&"auto"!==e&&(console.error(`Got invalid theme mode: ${e}. Resetting to auto.`),e="auto");var t=n.matches?"dark":"light";document.documentElement.dataset.mode=e;var o="auto"==e?t:e;document.documentElement.dataset.theme=o,localStorage.setItem("mode",e),localStorage.setItem("theme",o),console.log(`[PST]: Changed to ${e} mode using the ${o} theme.`),n.onchange="auto"==e?r:""}function c(){const e=document.documentElement.dataset.defaultMode||"auto",t=localStorage.getItem("mode")||e;var o,r,c=n.matches?["auto","light","dark"]:["auto","dark","light"];a(((r=(o=c).indexOf(t)+1)===o.length&&(r=0),o[r]))}var l=()=>{let e=document.querySelectorAll("form.bd-search");return e.length?(1==e.length?e[0]:document.querySelector("div:not(.search-button__search-container) > form.bd-search")).querySelector("input"):void 0},i=()=>{let e=l(),t=document.querySelector(".search-button__wrapper");e===t.querySelector("input")&&t.classList.toggle("show"),document.activeElement===e?e.blur():(e.focus(),e.select(),e.scrollIntoView({block:"center"}))};function d(e){const t=DOCUMENTATION_OPTIONS.pagename+".html",o=e.target.getAttribute("href");let n=o.replace(t,"");return $.ajax({type:"HEAD",url:o,success:function(){location.href=o}}).fail((function(){location.href=n})),!1}var s=document.querySelectorAll("version-switcher__button");s&&$.getJSON(DOCUMENTATION_OPTIONS.theme_switcher_json_url,(function(e,t,o){const n=DOCUMENTATION_OPTIONS.pagename+".html";s.forEach(e=>{e.dataset.activeVersionName="",e.dataset.activeVersion=""}),$.each(e,(function(e,t){"name"in t||(t.name=t.version);const o=document.createElement("span");o.textContent=""+t.name;const r=document.createElement("a");r.setAttribute("class","list-group-item list-group-item-action py-1"),r.setAttribute("href",`${t.url}${n}`),r.appendChild(o),r.onclick=d,r.dataset.versionName=t.name,r.dataset.version=t.version,$(".version-switcher__menu").append(r),"DOCUMENTATION_OPTIONS.version_switcher_version_match"==t.version&&(r.classList.add("active"),s.forEach(e=>{e.innerText=e.dataset.activeVersionName=t.name,e.dataset.activeVersion=t.version}))}))})),$((function(){a(document.documentElement.dataset.mode),document.querySelectorAll(".theme-switch-button").forEach(e=>{e.addEventListener("click",c)})})),$((function(){if(!document.getElementById("bd-docs-nav"))return;var e=document.querySelector("div.bd-sidebar");let t=parseInt(sessionStorage.getItem("sidebar-scroll-top"),10);if(isNaN(t)){var o=document.getElementById("bd-docs-nav").querySelectorAll(".active");if(o.length>0){var n=o[o.length-1],r=n.getBoundingClientRect().y-e.getBoundingClientRect().y;if(n.getBoundingClientRect().y>.5*window.innerHeight){let t=.25;e.scrollTop=r-e.clientHeight*t,console.log("[PST]: Scrolled sidebar using last active link...")}}}else e.scrollTop=t,console.log("[PST]: Scrolled sidebar using stored browser position...");window.addEventListener("beforeunload",()=>{sessionStorage.setItem("sidebar-scroll-top",e.scrollTop)})})),$((function(){$(window).on("activate.bs.scrollspy",(function(){document.querySelectorAll("#bd-toc-nav a").forEach(e=>{e.parentElement.classList.remove("active")});document.querySelectorAll("#bd-toc-nav a.active").forEach(e=>{e.parentElement.classList.add("active")})}))})),$(()=>{(()=>{let e=document.querySelectorAll("form.bd-search");window.navigator.platform.toUpperCase().indexOf("MAC")>=0&&e.forEach(e=>e.querySelector("kbd.kbd-shortcut__modifier").innerText="⌘")})(),window.addEventListener("keydown",e=>{let t=l();(e.ctrlKey||e.metaKey)&&"KeyK"==e.code?(e.preventDefault(),i()):document.activeElement===t&&"Escape"==e.code&&i()},!0),document.querySelectorAll(".search-button__button").forEach(e=>{e.onclick=i});let e=document.querySelector(".search-button__overlay");e&&(e.onclick=i)}),$((function(){new MutationObserver((e,t)=>{e.forEach(e=>{0!==e.addedNodes.length&&void 0!==e.addedNodes[0].data&&-1!=e.addedNodes[0].data.search("Inserted RTD Footer")&&e.addedNodes.forEach(e=>{document.getElementById("rtd-footer-container").append(e)})})}).observe(document.body,{childList:!0})}))}]); \ No newline at end of file diff --git a/v0.10.x/_static/searchtools.js b/v0.10.x/_static/searchtools.js new file mode 100644 index 000000000..7918c3fab --- /dev/null +++ b/v0.10.x/_static/searchtools.js @@ -0,0 +1,574 @@ +/* + * searchtools.js + * ~~~~~~~~~~~~~~~~ + * + * Sphinx JavaScript utilities for the full-text search. + * + * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ +"use strict"; + +/** + * Simple result scoring code. + */ +if (typeof Scorer === "undefined") { + var Scorer = { + // Implement the following function to further tweak the score for each result + // The function takes a result array [docname, title, anchor, descr, score, filename] + // and returns the new score. + /* + score: result => { + const [docname, title, anchor, descr, score, filename] = result + return score + }, + */ + + // query matches the full name of an object + objNameMatch: 11, + // or matches in the last dotted part of the object name + objPartialMatch: 6, + // Additive scores depending on the priority of the object + objPrio: { + 0: 15, // used to be importantResults + 1: 5, // used to be objectResults + 2: -5, // used to be unimportantResults + }, + // Used when the priority is not in the mapping. + objPrioDefault: 0, + + // query found in title + title: 15, + partialTitle: 7, + // query found in terms + term: 5, + partialTerm: 2, + }; +} + +const _removeChildren = (element) => { + while (element && element.lastChild) element.removeChild(element.lastChild); +}; + +/** + * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#escaping + */ +const _escapeRegExp = (string) => + string.replace(/[.*+\-?^${}()|[\]\\]/g, "\\$&"); // $& means the whole matched string + +const _displayItem = (item, searchTerms, highlightTerms) => { + const docBuilder = DOCUMENTATION_OPTIONS.BUILDER; + const docFileSuffix = DOCUMENTATION_OPTIONS.FILE_SUFFIX; + const docLinkSuffix = DOCUMENTATION_OPTIONS.LINK_SUFFIX; + const showSearchSummary = DOCUMENTATION_OPTIONS.SHOW_SEARCH_SUMMARY; + const contentRoot = document.documentElement.dataset.content_root; + + const [docName, title, anchor, descr, score, _filename] = item; + + let listItem = document.createElement("li"); + let requestUrl; + let linkUrl; + if (docBuilder === "dirhtml") { + // dirhtml builder + let dirname = docName + "/"; + if (dirname.match(/\/index\/$/)) + dirname = dirname.substring(0, dirname.length - 6); + else if (dirname === "index/") dirname = ""; + requestUrl = contentRoot + dirname; + linkUrl = requestUrl; + } else { + // normal html builders + requestUrl = contentRoot + docName + docFileSuffix; + linkUrl = docName + docLinkSuffix; + } + let linkEl = listItem.appendChild(document.createElement("a")); + linkEl.href = linkUrl + anchor; + linkEl.dataset.score = score; + linkEl.innerHTML = title; + if (descr) { + listItem.appendChild(document.createElement("span")).innerHTML = + " (" + descr + ")"; + // highlight search terms in the description + if (SPHINX_HIGHLIGHT_ENABLED) // set in sphinx_highlight.js + highlightTerms.forEach((term) => _highlightText(listItem, term, "highlighted")); + } + else if (showSearchSummary) + fetch(requestUrl) + .then((responseData) => responseData.text()) + .then((data) => { + if (data) + listItem.appendChild( + Search.makeSearchSummary(data, searchTerms) + ); + // highlight search terms in the summary + if (SPHINX_HIGHLIGHT_ENABLED) // set in sphinx_highlight.js + highlightTerms.forEach((term) => _highlightText(listItem, term, "highlighted")); + }); + Search.output.appendChild(listItem); +}; +const _finishSearch = (resultCount) => { + Search.stopPulse(); + Search.title.innerText = _("Search Results"); + if (!resultCount) + Search.status.innerText = Documentation.gettext( + "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories." + ); + else + Search.status.innerText = _( + `Search finished, found ${resultCount} page(s) matching the search query.` + ); +}; +const _displayNextItem = ( + results, + resultCount, + searchTerms, + highlightTerms, +) => { + // results left, load the summary and display it + // this is intended to be dynamic (don't sub resultsCount) + if (results.length) { + _displayItem(results.pop(), searchTerms, highlightTerms); + setTimeout( + () => _displayNextItem(results, resultCount, searchTerms, highlightTerms), + 5 + ); + } + // search finished, update title and status message + else _finishSearch(resultCount); +}; + +/** + * Default splitQuery function. Can be overridden in ``sphinx.search`` with a + * custom function per language. + * + * The regular expression works by splitting the string on consecutive characters + * that are not Unicode letters, numbers, underscores, or emoji characters. + * This is the same as ``\W+`` in Python, preserving the surrogate pair area. + */ +if (typeof splitQuery === "undefined") { + var splitQuery = (query) => query + .split(/[^\p{Letter}\p{Number}_\p{Emoji_Presentation}]+/gu) + .filter(term => term) // remove remaining empty strings +} + +/** + * Search Module + */ +const Search = { + _index: null, + _queued_query: null, + _pulse_status: -1, + + htmlToText: (htmlString) => { + const htmlElement = new DOMParser().parseFromString(htmlString, 'text/html'); + htmlElement.querySelectorAll(".headerlink").forEach((el) => { el.remove() }); + const docContent = htmlElement.querySelector('[role="main"]'); + if (docContent !== undefined) return docContent.textContent; + console.warn( + "Content block not found. Sphinx search tries to obtain it via '[role=main]'. Could you check your theme or template." + ); + return ""; + }, + + init: () => { + const query = new URLSearchParams(window.location.search).get("q"); + document + .querySelectorAll('input[name="q"]') + .forEach((el) => (el.value = query)); + if (query) Search.performSearch(query); + }, + + loadIndex: (url) => + (document.body.appendChild(document.createElement("script")).src = url), + + setIndex: (index) => { + Search._index = index; + if (Search._queued_query !== null) { + const query = Search._queued_query; + Search._queued_query = null; + Search.query(query); + } + }, + + hasIndex: () => Search._index !== null, + + deferQuery: (query) => (Search._queued_query = query), + + stopPulse: () => (Search._pulse_status = -1), + + startPulse: () => { + if (Search._pulse_status >= 0) return; + + const pulse = () => { + Search._pulse_status = (Search._pulse_status + 1) % 4; + Search.dots.innerText = ".".repeat(Search._pulse_status); + if (Search._pulse_status >= 0) window.setTimeout(pulse, 500); + }; + pulse(); + }, + + /** + * perform a search for something (or wait until index is loaded) + */ + performSearch: (query) => { + // create the required interface elements + const searchText = document.createElement("h2"); + searchText.textContent = _("Searching"); + const searchSummary = document.createElement("p"); + searchSummary.classList.add("search-summary"); + searchSummary.innerText = ""; + const searchList = document.createElement("ul"); + searchList.classList.add("search"); + + const out = document.getElementById("search-results"); + Search.title = out.appendChild(searchText); + Search.dots = Search.title.appendChild(document.createElement("span")); + Search.status = out.appendChild(searchSummary); + Search.output = out.appendChild(searchList); + + const searchProgress = document.getElementById("search-progress"); + // Some themes don't use the search progress node + if (searchProgress) { + searchProgress.innerText = _("Preparing search..."); + } + Search.startPulse(); + + // index already loaded, the browser was quick! + if (Search.hasIndex()) Search.query(query); + else Search.deferQuery(query); + }, + + /** + * execute search (requires search index to be loaded) + */ + query: (query) => { + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const titles = Search._index.titles; + const allTitles = Search._index.alltitles; + const indexEntries = Search._index.indexentries; + + // stem the search terms and add them to the correct list + const stemmer = new Stemmer(); + const searchTerms = new Set(); + const excludedTerms = new Set(); + const highlightTerms = new Set(); + const objectTerms = new Set(splitQuery(query.toLowerCase().trim())); + splitQuery(query.trim()).forEach((queryTerm) => { + const queryTermLower = queryTerm.toLowerCase(); + + // maybe skip this "word" + // stopwords array is from language_data.js + if ( + stopwords.indexOf(queryTermLower) !== -1 || + queryTerm.match(/^\d+$/) + ) + return; + + // stem the word + let word = stemmer.stemWord(queryTermLower); + // select the correct list + if (word[0] === "-") excludedTerms.add(word.substr(1)); + else { + searchTerms.add(word); + highlightTerms.add(queryTermLower); + } + }); + + if (SPHINX_HIGHLIGHT_ENABLED) { // set in sphinx_highlight.js + localStorage.setItem("sphinx_highlight_terms", [...highlightTerms].join(" ")) + } + + // console.debug("SEARCH: searching for:"); + // console.info("required: ", [...searchTerms]); + // console.info("excluded: ", [...excludedTerms]); + + // array of [docname, title, anchor, descr, score, filename] + let results = []; + _removeChildren(document.getElementById("search-progress")); + + const queryLower = query.toLowerCase(); + for (const [title, foundTitles] of Object.entries(allTitles)) { + if (title.toLowerCase().includes(queryLower) && (queryLower.length >= title.length/2)) { + for (const [file, id] of foundTitles) { + let score = Math.round(100 * queryLower.length / title.length) + results.push([ + docNames[file], + titles[file] !== title ? `${titles[file]} > ${title}` : title, + id !== null ? "#" + id : "", + null, + score, + filenames[file], + ]); + } + } + } + + // search for explicit entries in index directives + for (const [entry, foundEntries] of Object.entries(indexEntries)) { + if (entry.includes(queryLower) && (queryLower.length >= entry.length/2)) { + for (const [file, id] of foundEntries) { + let score = Math.round(100 * queryLower.length / entry.length) + results.push([ + docNames[file], + titles[file], + id ? "#" + id : "", + null, + score, + filenames[file], + ]); + } + } + } + + // lookup as object + objectTerms.forEach((term) => + results.push(...Search.performObjectSearch(term, objectTerms)) + ); + + // lookup as search terms in fulltext + results.push(...Search.performTermsSearch(searchTerms, excludedTerms)); + + // let the scorer override scores with a custom scoring function + if (Scorer.score) results.forEach((item) => (item[4] = Scorer.score(item))); + + // now sort the results by score (in opposite order of appearance, since the + // display function below uses pop() to retrieve items) and then + // alphabetically + results.sort((a, b) => { + const leftScore = a[4]; + const rightScore = b[4]; + if (leftScore === rightScore) { + // same score: sort alphabetically + const leftTitle = a[1].toLowerCase(); + const rightTitle = b[1].toLowerCase(); + if (leftTitle === rightTitle) return 0; + return leftTitle > rightTitle ? -1 : 1; // inverted is intentional + } + return leftScore > rightScore ? 1 : -1; + }); + + // remove duplicate search results + // note the reversing of results, so that in the case of duplicates, the highest-scoring entry is kept + let seen = new Set(); + results = results.reverse().reduce((acc, result) => { + let resultStr = result.slice(0, 4).concat([result[5]]).map(v => String(v)).join(','); + if (!seen.has(resultStr)) { + acc.push(result); + seen.add(resultStr); + } + return acc; + }, []); + + results = results.reverse(); + + // for debugging + //Search.lastresults = results.slice(); // a copy + // console.info("search results:", Search.lastresults); + + // print the results + _displayNextItem(results, results.length, searchTerms, highlightTerms); + }, + + /** + * search for object names + */ + performObjectSearch: (object, objectTerms) => { + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const objects = Search._index.objects; + const objNames = Search._index.objnames; + const titles = Search._index.titles; + + const results = []; + + const objectSearchCallback = (prefix, match) => { + const name = match[4] + const fullname = (prefix ? prefix + "." : "") + name; + const fullnameLower = fullname.toLowerCase(); + if (fullnameLower.indexOf(object) < 0) return; + + let score = 0; + const parts = fullnameLower.split("."); + + // check for different match types: exact matches of full name or + // "last name" (i.e. last dotted part) + if (fullnameLower === object || parts.slice(-1)[0] === object) + score += Scorer.objNameMatch; + else if (parts.slice(-1)[0].indexOf(object) > -1) + score += Scorer.objPartialMatch; // matches in last name + + const objName = objNames[match[1]][2]; + const title = titles[match[0]]; + + // If more than one term searched for, we require other words to be + // found in the name/title/description + const otherTerms = new Set(objectTerms); + otherTerms.delete(object); + if (otherTerms.size > 0) { + const haystack = `${prefix} ${name} ${objName} ${title}`.toLowerCase(); + if ( + [...otherTerms].some((otherTerm) => haystack.indexOf(otherTerm) < 0) + ) + return; + } + + let anchor = match[3]; + if (anchor === "") anchor = fullname; + else if (anchor === "-") anchor = objNames[match[1]][1] + "-" + fullname; + + const descr = objName + _(", in ") + title; + + // add custom score for some objects according to scorer + if (Scorer.objPrio.hasOwnProperty(match[2])) + score += Scorer.objPrio[match[2]]; + else score += Scorer.objPrioDefault; + + results.push([ + docNames[match[0]], + fullname, + "#" + anchor, + descr, + score, + filenames[match[0]], + ]); + }; + Object.keys(objects).forEach((prefix) => + objects[prefix].forEach((array) => + objectSearchCallback(prefix, array) + ) + ); + return results; + }, + + /** + * search for full-text terms in the index + */ + performTermsSearch: (searchTerms, excludedTerms) => { + // prepare search + const terms = Search._index.terms; + const titleTerms = Search._index.titleterms; + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const titles = Search._index.titles; + + const scoreMap = new Map(); + const fileMap = new Map(); + + // perform the search on the required terms + searchTerms.forEach((word) => { + const files = []; + const arr = [ + { files: terms[word], score: Scorer.term }, + { files: titleTerms[word], score: Scorer.title }, + ]; + // add support for partial matches + if (word.length > 2) { + const escapedWord = _escapeRegExp(word); + Object.keys(terms).forEach((term) => { + if (term.match(escapedWord) && !terms[word]) + arr.push({ files: terms[term], score: Scorer.partialTerm }); + }); + Object.keys(titleTerms).forEach((term) => { + if (term.match(escapedWord) && !titleTerms[word]) + arr.push({ files: titleTerms[word], score: Scorer.partialTitle }); + }); + } + + // no match but word was a required one + if (arr.every((record) => record.files === undefined)) return; + + // found search word in contents + arr.forEach((record) => { + if (record.files === undefined) return; + + let recordFiles = record.files; + if (recordFiles.length === undefined) recordFiles = [recordFiles]; + files.push(...recordFiles); + + // set score for the word in each file + recordFiles.forEach((file) => { + if (!scoreMap.has(file)) scoreMap.set(file, {}); + scoreMap.get(file)[word] = record.score; + }); + }); + + // create the mapping + files.forEach((file) => { + if (fileMap.has(file) && fileMap.get(file).indexOf(word) === -1) + fileMap.get(file).push(word); + else fileMap.set(file, [word]); + }); + }); + + // now check if the files don't contain excluded terms + const results = []; + for (const [file, wordList] of fileMap) { + // check if all requirements are matched + + // as search terms with length < 3 are discarded + const filteredTermCount = [...searchTerms].filter( + (term) => term.length > 2 + ).length; + if ( + wordList.length !== searchTerms.size && + wordList.length !== filteredTermCount + ) + continue; + + // ensure that none of the excluded terms is in the search result + if ( + [...excludedTerms].some( + (term) => + terms[term] === file || + titleTerms[term] === file || + (terms[term] || []).includes(file) || + (titleTerms[term] || []).includes(file) + ) + ) + break; + + // select one (max) score for the file. + const score = Math.max(...wordList.map((w) => scoreMap.get(file)[w])); + // add result to the result list + results.push([ + docNames[file], + titles[file], + "", + null, + score, + filenames[file], + ]); + } + return results; + }, + + /** + * helper function to return a node containing the + * search summary for a given text. keywords is a list + * of stemmed words. + */ + makeSearchSummary: (htmlText, keywords) => { + const text = Search.htmlToText(htmlText); + if (text === "") return null; + + const textLower = text.toLowerCase(); + const actualStartPosition = [...keywords] + .map((k) => textLower.indexOf(k.toLowerCase())) + .filter((i) => i > -1) + .slice(-1)[0]; + const startWithContext = Math.max(actualStartPosition - 120, 0); + + const top = startWithContext === 0 ? "" : "..."; + const tail = startWithContext + 240 < text.length ? "..." : ""; + + let summary = document.createElement("p"); + summary.classList.add("context"); + summary.textContent = top + text.substr(startWithContext, 240).trim() + tail; + + return summary; + }, +}; + +_ready(Search.init); diff --git a/v0.10.x/_static/sg_gallery-binder.css b/v0.10.x/_static/sg_gallery-binder.css new file mode 100644 index 000000000..420005d22 --- /dev/null +++ b/v0.10.x/_static/sg_gallery-binder.css @@ -0,0 +1,11 @@ +/* CSS for binder integration */ + +div.binder-badge { + margin: 1em auto; + vertical-align: middle; +} + +div.lite-badge { + margin: 1em auto; + vertical-align: middle; +} diff --git a/v0.10.x/_static/sg_gallery-dataframe.css b/v0.10.x/_static/sg_gallery-dataframe.css new file mode 100644 index 000000000..fac74c43b --- /dev/null +++ b/v0.10.x/_static/sg_gallery-dataframe.css @@ -0,0 +1,47 @@ +/* Pandas dataframe css */ +/* Taken from: https://github.com/spatialaudio/nbsphinx/blob/fb3ba670fc1ba5f54d4c487573dbc1b4ecf7e9ff/src/nbsphinx.py#L587-L619 */ +html[data-theme="light"] { + --sg-text-color: #000; + --sg-tr-odd-color: #f5f5f5; + --sg-tr-hover-color: rgba(66, 165, 245, 0.2); +} +html[data-theme="dark"] { + --sg-text-color: #fff; + --sg-tr-odd-color: #373737; + --sg-tr-hover-color: rgba(30, 81, 122, 0.2); +} + +table.dataframe { + border: none !important; + border-collapse: collapse; + border-spacing: 0; + border-color: transparent; + color: var(--sg-text-color); + font-size: 12px; + table-layout: fixed; + width: auto; +} +table.dataframe thead { + border-bottom: 1px solid var(--sg-text-color); + vertical-align: bottom; +} +table.dataframe tr, +table.dataframe th, +table.dataframe td { + text-align: right; + vertical-align: middle; + padding: 0.5em 0.5em; + line-height: normal; + white-space: normal; + max-width: none; + border: none; +} +table.dataframe th { + font-weight: bold; +} +table.dataframe tbody tr:nth-child(odd) { + background: var(--sg-tr-odd-color); +} +table.dataframe tbody tr:hover { + background: var(--sg-tr-hover-color); +} diff --git a/v0.10.x/_static/sg_gallery-rendered-html.css b/v0.10.x/_static/sg_gallery-rendered-html.css new file mode 100644 index 000000000..93dc2ffb0 --- /dev/null +++ b/v0.10.x/_static/sg_gallery-rendered-html.css @@ -0,0 +1,224 @@ +/* Adapted from notebook/static/style/style.min.css */ +html[data-theme="light"] { + --sg-text-color: #000; + --sg-background-color: #ffffff; + --sg-code-background-color: #eff0f1; + --sg-tr-hover-color: rgba(66, 165, 245, 0.2); + --sg-tr-odd-color: #f5f5f5; +} +html[data-theme="dark"] { + --sg-text-color: #fff; + --sg-background-color: #121212; + --sg-code-background-color: #2f2f30; + --sg-tr-hover-color: rgba(66, 165, 245, 0.2); + --sg-tr-odd-color: #1f1f1f; +} + +.rendered_html { + color: var(--sg-text-color); + /* any extras will just be numbers: */ +} +.rendered_html em { + font-style: italic; +} +.rendered_html strong { + font-weight: bold; +} +.rendered_html u { + text-decoration: underline; +} +.rendered_html :link { + text-decoration: underline; +} +.rendered_html :visited { + text-decoration: underline; +} +.rendered_html h1 { + font-size: 185.7%; + margin: 1.08em 0 0 0; + font-weight: bold; + line-height: 1.0; +} +.rendered_html h2 { + font-size: 157.1%; + margin: 1.27em 0 0 0; + font-weight: bold; + line-height: 1.0; +} +.rendered_html h3 { + font-size: 128.6%; + margin: 1.55em 0 0 0; + font-weight: bold; + line-height: 1.0; +} +.rendered_html h4 { + font-size: 100%; + margin: 2em 0 0 0; + font-weight: bold; + line-height: 1.0; +} +.rendered_html h5 { + font-size: 100%; + margin: 2em 0 0 0; + font-weight: bold; + line-height: 1.0; + font-style: italic; +} +.rendered_html h6 { + font-size: 100%; + margin: 2em 0 0 0; + font-weight: bold; + line-height: 1.0; + font-style: italic; +} +.rendered_html h1:first-child { + margin-top: 0.538em; +} +.rendered_html h2:first-child { + margin-top: 0.636em; +} +.rendered_html h3:first-child { + margin-top: 0.777em; +} +.rendered_html h4:first-child { + margin-top: 1em; +} +.rendered_html h5:first-child { + margin-top: 1em; +} +.rendered_html h6:first-child { + margin-top: 1em; +} +.rendered_html ul:not(.list-inline), +.rendered_html ol:not(.list-inline) { + padding-left: 2em; +} +.rendered_html ul { + list-style: disc; +} +.rendered_html ul ul { + list-style: square; + margin-top: 0; +} +.rendered_html ul ul ul { + list-style: circle; +} +.rendered_html ol { + list-style: decimal; +} +.rendered_html ol ol { + list-style: upper-alpha; + margin-top: 0; +} +.rendered_html ol ol ol { + list-style: lower-alpha; +} +.rendered_html ol ol ol ol { + list-style: lower-roman; +} +.rendered_html ol ol ol ol ol { + list-style: decimal; +} +.rendered_html * + ul { + margin-top: 1em; +} +.rendered_html * + ol { + margin-top: 1em; +} +.rendered_html hr { + color: var(--sg-text-color); + background-color: var(--sg-text-color); +} +.rendered_html pre { + margin: 1em 2em; + padding: 0px; + background-color: var(--sg-background-color); +} +.rendered_html code { + background-color: var(--sg-code-background-color); +} +.rendered_html p code { + padding: 1px 5px; +} +.rendered_html pre code { + background-color: var(--sg-background-color); +} +.rendered_html pre, +.rendered_html code { + border: 0; + color: var(--sg-text-color); + font-size: 100%; +} +.rendered_html blockquote { + margin: 1em 2em; +} +.rendered_html table { + margin-left: auto; + margin-right: auto; + border: none; + border-collapse: collapse; + border-spacing: 0; + color: var(--sg-text-color); + font-size: 12px; + table-layout: fixed; +} +.rendered_html thead { + border-bottom: 1px solid var(--sg-text-color); + vertical-align: bottom; +} +.rendered_html tr, +.rendered_html th, +.rendered_html td { + text-align: right; + vertical-align: middle; + padding: 0.5em 0.5em; + line-height: normal; + white-space: normal; + max-width: none; + border: none; +} +.rendered_html th { + font-weight: bold; +} +.rendered_html tbody tr:nth-child(odd) { + background: var(--sg-tr-odd-color); +} +.rendered_html tbody tr:hover { + color: var(--sg-text-color); + background: var(--sg-tr-hover-color); +} +.rendered_html * + table { + margin-top: 1em; +} +.rendered_html p { + text-align: left; +} +.rendered_html * + p { + margin-top: 1em; +} +.rendered_html img { + display: block; + margin-left: auto; + margin-right: auto; +} +.rendered_html * + img { + margin-top: 1em; +} +.rendered_html img, +.rendered_html svg { + max-width: 100%; + height: auto; +} +.rendered_html img.unconfined, +.rendered_html svg.unconfined { + max-width: none; +} +.rendered_html .alert { + margin-bottom: initial; +} +.rendered_html * + .alert { + margin-top: 1em; +} +[dir="rtl"] .rendered_html p { + text-align: right; +} diff --git a/v0.10.x/_static/sg_gallery.css b/v0.10.x/_static/sg_gallery.css new file mode 100644 index 000000000..72227837d --- /dev/null +++ b/v0.10.x/_static/sg_gallery.css @@ -0,0 +1,342 @@ +/* +Sphinx-Gallery has compatible CSS to fix default sphinx themes +Tested for Sphinx 1.3.1 for all themes: default, alabaster, sphinxdoc, +scrolls, agogo, traditional, nature, haiku, pyramid +Tested for Read the Docs theme 0.1.7 */ + +/* Define light colors */ +:root, html[data-theme="light"], body[data-theme="light"]{ + --sg-tooltip-foreground: black; + --sg-tooltip-background: rgba(250, 250, 250, 0.9); + --sg-tooltip-border: #ccc transparent; + --sg-thumb-box-shadow-color: #6c757d40; + --sg-thumb-hover-border: #0069d9; + --sg-script-out: #888; + --sg-script-pre: #fafae2; + --sg-pytb-foreground: #000; + --sg-pytb-background: #ffe4e4; + --sg-pytb-border-color: #f66; + --sg-download-a-background-color: #ffc; + --sg-download-a-background-image: linear-gradient(to bottom, #ffc, #d5d57e); + --sg-download-a-border-color: 1px solid #c2c22d; + --sg-download-a-color: #000; + --sg-download-a-hover-background-color: #d5d57e; + --sg-download-a-hover-box-shadow-1: rgba(255, 255, 255, 0.1); + --sg-download-a-hover-box-shadow-2: rgba(0, 0, 0, 0.25); +} +@media(prefers-color-scheme: light) { + :root[data-theme="auto"], html[data-theme="auto"], body[data-theme="auto"] { + --sg-tooltip-foreground: black; + --sg-tooltip-background: rgba(250, 250, 250, 0.9); + --sg-tooltip-border: #ccc transparent; + --sg-thumb-box-shadow-color: #6c757d40; + --sg-thumb-hover-border: #0069d9; + --sg-script-out: #888; + --sg-script-pre: #fafae2; + --sg-pytb-foreground: #000; + --sg-pytb-background: #ffe4e4; + --sg-pytb-border-color: #f66; + --sg-download-a-background-color: #ffc; + --sg-download-a-background-image: linear-gradient(to bottom, #ffc, #d5d57e); + --sg-download-a-border-color: 1px solid #c2c22d; + --sg-download-a-color: #000; + --sg-download-a-hover-background-color: #d5d57e; + --sg-download-a-hover-box-shadow-1: rgba(255, 255, 255, 0.1); + --sg-download-a-hover-box-shadow-2: rgba(0, 0, 0, 0.25); + } +} + +html[data-theme="dark"], body[data-theme="dark"] { + --sg-tooltip-foreground: white; + --sg-tooltip-background: rgba(10, 10, 10, 0.9); + --sg-tooltip-border: #333 transparent; + --sg-thumb-box-shadow-color: #79848d40; + --sg-thumb-hover-border: #003975; + --sg-script-out: rgb(179, 179, 179); + --sg-script-pre: #2e2e22; + --sg-pytb-foreground: #fff; + --sg-pytb-background: #1b1717; + --sg-pytb-border-color: #622; + --sg-download-a-background-color: #443; + --sg-download-a-background-image: linear-gradient(to bottom, #443, #221); + --sg-download-a-border-color: 1px solid #3a3a0d; + --sg-download-a-color: #fff; + --sg-download-a-hover-background-color: #616135; + --sg-download-a-hover-box-shadow-1: rgba(0, 0, 0, 0.1); + --sg-download-a-hover-box-shadow-2: rgba(255, 255, 255, 0.25); +} +@media(prefers-color-scheme: dark){ + html[data-theme="auto"], body[data-theme="auto"] { + --sg-tooltip-foreground: white; + --sg-tooltip-background: rgba(10, 10, 10, 0.9); + --sg-tooltip-border: #333 transparent; + --sg-thumb-box-shadow-color: #79848d40; + --sg-thumb-hover-border: #003975; + --sg-script-out: rgb(179, 179, 179); + --sg-script-pre: #2e2e22; + --sg-pytb-foreground: #fff; + --sg-pytb-background: #1b1717; + --sg-pytb-border-color: #622; + --sg-download-a-background-color: #443; + --sg-download-a-background-image: linear-gradient(to bottom, #443, #221); + --sg-download-a-border-color: 1px solid #3a3a0d; + --sg-download-a-color: #fff; + --sg-download-a-hover-background-color: #616135; + --sg-download-a-hover-box-shadow-1: rgba(0, 0, 0, 0.1); + --sg-download-a-hover-box-shadow-2: rgba(255, 255, 255, 0.25); + } +} + +.sphx-glr-thumbnails { + width: 100%; + margin: 0px 0px 20px 0px; + + /* align thumbnails on a grid */ + justify-content: space-between; + display: grid; + /* each grid column should be at least 160px (this will determine + the actual number of columns) and then take as much of the + remaining width as possible */ + grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); + gap: 15px; +} +.sphx-glr-thumbnails .toctree-wrapper { + /* hide empty toctree divs added to the DOM + by sphinx even though the toctree is hidden + (they would fill grid places with empty divs) */ + display: none; +} +.sphx-glr-thumbcontainer { + background: transparent; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + border-radius: 5px; + box-shadow: 0 0 10px var(--sg-thumb-box-shadow-color); + + /* useful to absolutely position link in div */ + position: relative; + + /* thumbnail width should include padding and borders + and take all available space */ + box-sizing: border-box; + width: 100%; + padding: 10px; + border: 1px solid transparent; + + /* align content in thumbnail */ + display: flex; + flex-direction: column; + align-items: center; + gap: 7px; +} +.sphx-glr-thumbcontainer p { + position: absolute; + top: 0; + left: 0; +} +.sphx-glr-thumbcontainer p, +.sphx-glr-thumbcontainer p a { + /* link should cover the whole thumbnail div */ + width: 100%; + height: 100%; +} +.sphx-glr-thumbcontainer p a span { + /* text within link should be masked + (we are just interested in the href) */ + display: none; +} +.sphx-glr-thumbcontainer:hover { + border: 1px solid; + border-color: var(--sg-thumb-hover-border); + cursor: pointer; +} +.sphx-glr-thumbcontainer a.internal { + bottom: 0; + display: block; + left: 0; + box-sizing: border-box; + padding: 150px 10px 0; + position: absolute; + right: 0; + top: 0; +} +/* Next one is to avoid Sphinx traditional theme to cover all the +thumbnail with its default link Background color */ +.sphx-glr-thumbcontainer a.internal:hover { + background-color: transparent; +} + +.sphx-glr-thumbcontainer p { + margin: 0 0 0.1em 0; +} +.sphx-glr-thumbcontainer .figure { + margin: 10px; + width: 160px; +} +.sphx-glr-thumbcontainer img { + display: inline; + max-height: 112px; + max-width: 160px; +} +.sphx-glr-thumbcontainer[tooltip]:hover:after { + background: var(--sg-tooltip-background); + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + color: var(--sg-tooltip-foreground); + content: attr(tooltip); + padding: 10px; + z-index: 98; + width: 100%; + height: 100%; + position: absolute; + pointer-events: none; + top: 0; + box-sizing: border-box; + overflow: hidden; + backdrop-filter: blur(3px); +} + +.sphx-glr-script-out { + color: var(--sg-script-out); + display: flex; + gap: 0.5em; +} +.sphx-glr-script-out::before { + content: "Out:"; + /* These numbers come from the pre style in the pydata sphinx theme. This + * turns out to match perfectly on the rtd theme, but be a bit too low for + * the pydata sphinx theme. As I could not find a dimension to use that was + * scaled the same way, I just picked one option that worked pretty close for + * both. */ + line-height: 1.4; + padding-top: 10px; +} +.sphx-glr-script-out .highlight { + background-color: transparent; + /* These options make the div expand... */ + flex-grow: 1; + /* ... but also keep it from overflowing its flex container. */ + overflow: auto; +} +.sphx-glr-script-out .highlight pre { + background-color: var(--sg-script-pre); + border: 0; + max-height: 30em; + overflow: auto; + padding-left: 1ex; + /* This margin is necessary in the pydata sphinx theme because pre has a box + * shadow which would be clipped by the overflow:auto in the parent div + * above. */ + margin: 2px; + word-break: break-word; +} +.sphx-glr-script-out + p { + margin-top: 1.8em; +} +blockquote.sphx-glr-script-out { + margin-left: 0pt; +} +.sphx-glr-script-out.highlight-pytb .highlight pre { + color: var(--sg-pytb-foreground); + background-color: var(--sg-pytb-background); + border: 1px solid var(--sg-pytb-border-color); + margin-top: 10px; + padding: 7px; +} + +div.sphx-glr-footer { + text-align: center; +} + +div.sphx-glr-download { + margin: 1em auto; + vertical-align: middle; +} + +div.sphx-glr-download a { + background-color: var(--sg-download-a-background-color); + background-image: var(--sg-download-a-background-image); + border-radius: 4px; + border: 1px solid var(--sg-download-a-border-color); + color: var(--sg-download-a-color); + display: inline-block; + font-weight: bold; + padding: 1ex; + text-align: center; +} + +div.sphx-glr-download code.download { + display: inline-block; + white-space: normal; + word-break: normal; + overflow-wrap: break-word; + /* border and background are given by the enclosing 'a' */ + border: none; + background: none; +} + +div.sphx-glr-download a:hover { + box-shadow: inset 0 1px 0 var(--sg-download-a-hover-box-shadow-1), 0 1px 5px var(--sg-download-a-hover-box-shadow-2); + text-decoration: none; + background-image: none; + background-color: var(--sg-download-a-hover-background-color); +} + +.sphx-glr-example-title:target::before { + display: block; + content: ""; + margin-top: -50px; + height: 50px; + visibility: hidden; +} + +ul.sphx-glr-horizontal { + list-style: none; + padding: 0; +} +ul.sphx-glr-horizontal li { + display: inline; +} +ul.sphx-glr-horizontal img { + height: auto !important; +} + +.sphx-glr-single-img { + margin: auto; + display: block; + max-width: 100%; +} + +.sphx-glr-multi-img { + max-width: 42%; + height: auto; +} + +div.sphx-glr-animation { + margin: auto; + display: block; + max-width: 100%; +} +div.sphx-glr-animation .animation { + display: block; +} + +p.sphx-glr-signature a.reference.external { + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + border-radius: 5px; + padding: 3px; + font-size: 75%; + text-align: right; + margin-left: auto; + display: table; +} + +.sphx-glr-clear { + clear: both; +} + +a.sphx-glr-backref-instance { + text-decoration: none; +} diff --git a/v0.10.x/_static/sphinx_highlight.js b/v0.10.x/_static/sphinx_highlight.js new file mode 100644 index 000000000..8a96c69a1 --- /dev/null +++ b/v0.10.x/_static/sphinx_highlight.js @@ -0,0 +1,154 @@ +/* Highlighting utilities for Sphinx HTML documentation. */ +"use strict"; + +const SPHINX_HIGHLIGHT_ENABLED = true + +/** + * highlight a given string on a node by wrapping it in + * span elements with the given class name. + */ +const _highlight = (node, addItems, text, className) => { + if (node.nodeType === Node.TEXT_NODE) { + const val = node.nodeValue; + const parent = node.parentNode; + const pos = val.toLowerCase().indexOf(text); + if ( + pos >= 0 && + !parent.classList.contains(className) && + !parent.classList.contains("nohighlight") + ) { + let span; + + const closestNode = parent.closest("body, svg, foreignObject"); + const isInSVG = closestNode && closestNode.matches("svg"); + if (isInSVG) { + span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); + } else { + span = document.createElement("span"); + span.classList.add(className); + } + + span.appendChild(document.createTextNode(val.substr(pos, text.length))); + const rest = document.createTextNode(val.substr(pos + text.length)); + parent.insertBefore( + span, + parent.insertBefore( + rest, + node.nextSibling + ) + ); + node.nodeValue = val.substr(0, pos); + /* There may be more occurrences of search term in this node. So call this + * function recursively on the remaining fragment. + */ + _highlight(rest, addItems, text, className); + + if (isInSVG) { + const rect = document.createElementNS( + "http://www.w3.org/2000/svg", + "rect" + ); + const bbox = parent.getBBox(); + rect.x.baseVal.value = bbox.x; + rect.y.baseVal.value = bbox.y; + rect.width.baseVal.value = bbox.width; + rect.height.baseVal.value = bbox.height; + rect.setAttribute("class", className); + addItems.push({ parent: parent, target: rect }); + } + } + } else if (node.matches && !node.matches("button, select, textarea")) { + node.childNodes.forEach((el) => _highlight(el, addItems, text, className)); + } +}; +const _highlightText = (thisNode, text, className) => { + let addItems = []; + _highlight(thisNode, addItems, text, className); + addItems.forEach((obj) => + obj.parent.insertAdjacentElement("beforebegin", obj.target) + ); +}; + +/** + * Small JavaScript module for the documentation. + */ +const SphinxHighlight = { + + /** + * highlight the search words provided in localstorage in the text + */ + highlightSearchWords: () => { + if (!SPHINX_HIGHLIGHT_ENABLED) return; // bail if no highlight + + // get and clear terms from localstorage + const url = new URL(window.location); + const highlight = + localStorage.getItem("sphinx_highlight_terms") + || url.searchParams.get("highlight") + || ""; + localStorage.removeItem("sphinx_highlight_terms") + url.searchParams.delete("highlight"); + window.history.replaceState({}, "", url); + + // get individual terms from highlight string + const terms = highlight.toLowerCase().split(/\s+/).filter(x => x); + if (terms.length === 0) return; // nothing to do + + // There should never be more than one element matching "div.body" + const divBody = document.querySelectorAll("div.body"); + const body = divBody.length ? divBody[0] : document.querySelector("body"); + window.setTimeout(() => { + terms.forEach((term) => _highlightText(body, term, "highlighted")); + }, 10); + + const searchBox = document.getElementById("searchbox"); + if (searchBox === null) return; + searchBox.appendChild( + document + .createRange() + .createContextualFragment( + '" + ) + ); + }, + + /** + * helper function to hide the search marks again + */ + hideSearchWords: () => { + document + .querySelectorAll("#searchbox .highlight-link") + .forEach((el) => el.remove()); + document + .querySelectorAll("span.highlighted") + .forEach((el) => el.classList.remove("highlighted")); + localStorage.removeItem("sphinx_highlight_terms") + }, + + initEscapeListener: () => { + // only install a listener if it is really needed + if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) return; + + document.addEventListener("keydown", (event) => { + // bail for input elements + if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return; + // bail with special keys + if (event.shiftKey || event.altKey || event.ctrlKey || event.metaKey) return; + if (DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS && (event.key === "Escape")) { + SphinxHighlight.hideSearchWords(); + event.preventDefault(); + } + }); + }, +}; + +_ready(() => { + /* Do not call highlightSearchWords() when we are on the search page. + * It will highlight words from the *previous* search query. + */ + if (typeof Search === "undefined") SphinxHighlight.highlightSearchWords(); + SphinxHighlight.initEscapeListener(); +}); diff --git a/v0.10.x/_static/styles/bootstrap.css b/v0.10.x/_static/styles/bootstrap.css new file mode 100644 index 000000000..034bf60e8 --- /dev/null +++ b/v0.10.x/_static/styles/bootstrap.css @@ -0,0 +1,6 @@ +/*! + * Bootstrap v4.6.1 (https://getbootstrap.com/) + * Copyright 2011-2021 The Bootstrap Authors + * Copyright 2011-2021 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + */:root{--blue:#007bff;--indigo:#6610f2;--purple:#6f42c1;--pink:#e83e8c;--red:#dc3545;--orange:#fd7e14;--yellow:#ffc107;--green:#28a745;--teal:#20c997;--cyan:#17a2b8;--white:#fff;--gray:#6c757d;--gray-dark:#343a40;--primary:#007bff;--secondary:#6c757d;--success:#28a745;--info:#17a2b8;--warning:#ffc107;--danger:#dc3545;--light:#f8f9fa;--dark:#343a40;--breakpoint-xs:0;--breakpoint-sm:540px;--breakpoint-md:720px;--breakpoint-lg:960px;--breakpoint-xl:1200px;--font-family-sans-serif:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans","Liberation Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";--font-family-monospace:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace}*,:after,:before{box-sizing:border-box}html{-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:rgba(0,0,0,0);font-family:sans-serif;line-height:1.15}article,aside,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}body{background-color:#fff;color:#212529;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,Liberation Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;font-size:1rem;font-weight:400;line-height:1.5;margin:0;text-align:left}[tabindex="-1"]:focus:not(:focus-visible){outline:0!important}hr{box-sizing:content-box;height:0;overflow:visible}h1,h2,h3,h4,h5,h6{margin-bottom:.5rem;margin-top:0}p{margin-bottom:1rem;margin-top:0}abbr[data-original-title],abbr[title]{border-bottom:0;cursor:help;text-decoration:underline;text-decoration:underline dotted;text-decoration-skip-ink:none}address{font-style:normal;line-height:inherit}address,dl,ol,ul{margin-bottom:1rem}dl,ol,ul{margin-top:0}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{background-color:transparent;color:#007bff;text-decoration:none}a:hover{color:#0056b3;text-decoration:underline}a:not([href]):not([class]),a:not([href]):not([class]):hover{color:inherit;text-decoration:none}code,kbd,pre,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:1em}pre{-ms-overflow-style:scrollbar;margin-bottom:1rem;margin-top:0;overflow:auto}figure{margin:0 0 1rem}img{border-style:none}img,svg{vertical-align:middle}svg{overflow:hidden}table{border-collapse:collapse}caption{caption-side:bottom;color:#6c757d;padding-bottom:.75rem;padding-top:.75rem;text-align:left}th{text-align:inherit;text-align:-webkit-match-parent}label{display:inline-block;margin-bottom:.5rem}button{border-radius:0}button:focus:not(:focus-visible){outline:0}button,input,optgroup,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit;margin:0}button,input{overflow:visible}button,select{text-transform:none}[role=button]{cursor:pointer}select{word-wrap:normal}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled),button:not(:disabled){cursor:pointer}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}textarea{overflow:auto;resize:vertical}fieldset{border:0;margin:0;min-width:0;padding:0}legend{color:inherit;display:block;font-size:1.5rem;line-height:inherit;margin-bottom:.5rem;max-width:100%;padding:0;white-space:normal;width:100%}progress{vertical-align:baseline}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:none;outline-offset:-2px}[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}output{display:inline-block}summary{cursor:pointer;display:list-item}template{display:none}[hidden]{display:none!important}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{font-weight:500;line-height:1.2;margin-bottom:.5rem}.h1,h1{font-size:2.5rem}.h2,h2{font-size:2rem}.h3,h3{font-size:1.75rem}.h4,h4{font-size:1.5rem}.h5,h5{font-size:1.25rem}.h6,h6{font-size:1rem}.lead{font-size:1.25rem;font-weight:300}.display-1{font-size:6rem}.display-1,.display-2{font-weight:300;line-height:1.2}.display-2{font-size:5.5rem}.display-3{font-size:4.5rem}.display-3,.display-4{font-weight:300;line-height:1.2}.display-4{font-size:3.5rem}hr{border:0;border-top:1px solid rgba(0,0,0,.1);margin-bottom:1rem;margin-top:1rem}.small,small{font-size:80%;font-weight:400}.mark,mark{background-color:#fcf8e3;padding:.2em}.list-inline,.list-unstyled{list-style:none;padding-left:0}.list-inline-item{display:inline-block}.list-inline-item:not(:last-child){margin-right:.5rem}.initialism{font-size:90%;text-transform:uppercase}.blockquote{font-size:1.25rem;margin-bottom:1rem}.blockquote-footer{color:#6c757d;display:block;font-size:80%}.blockquote-footer:before{content:"\2014\00A0"}.img-fluid,.img-thumbnail{height:auto;max-width:100%}.img-thumbnail{background-color:#fff;border:1px solid #dee2e6;border-radius:.25rem;padding:.25rem}.figure{display:inline-block}.figure-img{line-height:1;margin-bottom:.5rem}.figure-caption{color:#6c757d;font-size:90%}code{word-wrap:break-word;color:#e83e8c;font-size:87.5%}a>code{color:inherit}kbd{background-color:#212529;border-radius:.2rem;color:#fff;font-size:87.5%;padding:.2rem .4rem}kbd kbd{font-size:100%;font-weight:700;padding:0}pre{color:#212529;display:block;font-size:87.5%}pre code{color:inherit;font-size:inherit;word-break:normal}.pre-scrollable{max-height:340px;overflow-y:scroll}.container,.container-fluid,.container-lg,.container-md,.container-sm,.container-xl{margin-left:auto;margin-right:auto;padding-left:15px;padding-right:15px;width:100%}@media (min-width:540px){.container,.container-sm{max-width:540px}}@media (min-width:720px){.container,.container-md,.container-sm{max-width:720px}}@media (min-width:960px){.container,.container-lg,.container-md,.container-sm{max-width:960px}}@media (min-width:1200px){.container,.container-lg,.container-md,.container-sm,.container-xl{max-width:1400px}}.row{display:flex;flex-wrap:wrap;margin-left:-15px;margin-right:-15px}.no-gutters{margin-left:0;margin-right:0}.no-gutters>.col,.no-gutters>[class*=col-]{padding-left:0;padding-right:0}.col,.col-1,.col-10,.col-11,.col-12,.col-2,.col-3,.col-4,.col-5,.col-6,.col-7,.col-8,.col-9,.col-auto,.col-lg,.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-auto,.col-md,.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-auto,.col-sm,.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-auto,.col-xl,.col-xl-1,.col-xl-10,.col-xl-11,.col-xl-12,.col-xl-2,.col-xl-3,.col-xl-4,.col-xl-5,.col-xl-6,.col-xl-7,.col-xl-8,.col-xl-9,.col-xl-auto{padding-left:15px;padding-right:15px;position:relative;width:100%}.col{flex-basis:0;flex-grow:1;max-width:100%}.row-cols-1>*{flex:0 0 100%;max-width:100%}.row-cols-2>*{flex:0 0 50%;max-width:50%}.row-cols-3>*{flex:0 0 33.33333%;max-width:33.33333%}.row-cols-4>*{flex:0 0 25%;max-width:25%}.row-cols-5>*{flex:0 0 20%;max-width:20%}.row-cols-6>*{flex:0 0 16.66667%;max-width:16.66667%}.col-auto{flex:0 0 auto;max-width:100%;width:auto}.col-1{flex:0 0 8.33333%;max-width:8.33333%}.col-2{flex:0 0 16.66667%;max-width:16.66667%}.col-3{flex:0 0 25%;max-width:25%}.col-4{flex:0 0 33.33333%;max-width:33.33333%}.col-5{flex:0 0 41.66667%;max-width:41.66667%}.col-6{flex:0 0 50%;max-width:50%}.col-7{flex:0 0 58.33333%;max-width:58.33333%}.col-8{flex:0 0 66.66667%;max-width:66.66667%}.col-9{flex:0 0 75%;max-width:75%}.col-10{flex:0 0 83.33333%;max-width:83.33333%}.col-11{flex:0 0 91.66667%;max-width:91.66667%}.col-12{flex:0 0 100%;max-width:100%}.order-first{order:-1}.order-last{order:13}.order-0{order:0}.order-1{order:1}.order-2{order:2}.order-3{order:3}.order-4{order:4}.order-5{order:5}.order-6{order:6}.order-7{order:7}.order-8{order:8}.order-9{order:9}.order-10{order:10}.order-11{order:11}.order-12{order:12}.offset-1{margin-left:8.33333%}.offset-2{margin-left:16.66667%}.offset-3{margin-left:25%}.offset-4{margin-left:33.33333%}.offset-5{margin-left:41.66667%}.offset-6{margin-left:50%}.offset-7{margin-left:58.33333%}.offset-8{margin-left:66.66667%}.offset-9{margin-left:75%}.offset-10{margin-left:83.33333%}.offset-11{margin-left:91.66667%}@media (min-width:540px){.col-sm{flex-basis:0;flex-grow:1;max-width:100%}.row-cols-sm-1>*{flex:0 0 100%;max-width:100%}.row-cols-sm-2>*{flex:0 0 50%;max-width:50%}.row-cols-sm-3>*{flex:0 0 33.33333%;max-width:33.33333%}.row-cols-sm-4>*{flex:0 0 25%;max-width:25%}.row-cols-sm-5>*{flex:0 0 20%;max-width:20%}.row-cols-sm-6>*{flex:0 0 16.66667%;max-width:16.66667%}.col-sm-auto{flex:0 0 auto;max-width:100%;width:auto}.col-sm-1{flex:0 0 8.33333%;max-width:8.33333%}.col-sm-2{flex:0 0 16.66667%;max-width:16.66667%}.col-sm-3{flex:0 0 25%;max-width:25%}.col-sm-4{flex:0 0 33.33333%;max-width:33.33333%}.col-sm-5{flex:0 0 41.66667%;max-width:41.66667%}.col-sm-6{flex:0 0 50%;max-width:50%}.col-sm-7{flex:0 0 58.33333%;max-width:58.33333%}.col-sm-8{flex:0 0 66.66667%;max-width:66.66667%}.col-sm-9{flex:0 0 75%;max-width:75%}.col-sm-10{flex:0 0 83.33333%;max-width:83.33333%}.col-sm-11{flex:0 0 91.66667%;max-width:91.66667%}.col-sm-12{flex:0 0 100%;max-width:100%}.order-sm-first{order:-1}.order-sm-last{order:13}.order-sm-0{order:0}.order-sm-1{order:1}.order-sm-2{order:2}.order-sm-3{order:3}.order-sm-4{order:4}.order-sm-5{order:5}.order-sm-6{order:6}.order-sm-7{order:7}.order-sm-8{order:8}.order-sm-9{order:9}.order-sm-10{order:10}.order-sm-11{order:11}.order-sm-12{order:12}.offset-sm-0{margin-left:0}.offset-sm-1{margin-left:8.33333%}.offset-sm-2{margin-left:16.66667%}.offset-sm-3{margin-left:25%}.offset-sm-4{margin-left:33.33333%}.offset-sm-5{margin-left:41.66667%}.offset-sm-6{margin-left:50%}.offset-sm-7{margin-left:58.33333%}.offset-sm-8{margin-left:66.66667%}.offset-sm-9{margin-left:75%}.offset-sm-10{margin-left:83.33333%}.offset-sm-11{margin-left:91.66667%}}@media (min-width:720px){.col-md{flex-basis:0;flex-grow:1;max-width:100%}.row-cols-md-1>*{flex:0 0 100%;max-width:100%}.row-cols-md-2>*{flex:0 0 50%;max-width:50%}.row-cols-md-3>*{flex:0 0 33.33333%;max-width:33.33333%}.row-cols-md-4>*{flex:0 0 25%;max-width:25%}.row-cols-md-5>*{flex:0 0 20%;max-width:20%}.row-cols-md-6>*{flex:0 0 16.66667%;max-width:16.66667%}.col-md-auto{flex:0 0 auto;max-width:100%;width:auto}.col-md-1{flex:0 0 8.33333%;max-width:8.33333%}.col-md-2{flex:0 0 16.66667%;max-width:16.66667%}.col-md-3{flex:0 0 25%;max-width:25%}.col-md-4{flex:0 0 33.33333%;max-width:33.33333%}.col-md-5{flex:0 0 41.66667%;max-width:41.66667%}.col-md-6{flex:0 0 50%;max-width:50%}.col-md-7{flex:0 0 58.33333%;max-width:58.33333%}.col-md-8{flex:0 0 66.66667%;max-width:66.66667%}.col-md-9{flex:0 0 75%;max-width:75%}.col-md-10{flex:0 0 83.33333%;max-width:83.33333%}.col-md-11{flex:0 0 91.66667%;max-width:91.66667%}.col-md-12{flex:0 0 100%;max-width:100%}.order-md-first{order:-1}.order-md-last{order:13}.order-md-0{order:0}.order-md-1{order:1}.order-md-2{order:2}.order-md-3{order:3}.order-md-4{order:4}.order-md-5{order:5}.order-md-6{order:6}.order-md-7{order:7}.order-md-8{order:8}.order-md-9{order:9}.order-md-10{order:10}.order-md-11{order:11}.order-md-12{order:12}.offset-md-0{margin-left:0}.offset-md-1{margin-left:8.33333%}.offset-md-2{margin-left:16.66667%}.offset-md-3{margin-left:25%}.offset-md-4{margin-left:33.33333%}.offset-md-5{margin-left:41.66667%}.offset-md-6{margin-left:50%}.offset-md-7{margin-left:58.33333%}.offset-md-8{margin-left:66.66667%}.offset-md-9{margin-left:75%}.offset-md-10{margin-left:83.33333%}.offset-md-11{margin-left:91.66667%}}@media (min-width:960px){.col-lg{flex-basis:0;flex-grow:1;max-width:100%}.row-cols-lg-1>*{flex:0 0 100%;max-width:100%}.row-cols-lg-2>*{flex:0 0 50%;max-width:50%}.row-cols-lg-3>*{flex:0 0 33.33333%;max-width:33.33333%}.row-cols-lg-4>*{flex:0 0 25%;max-width:25%}.row-cols-lg-5>*{flex:0 0 20%;max-width:20%}.row-cols-lg-6>*{flex:0 0 16.66667%;max-width:16.66667%}.col-lg-auto{flex:0 0 auto;max-width:100%;width:auto}.col-lg-1{flex:0 0 8.33333%;max-width:8.33333%}.col-lg-2{flex:0 0 16.66667%;max-width:16.66667%}.col-lg-3{flex:0 0 25%;max-width:25%}.col-lg-4{flex:0 0 33.33333%;max-width:33.33333%}.col-lg-5{flex:0 0 41.66667%;max-width:41.66667%}.col-lg-6{flex:0 0 50%;max-width:50%}.col-lg-7{flex:0 0 58.33333%;max-width:58.33333%}.col-lg-8{flex:0 0 66.66667%;max-width:66.66667%}.col-lg-9{flex:0 0 75%;max-width:75%}.col-lg-10{flex:0 0 83.33333%;max-width:83.33333%}.col-lg-11{flex:0 0 91.66667%;max-width:91.66667%}.col-lg-12{flex:0 0 100%;max-width:100%}.order-lg-first{order:-1}.order-lg-last{order:13}.order-lg-0{order:0}.order-lg-1{order:1}.order-lg-2{order:2}.order-lg-3{order:3}.order-lg-4{order:4}.order-lg-5{order:5}.order-lg-6{order:6}.order-lg-7{order:7}.order-lg-8{order:8}.order-lg-9{order:9}.order-lg-10{order:10}.order-lg-11{order:11}.order-lg-12{order:12}.offset-lg-0{margin-left:0}.offset-lg-1{margin-left:8.33333%}.offset-lg-2{margin-left:16.66667%}.offset-lg-3{margin-left:25%}.offset-lg-4{margin-left:33.33333%}.offset-lg-5{margin-left:41.66667%}.offset-lg-6{margin-left:50%}.offset-lg-7{margin-left:58.33333%}.offset-lg-8{margin-left:66.66667%}.offset-lg-9{margin-left:75%}.offset-lg-10{margin-left:83.33333%}.offset-lg-11{margin-left:91.66667%}}@media (min-width:1200px){.col-xl{flex-basis:0;flex-grow:1;max-width:100%}.row-cols-xl-1>*{flex:0 0 100%;max-width:100%}.row-cols-xl-2>*{flex:0 0 50%;max-width:50%}.row-cols-xl-3>*{flex:0 0 33.33333%;max-width:33.33333%}.row-cols-xl-4>*{flex:0 0 25%;max-width:25%}.row-cols-xl-5>*{flex:0 0 20%;max-width:20%}.row-cols-xl-6>*{flex:0 0 16.66667%;max-width:16.66667%}.col-xl-auto{flex:0 0 auto;max-width:100%;width:auto}.col-xl-1{flex:0 0 8.33333%;max-width:8.33333%}.col-xl-2{flex:0 0 16.66667%;max-width:16.66667%}.col-xl-3{flex:0 0 25%;max-width:25%}.col-xl-4{flex:0 0 33.33333%;max-width:33.33333%}.col-xl-5{flex:0 0 41.66667%;max-width:41.66667%}.col-xl-6{flex:0 0 50%;max-width:50%}.col-xl-7{flex:0 0 58.33333%;max-width:58.33333%}.col-xl-8{flex:0 0 66.66667%;max-width:66.66667%}.col-xl-9{flex:0 0 75%;max-width:75%}.col-xl-10{flex:0 0 83.33333%;max-width:83.33333%}.col-xl-11{flex:0 0 91.66667%;max-width:91.66667%}.col-xl-12{flex:0 0 100%;max-width:100%}.order-xl-first{order:-1}.order-xl-last{order:13}.order-xl-0{order:0}.order-xl-1{order:1}.order-xl-2{order:2}.order-xl-3{order:3}.order-xl-4{order:4}.order-xl-5{order:5}.order-xl-6{order:6}.order-xl-7{order:7}.order-xl-8{order:8}.order-xl-9{order:9}.order-xl-10{order:10}.order-xl-11{order:11}.order-xl-12{order:12}.offset-xl-0{margin-left:0}.offset-xl-1{margin-left:8.33333%}.offset-xl-2{margin-left:16.66667%}.offset-xl-3{margin-left:25%}.offset-xl-4{margin-left:33.33333%}.offset-xl-5{margin-left:41.66667%}.offset-xl-6{margin-left:50%}.offset-xl-7{margin-left:58.33333%}.offset-xl-8{margin-left:66.66667%}.offset-xl-9{margin-left:75%}.offset-xl-10{margin-left:83.33333%}.offset-xl-11{margin-left:91.66667%}}.table{color:#212529;margin-bottom:1rem;width:100%}.table td,.table th{border-top:1px solid #dee2e6;padding:.75rem;vertical-align:top}.table thead th{border-bottom:2px solid #dee2e6;vertical-align:bottom}.table tbody+tbody{border-top:2px solid #dee2e6}.table-sm td,.table-sm th{padding:.3rem}.table-bordered,.table-bordered td,.table-bordered th{border:1px solid #dee2e6}.table-bordered thead td,.table-bordered thead th{border-bottom-width:2px}.table-borderless tbody+tbody,.table-borderless td,.table-borderless th,.table-borderless thead th{border:0}.table-striped tbody tr:nth-of-type(odd){background-color:rgba(0,0,0,.05)}.table-hover tbody tr:hover{background-color:rgba(0,0,0,.075);color:#212529}.table-primary,.table-primary>td,.table-primary>th{background-color:#b8daff}.table-primary tbody+tbody,.table-primary td,.table-primary th,.table-primary thead th{border-color:#7abaff}.table-hover .table-primary:hover,.table-hover .table-primary:hover>td,.table-hover .table-primary:hover>th{background-color:#9fcdff}.table-secondary,.table-secondary>td,.table-secondary>th{background-color:#d6d8db}.table-secondary tbody+tbody,.table-secondary td,.table-secondary th,.table-secondary thead th{border-color:#b3b7bb}.table-hover .table-secondary:hover,.table-hover .table-secondary:hover>td,.table-hover .table-secondary:hover>th{background-color:#c8cbcf}.table-success,.table-success>td,.table-success>th{background-color:#c3e6cb}.table-success tbody+tbody,.table-success td,.table-success th,.table-success thead th{border-color:#8fd19e}.table-hover .table-success:hover,.table-hover .table-success:hover>td,.table-hover .table-success:hover>th{background-color:#b1dfbb}.table-info,.table-info>td,.table-info>th{background-color:#bee5eb}.table-info tbody+tbody,.table-info td,.table-info th,.table-info thead th{border-color:#86cfda}.table-hover .table-info:hover,.table-hover .table-info:hover>td,.table-hover .table-info:hover>th{background-color:#abdde5}.table-warning,.table-warning>td,.table-warning>th{background-color:#ffeeba}.table-warning tbody+tbody,.table-warning td,.table-warning th,.table-warning thead th{border-color:#ffdf7e}.table-hover .table-warning:hover,.table-hover .table-warning:hover>td,.table-hover .table-warning:hover>th{background-color:#ffe8a1}.table-danger,.table-danger>td,.table-danger>th{background-color:#f5c6cb}.table-danger tbody+tbody,.table-danger td,.table-danger th,.table-danger thead th{border-color:#ed969e}.table-hover .table-danger:hover,.table-hover .table-danger:hover>td,.table-hover .table-danger:hover>th{background-color:#f1b0b7}.table-light,.table-light>td,.table-light>th{background-color:#fdfdfe}.table-light tbody+tbody,.table-light td,.table-light th,.table-light thead th{border-color:#fbfcfc}.table-hover .table-light:hover,.table-hover .table-light:hover>td,.table-hover .table-light:hover>th{background-color:#ececf6}.table-dark,.table-dark>td,.table-dark>th{background-color:#c6c8ca}.table-dark tbody+tbody,.table-dark td,.table-dark th,.table-dark thead th{border-color:#95999c}.table-hover .table-dark:hover,.table-hover .table-dark:hover>td,.table-hover .table-dark:hover>th{background-color:#b9bbbe}.table-active,.table-active>td,.table-active>th,.table-hover .table-active:hover,.table-hover .table-active:hover>td,.table-hover .table-active:hover>th{background-color:rgba(0,0,0,.075)}.table .thead-dark th{background-color:#343a40;border-color:#454d55;color:#fff}.table .thead-light th{background-color:#e9ecef;border-color:#dee2e6;color:#495057}.table-dark{background-color:#343a40;color:#fff}.table-dark td,.table-dark th,.table-dark thead th{border-color:#454d55}.table-dark.table-bordered{border:0}.table-dark.table-striped tbody tr:nth-of-type(odd){background-color:hsla(0,0%,100%,.05)}.table-dark.table-hover tbody tr:hover{background-color:hsla(0,0%,100%,.075);color:#fff}@media (max-width:539.98px){.table-responsive-sm{-webkit-overflow-scrolling:touch;display:block;overflow-x:auto;width:100%}.table-responsive-sm>.table-bordered{border:0}}@media (max-width:719.98px){.table-responsive-md{-webkit-overflow-scrolling:touch;display:block;overflow-x:auto;width:100%}.table-responsive-md>.table-bordered{border:0}}@media (max-width:959.98px){.table-responsive-lg{-webkit-overflow-scrolling:touch;display:block;overflow-x:auto;width:100%}.table-responsive-lg>.table-bordered{border:0}}@media (max-width:1199.98px){.table-responsive-xl{-webkit-overflow-scrolling:touch;display:block;overflow-x:auto;width:100%}.table-responsive-xl>.table-bordered{border:0}}.table-responsive{-webkit-overflow-scrolling:touch;display:block;overflow-x:auto;width:100%}.table-responsive>.table-bordered{border:0}.form-control{background-clip:padding-box;background-color:#fff;border:1px solid #ced4da;border-radius:.25rem;color:#495057;display:block;font-size:1rem;font-weight:400;height:calc(1.5em + .75rem + 2px);line-height:1.5;padding:.375rem .75rem;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out;width:100%}@media (prefers-reduced-motion:reduce){.form-control{transition:none}}.form-control::-ms-expand{background-color:transparent;border:0}.form-control:focus{background-color:#fff;border-color:#80bdff;box-shadow:0 0 0 .2rem rgba(0,123,255,.25);color:#495057;outline:0}.form-control::placeholder{color:#6c757d;opacity:1}.form-control:disabled,.form-control[readonly]{background-color:#e9ecef;opacity:1}input[type=date].form-control,input[type=datetime-local].form-control,input[type=month].form-control,input[type=time].form-control{appearance:none}select.form-control:-moz-focusring{color:transparent;text-shadow:0 0 0 #495057}select.form-control:focus::-ms-value{background-color:#fff;color:#495057}.form-control-file,.form-control-range{display:block;width:100%}.col-form-label{font-size:inherit;line-height:1.5;margin-bottom:0;padding-bottom:calc(.375rem + 1px);padding-top:calc(.375rem + 1px)}.col-form-label-lg{font-size:1.25rem;line-height:1.5;padding-bottom:calc(.5rem + 1px);padding-top:calc(.5rem + 1px)}.col-form-label-sm{font-size:.875rem;line-height:1.5;padding-bottom:calc(.25rem + 1px);padding-top:calc(.25rem + 1px)}.form-control-plaintext{background-color:transparent;border:solid transparent;border-width:1px 0;color:#212529;display:block;font-size:1rem;line-height:1.5;margin-bottom:0;padding:.375rem 0;width:100%}.form-control-plaintext.form-control-lg,.form-control-plaintext.form-control-sm{padding-left:0;padding-right:0}.form-control-sm{border-radius:.2rem;font-size:.875rem;height:calc(1.5em + .5rem + 2px);line-height:1.5;padding:.25rem .5rem}.form-control-lg{border-radius:.3rem;font-size:1.25rem;height:calc(1.5em + 1rem + 2px);line-height:1.5;padding:.5rem 1rem}select.form-control[multiple],select.form-control[size],textarea.form-control{height:auto}.form-group{margin-bottom:1rem}.form-text{display:block;margin-top:.25rem}.form-row{display:flex;flex-wrap:wrap;margin-left:-5px;margin-right:-5px}.form-row>.col,.form-row>[class*=col-]{padding-left:5px;padding-right:5px}.form-check{display:block;padding-left:1.25rem;position:relative}.form-check-input{margin-left:-1.25rem;margin-top:.3rem;position:absolute}.form-check-input:disabled~.form-check-label,.form-check-input[disabled]~.form-check-label{color:#6c757d}.form-check-label{margin-bottom:0}.form-check-inline{align-items:center;display:inline-flex;margin-right:.75rem;padding-left:0}.form-check-inline .form-check-input{margin-left:0;margin-right:.3125rem;margin-top:0;position:static}.valid-feedback{color:#28a745;display:none;font-size:80%;margin-top:.25rem;width:100%}.valid-tooltip{background-color:rgba(40,167,69,.9);border-radius:.25rem;color:#fff;display:none;font-size:.875rem;left:0;line-height:1.5;margin-top:.1rem;max-width:100%;padding:.25rem .5rem;position:absolute;top:100%;z-index:5}.form-row>.col>.valid-tooltip,.form-row>[class*=col-]>.valid-tooltip{left:5px}.is-valid~.valid-feedback,.is-valid~.valid-tooltip,.was-validated :valid~.valid-feedback,.was-validated :valid~.valid-tooltip{display:block}.form-control.is-valid,.was-validated .form-control:valid{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='8' height='8'%3E%3Cpath fill='%2328a745' d='M2.3 6.73.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3E%3C/svg%3E");background-position:right calc(.375em + .1875rem) center;background-repeat:no-repeat;background-size:calc(.75em + .375rem) calc(.75em + .375rem);border-color:#28a745;padding-right:calc(1.5em + .75rem)!important}.form-control.is-valid:focus,.was-validated .form-control:valid:focus{border-color:#28a745;box-shadow:0 0 0 .2rem rgba(40,167,69,.25)}.was-validated select.form-control:valid,select.form-control.is-valid{background-position:right 1.5rem center;padding-right:3rem!important}.was-validated textarea.form-control:valid,textarea.form-control.is-valid{background-position:top calc(.375em + .1875rem) right calc(.375em + .1875rem);padding-right:calc(1.5em + .75rem)}.custom-select.is-valid,.was-validated .custom-select:valid{background:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='4' height='5'%3E%3Cpath fill='%23343a40' d='M2 0 0 2h4zm0 5L0 3h4z'/%3E%3C/svg%3E") right .75rem center/8px 10px no-repeat,#fff url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='8' height='8'%3E%3Cpath fill='%2328a745' d='M2.3 6.73.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3E%3C/svg%3E") center right 1.75rem/calc(.75em + .375rem) calc(.75em + .375rem) no-repeat;border-color:#28a745;padding-right:calc(.75em + 2.3125rem)!important}.custom-select.is-valid:focus,.was-validated .custom-select:valid:focus{border-color:#28a745;box-shadow:0 0 0 .2rem rgba(40,167,69,.25)}.form-check-input.is-valid~.form-check-label,.was-validated .form-check-input:valid~.form-check-label{color:#28a745}.form-check-input.is-valid~.valid-feedback,.form-check-input.is-valid~.valid-tooltip,.was-validated .form-check-input:valid~.valid-feedback,.was-validated .form-check-input:valid~.valid-tooltip{display:block}.custom-control-input.is-valid~.custom-control-label,.was-validated .custom-control-input:valid~.custom-control-label{color:#28a745}.custom-control-input.is-valid~.custom-control-label:before,.was-validated .custom-control-input:valid~.custom-control-label:before{border-color:#28a745}.custom-control-input.is-valid:checked~.custom-control-label:before,.was-validated .custom-control-input:valid:checked~.custom-control-label:before{background-color:#34ce57;border-color:#34ce57}.custom-control-input.is-valid:focus~.custom-control-label:before,.was-validated .custom-control-input:valid:focus~.custom-control-label:before{box-shadow:0 0 0 .2rem rgba(40,167,69,.25)}.custom-control-input.is-valid:focus:not(:checked)~.custom-control-label:before,.was-validated .custom-control-input:valid:focus:not(:checked)~.custom-control-label:before{border-color:#28a745}.custom-file-input.is-valid~.custom-file-label,.was-validated .custom-file-input:valid~.custom-file-label{border-color:#28a745}.custom-file-input.is-valid:focus~.custom-file-label,.was-validated .custom-file-input:valid:focus~.custom-file-label{border-color:#28a745;box-shadow:0 0 0 .2rem rgba(40,167,69,.25)}.invalid-feedback{color:#dc3545;display:none;font-size:80%;margin-top:.25rem;width:100%}.invalid-tooltip{background-color:rgba(220,53,69,.9);border-radius:.25rem;color:#fff;display:none;font-size:.875rem;left:0;line-height:1.5;margin-top:.1rem;max-width:100%;padding:.25rem .5rem;position:absolute;top:100%;z-index:5}.form-row>.col>.invalid-tooltip,.form-row>[class*=col-]>.invalid-tooltip{left:5px}.is-invalid~.invalid-feedback,.is-invalid~.invalid-tooltip,.was-validated :invalid~.invalid-feedback,.was-validated :invalid~.invalid-tooltip{display:block}.form-control.is-invalid,.was-validated .form-control:invalid{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' fill='none' stroke='%23dc3545'%3E%3Ccircle cx='6' cy='6' r='4.5'/%3E%3Cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3E%3Ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3E%3C/svg%3E");background-position:right calc(.375em + .1875rem) center;background-repeat:no-repeat;background-size:calc(.75em + .375rem) calc(.75em + .375rem);border-color:#dc3545;padding-right:calc(1.5em + .75rem)!important}.form-control.is-invalid:focus,.was-validated .form-control:invalid:focus{border-color:#dc3545;box-shadow:0 0 0 .2rem rgba(220,53,69,.25)}.was-validated select.form-control:invalid,select.form-control.is-invalid{background-position:right 1.5rem center;padding-right:3rem!important}.was-validated textarea.form-control:invalid,textarea.form-control.is-invalid{background-position:top calc(.375em + .1875rem) right calc(.375em + .1875rem);padding-right:calc(1.5em + .75rem)}.custom-select.is-invalid,.was-validated .custom-select:invalid{background:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='4' height='5'%3E%3Cpath fill='%23343a40' d='M2 0 0 2h4zm0 5L0 3h4z'/%3E%3C/svg%3E") right .75rem center/8px 10px no-repeat,#fff url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' fill='none' stroke='%23dc3545'%3E%3Ccircle cx='6' cy='6' r='4.5'/%3E%3Cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3E%3Ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3E%3C/svg%3E") center right 1.75rem/calc(.75em + .375rem) calc(.75em + .375rem) no-repeat;border-color:#dc3545;padding-right:calc(.75em + 2.3125rem)!important}.custom-select.is-invalid:focus,.was-validated .custom-select:invalid:focus{border-color:#dc3545;box-shadow:0 0 0 .2rem rgba(220,53,69,.25)}.form-check-input.is-invalid~.form-check-label,.was-validated .form-check-input:invalid~.form-check-label{color:#dc3545}.form-check-input.is-invalid~.invalid-feedback,.form-check-input.is-invalid~.invalid-tooltip,.was-validated .form-check-input:invalid~.invalid-feedback,.was-validated .form-check-input:invalid~.invalid-tooltip{display:block}.custom-control-input.is-invalid~.custom-control-label,.was-validated .custom-control-input:invalid~.custom-control-label{color:#dc3545}.custom-control-input.is-invalid~.custom-control-label:before,.was-validated .custom-control-input:invalid~.custom-control-label:before{border-color:#dc3545}.custom-control-input.is-invalid:checked~.custom-control-label:before,.was-validated .custom-control-input:invalid:checked~.custom-control-label:before{background-color:#e4606d;border-color:#e4606d}.custom-control-input.is-invalid:focus~.custom-control-label:before,.was-validated .custom-control-input:invalid:focus~.custom-control-label:before{box-shadow:0 0 0 .2rem rgba(220,53,69,.25)}.custom-control-input.is-invalid:focus:not(:checked)~.custom-control-label:before,.was-validated .custom-control-input:invalid:focus:not(:checked)~.custom-control-label:before{border-color:#dc3545}.custom-file-input.is-invalid~.custom-file-label,.was-validated .custom-file-input:invalid~.custom-file-label{border-color:#dc3545}.custom-file-input.is-invalid:focus~.custom-file-label,.was-validated .custom-file-input:invalid:focus~.custom-file-label{border-color:#dc3545;box-shadow:0 0 0 .2rem rgba(220,53,69,.25)}.form-inline{align-items:center;display:flex;flex-flow:row wrap}.form-inline .form-check{width:100%}@media (min-width:540px){.form-inline label{justify-content:center}.form-inline .form-group,.form-inline label{align-items:center;display:flex;margin-bottom:0}.form-inline .form-group{flex:0 0 auto;flex-flow:row wrap}.form-inline .form-control{display:inline-block;vertical-align:middle;width:auto}.form-inline .form-control-plaintext{display:inline-block}.form-inline .custom-select,.form-inline .input-group{width:auto}.form-inline .form-check{align-items:center;display:flex;justify-content:center;padding-left:0;width:auto}.form-inline .form-check-input{flex-shrink:0;margin-left:0;margin-right:.25rem;margin-top:0;position:relative}.form-inline .custom-control{align-items:center;justify-content:center}.form-inline .custom-control-label{margin-bottom:0}}.btn{background-color:transparent;border:1px solid transparent;border-radius:.25rem;color:#212529;display:inline-block;font-size:1rem;font-weight:400;line-height:1.5;padding:.375rem .75rem;text-align:center;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;user-select:none;vertical-align:middle}@media (prefers-reduced-motion:reduce){.btn{transition:none}}.btn:hover{color:#212529;text-decoration:none}.btn.focus,.btn:focus{box-shadow:0 0 0 .2rem rgba(0,123,255,.25);outline:0}.btn.disabled,.btn:disabled{opacity:.65}.btn:not(:disabled):not(.disabled){cursor:pointer}a.btn.disabled,fieldset:disabled a.btn{pointer-events:none}.btn-primary{background-color:#007bff;border-color:#007bff;color:#fff}.btn-primary.focus,.btn-primary:focus,.btn-primary:hover{background-color:#0069d9;border-color:#0062cc;color:#fff}.btn-primary.focus,.btn-primary:focus{box-shadow:0 0 0 .2rem rgba(38,143,255,.5)}.btn-primary.disabled,.btn-primary:disabled{background-color:#007bff;border-color:#007bff;color:#fff}.btn-primary:not(:disabled):not(.disabled).active,.btn-primary:not(:disabled):not(.disabled):active,.show>.btn-primary.dropdown-toggle{background-color:#0062cc;border-color:#005cbf;color:#fff}.btn-primary:not(:disabled):not(.disabled).active:focus,.btn-primary:not(:disabled):not(.disabled):active:focus,.show>.btn-primary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(38,143,255,.5)}.btn-secondary{background-color:#6c757d;border-color:#6c757d;color:#fff}.btn-secondary.focus,.btn-secondary:focus,.btn-secondary:hover{background-color:#5a6268;border-color:#545b62;color:#fff}.btn-secondary.focus,.btn-secondary:focus{box-shadow:0 0 0 .2rem hsla(208,6%,54%,.5)}.btn-secondary.disabled,.btn-secondary:disabled{background-color:#6c757d;border-color:#6c757d;color:#fff}.btn-secondary:not(:disabled):not(.disabled).active,.btn-secondary:not(:disabled):not(.disabled):active,.show>.btn-secondary.dropdown-toggle{background-color:#545b62;border-color:#4e555b;color:#fff}.btn-secondary:not(:disabled):not(.disabled).active:focus,.btn-secondary:not(:disabled):not(.disabled):active:focus,.show>.btn-secondary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem hsla(208,6%,54%,.5)}.btn-success{background-color:#28a745;border-color:#28a745;color:#fff}.btn-success.focus,.btn-success:focus,.btn-success:hover{background-color:#218838;border-color:#1e7e34;color:#fff}.btn-success.focus,.btn-success:focus{box-shadow:0 0 0 .2rem rgba(72,180,97,.5)}.btn-success.disabled,.btn-success:disabled{background-color:#28a745;border-color:#28a745;color:#fff}.btn-success:not(:disabled):not(.disabled).active,.btn-success:not(:disabled):not(.disabled):active,.show>.btn-success.dropdown-toggle{background-color:#1e7e34;border-color:#1c7430;color:#fff}.btn-success:not(:disabled):not(.disabled).active:focus,.btn-success:not(:disabled):not(.disabled):active:focus,.show>.btn-success.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(72,180,97,.5)}.btn-info{background-color:#17a2b8;border-color:#17a2b8;color:#fff}.btn-info.focus,.btn-info:focus,.btn-info:hover{background-color:#138496;border-color:#117a8b;color:#fff}.btn-info.focus,.btn-info:focus{box-shadow:0 0 0 .2rem rgba(58,176,195,.5)}.btn-info.disabled,.btn-info:disabled{background-color:#17a2b8;border-color:#17a2b8;color:#fff}.btn-info:not(:disabled):not(.disabled).active,.btn-info:not(:disabled):not(.disabled):active,.show>.btn-info.dropdown-toggle{background-color:#117a8b;border-color:#10707f;color:#fff}.btn-info:not(:disabled):not(.disabled).active:focus,.btn-info:not(:disabled):not(.disabled):active:focus,.show>.btn-info.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(58,176,195,.5)}.btn-warning{background-color:#ffc107;border-color:#ffc107;color:#212529}.btn-warning.focus,.btn-warning:focus,.btn-warning:hover{background-color:#e0a800;border-color:#d39e00;color:#212529}.btn-warning.focus,.btn-warning:focus{box-shadow:0 0 0 .2rem rgba(222,170,12,.5)}.btn-warning.disabled,.btn-warning:disabled{background-color:#ffc107;border-color:#ffc107;color:#212529}.btn-warning:not(:disabled):not(.disabled).active,.btn-warning:not(:disabled):not(.disabled):active,.show>.btn-warning.dropdown-toggle{background-color:#d39e00;border-color:#c69500;color:#212529}.btn-warning:not(:disabled):not(.disabled).active:focus,.btn-warning:not(:disabled):not(.disabled):active:focus,.show>.btn-warning.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(222,170,12,.5)}.btn-danger{background-color:#dc3545;border-color:#dc3545;color:#fff}.btn-danger.focus,.btn-danger:focus,.btn-danger:hover{background-color:#c82333;border-color:#bd2130;color:#fff}.btn-danger.focus,.btn-danger:focus{box-shadow:0 0 0 .2rem rgba(225,83,97,.5)}.btn-danger.disabled,.btn-danger:disabled{background-color:#dc3545;border-color:#dc3545;color:#fff}.btn-danger:not(:disabled):not(.disabled).active,.btn-danger:not(:disabled):not(.disabled):active,.show>.btn-danger.dropdown-toggle{background-color:#bd2130;border-color:#b21f2d;color:#fff}.btn-danger:not(:disabled):not(.disabled).active:focus,.btn-danger:not(:disabled):not(.disabled):active:focus,.show>.btn-danger.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(225,83,97,.5)}.btn-light{background-color:#f8f9fa;border-color:#f8f9fa;color:#212529}.btn-light.focus,.btn-light:focus,.btn-light:hover{background-color:#e2e6ea;border-color:#dae0e5;color:#212529}.btn-light.focus,.btn-light:focus{box-shadow:0 0 0 .2rem hsla(220,4%,85%,.5)}.btn-light.disabled,.btn-light:disabled{background-color:#f8f9fa;border-color:#f8f9fa;color:#212529}.btn-light:not(:disabled):not(.disabled).active,.btn-light:not(:disabled):not(.disabled):active,.show>.btn-light.dropdown-toggle{background-color:#dae0e5;border-color:#d3d9df;color:#212529}.btn-light:not(:disabled):not(.disabled).active:focus,.btn-light:not(:disabled):not(.disabled):active:focus,.show>.btn-light.dropdown-toggle:focus{box-shadow:0 0 0 .2rem hsla(220,4%,85%,.5)}.btn-dark{background-color:#343a40;border-color:#343a40;color:#fff}.btn-dark.focus,.btn-dark:focus,.btn-dark:hover{background-color:#23272b;border-color:#1d2124;color:#fff}.btn-dark.focus,.btn-dark:focus{box-shadow:0 0 0 .2rem rgba(82,88,93,.5)}.btn-dark.disabled,.btn-dark:disabled{background-color:#343a40;border-color:#343a40;color:#fff}.btn-dark:not(:disabled):not(.disabled).active,.btn-dark:not(:disabled):not(.disabled):active,.show>.btn-dark.dropdown-toggle{background-color:#1d2124;border-color:#171a1d;color:#fff}.btn-dark:not(:disabled):not(.disabled).active:focus,.btn-dark:not(:disabled):not(.disabled):active:focus,.show>.btn-dark.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(82,88,93,.5)}.btn-outline-primary{border-color:#007bff;color:#007bff}.btn-outline-primary:hover{background-color:#007bff;border-color:#007bff;color:#fff}.btn-outline-primary.focus,.btn-outline-primary:focus{box-shadow:0 0 0 .2rem rgba(0,123,255,.5)}.btn-outline-primary.disabled,.btn-outline-primary:disabled{background-color:transparent;color:#007bff}.btn-outline-primary:not(:disabled):not(.disabled).active,.btn-outline-primary:not(:disabled):not(.disabled):active,.show>.btn-outline-primary.dropdown-toggle{background-color:#007bff;border-color:#007bff;color:#fff}.btn-outline-primary:not(:disabled):not(.disabled).active:focus,.btn-outline-primary:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-primary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(0,123,255,.5)}.btn-outline-secondary{border-color:#6c757d;color:#6c757d}.btn-outline-secondary:hover{background-color:#6c757d;border-color:#6c757d;color:#fff}.btn-outline-secondary.focus,.btn-outline-secondary:focus{box-shadow:0 0 0 .2rem hsla(208,7%,46%,.5)}.btn-outline-secondary.disabled,.btn-outline-secondary:disabled{background-color:transparent;color:#6c757d}.btn-outline-secondary:not(:disabled):not(.disabled).active,.btn-outline-secondary:not(:disabled):not(.disabled):active,.show>.btn-outline-secondary.dropdown-toggle{background-color:#6c757d;border-color:#6c757d;color:#fff}.btn-outline-secondary:not(:disabled):not(.disabled).active:focus,.btn-outline-secondary:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-secondary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem hsla(208,7%,46%,.5)}.btn-outline-success{border-color:#28a745;color:#28a745}.btn-outline-success:hover{background-color:#28a745;border-color:#28a745;color:#fff}.btn-outline-success.focus,.btn-outline-success:focus{box-shadow:0 0 0 .2rem rgba(40,167,69,.5)}.btn-outline-success.disabled,.btn-outline-success:disabled{background-color:transparent;color:#28a745}.btn-outline-success:not(:disabled):not(.disabled).active,.btn-outline-success:not(:disabled):not(.disabled):active,.show>.btn-outline-success.dropdown-toggle{background-color:#28a745;border-color:#28a745;color:#fff}.btn-outline-success:not(:disabled):not(.disabled).active:focus,.btn-outline-success:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-success.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(40,167,69,.5)}.btn-outline-info{border-color:#17a2b8;color:#17a2b8}.btn-outline-info:hover{background-color:#17a2b8;border-color:#17a2b8;color:#fff}.btn-outline-info.focus,.btn-outline-info:focus{box-shadow:0 0 0 .2rem rgba(23,162,184,.5)}.btn-outline-info.disabled,.btn-outline-info:disabled{background-color:transparent;color:#17a2b8}.btn-outline-info:not(:disabled):not(.disabled).active,.btn-outline-info:not(:disabled):not(.disabled):active,.show>.btn-outline-info.dropdown-toggle{background-color:#17a2b8;border-color:#17a2b8;color:#fff}.btn-outline-info:not(:disabled):not(.disabled).active:focus,.btn-outline-info:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-info.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(23,162,184,.5)}.btn-outline-warning{border-color:#ffc107;color:#ffc107}.btn-outline-warning:hover{background-color:#ffc107;border-color:#ffc107;color:#212529}.btn-outline-warning.focus,.btn-outline-warning:focus{box-shadow:0 0 0 .2rem rgba(255,193,7,.5)}.btn-outline-warning.disabled,.btn-outline-warning:disabled{background-color:transparent;color:#ffc107}.btn-outline-warning:not(:disabled):not(.disabled).active,.btn-outline-warning:not(:disabled):not(.disabled):active,.show>.btn-outline-warning.dropdown-toggle{background-color:#ffc107;border-color:#ffc107;color:#212529}.btn-outline-warning:not(:disabled):not(.disabled).active:focus,.btn-outline-warning:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-warning.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(255,193,7,.5)}.btn-outline-danger{border-color:#dc3545;color:#dc3545}.btn-outline-danger:hover{background-color:#dc3545;border-color:#dc3545;color:#fff}.btn-outline-danger.focus,.btn-outline-danger:focus{box-shadow:0 0 0 .2rem rgba(220,53,69,.5)}.btn-outline-danger.disabled,.btn-outline-danger:disabled{background-color:transparent;color:#dc3545}.btn-outline-danger:not(:disabled):not(.disabled).active,.btn-outline-danger:not(:disabled):not(.disabled):active,.show>.btn-outline-danger.dropdown-toggle{background-color:#dc3545;border-color:#dc3545;color:#fff}.btn-outline-danger:not(:disabled):not(.disabled).active:focus,.btn-outline-danger:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-danger.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(220,53,69,.5)}.btn-outline-light{border-color:#f8f9fa;color:#f8f9fa}.btn-outline-light:hover{background-color:#f8f9fa;border-color:#f8f9fa;color:#212529}.btn-outline-light.focus,.btn-outline-light:focus{box-shadow:0 0 0 .2rem rgba(248,249,250,.5)}.btn-outline-light.disabled,.btn-outline-light:disabled{background-color:transparent;color:#f8f9fa}.btn-outline-light:not(:disabled):not(.disabled).active,.btn-outline-light:not(:disabled):not(.disabled):active,.show>.btn-outline-light.dropdown-toggle{background-color:#f8f9fa;border-color:#f8f9fa;color:#212529}.btn-outline-light:not(:disabled):not(.disabled).active:focus,.btn-outline-light:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-light.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(248,249,250,.5)}.btn-outline-dark{border-color:#343a40;color:#343a40}.btn-outline-dark:hover{background-color:#343a40;border-color:#343a40;color:#fff}.btn-outline-dark.focus,.btn-outline-dark:focus{box-shadow:0 0 0 .2rem rgba(52,58,64,.5)}.btn-outline-dark.disabled,.btn-outline-dark:disabled{background-color:transparent;color:#343a40}.btn-outline-dark:not(:disabled):not(.disabled).active,.btn-outline-dark:not(:disabled):not(.disabled):active,.show>.btn-outline-dark.dropdown-toggle{background-color:#343a40;border-color:#343a40;color:#fff}.btn-outline-dark:not(:disabled):not(.disabled).active:focus,.btn-outline-dark:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-dark.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(52,58,64,.5)}.btn-link{color:#007bff;font-weight:400;text-decoration:none}.btn-link:hover{color:#0056b3}.btn-link.focus,.btn-link:focus,.btn-link:hover{text-decoration:underline}.btn-link.disabled,.btn-link:disabled{color:#6c757d;pointer-events:none}.btn-group-lg>.btn,.btn-lg{border-radius:.3rem;font-size:1.25rem;line-height:1.5;padding:.5rem 1rem}.btn-group-sm>.btn,.btn-sm{border-radius:.2rem;font-size:.875rem;line-height:1.5;padding:.25rem .5rem}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:.5rem}input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-block{width:100%}.fade{transition:opacity .15s linear}@media (prefers-reduced-motion:reduce){.fade{transition:none}}.fade:not(.show){opacity:0}.collapse:not(.show){display:none}.collapsing{height:0;overflow:hidden;position:relative;transition:height .35s ease}@media (prefers-reduced-motion:reduce){.collapsing{transition:none}}.dropdown,.dropleft,.dropright,.dropup{position:relative}.dropdown-toggle{white-space:nowrap}.dropdown-toggle:after{border-bottom:0;border-left:.3em solid transparent;border-right:.3em solid transparent;border-top:.3em solid;content:"";display:inline-block;margin-left:.255em;vertical-align:.255em}.dropdown-toggle:empty:after{margin-left:0}.dropdown-menu{background-clip:padding-box;background-color:#fff;border:1px solid rgba(0,0,0,.15);border-radius:.25rem;color:#212529;display:none;float:left;font-size:1rem;left:0;list-style:none;margin:.125rem 0 0;min-width:10rem;padding:.5rem 0;position:absolute;text-align:left;top:100%;z-index:1000}.dropdown-menu-left{left:0;right:auto}.dropdown-menu-right{left:auto;right:0}@media (min-width:540px){.dropdown-menu-sm-left{left:0;right:auto}.dropdown-menu-sm-right{left:auto;right:0}}@media (min-width:720px){.dropdown-menu-md-left{left:0;right:auto}.dropdown-menu-md-right{left:auto;right:0}}@media (min-width:960px){.dropdown-menu-lg-left{left:0;right:auto}.dropdown-menu-lg-right{left:auto;right:0}}@media (min-width:1200px){.dropdown-menu-xl-left{left:0;right:auto}.dropdown-menu-xl-right{left:auto;right:0}}.dropup .dropdown-menu{bottom:100%;margin-bottom:.125rem;margin-top:0;top:auto}.dropup .dropdown-toggle:after{border-bottom:.3em solid;border-left:.3em solid transparent;border-right:.3em solid transparent;border-top:0;content:"";display:inline-block;margin-left:.255em;vertical-align:.255em}.dropup .dropdown-toggle:empty:after{margin-left:0}.dropright .dropdown-menu{left:100%;margin-left:.125rem;margin-top:0;right:auto;top:0}.dropright .dropdown-toggle:after{border-bottom:.3em solid transparent;border-left:.3em solid;border-right:0;border-top:.3em solid transparent;content:"";display:inline-block;margin-left:.255em;vertical-align:.255em}.dropright .dropdown-toggle:empty:after{margin-left:0}.dropright .dropdown-toggle:after{vertical-align:0}.dropleft .dropdown-menu{left:auto;margin-right:.125rem;margin-top:0;right:100%;top:0}.dropleft .dropdown-toggle:after{content:"";display:inline-block;display:none;margin-left:.255em;vertical-align:.255em}.dropleft .dropdown-toggle:before{border-bottom:.3em solid transparent;border-right:.3em solid;border-top:.3em solid transparent;content:"";display:inline-block;margin-right:.255em;vertical-align:.255em}.dropleft .dropdown-toggle:empty:after{margin-left:0}.dropleft .dropdown-toggle:before{vertical-align:0}.dropdown-menu[x-placement^=bottom],.dropdown-menu[x-placement^=left],.dropdown-menu[x-placement^=right],.dropdown-menu[x-placement^=top]{bottom:auto;right:auto}.dropdown-divider{border-top:1px solid #e9ecef;height:0;margin:.5rem 0;overflow:hidden}.dropdown-item{background-color:transparent;border:0;clear:both;color:#212529;display:block;font-weight:400;padding:.25rem 1.5rem;text-align:inherit;white-space:nowrap;width:100%}.dropdown-item:focus,.dropdown-item:hover{background-color:#e9ecef;color:#16181b;text-decoration:none}.dropdown-item.active,.dropdown-item:active{background-color:#007bff;color:#fff;text-decoration:none}.dropdown-item.disabled,.dropdown-item:disabled{background-color:transparent;color:#adb5bd;pointer-events:none}.dropdown-menu.show{display:block}.dropdown-header{color:#6c757d;display:block;font-size:.875rem;margin-bottom:0;padding:.5rem 1.5rem;white-space:nowrap}.dropdown-item-text{color:#212529;display:block;padding:.25rem 1.5rem}.btn-group,.btn-group-vertical{display:inline-flex;position:relative;vertical-align:middle}.btn-group-vertical>.btn,.btn-group>.btn{flex:1 1 auto;position:relative}.btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:hover,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus,.btn-group>.btn:hover{z-index:1}.btn-toolbar{display:flex;flex-wrap:wrap;justify-content:flex-start}.btn-toolbar .input-group{width:auto}.btn-group>.btn-group:not(:first-child),.btn-group>.btn:not(:first-child){margin-left:-1px}.btn-group>.btn-group:not(:last-child)>.btn,.btn-group>.btn:not(:last-child):not(.dropdown-toggle){border-bottom-right-radius:0;border-top-right-radius:0}.btn-group>.btn-group:not(:first-child)>.btn,.btn-group>.btn:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.dropdown-toggle-split{padding-left:.5625rem;padding-right:.5625rem}.dropdown-toggle-split:after,.dropright .dropdown-toggle-split:after,.dropup .dropdown-toggle-split:after{margin-left:0}.dropleft .dropdown-toggle-split:before{margin-right:0}.btn-group-sm>.btn+.dropdown-toggle-split,.btn-sm+.dropdown-toggle-split{padding-left:.375rem;padding-right:.375rem}.btn-group-lg>.btn+.dropdown-toggle-split,.btn-lg+.dropdown-toggle-split{padding-left:.75rem;padding-right:.75rem}.btn-group-vertical{align-items:flex-start;flex-direction:column;justify-content:center}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group{width:100%}.btn-group-vertical>.btn-group:not(:first-child),.btn-group-vertical>.btn:not(:first-child){margin-top:-1px}.btn-group-vertical>.btn-group:not(:last-child)>.btn,.btn-group-vertical>.btn:not(:last-child):not(.dropdown-toggle){border-bottom-left-radius:0;border-bottom-right-radius:0}.btn-group-vertical>.btn-group:not(:first-child)>.btn,.btn-group-vertical>.btn:not(:first-child){border-top-left-radius:0;border-top-right-radius:0}.btn-group-toggle>.btn,.btn-group-toggle>.btn-group>.btn{margin-bottom:0}.btn-group-toggle>.btn input[type=checkbox],.btn-group-toggle>.btn input[type=radio],.btn-group-toggle>.btn-group>.btn input[type=checkbox],.btn-group-toggle>.btn-group>.btn input[type=radio]{clip:rect(0,0,0,0);pointer-events:none;position:absolute}.input-group{align-items:stretch;display:flex;flex-wrap:wrap;position:relative;width:100%}.input-group>.custom-file,.input-group>.custom-select,.input-group>.form-control,.input-group>.form-control-plaintext{flex:1 1 auto;margin-bottom:0;min-width:0;position:relative;width:1%}.input-group>.custom-file+.custom-file,.input-group>.custom-file+.custom-select,.input-group>.custom-file+.form-control,.input-group>.custom-select+.custom-file,.input-group>.custom-select+.custom-select,.input-group>.custom-select+.form-control,.input-group>.form-control+.custom-file,.input-group>.form-control+.custom-select,.input-group>.form-control+.form-control,.input-group>.form-control-plaintext+.custom-file,.input-group>.form-control-plaintext+.custom-select,.input-group>.form-control-plaintext+.form-control{margin-left:-1px}.input-group>.custom-file .custom-file-input:focus~.custom-file-label,.input-group>.custom-select:focus,.input-group>.form-control:focus{z-index:3}.input-group>.custom-file .custom-file-input:focus{z-index:4}.input-group>.custom-select:not(:first-child),.input-group>.form-control:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.input-group>.custom-file{align-items:center;display:flex}.input-group>.custom-file:not(:last-child) .custom-file-label,.input-group>.custom-file:not(:last-child) .custom-file-label:after{border-bottom-right-radius:0;border-top-right-radius:0}.input-group>.custom-file:not(:first-child) .custom-file-label{border-bottom-left-radius:0;border-top-left-radius:0}.input-group.has-validation>.custom-file:nth-last-child(n+3) .custom-file-label,.input-group.has-validation>.custom-file:nth-last-child(n+3) .custom-file-label:after,.input-group.has-validation>.custom-select:nth-last-child(n+3),.input-group.has-validation>.form-control:nth-last-child(n+3),.input-group:not(.has-validation)>.custom-file:not(:last-child) .custom-file-label,.input-group:not(.has-validation)>.custom-file:not(:last-child) .custom-file-label:after,.input-group:not(.has-validation)>.custom-select:not(:last-child),.input-group:not(.has-validation)>.form-control:not(:last-child){border-bottom-right-radius:0;border-top-right-radius:0}.input-group-append,.input-group-prepend{display:flex}.input-group-append .btn,.input-group-prepend .btn{position:relative;z-index:2}.input-group-append .btn:focus,.input-group-prepend .btn:focus{z-index:3}.input-group-append .btn+.btn,.input-group-append .btn+.input-group-text,.input-group-append .input-group-text+.btn,.input-group-append .input-group-text+.input-group-text,.input-group-prepend .btn+.btn,.input-group-prepend .btn+.input-group-text,.input-group-prepend .input-group-text+.btn,.input-group-prepend .input-group-text+.input-group-text{margin-left:-1px}.input-group-prepend{margin-right:-1px}.input-group-append{margin-left:-1px}.input-group-text{align-items:center;background-color:#e9ecef;border:1px solid #ced4da;border-radius:.25rem;color:#495057;display:flex;font-size:1rem;font-weight:400;line-height:1.5;margin-bottom:0;padding:.375rem .75rem;text-align:center;white-space:nowrap}.input-group-text input[type=checkbox],.input-group-text input[type=radio]{margin-top:0}.input-group-lg>.custom-select,.input-group-lg>.form-control:not(textarea){height:calc(1.5em + 1rem + 2px)}.input-group-lg>.custom-select,.input-group-lg>.form-control,.input-group-lg>.input-group-append>.btn,.input-group-lg>.input-group-append>.input-group-text,.input-group-lg>.input-group-prepend>.btn,.input-group-lg>.input-group-prepend>.input-group-text{border-radius:.3rem;font-size:1.25rem;line-height:1.5;padding:.5rem 1rem}.input-group-sm>.custom-select,.input-group-sm>.form-control:not(textarea){height:calc(1.5em + .5rem + 2px)}.input-group-sm>.custom-select,.input-group-sm>.form-control,.input-group-sm>.input-group-append>.btn,.input-group-sm>.input-group-append>.input-group-text,.input-group-sm>.input-group-prepend>.btn,.input-group-sm>.input-group-prepend>.input-group-text{border-radius:.2rem;font-size:.875rem;line-height:1.5;padding:.25rem .5rem}.input-group-lg>.custom-select,.input-group-sm>.custom-select{padding-right:1.75rem}.input-group.has-validation>.input-group-append:nth-last-child(n+3)>.btn,.input-group.has-validation>.input-group-append:nth-last-child(n+3)>.input-group-text,.input-group:not(.has-validation)>.input-group-append:not(:last-child)>.btn,.input-group:not(.has-validation)>.input-group-append:not(:last-child)>.input-group-text,.input-group>.input-group-append:last-child>.btn:not(:last-child):not(.dropdown-toggle),.input-group>.input-group-append:last-child>.input-group-text:not(:last-child),.input-group>.input-group-prepend>.btn,.input-group>.input-group-prepend>.input-group-text{border-bottom-right-radius:0;border-top-right-radius:0}.input-group>.input-group-append>.btn,.input-group>.input-group-append>.input-group-text,.input-group>.input-group-prepend:first-child>.btn:not(:first-child),.input-group>.input-group-prepend:first-child>.input-group-text:not(:first-child),.input-group>.input-group-prepend:not(:first-child)>.btn,.input-group>.input-group-prepend:not(:first-child)>.input-group-text{border-bottom-left-radius:0;border-top-left-radius:0}.custom-control{color-adjust:exact;display:block;min-height:1.5rem;padding-left:1.5rem;position:relative;z-index:1}.custom-control-inline{display:inline-flex;margin-right:1rem}.custom-control-input{height:1.25rem;left:0;opacity:0;position:absolute;width:1rem;z-index:-1}.custom-control-input:checked~.custom-control-label:before{background-color:#007bff;border-color:#007bff;color:#fff}.custom-control-input:focus~.custom-control-label:before{box-shadow:0 0 0 .2rem rgba(0,123,255,.25)}.custom-control-input:focus:not(:checked)~.custom-control-label:before{border-color:#80bdff}.custom-control-input:not(:disabled):active~.custom-control-label:before{background-color:#b3d7ff;border-color:#b3d7ff;color:#fff}.custom-control-input:disabled~.custom-control-label,.custom-control-input[disabled]~.custom-control-label{color:#6c757d}.custom-control-input:disabled~.custom-control-label:before,.custom-control-input[disabled]~.custom-control-label:before{background-color:#e9ecef}.custom-control-label{margin-bottom:0;position:relative;vertical-align:top}.custom-control-label:before{background-color:#fff;border:1px solid #adb5bd;pointer-events:none}.custom-control-label:after,.custom-control-label:before{content:"";display:block;height:1rem;left:-1.5rem;position:absolute;top:.25rem;width:1rem}.custom-control-label:after{background:50%/50% 50% no-repeat}.custom-checkbox .custom-control-label:before{border-radius:.25rem}.custom-checkbox .custom-control-input:checked~.custom-control-label:after{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='8' height='8'%3E%3Cpath fill='%23fff' d='m6.564.75-3.59 3.612-1.538-1.55L0 4.26l2.974 2.99L8 2.193z'/%3E%3C/svg%3E")}.custom-checkbox .custom-control-input:indeterminate~.custom-control-label:before{background-color:#007bff;border-color:#007bff}.custom-checkbox .custom-control-input:indeterminate~.custom-control-label:after{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='4' height='4'%3E%3Cpath stroke='%23fff' d='M0 2h4'/%3E%3C/svg%3E")}.custom-checkbox .custom-control-input:disabled:checked~.custom-control-label:before{background-color:rgba(0,123,255,.5)}.custom-checkbox .custom-control-input:disabled:indeterminate~.custom-control-label:before{background-color:rgba(0,123,255,.5)}.custom-radio .custom-control-label:before{border-radius:50%}.custom-radio .custom-control-input:checked~.custom-control-label:after{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='-4 -4 8 8'%3E%3Ccircle r='3' fill='%23fff'/%3E%3C/svg%3E")}.custom-radio .custom-control-input:disabled:checked~.custom-control-label:before{background-color:rgba(0,123,255,.5)}.custom-switch{padding-left:2.25rem}.custom-switch .custom-control-label:before{border-radius:.5rem;left:-2.25rem;pointer-events:all;width:1.75rem}.custom-switch .custom-control-label:after{background-color:#adb5bd;border-radius:.5rem;height:calc(1rem - 4px);left:calc(-2.25rem + 2px);top:calc(.25rem + 2px);transition:transform .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;width:calc(1rem - 4px)}@media (prefers-reduced-motion:reduce){.custom-switch .custom-control-label:after{transition:none}}.custom-switch .custom-control-input:checked~.custom-control-label:after{background-color:#fff;transform:translateX(.75rem)}.custom-switch .custom-control-input:disabled:checked~.custom-control-label:before{background-color:rgba(0,123,255,.5)}.custom-select{appearance:none;background:#fff url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='4' height='5'%3E%3Cpath fill='%23343a40' d='M2 0 0 2h4zm0 5L0 3h4z'/%3E%3C/svg%3E") right .75rem center/8px 10px no-repeat;border:1px solid #ced4da;border-radius:.25rem;color:#495057;display:inline-block;font-size:1rem;font-weight:400;height:calc(1.5em + .75rem + 2px);line-height:1.5;padding:.375rem 1.75rem .375rem .75rem;vertical-align:middle;width:100%}.custom-select:focus{border-color:#80bdff;box-shadow:0 0 0 .2rem rgba(0,123,255,.25);outline:0}.custom-select:focus::-ms-value{background-color:#fff;color:#495057}.custom-select[multiple],.custom-select[size]:not([size="1"]){background-image:none;height:auto;padding-right:.75rem}.custom-select:disabled{background-color:#e9ecef;color:#6c757d}.custom-select::-ms-expand{display:none}.custom-select:-moz-focusring{color:transparent;text-shadow:0 0 0 #495057}.custom-select-sm{font-size:.875rem;height:calc(1.5em + .5rem + 2px);padding-bottom:.25rem;padding-left:.5rem;padding-top:.25rem}.custom-select-lg{font-size:1.25rem;height:calc(1.5em + 1rem + 2px);padding-bottom:.5rem;padding-left:1rem;padding-top:.5rem}.custom-file{display:inline-block;margin-bottom:0}.custom-file,.custom-file-input{height:calc(1.5em + .75rem + 2px);position:relative;width:100%}.custom-file-input{margin:0;opacity:0;overflow:hidden;z-index:2}.custom-file-input:focus~.custom-file-label{border-color:#80bdff;box-shadow:0 0 0 .2rem rgba(0,123,255,.25)}.custom-file-input:disabled~.custom-file-label,.custom-file-input[disabled]~.custom-file-label{background-color:#e9ecef}.custom-file-input:lang(en)~.custom-file-label:after{content:"Browse"}.custom-file-input~.custom-file-label[data-browse]:after{content:attr(data-browse)}.custom-file-label{background-color:#fff;border:1px solid #ced4da;border-radius:.25rem;font-weight:400;height:calc(1.5em + .75rem + 2px);left:0;overflow:hidden;z-index:1}.custom-file-label,.custom-file-label:after{color:#495057;line-height:1.5;padding:.375rem .75rem;position:absolute;right:0;top:0}.custom-file-label:after{background-color:#e9ecef;border-left:inherit;border-radius:0 .25rem .25rem 0;bottom:0;content:"Browse";display:block;height:calc(1.5em + .75rem);z-index:3}.custom-range{appearance:none;background-color:transparent;height:1.4rem;padding:0;width:100%}.custom-range:focus{outline:0}.custom-range:focus::-webkit-slider-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .2rem rgba(0,123,255,.25)}.custom-range:focus::-moz-range-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .2rem rgba(0,123,255,.25)}.custom-range:focus::-ms-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .2rem rgba(0,123,255,.25)}.custom-range::-moz-focus-outer{border:0}.custom-range::-webkit-slider-thumb{appearance:none;background-color:#007bff;border:0;border-radius:1rem;height:1rem;margin-top:-.25rem;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;width:1rem}@media (prefers-reduced-motion:reduce){.custom-range::-webkit-slider-thumb{transition:none}}.custom-range::-webkit-slider-thumb:active{background-color:#b3d7ff}.custom-range::-webkit-slider-runnable-track{background-color:#dee2e6;border-color:transparent;border-radius:1rem;color:transparent;cursor:pointer;height:.5rem;width:100%}.custom-range::-moz-range-thumb{appearance:none;background-color:#007bff;border:0;border-radius:1rem;height:1rem;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;width:1rem}@media (prefers-reduced-motion:reduce){.custom-range::-moz-range-thumb{transition:none}}.custom-range::-moz-range-thumb:active{background-color:#b3d7ff}.custom-range::-moz-range-track{background-color:#dee2e6;border-color:transparent;border-radius:1rem;color:transparent;cursor:pointer;height:.5rem;width:100%}.custom-range::-ms-thumb{appearance:none;background-color:#007bff;border:0;border-radius:1rem;height:1rem;margin-left:.2rem;margin-right:.2rem;margin-top:0;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;width:1rem}@media (prefers-reduced-motion:reduce){.custom-range::-ms-thumb{transition:none}}.custom-range::-ms-thumb:active{background-color:#b3d7ff}.custom-range::-ms-track{background-color:transparent;border-color:transparent;border-width:.5rem;color:transparent;cursor:pointer;height:.5rem;width:100%}.custom-range::-ms-fill-lower,.custom-range::-ms-fill-upper{background-color:#dee2e6;border-radius:1rem}.custom-range::-ms-fill-upper{margin-right:15px}.custom-range:disabled::-webkit-slider-thumb{background-color:#adb5bd}.custom-range:disabled::-webkit-slider-runnable-track{cursor:default}.custom-range:disabled::-moz-range-thumb{background-color:#adb5bd}.custom-range:disabled::-moz-range-track{cursor:default}.custom-range:disabled::-ms-thumb{background-color:#adb5bd}.custom-control-label:before,.custom-file-label,.custom-select{transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.custom-control-label:before,.custom-file-label,.custom-select{transition:none}}.nav{display:flex;flex-wrap:wrap;list-style:none;margin-bottom:0;padding-left:0}.nav-link{display:block;padding:.5rem 1rem}.nav-link:focus,.nav-link:hover{text-decoration:none}.nav-link.disabled{color:#6c757d;cursor:default;pointer-events:none}.nav-tabs{border-bottom:1px solid #dee2e6}.nav-tabs .nav-link{border:1px solid transparent;border-top-left-radius:.25rem;border-top-right-radius:.25rem;margin-bottom:-1px}.nav-tabs .nav-link:focus,.nav-tabs .nav-link:hover{border-color:#e9ecef #e9ecef #dee2e6}.nav-tabs .nav-link.disabled{background-color:transparent;border-color:transparent;color:#6c757d}.nav-tabs .nav-item.show .nav-link,.nav-tabs .nav-link.active{background-color:#fff;border-color:#dee2e6 #dee2e6 #fff;color:#495057}.nav-tabs .dropdown-menu{border-top-left-radius:0;border-top-right-radius:0;margin-top:-1px}.nav-pills .nav-link{border-radius:.25rem}.nav-pills .nav-link.active,.nav-pills .show>.nav-link{background-color:#007bff;color:#fff}.nav-fill .nav-item,.nav-fill>.nav-link{flex:1 1 auto;text-align:center}.nav-justified .nav-item,.nav-justified>.nav-link{flex-basis:0;flex-grow:1;text-align:center}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.navbar{padding:.5rem 1rem;position:relative}.navbar,.navbar .container,.navbar .container-fluid,.navbar .container-lg,.navbar .container-md,.navbar .container-sm,.navbar .container-xl{align-items:center;display:flex;flex-wrap:wrap;justify-content:space-between}.navbar-brand{display:inline-block;font-size:1.25rem;line-height:inherit;margin-right:1rem;padding-bottom:.3125rem;padding-top:.3125rem;white-space:nowrap}.navbar-brand:focus,.navbar-brand:hover{text-decoration:none}.navbar-nav{display:flex;flex-direction:column;list-style:none;margin-bottom:0;padding-left:0}.navbar-nav .nav-link{padding-left:0;padding-right:0}.navbar-nav .dropdown-menu{float:none;position:static}.navbar-text{display:inline-block;padding-bottom:.5rem;padding-top:.5rem}.navbar-collapse{align-items:center;flex-basis:100%;flex-grow:1}.navbar-toggler{background-color:transparent;border:1px solid transparent;border-radius:.25rem;font-size:1.25rem;line-height:1;padding:.25rem .75rem}.navbar-toggler:focus,.navbar-toggler:hover{text-decoration:none}.navbar-toggler-icon{background:50%/100% 100% no-repeat;content:"";display:inline-block;height:1.5em;vertical-align:middle;width:1.5em}.navbar-nav-scroll{max-height:75vh;overflow-y:auto}@media (max-width:539.98px){.navbar-expand-sm>.container,.navbar-expand-sm>.container-fluid,.navbar-expand-sm>.container-lg,.navbar-expand-sm>.container-md,.navbar-expand-sm>.container-sm,.navbar-expand-sm>.container-xl{padding-left:0;padding-right:0}}@media (min-width:540px){.navbar-expand-sm{flex-flow:row nowrap;justify-content:flex-start}.navbar-expand-sm .navbar-nav{flex-direction:row}.navbar-expand-sm .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-sm .navbar-nav .nav-link{padding-left:.5rem;padding-right:.5rem}.navbar-expand-sm>.container,.navbar-expand-sm>.container-fluid,.navbar-expand-sm>.container-lg,.navbar-expand-sm>.container-md,.navbar-expand-sm>.container-sm,.navbar-expand-sm>.container-xl{flex-wrap:nowrap}.navbar-expand-sm .navbar-nav-scroll{overflow:visible}.navbar-expand-sm .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-sm .navbar-toggler{display:none}}@media (max-width:719.98px){.navbar-expand-md>.container,.navbar-expand-md>.container-fluid,.navbar-expand-md>.container-lg,.navbar-expand-md>.container-md,.navbar-expand-md>.container-sm,.navbar-expand-md>.container-xl{padding-left:0;padding-right:0}}@media (min-width:720px){.navbar-expand-md{flex-flow:row nowrap;justify-content:flex-start}.navbar-expand-md .navbar-nav{flex-direction:row}.navbar-expand-md .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-md .navbar-nav .nav-link{padding-left:.5rem;padding-right:.5rem}.navbar-expand-md>.container,.navbar-expand-md>.container-fluid,.navbar-expand-md>.container-lg,.navbar-expand-md>.container-md,.navbar-expand-md>.container-sm,.navbar-expand-md>.container-xl{flex-wrap:nowrap}.navbar-expand-md .navbar-nav-scroll{overflow:visible}.navbar-expand-md .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-md .navbar-toggler{display:none}}@media (max-width:959.98px){.navbar-expand-lg>.container,.navbar-expand-lg>.container-fluid,.navbar-expand-lg>.container-lg,.navbar-expand-lg>.container-md,.navbar-expand-lg>.container-sm,.navbar-expand-lg>.container-xl{padding-left:0;padding-right:0}}@media (min-width:960px){.navbar-expand-lg{flex-flow:row nowrap;justify-content:flex-start}.navbar-expand-lg .navbar-nav{flex-direction:row}.navbar-expand-lg .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-lg .navbar-nav .nav-link{padding-left:.5rem;padding-right:.5rem}.navbar-expand-lg>.container,.navbar-expand-lg>.container-fluid,.navbar-expand-lg>.container-lg,.navbar-expand-lg>.container-md,.navbar-expand-lg>.container-sm,.navbar-expand-lg>.container-xl{flex-wrap:nowrap}.navbar-expand-lg .navbar-nav-scroll{overflow:visible}.navbar-expand-lg .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-lg .navbar-toggler{display:none}}@media (max-width:1199.98px){.navbar-expand-xl>.container,.navbar-expand-xl>.container-fluid,.navbar-expand-xl>.container-lg,.navbar-expand-xl>.container-md,.navbar-expand-xl>.container-sm,.navbar-expand-xl>.container-xl{padding-left:0;padding-right:0}}@media (min-width:1200px){.navbar-expand-xl{flex-flow:row nowrap;justify-content:flex-start}.navbar-expand-xl .navbar-nav{flex-direction:row}.navbar-expand-xl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xl .navbar-nav .nav-link{padding-left:.5rem;padding-right:.5rem}.navbar-expand-xl>.container,.navbar-expand-xl>.container-fluid,.navbar-expand-xl>.container-lg,.navbar-expand-xl>.container-md,.navbar-expand-xl>.container-sm,.navbar-expand-xl>.container-xl{flex-wrap:nowrap}.navbar-expand-xl .navbar-nav-scroll{overflow:visible}.navbar-expand-xl .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-xl .navbar-toggler{display:none}}.navbar-expand{flex-flow:row nowrap;justify-content:flex-start}.navbar-expand>.container,.navbar-expand>.container-fluid,.navbar-expand>.container-lg,.navbar-expand>.container-md,.navbar-expand>.container-sm,.navbar-expand>.container-xl{padding-left:0;padding-right:0}.navbar-expand .navbar-nav{flex-direction:row}.navbar-expand .navbar-nav .dropdown-menu{position:absolute}.navbar-expand .navbar-nav .nav-link{padding-left:.5rem;padding-right:.5rem}.navbar-expand>.container,.navbar-expand>.container-fluid,.navbar-expand>.container-lg,.navbar-expand>.container-md,.navbar-expand>.container-sm,.navbar-expand>.container-xl{flex-wrap:nowrap}.navbar-expand .navbar-nav-scroll{overflow:visible}.navbar-expand .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand .navbar-toggler{display:none}.navbar-light .navbar-brand,.navbar-light .navbar-brand:focus,.navbar-light .navbar-brand:hover{color:rgba(0,0,0,.9)}.navbar-light .navbar-nav .nav-link{color:rgba(0,0,0,.5)}.navbar-light .navbar-nav .nav-link:focus,.navbar-light .navbar-nav .nav-link:hover{color:rgba(0,0,0,.7)}.navbar-light .navbar-nav .nav-link.disabled{color:rgba(0,0,0,.3)}.navbar-light .navbar-nav .active>.nav-link,.navbar-light .navbar-nav .nav-link.active,.navbar-light .navbar-nav .nav-link.show,.navbar-light .navbar-nav .show>.nav-link{color:rgba(0,0,0,.9)}.navbar-light .navbar-toggler{border-color:rgba(0,0,0,.1);color:rgba(0,0,0,.5)}.navbar-light .navbar-toggler-icon{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='30' height='30'%3E%3Cpath stroke='rgba(0,0,0,0.5)' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3E%3C/svg%3E")}.navbar-light .navbar-text{color:rgba(0,0,0,.5)}.navbar-light .navbar-text a,.navbar-light .navbar-text a:focus,.navbar-light .navbar-text a:hover{color:rgba(0,0,0,.9)}.navbar-dark .navbar-brand,.navbar-dark .navbar-brand:focus,.navbar-dark .navbar-brand:hover{color:#fff}.navbar-dark .navbar-nav .nav-link{color:hsla(0,0%,100%,.5)}.navbar-dark .navbar-nav .nav-link:focus,.navbar-dark .navbar-nav .nav-link:hover{color:hsla(0,0%,100%,.75)}.navbar-dark .navbar-nav .nav-link.disabled{color:hsla(0,0%,100%,.25)}.navbar-dark .navbar-nav .active>.nav-link,.navbar-dark .navbar-nav .nav-link.active,.navbar-dark .navbar-nav .nav-link.show,.navbar-dark .navbar-nav .show>.nav-link{color:#fff}.navbar-dark .navbar-toggler{border-color:hsla(0,0%,100%,.1);color:hsla(0,0%,100%,.5)}.navbar-dark .navbar-toggler-icon{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='30' height='30'%3E%3Cpath stroke='rgba(255,255,255,0.5)' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3E%3C/svg%3E")}.navbar-dark .navbar-text{color:hsla(0,0%,100%,.5)}.navbar-dark .navbar-text a,.navbar-dark .navbar-text a:focus,.navbar-dark .navbar-text a:hover{color:#fff}.card{word-wrap:break-word;background-clip:border-box;background-color:#fff;border:1px solid rgba(0,0,0,.125);border-radius:.25rem;display:flex;flex-direction:column;min-width:0;position:relative}.card>hr{margin-left:0;margin-right:0}.card>.list-group{border-bottom:inherit;border-top:inherit}.card>.list-group:first-child{border-top-left-radius:calc(.25rem - 1px);border-top-right-radius:calc(.25rem - 1px);border-top-width:0}.card>.list-group:last-child{border-bottom-left-radius:calc(.25rem - 1px);border-bottom-right-radius:calc(.25rem - 1px);border-bottom-width:0}.card>.card-header+.list-group,.card>.list-group+.card-footer{border-top:0}.card-body{flex:1 1 auto;min-height:1px;padding:1.25rem}.card-title{margin-bottom:.75rem}.card-subtitle{margin-top:-.375rem}.card-subtitle,.card-text:last-child{margin-bottom:0}.card-link:hover{text-decoration:none}.card-link+.card-link{margin-left:1.25rem}.card-header{background-color:rgba(0,0,0,.03);border-bottom:1px solid rgba(0,0,0,.125);margin-bottom:0;padding:.75rem 1.25rem}.card-header:first-child{border-radius:calc(.25rem - 1px) calc(.25rem - 1px) 0 0}.card-footer{background-color:rgba(0,0,0,.03);border-top:1px solid rgba(0,0,0,.125);padding:.75rem 1.25rem}.card-footer:last-child{border-radius:0 0 calc(.25rem - 1px) calc(.25rem - 1px)}.card-header-tabs{border-bottom:0;margin-bottom:-.75rem}.card-header-pills,.card-header-tabs{margin-left:-.625rem;margin-right:-.625rem}.card-img-overlay{border-radius:calc(.25rem - 1px);bottom:0;left:0;padding:1.25rem;position:absolute;right:0;top:0}.card-img,.card-img-bottom,.card-img-top{flex-shrink:0;width:100%}.card-img,.card-img-top{border-top-left-radius:calc(.25rem - 1px);border-top-right-radius:calc(.25rem - 1px)}.card-img,.card-img-bottom{border-bottom-left-radius:calc(.25rem - 1px);border-bottom-right-radius:calc(.25rem - 1px)}.card-deck .card{margin-bottom:15px}@media (min-width:540px){.card-deck{display:flex;flex-flow:row wrap;margin-left:-15px;margin-right:-15px}.card-deck .card{flex:1 0 0%;margin-bottom:0;margin-left:15px;margin-right:15px}}.card-group>.card{margin-bottom:15px}@media (min-width:540px){.card-group{display:flex;flex-flow:row wrap}.card-group>.card{flex:1 0 0%;margin-bottom:0}.card-group>.card+.card{border-left:0;margin-left:0}.card-group>.card:not(:last-child){border-bottom-right-radius:0;border-top-right-radius:0}.card-group>.card:not(:last-child) .card-header,.card-group>.card:not(:last-child) .card-img-top{border-top-right-radius:0}.card-group>.card:not(:last-child) .card-footer,.card-group>.card:not(:last-child) .card-img-bottom{border-bottom-right-radius:0}.card-group>.card:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.card-group>.card:not(:first-child) .card-header,.card-group>.card:not(:first-child) .card-img-top{border-top-left-radius:0}.card-group>.card:not(:first-child) .card-footer,.card-group>.card:not(:first-child) .card-img-bottom{border-bottom-left-radius:0}}.card-columns .card{margin-bottom:.75rem}@media (min-width:540px){.card-columns{column-count:3;column-gap:1.25rem;orphans:1;widows:1}.card-columns .card{display:inline-block;width:100%}}.accordion{overflow-anchor:none}.accordion>.card{overflow:hidden}.accordion>.card:not(:last-of-type){border-bottom:0;border-bottom-left-radius:0;border-bottom-right-radius:0}.accordion>.card:not(:first-of-type){border-top-left-radius:0;border-top-right-radius:0}.accordion>.card>.card-header{border-radius:0;margin-bottom:-1px}.breadcrumb{background-color:#e9ecef;border-radius:.25rem;display:flex;flex-wrap:wrap;list-style:none;margin-bottom:1rem;padding:.75rem 1rem}.breadcrumb-item+.breadcrumb-item{padding-left:.5rem}.breadcrumb-item+.breadcrumb-item:before{color:#6c757d;content:"/";float:left;padding-right:.5rem}.breadcrumb-item+.breadcrumb-item:hover:before{text-decoration:underline;text-decoration:none}.breadcrumb-item.active{color:#6c757d}.pagination{border-radius:.25rem;display:flex;list-style:none;padding-left:0}.page-link{background-color:#fff;border:1px solid #dee2e6;color:#007bff;display:block;line-height:1.25;margin-left:-1px;padding:.5rem .75rem;position:relative}.page-link:hover{background-color:#e9ecef;border-color:#dee2e6;color:#0056b3;text-decoration:none;z-index:2}.page-link:focus{box-shadow:0 0 0 .2rem rgba(0,123,255,.25);outline:0;z-index:3}.page-item:first-child .page-link{border-bottom-left-radius:.25rem;border-top-left-radius:.25rem;margin-left:0}.page-item:last-child .page-link{border-bottom-right-radius:.25rem;border-top-right-radius:.25rem}.page-item.active .page-link{background-color:#007bff;border-color:#007bff;color:#fff;z-index:3}.page-item.disabled .page-link{background-color:#fff;border-color:#dee2e6;color:#6c757d;cursor:auto;pointer-events:none}.pagination-lg .page-link{font-size:1.25rem;line-height:1.5;padding:.75rem 1.5rem}.pagination-lg .page-item:first-child .page-link{border-bottom-left-radius:.3rem;border-top-left-radius:.3rem}.pagination-lg .page-item:last-child .page-link{border-bottom-right-radius:.3rem;border-top-right-radius:.3rem}.pagination-sm .page-link{font-size:.875rem;line-height:1.5;padding:.25rem .5rem}.pagination-sm .page-item:first-child .page-link{border-bottom-left-radius:.2rem;border-top-left-radius:.2rem}.pagination-sm .page-item:last-child .page-link{border-bottom-right-radius:.2rem;border-top-right-radius:.2rem}.badge{border-radius:.25rem;display:inline-block;font-size:75%;font-weight:700;line-height:1;padding:.25em .4em;text-align:center;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;vertical-align:baseline;white-space:nowrap}@media (prefers-reduced-motion:reduce){.badge{transition:none}}a.badge:focus,a.badge:hover{text-decoration:none}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.badge-pill{border-radius:10rem;padding-left:.6em;padding-right:.6em}.badge-primary{background-color:#007bff;color:#fff}a.badge-primary:focus,a.badge-primary:hover{background-color:#0062cc;color:#fff}a.badge-primary.focus,a.badge-primary:focus{box-shadow:0 0 0 .2rem rgba(0,123,255,.5);outline:0}.badge-secondary{background-color:#6c757d;color:#fff}a.badge-secondary:focus,a.badge-secondary:hover{background-color:#545b62;color:#fff}a.badge-secondary.focus,a.badge-secondary:focus{box-shadow:0 0 0 .2rem hsla(208,7%,46%,.5);outline:0}.badge-success{background-color:#28a745;color:#fff}a.badge-success:focus,a.badge-success:hover{background-color:#1e7e34;color:#fff}a.badge-success.focus,a.badge-success:focus{box-shadow:0 0 0 .2rem rgba(40,167,69,.5);outline:0}.badge-info{background-color:#17a2b8;color:#fff}a.badge-info:focus,a.badge-info:hover{background-color:#117a8b;color:#fff}a.badge-info.focus,a.badge-info:focus{box-shadow:0 0 0 .2rem rgba(23,162,184,.5);outline:0}.badge-warning{background-color:#ffc107;color:#212529}a.badge-warning:focus,a.badge-warning:hover{background-color:#d39e00;color:#212529}a.badge-warning.focus,a.badge-warning:focus{box-shadow:0 0 0 .2rem rgba(255,193,7,.5);outline:0}.badge-danger{background-color:#dc3545;color:#fff}a.badge-danger:focus,a.badge-danger:hover{background-color:#bd2130;color:#fff}a.badge-danger.focus,a.badge-danger:focus{box-shadow:0 0 0 .2rem rgba(220,53,69,.5);outline:0}.badge-light{background-color:#f8f9fa;color:#212529}a.badge-light:focus,a.badge-light:hover{background-color:#dae0e5;color:#212529}a.badge-light.focus,a.badge-light:focus{box-shadow:0 0 0 .2rem rgba(248,249,250,.5);outline:0}.badge-dark{background-color:#343a40;color:#fff}a.badge-dark:focus,a.badge-dark:hover{background-color:#1d2124;color:#fff}a.badge-dark.focus,a.badge-dark:focus{box-shadow:0 0 0 .2rem rgba(52,58,64,.5);outline:0}.jumbotron{background-color:#e9ecef;border-radius:.3rem;margin-bottom:2rem;padding:2rem 1rem}@media (min-width:540px){.jumbotron{padding:4rem 2rem}}.jumbotron-fluid{border-radius:0;padding-left:0;padding-right:0}.alert{border:1px solid transparent;border-radius:.25rem;margin-bottom:1rem;padding:.75rem 1.25rem;position:relative}.alert-heading{color:inherit}.alert-link{font-weight:700}.alert-dismissible{padding-right:4rem}.alert-dismissible .close{color:inherit;padding:.75rem 1.25rem;position:absolute;right:0;top:0;z-index:2}.alert-primary{background-color:#cce5ff;border-color:#b8daff;color:#004085}.alert-primary hr{border-top-color:#9fcdff}.alert-primary .alert-link{color:#002752}.alert-secondary{background-color:#e2e3e5;border-color:#d6d8db;color:#383d41}.alert-secondary hr{border-top-color:#c8cbcf}.alert-secondary .alert-link{color:#202326}.alert-success{background-color:#d4edda;border-color:#c3e6cb;color:#155724}.alert-success hr{border-top-color:#b1dfbb}.alert-success .alert-link{color:#0b2e13}.alert-info{background-color:#d1ecf1;border-color:#bee5eb;color:#0c5460}.alert-info hr{border-top-color:#abdde5}.alert-info .alert-link{color:#062c33}.alert-warning{background-color:#fff3cd;border-color:#ffeeba;color:#856404}.alert-warning hr{border-top-color:#ffe8a1}.alert-warning .alert-link{color:#533f03}.alert-danger{background-color:#f8d7da;border-color:#f5c6cb;color:#721c24}.alert-danger hr{border-top-color:#f1b0b7}.alert-danger .alert-link{color:#491217}.alert-light{background-color:#fefefe;border-color:#fdfdfe;color:#818182}.alert-light hr{border-top-color:#ececf6}.alert-light .alert-link{color:#686868}.alert-dark{background-color:#d6d8d9;border-color:#c6c8ca;color:#1b1e21}.alert-dark hr{border-top-color:#b9bbbe}.alert-dark .alert-link{color:#040505}@keyframes progress-bar-stripes{0%{background-position:1rem 0}to{background-position:0 0}}.progress{background-color:#e9ecef;border-radius:.25rem;font-size:.75rem;height:1rem;line-height:0}.progress,.progress-bar{display:flex;overflow:hidden}.progress-bar{background-color:#007bff;color:#fff;flex-direction:column;justify-content:center;text-align:center;transition:width .6s ease;white-space:nowrap}@media (prefers-reduced-motion:reduce){.progress-bar{transition:none}}.progress-bar-striped{background-image:linear-gradient(45deg,hsla(0,0%,100%,.15) 25%,transparent 0,transparent 50%,hsla(0,0%,100%,.15) 0,hsla(0,0%,100%,.15) 75%,transparent 0,transparent);background-size:1rem 1rem}.progress-bar-animated{animation:progress-bar-stripes 1s linear infinite}@media (prefers-reduced-motion:reduce){.progress-bar-animated{animation:none}}.media{align-items:flex-start;display:flex}.media-body{flex:1}.list-group{border-radius:.25rem;display:flex;flex-direction:column;margin-bottom:0;padding-left:0}.list-group-item-action{color:#495057;text-align:inherit;width:100%}.list-group-item-action:focus,.list-group-item-action:hover{background-color:#f8f9fa;color:#495057;text-decoration:none;z-index:1}.list-group-item-action:active{background-color:#e9ecef;color:#212529}.list-group-item{background-color:#fff;border:1px solid rgba(0,0,0,.125);display:block;padding:.75rem 1.25rem;position:relative}.list-group-item:first-child{border-top-left-radius:inherit;border-top-right-radius:inherit}.list-group-item:last-child{border-bottom-left-radius:inherit;border-bottom-right-radius:inherit}.list-group-item.disabled,.list-group-item:disabled{background-color:#fff;color:#6c757d;pointer-events:none}.list-group-item.active{background-color:#007bff;border-color:#007bff;color:#fff;z-index:2}.list-group-item+.list-group-item{border-top-width:0}.list-group-item+.list-group-item.active{border-top-width:1px;margin-top:-1px}.list-group-horizontal{flex-direction:row}.list-group-horizontal>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal>.list-group-item:last-child{border-bottom-left-radius:0;border-top-right-radius:.25rem}.list-group-horizontal>.list-group-item.active{margin-top:0}.list-group-horizontal>.list-group-item+.list-group-item{border-left-width:0;border-top-width:1px}.list-group-horizontal>.list-group-item+.list-group-item.active{border-left-width:1px;margin-left:-1px}@media (min-width:540px){.list-group-horizontal-sm{flex-direction:row}.list-group-horizontal-sm>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-sm>.list-group-item:last-child{border-bottom-left-radius:0;border-top-right-radius:.25rem}.list-group-horizontal-sm>.list-group-item.active{margin-top:0}.list-group-horizontal-sm>.list-group-item+.list-group-item{border-left-width:0;border-top-width:1px}.list-group-horizontal-sm>.list-group-item+.list-group-item.active{border-left-width:1px;margin-left:-1px}}@media (min-width:720px){.list-group-horizontal-md{flex-direction:row}.list-group-horizontal-md>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-md>.list-group-item:last-child{border-bottom-left-radius:0;border-top-right-radius:.25rem}.list-group-horizontal-md>.list-group-item.active{margin-top:0}.list-group-horizontal-md>.list-group-item+.list-group-item{border-left-width:0;border-top-width:1px}.list-group-horizontal-md>.list-group-item+.list-group-item.active{border-left-width:1px;margin-left:-1px}}@media (min-width:960px){.list-group-horizontal-lg{flex-direction:row}.list-group-horizontal-lg>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-lg>.list-group-item:last-child{border-bottom-left-radius:0;border-top-right-radius:.25rem}.list-group-horizontal-lg>.list-group-item.active{margin-top:0}.list-group-horizontal-lg>.list-group-item+.list-group-item{border-left-width:0;border-top-width:1px}.list-group-horizontal-lg>.list-group-item+.list-group-item.active{border-left-width:1px;margin-left:-1px}}@media (min-width:1200px){.list-group-horizontal-xl{flex-direction:row}.list-group-horizontal-xl>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-xl>.list-group-item:last-child{border-bottom-left-radius:0;border-top-right-radius:.25rem}.list-group-horizontal-xl>.list-group-item.active{margin-top:0}.list-group-horizontal-xl>.list-group-item+.list-group-item{border-left-width:0;border-top-width:1px}.list-group-horizontal-xl>.list-group-item+.list-group-item.active{border-left-width:1px;margin-left:-1px}}.list-group-flush{border-radius:0}.list-group-flush>.list-group-item{border-width:0 0 1px}.list-group-flush>.list-group-item:last-child{border-bottom-width:0}.list-group-item-primary{background-color:#b8daff;color:#004085}.list-group-item-primary.list-group-item-action:focus,.list-group-item-primary.list-group-item-action:hover{background-color:#9fcdff;color:#004085}.list-group-item-primary.list-group-item-action.active{background-color:#004085;border-color:#004085;color:#fff}.list-group-item-secondary{background-color:#d6d8db;color:#383d41}.list-group-item-secondary.list-group-item-action:focus,.list-group-item-secondary.list-group-item-action:hover{background-color:#c8cbcf;color:#383d41}.list-group-item-secondary.list-group-item-action.active{background-color:#383d41;border-color:#383d41;color:#fff}.list-group-item-success{background-color:#c3e6cb;color:#155724}.list-group-item-success.list-group-item-action:focus,.list-group-item-success.list-group-item-action:hover{background-color:#b1dfbb;color:#155724}.list-group-item-success.list-group-item-action.active{background-color:#155724;border-color:#155724;color:#fff}.list-group-item-info{background-color:#bee5eb;color:#0c5460}.list-group-item-info.list-group-item-action:focus,.list-group-item-info.list-group-item-action:hover{background-color:#abdde5;color:#0c5460}.list-group-item-info.list-group-item-action.active{background-color:#0c5460;border-color:#0c5460;color:#fff}.list-group-item-warning{background-color:#ffeeba;color:#856404}.list-group-item-warning.list-group-item-action:focus,.list-group-item-warning.list-group-item-action:hover{background-color:#ffe8a1;color:#856404}.list-group-item-warning.list-group-item-action.active{background-color:#856404;border-color:#856404;color:#fff}.list-group-item-danger{background-color:#f5c6cb;color:#721c24}.list-group-item-danger.list-group-item-action:focus,.list-group-item-danger.list-group-item-action:hover{background-color:#f1b0b7;color:#721c24}.list-group-item-danger.list-group-item-action.active{background-color:#721c24;border-color:#721c24;color:#fff}.list-group-item-light{background-color:#fdfdfe;color:#818182}.list-group-item-light.list-group-item-action:focus,.list-group-item-light.list-group-item-action:hover{background-color:#ececf6;color:#818182}.list-group-item-light.list-group-item-action.active{background-color:#818182;border-color:#818182;color:#fff}.list-group-item-dark{background-color:#c6c8ca;color:#1b1e21}.list-group-item-dark.list-group-item-action:focus,.list-group-item-dark.list-group-item-action:hover{background-color:#b9bbbe;color:#1b1e21}.list-group-item-dark.list-group-item-action.active{background-color:#1b1e21;border-color:#1b1e21;color:#fff}.close{color:#000;float:right;font-size:1.5rem;font-weight:700;line-height:1;opacity:.5;text-shadow:0 1px 0 #fff}.close:hover{color:#000;text-decoration:none}.close:not(:disabled):not(.disabled):focus,.close:not(:disabled):not(.disabled):hover{opacity:.75}button.close{background-color:transparent;border:0;padding:0}a.close.disabled{pointer-events:none}.toast{background-clip:padding-box;background-color:hsla(0,0%,100%,.85);border:1px solid rgba(0,0,0,.1);border-radius:.25rem;box-shadow:0 .25rem .75rem rgba(0,0,0,.1);flex-basis:350px;font-size:.875rem;max-width:350px;opacity:0}.toast:not(:last-child){margin-bottom:.75rem}.toast.showing{opacity:1}.toast.show{display:block;opacity:1}.toast.hide{display:none}.toast-header{align-items:center;background-clip:padding-box;background-color:hsla(0,0%,100%,.85);border-bottom:1px solid rgba(0,0,0,.05);border-top-left-radius:calc(.25rem - 1px);border-top-right-radius:calc(.25rem - 1px);color:#6c757d;display:flex;padding:.25rem .75rem}.toast-body{padding:.75rem}.modal-open{overflow:hidden}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal{display:none;height:100%;left:0;outline:0;overflow:hidden;position:fixed;top:0;width:100%;z-index:1050}.modal-dialog{margin:.5rem;pointer-events:none;position:relative;width:auto}.modal.fade .modal-dialog{transform:translateY(-50px);transition:transform .3s ease-out}@media (prefers-reduced-motion:reduce){.modal.fade .modal-dialog{transition:none}}.modal.show .modal-dialog{transform:none}.modal.modal-static .modal-dialog{transform:scale(1.02)}.modal-dialog-scrollable{display:flex;max-height:calc(100% - 1rem)}.modal-dialog-scrollable .modal-content{max-height:calc(100vh - 1rem);overflow:hidden}.modal-dialog-scrollable .modal-footer,.modal-dialog-scrollable .modal-header{flex-shrink:0}.modal-dialog-scrollable .modal-body{overflow-y:auto}.modal-dialog-centered{align-items:center;display:flex;min-height:calc(100% - 1rem)}.modal-dialog-centered:before{content:"";display:block;height:calc(100vh - 1rem);height:min-content}.modal-dialog-centered.modal-dialog-scrollable{flex-direction:column;height:100%;justify-content:center}.modal-dialog-centered.modal-dialog-scrollable .modal-content{max-height:none}.modal-dialog-centered.modal-dialog-scrollable:before{content:none}.modal-content{background-clip:padding-box;background-color:#fff;border:1px solid rgba(0,0,0,.2);border-radius:.3rem;display:flex;flex-direction:column;outline:0;pointer-events:auto;position:relative;width:100%}.modal-backdrop{background-color:#000;height:100vh;left:0;position:fixed;top:0;width:100vw;z-index:1040}.modal-backdrop.fade{opacity:0}.modal-backdrop.show{opacity:.5}.modal-header{align-items:flex-start;border-bottom:1px solid #dee2e6;border-top-left-radius:calc(.3rem - 1px);border-top-right-radius:calc(.3rem - 1px);display:flex;justify-content:space-between;padding:1rem}.modal-header .close{margin:-1rem -1rem -1rem auto;padding:1rem}.modal-title{line-height:1.5;margin-bottom:0}.modal-body{flex:1 1 auto;padding:1rem;position:relative}.modal-footer{align-items:center;border-bottom-left-radius:calc(.3rem - 1px);border-bottom-right-radius:calc(.3rem - 1px);border-top:1px solid #dee2e6;display:flex;flex-wrap:wrap;justify-content:flex-end;padding:.75rem}.modal-footer>*{margin:.25rem}.modal-scrollbar-measure{height:50px;overflow:scroll;position:absolute;top:-9999px;width:50px}@media (min-width:540px){.modal-dialog{margin:1.75rem auto;max-width:500px}.modal-dialog-scrollable{max-height:calc(100% - 3.5rem)}.modal-dialog-scrollable .modal-content{max-height:calc(100vh - 3.5rem)}.modal-dialog-centered{min-height:calc(100% - 3.5rem)}.modal-dialog-centered:before{height:calc(100vh - 3.5rem);height:min-content}.modal-sm{max-width:300px}}@media (min-width:960px){.modal-lg,.modal-xl{max-width:800px}}@media (min-width:1200px){.modal-xl{max-width:1140px}}.tooltip{word-wrap:break-word;display:block;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,Liberation Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;font-size:.875rem;font-style:normal;font-weight:400;letter-spacing:normal;line-break:auto;line-height:1.5;margin:0;opacity:0;position:absolute;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;white-space:normal;word-break:normal;word-spacing:normal;z-index:1070}.tooltip.show{opacity:.9}.tooltip .arrow{display:block;height:.4rem;position:absolute;width:.8rem}.tooltip .arrow:before{border-color:transparent;border-style:solid;content:"";position:absolute}.bs-tooltip-auto[x-placement^=top],.bs-tooltip-top{padding:.4rem 0}.bs-tooltip-auto[x-placement^=top] .arrow,.bs-tooltip-top .arrow{bottom:0}.bs-tooltip-auto[x-placement^=top] .arrow:before,.bs-tooltip-top .arrow:before{border-top-color:#000;border-width:.4rem .4rem 0;top:0}.bs-tooltip-auto[x-placement^=right],.bs-tooltip-right{padding:0 .4rem}.bs-tooltip-auto[x-placement^=right] .arrow,.bs-tooltip-right .arrow{height:.8rem;left:0;width:.4rem}.bs-tooltip-auto[x-placement^=right] .arrow:before,.bs-tooltip-right .arrow:before{border-right-color:#000;border-width:.4rem .4rem .4rem 0;right:0}.bs-tooltip-auto[x-placement^=bottom],.bs-tooltip-bottom{padding:.4rem 0}.bs-tooltip-auto[x-placement^=bottom] .arrow,.bs-tooltip-bottom .arrow{top:0}.bs-tooltip-auto[x-placement^=bottom] .arrow:before,.bs-tooltip-bottom .arrow:before{border-bottom-color:#000;border-width:0 .4rem .4rem;bottom:0}.bs-tooltip-auto[x-placement^=left],.bs-tooltip-left{padding:0 .4rem}.bs-tooltip-auto[x-placement^=left] .arrow,.bs-tooltip-left .arrow{height:.8rem;right:0;width:.4rem}.bs-tooltip-auto[x-placement^=left] .arrow:before,.bs-tooltip-left .arrow:before{border-left-color:#000;border-width:.4rem 0 .4rem .4rem;left:0}.tooltip-inner{background-color:#000;border-radius:.25rem;color:#fff;max-width:200px;padding:.25rem .5rem;text-align:center}.popover{word-wrap:break-word;background-clip:padding-box;background-color:#fff;border:1px solid rgba(0,0,0,.2);border-radius:.3rem;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,Liberation Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;font-size:.875rem;font-style:normal;font-weight:400;left:0;letter-spacing:normal;line-break:auto;line-height:1.5;max-width:276px;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;top:0;white-space:normal;word-break:normal;word-spacing:normal;z-index:1060}.popover,.popover .arrow{display:block;position:absolute}.popover .arrow{height:.5rem;margin:0 .3rem;width:1rem}.popover .arrow:after,.popover .arrow:before{border-color:transparent;border-style:solid;content:"";display:block;position:absolute}.bs-popover-auto[x-placement^=top],.bs-popover-top{margin-bottom:.5rem}.bs-popover-auto[x-placement^=top]>.arrow,.bs-popover-top>.arrow{bottom:calc(-.5rem - 1px)}.bs-popover-auto[x-placement^=top]>.arrow:before,.bs-popover-top>.arrow:before{border-top-color:rgba(0,0,0,.25);border-width:.5rem .5rem 0;bottom:0}.bs-popover-auto[x-placement^=top]>.arrow:after,.bs-popover-top>.arrow:after{border-top-color:#fff;border-width:.5rem .5rem 0;bottom:1px}.bs-popover-auto[x-placement^=right],.bs-popover-right{margin-left:.5rem}.bs-popover-auto[x-placement^=right]>.arrow,.bs-popover-right>.arrow{height:1rem;left:calc(-.5rem - 1px);margin:.3rem 0;width:.5rem}.bs-popover-auto[x-placement^=right]>.arrow:before,.bs-popover-right>.arrow:before{border-right-color:rgba(0,0,0,.25);border-width:.5rem .5rem .5rem 0;left:0}.bs-popover-auto[x-placement^=right]>.arrow:after,.bs-popover-right>.arrow:after{border-right-color:#fff;border-width:.5rem .5rem .5rem 0;left:1px}.bs-popover-auto[x-placement^=bottom],.bs-popover-bottom{margin-top:.5rem}.bs-popover-auto[x-placement^=bottom]>.arrow,.bs-popover-bottom>.arrow{top:calc(-.5rem - 1px)}.bs-popover-auto[x-placement^=bottom]>.arrow:before,.bs-popover-bottom>.arrow:before{border-bottom-color:rgba(0,0,0,.25);border-width:0 .5rem .5rem;top:0}.bs-popover-auto[x-placement^=bottom]>.arrow:after,.bs-popover-bottom>.arrow:after{border-bottom-color:#fff;border-width:0 .5rem .5rem;top:1px}.bs-popover-auto[x-placement^=bottom] .popover-header:before,.bs-popover-bottom .popover-header:before{border-bottom:1px solid #f7f7f7;content:"";display:block;left:50%;margin-left:-.5rem;position:absolute;top:0;width:1rem}.bs-popover-auto[x-placement^=left],.bs-popover-left{margin-right:.5rem}.bs-popover-auto[x-placement^=left]>.arrow,.bs-popover-left>.arrow{height:1rem;margin:.3rem 0;right:calc(-.5rem - 1px);width:.5rem}.bs-popover-auto[x-placement^=left]>.arrow:before,.bs-popover-left>.arrow:before{border-left-color:rgba(0,0,0,.25);border-width:.5rem 0 .5rem .5rem;right:0}.bs-popover-auto[x-placement^=left]>.arrow:after,.bs-popover-left>.arrow:after{border-left-color:#fff;border-width:.5rem 0 .5rem .5rem;right:1px}.popover-header{background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-top-left-radius:calc(.3rem - 1px);border-top-right-radius:calc(.3rem - 1px);font-size:1rem;margin-bottom:0;padding:.5rem .75rem}.popover-header:empty{display:none}.popover-body{color:#212529;padding:.5rem .75rem}.carousel{position:relative}.carousel.pointer-event{touch-action:pan-y}.carousel-inner{overflow:hidden;position:relative;width:100%}.carousel-inner:after{clear:both;content:"";display:block}.carousel-item{backface-visibility:hidden;display:none;float:left;margin-right:-100%;position:relative;transition:transform .6s ease-in-out;width:100%}@media (prefers-reduced-motion:reduce){.carousel-item{transition:none}}.carousel-item-next,.carousel-item-prev,.carousel-item.active{display:block}.active.carousel-item-right,.carousel-item-next:not(.carousel-item-left){transform:translateX(100%)}.active.carousel-item-left,.carousel-item-prev:not(.carousel-item-right){transform:translateX(-100%)}.carousel-fade .carousel-item{opacity:0;transform:none;transition-property:opacity}.carousel-fade .carousel-item-next.carousel-item-left,.carousel-fade .carousel-item-prev.carousel-item-right,.carousel-fade .carousel-item.active{opacity:1;z-index:1}.carousel-fade .active.carousel-item-left,.carousel-fade .active.carousel-item-right{opacity:0;transition:opacity 0s .6s;z-index:0}@media (prefers-reduced-motion:reduce){.carousel-fade .active.carousel-item-left,.carousel-fade .active.carousel-item-right{transition:none}}.carousel-control-next,.carousel-control-prev{align-items:center;background:none;border:0;bottom:0;color:#fff;display:flex;justify-content:center;opacity:.5;padding:0;position:absolute;text-align:center;top:0;transition:opacity .15s ease;width:15%;z-index:1}@media (prefers-reduced-motion:reduce){.carousel-control-next,.carousel-control-prev{transition:none}}.carousel-control-next:focus,.carousel-control-next:hover,.carousel-control-prev:focus,.carousel-control-prev:hover{color:#fff;opacity:.9;outline:0;text-decoration:none}.carousel-control-prev{left:0}.carousel-control-next{right:0}.carousel-control-next-icon,.carousel-control-prev-icon{background:50%/100% 100% no-repeat;display:inline-block;height:20px;width:20px}.carousel-control-prev-icon{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' width='8' height='8'%3E%3Cpath d='m5.25 0-4 4 4 4 1.5-1.5L4.25 4l2.5-2.5L5.25 0z'/%3E%3C/svg%3E")}.carousel-control-next-icon{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' width='8' height='8'%3E%3Cpath d='m2.75 0-1.5 1.5L3.75 4l-2.5 2.5L2.75 8l4-4-4-4z'/%3E%3C/svg%3E")}.carousel-indicators{bottom:0;display:flex;justify-content:center;left:0;list-style:none;margin-left:15%;margin-right:15%;padding-left:0;position:absolute;right:0;z-index:15}.carousel-indicators li{background-clip:padding-box;background-color:#fff;border-bottom:10px solid transparent;border-top:10px solid transparent;box-sizing:content-box;cursor:pointer;flex:0 1 auto;height:3px;margin-left:3px;margin-right:3px;opacity:.5;text-indent:-999px;transition:opacity .6s ease;width:30px}@media (prefers-reduced-motion:reduce){.carousel-indicators li{transition:none}}.carousel-indicators .active{opacity:1}.carousel-caption{bottom:20px;color:#fff;left:15%;padding-bottom:20px;padding-top:20px;position:absolute;right:15%;text-align:center;z-index:10}@keyframes spinner-border{to{transform:rotate(1turn)}}.spinner-border{animation:spinner-border .75s linear infinite;border:.25em solid;border-radius:50%;border-right:.25em solid transparent;display:inline-block;height:2rem;vertical-align:-.125em;width:2rem}.spinner-border-sm{border-width:.2em;height:1rem;width:1rem}@keyframes spinner-grow{0%{transform:scale(0)}50%{opacity:1;transform:none}}.spinner-grow{animation:spinner-grow .75s linear infinite;background-color:currentColor;border-radius:50%;display:inline-block;height:2rem;opacity:0;vertical-align:-.125em;width:2rem}.spinner-grow-sm{height:1rem;width:1rem}@media (prefers-reduced-motion:reduce){.spinner-border,.spinner-grow{animation-duration:1.5s}}.align-baseline{vertical-align:baseline!important}.align-top{vertical-align:top!important}.align-middle{vertical-align:middle!important}.align-bottom{vertical-align:bottom!important}.align-text-bottom{vertical-align:text-bottom!important}.align-text-top{vertical-align:text-top!important}.bg-primary{background-color:#007bff!important}a.bg-primary:focus,a.bg-primary:hover,button.bg-primary:focus,button.bg-primary:hover{background-color:#0062cc!important}.bg-secondary{background-color:#6c757d!important}a.bg-secondary:focus,a.bg-secondary:hover,button.bg-secondary:focus,button.bg-secondary:hover{background-color:#545b62!important}.bg-success{background-color:#28a745!important}a.bg-success:focus,a.bg-success:hover,button.bg-success:focus,button.bg-success:hover{background-color:#1e7e34!important}.bg-info{background-color:#17a2b8!important}a.bg-info:focus,a.bg-info:hover,button.bg-info:focus,button.bg-info:hover{background-color:#117a8b!important}.bg-warning{background-color:#ffc107!important}a.bg-warning:focus,a.bg-warning:hover,button.bg-warning:focus,button.bg-warning:hover{background-color:#d39e00!important}.bg-danger{background-color:#dc3545!important}a.bg-danger:focus,a.bg-danger:hover,button.bg-danger:focus,button.bg-danger:hover{background-color:#bd2130!important}.bg-light{background-color:#f8f9fa!important}a.bg-light:focus,a.bg-light:hover,button.bg-light:focus,button.bg-light:hover{background-color:#dae0e5!important}.bg-dark{background-color:#343a40!important}a.bg-dark:focus,a.bg-dark:hover,button.bg-dark:focus,button.bg-dark:hover{background-color:#1d2124!important}.bg-white{background-color:#fff!important}.bg-transparent{background-color:transparent!important}.border{border:1px solid #dee2e6!important}.border-top{border-top:1px solid #dee2e6!important}.border-right{border-right:1px solid #dee2e6!important}.border-bottom{border-bottom:1px solid #dee2e6!important}.border-left{border-left:1px solid #dee2e6!important}.border-0{border:0!important}.border-top-0{border-top:0!important}.border-right-0{border-right:0!important}.border-bottom-0{border-bottom:0!important}.border-left-0{border-left:0!important}.border-primary{border-color:#007bff!important}.border-secondary{border-color:#6c757d!important}.border-success{border-color:#28a745!important}.border-info{border-color:#17a2b8!important}.border-warning{border-color:#ffc107!important}.border-danger{border-color:#dc3545!important}.border-light{border-color:#f8f9fa!important}.border-dark{border-color:#343a40!important}.border-white{border-color:#fff!important}.rounded-sm{border-radius:.2rem!important}.rounded{border-radius:.25rem!important}.rounded-top{border-top-left-radius:.25rem!important}.rounded-right,.rounded-top{border-top-right-radius:.25rem!important}.rounded-bottom,.rounded-right{border-bottom-right-radius:.25rem!important}.rounded-bottom,.rounded-left{border-bottom-left-radius:.25rem!important}.rounded-left{border-top-left-radius:.25rem!important}.rounded-lg{border-radius:.3rem!important}.rounded-circle{border-radius:50%!important}.rounded-pill{border-radius:50rem!important}.rounded-0{border-radius:0!important}.clearfix:after{clear:both;content:"";display:block}.d-none{display:none!important}.d-inline{display:inline!important}.d-inline-block{display:inline-block!important}.d-block{display:block!important}.d-table{display:table!important}.d-table-row{display:table-row!important}.d-table-cell{display:table-cell!important}.d-flex{display:flex!important}.d-inline-flex{display:inline-flex!important}@media (min-width:540px){.d-sm-none{display:none!important}.d-sm-inline{display:inline!important}.d-sm-inline-block{display:inline-block!important}.d-sm-block{display:block!important}.d-sm-table{display:table!important}.d-sm-table-row{display:table-row!important}.d-sm-table-cell{display:table-cell!important}.d-sm-flex{display:flex!important}.d-sm-inline-flex{display:inline-flex!important}}@media (min-width:720px){.d-md-none{display:none!important}.d-md-inline{display:inline!important}.d-md-inline-block{display:inline-block!important}.d-md-block{display:block!important}.d-md-table{display:table!important}.d-md-table-row{display:table-row!important}.d-md-table-cell{display:table-cell!important}.d-md-flex{display:flex!important}.d-md-inline-flex{display:inline-flex!important}}@media (min-width:960px){.d-lg-none{display:none!important}.d-lg-inline{display:inline!important}.d-lg-inline-block{display:inline-block!important}.d-lg-block{display:block!important}.d-lg-table{display:table!important}.d-lg-table-row{display:table-row!important}.d-lg-table-cell{display:table-cell!important}.d-lg-flex{display:flex!important}.d-lg-inline-flex{display:inline-flex!important}}@media (min-width:1200px){.d-xl-none{display:none!important}.d-xl-inline{display:inline!important}.d-xl-inline-block{display:inline-block!important}.d-xl-block{display:block!important}.d-xl-table{display:table!important}.d-xl-table-row{display:table-row!important}.d-xl-table-cell{display:table-cell!important}.d-xl-flex{display:flex!important}.d-xl-inline-flex{display:inline-flex!important}}@media print{.d-print-none{display:none!important}.d-print-inline{display:inline!important}.d-print-inline-block{display:inline-block!important}.d-print-block{display:block!important}.d-print-table{display:table!important}.d-print-table-row{display:table-row!important}.d-print-table-cell{display:table-cell!important}.d-print-flex{display:flex!important}.d-print-inline-flex{display:inline-flex!important}}.embed-responsive{display:block;overflow:hidden;padding:0;position:relative;width:100%}.embed-responsive:before{content:"";display:block}.embed-responsive .embed-responsive-item,.embed-responsive embed,.embed-responsive iframe,.embed-responsive object,.embed-responsive video{border:0;bottom:0;height:100%;left:0;position:absolute;top:0;width:100%}.embed-responsive-21by9:before{padding-top:42.85714%}.embed-responsive-16by9:before{padding-top:56.25%}.embed-responsive-4by3:before{padding-top:75%}.embed-responsive-1by1:before{padding-top:100%}.flex-row{flex-direction:row!important}.flex-column{flex-direction:column!important}.flex-row-reverse{flex-direction:row-reverse!important}.flex-column-reverse{flex-direction:column-reverse!important}.flex-wrap{flex-wrap:wrap!important}.flex-nowrap{flex-wrap:nowrap!important}.flex-wrap-reverse{flex-wrap:wrap-reverse!important}.flex-fill{flex:1 1 auto!important}.flex-grow-0{flex-grow:0!important}.flex-grow-1{flex-grow:1!important}.flex-shrink-0{flex-shrink:0!important}.flex-shrink-1{flex-shrink:1!important}.justify-content-start{justify-content:flex-start!important}.justify-content-end{justify-content:flex-end!important}.justify-content-center{justify-content:center!important}.justify-content-between{justify-content:space-between!important}.justify-content-around{justify-content:space-around!important}.align-items-start{align-items:flex-start!important}.align-items-end{align-items:flex-end!important}.align-items-center{align-items:center!important}.align-items-baseline{align-items:baseline!important}.align-items-stretch{align-items:stretch!important}.align-content-start{align-content:flex-start!important}.align-content-end{align-content:flex-end!important}.align-content-center{align-content:center!important}.align-content-between{align-content:space-between!important}.align-content-around{align-content:space-around!important}.align-content-stretch{align-content:stretch!important}.align-self-auto{align-self:auto!important}.align-self-start{align-self:flex-start!important}.align-self-end{align-self:flex-end!important}.align-self-center{align-self:center!important}.align-self-baseline{align-self:baseline!important}.align-self-stretch{align-self:stretch!important}@media (min-width:540px){.flex-sm-row{flex-direction:row!important}.flex-sm-column{flex-direction:column!important}.flex-sm-row-reverse{flex-direction:row-reverse!important}.flex-sm-column-reverse{flex-direction:column-reverse!important}.flex-sm-wrap{flex-wrap:wrap!important}.flex-sm-nowrap{flex-wrap:nowrap!important}.flex-sm-wrap-reverse{flex-wrap:wrap-reverse!important}.flex-sm-fill{flex:1 1 auto!important}.flex-sm-grow-0{flex-grow:0!important}.flex-sm-grow-1{flex-grow:1!important}.flex-sm-shrink-0{flex-shrink:0!important}.flex-sm-shrink-1{flex-shrink:1!important}.justify-content-sm-start{justify-content:flex-start!important}.justify-content-sm-end{justify-content:flex-end!important}.justify-content-sm-center{justify-content:center!important}.justify-content-sm-between{justify-content:space-between!important}.justify-content-sm-around{justify-content:space-around!important}.align-items-sm-start{align-items:flex-start!important}.align-items-sm-end{align-items:flex-end!important}.align-items-sm-center{align-items:center!important}.align-items-sm-baseline{align-items:baseline!important}.align-items-sm-stretch{align-items:stretch!important}.align-content-sm-start{align-content:flex-start!important}.align-content-sm-end{align-content:flex-end!important}.align-content-sm-center{align-content:center!important}.align-content-sm-between{align-content:space-between!important}.align-content-sm-around{align-content:space-around!important}.align-content-sm-stretch{align-content:stretch!important}.align-self-sm-auto{align-self:auto!important}.align-self-sm-start{align-self:flex-start!important}.align-self-sm-end{align-self:flex-end!important}.align-self-sm-center{align-self:center!important}.align-self-sm-baseline{align-self:baseline!important}.align-self-sm-stretch{align-self:stretch!important}}@media (min-width:720px){.flex-md-row{flex-direction:row!important}.flex-md-column{flex-direction:column!important}.flex-md-row-reverse{flex-direction:row-reverse!important}.flex-md-column-reverse{flex-direction:column-reverse!important}.flex-md-wrap{flex-wrap:wrap!important}.flex-md-nowrap{flex-wrap:nowrap!important}.flex-md-wrap-reverse{flex-wrap:wrap-reverse!important}.flex-md-fill{flex:1 1 auto!important}.flex-md-grow-0{flex-grow:0!important}.flex-md-grow-1{flex-grow:1!important}.flex-md-shrink-0{flex-shrink:0!important}.flex-md-shrink-1{flex-shrink:1!important}.justify-content-md-start{justify-content:flex-start!important}.justify-content-md-end{justify-content:flex-end!important}.justify-content-md-center{justify-content:center!important}.justify-content-md-between{justify-content:space-between!important}.justify-content-md-around{justify-content:space-around!important}.align-items-md-start{align-items:flex-start!important}.align-items-md-end{align-items:flex-end!important}.align-items-md-center{align-items:center!important}.align-items-md-baseline{align-items:baseline!important}.align-items-md-stretch{align-items:stretch!important}.align-content-md-start{align-content:flex-start!important}.align-content-md-end{align-content:flex-end!important}.align-content-md-center{align-content:center!important}.align-content-md-between{align-content:space-between!important}.align-content-md-around{align-content:space-around!important}.align-content-md-stretch{align-content:stretch!important}.align-self-md-auto{align-self:auto!important}.align-self-md-start{align-self:flex-start!important}.align-self-md-end{align-self:flex-end!important}.align-self-md-center{align-self:center!important}.align-self-md-baseline{align-self:baseline!important}.align-self-md-stretch{align-self:stretch!important}}@media (min-width:960px){.flex-lg-row{flex-direction:row!important}.flex-lg-column{flex-direction:column!important}.flex-lg-row-reverse{flex-direction:row-reverse!important}.flex-lg-column-reverse{flex-direction:column-reverse!important}.flex-lg-wrap{flex-wrap:wrap!important}.flex-lg-nowrap{flex-wrap:nowrap!important}.flex-lg-wrap-reverse{flex-wrap:wrap-reverse!important}.flex-lg-fill{flex:1 1 auto!important}.flex-lg-grow-0{flex-grow:0!important}.flex-lg-grow-1{flex-grow:1!important}.flex-lg-shrink-0{flex-shrink:0!important}.flex-lg-shrink-1{flex-shrink:1!important}.justify-content-lg-start{justify-content:flex-start!important}.justify-content-lg-end{justify-content:flex-end!important}.justify-content-lg-center{justify-content:center!important}.justify-content-lg-between{justify-content:space-between!important}.justify-content-lg-around{justify-content:space-around!important}.align-items-lg-start{align-items:flex-start!important}.align-items-lg-end{align-items:flex-end!important}.align-items-lg-center{align-items:center!important}.align-items-lg-baseline{align-items:baseline!important}.align-items-lg-stretch{align-items:stretch!important}.align-content-lg-start{align-content:flex-start!important}.align-content-lg-end{align-content:flex-end!important}.align-content-lg-center{align-content:center!important}.align-content-lg-between{align-content:space-between!important}.align-content-lg-around{align-content:space-around!important}.align-content-lg-stretch{align-content:stretch!important}.align-self-lg-auto{align-self:auto!important}.align-self-lg-start{align-self:flex-start!important}.align-self-lg-end{align-self:flex-end!important}.align-self-lg-center{align-self:center!important}.align-self-lg-baseline{align-self:baseline!important}.align-self-lg-stretch{align-self:stretch!important}}@media (min-width:1200px){.flex-xl-row{flex-direction:row!important}.flex-xl-column{flex-direction:column!important}.flex-xl-row-reverse{flex-direction:row-reverse!important}.flex-xl-column-reverse{flex-direction:column-reverse!important}.flex-xl-wrap{flex-wrap:wrap!important}.flex-xl-nowrap{flex-wrap:nowrap!important}.flex-xl-wrap-reverse{flex-wrap:wrap-reverse!important}.flex-xl-fill{flex:1 1 auto!important}.flex-xl-grow-0{flex-grow:0!important}.flex-xl-grow-1{flex-grow:1!important}.flex-xl-shrink-0{flex-shrink:0!important}.flex-xl-shrink-1{flex-shrink:1!important}.justify-content-xl-start{justify-content:flex-start!important}.justify-content-xl-end{justify-content:flex-end!important}.justify-content-xl-center{justify-content:center!important}.justify-content-xl-between{justify-content:space-between!important}.justify-content-xl-around{justify-content:space-around!important}.align-items-xl-start{align-items:flex-start!important}.align-items-xl-end{align-items:flex-end!important}.align-items-xl-center{align-items:center!important}.align-items-xl-baseline{align-items:baseline!important}.align-items-xl-stretch{align-items:stretch!important}.align-content-xl-start{align-content:flex-start!important}.align-content-xl-end{align-content:flex-end!important}.align-content-xl-center{align-content:center!important}.align-content-xl-between{align-content:space-between!important}.align-content-xl-around{align-content:space-around!important}.align-content-xl-stretch{align-content:stretch!important}.align-self-xl-auto{align-self:auto!important}.align-self-xl-start{align-self:flex-start!important}.align-self-xl-end{align-self:flex-end!important}.align-self-xl-center{align-self:center!important}.align-self-xl-baseline{align-self:baseline!important}.align-self-xl-stretch{align-self:stretch!important}}.float-left{float:left!important}.float-right{float:right!important}.float-none{float:none!important}@media (min-width:540px){.float-sm-left{float:left!important}.float-sm-right{float:right!important}.float-sm-none{float:none!important}}@media (min-width:720px){.float-md-left{float:left!important}.float-md-right{float:right!important}.float-md-none{float:none!important}}@media (min-width:960px){.float-lg-left{float:left!important}.float-lg-right{float:right!important}.float-lg-none{float:none!important}}@media (min-width:1200px){.float-xl-left{float:left!important}.float-xl-right{float:right!important}.float-xl-none{float:none!important}}.user-select-all{user-select:all!important}.user-select-auto{user-select:auto!important}.user-select-none{user-select:none!important}.overflow-auto{overflow:auto!important}.overflow-hidden{overflow:hidden!important}.position-static{position:static!important}.position-relative{position:relative!important}.position-absolute{position:absolute!important}.position-fixed{position:fixed!important}.position-sticky{position:sticky!important}.fixed-top{top:0}.fixed-bottom,.fixed-top{left:0;position:fixed;right:0;z-index:1030}.fixed-bottom{bottom:0}@supports (position:sticky){.sticky-top{position:sticky;top:0;z-index:1020}}.sr-only{clip:rect(0,0,0,0);border:0;height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;white-space:nowrap;width:1px}.sr-only-focusable:active,.sr-only-focusable:focus{clip:auto;height:auto;overflow:visible;position:static;white-space:normal;width:auto}.shadow-sm{box-shadow:0 .125rem .25rem rgba(0,0,0,.075)!important}.shadow{box-shadow:0 .5rem 1rem rgba(0,0,0,.15)!important}.shadow-lg{box-shadow:0 1rem 3rem rgba(0,0,0,.175)!important}.shadow-none{box-shadow:none!important}.w-25{width:25%!important}.w-50{width:50%!important}.w-75{width:75%!important}.w-100{width:100%!important}.w-auto{width:auto!important}.h-25{height:25%!important}.h-50{height:50%!important}.h-75{height:75%!important}.h-100{height:100%!important}.h-auto{height:auto!important}.mw-100{max-width:100%!important}.mh-100{max-height:100%!important}.min-vw-100{min-width:100vw!important}.min-vh-100{min-height:100vh!important}.vw-100{width:100vw!important}.vh-100{height:100vh!important}.m-0{margin:0!important}.mt-0,.my-0{margin-top:0!important}.mr-0,.mx-0{margin-right:0!important}.mb-0,.my-0{margin-bottom:0!important}.ml-0,.mx-0{margin-left:0!important}.m-1{margin:.25rem!important}.mt-1,.my-1{margin-top:.25rem!important}.mr-1,.mx-1{margin-right:.25rem!important}.mb-1,.my-1{margin-bottom:.25rem!important}.ml-1,.mx-1{margin-left:.25rem!important}.m-2{margin:.5rem!important}.mt-2,.my-2{margin-top:.5rem!important}.mr-2,.mx-2{margin-right:.5rem!important}.mb-2,.my-2{margin-bottom:.5rem!important}.ml-2,.mx-2{margin-left:.5rem!important}.m-3{margin:1rem!important}.mt-3,.my-3{margin-top:1rem!important}.mr-3,.mx-3{margin-right:1rem!important}.mb-3,.my-3{margin-bottom:1rem!important}.ml-3,.mx-3{margin-left:1rem!important}.m-4{margin:1.5rem!important}.mt-4,.my-4{margin-top:1.5rem!important}.mr-4,.mx-4{margin-right:1.5rem!important}.mb-4,.my-4{margin-bottom:1.5rem!important}.ml-4,.mx-4{margin-left:1.5rem!important}.m-5{margin:3rem!important}.mt-5,.my-5{margin-top:3rem!important}.mr-5,.mx-5{margin-right:3rem!important}.mb-5,.my-5{margin-bottom:3rem!important}.ml-5,.mx-5{margin-left:3rem!important}.p-0{padding:0!important}.pt-0,.py-0{padding-top:0!important}.pr-0,.px-0{padding-right:0!important}.pb-0,.py-0{padding-bottom:0!important}.pl-0,.px-0{padding-left:0!important}.p-1{padding:.25rem!important}.pt-1,.py-1{padding-top:.25rem!important}.pr-1,.px-1{padding-right:.25rem!important}.pb-1,.py-1{padding-bottom:.25rem!important}.pl-1,.px-1{padding-left:.25rem!important}.p-2{padding:.5rem!important}.pt-2,.py-2{padding-top:.5rem!important}.pr-2,.px-2{padding-right:.5rem!important}.pb-2,.py-2{padding-bottom:.5rem!important}.pl-2,.px-2{padding-left:.5rem!important}.p-3{padding:1rem!important}.pt-3,.py-3{padding-top:1rem!important}.pr-3,.px-3{padding-right:1rem!important}.pb-3,.py-3{padding-bottom:1rem!important}.pl-3,.px-3{padding-left:1rem!important}.p-4{padding:1.5rem!important}.pt-4,.py-4{padding-top:1.5rem!important}.pr-4,.px-4{padding-right:1.5rem!important}.pb-4,.py-4{padding-bottom:1.5rem!important}.pl-4,.px-4{padding-left:1.5rem!important}.p-5{padding:3rem!important}.pt-5,.py-5{padding-top:3rem!important}.pr-5,.px-5{padding-right:3rem!important}.pb-5,.py-5{padding-bottom:3rem!important}.pl-5,.px-5{padding-left:3rem!important}.m-n1{margin:-.25rem!important}.mt-n1,.my-n1{margin-top:-.25rem!important}.mr-n1,.mx-n1{margin-right:-.25rem!important}.mb-n1,.my-n1{margin-bottom:-.25rem!important}.ml-n1,.mx-n1{margin-left:-.25rem!important}.m-n2{margin:-.5rem!important}.mt-n2,.my-n2{margin-top:-.5rem!important}.mr-n2,.mx-n2{margin-right:-.5rem!important}.mb-n2,.my-n2{margin-bottom:-.5rem!important}.ml-n2,.mx-n2{margin-left:-.5rem!important}.m-n3{margin:-1rem!important}.mt-n3,.my-n3{margin-top:-1rem!important}.mr-n3,.mx-n3{margin-right:-1rem!important}.mb-n3,.my-n3{margin-bottom:-1rem!important}.ml-n3,.mx-n3{margin-left:-1rem!important}.m-n4{margin:-1.5rem!important}.mt-n4,.my-n4{margin-top:-1.5rem!important}.mr-n4,.mx-n4{margin-right:-1.5rem!important}.mb-n4,.my-n4{margin-bottom:-1.5rem!important}.ml-n4,.mx-n4{margin-left:-1.5rem!important}.m-n5{margin:-3rem!important}.mt-n5,.my-n5{margin-top:-3rem!important}.mr-n5,.mx-n5{margin-right:-3rem!important}.mb-n5,.my-n5{margin-bottom:-3rem!important}.ml-n5,.mx-n5{margin-left:-3rem!important}.m-auto{margin:auto!important}.mt-auto,.my-auto{margin-top:auto!important}.mr-auto,.mx-auto{margin-right:auto!important}.mb-auto,.my-auto{margin-bottom:auto!important}.ml-auto,.mx-auto{margin-left:auto!important}@media (min-width:540px){.m-sm-0{margin:0!important}.mt-sm-0,.my-sm-0{margin-top:0!important}.mr-sm-0,.mx-sm-0{margin-right:0!important}.mb-sm-0,.my-sm-0{margin-bottom:0!important}.ml-sm-0,.mx-sm-0{margin-left:0!important}.m-sm-1{margin:.25rem!important}.mt-sm-1,.my-sm-1{margin-top:.25rem!important}.mr-sm-1,.mx-sm-1{margin-right:.25rem!important}.mb-sm-1,.my-sm-1{margin-bottom:.25rem!important}.ml-sm-1,.mx-sm-1{margin-left:.25rem!important}.m-sm-2{margin:.5rem!important}.mt-sm-2,.my-sm-2{margin-top:.5rem!important}.mr-sm-2,.mx-sm-2{margin-right:.5rem!important}.mb-sm-2,.my-sm-2{margin-bottom:.5rem!important}.ml-sm-2,.mx-sm-2{margin-left:.5rem!important}.m-sm-3{margin:1rem!important}.mt-sm-3,.my-sm-3{margin-top:1rem!important}.mr-sm-3,.mx-sm-3{margin-right:1rem!important}.mb-sm-3,.my-sm-3{margin-bottom:1rem!important}.ml-sm-3,.mx-sm-3{margin-left:1rem!important}.m-sm-4{margin:1.5rem!important}.mt-sm-4,.my-sm-4{margin-top:1.5rem!important}.mr-sm-4,.mx-sm-4{margin-right:1.5rem!important}.mb-sm-4,.my-sm-4{margin-bottom:1.5rem!important}.ml-sm-4,.mx-sm-4{margin-left:1.5rem!important}.m-sm-5{margin:3rem!important}.mt-sm-5,.my-sm-5{margin-top:3rem!important}.mr-sm-5,.mx-sm-5{margin-right:3rem!important}.mb-sm-5,.my-sm-5{margin-bottom:3rem!important}.ml-sm-5,.mx-sm-5{margin-left:3rem!important}.p-sm-0{padding:0!important}.pt-sm-0,.py-sm-0{padding-top:0!important}.pr-sm-0,.px-sm-0{padding-right:0!important}.pb-sm-0,.py-sm-0{padding-bottom:0!important}.pl-sm-0,.px-sm-0{padding-left:0!important}.p-sm-1{padding:.25rem!important}.pt-sm-1,.py-sm-1{padding-top:.25rem!important}.pr-sm-1,.px-sm-1{padding-right:.25rem!important}.pb-sm-1,.py-sm-1{padding-bottom:.25rem!important}.pl-sm-1,.px-sm-1{padding-left:.25rem!important}.p-sm-2{padding:.5rem!important}.pt-sm-2,.py-sm-2{padding-top:.5rem!important}.pr-sm-2,.px-sm-2{padding-right:.5rem!important}.pb-sm-2,.py-sm-2{padding-bottom:.5rem!important}.pl-sm-2,.px-sm-2{padding-left:.5rem!important}.p-sm-3{padding:1rem!important}.pt-sm-3,.py-sm-3{padding-top:1rem!important}.pr-sm-3,.px-sm-3{padding-right:1rem!important}.pb-sm-3,.py-sm-3{padding-bottom:1rem!important}.pl-sm-3,.px-sm-3{padding-left:1rem!important}.p-sm-4{padding:1.5rem!important}.pt-sm-4,.py-sm-4{padding-top:1.5rem!important}.pr-sm-4,.px-sm-4{padding-right:1.5rem!important}.pb-sm-4,.py-sm-4{padding-bottom:1.5rem!important}.pl-sm-4,.px-sm-4{padding-left:1.5rem!important}.p-sm-5{padding:3rem!important}.pt-sm-5,.py-sm-5{padding-top:3rem!important}.pr-sm-5,.px-sm-5{padding-right:3rem!important}.pb-sm-5,.py-sm-5{padding-bottom:3rem!important}.pl-sm-5,.px-sm-5{padding-left:3rem!important}.m-sm-n1{margin:-.25rem!important}.mt-sm-n1,.my-sm-n1{margin-top:-.25rem!important}.mr-sm-n1,.mx-sm-n1{margin-right:-.25rem!important}.mb-sm-n1,.my-sm-n1{margin-bottom:-.25rem!important}.ml-sm-n1,.mx-sm-n1{margin-left:-.25rem!important}.m-sm-n2{margin:-.5rem!important}.mt-sm-n2,.my-sm-n2{margin-top:-.5rem!important}.mr-sm-n2,.mx-sm-n2{margin-right:-.5rem!important}.mb-sm-n2,.my-sm-n2{margin-bottom:-.5rem!important}.ml-sm-n2,.mx-sm-n2{margin-left:-.5rem!important}.m-sm-n3{margin:-1rem!important}.mt-sm-n3,.my-sm-n3{margin-top:-1rem!important}.mr-sm-n3,.mx-sm-n3{margin-right:-1rem!important}.mb-sm-n3,.my-sm-n3{margin-bottom:-1rem!important}.ml-sm-n3,.mx-sm-n3{margin-left:-1rem!important}.m-sm-n4{margin:-1.5rem!important}.mt-sm-n4,.my-sm-n4{margin-top:-1.5rem!important}.mr-sm-n4,.mx-sm-n4{margin-right:-1.5rem!important}.mb-sm-n4,.my-sm-n4{margin-bottom:-1.5rem!important}.ml-sm-n4,.mx-sm-n4{margin-left:-1.5rem!important}.m-sm-n5{margin:-3rem!important}.mt-sm-n5,.my-sm-n5{margin-top:-3rem!important}.mr-sm-n5,.mx-sm-n5{margin-right:-3rem!important}.mb-sm-n5,.my-sm-n5{margin-bottom:-3rem!important}.ml-sm-n5,.mx-sm-n5{margin-left:-3rem!important}.m-sm-auto{margin:auto!important}.mt-sm-auto,.my-sm-auto{margin-top:auto!important}.mr-sm-auto,.mx-sm-auto{margin-right:auto!important}.mb-sm-auto,.my-sm-auto{margin-bottom:auto!important}.ml-sm-auto,.mx-sm-auto{margin-left:auto!important}}@media (min-width:720px){.m-md-0{margin:0!important}.mt-md-0,.my-md-0{margin-top:0!important}.mr-md-0,.mx-md-0{margin-right:0!important}.mb-md-0,.my-md-0{margin-bottom:0!important}.ml-md-0,.mx-md-0{margin-left:0!important}.m-md-1{margin:.25rem!important}.mt-md-1,.my-md-1{margin-top:.25rem!important}.mr-md-1,.mx-md-1{margin-right:.25rem!important}.mb-md-1,.my-md-1{margin-bottom:.25rem!important}.ml-md-1,.mx-md-1{margin-left:.25rem!important}.m-md-2{margin:.5rem!important}.mt-md-2,.my-md-2{margin-top:.5rem!important}.mr-md-2,.mx-md-2{margin-right:.5rem!important}.mb-md-2,.my-md-2{margin-bottom:.5rem!important}.ml-md-2,.mx-md-2{margin-left:.5rem!important}.m-md-3{margin:1rem!important}.mt-md-3,.my-md-3{margin-top:1rem!important}.mr-md-3,.mx-md-3{margin-right:1rem!important}.mb-md-3,.my-md-3{margin-bottom:1rem!important}.ml-md-3,.mx-md-3{margin-left:1rem!important}.m-md-4{margin:1.5rem!important}.mt-md-4,.my-md-4{margin-top:1.5rem!important}.mr-md-4,.mx-md-4{margin-right:1.5rem!important}.mb-md-4,.my-md-4{margin-bottom:1.5rem!important}.ml-md-4,.mx-md-4{margin-left:1.5rem!important}.m-md-5{margin:3rem!important}.mt-md-5,.my-md-5{margin-top:3rem!important}.mr-md-5,.mx-md-5{margin-right:3rem!important}.mb-md-5,.my-md-5{margin-bottom:3rem!important}.ml-md-5,.mx-md-5{margin-left:3rem!important}.p-md-0{padding:0!important}.pt-md-0,.py-md-0{padding-top:0!important}.pr-md-0,.px-md-0{padding-right:0!important}.pb-md-0,.py-md-0{padding-bottom:0!important}.pl-md-0,.px-md-0{padding-left:0!important}.p-md-1{padding:.25rem!important}.pt-md-1,.py-md-1{padding-top:.25rem!important}.pr-md-1,.px-md-1{padding-right:.25rem!important}.pb-md-1,.py-md-1{padding-bottom:.25rem!important}.pl-md-1,.px-md-1{padding-left:.25rem!important}.p-md-2{padding:.5rem!important}.pt-md-2,.py-md-2{padding-top:.5rem!important}.pr-md-2,.px-md-2{padding-right:.5rem!important}.pb-md-2,.py-md-2{padding-bottom:.5rem!important}.pl-md-2,.px-md-2{padding-left:.5rem!important}.p-md-3{padding:1rem!important}.pt-md-3,.py-md-3{padding-top:1rem!important}.pr-md-3,.px-md-3{padding-right:1rem!important}.pb-md-3,.py-md-3{padding-bottom:1rem!important}.pl-md-3,.px-md-3{padding-left:1rem!important}.p-md-4{padding:1.5rem!important}.pt-md-4,.py-md-4{padding-top:1.5rem!important}.pr-md-4,.px-md-4{padding-right:1.5rem!important}.pb-md-4,.py-md-4{padding-bottom:1.5rem!important}.pl-md-4,.px-md-4{padding-left:1.5rem!important}.p-md-5{padding:3rem!important}.pt-md-5,.py-md-5{padding-top:3rem!important}.pr-md-5,.px-md-5{padding-right:3rem!important}.pb-md-5,.py-md-5{padding-bottom:3rem!important}.pl-md-5,.px-md-5{padding-left:3rem!important}.m-md-n1{margin:-.25rem!important}.mt-md-n1,.my-md-n1{margin-top:-.25rem!important}.mr-md-n1,.mx-md-n1{margin-right:-.25rem!important}.mb-md-n1,.my-md-n1{margin-bottom:-.25rem!important}.ml-md-n1,.mx-md-n1{margin-left:-.25rem!important}.m-md-n2{margin:-.5rem!important}.mt-md-n2,.my-md-n2{margin-top:-.5rem!important}.mr-md-n2,.mx-md-n2{margin-right:-.5rem!important}.mb-md-n2,.my-md-n2{margin-bottom:-.5rem!important}.ml-md-n2,.mx-md-n2{margin-left:-.5rem!important}.m-md-n3{margin:-1rem!important}.mt-md-n3,.my-md-n3{margin-top:-1rem!important}.mr-md-n3,.mx-md-n3{margin-right:-1rem!important}.mb-md-n3,.my-md-n3{margin-bottom:-1rem!important}.ml-md-n3,.mx-md-n3{margin-left:-1rem!important}.m-md-n4{margin:-1.5rem!important}.mt-md-n4,.my-md-n4{margin-top:-1.5rem!important}.mr-md-n4,.mx-md-n4{margin-right:-1.5rem!important}.mb-md-n4,.my-md-n4{margin-bottom:-1.5rem!important}.ml-md-n4,.mx-md-n4{margin-left:-1.5rem!important}.m-md-n5{margin:-3rem!important}.mt-md-n5,.my-md-n5{margin-top:-3rem!important}.mr-md-n5,.mx-md-n5{margin-right:-3rem!important}.mb-md-n5,.my-md-n5{margin-bottom:-3rem!important}.ml-md-n5,.mx-md-n5{margin-left:-3rem!important}.m-md-auto{margin:auto!important}.mt-md-auto,.my-md-auto{margin-top:auto!important}.mr-md-auto,.mx-md-auto{margin-right:auto!important}.mb-md-auto,.my-md-auto{margin-bottom:auto!important}.ml-md-auto,.mx-md-auto{margin-left:auto!important}}@media (min-width:960px){.m-lg-0{margin:0!important}.mt-lg-0,.my-lg-0{margin-top:0!important}.mr-lg-0,.mx-lg-0{margin-right:0!important}.mb-lg-0,.my-lg-0{margin-bottom:0!important}.ml-lg-0,.mx-lg-0{margin-left:0!important}.m-lg-1{margin:.25rem!important}.mt-lg-1,.my-lg-1{margin-top:.25rem!important}.mr-lg-1,.mx-lg-1{margin-right:.25rem!important}.mb-lg-1,.my-lg-1{margin-bottom:.25rem!important}.ml-lg-1,.mx-lg-1{margin-left:.25rem!important}.m-lg-2{margin:.5rem!important}.mt-lg-2,.my-lg-2{margin-top:.5rem!important}.mr-lg-2,.mx-lg-2{margin-right:.5rem!important}.mb-lg-2,.my-lg-2{margin-bottom:.5rem!important}.ml-lg-2,.mx-lg-2{margin-left:.5rem!important}.m-lg-3{margin:1rem!important}.mt-lg-3,.my-lg-3{margin-top:1rem!important}.mr-lg-3,.mx-lg-3{margin-right:1rem!important}.mb-lg-3,.my-lg-3{margin-bottom:1rem!important}.ml-lg-3,.mx-lg-3{margin-left:1rem!important}.m-lg-4{margin:1.5rem!important}.mt-lg-4,.my-lg-4{margin-top:1.5rem!important}.mr-lg-4,.mx-lg-4{margin-right:1.5rem!important}.mb-lg-4,.my-lg-4{margin-bottom:1.5rem!important}.ml-lg-4,.mx-lg-4{margin-left:1.5rem!important}.m-lg-5{margin:3rem!important}.mt-lg-5,.my-lg-5{margin-top:3rem!important}.mr-lg-5,.mx-lg-5{margin-right:3rem!important}.mb-lg-5,.my-lg-5{margin-bottom:3rem!important}.ml-lg-5,.mx-lg-5{margin-left:3rem!important}.p-lg-0{padding:0!important}.pt-lg-0,.py-lg-0{padding-top:0!important}.pr-lg-0,.px-lg-0{padding-right:0!important}.pb-lg-0,.py-lg-0{padding-bottom:0!important}.pl-lg-0,.px-lg-0{padding-left:0!important}.p-lg-1{padding:.25rem!important}.pt-lg-1,.py-lg-1{padding-top:.25rem!important}.pr-lg-1,.px-lg-1{padding-right:.25rem!important}.pb-lg-1,.py-lg-1{padding-bottom:.25rem!important}.pl-lg-1,.px-lg-1{padding-left:.25rem!important}.p-lg-2{padding:.5rem!important}.pt-lg-2,.py-lg-2{padding-top:.5rem!important}.pr-lg-2,.px-lg-2{padding-right:.5rem!important}.pb-lg-2,.py-lg-2{padding-bottom:.5rem!important}.pl-lg-2,.px-lg-2{padding-left:.5rem!important}.p-lg-3{padding:1rem!important}.pt-lg-3,.py-lg-3{padding-top:1rem!important}.pr-lg-3,.px-lg-3{padding-right:1rem!important}.pb-lg-3,.py-lg-3{padding-bottom:1rem!important}.pl-lg-3,.px-lg-3{padding-left:1rem!important}.p-lg-4{padding:1.5rem!important}.pt-lg-4,.py-lg-4{padding-top:1.5rem!important}.pr-lg-4,.px-lg-4{padding-right:1.5rem!important}.pb-lg-4,.py-lg-4{padding-bottom:1.5rem!important}.pl-lg-4,.px-lg-4{padding-left:1.5rem!important}.p-lg-5{padding:3rem!important}.pt-lg-5,.py-lg-5{padding-top:3rem!important}.pr-lg-5,.px-lg-5{padding-right:3rem!important}.pb-lg-5,.py-lg-5{padding-bottom:3rem!important}.pl-lg-5,.px-lg-5{padding-left:3rem!important}.m-lg-n1{margin:-.25rem!important}.mt-lg-n1,.my-lg-n1{margin-top:-.25rem!important}.mr-lg-n1,.mx-lg-n1{margin-right:-.25rem!important}.mb-lg-n1,.my-lg-n1{margin-bottom:-.25rem!important}.ml-lg-n1,.mx-lg-n1{margin-left:-.25rem!important}.m-lg-n2{margin:-.5rem!important}.mt-lg-n2,.my-lg-n2{margin-top:-.5rem!important}.mr-lg-n2,.mx-lg-n2{margin-right:-.5rem!important}.mb-lg-n2,.my-lg-n2{margin-bottom:-.5rem!important}.ml-lg-n2,.mx-lg-n2{margin-left:-.5rem!important}.m-lg-n3{margin:-1rem!important}.mt-lg-n3,.my-lg-n3{margin-top:-1rem!important}.mr-lg-n3,.mx-lg-n3{margin-right:-1rem!important}.mb-lg-n3,.my-lg-n3{margin-bottom:-1rem!important}.ml-lg-n3,.mx-lg-n3{margin-left:-1rem!important}.m-lg-n4{margin:-1.5rem!important}.mt-lg-n4,.my-lg-n4{margin-top:-1.5rem!important}.mr-lg-n4,.mx-lg-n4{margin-right:-1.5rem!important}.mb-lg-n4,.my-lg-n4{margin-bottom:-1.5rem!important}.ml-lg-n4,.mx-lg-n4{margin-left:-1.5rem!important}.m-lg-n5{margin:-3rem!important}.mt-lg-n5,.my-lg-n5{margin-top:-3rem!important}.mr-lg-n5,.mx-lg-n5{margin-right:-3rem!important}.mb-lg-n5,.my-lg-n5{margin-bottom:-3rem!important}.ml-lg-n5,.mx-lg-n5{margin-left:-3rem!important}.m-lg-auto{margin:auto!important}.mt-lg-auto,.my-lg-auto{margin-top:auto!important}.mr-lg-auto,.mx-lg-auto{margin-right:auto!important}.mb-lg-auto,.my-lg-auto{margin-bottom:auto!important}.ml-lg-auto,.mx-lg-auto{margin-left:auto!important}}@media (min-width:1200px){.m-xl-0{margin:0!important}.mt-xl-0,.my-xl-0{margin-top:0!important}.mr-xl-0,.mx-xl-0{margin-right:0!important}.mb-xl-0,.my-xl-0{margin-bottom:0!important}.ml-xl-0,.mx-xl-0{margin-left:0!important}.m-xl-1{margin:.25rem!important}.mt-xl-1,.my-xl-1{margin-top:.25rem!important}.mr-xl-1,.mx-xl-1{margin-right:.25rem!important}.mb-xl-1,.my-xl-1{margin-bottom:.25rem!important}.ml-xl-1,.mx-xl-1{margin-left:.25rem!important}.m-xl-2{margin:.5rem!important}.mt-xl-2,.my-xl-2{margin-top:.5rem!important}.mr-xl-2,.mx-xl-2{margin-right:.5rem!important}.mb-xl-2,.my-xl-2{margin-bottom:.5rem!important}.ml-xl-2,.mx-xl-2{margin-left:.5rem!important}.m-xl-3{margin:1rem!important}.mt-xl-3,.my-xl-3{margin-top:1rem!important}.mr-xl-3,.mx-xl-3{margin-right:1rem!important}.mb-xl-3,.my-xl-3{margin-bottom:1rem!important}.ml-xl-3,.mx-xl-3{margin-left:1rem!important}.m-xl-4{margin:1.5rem!important}.mt-xl-4,.my-xl-4{margin-top:1.5rem!important}.mr-xl-4,.mx-xl-4{margin-right:1.5rem!important}.mb-xl-4,.my-xl-4{margin-bottom:1.5rem!important}.ml-xl-4,.mx-xl-4{margin-left:1.5rem!important}.m-xl-5{margin:3rem!important}.mt-xl-5,.my-xl-5{margin-top:3rem!important}.mr-xl-5,.mx-xl-5{margin-right:3rem!important}.mb-xl-5,.my-xl-5{margin-bottom:3rem!important}.ml-xl-5,.mx-xl-5{margin-left:3rem!important}.p-xl-0{padding:0!important}.pt-xl-0,.py-xl-0{padding-top:0!important}.pr-xl-0,.px-xl-0{padding-right:0!important}.pb-xl-0,.py-xl-0{padding-bottom:0!important}.pl-xl-0,.px-xl-0{padding-left:0!important}.p-xl-1{padding:.25rem!important}.pt-xl-1,.py-xl-1{padding-top:.25rem!important}.pr-xl-1,.px-xl-1{padding-right:.25rem!important}.pb-xl-1,.py-xl-1{padding-bottom:.25rem!important}.pl-xl-1,.px-xl-1{padding-left:.25rem!important}.p-xl-2{padding:.5rem!important}.pt-xl-2,.py-xl-2{padding-top:.5rem!important}.pr-xl-2,.px-xl-2{padding-right:.5rem!important}.pb-xl-2,.py-xl-2{padding-bottom:.5rem!important}.pl-xl-2,.px-xl-2{padding-left:.5rem!important}.p-xl-3{padding:1rem!important}.pt-xl-3,.py-xl-3{padding-top:1rem!important}.pr-xl-3,.px-xl-3{padding-right:1rem!important}.pb-xl-3,.py-xl-3{padding-bottom:1rem!important}.pl-xl-3,.px-xl-3{padding-left:1rem!important}.p-xl-4{padding:1.5rem!important}.pt-xl-4,.py-xl-4{padding-top:1.5rem!important}.pr-xl-4,.px-xl-4{padding-right:1.5rem!important}.pb-xl-4,.py-xl-4{padding-bottom:1.5rem!important}.pl-xl-4,.px-xl-4{padding-left:1.5rem!important}.p-xl-5{padding:3rem!important}.pt-xl-5,.py-xl-5{padding-top:3rem!important}.pr-xl-5,.px-xl-5{padding-right:3rem!important}.pb-xl-5,.py-xl-5{padding-bottom:3rem!important}.pl-xl-5,.px-xl-5{padding-left:3rem!important}.m-xl-n1{margin:-.25rem!important}.mt-xl-n1,.my-xl-n1{margin-top:-.25rem!important}.mr-xl-n1,.mx-xl-n1{margin-right:-.25rem!important}.mb-xl-n1,.my-xl-n1{margin-bottom:-.25rem!important}.ml-xl-n1,.mx-xl-n1{margin-left:-.25rem!important}.m-xl-n2{margin:-.5rem!important}.mt-xl-n2,.my-xl-n2{margin-top:-.5rem!important}.mr-xl-n2,.mx-xl-n2{margin-right:-.5rem!important}.mb-xl-n2,.my-xl-n2{margin-bottom:-.5rem!important}.ml-xl-n2,.mx-xl-n2{margin-left:-.5rem!important}.m-xl-n3{margin:-1rem!important}.mt-xl-n3,.my-xl-n3{margin-top:-1rem!important}.mr-xl-n3,.mx-xl-n3{margin-right:-1rem!important}.mb-xl-n3,.my-xl-n3{margin-bottom:-1rem!important}.ml-xl-n3,.mx-xl-n3{margin-left:-1rem!important}.m-xl-n4{margin:-1.5rem!important}.mt-xl-n4,.my-xl-n4{margin-top:-1.5rem!important}.mr-xl-n4,.mx-xl-n4{margin-right:-1.5rem!important}.mb-xl-n4,.my-xl-n4{margin-bottom:-1.5rem!important}.ml-xl-n4,.mx-xl-n4{margin-left:-1.5rem!important}.m-xl-n5{margin:-3rem!important}.mt-xl-n5,.my-xl-n5{margin-top:-3rem!important}.mr-xl-n5,.mx-xl-n5{margin-right:-3rem!important}.mb-xl-n5,.my-xl-n5{margin-bottom:-3rem!important}.ml-xl-n5,.mx-xl-n5{margin-left:-3rem!important}.m-xl-auto{margin:auto!important}.mt-xl-auto,.my-xl-auto{margin-top:auto!important}.mr-xl-auto,.mx-xl-auto{margin-right:auto!important}.mb-xl-auto,.my-xl-auto{margin-bottom:auto!important}.ml-xl-auto,.mx-xl-auto{margin-left:auto!important}}.stretched-link:after{background-color:transparent;bottom:0;content:"";left:0;pointer-events:auto;position:absolute;right:0;top:0;z-index:1}.text-monospace{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace!important}.text-justify{text-align:justify!important}.text-wrap{white-space:normal!important}.text-nowrap{white-space:nowrap!important}.text-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.text-left{text-align:left!important}.text-right{text-align:right!important}.text-center{text-align:center!important}@media (min-width:540px){.text-sm-left{text-align:left!important}.text-sm-right{text-align:right!important}.text-sm-center{text-align:center!important}}@media (min-width:720px){.text-md-left{text-align:left!important}.text-md-right{text-align:right!important}.text-md-center{text-align:center!important}}@media (min-width:960px){.text-lg-left{text-align:left!important}.text-lg-right{text-align:right!important}.text-lg-center{text-align:center!important}}@media (min-width:1200px){.text-xl-left{text-align:left!important}.text-xl-right{text-align:right!important}.text-xl-center{text-align:center!important}}.text-lowercase{text-transform:lowercase!important}.text-uppercase{text-transform:uppercase!important}.text-capitalize{text-transform:capitalize!important}.font-weight-light{font-weight:300!important}.font-weight-lighter{font-weight:lighter!important}.font-weight-normal{font-weight:400!important}.font-weight-bold{font-weight:700!important}.font-weight-bolder{font-weight:bolder!important}.font-italic{font-style:italic!important}.text-white{color:#fff!important}.text-primary{color:#007bff!important}a.text-primary:focus,a.text-primary:hover{color:#0056b3!important}.text-secondary{color:#6c757d!important}a.text-secondary:focus,a.text-secondary:hover{color:#494f54!important}.text-success{color:#28a745!important}a.text-success:focus,a.text-success:hover{color:#19692c!important}.text-info{color:#17a2b8!important}a.text-info:focus,a.text-info:hover{color:#0f6674!important}.text-warning{color:#ffc107!important}a.text-warning:focus,a.text-warning:hover{color:#ba8b00!important}.text-danger{color:#dc3545!important}a.text-danger:focus,a.text-danger:hover{color:#a71d2a!important}.text-light{color:#f8f9fa!important}a.text-light:focus,a.text-light:hover{color:#cbd3da!important}.text-dark{color:#343a40!important}a.text-dark:focus,a.text-dark:hover{color:#121416!important}.text-body{color:#212529!important}.text-muted{color:#6c757d!important}.text-black-50{color:rgba(0,0,0,.5)!important}.text-white-50{color:hsla(0,0%,100%,.5)!important}.text-hide{background-color:transparent;border:0;color:transparent;font:0/0 a;text-shadow:none}.text-decoration-none{text-decoration:none!important}.text-break{word-wrap:break-word!important;word-break:break-word!important}.text-reset{color:inherit!important}.visible{visibility:visible!important}.invisible{visibility:hidden!important}@media print{*,:after,:before{box-shadow:none!important;text-shadow:none!important}a:not(.btn){text-decoration:underline}abbr[title]:after{content:" (" attr(title) ")"}pre{white-space:pre-wrap!important}blockquote,pre{border:1px solid #adb5bd}blockquote,img,pre,tr{page-break-inside:avoid}h2,h3,p{orphans:3;widows:3}h2,h3{page-break-after:avoid}@page{size:a3}.container,body{min-width:960px!important}.navbar{display:none}.badge{border:1px solid #000}.table{border-collapse:collapse!important}.table td,.table th{background-color:#fff!important}.table-bordered td,.table-bordered th{border:1px solid #dee2e6!important}.table-dark{color:inherit}.table-dark tbody+tbody,.table-dark td,.table-dark th,.table-dark thead th{border-color:#dee2e6}.table .thead-dark th{border-color:#dee2e6;color:inherit}} \ No newline at end of file diff --git a/v0.10.x/_static/styles/pydata-sphinx-theme.css b/v0.10.x/_static/styles/pydata-sphinx-theme.css new file mode 100644 index 000000000..4685d7ac2 --- /dev/null +++ b/v0.10.x/_static/styles/pydata-sphinx-theme.css @@ -0,0 +1 @@ +html{--pst-header-height:3rem;--pst-header-article-height:calc(var(--pst-header-height)*2/3);--pst-sidebar-secondary:17rem;--pst-font-size-base:15px;--pst-font-size-h1:36px;--pst-font-size-h2:32px;--pst-font-size-h3:26px;--pst-font-size-h4:21px;--pst-font-size-h5:18px;--pst-font-size-h6:16px;--pst-font-size-milli:12px;--pst-sidebar-font-size:0.9em;--pst-sidebar-font-size-mobile:1.2em;--pst-sidebar-header-font-size:1.2em;--pst-sidebar-header-font-weight:600;--pst-font-weight-caption:300;--pst-font-weight-heading:600;--pst-font-family-base-system:-apple-system,BlinkMacSystemFont,Segoe UI,"Helvetica Neue",Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol;--pst-font-family-monospace-system:"SFMono-Regular",Menlo,Consolas,Monaco,Liberation Mono,Lucida Console,monospace;--pst-font-family-base:var(--pst-font-family-base-system);--pst-font-family-heading:var(--pst-font-family-base-system);--pst-font-family-monospace:var(--pst-font-family-monospace-system);--pst-font-size-icon:1.5rem;--pst-icon-check-circle:"\f058";--pst-icon-info-circle:"\f05a";--pst-icon-exclamation-triangle:"\f071";--pst-icon-exclamation-circle:"\f06a";--pst-icon-times-circle:"\f057";--pst-icon-lightbulb:"\f0eb";--pst-icon-download:"\f019";--pst-icon-angle-left:"\f104";--pst-icon-angle-right:"\f105";--pst-icon-external-link:"\f35d";--pst-icon-search-minus:"\f010";--pst-icon-github:"\f09b";--pst-icon-gitlab:"\f296";--pst-icon-share:"\f064";--pst-icon-bell:"\f0f3";--pst-icon-pencil:"\f303";--pst-icon-admonition-default:var(--pst-icon-bell);--pst-icon-admonition-note:var(--pst-icon-info-circle);--pst-icon-admonition-attention:var(--pst-icon-exclamation-circle);--pst-icon-admonition-caution:var(--pst-icon-exclamation-triangle);--pst-icon-admonition-warning:var(--pst-icon-exclamation-triangle);--pst-icon-admonition-danger:var(--pst-icon-exclamation-triangle);--pst-icon-admonition-error:var(--pst-icon-times-circle);--pst-icon-admonition-hint:var(--pst-icon-lightbulb);--pst-icon-admonition-tip:var(--pst-icon-lightbulb);--pst-icon-admonition-important:var(--pst-icon-exclamation-circle);--pst-icon-admonition-seealso:var(--pst-icon-share);--pst-icon-admonition-todo:var(--pst-icon-pencil);--pst-icon-versionmodified-default:var(--pst-icon-exclamation-circle);--pst-icon-versionmodified-added:var(--pst-icon-exclamation-circle);--pst-icon-versionmodified-changed:var(--pst-icon-exclamation-circle);--pst-icon-versionmodified-deprecated:var(--pst-icon-exclamation-circle)}html[data-theme=light]{--pst-color-attention:#ffc107;--pst-color-text-base:#323232;--pst-color-text-muted:#646464;--pst-color-shadow:#d8d8d8;--pst-color-border:#c9c9c9;--pst-color-inline-code:#e83e8c;--pst-color-target:#fbe54e;--pst-color-background:#fff;--pst-color-on-background:#fff;--pst-color-surface:#f5f5f5;--pst-color-on-surface:#e1e1e1;--pst-color-link:var(--pst-color-primary);--pst-color-link-hover:var(--pst-color-warning)}html[data-theme=light] .only-dark{display:none!important}html[data-theme=dark]{--pst-color-attention:#dca90f;--pst-color-text-base:#cecece;--pst-color-text-muted:#a6a6a6;--pst-color-shadow:#212121;--pst-color-border:silver;--pst-color-inline-code:#dd9ec2;--pst-color-target:#472700;--pst-color-background:#121212;--pst-color-on-background:#1e1e1e;--pst-color-surface:#212121;--pst-color-on-surface:#373737;--pst-color-link:var(--pst-color-primary);--pst-color-link-hover:var(--pst-color-warning)}html[data-theme=dark] .only-light{display:none!important}html[data-theme=dark] img:not(.only-dark):not(.dark-light){filter:brightness(.8) contrast(1.2)}html[data-theme=dark] .bd-content img:not(.only-dark):not(.dark-light){background:#fff;border-radius:.25rem}html[data-theme=dark] .MathJax_SVG *{fill:var(--pst-color-text-base)}html{font-size:var(--pst-font-size-base);scroll-padding-top:calc(var(--pst-header-height) + 12px)}body{background-color:var(--pst-color-background);color:var(--pst-color-text-base);display:flex;flex-direction:column;font-family:var(--pst-font-family-base);font-weight:400;line-height:1.65;min-height:100vh}body::-webkit-scrollbar{height:.5rem;width:.5rem}body::-webkit-scrollbar-thumb{background:var(--pst-color-text-muted);border-radius:.25rem}body::-webkit-scrollbar-track{background:transparent}body::-webkit-scrollbar-thumb{background:var(--pst-color-on-surface)}body::-webkit-scrollbar-thumb:hover,body:hover::-webkit-scrollbar-thumb{background:var(--pst-color-text-muted)}body::-webkit-scrollbar-track{background:var(--pst-color-background)}p{color:var(--pst-color-text-base);font-size:1em;margin-bottom:1.15rem}p.rubric{border-bottom:1px solid var(--pst-color-border)}p.centered{text-align:center}a{color:var(--pst-color-link);text-decoration:none}a:hover{color:var(--pst-color-link-hover);text-decoration:underline}a.headerlink{color:var(--pst-color-warning);font-size:.8em;margin-left:.2em;opacity:.4;padding:0 4px;text-decoration:none;transition:all .2s ease-out;user-select:none}a.headerlink:hover{opacity:1}a:before{color:var(--pst-color-text-muted);font-family:Font Awesome\ 6 Brands;margin-right:.25rem}a.github:before{content:var(--pst-icon-github)}a.gitlab:before{content:var(--pst-icon-gitlab)}.heading-style,h1,h2,h3,h4,h5,h6{font-family:var(--pst-font-family-heading);font-weight:400;line-height:1.15;margin:2.75rem 0 1.05rem}h1{font-size:var(--pst-font-size-h1);margin-top:0}h1,h2{color:var(--pst-color-primary)}h2{font-size:var(--pst-font-size-h2)}h3{font-size:var(--pst-font-size-h3)}h3,h4{color:var(--pst-color-text-base)}h4{font-size:var(--pst-font-size-h4)}h5{font-size:var(--pst-font-size-h5)}h5,h6{color:var(--pst-color-text-base)}h6{font-size:var(--pst-font-size-h6)}.text_small,small{font-size:var(--pst-font-size-milli)}hr{border:0;border-top:1px solid var(--pst-color-border)}code,kbd,pre,samp{font-family:var(--pst-font-family-monospace)}kbd{background-color:var(--pst-color-on-background);color:var(--pst-color-text-muted)}kbd:not(.compound){border:1px solid var(--pst-color-border);box-shadow:1px 1px 1px var(--pst-color-shadow);margin:0 .1rem;padding:.1rem .4rem}code{color:var(--pst-color-inline-code)}pre{background-color:var(--pst-color-surface);border:1px solid var(--pst-color-border);border-radius:.25rem;color:var(--pst-color-text-base);line-height:1.2em;margin:1.5em 0;padding:1rem}pre::-webkit-scrollbar{height:.5rem;width:.5rem}pre::-webkit-scrollbar-thumb{background:var(--pst-color-text-muted);border-radius:.25rem}pre::-webkit-scrollbar-track{background:transparent}pre::-webkit-scrollbar-thumb{background:var(--pst-color-on-surface)}pre::-webkit-scrollbar-thumb:hover,pre:hover::-webkit-scrollbar-thumb{background:var(--pst-color-text-muted)}pre .linenos{opacity:.5;padding-right:10px}.skip-link{background-color:var(--pst-color-background);border-bottom:1px solid var(--pst-color-border);color:var(--pst-color-link);left:0;padding:.5rem;position:fixed;right:0;text-align:center;top:0;transition:translate .15s ease-in-out;translate:0 -100%;z-index:1050}.skip-link:focus{translate:0}.bd-container{display:flex;flex-grow:1;justify-content:center}.bd-container .bd-container__inner{display:flex}.bd-page-width{width:100%}@media (min-width:960px){.bd-page-width{max-width:88rem}}.bd-header-announcement{align-items:center;display:flex;justify-content:center;min-height:3rem;padding:.5rem 12.5%;position:relative;text-align:center;width:100%}@media (max-width:1199.98px){.bd-header-announcement{padding:.5rem 2%}}.bd-header-announcement p{font-weight:700;margin:0}.bd-header-announcement:after{background-color:var(--pst-color-info);content:"";height:100%;left:0;opacity:.2;position:absolute;top:0;width:100%;z-index:-1}.bd-header-announcement:empty{display:none}.bd-main{display:flex;flex-direction:column;flex-grow:1;min-width:0}.bd-main .bd-content{display:flex;height:100%;justify-content:center}.bd-main .bd-content .bd-article-container{display:flex;flex-direction:column;justify-content:start;max-width:60em;overflow-x:auto;padding:1rem;width:100%}@media (min-width:1200px){.bd-main .bd-content .bd-article-container .bd-article{padding-left:2rem;padding-top:1.5rem}}footer.bd-footer{border-top:1px solid var(--pst-color-border);padding:10px;width:100%}footer.bd-footer .footer-item p{margin-bottom:0}.bd-footer-article{display:flex;margin-top:auto}.bd-header{background:var(--pst-color-on-background)!important;box-shadow:0 .125rem .25rem 0 var(--pst-color-shadow);justify-content:center;max-width:100vw;min-height:var(--pst-header-height);padding:.5rem 0;position:sticky;top:0;width:100%;z-index:1030}.bd-header .bd-header__inner{align-items:center;display:flex;height:100%;padding-left:1rem;padding-right:1rem}@media (min-width:960px){.bd-header .navbar-header-items{display:flex;flex-grow:1;padding:0 0 0 .5rem}}.bd-header #navbar-center,.bd-header #navbar-end,.bd-header #navbar-start{align-items:center;display:flex;flex-flow:wrap}.bd-header #navbar-center,.bd-header #navbar-end{gap:1rem}.bd-header #navbar-start{gap:.5rem;margin-right:auto}.bd-header #navbar-end{justify-content:end}.bd-header .navbar-nav{display:flex}@media (min-width:960px){.bd-header .navbar-nav{align-items:center}}.bd-header .navbar-nav li a.nav-link{color:var(--pst-color-text-muted)}.bd-header .navbar-nav li a.nav-link:focus,.bd-header .navbar-nav li a.nav-link:hover{color:var(--pst-color-primary)}.bd-header .navbar-nav>.active>.nav-link{color:var(--pst-color-primary);font-weight:600}.bd-header .navbar-nav .dropdown button{border:none;color:var(--pst-color-text-muted);display:unset}.bd-header .navbar-nav .dropdown .dropdown-menu{background-color:var(--pst-color-on-background);border:1px solid var(--pst-color-border);box-shadow:0 0 .3rem .1rem var(--pst-color-shadow);margin:.5rem 0;min-width:20rem;padding:.5rem 1rem;z-index:1060}.bd-header .navbar-nav .dropdown .dropdown-menu:not(.show){display:none}@media (min-width:960px){.navbar-center-item{display:inline-block}}.toc-entry>.nav-link.active{background-color:transparent;border-left:2px solid var(--pst-color-primary);color:var(--pst-color-primary);font-weight:600}.nav-link:hover{border-style:none}.nav-link.nav-external:after{content:var(--pst-icon-external-link);font-family:Font Awesome\ 6 Free;font-size:.75em;font-weight:900;margin-left:.3em}#navbar-main-elements li.nav-item i{font-size:.7rem;padding-left:2px;vertical-align:middle}.bd-header label.sidebar-toggle{align-items:center;color:var(--pst-color-muted);cursor:pointer;display:flex;font-size:var(--pst-font-size-icon);margin-bottom:0}.bd-header label.primary-toggle{padding-right:1rem}@media (min-width:960px){.bd-header label.primary-toggle{display:none}}.bd-header label.secondary-toggle{padding-left:1rem}@media (min-width:1200px){.bd-header label.secondary-toggle{display:none}}.bd-header .navbar-header-items{display:none}@media (min-width:960px){.bd-header .navbar-header-items{display:inherit}}.navbar-persistent--mobile{margin-left:auto}@media (min-width:960px){.navbar-persistent--mobile{display:none}}.navbar-persistent--container{display:none}@media (min-width:960px){.navbar-persistent--container{display:flex}}.bd-header-article__inner{align-items:center;display:flex;min-height:var(--pst-header-article-height);padding:0 .5rem}.bd-header-article__inner .bd-header-article__end{margin-left:auto}.bd-sidebar-primary{background-color:var(--pst-color-background);border-right:1px solid var(--pst-color-border);display:flex;flex:0 0 25%;flex-direction:column;font-size:var(--pst-sidebar-font-size-mobile);gap:1rem;max-height:calc(100vh - var(--pst-header-height));max-width:25%;overflow-y:auto;padding:2rem 1rem 1rem;position:sticky;top:var(--pst-header-height)}.bd-sidebar-primary::-webkit-scrollbar{height:.5rem;width:.5rem}.bd-sidebar-primary::-webkit-scrollbar-thumb{background:var(--pst-color-text-muted);border-radius:.25rem}.bd-sidebar-primary::-webkit-scrollbar-track{background:transparent}.bd-sidebar-primary::-webkit-scrollbar-thumb{background:var(--pst-color-on-surface)}.bd-sidebar-primary::-webkit-scrollbar-thumb:hover,.bd-sidebar-primary:hover::-webkit-scrollbar-thumb{background:var(--pst-color-text-muted)}@media (min-width:960px){.bd-sidebar-primary{font-size:var(--pst-sidebar-font-size)}}.bd-sidebar-primary.no-sidebar{border-right:0}@media (min-width:960px){.bd-sidebar-primary.hide-on-wide{display:none}}.bd-sidebar-primary .sidebar-end-items__item,.bd-sidebar-primary .sidebar-start-items__item{padding:.5rem 0}.bd-sidebar-primary .sidebar-header-items{display:flex;flex-direction:column}.bd-sidebar-primary .sidebar-header-items .sidebar-header-items__title{color:var(--pst-color-text-base);font-size:var(--pst-sidebar-header-font-size);font-weight:var(--pst-sidebar-header-font-weight);margin-bottom:.5rem}.bd-sidebar-primary .sidebar-header-items .nav-item.dropdown button{display:none}.bd-sidebar-primary .sidebar-header-items .nav-item.dropdown .dropdown-menu{background-color:inherit;border:none;display:flex;flex-direction:column;font-size:inherit;margin:0;padding:0}.bd-sidebar-primary .sidebar-header-items .sidebar-header-items__center{display:flex;flex-direction:column}.bd-sidebar-primary .sidebar-header-items .sidebar-header-items__end{align-items:center;display:flex;gap:.5rem}@media (min-width:960px){.bd-sidebar-primary .sidebar-header-items{display:none}}.bd-sidebar-primary .sidebar-start-items{border-top:1px solid var(--pst-color-border)}@media (min-width:960px){.bd-sidebar-primary .sidebar-start-items{border-top:none}}.bd-sidebar-primary .sidebar-end-items{margin-bottom:1em;margin-top:auto}.bd-sidebar-primary .list-caption{list-style:none;padding-left:0}.bd-sidebar-primary li{position:relative}.bd-sidebar-primary li.has-children>.reference{padding-right:30px}.bd-sidebar-primary label.toctree-toggle{align-items:center;cursor:pointer;display:flex;height:30px;justify-content:center;position:absolute;right:0;top:0;width:30px}.bd-sidebar-primary label.toctree-toggle:hover{background:var(--pst-color-surface)}.bd-sidebar-primary label.toctree-toggle i{display:inline-block;font-size:.75rem;text-align:center}.bd-sidebar-primary label.toctree-toggle i:hover{color:var(--pst-color-primary)}.bd-sidebar-primary .label-parts{height:100%;width:100%}.bd-sidebar-primary .label-parts:hover{background:none}.bd-sidebar-primary .label-parts i{position:absolute;right:0;top:.3em;width:30px}nav.bd-links{margin-right:-1rem}@media (min-width:960px){nav.bd-links{display:block}}nav.bd-links ul{list-style:none}nav.bd-links ul ul{padding:0 0 0 1rem}nav.bd-links li>a{color:var(--pst-color-text-muted);display:block;padding:.25rem 0}nav.bd-links li>a:hover{background-color:transparent;color:var(--pst-color-primary);text-decoration:none}nav.bd-links li>a.reference.external:after{content:var(--pst-icon-external-link);font-family:Font Awesome\ 6 Free;font-size:.75em;font-weight:900;margin-left:.3em}nav.bd-links .active:hover>a,nav.bd-links .active>a{color:var(--pst-color-primary);font-weight:600}nav.bd-links p.bd-links__title{font-size:var(--pst-sidebar-header-font-size);font-weight:var(--pst-sidebar-header-font-weight);margin-bottom:.5rem}nav.bd-links p.caption{color:var(--pst-color-text-base);font-weight:var(--pst-sidebar-header-font-weight);margin-bottom:.5em;margin-top:1.25em;position:relative}nav.bd-links p.caption:first-child{margin-top:0}.bd-sidebar-secondary{background-color:var(--pst-color-background);display:flex;flex-direction:column;flex-shrink:0;font-size:var(--pst-sidebar-font-size-mobile);max-height:calc(100vh - var(--pst-header-height));order:2;overflow-y:auto;padding:2rem 1rem 1rem;position:sticky;top:var(--pst-header-height);width:var(--pst-sidebar-secondary)}@media (min-width:1200px){.bd-sidebar-secondary{font-size:var(--pst-sidebar-secondary-font-size)}}.bd-sidebar-secondary .onthispage{color:var(--pst-color-text-base);font-weight:var(--pst-sidebar-header-font-weight)}.bd-sidebar-secondary::-webkit-scrollbar{height:.5rem;width:.5rem}.bd-sidebar-secondary::-webkit-scrollbar-thumb{background:var(--pst-color-text-muted);border-radius:.25rem}.bd-sidebar-secondary::-webkit-scrollbar-track{background:transparent}.bd-sidebar-secondary::-webkit-scrollbar-thumb{background:var(--pst-color-on-surface)}.bd-sidebar-secondary::-webkit-scrollbar-thumb:hover,.bd-sidebar-secondary:hover::-webkit-scrollbar-thumb{background:var(--pst-color-text-muted)}.toc-item{padding:.5rem}@media (min-width:1200px){.toc-item{border-left:1px solid var(--pst-color-border);padding-left:1rem}}.toc-item i{padding-right:.5rem}.section-nav{border-bottom:none;padding-left:0}.section-nav ul{padding-left:1rem}div#searchbox p.highlight-link{margin-bottom:0}div#searchbox p.highlight-link a:before{color:unset;content:var(--pst-icon-search-minus);font-family:Font Awesome\ 6 Free;font-weight:900;margin-right:0;padding-right:.5rem}input.sidebar-toggle{display:none}label.overlay{background-color:#000;height:0;left:0;opacity:.5;position:fixed;top:0;transition:opacity .2s ease-out;width:0;z-index:1040}input#__primary:checked+label.overlay.overlay-primary,input#__secondary:checked+label.overlay.overlay-secondary{height:100vh;width:100vw}input#__primary:checked~.bd-container .bd-sidebar-primary{margin-left:0;visibility:visible}input#__secondary:checked~.bd-container .bd-sidebar-secondary{margin-right:0;visibility:visible}@media (min-width:960px){label.sidebar-toggle.primary-toggle{display:none}input#__primary:checked+label.overlay.overlay-primary{height:0;width:0}.bd-sidebar-primary{margin-left:0;visibility:visible}}@media (max-width:959.98px){.bd-sidebar-primary{flex-grow:0.75;height:100vh;left:0;margin-left:-75%;max-height:100vh;max-width:350px;position:fixed;top:0;transition:visibility .2s ease-out,margin .2s ease-out;visibility:hidden;width:75%;z-index:1050}}@media (max-width:1199.98px){.bd-sidebar-secondary{flex-grow:0.75;height:100vh;margin-right:-75%;max-height:100vh;max-width:350px;position:fixed;right:0;top:0;transition:visibility .2s ease-out,margin .2s ease-out;visibility:hidden;width:75%;z-index:1050}}#navbar-icon-links i.fa-brands,#navbar-icon-links i.fa-regular,#navbar-icon-links i.fa-solid{font-size:var(--pst-font-size-icon);font-style:normal;vertical-align:middle}#navbar-icon-links i.fa-square-twitter:before{color:#55acee}#navbar-icon-links i.fa-square-gitlab:before{color:#548}#navbar-icon-links i.fa-bitbucket:before{color:#0052cc}#navbar-icon-links img.icon-link-image{border-radius:.2rem;height:1.5em}#navbar-icon-links li:first-child a{padding-left:0}#navbar-icon-links a span{align-items:center;display:flex}@media (max-width:1199.98px){#navbar-icon-links{flex-direction:row}#navbar-icon-links a{padding:0 .5rem}}.navbar-brand{align-items:center;display:flex;gap:.5rem;height:var(--pst-header-height);margin:0;padding:0;position:relative;width:auto}.navbar-brand p{margin-bottom:0}.navbar-brand img{height:100%;max-width:100%;width:auto}.navbar-nav ul{display:block;list-style:none}.navbar-nav ul ul{padding:0 0 0 1rem}.navbar-nav li{display:flex;flex-direction:column}.navbar-nav li a{align-items:center;color:var(--pst-color-text-muted);display:flex;height:100%;padding-bottom:.25rem;padding-top:.25rem}.navbar-nav li a:hover{border-style:none;text-decoration-line:none}.navbar-nav li a:focus,.navbar-nav li a:hover,.navbar-nav li.current>a{color:var(--pst-color-primary)}.navbar-nav li.current>a{font-weight:600}.navbar-nav .toctree-checkbox{display:none;position:absolute}.navbar-nav .toctree-checkbox~ul{display:none}.navbar-nav .toctree-checkbox~label i{transform:rotate(0deg)}.navbar-nav .toctree-checkbox:checked~ul{display:block}.navbar-nav .toctree-checkbox:checked~label i{transform:rotate(180deg)}.bd-header .navbar-nav>p.sidebar-header-items__title{display:none}.prev-next-area{width:100%}.prev-next-area p{line-height:1.3em;margin:0 .3em}.prev-next-area i{font-size:1.2em}.prev-next-area a{align-items:center;border:none;color:var(--pst-color-text-muted);display:flex;max-width:45%;overflow-x:hidden;padding:10px;text-decoration:none}.prev-next-area a p.prev-next-title{color:var(--pst-color-primary);font-size:1.1em;font-weight:var(--pst-font-weight-heading)}.prev-next-area a:hover p.prev-next-title{text-decoration:underline}.prev-next-area a .prev-next-info{flex-direction:column;margin:0 .5em}.prev-next-area a .prev-next-info .prev-next-subtitle{text-transform:capitalize}.prev-next-area a.left-prev{float:left}.prev-next-area a.right-next{float:right}.prev-next-area a.right-next div.prev-next-info{text-align:right}.bd-search{margin-left:-15px;margin-right:-15px;padding:1rem 15px;position:relative}.bd-search .icon{color:var(--pst-color-border);left:25px;position:absolute}.bd-search i.fa-solid.fa-magnifying-glass{color:var(--pst-color-text-muted);left:1.6rem;position:absolute}.bd-search input{background-color:var(--pst-color-background);border:1px solid var(--pst-color-border);border-radius:.25rem;color:var(--pst-color-text-base);padding-left:2.5rem}.bd-search input::placeholder{color:var(--pst-color-border)}.bd-search input:active,.bd-search input:focus{background-color:var(--pst-color-background);color:var(--pst-color-text-base)}.bd-search input::-webkit-search-cancel-button,.bd-search input::-webkit-search-decoration{-webkit-appearance:none;appearance:none}.bd-search .search-button__kbd-shortcut{color:var(--pst-color-border);position:absolute;right:2em}.search-button{align-content:center;align-items:center;color:var(--pst-color-text-muted);display:flex;padding:0}.search-button:hover{color:var(--pst-color-primary)}.search-button i{font-size:1.3rem}.search-button__overlay,.search-button__search-container{display:none}.search-button__wrapper.show .search-button__search-container{display:flex;left:50%;margin-top:.5rem;max-width:800px;position:fixed;right:1rem;top:30%;transform:translate(-50%,-50%);width:90%;z-index:1050}.search-button__wrapper.show .search-button__overlay{background-color:#000;display:flex;height:100%;left:0;opacity:.5;position:fixed;top:0;width:100%;z-index:1040}.search-button__wrapper.show form.bd-search{flex-grow:1;padding-bottom:0;padding-top:0}.search-button__wrapper.show i,.search-button__wrapper.show input{font-size:var(--pst-font-size-icon)}.theme-switch-button{border-color:var(--pst-color-on-background);font-size:calc(var(--pst-font-size-icon) - .1rem);margin:0 -.5rem;padding:0}.theme-switch-button span{color:var(--pst-color-text-muted);display:none;padding:.5rem}.theme-switch-button span:active,.theme-switch-button span:focus,.theme-switch-button span:hover{text-decoration:none}.theme-switch-button:active,.theme-switch-button:hover{background-color:var(--pst-color-on-surface)!important;border-color:var(--pst-color-on-background)!important}.theme-switch-button:active a,.theme-switch-button:hover a{color:var(--pst-color-text-muted)}.bd-sidebar-primary .theme-switch-button{border-color:var(--pst-color-background)}.bd-sidebar-primary .theme-switch-button:active,.bd-sidebar-primary .theme-switch-button:hover{border-color:var(--pst-color-background)!important}html[data-mode=auto] .theme-switch-button span[data-mode=auto],html[data-mode=dark] .theme-switch-button span[data-mode=dark],html[data-mode=light] .theme-switch-button span[data-mode=light]{display:flex}button.version-switcher__button{border-color:var(--pst-color-border);color:var(--pst-color-text-base);margin-bottom:1em}@media (min-width:960px){button.version-switcher__button{margin-bottom:unset}}button.version-switcher__button:hover{color:var(--pst-color-text-base)}.version-switcher__menu{border-color:var(--pst-color-border)}.version-switcher__menu a.list-group-item{background-color:var(--pst-color-on-background);border-color:var(--pst-color-border);color:var(--pst-color-text-base)}.version-switcher__menu a.list-group-item:hover{background-color:var(--pst-color-surface)}.version-switcher__menu a.list-group-item.active{color:var(--pst-color-primary)}.version-switcher__menu a.list-group-item.active span:before{background-color:var(--pst-color-primary);content:"";height:100%;left:0;opacity:.1;position:absolute;top:0;width:100%}.version-switcher__menu,button.version-switcher__button{font-size:1.1em}@media (min-width:960px){.version-switcher__menu,button.version-switcher__button{font-size:unset}}nav.page-toc{margin-bottom:1rem}nav.page-toc ul>li{font-size:.95em}.bd-toc .nav .nav,.list-caption .nav{display:none}.bd-toc .nav .nav.visible,.bd-toc .nav>.active>ul,.list-caption .nav.visible,.list-caption>.active>ul,.toc-entry{display:block}.toc-entry a.nav-link{color:var(--pst-color-text-muted);display:block;margin-left:-1rem;padding:.125rem 0 .125rem 1rem}.toc-entry a.nav-link:hover{color:var(--pst-color-primary);text-decoration:none}.toc-entry a.nav-link.active{background-color:transparent;border-left:2px solid var(--pst-color-primary);color:var(--pst-color-primary);font-weight:600}div.deprecated,div.versionadded,div.versionchanged{background-color:var(--pst-color-on-background);border-left:.2rem solid;border-color:var(--pst-color-info);border-radius:.25rem;box-shadow:0 .2rem .5rem var(--pst-color-shadow),0 0 .0625rem var(--pst-color-shadow)!important;margin:1.5625em auto;overflow:hidden;padding:0 .6rem;page-break-inside:avoid;position:relative;transition:color .25s,background-color .25s,border-color .25s;vertical-align:middle}div.deprecated>p,div.versionadded>p,div.versionchanged>p{margin-bottom:.6rem;margin-top:.6rem}div.deprecated>p:before,div.versionadded>p:before,div.versionchanged>p:before{background-color:var(--pst-color-info);content:"";height:100%;left:0;opacity:.1;pointer-events:none;position:absolute;top:0;width:100%}div.versionadded{border-color:var(--pst-color-success)}div.versionadded p:before{background-color:var(--pst-color-success)}div.versionchanged{border-color:var(--pst-color-warning)}div.versionchanged p:before{background-color:var(--pst-color-warning)}div.deprecated{border-color:var(--pst-color-danger)}div.deprecated p:before{background-color:var(--pst-color-danger)}span.versionmodified{font-weight:600}span.versionmodified:before{color:var(--pst-color-info);content:var(--pst-icon-versionmodified-default);font-family:Font Awesome\ 6 Free;font-style:normal;font-weight:900;margin-right:.6rem}span.versionmodified.added:before{color:var(--pst-color-success);content:var(--pst-icon-versionmodified-added)}span.versionmodified.changed:before{color:var(--pst-color-warning);content:var(--pst-icon-versionmodified-changed)}span.versionmodified.deprecated:before{color:var(--pst-color-danger);content:var(--pst-icon-versionmodified-deprecated)}.sidebar-indices-items{border-top:1px solid var(--pst-color-border);display:flex;flex-direction:column}@media (min-width:960px){.sidebar-indices-items{border-top:none}}.sidebar-indices-items .sidebar-indices-items__title{color:var(--pst-color-text-base);font-size:var(--pst-sidebar-header-font-size);font-weight:var(--pst-sidebar-header-font-weight);margin-bottom:.5rem}.sidebar-indices-items ul.indices-link{list-style:none;margin-right:-1rem;padding:0}.sidebar-indices-items ul.indices-link li>a{color:var(--pst-color-text-muted);display:block;padding:.25rem 0}.sidebar-indices-items ul.indices-link li>a:hover{background-color:transparent;color:var(--pst-color-primary);text-decoration:none}.bd-sidebar-primary div#rtd-footer-container{bottom:-1rem;margin:-1rem;position:sticky}.bd-sidebar-primary div#rtd-footer-container .rst-versions.rst-badge{font-family:var(--pst-font-family-base);font-size:.9em;max-width:unset;position:unset}.bd-sidebar-primary div#rtd-footer-container .rst-versions.rst-badge .rst-current-version{align-items:center;background-color:var(--pst-color-background);border-top:1px solid var(--pst-color-border);color:var(--pst-color-success);display:flex;gap:.2rem;height:2.5rem;transition:background-color .2s ease-out}.bd-sidebar-primary div#rtd-footer-container .rst-versions.rst-badge .fa.fa-book{color:var(--pst-color-text-muted);margin-right:auto}.bd-sidebar-primary div#rtd-footer-container .rst-versions.rst-badge .fa.fa-book:after{color:var(--pst-color-text-base);content:"Read The Docs";font-family:var(--pst-font-family-base);font-weight:var(--pst-font-weight-heading)}.bd-sidebar-primary div#rtd-footer-container .rst-versions.rst-badge .fa.fa-caret-down{color:var(--pst-color-text-muted)}.bd-sidebar-primary div#rtd-footer-container .rst-versions.rst-badge.shift-up .rst-current-version{border-bottom:1px solid var(--pst-color-border)}.bd-sidebar-primary div#rtd-footer-container .rst-other-versions{background-color:var(--pst-color-surface);color:var(--pst-color-text-base)}.bd-sidebar-primary div#rtd-footer-container .rst-other-versions dl dd a{color:var(--pst-color-text-muted)}.bd-sidebar-primary div#rtd-footer-container .rst-other-versions hr{background-color:var(--pst-color-border)}.bd-sidebar-primary div#rtd-footer-container .rst-other-versions small a{color:var(--pst-color-link)}.bd-sidebar-primary div#rtd-footer-container .rst-other-versions input{background-color:var(--pst-color-surface);border:1px solid var(--pst-color-border);padding-left:.5rem}.admonition,div.admonition{background-color:var(--pst-color-on-background);border-left:.2rem solid;border-color:var(--pst-color-info);border-radius:.25rem;box-shadow:0 .2rem .5rem var(--pst-color-shadow),0 0 .0625rem var(--pst-color-shadow)!important;margin:1.5625em auto;overflow:hidden;padding:0 .6rem .8rem;page-break-inside:avoid}.admonition :last-child,div.admonition :last-child{margin-bottom:0}.admonition p.admonition-title~*,div.admonition p.admonition-title~*{margin-left:1.4rem;margin-right:1.4rem}.admonition>ol,.admonition>ul,div.admonition>ol,div.admonition>ul{margin-left:1em}.admonition>.admonition-title,div.admonition>.admonition-title{font-weight:var(--pst-font-weight-heading);margin:0 -.6rem;padding:.4rem .6rem .4rem 2rem;position:relative}.admonition>.admonition-title:after,div.admonition>.admonition-title:after{color:var(--pst-color-info);content:var(--pst-icon-admonition-default);font-family:Font Awesome\ 6 Free;font-weight:900;height:1rem;left:.5rem;opacity:1;position:absolute;width:1rem}.admonition>.admonition-title:before,div.admonition>.admonition-title:before{background-color:var(--pst-color-info);content:"";height:100%;left:0;opacity:.1;pointer-events:none;position:absolute;top:0;width:100%}.admonition>.admonition-title+*,div.admonition>.admonition-title+*{margin-top:.4em}.admonition.attention,div.admonition.attention{border-color:var(--pst-color-attention)}.admonition.attention>.admonition-title:before,div.admonition.attention>.admonition-title:before{background-color:var(--pst-color-attention)}.admonition.attention>.admonition-title:after,div.admonition.attention>.admonition-title:after{color:var(--pst-color-attention);content:var(--pst-icon-admonition-attention)}.admonition.caution,div.admonition.caution{border-color:var(--pst-color-warning)}.admonition.caution>.admonition-title:before,div.admonition.caution>.admonition-title:before{background-color:var(--pst-color-warning)}.admonition.caution>.admonition-title:after,div.admonition.caution>.admonition-title:after{color:var(--pst-color-warning);content:var(--pst-icon-admonition-caution)}.admonition.warning,div.admonition.warning{border-color:var(--pst-color-warning)}.admonition.warning>.admonition-title:before,div.admonition.warning>.admonition-title:before{background-color:var(--pst-color-warning)}.admonition.warning>.admonition-title:after,div.admonition.warning>.admonition-title:after{color:var(--pst-color-warning);content:var(--pst-icon-admonition-warning)}.admonition.danger,div.admonition.danger{border-color:var(--pst-color-danger)}.admonition.danger>.admonition-title:before,div.admonition.danger>.admonition-title:before{background-color:var(--pst-color-danger)}.admonition.danger>.admonition-title:after,div.admonition.danger>.admonition-title:after{color:var(--pst-color-danger);content:var(--pst-icon-admonition-danger)}.admonition.error,div.admonition.error{border-color:var(--pst-color-danger)}.admonition.error>.admonition-title:before,div.admonition.error>.admonition-title:before{background-color:var(--pst-color-danger)}.admonition.error>.admonition-title:after,div.admonition.error>.admonition-title:after{color:var(--pst-color-danger);content:var(--pst-icon-admonition-error)}.admonition.hint,div.admonition.hint{border-color:var(--pst-color-success)}.admonition.hint>.admonition-title:before,div.admonition.hint>.admonition-title:before{background-color:var(--pst-color-success)}.admonition.hint>.admonition-title:after,div.admonition.hint>.admonition-title:after{color:var(--pst-color-success);content:var(--pst-icon-admonition-hint)}.admonition.tip,div.admonition.tip{border-color:var(--pst-color-success)}.admonition.tip>.admonition-title:before,div.admonition.tip>.admonition-title:before{background-color:var(--pst-color-success)}.admonition.tip>.admonition-title:after,div.admonition.tip>.admonition-title:after{color:var(--pst-color-success);content:var(--pst-icon-admonition-tip)}.admonition.important,div.admonition.important{border-color:var(--pst-color-attention)}.admonition.important>.admonition-title:before,div.admonition.important>.admonition-title:before{background-color:var(--pst-color-attention)}.admonition.important>.admonition-title:after,div.admonition.important>.admonition-title:after{color:var(--pst-color-attention);content:var(--pst-icon-admonition-important)}.admonition.note,div.admonition.note{border-color:var(--pst-color-info)}.admonition.note>.admonition-title:before,div.admonition.note>.admonition-title:before{background-color:var(--pst-color-info)}.admonition.note>.admonition-title:after,div.admonition.note>.admonition-title:after{color:var(--pst-color-info);content:var(--pst-icon-admonition-note)}.admonition.seealso,div.admonition.seealso{border-color:var(--pst-color-success)}.admonition.seealso>.admonition-title:before,div.admonition.seealso>.admonition-title:before{background-color:var(--pst-color-success)}.admonition.seealso>.admonition-title:after,div.admonition.seealso>.admonition-title:after{color:var(--pst-color-success);content:var(--pst-icon-admonition-seealso)}.admonition.admonition-todo,div.admonition.admonition-todo{border-color:var(--pst-color-border)}.admonition.admonition-todo>.admonition-title:before,div.admonition.admonition-todo>.admonition-title:before{background-color:var(--pst-color-border)}.admonition.admonition-todo>.admonition-title:after,div.admonition.admonition-todo>.admonition-title:after{color:var(--pst-color-border);content:var(--pst-icon-admonition-todo)}.admonition.sidebar,div.admonition.sidebar{border-width:0 0 0 .2rem;clear:both;float:right;margin-left:.5rem;margin-top:0;max-width:40%}.admonition.sidebar.attention,.admonition.sidebar.important,div.admonition.sidebar.attention,div.admonition.sidebar.important{border-color:var(--pst-color-attention)}.admonition.sidebar.caution,.admonition.sidebar.warning,div.admonition.sidebar.caution,div.admonition.sidebar.warning{border-color:var(--pst-color-warning)}.admonition.sidebar.danger,.admonition.sidebar.error,div.admonition.sidebar.danger,div.admonition.sidebar.error{border-color:var(--pst-color-danger)}.admonition.sidebar.hint,.admonition.sidebar.seealso,.admonition.sidebar.tip,div.admonition.sidebar.hint,div.admonition.sidebar.seealso,div.admonition.sidebar.tip{border-color:var(--pst-color-success)}.admonition.sidebar.note,.admonition.sidebar.todo,div.admonition.sidebar.note,div.admonition.sidebar.todo{border-color:var(--pst-color-info)}.admonition.sidebar p.admonition-title~*,div.admonition.sidebar p.admonition-title~*{margin-left:0;margin-right:0}aside.topic,div.topic,div.topic.contents,nav.contents{background-color:var(--pst-color-surface);border-color:var(--pst-color-border);border-radius:.25rem;box-shadow:0 .2rem .5rem var(--pst-color-shadow),0 0 .0625rem var(--pst-color-shadow)!important;display:flex;flex-direction:column;padding:1rem 1.25rem}aside.topic .topic-title,div.topic .topic-title,div.topic.contents .topic-title,nav.contents .topic-title{margin:0 0 .5rem}aside.topic ul.simple,div.topic ul.simple,div.topic.contents ul.simple,nav.contents ul.simple{padding-left:1rem}aside.topic ul.simple ul,div.topic ul.simple ul,div.topic.contents ul.simple ul,nav.contents ul.simple ul{padding-left:2em}aside.sidebar{background-color:var(--pst-color-surface);border:1px solid var(--pst-color-border);border-radius:.25rem;margin-left:.5rem;padding:0}aside.sidebar>:last-child{padding-bottom:1rem}aside.sidebar p.sidebar-title{border-bottom:1px solid var(--pst-color-border);font-family:var(--pst-font-family-heading);font-weight:var(--pst-font-weight-heading);margin-bottom:0;padding-bottom:.5rem;padding-top:.5rem;position:relative}aside.sidebar>:not(.sidebar-title):first-child,aside.sidebar>p.sidebar-title+*{margin-top:1rem}aside.sidebar>*{padding-left:1rem;padding-right:1rem}p.rubric{display:flex;flex-direction:column}.seealso dd{margin-bottom:0;margin-top:0}table.field-list{border-collapse:separate;border-spacing:10px;margin-left:1px}table.field-list th.field-name{background-color:var(--pst-color-surface);padding:1px 8px 1px 5px;white-space:nowrap}table.field-list td.field-body p{font-style:italic}table.field-list td.field-body p>strong{font-style:normal}table.field-list td.field-body blockquote{border-left:none;margin:0 0 .3em;padding-left:30px}.table.autosummary td:first-child{white-space:nowrap}.sig{font-family:var(--pst-font-family-monospace)}.sig-inline.c-texpr,.sig-inline.cpp-texpr{font-family:unset}.sig.c .k,.sig.c .kt,.sig.c .m,.sig.c .s,.sig.c .sc,.sig.cpp .k,.sig.cpp .kt,.sig.cpp .m,.sig.cpp .s,.sig.cpp .sc{color:var(--pst-color-text-base)}.sig-name{color:var(--pst-color-inline-code)}dt:target,span.highlighted{background-color:var(--pst-color-target)}.viewcode-back{font-family:var(--pst-font-family-base)}.viewcode-block:target{background-color:var(--pst-color-target);border-bottom:1px solid var(--pst-color-border);border-top:1px solid var(--pst-color-border);position:relative}dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) dd{margin-left:2rem}dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) dd>dl.simple>dt{display:flex}dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) dl.field-list{display:grid;grid-template-columns:unset}dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) dt.field-even,dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) dt.field-odd{background-color:var(--pst-color-surface);margin-bottom:.1rem;margin-top:.2rem}div.highlight,div.literal-block-wrapper,div[class*=highlight-]{border-radius:.25rem;display:flex;flex-direction:column;width:unset}div.literal-block-wrapper{border:1px solid var(--pst-color-border);border-radius:.25rem}div.literal-block-wrapper div.code-block-caption{border-bottom:1px solid var(--pst-color-border);font-size:1rem;font-weight:var(--pst-font-weight-caption);margin:0;padding:.5rem}div.literal-block-wrapper div.code-block-caption a.headerlink{font-size:inherit}div.literal-block-wrapper div[class*=highlight-]{border-radius:0;margin:0}div.literal-block-wrapper div[class*=highlight-] pre{border:none;box-shadow:none}code.literal{background-color:var(--pst-color-surface);border:1px solid var(--pst-color-on-surface);border-radius:.25rem;padding:.1rem .25rem}figure a.headerlink{font-size:inherit;position:absolute}figure:hover a.headerlink{visibility:visible}figure figcaption{color:var(--pst-color-text-muted);font-family:var(--pst-font-family-heading);font-weight:var(--pst-font-weight-caption);margin-left:auto;margin-right:auto}figure figcaption table.table{margin-left:auto;margin-right:auto;width:fit-content}dt.label>span.brackets:not(:only-child):before{content:"["}dt.label>span.brackets:not(:only-child):after{content:"]"}a.footnote-reference{font-size:small;vertical-align:super}aside.footnote{margin-bottom:.5rem}aside.footnote:last-child{margin-bottom:1rem}aside.footnote span.backrefs,aside.footnote span.label{font-weight:700}aside.footnote:target{background-color:var(--pst-color-target)}div.doctest>div.highlight span.gp,span.linenos,table.highlighttable td.linenos{user-select:none;-webkit-user-select:text;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none}dd{margin-bottom:10px;margin-left:30px;margin-top:3px}ol li>p:first-child,ul li>p:first-child{margin-bottom:.25rem;margin-top:.25rem}blockquote{border-left:.25em solid var(--pst-color-border);border-radius:.25rem;padding:1em;position:relative}blockquote,blockquote p{color:var(--pst-color-text-muted)}blockquote .line-block{margin:0}blockquote p:last-child{margin-bottom:0}blockquote:before{background-color:var(--pst-color-border);content:"";height:100%;left:0;opacity:.1;pointer-events:none;position:absolute;top:0;width:100%;z-index:-1}span.guilabel{border:1px solid var(--pst-color-info);border-radius:4px;color:var(--pst-color-info);font-size:80%;font-weight:700;margin:auto 2px;padding:2.4px 6px;position:relative}span.guilabel:before{background-color:var(--pst-color-info);content:"";height:100%;left:0;opacity:.1;pointer-events:none;position:absolute;top:0;width:100%}a.reference.download:before{color:var(--pst-color-text-muted);content:var(--pst-icon-download);font-family:Font Awesome\ 6 Free;font-size:.8em;font-weight:600;padding:0 .25em}table{display:table;margin-left:auto;margin-right:auto;max-width:100%;overflow:auto;width:fit-content}table::-webkit-scrollbar{height:.5rem;width:.5rem}table::-webkit-scrollbar-thumb{background:var(--pst-color-text-muted);border-radius:.25rem}table::-webkit-scrollbar-track{background:transparent}table::-webkit-scrollbar-thumb{background:var(--pst-color-on-surface)}table::-webkit-scrollbar-thumb:hover,table:hover::-webkit-scrollbar-thumb{background:var(--pst-color-text-muted)}table.table-right{margin-right:0}table.table-left{margin-left:0}table caption{caption-side:top;color:var(--pst-color-text-muted);text-align:center}td.text-align\:left,th.text-align\:left{text-align:left}td.text-align\:right,th.text-align\:right{text-align:right}td.text-align\:center,th.text-align\:center{text-align:center}.toctree-wrapper p.caption{font-size:1.5em;margin-bottom:0}.toctree-wrapper>ul{padding-left:0}.toctree-wrapper li[class^=toctree-l]{list-style:none;margin-bottom:.2em}.toctree-wrapper li[class^=toctree-l]>a{font-size:1.1em;list-style:none}.toctree-wrapper li[class^=toctree-l]>ul{list-style:none;padding-inline-start:1.5em}.toctree-wrapper .toctree-l1>a{font-size:1.3em}div.topic.contents ul.simple,nav.contents ul.simple{list-style:none;padding-left:0}div.math,span.math{align-items:center;display:flex;max-width:100%;overflow:hidden}span.math{display:inline-flex}div.math{flex-direction:row-reverse;gap:.5em}div.math span.eqno a.headerlink{font-size:1em;position:relative}div.math mjx-container{flex-grow:1;overflow-x:auto;padding-bottom:.2rem}div.math mjx-container::-webkit-scrollbar{height:.5rem;width:.5rem}div.math mjx-container::-webkit-scrollbar-thumb{background:var(--pst-color-text-muted);border-radius:.25rem}div.math mjx-container::-webkit-scrollbar-track{background:transparent}div.math mjx-container::-webkit-scrollbar-thumb{background:var(--pst-color-on-surface)}div.math mjx-container::-webkit-scrollbar-thumb:hover,div.math mjx-container:hover::-webkit-scrollbar-thumb{background:var(--pst-color-text-muted)}.bd-sidebar-primary .sidebar-start-items>h2,.bd-sidebar-primary .sidebar-start-items>h3{margin-top:1rem}.bd-sidebar-primary .sidebar-start-items>ul{list-style:none;padding-left:0}article.bd-article>section+div.section{font-size:1.2em}article.bd-article>section+div.section span:first-child:before{content:var(--pst-icon-angle-left);font-family:Font Awesome\ 6 Free;font-weight:800}article.bd-article>section+div.section span:last-child:after{content:var(--pst-icon-angle-right);font-family:Font Awesome\ 6 Free;font-weight:800}.ablog-post ul.ablog-archive{padding-left:0}.docutils.container{margin-left:unset;margin-right:unset;max-width:unset;padding-left:unset;padding-right:unset;width:unset}div.highlight button.copybtn{align-items:center;background-color:unset;background-color:var(--pst-color-surface);border:none;display:flex;justify-content:center}div.highlight button.copybtn:not(.success){color:var(--pst-color-muted)}div.highlight button.copybtn:hover:not(.success){color:var(--pst-color-text)}div.highlight button.copybtn.o-tooltip--left:after{background-color:var(--pst-color-surface);color:var(--pst-color-text)}#ethical-ad-placement .ethical-footer a,#ethical-ad-placement .ethical-footer a:active,#ethical-ad-placement .ethical-footer a:hover,#ethical-ad-placement .ethical-footer a:visited,#ethical-ad-placement .ethical-sidebar a,#ethical-ad-placement .ethical-sidebar a:active,#ethical-ad-placement .ethical-sidebar a:hover,#ethical-ad-placement .ethical-sidebar a:visited{color:var(--pst-color-text-base)}#ethical-ad-placement .ethical-footer,#ethical-ad-placement .ethical-sidebar{background-color:var(--pst-color-background);border:1px solid var(--pst-color-border);border-radius:5px;color:var(--pst-color-text-base);font-size:14px;line-height:20px}html[data-theme=dark] .bd-content div.jupyter_container{background-color:var(--pst-color-surface);border:1px solid var(--pst-color-border);border-radius:.25rem}html[data-theme=dark] .bd-content div.jupyter_container div.highlight,html[data-theme=dark] .bd-content div.jupyter_container div.output{border-radius:.25rem}html[data-theme=dark] .bd-content div.jupyter_container div.highlight{background-color:var(--pst-color-surface)}.xr-wrap[hidden]{display:block!important}html[data-theme=light]{--pst-color-primary:#459db9;--pst-color-primary-text:#fff;--pst-color-primary-highlight:#306e81;--sd-color-primary:var(--pst-color-primary);--sd-color-primary-text:var(--pst-color-primary-text);--sd-color-primary-highlight:var(--pst-color-primary-highlight);--pst-color-secondary:#ee9040;--pst-color-secondary-text:#fff;--pst-color-secondary-highlight:#cf6912;--sd-color-secondary:var(--pst-color-secondary);--sd-color-secondary-text:var(--pst-color-secondary-text);--sd-color-secondary-highlight:var(--pst-color-secondary-highlight);--pst-color-success:#28a745;--pst-color-success-text:#fff;--pst-color-success-highlight:#19692c;--sd-color-success:var(--pst-color-success);--sd-color-success-text:var(--pst-color-success-text);--sd-color-success-highlight:var(--pst-color-success-highlight);--pst-color-info:#459db9;--pst-color-info-text:#fff;--pst-color-info-highlight:#306e81;--sd-color-info:var(--pst-color-info);--sd-color-info-text:var(--pst-color-info-text);--sd-color-info-highlight:var(--pst-color-info-highlight);--pst-color-warning:#ee9040;--pst-color-warning-text:#fff;--pst-color-warning-highlight:#cf6912;--sd-color-warning:var(--pst-color-warning);--sd-color-warning-text:var(--pst-color-warning-text);--sd-color-warning-highlight:var(--pst-color-warning-highlight);--pst-color-danger:#dc3545;--pst-color-danger-text:#fff;--pst-color-danger-highlight:#a71d2a;--sd-color-danger:var(--pst-color-danger);--sd-color-danger-text:var(--pst-color-danger-text);--sd-color-danger-highlight:var(--pst-color-danger-highlight);--pst-color-light:#c9c9c9;--pst-color-light-text:#000;--pst-color-light-highlight:#a3a3a3;--sd-color-light:var(--pst-color-light);--sd-color-light-text:var(--pst-color-light-text);--sd-color-light-highlight:var(--pst-color-light-highlight);--pst-color-muted:#646464;--pst-color-muted-text:#fff;--pst-color-muted-highlight:#3e3e3e;--sd-color-muted:var(--pst-color-muted);--sd-color-muted-text:var(--pst-color-muted-text);--sd-color-muted-highlight:var(--pst-color-muted-highlight);--pst-color-dark:#323232;--pst-color-dark-text:#fff;--pst-color-dark-highlight:#0c0c0c;--sd-color-dark:var(--pst-color-dark);--sd-color-dark-text:var(--pst-color-dark-text);--sd-color-dark-highlight:var(--pst-color-dark-highlight);--pst-color-black:#000;--pst-color-black-text:#fff;--pst-color-black-highlight:#000;--sd-color-black:var(--pst-color-black);--sd-color-black-text:var(--pst-color-black-text);--sd-color-black-highlight:var(--pst-color-black-highlight);--pst-color-white:#fff;--pst-color-white-text:#000;--pst-color-white-highlight:#d9d9d9;--sd-color-white:var(--pst-color-white);--sd-color-white-text:var(--pst-color-white-text);--sd-color-white-highlight:var(--pst-color-white-highlight)}html[data-theme=dark]{--pst-color-primary:#459db9;--pst-color-primary-text:#fff;--pst-color-primary-highlight:#306e81;--sd-color-primary:var(--pst-color-primary);--sd-color-primary-text:var(--pst-color-primary-text);--sd-color-primary-highlight:var(--pst-color-primary-highlight);--pst-color-secondary:#ee9040;--pst-color-secondary-text:#fff;--pst-color-secondary-highlight:#cf6912;--sd-color-secondary:var(--pst-color-secondary);--sd-color-secondary-text:var(--pst-color-secondary-text);--sd-color-secondary-highlight:var(--pst-color-secondary-highlight);--pst-color-success:#488757;--pst-color-success-text:#fff;--pst-color-success-highlight:#2d5537;--sd-color-success:var(--pst-color-success);--sd-color-success-text:var(--pst-color-success-text);--sd-color-success-highlight:var(--pst-color-success-highlight);--pst-color-info:#459db9;--pst-color-info-text:#fff;--pst-color-info-highlight:#306e81;--sd-color-info:var(--pst-color-info);--sd-color-info-text:var(--pst-color-info-text);--sd-color-info-highlight:var(--pst-color-info-highlight);--pst-color-warning:#ee9040;--pst-color-warning-text:#fff;--pst-color-warning-highlight:#cf6912;--sd-color-warning:var(--pst-color-warning);--sd-color-warning-text:var(--pst-color-warning-text);--sd-color-warning-highlight:var(--pst-color-warning-highlight);--pst-color-danger:#cb4653;--pst-color-danger-text:#fff;--pst-color-danger-highlight:#992b36;--sd-color-danger:var(--pst-color-danger);--sd-color-danger-text:var(--pst-color-danger-text);--sd-color-danger-highlight:var(--pst-color-danger-highlight);--pst-color-light:#c9c9c9;--pst-color-light-text:#000;--pst-color-light-highlight:#a3a3a3;--sd-color-light:var(--pst-color-light);--sd-color-light-text:var(--pst-color-light-text);--sd-color-light-highlight:var(--pst-color-light-highlight);--pst-color-muted:#a6a6a6;--pst-color-muted-text:#fff;--pst-color-muted-highlight:gray;--sd-color-muted:var(--pst-color-muted);--sd-color-muted-text:var(--pst-color-muted-text);--sd-color-muted-highlight:var(--pst-color-muted-highlight);--pst-color-dark:#cecece;--pst-color-dark-text:#000;--pst-color-dark-highlight:#a8a8a8;--sd-color-dark:var(--pst-color-dark);--sd-color-dark-text:var(--pst-color-dark-text);--sd-color-dark-highlight:var(--pst-color-dark-highlight);--pst-color-black:#000;--pst-color-black-text:#fff;--pst-color-black-highlight:#000;--sd-color-black:var(--pst-color-black);--sd-color-black-text:var(--pst-color-black-text);--sd-color-black-highlight:var(--pst-color-black-highlight);--pst-color-white:#fff;--pst-color-white-text:#000;--pst-color-white-highlight:#d9d9d9;--sd-color-white:var(--pst-color-white);--sd-color-white-text:var(--pst-color-white-text);--sd-color-white-highlight:var(--pst-color-white-highlight)}html[data-theme=dark],html[data-theme=light]{--sd-color-card-border:var(--pst-color-border)}html[data-theme=light] .sd-shadow-lg,html[data-theme=light] .sd-shadow-md,html[data-theme=light] .sd-shadow-sm,html[data-theme=light] .sd-shadow-xs{box-shadow:0 .2rem .5rem var(--pst-color-shadow),0 0 .0625rem var(--pst-color-shadow)!important}.bd-content .sd-card{border:1px solid var(--pst-color-border)}.bd-content .sd-card .sd-card-header{background-color:var(--pst-color-panel-background);border-bottom:1px solid var(--pst-color-border)}.bd-content .sd-card .sd-card-footer{border-top:1px solid var(--pst-color-border)}.bd-content .sd-card .sd-card-body,.bd-content .sd-card .sd-card-footer{background-color:var(--pst-color-panel-background)}.bd-content .sd-tab-set>input:checked+label,.bd-content .sd-tab-set>input:not(:checked)+label:hover{border-color:var(--pst-color-primary);color:var(--pst-color-primary)}.bd-content .sd-tab-set>input:not(:checked)+label:hover{opacity:.5}.bd-content .sd-tab-set>label{color:var(--pst-color-text-muted)}html .bd-content .sd-tab-set>label:hover{border-color:var(--pst-color-primary);color:var(--pst-color-primary);opacity:.5}details.sd-dropdown{border:0!important;box-shadow:0 .2rem .5rem var(--pst-color-shadow),0 0 .0625rem var(--pst-color-shadow)!important}details.sd-dropdown summary.sd-card-header{border:0!important}details.sd-dropdown summary.sd-card-header+div.sd-summary-content{border:0}details.sd-dropdown summary.sd-card-header{align-items:center;background-color:unset!important;border-left:.2rem solid var(--pst-sd-dropdown-color)!important;color:var(--pst-color-text)!important;display:flex;font-weight:600;padding-bottom:.5rem;padding-top:.5rem;position:relative}details.sd-dropdown summary.sd-card-header,details.sd-dropdown summary.sd-card-header+div.sd-summary-content{--pst-sd-dropdown-color:var(--sd-color-card-border)}details.sd-dropdown summary.sd-card-header.sd-bg-primary,details.sd-dropdown summary.sd-card-header.sd-bg-primary+div.sd-summary-content{--pst-sd-dropdown-color:var(--sd-color-primary)}details.sd-dropdown summary.sd-card-header.sd-bg-secondary,details.sd-dropdown summary.sd-card-header.sd-bg-secondary+div.sd-summary-content{--pst-sd-dropdown-color:var(--sd-color-secondary)}details.sd-dropdown summary.sd-card-header.sd-bg-success,details.sd-dropdown summary.sd-card-header.sd-bg-success+div.sd-summary-content{--pst-sd-dropdown-color:var(--sd-color-success)}details.sd-dropdown summary.sd-card-header.sd-bg-info,details.sd-dropdown summary.sd-card-header.sd-bg-info+div.sd-summary-content{--pst-sd-dropdown-color:var(--sd-color-info)}details.sd-dropdown summary.sd-card-header.sd-bg-warning,details.sd-dropdown summary.sd-card-header.sd-bg-warning+div.sd-summary-content{--pst-sd-dropdown-color:var(--sd-color-warning)}details.sd-dropdown summary.sd-card-header.sd-bg-danger,details.sd-dropdown summary.sd-card-header.sd-bg-danger+div.sd-summary-content{--pst-sd-dropdown-color:var(--sd-color-danger)}details.sd-dropdown summary.sd-card-header.sd-bg-light,details.sd-dropdown summary.sd-card-header.sd-bg-light+div.sd-summary-content{--pst-sd-dropdown-color:var(--sd-color-light)}details.sd-dropdown summary.sd-card-header.sd-bg-muted,details.sd-dropdown summary.sd-card-header.sd-bg-muted+div.sd-summary-content{--pst-sd-dropdown-color:var(--sd-color-muted)}details.sd-dropdown summary.sd-card-header.sd-bg-dark,details.sd-dropdown summary.sd-card-header.sd-bg-dark+div.sd-summary-content{--pst-sd-dropdown-color:var(--sd-color-dark)}details.sd-dropdown summary.sd-card-header.sd-bg-black,details.sd-dropdown summary.sd-card-header.sd-bg-black+div.sd-summary-content{--pst-sd-dropdown-color:var(--sd-color-black)}details.sd-dropdown summary.sd-card-header.sd-bg-white,details.sd-dropdown summary.sd-card-header.sd-bg-white+div.sd-summary-content{--pst-sd-dropdown-color:var(--sd-color-white)}details.sd-dropdown summary.sd-card-header:before{background-color:var(--pst-sd-dropdown-color);content:"";height:100%;left:0;opacity:.1;pointer-events:none;position:absolute;top:0;width:100%}details.sd-dropdown summary.sd-card-header+div.sd-summary-content{border-bottom-left-radius:calc(.25rem - 1px);border-left:.2rem solid var(--pst-sd-dropdown-color)!important}details.sd-dropdown summary.sd-card-header span.sd-summary-icon{align-items:center;color:var(--pst-sd-dropdown-color)!important;display:inline-flex}details.sd-dropdown summary.sd-card-header .sd-summary-down,details.sd-dropdown summary.sd-card-header .sd-summary-up{top:.7rem}@use "../variables/color" as *;html[data-theme=dark],html[data-theme=light]{--pst-color-panel-background:$value}.container[role=main]{max-width:none;padding-left:0;padding-right:0}.sphinx-bs .card{background-color:var(--pst-color-panel-background);border:1px solid var(--pst-color-border)}.sphinx-bs .card .card-header{border-bottom:1px solid var(--pst-color-border)}.sphinx-bs .card .card-footer{border-top:1px solid var(--pst-color-border)}.bd-content .tabbed-set>input:checked+label,.bd-content .tabbed-set>input:not(:checked)+label:hover{border-color:var(--pst-color-primary);color:var(--pst-color-primary)}.bd-content .tabbed-set>input:not(:checked)+label:hover{opacity:.5}.bd-content .tabbed-set>label{color:var(--pst-color-text-muted)}html .bd-content .tabbed-set>label:hover{border-color:var(--pst-color-primary);color:var(--pst-color-primary);opacity:.5}.bd-content .tabbed-set>.tabbed-content{border-color:var(--pst-color-border)}.bd-content .admonition button.toggle-button{color:inherit}.bd-content details.toggle-details summary{border-left:3px solid var(--pst-color-primary)}html div.rendered_html table{table-layout:auto}html[data-theme=dark] .bd-content .nboutput .output_area.rendered_html{background-color:var(--pst-color-text-base);border-radius:.25rem;color:var(--pst-color-on-background);padding:.5rem}html[data-theme=dark] .bd-content .nboutput .output_area.stderr{background:var(--pst-color-danger)}div.nblast.container{margin-bottom:1rem}div.cell_output .output{max-width:100%;overflow-x:auto}div.cell_output .output::-webkit-scrollbar{height:.5rem;width:.5rem}div.cell_output .output::-webkit-scrollbar-thumb{background:var(--pst-color-text-muted);border-radius:.25rem}div.cell_output .output::-webkit-scrollbar-track{background:transparent}div.cell_output .output::-webkit-scrollbar-thumb{background:var(--pst-color-on-surface)}div.cell_output .output::-webkit-scrollbar-thumb:hover,div.cell_output .output:hover::-webkit-scrollbar-thumb{background:var(--pst-color-text-muted)}html[data-theme=dark] .bd-content div.cell_output .text_html,html[data-theme=dark] .bd-content div.cell_output img{background-color:var(--pst-color-text-base);border-radius:.25rem;color:var(--pst-color-on-background);padding:.5rem}.bd-content div.cell_input{display:flex;flex-direction:column;justify-content:stretch}.bd-content div.cell_input,.bd-content div.output{border-radius:.25rem}.bd-content div.output table{table-layout:auto}.bd-search-container div#search-results>h2{font-size:var(--pst-font-size-icon);margin-top:0}.bd-search-container div#search-results p.search-summary{color:var(--pst-color-text-muted)}.bd-search-container ul.search{list-style:none;margin:0}.bd-search-container ul.search li{background-image:none;border-top:1px solid var(--pst-color-text-muted);margin:1rem 0;padding:1rem 0}.bd-search-container ul.search li>a{font-size:1.2em}.bd-search-container ul.search li div.context,.bd-search-container ul.search li p.context{color:var(--pst-color-text-base);margin:.5em 0 0}.bd-search-container ul.search li div.context a:before,.bd-search-container ul.search li p.context a:before{color:var(--pst-color-text-muted);content:"#";padding-right:.2em} \ No newline at end of file diff --git a/v0.10.x/_static/styles/theme.css b/v0.10.x/_static/styles/theme.css new file mode 100644 index 000000000..4519dd912 --- /dev/null +++ b/v0.10.x/_static/styles/theme.css @@ -0,0 +1,2 @@ +/* Provided by Sphinx's 'basic' theme, and included in the final set of assets */ +@import "../basic.css"; diff --git a/v0.10.x/_static/vendor/code-highlight.css b/v0.10.x/_static/vendor/code-highlight.css new file mode 100644 index 000000000..bbac8f245 --- /dev/null +++ b/v0.10.x/_static/vendor/code-highlight.css @@ -0,0 +1,69 @@ +/* + +Generated using: + + hugo gen chromastyles --style=witchhazel > /assets/css/code-highlight.css + +We replaced the background color, `#433e56`, with `var(--colorPrimaryDark)`. + +*/ +/* Background */ .chroma { color: #f8f8f2; background-color: var(--colorPrimaryDark) } +/* Error */ .chroma .err { color: #960050; background-color: #1e0010 } +/* LineTableTD */ .chroma .lntd { vertical-align: top; padding: 0; margin: 0; border: 0; } +/* LineTable */ .chroma .lntable { border-spacing: 0; padding: 0; margin: 0; border: 0; width: auto; overflow: auto; display: block; } +/* LineHighlight */ .chroma .hl { display: block; width: 100%;background-color: #555166 } +/* LineNumbersTable */ .chroma .lnt { margin-right: 0.4em; padding: 0 0.4em 0 0.4em;color: #7f7f7f } +/* LineNumbers */ .chroma .ln { margin-right: 0.4em; padding: 0 0.4em 0 0.4em;color: #7f7f7f } +/* Keyword */ .chroma .k { color: #c2ffdf } +/* KeywordConstant */ .chroma .kc { color: #c2ffdf } +/* KeywordDeclaration */ .chroma .kd { color: #c2ffdf } +/* KeywordNamespace */ .chroma .kn { color: #ffb8d1 } +/* KeywordPseudo */ .chroma .kp { color: #c2ffdf } +/* KeywordReserved */ .chroma .kr { color: #c2ffdf } +/* KeywordType */ .chroma .kt { color: #c2ffdf } +/* NameAttribute */ .chroma .na { color: #ceb1ff } +/* NameBuiltinPseudo */ .chroma .bp { color: #80cbc4 } +/* NameClass */ .chroma .nc { color: #ceb1ff } +/* NameConstant */ .chroma .no { color: #c5a3ff } +/* NameDecorator */ .chroma .nd { color: #ceb1ff } +/* NameException */ .chroma .ne { color: #ceb1ff } +/* NameFunction */ .chroma .nf { color: #ceb1ff } +/* NameTag */ .chroma .nt { color: #ffb8d1 } +/* Literal */ .chroma .l { color: #ae81ff } +/* LiteralDate */ .chroma .ld { color: #e6db74 } +/* LiteralString */ .chroma .s { color: #1bc5e0 } +/* LiteralStringAffix */ .chroma .sa { color: #1bc5e0 } +/* LiteralStringBacktick */ .chroma .sb { color: #1bc5e0 } +/* LiteralStringChar */ .chroma .sc { color: #1bc5e0 } +/* LiteralStringDelimiter */ .chroma .dl { color: #1bc5e0 } +/* LiteralStringDoc */ .chroma .sd { color: #1bc5e0 } +/* LiteralStringDouble */ .chroma .s2 { color: #1bc5e0 } +/* LiteralStringEscape */ .chroma .se { color: #1bc5e0 } +/* LiteralStringHeredoc */ .chroma .sh { color: #1bc5e0 } +/* LiteralStringInterpol */ .chroma .si { color: #1bc5e0 } +/* LiteralStringOther */ .chroma .sx { color: #1bc5e0 } +/* LiteralStringRegex */ .chroma .sr { color: #1bc5e0 } +/* LiteralStringSingle */ .chroma .s1 { color: #1bc5e0 } +/* LiteralStringSymbol */ .chroma .ss { color: #1bc5e0 } +/* LiteralNumber */ .chroma .m { color: #c5a3ff } +/* LiteralNumberBin */ .chroma .mb { color: #c5a3ff } +/* LiteralNumberFloat */ .chroma .mf { color: #c5a3ff } +/* LiteralNumberHex */ .chroma .mh { color: #c5a3ff } +/* LiteralNumberInteger */ .chroma .mi { color: #c5a3ff } +/* LiteralNumberIntegerLong */ .chroma .il { color: #c5a3ff } +/* LiteralNumberOct */ .chroma .mo { color: #c5a3ff } +/* Operator */ .chroma .o { color: #ffb8d1 } +/* OperatorWord */ .chroma .ow { color: #ffb8d1 } +/* Comment */ .chroma .c { color: #b0bec5 } +/* CommentHashbang */ .chroma .ch { color: #b0bec5 } +/* CommentMultiline */ .chroma .cm { color: #b0bec5 } +/* CommentSingle */ .chroma .c1 { color: #b0bec5 } +/* CommentSpecial */ .chroma .cs { color: #b0bec5 } +/* CommentPreproc */ .chroma .cp { color: #b0bec5 } +/* CommentPreprocFile */ .chroma .cpf { color: #b0bec5 } +/* GenericDeleted */ .chroma .gd { color: #f92672 } +/* GenericEmph */ .chroma .ge { font-style: italic } +/* GenericInserted */ .chroma .gi { color: #a6e22e } +/* GenericStrong */ .chroma .gs { font-weight: bold } +/* GenericSubheading */ .chroma .gu { color: #75715e } +/* TextWhitespace */ .chroma .w { color: #a8757b } diff --git a/v0.10.x/_static/vendor/content.css b/v0.10.x/_static/vendor/content.css new file mode 100644 index 000000000..45e5d5750 --- /dev/null +++ b/v0.10.x/_static/vendor/content.css @@ -0,0 +1,89 @@ +.content-padding { + display: flex; + justify-content: center; + padding: 75px 15px 125px 15px; +} + +.shortcuts-container { + width: 100%; + max-width: 150px; + margin: 75px 15px; +} + +.content-container { + max-width: 850px; + margin: 0 30px; + overflow: hidden; +} + +.content-container ul { + list-style-type: circle; + padding: 10px; + margin-left: 15px; +} + +.content-container ol { + padding: 10px; + margin-left: 15px; +} + +.content-container h1 { + font-size: 2em; + text-transform: uppercase; + letter-spacing: 1.5px; + font-weight: bold; +} + +.content-container .divider { + background: var(--colorPrimaryDark); +} + +.content-container h2 { + font-size: 1.4em; + text-transform: uppercase; + letter-spacing: 1.3px; + font-weight: bold; + margin-top:30px; +} + +.content-container h3 { + font-size: 1.1em; + text-transform: uppercase; + letter-spacing: 1.3px; + font-weight: bold; + margin-top: 25px; +} + +.shortcuts-title { + font-size: 17px; + font-weight: bold; +} + +#shortcuts { + margin-top: 10px; + border-left: 1px solid var(--colorPrimaryDark); +} + +.shortcuts-H2 { + margin: 5px 5px 0 15px; + font-size: 15px; + cursor: pointer; +} + +.shortcuts-H3 { + margin: 5px 5px 0 25px; + font-size: 14px; + cursor: pointer; +} + +.sidebar-links { + display: flex; + flex-direction: column; + margin: 30px 0 0 0; +} + +@media only screen and (max-width: 1090px) { + .shortcuts-container { + display: none; + } +} diff --git a/v0.10.x/_static/vendor/display-card.css b/v0.10.x/_static/vendor/display-card.css new file mode 100644 index 000000000..201269588 --- /dev/null +++ b/v0.10.x/_static/vendor/display-card.css @@ -0,0 +1,148 @@ +.h-card { + width: 100%; + + border-radius: 12px; + + /* box-shadow: rgba(0, 0, 0, 0.16) 0px 1px 4px; */ +} + +.h-card__holder { + display: flex; + padding: 50px 0; + box-shadow: 0 1em 1em -1em rgba(0, 0, 0, .25); +} + +.h-card .h-card__holder:nth-child(even) { + flex-direction: row-reverse; +} + +.h-card .h-card__holder:nth-child(even) .h-card__display-wrapper { + margin-right: 0; + margin-left: 24px; +} + +.h-card__display { + width: 360px; + height: 220px; + + border-radius: 12px; + transition: transform 0.5s ease-in-out; +} + +.h-card__display-wrapper:hover .h-card__display { + transform: scale(1.3); +} + +.h-card__display-wrapper { + width: 360px; + min-width: 360px; + height: 220px; + + border-radius: 12px; + margin-right: 24px; + + overflow: hidden; +} + +.h-card__header { + display: flex; +} + +.h-card__title-icon { + width: 30px; + height: 30px; + filter: invert(11%) sepia(86%) saturate(4861%) hue-rotate(10deg) brightness(84%) contrast(121%); + + margin-right: 12px; +} + +@media only screen and (max-width: 600px) { + .h-card__title-icon { + width: 15px; + height: 15px; + filter: brightness(0) invert(1); + margin-right: 8px; + } +} + +.h-card__title { + font-weight: 600; + color: var(--colorPrimaryDark); + + margin: 0; + margin-bottom: 10px; +} + +@media only screen and (max-width: 600px) { + .h-card__title { + font-size: 12px; + color: white; + } +} + +.h-card__data { + display: flex; + flex-direction: column; + justify-content: space-between; + + position: relative; + overflow: hidden; +} + +.h-card__content { + margin: 0 0 10px 0; + padding: 0; + + justify-content: center; +} + +.h-card__button { + height: 20px; + + font-size: 12px; + font-weight: 600; + + text-transform: uppercase; + + color: rgb(153, 0, 0); + text-decoration: underline; + + border-radius: 25px; + + display: flex; + align-items: center; +} + +.h-card__button .svg-inline--fa { + margin-left: 10px; + font-size: 15px; +} + +.h-card__divider { + margin-top: -10px; + +} + +.h-card__data-background { + position: absolute; + + opacity: 0.04; + + filter: invert(11%) sepia(86%) saturate(4861%) hue-rotate(10deg) brightness(84%) contrast(121%); + + width: 80%; + height: 80%; + + top: 10%; + left: 30%; + + transition: opacity 0.2s ease-in-out; +} + +.h-card__holder:hover .h-card__data-background { + opacity: 0.1; +} + +.engineering { + transform: rotate(-15deg); +} diff --git a/v0.10.x/_static/vendor/fa.css b/v0.10.x/_static/vendor/fa.css new file mode 100644 index 000000000..dc98a1c59 --- /dev/null +++ b/v0.10.x/_static/vendor/fa.css @@ -0,0 +1,5 @@ +/*! + * Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com + * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) + */ +.fa,.fab,.fad,.fal,.far,.fas{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;display:inline-block;font-style:normal;font-variant:normal;text-rendering:auto;line-height:1}.fa-lg{font-size:1.33333em;line-height:.75em;vertical-align:-.0667em}.fa-xs{font-size:.75em}.fa-sm{font-size:.875em}.fa-1x{font-size:1em}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-6x{font-size:6em}.fa-7x{font-size:7em}.fa-8x{font-size:8em}.fa-9x{font-size:9em}.fa-10x{font-size:10em}.fa-fw{text-align:center;width:1.25em}.fa-ul{list-style-type:none;margin-left:2.5em;padding-left:0}.fa-ul>li{position:relative}.fa-li{left:-2em;position:absolute;text-align:center;width:2em;line-height:inherit}.fa-border{border:.08em solid #eee;border-radius:.1em;padding:.2em .25em .15em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left,.fab.fa-pull-left,.fal.fa-pull-left,.far.fa-pull-left,.fas.fa-pull-left{margin-right:.3em}.fa.fa-pull-right,.fab.fa-pull-right,.fal.fa-pull-right,.far.fa-pull-right,.fas.fa-pull-right{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s linear infinite;animation:fa-spin 2s linear infinite}.fa-pulse{-webkit-animation:fa-spin 1s steps(8) infinite;animation:fa-spin 1s steps(8) infinite}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";-webkit-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";-webkit-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";-webkit-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";-webkit-transform:scaleX(-1);transform:scaleX(-1)}.fa-flip-vertical{-webkit-transform:scaleY(-1);transform:scaleY(-1)}.fa-flip-both,.fa-flip-horizontal.fa-flip-vertical,.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)"}.fa-flip-both,.fa-flip-horizontal.fa-flip-vertical{-webkit-transform:scale(-1);transform:scale(-1)}:root .fa-flip-both,:root .fa-flip-horizontal,:root .fa-flip-vertical,:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270{-webkit-filter:none;filter:none}.fa-stack{display:inline-block;height:2em;line-height:2em;position:relative;vertical-align:middle;width:2.5em}.fa-stack-1x,.fa-stack-2x{left:0;position:absolute;text-align:center;width:100%}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-500px:before{content:"\f26e"}.fa-accessible-icon:before{content:"\f368"}.fa-accusoft:before{content:"\f369"}.fa-acquisitions-incorporated:before{content:"\f6af"}.fa-ad:before{content:"\f641"}.fa-address-book:before{content:"\f2b9"}.fa-address-card:before{content:"\f2bb"}.fa-adjust:before{content:"\f042"}.fa-adn:before{content:"\f170"}.fa-adversal:before{content:"\f36a"}.fa-affiliatetheme:before{content:"\f36b"}.fa-air-freshener:before{content:"\f5d0"}.fa-airbnb:before{content:"\f834"}.fa-algolia:before{content:"\f36c"}.fa-align-center:before{content:"\f037"}.fa-align-justify:before{content:"\f039"}.fa-align-left:before{content:"\f036"}.fa-align-right:before{content:"\f038"}.fa-alipay:before{content:"\f642"}.fa-allergies:before{content:"\f461"}.fa-amazon:before{content:"\f270"}.fa-amazon-pay:before{content:"\f42c"}.fa-ambulance:before{content:"\f0f9"}.fa-american-sign-language-interpreting:before{content:"\f2a3"}.fa-amilia:before{content:"\f36d"}.fa-anchor:before{content:"\f13d"}.fa-android:before{content:"\f17b"}.fa-angellist:before{content:"\f209"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-down:before{content:"\f107"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angry:before{content:"\f556"}.fa-angrycreative:before{content:"\f36e"}.fa-angular:before{content:"\f420"}.fa-ankh:before{content:"\f644"}.fa-app-store:before{content:"\f36f"}.fa-app-store-ios:before{content:"\f370"}.fa-apper:before{content:"\f371"}.fa-apple:before{content:"\f179"}.fa-apple-alt:before{content:"\f5d1"}.fa-apple-pay:before{content:"\f415"}.fa-archive:before{content:"\f187"}.fa-archway:before{content:"\f557"}.fa-arrow-alt-circle-down:before{content:"\f358"}.fa-arrow-alt-circle-left:before{content:"\f359"}.fa-arrow-alt-circle-right:before{content:"\f35a"}.fa-arrow-alt-circle-up:before{content:"\f35b"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-down:before{content:"\f063"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrows-alt:before{content:"\f0b2"}.fa-arrows-alt-h:before{content:"\f337"}.fa-arrows-alt-v:before{content:"\f338"}.fa-artstation:before{content:"\f77a"}.fa-assistive-listening-systems:before{content:"\f2a2"}.fa-asterisk:before{content:"\f069"}.fa-asymmetrik:before{content:"\f372"}.fa-at:before{content:"\f1fa"}.fa-atlas:before{content:"\f558"}.fa-atlassian:before{content:"\f77b"}.fa-atom:before{content:"\f5d2"}.fa-audible:before{content:"\f373"}.fa-audio-description:before{content:"\f29e"}.fa-autoprefixer:before{content:"\f41c"}.fa-avianex:before{content:"\f374"}.fa-aviato:before{content:"\f421"}.fa-award:before{content:"\f559"}.fa-aws:before{content:"\f375"}.fa-baby:before{content:"\f77c"}.fa-baby-carriage:before{content:"\f77d"}.fa-backspace:before{content:"\f55a"}.fa-backward:before{content:"\f04a"}.fa-bacon:before{content:"\f7e5"}.fa-bacteria:before{content:"\e059"}.fa-bacterium:before{content:"\e05a"}.fa-bahai:before{content:"\f666"}.fa-balance-scale:before{content:"\f24e"}.fa-balance-scale-left:before{content:"\f515"}.fa-balance-scale-right:before{content:"\f516"}.fa-ban:before{content:"\f05e"}.fa-band-aid:before{content:"\f462"}.fa-bandcamp:before{content:"\f2d5"}.fa-barcode:before{content:"\f02a"}.fa-bars:before{content:"\f0c9"}.fa-baseball-ball:before{content:"\f433"}.fa-basketball-ball:before{content:"\f434"}.fa-bath:before{content:"\f2cd"}.fa-battery-empty:before{content:"\f244"}.fa-battery-full:before{content:"\f240"}.fa-battery-half:before{content:"\f242"}.fa-battery-quarter:before{content:"\f243"}.fa-battery-three-quarters:before{content:"\f241"}.fa-battle-net:before{content:"\f835"}.fa-bed:before{content:"\f236"}.fa-beer:before{content:"\f0fc"}.fa-behance:before{content:"\f1b4"}.fa-behance-square:before{content:"\f1b5"}.fa-bell:before{content:"\f0f3"}.fa-bell-slash:before{content:"\f1f6"}.fa-bezier-curve:before{content:"\f55b"}.fa-bible:before{content:"\f647"}.fa-bicycle:before{content:"\f206"}.fa-biking:before{content:"\f84a"}.fa-bimobject:before{content:"\f378"}.fa-binoculars:before{content:"\f1e5"}.fa-biohazard:before{content:"\f780"}.fa-birthday-cake:before{content:"\f1fd"}.fa-bitbucket:before{content:"\f171"}.fa-bitcoin:before{content:"\f379"}.fa-bity:before{content:"\f37a"}.fa-black-tie:before{content:"\f27e"}.fa-blackberry:before{content:"\f37b"}.fa-blender:before{content:"\f517"}.fa-blender-phone:before{content:"\f6b6"}.fa-blind:before{content:"\f29d"}.fa-blog:before{content:"\f781"}.fa-blogger:before{content:"\f37c"}.fa-blogger-b:before{content:"\f37d"}.fa-bluetooth:before{content:"\f293"}.fa-bluetooth-b:before{content:"\f294"}.fa-bold:before{content:"\f032"}.fa-bolt:before{content:"\f0e7"}.fa-bomb:before{content:"\f1e2"}.fa-bone:before{content:"\f5d7"}.fa-bong:before{content:"\f55c"}.fa-book:before{content:"\f02d"}.fa-book-dead:before{content:"\f6b7"}.fa-book-medical:before{content:"\f7e6"}.fa-book-open:before{content:"\f518"}.fa-book-reader:before{content:"\f5da"}.fa-bookmark:before{content:"\f02e"}.fa-bootstrap:before{content:"\f836"}.fa-border-all:before{content:"\f84c"}.fa-border-none:before{content:"\f850"}.fa-border-style:before{content:"\f853"}.fa-bowling-ball:before{content:"\f436"}.fa-box:before{content:"\f466"}.fa-box-open:before{content:"\f49e"}.fa-box-tissue:before{content:"\e05b"}.fa-boxes:before{content:"\f468"}.fa-braille:before{content:"\f2a1"}.fa-brain:before{content:"\f5dc"}.fa-bread-slice:before{content:"\f7ec"}.fa-briefcase:before{content:"\f0b1"}.fa-briefcase-medical:before{content:"\f469"}.fa-broadcast-tower:before{content:"\f519"}.fa-broom:before{content:"\f51a"}.fa-brush:before{content:"\f55d"}.fa-btc:before{content:"\f15a"}.fa-buffer:before{content:"\f837"}.fa-bug:before{content:"\f188"}.fa-building:before{content:"\f1ad"}.fa-bullhorn:before{content:"\f0a1"}.fa-bullseye:before{content:"\f140"}.fa-burn:before{content:"\f46a"}.fa-buromobelexperte:before{content:"\f37f"}.fa-bus:before{content:"\f207"}.fa-bus-alt:before{content:"\f55e"}.fa-business-time:before{content:"\f64a"}.fa-buy-n-large:before{content:"\f8a6"}.fa-buysellads:before{content:"\f20d"}.fa-calculator:before{content:"\f1ec"}.fa-calendar:before{content:"\f133"}.fa-calendar-alt:before{content:"\f073"}.fa-calendar-check:before{content:"\f274"}.fa-calendar-day:before{content:"\f783"}.fa-calendar-minus:before{content:"\f272"}.fa-calendar-plus:before{content:"\f271"}.fa-calendar-times:before{content:"\f273"}.fa-calendar-week:before{content:"\f784"}.fa-camera:before{content:"\f030"}.fa-camera-retro:before{content:"\f083"}.fa-campground:before{content:"\f6bb"}.fa-canadian-maple-leaf:before{content:"\f785"}.fa-candy-cane:before{content:"\f786"}.fa-cannabis:before{content:"\f55f"}.fa-capsules:before{content:"\f46b"}.fa-car:before{content:"\f1b9"}.fa-car-alt:before{content:"\f5de"}.fa-car-battery:before{content:"\f5df"}.fa-car-crash:before{content:"\f5e1"}.fa-car-side:before{content:"\f5e4"}.fa-caravan:before{content:"\f8ff"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-caret-square-down:before{content:"\f150"}.fa-caret-square-left:before{content:"\f191"}.fa-caret-square-right:before{content:"\f152"}.fa-caret-square-up:before{content:"\f151"}.fa-caret-up:before{content:"\f0d8"}.fa-carrot:before{content:"\f787"}.fa-cart-arrow-down:before{content:"\f218"}.fa-cart-plus:before{content:"\f217"}.fa-cash-register:before{content:"\f788"}.fa-cat:before{content:"\f6be"}.fa-cc-amazon-pay:before{content:"\f42d"}.fa-cc-amex:before{content:"\f1f3"}.fa-cc-apple-pay:before{content:"\f416"}.fa-cc-diners-club:before{content:"\f24c"}.fa-cc-discover:before{content:"\f1f2"}.fa-cc-jcb:before{content:"\f24b"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-cc-paypal:before{content:"\f1f4"}.fa-cc-stripe:before{content:"\f1f5"}.fa-cc-visa:before{content:"\f1f0"}.fa-centercode:before{content:"\f380"}.fa-centos:before{content:"\f789"}.fa-certificate:before{content:"\f0a3"}.fa-chair:before{content:"\f6c0"}.fa-chalkboard:before{content:"\f51b"}.fa-chalkboard-teacher:before{content:"\f51c"}.fa-charging-station:before{content:"\f5e7"}.fa-chart-area:before{content:"\f1fe"}.fa-chart-bar:before{content:"\f080"}.fa-chart-line:before{content:"\f201"}.fa-chart-pie:before{content:"\f200"}.fa-check:before{content:"\f00c"}.fa-check-circle:before{content:"\f058"}.fa-check-double:before{content:"\f560"}.fa-check-square:before{content:"\f14a"}.fa-cheese:before{content:"\f7ef"}.fa-chess:before{content:"\f439"}.fa-chess-bishop:before{content:"\f43a"}.fa-chess-board:before{content:"\f43c"}.fa-chess-king:before{content:"\f43f"}.fa-chess-knight:before{content:"\f441"}.fa-chess-pawn:before{content:"\f443"}.fa-chess-queen:before{content:"\f445"}.fa-chess-rook:before{content:"\f447"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-down:before{content:"\f078"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-chevron-up:before{content:"\f077"}.fa-child:before{content:"\f1ae"}.fa-chrome:before{content:"\f268"}.fa-chromecast:before{content:"\f838"}.fa-church:before{content:"\f51d"}.fa-circle:before{content:"\f111"}.fa-circle-notch:before{content:"\f1ce"}.fa-city:before{content:"\f64f"}.fa-clinic-medical:before{content:"\f7f2"}.fa-clipboard:before{content:"\f328"}.fa-clipboard-check:before{content:"\f46c"}.fa-clipboard-list:before{content:"\f46d"}.fa-clock:before{content:"\f017"}.fa-clone:before{content:"\f24d"}.fa-closed-captioning:before{content:"\f20a"}.fa-cloud:before{content:"\f0c2"}.fa-cloud-download-alt:before{content:"\f381"}.fa-cloud-meatball:before{content:"\f73b"}.fa-cloud-moon:before{content:"\f6c3"}.fa-cloud-moon-rain:before{content:"\f73c"}.fa-cloud-rain:before{content:"\f73d"}.fa-cloud-showers-heavy:before{content:"\f740"}.fa-cloud-sun:before{content:"\f6c4"}.fa-cloud-sun-rain:before{content:"\f743"}.fa-cloud-upload-alt:before{content:"\f382"}.fa-cloudflare:before{content:"\e07d"}.fa-cloudscale:before{content:"\f383"}.fa-cloudsmith:before{content:"\f384"}.fa-cloudversify:before{content:"\f385"}.fa-cocktail:before{content:"\f561"}.fa-code:before{content:"\f121"}.fa-code-branch:before{content:"\f126"}.fa-codepen:before{content:"\f1cb"}.fa-codiepie:before{content:"\f284"}.fa-coffee:before{content:"\f0f4"}.fa-cog:before{content:"\f013"}.fa-cogs:before{content:"\f085"}.fa-coins:before{content:"\f51e"}.fa-columns:before{content:"\f0db"}.fa-comment:before{content:"\f075"}.fa-comment-alt:before{content:"\f27a"}.fa-comment-dollar:before{content:"\f651"}.fa-comment-dots:before{content:"\f4ad"}.fa-comment-medical:before{content:"\f7f5"}.fa-comment-slash:before{content:"\f4b3"}.fa-comments:before{content:"\f086"}.fa-comments-dollar:before{content:"\f653"}.fa-compact-disc:before{content:"\f51f"}.fa-compass:before{content:"\f14e"}.fa-compress:before{content:"\f066"}.fa-compress-alt:before{content:"\f422"}.fa-compress-arrows-alt:before{content:"\f78c"}.fa-concierge-bell:before{content:"\f562"}.fa-confluence:before{content:"\f78d"}.fa-connectdevelop:before{content:"\f20e"}.fa-contao:before{content:"\f26d"}.fa-cookie:before{content:"\f563"}.fa-cookie-bite:before{content:"\f564"}.fa-copy:before{content:"\f0c5"}.fa-copyright:before{content:"\f1f9"}.fa-cotton-bureau:before{content:"\f89e"}.fa-couch:before{content:"\f4b8"}.fa-cpanel:before{content:"\f388"}.fa-creative-commons:before{content:"\f25e"}.fa-creative-commons-by:before{content:"\f4e7"}.fa-creative-commons-nc:before{content:"\f4e8"}.fa-creative-commons-nc-eu:before{content:"\f4e9"}.fa-creative-commons-nc-jp:before{content:"\f4ea"}.fa-creative-commons-nd:before{content:"\f4eb"}.fa-creative-commons-pd:before{content:"\f4ec"}.fa-creative-commons-pd-alt:before{content:"\f4ed"}.fa-creative-commons-remix:before{content:"\f4ee"}.fa-creative-commons-sa:before{content:"\f4ef"}.fa-creative-commons-sampling:before{content:"\f4f0"}.fa-creative-commons-sampling-plus:before{content:"\f4f1"}.fa-creative-commons-share:before{content:"\f4f2"}.fa-creative-commons-zero:before{content:"\f4f3"}.fa-credit-card:before{content:"\f09d"}.fa-critical-role:before{content:"\f6c9"}.fa-crop:before{content:"\f125"}.fa-crop-alt:before{content:"\f565"}.fa-cross:before{content:"\f654"}.fa-crosshairs:before{content:"\f05b"}.fa-crow:before{content:"\f520"}.fa-crown:before{content:"\f521"}.fa-crutch:before{content:"\f7f7"}.fa-css3:before{content:"\f13c"}.fa-css3-alt:before{content:"\f38b"}.fa-cube:before{content:"\f1b2"}.fa-cubes:before{content:"\f1b3"}.fa-cut:before{content:"\f0c4"}.fa-cuttlefish:before{content:"\f38c"}.fa-d-and-d:before{content:"\f38d"}.fa-d-and-d-beyond:before{content:"\f6ca"}.fa-dailymotion:before{content:"\e052"}.fa-dashcube:before{content:"\f210"}.fa-database:before{content:"\f1c0"}.fa-deaf:before{content:"\f2a4"}.fa-deezer:before{content:"\e077"}.fa-delicious:before{content:"\f1a5"}.fa-democrat:before{content:"\f747"}.fa-deploydog:before{content:"\f38e"}.fa-deskpro:before{content:"\f38f"}.fa-desktop:before{content:"\f108"}.fa-dev:before{content:"\f6cc"}.fa-deviantart:before{content:"\f1bd"}.fa-dharmachakra:before{content:"\f655"}.fa-dhl:before{content:"\f790"}.fa-diagnoses:before{content:"\f470"}.fa-diaspora:before{content:"\f791"}.fa-dice:before{content:"\f522"}.fa-dice-d20:before{content:"\f6cf"}.fa-dice-d6:before{content:"\f6d1"}.fa-dice-five:before{content:"\f523"}.fa-dice-four:before{content:"\f524"}.fa-dice-one:before{content:"\f525"}.fa-dice-six:before{content:"\f526"}.fa-dice-three:before{content:"\f527"}.fa-dice-two:before{content:"\f528"}.fa-digg:before{content:"\f1a6"}.fa-digital-ocean:before{content:"\f391"}.fa-digital-tachograph:before{content:"\f566"}.fa-directions:before{content:"\f5eb"}.fa-discord:before{content:"\f392"}.fa-discourse:before{content:"\f393"}.fa-disease:before{content:"\f7fa"}.fa-divide:before{content:"\f529"}.fa-dizzy:before{content:"\f567"}.fa-dna:before{content:"\f471"}.fa-dochub:before{content:"\f394"}.fa-docker:before{content:"\f395"}.fa-dog:before{content:"\f6d3"}.fa-dollar-sign:before{content:"\f155"}.fa-dolly:before{content:"\f472"}.fa-dolly-flatbed:before{content:"\f474"}.fa-donate:before{content:"\f4b9"}.fa-door-closed:before{content:"\f52a"}.fa-door-open:before{content:"\f52b"}.fa-dot-circle:before{content:"\f192"}.fa-dove:before{content:"\f4ba"}.fa-download:before{content:"\f019"}.fa-draft2digital:before{content:"\f396"}.fa-drafting-compass:before{content:"\f568"}.fa-dragon:before{content:"\f6d5"}.fa-draw-polygon:before{content:"\f5ee"}.fa-dribbble:before{content:"\f17d"}.fa-dribbble-square:before{content:"\f397"}.fa-dropbox:before{content:"\f16b"}.fa-drum:before{content:"\f569"}.fa-drum-steelpan:before{content:"\f56a"}.fa-drumstick-bite:before{content:"\f6d7"}.fa-drupal:before{content:"\f1a9"}.fa-dumbbell:before{content:"\f44b"}.fa-dumpster:before{content:"\f793"}.fa-dumpster-fire:before{content:"\f794"}.fa-dungeon:before{content:"\f6d9"}.fa-dyalog:before{content:"\f399"}.fa-earlybirds:before{content:"\f39a"}.fa-ebay:before{content:"\f4f4"}.fa-edge:before{content:"\f282"}.fa-edge-legacy:before{content:"\e078"}.fa-edit:before{content:"\f044"}.fa-egg:before{content:"\f7fb"}.fa-eject:before{content:"\f052"}.fa-elementor:before{content:"\f430"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-ello:before{content:"\f5f1"}.fa-ember:before{content:"\f423"}.fa-empire:before{content:"\f1d1"}.fa-envelope:before{content:"\f0e0"}.fa-envelope-open:before{content:"\f2b6"}.fa-envelope-open-text:before{content:"\f658"}.fa-envelope-square:before{content:"\f199"}.fa-envira:before{content:"\f299"}.fa-equals:before{content:"\f52c"}.fa-eraser:before{content:"\f12d"}.fa-erlang:before{content:"\f39d"}.fa-ethereum:before{content:"\f42e"}.fa-ethernet:before{content:"\f796"}.fa-etsy:before{content:"\f2d7"}.fa-euro-sign:before{content:"\f153"}.fa-evernote:before{content:"\f839"}.fa-exchange-alt:before{content:"\f362"}.fa-exclamation:before{content:"\f12a"}.fa-exclamation-circle:before{content:"\f06a"}.fa-exclamation-triangle:before{content:"\f071"}.fa-expand:before{content:"\f065"}.fa-expand-alt:before{content:"\f424"}.fa-expand-arrows-alt:before{content:"\f31e"}.fa-expeditedssl:before{content:"\f23e"}.fa-external-link-alt:before{content:"\f35d"}.fa-external-link-square-alt:before{content:"\f360"}.fa-eye:before{content:"\f06e"}.fa-eye-dropper:before{content:"\f1fb"}.fa-eye-slash:before{content:"\f070"}.fa-facebook:before{content:"\f09a"}.fa-facebook-f:before{content:"\f39e"}.fa-facebook-messenger:before{content:"\f39f"}.fa-facebook-square:before{content:"\f082"}.fa-fan:before{content:"\f863"}.fa-fantasy-flight-games:before{content:"\f6dc"}.fa-fast-backward:before{content:"\f049"}.fa-fast-forward:before{content:"\f050"}.fa-faucet:before{content:"\e005"}.fa-fax:before{content:"\f1ac"}.fa-feather:before{content:"\f52d"}.fa-feather-alt:before{content:"\f56b"}.fa-fedex:before{content:"\f797"}.fa-fedora:before{content:"\f798"}.fa-female:before{content:"\f182"}.fa-fighter-jet:before{content:"\f0fb"}.fa-figma:before{content:"\f799"}.fa-file:before{content:"\f15b"}.fa-file-alt:before{content:"\f15c"}.fa-file-archive:before{content:"\f1c6"}.fa-file-audio:before{content:"\f1c7"}.fa-file-code:before{content:"\f1c9"}.fa-file-contract:before{content:"\f56c"}.fa-file-csv:before{content:"\f6dd"}.fa-file-download:before{content:"\f56d"}.fa-file-excel:before{content:"\f1c3"}.fa-file-export:before{content:"\f56e"}.fa-file-image:before{content:"\f1c5"}.fa-file-import:before{content:"\f56f"}.fa-file-invoice:before{content:"\f570"}.fa-file-invoice-dollar:before{content:"\f571"}.fa-file-medical:before{content:"\f477"}.fa-file-medical-alt:before{content:"\f478"}.fa-file-pdf:before{content:"\f1c1"}.fa-file-powerpoint:before{content:"\f1c4"}.fa-file-prescription:before{content:"\f572"}.fa-file-signature:before{content:"\f573"}.fa-file-upload:before{content:"\f574"}.fa-file-video:before{content:"\f1c8"}.fa-file-word:before{content:"\f1c2"}.fa-fill:before{content:"\f575"}.fa-fill-drip:before{content:"\f576"}.fa-film:before{content:"\f008"}.fa-filter:before{content:"\f0b0"}.fa-fingerprint:before{content:"\f577"}.fa-fire:before{content:"\f06d"}.fa-fire-alt:before{content:"\f7e4"}.fa-fire-extinguisher:before{content:"\f134"}.fa-firefox:before{content:"\f269"}.fa-firefox-browser:before{content:"\e007"}.fa-first-aid:before{content:"\f479"}.fa-first-order:before{content:"\f2b0"}.fa-first-order-alt:before{content:"\f50a"}.fa-firstdraft:before{content:"\f3a1"}.fa-fish:before{content:"\f578"}.fa-fist-raised:before{content:"\f6de"}.fa-flag:before{content:"\f024"}.fa-flag-checkered:before{content:"\f11e"}.fa-flag-usa:before{content:"\f74d"}.fa-flask:before{content:"\f0c3"}.fa-flickr:before{content:"\f16e"}.fa-flipboard:before{content:"\f44d"}.fa-flushed:before{content:"\f579"}.fa-fly:before{content:"\f417"}.fa-folder:before{content:"\f07b"}.fa-folder-minus:before{content:"\f65d"}.fa-folder-open:before{content:"\f07c"}.fa-folder-plus:before{content:"\f65e"}.fa-font:before{content:"\f031"}.fa-font-awesome:before{content:"\f2b4"}.fa-font-awesome-alt:before{content:"\f35c"}.fa-font-awesome-flag:before{content:"\f425"}.fa-font-awesome-logo-full:before{content:"\f4e6"}.fa-fonticons:before{content:"\f280"}.fa-fonticons-fi:before{content:"\f3a2"}.fa-football-ball:before{content:"\f44e"}.fa-fort-awesome:before{content:"\f286"}.fa-fort-awesome-alt:before{content:"\f3a3"}.fa-forumbee:before{content:"\f211"}.fa-forward:before{content:"\f04e"}.fa-foursquare:before{content:"\f180"}.fa-free-code-camp:before{content:"\f2c5"}.fa-freebsd:before{content:"\f3a4"}.fa-frog:before{content:"\f52e"}.fa-frown:before{content:"\f119"}.fa-frown-open:before{content:"\f57a"}.fa-fulcrum:before{content:"\f50b"}.fa-funnel-dollar:before{content:"\f662"}.fa-futbol:before{content:"\f1e3"}.fa-galactic-republic:before{content:"\f50c"}.fa-galactic-senate:before{content:"\f50d"}.fa-gamepad:before{content:"\f11b"}.fa-gas-pump:before{content:"\f52f"}.fa-gavel:before{content:"\f0e3"}.fa-gem:before{content:"\f3a5"}.fa-genderless:before{content:"\f22d"}.fa-get-pocket:before{content:"\f265"}.fa-gg:before{content:"\f260"}.fa-gg-circle:before{content:"\f261"}.fa-ghost:before{content:"\f6e2"}.fa-gift:before{content:"\f06b"}.fa-gifts:before{content:"\f79c"}.fa-git:before{content:"\f1d3"}.fa-git-alt:before{content:"\f841"}.fa-git-square:before{content:"\f1d2"}.fa-github:before{content:"\f09b"}.fa-github-alt:before{content:"\f113"}.fa-github-square:before{content:"\f092"}.fa-gitkraken:before{content:"\f3a6"}.fa-gitlab:before{content:"\f296"}.fa-gitter:before{content:"\f426"}.fa-glass-cheers:before{content:"\f79f"}.fa-glass-martini:before{content:"\f000"}.fa-glass-martini-alt:before{content:"\f57b"}.fa-glass-whiskey:before{content:"\f7a0"}.fa-glasses:before{content:"\f530"}.fa-glide:before{content:"\f2a5"}.fa-glide-g:before{content:"\f2a6"}.fa-globe:before{content:"\f0ac"}.fa-globe-africa:before{content:"\f57c"}.fa-globe-americas:before{content:"\f57d"}.fa-globe-asia:before{content:"\f57e"}.fa-globe-europe:before{content:"\f7a2"}.fa-gofore:before{content:"\f3a7"}.fa-golf-ball:before{content:"\f450"}.fa-goodreads:before{content:"\f3a8"}.fa-goodreads-g:before{content:"\f3a9"}.fa-google:before{content:"\f1a0"}.fa-google-drive:before{content:"\f3aa"}.fa-google-pay:before{content:"\e079"}.fa-google-play:before{content:"\f3ab"}.fa-google-plus:before{content:"\f2b3"}.fa-google-plus-g:before{content:"\f0d5"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-wallet:before{content:"\f1ee"}.fa-gopuram:before{content:"\f664"}.fa-graduation-cap:before{content:"\f19d"}.fa-gratipay:before{content:"\f184"}.fa-grav:before{content:"\f2d6"}.fa-greater-than:before{content:"\f531"}.fa-greater-than-equal:before{content:"\f532"}.fa-grimace:before{content:"\f57f"}.fa-grin:before{content:"\f580"}.fa-grin-alt:before{content:"\f581"}.fa-grin-beam:before{content:"\f582"}.fa-grin-beam-sweat:before{content:"\f583"}.fa-grin-hearts:before{content:"\f584"}.fa-grin-squint:before{content:"\f585"}.fa-grin-squint-tears:before{content:"\f586"}.fa-grin-stars:before{content:"\f587"}.fa-grin-tears:before{content:"\f588"}.fa-grin-tongue:before{content:"\f589"}.fa-grin-tongue-squint:before{content:"\f58a"}.fa-grin-tongue-wink:before{content:"\f58b"}.fa-grin-wink:before{content:"\f58c"}.fa-grip-horizontal:before{content:"\f58d"}.fa-grip-lines:before{content:"\f7a4"}.fa-grip-lines-vertical:before{content:"\f7a5"}.fa-grip-vertical:before{content:"\f58e"}.fa-gripfire:before{content:"\f3ac"}.fa-grunt:before{content:"\f3ad"}.fa-guilded:before{content:"\e07e"}.fa-guitar:before{content:"\f7a6"}.fa-gulp:before{content:"\f3ae"}.fa-h-square:before{content:"\f0fd"}.fa-hacker-news:before{content:"\f1d4"}.fa-hacker-news-square:before{content:"\f3af"}.fa-hackerrank:before{content:"\f5f7"}.fa-hamburger:before{content:"\f805"}.fa-hammer:before{content:"\f6e3"}.fa-hamsa:before{content:"\f665"}.fa-hand-holding:before{content:"\f4bd"}.fa-hand-holding-heart:before{content:"\f4be"}.fa-hand-holding-medical:before{content:"\e05c"}.fa-hand-holding-usd:before{content:"\f4c0"}.fa-hand-holding-water:before{content:"\f4c1"}.fa-hand-lizard:before{content:"\f258"}.fa-hand-middle-finger:before{content:"\f806"}.fa-hand-paper:before{content:"\f256"}.fa-hand-peace:before{content:"\f25b"}.fa-hand-point-down:before{content:"\f0a7"}.fa-hand-point-left:before{content:"\f0a5"}.fa-hand-point-right:before{content:"\f0a4"}.fa-hand-point-up:before{content:"\f0a6"}.fa-hand-pointer:before{content:"\f25a"}.fa-hand-rock:before{content:"\f255"}.fa-hand-scissors:before{content:"\f257"}.fa-hand-sparkles:before{content:"\e05d"}.fa-hand-spock:before{content:"\f259"}.fa-hands:before{content:"\f4c2"}.fa-hands-helping:before{content:"\f4c4"}.fa-hands-wash:before{content:"\e05e"}.fa-handshake:before{content:"\f2b5"}.fa-handshake-alt-slash:before{content:"\e05f"}.fa-handshake-slash:before{content:"\e060"}.fa-hanukiah:before{content:"\f6e6"}.fa-hard-hat:before{content:"\f807"}.fa-hashtag:before{content:"\f292"}.fa-hat-cowboy:before{content:"\f8c0"}.fa-hat-cowboy-side:before{content:"\f8c1"}.fa-hat-wizard:before{content:"\f6e8"}.fa-hdd:before{content:"\f0a0"}.fa-head-side-cough:before{content:"\e061"}.fa-head-side-cough-slash:before{content:"\e062"}.fa-head-side-mask:before{content:"\e063"}.fa-head-side-virus:before{content:"\e064"}.fa-heading:before{content:"\f1dc"}.fa-headphones:before{content:"\f025"}.fa-headphones-alt:before{content:"\f58f"}.fa-headset:before{content:"\f590"}.fa-heart:before{content:"\f004"}.fa-heart-broken:before{content:"\f7a9"}.fa-heartbeat:before{content:"\f21e"}.fa-helicopter:before{content:"\f533"}.fa-highlighter:before{content:"\f591"}.fa-hiking:before{content:"\f6ec"}.fa-hippo:before{content:"\f6ed"}.fa-hips:before{content:"\f452"}.fa-hire-a-helper:before{content:"\f3b0"}.fa-history:before{content:"\f1da"}.fa-hive:before{content:"\e07f"}.fa-hockey-puck:before{content:"\f453"}.fa-holly-berry:before{content:"\f7aa"}.fa-home:before{content:"\f015"}.fa-hooli:before{content:"\f427"}.fa-hornbill:before{content:"\f592"}.fa-horse:before{content:"\f6f0"}.fa-horse-head:before{content:"\f7ab"}.fa-hospital:before{content:"\f0f8"}.fa-hospital-alt:before{content:"\f47d"}.fa-hospital-symbol:before{content:"\f47e"}.fa-hospital-user:before{content:"\f80d"}.fa-hot-tub:before{content:"\f593"}.fa-hotdog:before{content:"\f80f"}.fa-hotel:before{content:"\f594"}.fa-hotjar:before{content:"\f3b1"}.fa-hourglass:before{content:"\f254"}.fa-hourglass-end:before{content:"\f253"}.fa-hourglass-half:before{content:"\f252"}.fa-hourglass-start:before{content:"\f251"}.fa-house-damage:before{content:"\f6f1"}.fa-house-user:before{content:"\e065"}.fa-houzz:before{content:"\f27c"}.fa-hryvnia:before{content:"\f6f2"}.fa-html5:before{content:"\f13b"}.fa-hubspot:before{content:"\f3b2"}.fa-i-cursor:before{content:"\f246"}.fa-ice-cream:before{content:"\f810"}.fa-icicles:before{content:"\f7ad"}.fa-icons:before{content:"\f86d"}.fa-id-badge:before{content:"\f2c1"}.fa-id-card:before{content:"\f2c2"}.fa-id-card-alt:before{content:"\f47f"}.fa-ideal:before{content:"\e013"}.fa-igloo:before{content:"\f7ae"}.fa-image:before{content:"\f03e"}.fa-images:before{content:"\f302"}.fa-imdb:before{content:"\f2d8"}.fa-inbox:before{content:"\f01c"}.fa-indent:before{content:"\f03c"}.fa-industry:before{content:"\f275"}.fa-infinity:before{content:"\f534"}.fa-info:before{content:"\f129"}.fa-info-circle:before{content:"\f05a"}.fa-innosoft:before{content:"\e080"}.fa-instagram:before{content:"\f16d"}.fa-instagram-square:before{content:"\e055"}.fa-instalod:before{content:"\e081"}.fa-intercom:before{content:"\f7af"}.fa-internet-explorer:before{content:"\f26b"}.fa-invision:before{content:"\f7b0"}.fa-ioxhost:before{content:"\f208"}.fa-italic:before{content:"\f033"}.fa-itch-io:before{content:"\f83a"}.fa-itunes:before{content:"\f3b4"}.fa-itunes-note:before{content:"\f3b5"}.fa-java:before{content:"\f4e4"}.fa-jedi:before{content:"\f669"}.fa-jedi-order:before{content:"\f50e"}.fa-jenkins:before{content:"\f3b6"}.fa-jira:before{content:"\f7b1"}.fa-joget:before{content:"\f3b7"}.fa-joint:before{content:"\f595"}.fa-joomla:before{content:"\f1aa"}.fa-journal-whills:before{content:"\f66a"}.fa-js:before{content:"\f3b8"}.fa-js-square:before{content:"\f3b9"}.fa-jsfiddle:before{content:"\f1cc"}.fa-kaaba:before{content:"\f66b"}.fa-kaggle:before{content:"\f5fa"}.fa-key:before{content:"\f084"}.fa-keybase:before{content:"\f4f5"}.fa-keyboard:before{content:"\f11c"}.fa-keycdn:before{content:"\f3ba"}.fa-khanda:before{content:"\f66d"}.fa-kickstarter:before{content:"\f3bb"}.fa-kickstarter-k:before{content:"\f3bc"}.fa-kiss:before{content:"\f596"}.fa-kiss-beam:before{content:"\f597"}.fa-kiss-wink-heart:before{content:"\f598"}.fa-kiwi-bird:before{content:"\f535"}.fa-korvue:before{content:"\f42f"}.fa-landmark:before{content:"\f66f"}.fa-language:before{content:"\f1ab"}.fa-laptop:before{content:"\f109"}.fa-laptop-code:before{content:"\f5fc"}.fa-laptop-house:before{content:"\e066"}.fa-laptop-medical:before{content:"\f812"}.fa-laravel:before{content:"\f3bd"}.fa-lastfm:before{content:"\f202"}.fa-lastfm-square:before{content:"\f203"}.fa-laugh:before{content:"\f599"}.fa-laugh-beam:before{content:"\f59a"}.fa-laugh-squint:before{content:"\f59b"}.fa-laugh-wink:before{content:"\f59c"}.fa-layer-group:before{content:"\f5fd"}.fa-leaf:before{content:"\f06c"}.fa-leanpub:before{content:"\f212"}.fa-lemon:before{content:"\f094"}.fa-less:before{content:"\f41d"}.fa-less-than:before{content:"\f536"}.fa-less-than-equal:before{content:"\f537"}.fa-level-down-alt:before{content:"\f3be"}.fa-level-up-alt:before{content:"\f3bf"}.fa-life-ring:before{content:"\f1cd"}.fa-lightbulb:before{content:"\f0eb"}.fa-line:before{content:"\f3c0"}.fa-link:before{content:"\f0c1"}.fa-linkedin:before{content:"\f08c"}.fa-linkedin-in:before{content:"\f0e1"}.fa-linode:before{content:"\f2b8"}.fa-linux:before{content:"\f17c"}.fa-lira-sign:before{content:"\f195"}.fa-list:before{content:"\f03a"}.fa-list-alt:before{content:"\f022"}.fa-list-ol:before{content:"\f0cb"}.fa-list-ul:before{content:"\f0ca"}.fa-location-arrow:before{content:"\f124"}.fa-lock:before{content:"\f023"}.fa-lock-open:before{content:"\f3c1"}.fa-long-arrow-alt-down:before{content:"\f309"}.fa-long-arrow-alt-left:before{content:"\f30a"}.fa-long-arrow-alt-right:before{content:"\f30b"}.fa-long-arrow-alt-up:before{content:"\f30c"}.fa-low-vision:before{content:"\f2a8"}.fa-luggage-cart:before{content:"\f59d"}.fa-lungs:before{content:"\f604"}.fa-lungs-virus:before{content:"\e067"}.fa-lyft:before{content:"\f3c3"}.fa-magento:before{content:"\f3c4"}.fa-magic:before{content:"\f0d0"}.fa-magnet:before{content:"\f076"}.fa-mail-bulk:before{content:"\f674"}.fa-mailchimp:before{content:"\f59e"}.fa-male:before{content:"\f183"}.fa-mandalorian:before{content:"\f50f"}.fa-map:before{content:"\f279"}.fa-map-marked:before{content:"\f59f"}.fa-map-marked-alt:before{content:"\f5a0"}.fa-map-marker:before{content:"\f041"}.fa-map-marker-alt:before{content:"\f3c5"}.fa-map-pin:before{content:"\f276"}.fa-map-signs:before{content:"\f277"}.fa-markdown:before{content:"\f60f"}.fa-marker:before{content:"\f5a1"}.fa-mars:before{content:"\f222"}.fa-mars-double:before{content:"\f227"}.fa-mars-stroke:before{content:"\f229"}.fa-mars-stroke-h:before{content:"\f22b"}.fa-mars-stroke-v:before{content:"\f22a"}.fa-mask:before{content:"\f6fa"}.fa-mastodon:before{content:"\f4f6"}.fa-maxcdn:before{content:"\f136"}.fa-mdb:before{content:"\f8ca"}.fa-medal:before{content:"\f5a2"}.fa-medapps:before{content:"\f3c6"}.fa-medium:before{content:"\f23a"}.fa-medium-m:before{content:"\f3c7"}.fa-medkit:before{content:"\f0fa"}.fa-medrt:before{content:"\f3c8"}.fa-meetup:before{content:"\f2e0"}.fa-megaport:before{content:"\f5a3"}.fa-meh:before{content:"\f11a"}.fa-meh-blank:before{content:"\f5a4"}.fa-meh-rolling-eyes:before{content:"\f5a5"}.fa-memory:before{content:"\f538"}.fa-mendeley:before{content:"\f7b3"}.fa-menorah:before{content:"\f676"}.fa-mercury:before{content:"\f223"}.fa-meteor:before{content:"\f753"}.fa-microblog:before{content:"\e01a"}.fa-microchip:before{content:"\f2db"}.fa-microphone:before{content:"\f130"}.fa-microphone-alt:before{content:"\f3c9"}.fa-microphone-alt-slash:before{content:"\f539"}.fa-microphone-slash:before{content:"\f131"}.fa-microscope:before{content:"\f610"}.fa-microsoft:before{content:"\f3ca"}.fa-minus:before{content:"\f068"}.fa-minus-circle:before{content:"\f056"}.fa-minus-square:before{content:"\f146"}.fa-mitten:before{content:"\f7b5"}.fa-mix:before{content:"\f3cb"}.fa-mixcloud:before{content:"\f289"}.fa-mixer:before{content:"\e056"}.fa-mizuni:before{content:"\f3cc"}.fa-mobile:before{content:"\f10b"}.fa-mobile-alt:before{content:"\f3cd"}.fa-modx:before{content:"\f285"}.fa-monero:before{content:"\f3d0"}.fa-money-bill:before{content:"\f0d6"}.fa-money-bill-alt:before{content:"\f3d1"}.fa-money-bill-wave:before{content:"\f53a"}.fa-money-bill-wave-alt:before{content:"\f53b"}.fa-money-check:before{content:"\f53c"}.fa-money-check-alt:before{content:"\f53d"}.fa-monument:before{content:"\f5a6"}.fa-moon:before{content:"\f186"}.fa-mortar-pestle:before{content:"\f5a7"}.fa-mosque:before{content:"\f678"}.fa-motorcycle:before{content:"\f21c"}.fa-mountain:before{content:"\f6fc"}.fa-mouse:before{content:"\f8cc"}.fa-mouse-pointer:before{content:"\f245"}.fa-mug-hot:before{content:"\f7b6"}.fa-music:before{content:"\f001"}.fa-napster:before{content:"\f3d2"}.fa-neos:before{content:"\f612"}.fa-network-wired:before{content:"\f6ff"}.fa-neuter:before{content:"\f22c"}.fa-newspaper:before{content:"\f1ea"}.fa-nimblr:before{content:"\f5a8"}.fa-node:before{content:"\f419"}.fa-node-js:before{content:"\f3d3"}.fa-not-equal:before{content:"\f53e"}.fa-notes-medical:before{content:"\f481"}.fa-npm:before{content:"\f3d4"}.fa-ns8:before{content:"\f3d5"}.fa-nutritionix:before{content:"\f3d6"}.fa-object-group:before{content:"\f247"}.fa-object-ungroup:before{content:"\f248"}.fa-octopus-deploy:before{content:"\e082"}.fa-odnoklassniki:before{content:"\f263"}.fa-odnoklassniki-square:before{content:"\f264"}.fa-oil-can:before{content:"\f613"}.fa-old-republic:before{content:"\f510"}.fa-om:before{content:"\f679"}.fa-opencart:before{content:"\f23d"}.fa-openid:before{content:"\f19b"}.fa-opera:before{content:"\f26a"}.fa-optin-monster:before{content:"\f23c"}.fa-orcid:before{content:"\f8d2"}.fa-osi:before{content:"\f41a"}.fa-otter:before{content:"\f700"}.fa-outdent:before{content:"\f03b"}.fa-page4:before{content:"\f3d7"}.fa-pagelines:before{content:"\f18c"}.fa-pager:before{content:"\f815"}.fa-paint-brush:before{content:"\f1fc"}.fa-paint-roller:before{content:"\f5aa"}.fa-palette:before{content:"\f53f"}.fa-palfed:before{content:"\f3d8"}.fa-pallet:before{content:"\f482"}.fa-paper-plane:before{content:"\f1d8"}.fa-paperclip:before{content:"\f0c6"}.fa-parachute-box:before{content:"\f4cd"}.fa-paragraph:before{content:"\f1dd"}.fa-parking:before{content:"\f540"}.fa-passport:before{content:"\f5ab"}.fa-pastafarianism:before{content:"\f67b"}.fa-paste:before{content:"\f0ea"}.fa-patreon:before{content:"\f3d9"}.fa-pause:before{content:"\f04c"}.fa-pause-circle:before{content:"\f28b"}.fa-paw:before{content:"\f1b0"}.fa-paypal:before{content:"\f1ed"}.fa-peace:before{content:"\f67c"}.fa-pen:before{content:"\f304"}.fa-pen-alt:before{content:"\f305"}.fa-pen-fancy:before{content:"\f5ac"}.fa-pen-nib:before{content:"\f5ad"}.fa-pen-square:before{content:"\f14b"}.fa-pencil-alt:before{content:"\f303"}.fa-pencil-ruler:before{content:"\f5ae"}.fa-penny-arcade:before{content:"\f704"}.fa-people-arrows:before{content:"\e068"}.fa-people-carry:before{content:"\f4ce"}.fa-pepper-hot:before{content:"\f816"}.fa-perbyte:before{content:"\e083"}.fa-percent:before{content:"\f295"}.fa-percentage:before{content:"\f541"}.fa-periscope:before{content:"\f3da"}.fa-person-booth:before{content:"\f756"}.fa-phabricator:before{content:"\f3db"}.fa-phoenix-framework:before{content:"\f3dc"}.fa-phoenix-squadron:before{content:"\f511"}.fa-phone:before{content:"\f095"}.fa-phone-alt:before{content:"\f879"}.fa-phone-slash:before{content:"\f3dd"}.fa-phone-square:before{content:"\f098"}.fa-phone-square-alt:before{content:"\f87b"}.fa-phone-volume:before{content:"\f2a0"}.fa-photo-video:before{content:"\f87c"}.fa-php:before{content:"\f457"}.fa-pied-piper:before{content:"\f2ae"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-pied-piper-hat:before{content:"\f4e5"}.fa-pied-piper-pp:before{content:"\f1a7"}.fa-pied-piper-square:before{content:"\e01e"}.fa-piggy-bank:before{content:"\f4d3"}.fa-pills:before{content:"\f484"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-p:before{content:"\f231"}.fa-pinterest-square:before{content:"\f0d3"}.fa-pizza-slice:before{content:"\f818"}.fa-place-of-worship:before{content:"\f67f"}.fa-plane:before{content:"\f072"}.fa-plane-arrival:before{content:"\f5af"}.fa-plane-departure:before{content:"\f5b0"}.fa-plane-slash:before{content:"\e069"}.fa-play:before{content:"\f04b"}.fa-play-circle:before{content:"\f144"}.fa-playstation:before{content:"\f3df"}.fa-plug:before{content:"\f1e6"}.fa-plus:before{content:"\f067"}.fa-plus-circle:before{content:"\f055"}.fa-plus-square:before{content:"\f0fe"}.fa-podcast:before{content:"\f2ce"}.fa-poll:before{content:"\f681"}.fa-poll-h:before{content:"\f682"}.fa-poo:before{content:"\f2fe"}.fa-poo-storm:before{content:"\f75a"}.fa-poop:before{content:"\f619"}.fa-portrait:before{content:"\f3e0"}.fa-pound-sign:before{content:"\f154"}.fa-power-off:before{content:"\f011"}.fa-pray:before{content:"\f683"}.fa-praying-hands:before{content:"\f684"}.fa-prescription:before{content:"\f5b1"}.fa-prescription-bottle:before{content:"\f485"}.fa-prescription-bottle-alt:before{content:"\f486"}.fa-print:before{content:"\f02f"}.fa-procedures:before{content:"\f487"}.fa-product-hunt:before{content:"\f288"}.fa-project-diagram:before{content:"\f542"}.fa-pump-medical:before{content:"\e06a"}.fa-pump-soap:before{content:"\e06b"}.fa-pushed:before{content:"\f3e1"}.fa-puzzle-piece:before{content:"\f12e"}.fa-python:before{content:"\f3e2"}.fa-qq:before{content:"\f1d6"}.fa-qrcode:before{content:"\f029"}.fa-question:before{content:"\f128"}.fa-question-circle:before{content:"\f059"}.fa-quidditch:before{content:"\f458"}.fa-quinscape:before{content:"\f459"}.fa-quora:before{content:"\f2c4"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-quran:before{content:"\f687"}.fa-r-project:before{content:"\f4f7"}.fa-radiation:before{content:"\f7b9"}.fa-radiation-alt:before{content:"\f7ba"}.fa-rainbow:before{content:"\f75b"}.fa-random:before{content:"\f074"}.fa-raspberry-pi:before{content:"\f7bb"}.fa-ravelry:before{content:"\f2d9"}.fa-react:before{content:"\f41b"}.fa-reacteurope:before{content:"\f75d"}.fa-readme:before{content:"\f4d5"}.fa-rebel:before{content:"\f1d0"}.fa-receipt:before{content:"\f543"}.fa-record-vinyl:before{content:"\f8d9"}.fa-recycle:before{content:"\f1b8"}.fa-red-river:before{content:"\f3e3"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-alien:before{content:"\f281"}.fa-reddit-square:before{content:"\f1a2"}.fa-redhat:before{content:"\f7bc"}.fa-redo:before{content:"\f01e"}.fa-redo-alt:before{content:"\f2f9"}.fa-registered:before{content:"\f25d"}.fa-remove-format:before{content:"\f87d"}.fa-renren:before{content:"\f18b"}.fa-reply:before{content:"\f3e5"}.fa-reply-all:before{content:"\f122"}.fa-replyd:before{content:"\f3e6"}.fa-republican:before{content:"\f75e"}.fa-researchgate:before{content:"\f4f8"}.fa-resolving:before{content:"\f3e7"}.fa-restroom:before{content:"\f7bd"}.fa-retweet:before{content:"\f079"}.fa-rev:before{content:"\f5b2"}.fa-ribbon:before{content:"\f4d6"}.fa-ring:before{content:"\f70b"}.fa-road:before{content:"\f018"}.fa-robot:before{content:"\f544"}.fa-rocket:before{content:"\f135"}.fa-rocketchat:before{content:"\f3e8"}.fa-rockrms:before{content:"\f3e9"}.fa-route:before{content:"\f4d7"}.fa-rss:before{content:"\f09e"}.fa-rss-square:before{content:"\f143"}.fa-ruble-sign:before{content:"\f158"}.fa-ruler:before{content:"\f545"}.fa-ruler-combined:before{content:"\f546"}.fa-ruler-horizontal:before{content:"\f547"}.fa-ruler-vertical:before{content:"\f548"}.fa-running:before{content:"\f70c"}.fa-rupee-sign:before{content:"\f156"}.fa-rust:before{content:"\e07a"}.fa-sad-cry:before{content:"\f5b3"}.fa-sad-tear:before{content:"\f5b4"}.fa-safari:before{content:"\f267"}.fa-salesforce:before{content:"\f83b"}.fa-sass:before{content:"\f41e"}.fa-satellite:before{content:"\f7bf"}.fa-satellite-dish:before{content:"\f7c0"}.fa-save:before{content:"\f0c7"}.fa-schlix:before{content:"\f3ea"}.fa-school:before{content:"\f549"}.fa-screwdriver:before{content:"\f54a"}.fa-scribd:before{content:"\f28a"}.fa-scroll:before{content:"\f70e"}.fa-sd-card:before{content:"\f7c2"}.fa-search:before{content:"\f002"}.fa-search-dollar:before{content:"\f688"}.fa-search-location:before{content:"\f689"}.fa-search-minus:before{content:"\f010"}.fa-search-plus:before{content:"\f00e"}.fa-searchengin:before{content:"\f3eb"}.fa-seedling:before{content:"\f4d8"}.fa-sellcast:before{content:"\f2da"}.fa-sellsy:before{content:"\f213"}.fa-server:before{content:"\f233"}.fa-servicestack:before{content:"\f3ec"}.fa-shapes:before{content:"\f61f"}.fa-share:before{content:"\f064"}.fa-share-alt:before{content:"\f1e0"}.fa-share-alt-square:before{content:"\f1e1"}.fa-share-square:before{content:"\f14d"}.fa-shekel-sign:before{content:"\f20b"}.fa-shield-alt:before{content:"\f3ed"}.fa-shield-virus:before{content:"\e06c"}.fa-ship:before{content:"\f21a"}.fa-shipping-fast:before{content:"\f48b"}.fa-shirtsinbulk:before{content:"\f214"}.fa-shoe-prints:before{content:"\f54b"}.fa-shopify:before{content:"\e057"}.fa-shopping-bag:before{content:"\f290"}.fa-shopping-basket:before{content:"\f291"}.fa-shopping-cart:before{content:"\f07a"}.fa-shopware:before{content:"\f5b5"}.fa-shower:before{content:"\f2cc"}.fa-shuttle-van:before{content:"\f5b6"}.fa-sign:before{content:"\f4d9"}.fa-sign-in-alt:before{content:"\f2f6"}.fa-sign-language:before{content:"\f2a7"}.fa-sign-out-alt:before{content:"\f2f5"}.fa-signal:before{content:"\f012"}.fa-signature:before{content:"\f5b7"}.fa-sim-card:before{content:"\f7c4"}.fa-simplybuilt:before{content:"\f215"}.fa-sink:before{content:"\e06d"}.fa-sistrix:before{content:"\f3ee"}.fa-sitemap:before{content:"\f0e8"}.fa-sith:before{content:"\f512"}.fa-skating:before{content:"\f7c5"}.fa-sketch:before{content:"\f7c6"}.fa-skiing:before{content:"\f7c9"}.fa-skiing-nordic:before{content:"\f7ca"}.fa-skull:before{content:"\f54c"}.fa-skull-crossbones:before{content:"\f714"}.fa-skyatlas:before{content:"\f216"}.fa-skype:before{content:"\f17e"}.fa-slack:before{content:"\f198"}.fa-slack-hash:before{content:"\f3ef"}.fa-slash:before{content:"\f715"}.fa-sleigh:before{content:"\f7cc"}.fa-sliders-h:before{content:"\f1de"}.fa-slideshare:before{content:"\f1e7"}.fa-smile:before{content:"\f118"}.fa-smile-beam:before{content:"\f5b8"}.fa-smile-wink:before{content:"\f4da"}.fa-smog:before{content:"\f75f"}.fa-smoking:before{content:"\f48d"}.fa-smoking-ban:before{content:"\f54d"}.fa-sms:before{content:"\f7cd"}.fa-snapchat:before{content:"\f2ab"}.fa-snapchat-ghost:before{content:"\f2ac"}.fa-snapchat-square:before{content:"\f2ad"}.fa-snowboarding:before{content:"\f7ce"}.fa-snowflake:before{content:"\f2dc"}.fa-snowman:before{content:"\f7d0"}.fa-snowplow:before{content:"\f7d2"}.fa-soap:before{content:"\e06e"}.fa-socks:before{content:"\f696"}.fa-solar-panel:before{content:"\f5ba"}.fa-sort:before{content:"\f0dc"}.fa-sort-alpha-down:before{content:"\f15d"}.fa-sort-alpha-down-alt:before{content:"\f881"}.fa-sort-alpha-up:before{content:"\f15e"}.fa-sort-alpha-up-alt:before{content:"\f882"}.fa-sort-amount-down:before{content:"\f160"}.fa-sort-amount-down-alt:before{content:"\f884"}.fa-sort-amount-up:before{content:"\f161"}.fa-sort-amount-up-alt:before{content:"\f885"}.fa-sort-down:before{content:"\f0dd"}.fa-sort-numeric-down:before{content:"\f162"}.fa-sort-numeric-down-alt:before{content:"\f886"}.fa-sort-numeric-up:before{content:"\f163"}.fa-sort-numeric-up-alt:before{content:"\f887"}.fa-sort-up:before{content:"\f0de"}.fa-soundcloud:before{content:"\f1be"}.fa-sourcetree:before{content:"\f7d3"}.fa-spa:before{content:"\f5bb"}.fa-space-shuttle:before{content:"\f197"}.fa-speakap:before{content:"\f3f3"}.fa-speaker-deck:before{content:"\f83c"}.fa-spell-check:before{content:"\f891"}.fa-spider:before{content:"\f717"}.fa-spinner:before{content:"\f110"}.fa-splotch:before{content:"\f5bc"}.fa-spotify:before{content:"\f1bc"}.fa-spray-can:before{content:"\f5bd"}.fa-square:before{content:"\f0c8"}.fa-square-full:before{content:"\f45c"}.fa-square-root-alt:before{content:"\f698"}.fa-squarespace:before{content:"\f5be"}.fa-stack-exchange:before{content:"\f18d"}.fa-stack-overflow:before{content:"\f16c"}.fa-stackpath:before{content:"\f842"}.fa-stamp:before{content:"\f5bf"}.fa-star:before{content:"\f005"}.fa-star-and-crescent:before{content:"\f699"}.fa-star-half:before{content:"\f089"}.fa-star-half-alt:before{content:"\f5c0"}.fa-star-of-david:before{content:"\f69a"}.fa-star-of-life:before{content:"\f621"}.fa-staylinked:before{content:"\f3f5"}.fa-steam:before{content:"\f1b6"}.fa-steam-square:before{content:"\f1b7"}.fa-steam-symbol:before{content:"\f3f6"}.fa-step-backward:before{content:"\f048"}.fa-step-forward:before{content:"\f051"}.fa-stethoscope:before{content:"\f0f1"}.fa-sticker-mule:before{content:"\f3f7"}.fa-sticky-note:before{content:"\f249"}.fa-stop:before{content:"\f04d"}.fa-stop-circle:before{content:"\f28d"}.fa-stopwatch:before{content:"\f2f2"}.fa-stopwatch-20:before{content:"\e06f"}.fa-store:before{content:"\f54e"}.fa-store-alt:before{content:"\f54f"}.fa-store-alt-slash:before{content:"\e070"}.fa-store-slash:before{content:"\e071"}.fa-strava:before{content:"\f428"}.fa-stream:before{content:"\f550"}.fa-street-view:before{content:"\f21d"}.fa-strikethrough:before{content:"\f0cc"}.fa-stripe:before{content:"\f429"}.fa-stripe-s:before{content:"\f42a"}.fa-stroopwafel:before{content:"\f551"}.fa-studiovinari:before{content:"\f3f8"}.fa-stumbleupon:before{content:"\f1a4"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-subscript:before{content:"\f12c"}.fa-subway:before{content:"\f239"}.fa-suitcase:before{content:"\f0f2"}.fa-suitcase-rolling:before{content:"\f5c1"}.fa-sun:before{content:"\f185"}.fa-superpowers:before{content:"\f2dd"}.fa-superscript:before{content:"\f12b"}.fa-supple:before{content:"\f3f9"}.fa-surprise:before{content:"\f5c2"}.fa-suse:before{content:"\f7d6"}.fa-swatchbook:before{content:"\f5c3"}.fa-swift:before{content:"\f8e1"}.fa-swimmer:before{content:"\f5c4"}.fa-swimming-pool:before{content:"\f5c5"}.fa-symfony:before{content:"\f83d"}.fa-synagogue:before{content:"\f69b"}.fa-sync:before{content:"\f021"}.fa-sync-alt:before{content:"\f2f1"}.fa-syringe:before{content:"\f48e"}.fa-table:before{content:"\f0ce"}.fa-table-tennis:before{content:"\f45d"}.fa-tablet:before{content:"\f10a"}.fa-tablet-alt:before{content:"\f3fa"}.fa-tablets:before{content:"\f490"}.fa-tachometer-alt:before{content:"\f3fd"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-tape:before{content:"\f4db"}.fa-tasks:before{content:"\f0ae"}.fa-taxi:before{content:"\f1ba"}.fa-teamspeak:before{content:"\f4f9"}.fa-teeth:before{content:"\f62e"}.fa-teeth-open:before{content:"\f62f"}.fa-telegram:before{content:"\f2c6"}.fa-telegram-plane:before{content:"\f3fe"}.fa-temperature-high:before{content:"\f769"}.fa-temperature-low:before{content:"\f76b"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-tenge:before{content:"\f7d7"}.fa-terminal:before{content:"\f120"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-th:before{content:"\f00a"}.fa-th-large:before{content:"\f009"}.fa-th-list:before{content:"\f00b"}.fa-the-red-yeti:before{content:"\f69d"}.fa-theater-masks:before{content:"\f630"}.fa-themeco:before{content:"\f5c6"}.fa-themeisle:before{content:"\f2b2"}.fa-thermometer:before{content:"\f491"}.fa-thermometer-empty:before{content:"\f2cb"}.fa-thermometer-full:before{content:"\f2c7"}.fa-thermometer-half:before{content:"\f2c9"}.fa-thermometer-quarter:before{content:"\f2ca"}.fa-thermometer-three-quarters:before{content:"\f2c8"}.fa-think-peaks:before{content:"\f731"}.fa-thumbs-down:before{content:"\f165"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbtack:before{content:"\f08d"}.fa-ticket-alt:before{content:"\f3ff"}.fa-tiktok:before{content:"\e07b"}.fa-times:before{content:"\f00d"}.fa-times-circle:before{content:"\f057"}.fa-tint:before{content:"\f043"}.fa-tint-slash:before{content:"\f5c7"}.fa-tired:before{content:"\f5c8"}.fa-toggle-off:before{content:"\f204"}.fa-toggle-on:before{content:"\f205"}.fa-toilet:before{content:"\f7d8"}.fa-toilet-paper:before{content:"\f71e"}.fa-toilet-paper-slash:before{content:"\e072"}.fa-toolbox:before{content:"\f552"}.fa-tools:before{content:"\f7d9"}.fa-tooth:before{content:"\f5c9"}.fa-torah:before{content:"\f6a0"}.fa-torii-gate:before{content:"\f6a1"}.fa-tractor:before{content:"\f722"}.fa-trade-federation:before{content:"\f513"}.fa-trademark:before{content:"\f25c"}.fa-traffic-light:before{content:"\f637"}.fa-trailer:before{content:"\e041"}.fa-train:before{content:"\f238"}.fa-tram:before{content:"\f7da"}.fa-transgender:before{content:"\f224"}.fa-transgender-alt:before{content:"\f225"}.fa-trash:before{content:"\f1f8"}.fa-trash-alt:before{content:"\f2ed"}.fa-trash-restore:before{content:"\f829"}.fa-trash-restore-alt:before{content:"\f82a"}.fa-tree:before{content:"\f1bb"}.fa-trello:before{content:"\f181"}.fa-trophy:before{content:"\f091"}.fa-truck:before{content:"\f0d1"}.fa-truck-loading:before{content:"\f4de"}.fa-truck-monster:before{content:"\f63b"}.fa-truck-moving:before{content:"\f4df"}.fa-truck-pickup:before{content:"\f63c"}.fa-tshirt:before{content:"\f553"}.fa-tty:before{content:"\f1e4"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-tv:before{content:"\f26c"}.fa-twitch:before{content:"\f1e8"}.fa-twitter:before{content:"\f099"}.fa-twitter-square:before{content:"\f081"}.fa-typo3:before{content:"\f42b"}.fa-uber:before{content:"\f402"}.fa-ubuntu:before{content:"\f7df"}.fa-uikit:before{content:"\f403"}.fa-umbraco:before{content:"\f8e8"}.fa-umbrella:before{content:"\f0e9"}.fa-umbrella-beach:before{content:"\f5ca"}.fa-uncharted:before{content:"\e084"}.fa-underline:before{content:"\f0cd"}.fa-undo:before{content:"\f0e2"}.fa-undo-alt:before{content:"\f2ea"}.fa-uniregistry:before{content:"\f404"}.fa-unity:before{content:"\e049"}.fa-universal-access:before{content:"\f29a"}.fa-university:before{content:"\f19c"}.fa-unlink:before{content:"\f127"}.fa-unlock:before{content:"\f09c"}.fa-unlock-alt:before{content:"\f13e"}.fa-unsplash:before{content:"\e07c"}.fa-untappd:before{content:"\f405"}.fa-upload:before{content:"\f093"}.fa-ups:before{content:"\f7e0"}.fa-usb:before{content:"\f287"}.fa-user:before{content:"\f007"}.fa-user-alt:before{content:"\f406"}.fa-user-alt-slash:before{content:"\f4fa"}.fa-user-astronaut:before{content:"\f4fb"}.fa-user-check:before{content:"\f4fc"}.fa-user-circle:before{content:"\f2bd"}.fa-user-clock:before{content:"\f4fd"}.fa-user-cog:before{content:"\f4fe"}.fa-user-edit:before{content:"\f4ff"}.fa-user-friends:before{content:"\f500"}.fa-user-graduate:before{content:"\f501"}.fa-user-injured:before{content:"\f728"}.fa-user-lock:before{content:"\f502"}.fa-user-md:before{content:"\f0f0"}.fa-user-minus:before{content:"\f503"}.fa-user-ninja:before{content:"\f504"}.fa-user-nurse:before{content:"\f82f"}.fa-user-plus:before{content:"\f234"}.fa-user-secret:before{content:"\f21b"}.fa-user-shield:before{content:"\f505"}.fa-user-slash:before{content:"\f506"}.fa-user-tag:before{content:"\f507"}.fa-user-tie:before{content:"\f508"}.fa-user-times:before{content:"\f235"}.fa-users:before{content:"\f0c0"}.fa-users-cog:before{content:"\f509"}.fa-users-slash:before{content:"\e073"}.fa-usps:before{content:"\f7e1"}.fa-ussunnah:before{content:"\f407"}.fa-utensil-spoon:before{content:"\f2e5"}.fa-utensils:before{content:"\f2e7"}.fa-vaadin:before{content:"\f408"}.fa-vector-square:before{content:"\f5cb"}.fa-venus:before{content:"\f221"}.fa-venus-double:before{content:"\f226"}.fa-venus-mars:before{content:"\f228"}.fa-vest:before{content:"\e085"}.fa-vest-patches:before{content:"\e086"}.fa-viacoin:before{content:"\f237"}.fa-viadeo:before{content:"\f2a9"}.fa-viadeo-square:before{content:"\f2aa"}.fa-vial:before{content:"\f492"}.fa-vials:before{content:"\f493"}.fa-viber:before{content:"\f409"}.fa-video:before{content:"\f03d"}.fa-video-slash:before{content:"\f4e2"}.fa-vihara:before{content:"\f6a7"}.fa-vimeo:before{content:"\f40a"}.fa-vimeo-square:before{content:"\f194"}.fa-vimeo-v:before{content:"\f27d"}.fa-vine:before{content:"\f1ca"}.fa-virus:before{content:"\e074"}.fa-virus-slash:before{content:"\e075"}.fa-viruses:before{content:"\e076"}.fa-vk:before{content:"\f189"}.fa-vnv:before{content:"\f40b"}.fa-voicemail:before{content:"\f897"}.fa-volleyball-ball:before{content:"\f45f"}.fa-volume-down:before{content:"\f027"}.fa-volume-mute:before{content:"\f6a9"}.fa-volume-off:before{content:"\f026"}.fa-volume-up:before{content:"\f028"}.fa-vote-yea:before{content:"\f772"}.fa-vr-cardboard:before{content:"\f729"}.fa-vuejs:before{content:"\f41f"}.fa-walking:before{content:"\f554"}.fa-wallet:before{content:"\f555"}.fa-warehouse:before{content:"\f494"}.fa-watchman-monitoring:before{content:"\e087"}.fa-water:before{content:"\f773"}.fa-wave-square:before{content:"\f83e"}.fa-waze:before{content:"\f83f"}.fa-weebly:before{content:"\f5cc"}.fa-weibo:before{content:"\f18a"}.fa-weight:before{content:"\f496"}.fa-weight-hanging:before{content:"\f5cd"}.fa-weixin:before{content:"\f1d7"}.fa-whatsapp:before{content:"\f232"}.fa-whatsapp-square:before{content:"\f40c"}.fa-wheelchair:before{content:"\f193"}.fa-whmcs:before{content:"\f40d"}.fa-wifi:before{content:"\f1eb"}.fa-wikipedia-w:before{content:"\f266"}.fa-wind:before{content:"\f72e"}.fa-window-close:before{content:"\f410"}.fa-window-maximize:before{content:"\f2d0"}.fa-window-minimize:before{content:"\f2d1"}.fa-window-restore:before{content:"\f2d2"}.fa-windows:before{content:"\f17a"}.fa-wine-bottle:before{content:"\f72f"}.fa-wine-glass:before{content:"\f4e3"}.fa-wine-glass-alt:before{content:"\f5ce"}.fa-wix:before{content:"\f5cf"}.fa-wizards-of-the-coast:before{content:"\f730"}.fa-wodu:before{content:"\e088"}.fa-wolf-pack-battalion:before{content:"\f514"}.fa-won-sign:before{content:"\f159"}.fa-wordpress:before{content:"\f19a"}.fa-wordpress-simple:before{content:"\f411"}.fa-wpbeginner:before{content:"\f297"}.fa-wpexplorer:before{content:"\f2de"}.fa-wpforms:before{content:"\f298"}.fa-wpressr:before{content:"\f3e4"}.fa-wrench:before{content:"\f0ad"}.fa-x-ray:before{content:"\f497"}.fa-xbox:before{content:"\f412"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-y-combinator:before{content:"\f23b"}.fa-yahoo:before{content:"\f19e"}.fa-yammer:before{content:"\f840"}.fa-yandex:before{content:"\f413"}.fa-yandex-international:before{content:"\f414"}.fa-yarn:before{content:"\f7e3"}.fa-yelp:before{content:"\f1e9"}.fa-yen-sign:before{content:"\f157"}.fa-yin-yang:before{content:"\f6ad"}.fa-yoast:before{content:"\f2b1"}.fa-youtube:before{content:"\f167"}.fa-youtube-square:before{content:"\f431"}.fa-zhihu:before{content:"\f63f"}.sr-only{border:0;clip:rect(0,0,0,0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.sr-only-focusable:active,.sr-only-focusable:focus{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto}@font-face{font-family:"Font Awesome 5 Brands";font-style:normal;font-weight:400;font-display:block;src:url(../webfonts/fa-brands-400.eot);src:url(../webfonts/fa-brands-400.eot?#iefix) format("embedded-opentype"),url(../webfonts/fa-brands-400.woff2) format("woff2"),url(../webfonts/fa-brands-400.woff) format("woff"),url(../webfonts/fa-brands-400.ttf) format("truetype"),url(../webfonts/fa-brands-400.svg#fontawesome) format("svg")}.fab{font-family:"Font Awesome 5 Brands"}@font-face{font-family:"Font Awesome 5 Free";font-style:normal;font-weight:400;font-display:block;src:url(../webfonts/fa-regular-400.eot);src:url(../webfonts/fa-regular-400.eot?#iefix) format("embedded-opentype"),url(../webfonts/fa-regular-400.woff2) format("woff2"),url(../webfonts/fa-regular-400.woff) format("woff"),url(../webfonts/fa-regular-400.ttf) format("truetype"),url(../webfonts/fa-regular-400.svg#fontawesome) format("svg")}.fab,.far{font-weight:400}@font-face{font-family:"Font Awesome 5 Free";font-style:normal;font-weight:900;font-display:block;src:url(../webfonts/fa-solid-900.eot);src:url(../webfonts/fa-solid-900.eot?#iefix) format("embedded-opentype"),url(../webfonts/fa-solid-900.woff2) format("woff2"),url(../webfonts/fa-solid-900.woff) format("woff"),url(../webfonts/fa-solid-900.ttf) format("truetype"),url(../webfonts/fa-solid-900.svg#fontawesome) format("svg")}.fa,.far,.fas{font-family:"Font Awesome 5 Free"}.fa,.fas{font-weight:900} diff --git a/v0.10.x/_static/vendor/features.css b/v0.10.x/_static/vendor/features.css new file mode 100644 index 000000000..79354e7db --- /dev/null +++ b/v0.10.x/_static/vendor/features.css @@ -0,0 +1,135 @@ +.wrapper:before, +.wrapper:after { + content: ""; + display: table; +} +.wrapper:after { + clear: both; +} +@media screen { + .feature-wrapper { + max-width: 1200px; + margin: 0 auto; + } +} + +#intro-feature-list { + /* padding-top: 20px; */ + display: -webkit-box; + display: -moz-box; + display: -webkit-flex; + display: -ms-flexbox; + display: box; + display: flex; + -webkit-box-orient: vertical; + -moz-box-orient: vertical; + -webkit-flex-flow: column; + -ms-flex-flow: column; + flex-flow: column; + justify-content: center; + align-items: center; + } + @media screen and (min-width: 769px) { + #intro-feature-list { + -webkit-box-orient: horizontal; + -moz-box-orient: horizontal; + -webkit-box-lines: multiple; + -moz-box-lines: multiple; + -webkit-flex-flow: row wrap; + -ms-flex-flow: row wrap; + flex-flow: row wrap; + } + } + .intro-feature-wrap { + /* padding-top: 20px; */ + } + @media screen and (min-width: 769px) { + .intro-feature-wrap { + -webkit-box-flex: 1; + -moz-box-flex: 1; + box-flex: 1; + -webkit-flex: 0 0 50%; + -ms-flex: 0 0 50%; + flex: 0 0 50%; + padding-top: 10px; + } + } + .intro-feature { + position: relative; + text-align: center; + } + @media screen and (min-width: 769px) { + .intro-feature { + text-align: left; + padding-left: 70px; + } + } + .intro-feature-icon { + color: #01426A; /*#0e83cd;*/; + font-size: 36px; + padding-bottom: 26px; + text-align: center; + } + @media screen and (min-width: 769px) { + .intro-feature-icon { + position: absolute; + top: 0; + left: 20px; + font-size: 24px; + width: 24px; + } + } + .intro-feature-title { + color: #01426A; /*#0e83cd;*/; + font-family: Lato, "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 24px; + } + .intro-feature-desc { + margin: 1.6em 0; + line-height: 1.6em; + } + #intro-cmd-wrap { + max-width: 700px; + background: #eee; + padding: 15px 0; + margin: 25px -20px 0; + } + @media screen and (min-width: 769px) { + #intro-cmd-wrap { + margin: 50px auto 0; + } + } + .intro-cmd-item { + font-size: 16px; + font-family: "Source Code Pro", Monaco, Menlo, Consolas, monospace; + line-height: 2; + padding: 0 30px; + } + .intro-cmd-item:before { + content: "$"; + color: #01426A; /*#0e83cd;*/; + padding-right: 15px; + } + #intro-get-started-wrap { + text-align: center; + } + #intro-get-started-link { + font-size: 18px; + font-family: Lato, "Helvetica Neue", Helvetica, Arial, sans-serif; + display: inline-block; + color: #01426A; /*#0e83cd;*/ + text-decoration: none; + margin: 40px 0; + border: 3px solid; + border-color: #006298; /* #25a1f0;*/ + padding: 12px 24px; + position: relative; + -webkit-transition: 0.2s; + -moz-transition: 0.2s; + -ms-transition: 0.2s; + transition: 0.2s; + } + #intro-get-started-link:hover { + background: #006298; /* #25a1f0;*/; + color: #fff; + } diff --git a/v0.10.x/_static/vendor/fontawesome/6.1.2/LICENSE.txt b/v0.10.x/_static/vendor/fontawesome/6.1.2/LICENSE.txt new file mode 100644 index 000000000..cc557ece4 --- /dev/null +++ b/v0.10.x/_static/vendor/fontawesome/6.1.2/LICENSE.txt @@ -0,0 +1,165 @@ +Fonticons, Inc. (https://fontawesome.com) + +-------------------------------------------------------------------------------- + +Font Awesome Free License + +Font Awesome Free is free, open source, and GPL friendly. You can use it for +commercial projects, open source projects, or really almost whatever you want. +Full Font Awesome Free license: https://fontawesome.com/license/free. + +-------------------------------------------------------------------------------- + +# Icons: CC BY 4.0 License (https://creativecommons.org/licenses/by/4.0/) + +The Font Awesome Free download is licensed under a Creative Commons +Attribution 4.0 International License and applies to all icons packaged +as SVG and JS file types. + +-------------------------------------------------------------------------------- + +# Fonts: SIL OFL 1.1 License + +In the Font Awesome Free download, the SIL OFL license applies to all icons +packaged as web and desktop font files. + +Copyright (c) 2022 Fonticons, Inc. (https://fontawesome.com) +with Reserved Font Name: "Font Awesome". + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + +SIL OPEN FONT LICENSE +Version 1.1 - 26 February 2007 + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting — in part or in whole — any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. + +-------------------------------------------------------------------------------- + +# Code: MIT License (https://opensource.org/licenses/MIT) + +In the Font Awesome Free download, the MIT license applies to all non-font and +non-icon files. + +Copyright 2022 Fonticons, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in the +Software without restriction, including without limitation the rights to use, copy, +modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, +and to permit persons to whom the Software is furnished to do so, subject to the +following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +-------------------------------------------------------------------------------- + +# Attribution + +Attribution is required by MIT, SIL OFL, and CC BY licenses. Downloaded Font +Awesome Free files already contain embedded comments with sufficient +attribution, so you shouldn't need to do anything additional when using these +files normally. + +We've kept attribution comments terse, so we ask that you do not actively work +to remove them from files, especially code. They're a great way for folks to +learn about Font Awesome. + +-------------------------------------------------------------------------------- + +# Brand Icons + +All brand icons are trademarks of their respective owners. The use of these +trademarks does not indicate endorsement of the trademark holder by Font +Awesome, nor vice versa. **Please do not use brand logos for any purpose except +to represent the company, product, or service to which they refer.** diff --git a/v0.10.x/_static/vendor/fontawesome/6.1.2/css/all.min.css b/v0.10.x/_static/vendor/fontawesome/6.1.2/css/all.min.css new file mode 100644 index 000000000..b9a01fbb7 --- /dev/null +++ b/v0.10.x/_static/vendor/fontawesome/6.1.2/css/all.min.css @@ -0,0 +1,6 @@ +/*! + * Font Awesome Free 6.1.2 by @fontawesome - https://fontawesome.com + * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) + * Copyright 2022 Fonticons, Inc. + */ +.fa{font-family:var(--fa-style-family,"Font Awesome 6 Free");font-weight:var(--fa-style,900)}.fa,.fa-brands,.fa-duotone,.fa-light,.fa-regular,.fa-solid,.fa-thin,.fab,.fad,.fal,.far,.fas,.fat{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;display:var(--fa-display,inline-block);font-style:normal;font-variant:normal;line-height:1;text-rendering:auto}.fa-1x{font-size:1em}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-6x{font-size:6em}.fa-7x{font-size:7em}.fa-8x{font-size:8em}.fa-9x{font-size:9em}.fa-10x{font-size:10em}.fa-2xs{font-size:.625em;line-height:.1em;vertical-align:.225em}.fa-xs{font-size:.75em;line-height:.08333em;vertical-align:.125em}.fa-sm{font-size:.875em;line-height:.07143em;vertical-align:.05357em}.fa-lg{font-size:1.25em;line-height:.05em;vertical-align:-.075em}.fa-xl{font-size:1.5em;line-height:.04167em;vertical-align:-.125em}.fa-2xl{font-size:2em;line-height:.03125em;vertical-align:-.1875em}.fa-fw{text-align:center;width:1.25em}.fa-ul{list-style-type:none;margin-left:var(--fa-li-margin,2.5em);padding-left:0}.fa-ul>li{position:relative}.fa-li{left:calc(var(--fa-li-width, 2em)*-1);position:absolute;text-align:center;width:var(--fa-li-width,2em);line-height:inherit}.fa-border{border-radius:var(--fa-border-radius,.1em);border:var(--fa-border-width,.08em) var(--fa-border-style,solid) var(--fa-border-color,#eee);padding:var(--fa-border-padding,.2em .25em .15em)}.fa-pull-left{float:left;margin-right:var(--fa-pull-margin,.3em)}.fa-pull-right{float:right;margin-left:var(--fa-pull-margin,.3em)}.fa-beat{-webkit-animation-name:fa-beat;animation-name:fa-beat;-webkit-animation-delay:var(--fa-animation-delay,0);animation-delay:var(--fa-animation-delay,0);-webkit-animation-direction:var(--fa-animation-direction,normal);animation-direction:var(--fa-animation-direction,normal);-webkit-animation-duration:var(--fa-animation-duration,1s);animation-duration:var(--fa-animation-duration,1s);-webkit-animation-iteration-count:var(--fa-animation-iteration-count,infinite);animation-iteration-count:var(--fa-animation-iteration-count,infinite);-webkit-animation-timing-function:var(--fa-animation-timing,ease-in-out);animation-timing-function:var(--fa-animation-timing,ease-in-out)}.fa-bounce{-webkit-animation-name:fa-bounce;animation-name:fa-bounce;-webkit-animation-delay:var(--fa-animation-delay,0);animation-delay:var(--fa-animation-delay,0);-webkit-animation-direction:var(--fa-animation-direction,normal);animation-direction:var(--fa-animation-direction,normal);-webkit-animation-duration:var(--fa-animation-duration,1s);animation-duration:var(--fa-animation-duration,1s);-webkit-animation-iteration-count:var(--fa-animation-iteration-count,infinite);animation-iteration-count:var(--fa-animation-iteration-count,infinite);-webkit-animation-timing-function:var(--fa-animation-timing,cubic-bezier(.28,.84,.42,1));animation-timing-function:var(--fa-animation-timing,cubic-bezier(.28,.84,.42,1))}.fa-fade{-webkit-animation-name:fa-fade;animation-name:fa-fade;-webkit-animation-iteration-count:var(--fa-animation-iteration-count,infinite);animation-iteration-count:var(--fa-animation-iteration-count,infinite);-webkit-animation-timing-function:var(--fa-animation-timing,cubic-bezier(.4,0,.6,1));animation-timing-function:var(--fa-animation-timing,cubic-bezier(.4,0,.6,1))}.fa-beat-fade,.fa-fade{-webkit-animation-delay:var(--fa-animation-delay,0);animation-delay:var(--fa-animation-delay,0);-webkit-animation-direction:var(--fa-animation-direction,normal);animation-direction:var(--fa-animation-direction,normal);-webkit-animation-duration:var(--fa-animation-duration,1s);animation-duration:var(--fa-animation-duration,1s)}.fa-beat-fade{-webkit-animation-name:fa-beat-fade;animation-name:fa-beat-fade;-webkit-animation-iteration-count:var(--fa-animation-iteration-count,infinite);animation-iteration-count:var(--fa-animation-iteration-count,infinite);-webkit-animation-timing-function:var(--fa-animation-timing,cubic-bezier(.4,0,.6,1));animation-timing-function:var(--fa-animation-timing,cubic-bezier(.4,0,.6,1))}.fa-flip{-webkit-animation-name:fa-flip;animation-name:fa-flip;-webkit-animation-delay:var(--fa-animation-delay,0);animation-delay:var(--fa-animation-delay,0);-webkit-animation-direction:var(--fa-animation-direction,normal);animation-direction:var(--fa-animation-direction,normal);-webkit-animation-duration:var(--fa-animation-duration,1s);animation-duration:var(--fa-animation-duration,1s);-webkit-animation-iteration-count:var(--fa-animation-iteration-count,infinite);animation-iteration-count:var(--fa-animation-iteration-count,infinite);-webkit-animation-timing-function:var(--fa-animation-timing,ease-in-out);animation-timing-function:var(--fa-animation-timing,ease-in-out)}.fa-shake{-webkit-animation-name:fa-shake;animation-name:fa-shake;-webkit-animation-duration:var(--fa-animation-duration,1s);animation-duration:var(--fa-animation-duration,1s);-webkit-animation-iteration-count:var(--fa-animation-iteration-count,infinite);animation-iteration-count:var(--fa-animation-iteration-count,infinite);-webkit-animation-timing-function:var(--fa-animation-timing,linear);animation-timing-function:var(--fa-animation-timing,linear)}.fa-shake,.fa-spin{-webkit-animation-delay:var(--fa-animation-delay,0);animation-delay:var(--fa-animation-delay,0);-webkit-animation-direction:var(--fa-animation-direction,normal);animation-direction:var(--fa-animation-direction,normal)}.fa-spin{-webkit-animation-name:fa-spin;animation-name:fa-spin;-webkit-animation-duration:var(--fa-animation-duration,2s);animation-duration:var(--fa-animation-duration,2s);-webkit-animation-iteration-count:var(--fa-animation-iteration-count,infinite);animation-iteration-count:var(--fa-animation-iteration-count,infinite);-webkit-animation-timing-function:var(--fa-animation-timing,linear);animation-timing-function:var(--fa-animation-timing,linear)}.fa-spin-reverse{--fa-animation-direction:reverse}.fa-pulse,.fa-spin-pulse{-webkit-animation-name:fa-spin;animation-name:fa-spin;-webkit-animation-direction:var(--fa-animation-direction,normal);animation-direction:var(--fa-animation-direction,normal);-webkit-animation-duration:var(--fa-animation-duration,1s);animation-duration:var(--fa-animation-duration,1s);-webkit-animation-iteration-count:var(--fa-animation-iteration-count,infinite);animation-iteration-count:var(--fa-animation-iteration-count,infinite);-webkit-animation-timing-function:var(--fa-animation-timing,steps(8));animation-timing-function:var(--fa-animation-timing,steps(8))}@media (prefers-reduced-motion:reduce){.fa-beat,.fa-beat-fade,.fa-bounce,.fa-fade,.fa-flip,.fa-pulse,.fa-shake,.fa-spin,.fa-spin-pulse{-webkit-animation-delay:-1ms;animation-delay:-1ms;-webkit-animation-duration:1ms;animation-duration:1ms;-webkit-animation-iteration-count:1;animation-iteration-count:1;transition-delay:0s;transition-duration:0s}}@-webkit-keyframes fa-beat{0%,90%{-webkit-transform:scale(1);transform:scale(1)}45%{-webkit-transform:scale(var(--fa-beat-scale,1.25));transform:scale(var(--fa-beat-scale,1.25))}}@keyframes fa-beat{0%,90%{-webkit-transform:scale(1);transform:scale(1)}45%{-webkit-transform:scale(var(--fa-beat-scale,1.25));transform:scale(var(--fa-beat-scale,1.25))}}@-webkit-keyframes fa-bounce{0%{-webkit-transform:scale(1) translateY(0);transform:scale(1) translateY(0)}10%{-webkit-transform:scale(var(--fa-bounce-start-scale-x,1.1),var(--fa-bounce-start-scale-y,.9)) translateY(0);transform:scale(var(--fa-bounce-start-scale-x,1.1),var(--fa-bounce-start-scale-y,.9)) translateY(0)}30%{-webkit-transform:scale(var(--fa-bounce-jump-scale-x,.9),var(--fa-bounce-jump-scale-y,1.1)) translateY(var(--fa-bounce-height,-.5em));transform:scale(var(--fa-bounce-jump-scale-x,.9),var(--fa-bounce-jump-scale-y,1.1)) translateY(var(--fa-bounce-height,-.5em))}50%{-webkit-transform:scale(var(--fa-bounce-land-scale-x,1.05),var(--fa-bounce-land-scale-y,.95)) translateY(0);transform:scale(var(--fa-bounce-land-scale-x,1.05),var(--fa-bounce-land-scale-y,.95)) translateY(0)}57%{-webkit-transform:scale(1) translateY(var(--fa-bounce-rebound,-.125em));transform:scale(1) translateY(var(--fa-bounce-rebound,-.125em))}64%{-webkit-transform:scale(1) translateY(0);transform:scale(1) translateY(0)}to{-webkit-transform:scale(1) translateY(0);transform:scale(1) translateY(0)}}@keyframes fa-bounce{0%{-webkit-transform:scale(1) translateY(0);transform:scale(1) translateY(0)}10%{-webkit-transform:scale(var(--fa-bounce-start-scale-x,1.1),var(--fa-bounce-start-scale-y,.9)) translateY(0);transform:scale(var(--fa-bounce-start-scale-x,1.1),var(--fa-bounce-start-scale-y,.9)) translateY(0)}30%{-webkit-transform:scale(var(--fa-bounce-jump-scale-x,.9),var(--fa-bounce-jump-scale-y,1.1)) translateY(var(--fa-bounce-height,-.5em));transform:scale(var(--fa-bounce-jump-scale-x,.9),var(--fa-bounce-jump-scale-y,1.1)) translateY(var(--fa-bounce-height,-.5em))}50%{-webkit-transform:scale(var(--fa-bounce-land-scale-x,1.05),var(--fa-bounce-land-scale-y,.95)) translateY(0);transform:scale(var(--fa-bounce-land-scale-x,1.05),var(--fa-bounce-land-scale-y,.95)) translateY(0)}57%{-webkit-transform:scale(1) translateY(var(--fa-bounce-rebound,-.125em));transform:scale(1) translateY(var(--fa-bounce-rebound,-.125em))}64%{-webkit-transform:scale(1) translateY(0);transform:scale(1) translateY(0)}to{-webkit-transform:scale(1) translateY(0);transform:scale(1) translateY(0)}}@-webkit-keyframes fa-fade{50%{opacity:var(--fa-fade-opacity,.4)}}@keyframes fa-fade{50%{opacity:var(--fa-fade-opacity,.4)}}@-webkit-keyframes fa-beat-fade{0%,to{opacity:var(--fa-beat-fade-opacity,.4);-webkit-transform:scale(1);transform:scale(1)}50%{opacity:1;-webkit-transform:scale(var(--fa-beat-fade-scale,1.125));transform:scale(var(--fa-beat-fade-scale,1.125))}}@keyframes fa-beat-fade{0%,to{opacity:var(--fa-beat-fade-opacity,.4);-webkit-transform:scale(1);transform:scale(1)}50%{opacity:1;-webkit-transform:scale(var(--fa-beat-fade-scale,1.125));transform:scale(var(--fa-beat-fade-scale,1.125))}}@-webkit-keyframes fa-flip{50%{-webkit-transform:rotate3d(var(--fa-flip-x,0),var(--fa-flip-y,1),var(--fa-flip-z,0),var(--fa-flip-angle,-180deg));transform:rotate3d(var(--fa-flip-x,0),var(--fa-flip-y,1),var(--fa-flip-z,0),var(--fa-flip-angle,-180deg))}}@keyframes fa-flip{50%{-webkit-transform:rotate3d(var(--fa-flip-x,0),var(--fa-flip-y,1),var(--fa-flip-z,0),var(--fa-flip-angle,-180deg));transform:rotate3d(var(--fa-flip-x,0),var(--fa-flip-y,1),var(--fa-flip-z,0),var(--fa-flip-angle,-180deg))}}@-webkit-keyframes fa-shake{0%{-webkit-transform:rotate(-15deg);transform:rotate(-15deg)}4%{-webkit-transform:rotate(15deg);transform:rotate(15deg)}8%,24%{-webkit-transform:rotate(-18deg);transform:rotate(-18deg)}12%,28%{-webkit-transform:rotate(18deg);transform:rotate(18deg)}16%{-webkit-transform:rotate(-22deg);transform:rotate(-22deg)}20%{-webkit-transform:rotate(22deg);transform:rotate(22deg)}32%{-webkit-transform:rotate(-12deg);transform:rotate(-12deg)}36%{-webkit-transform:rotate(12deg);transform:rotate(12deg)}40%,to{-webkit-transform:rotate(0deg);transform:rotate(0deg)}}@keyframes fa-shake{0%{-webkit-transform:rotate(-15deg);transform:rotate(-15deg)}4%{-webkit-transform:rotate(15deg);transform:rotate(15deg)}8%,24%{-webkit-transform:rotate(-18deg);transform:rotate(-18deg)}12%,28%{-webkit-transform:rotate(18deg);transform:rotate(18deg)}16%{-webkit-transform:rotate(-22deg);transform:rotate(-22deg)}20%{-webkit-transform:rotate(22deg);transform:rotate(22deg)}32%{-webkit-transform:rotate(-12deg);transform:rotate(-12deg)}36%{-webkit-transform:rotate(12deg);transform:rotate(12deg)}40%,to{-webkit-transform:rotate(0deg);transform:rotate(0deg)}}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}.fa-rotate-90{-webkit-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-webkit-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-webkit-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-webkit-transform:scaleX(-1);transform:scaleX(-1)}.fa-flip-vertical{-webkit-transform:scaleY(-1);transform:scaleY(-1)}.fa-flip-both,.fa-flip-horizontal.fa-flip-vertical{-webkit-transform:scale(-1);transform:scale(-1)}.fa-rotate-by{-webkit-transform:rotate(var(--fa-rotate-angle,none));transform:rotate(var(--fa-rotate-angle,none))}.fa-stack{display:inline-block;height:2em;line-height:2em;position:relative;vertical-align:middle;width:2.5em}.fa-stack-1x,.fa-stack-2x{left:0;position:absolute;text-align:center;width:100%;z-index:var(--fa-stack-z-index,auto)}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:var(--fa-inverse,#fff)}.fa-0:before{content:"\30"}.fa-1:before{content:"\31"}.fa-2:before{content:"\32"}.fa-3:before{content:"\33"}.fa-4:before{content:"\34"}.fa-5:before{content:"\35"}.fa-6:before{content:"\36"}.fa-7:before{content:"\37"}.fa-8:before{content:"\38"}.fa-9:before{content:"\39"}.fa-a:before{content:"\41"}.fa-address-book:before,.fa-contact-book:before{content:"\f2b9"}.fa-address-card:before,.fa-contact-card:before,.fa-vcard:before{content:"\f2bb"}.fa-align-center:before{content:"\f037"}.fa-align-justify:before{content:"\f039"}.fa-align-left:before{content:"\f036"}.fa-align-right:before{content:"\f038"}.fa-anchor:before{content:"\f13d"}.fa-anchor-circle-check:before{content:"\e4aa"}.fa-anchor-circle-exclamation:before{content:"\e4ab"}.fa-anchor-circle-xmark:before{content:"\e4ac"}.fa-anchor-lock:before{content:"\e4ad"}.fa-angle-down:before{content:"\f107"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angle-double-down:before,.fa-angles-down:before{content:"\f103"}.fa-angle-double-left:before,.fa-angles-left:before{content:"\f100"}.fa-angle-double-right:before,.fa-angles-right:before{content:"\f101"}.fa-angle-double-up:before,.fa-angles-up:before{content:"\f102"}.fa-ankh:before{content:"\f644"}.fa-apple-alt:before,.fa-apple-whole:before{content:"\f5d1"}.fa-archway:before{content:"\f557"}.fa-arrow-down:before{content:"\f063"}.fa-arrow-down-1-9:before,.fa-sort-numeric-asc:before,.fa-sort-numeric-down:before{content:"\f162"}.fa-arrow-down-9-1:before,.fa-sort-numeric-desc:before,.fa-sort-numeric-down-alt:before{content:"\f886"}.fa-arrow-down-a-z:before,.fa-sort-alpha-asc:before,.fa-sort-alpha-down:before{content:"\f15d"}.fa-arrow-down-long:before,.fa-long-arrow-down:before{content:"\f175"}.fa-arrow-down-short-wide:before,.fa-sort-amount-desc:before,.fa-sort-amount-down-alt:before{content:"\f884"}.fa-arrow-down-up-across-line:before{content:"\e4af"}.fa-arrow-down-up-lock:before{content:"\e4b0"}.fa-arrow-down-wide-short:before,.fa-sort-amount-asc:before,.fa-sort-amount-down:before{content:"\f160"}.fa-arrow-down-z-a:before,.fa-sort-alpha-desc:before,.fa-sort-alpha-down-alt:before{content:"\f881"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-left-long:before,.fa-long-arrow-left:before{content:"\f177"}.fa-arrow-pointer:before,.fa-mouse-pointer:before{content:"\f245"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-right-arrow-left:before,.fa-exchange:before{content:"\f0ec"}.fa-arrow-right-from-bracket:before,.fa-sign-out:before{content:"\f08b"}.fa-arrow-right-long:before,.fa-long-arrow-right:before{content:"\f178"}.fa-arrow-right-to-bracket:before,.fa-sign-in:before{content:"\f090"}.fa-arrow-right-to-city:before{content:"\e4b3"}.fa-arrow-left-rotate:before,.fa-arrow-rotate-back:before,.fa-arrow-rotate-backward:before,.fa-arrow-rotate-left:before,.fa-undo:before{content:"\f0e2"}.fa-arrow-right-rotate:before,.fa-arrow-rotate-forward:before,.fa-arrow-rotate-right:before,.fa-redo:before{content:"\f01e"}.fa-arrow-trend-down:before{content:"\e097"}.fa-arrow-trend-up:before{content:"\e098"}.fa-arrow-turn-down:before,.fa-level-down:before{content:"\f149"}.fa-arrow-turn-up:before,.fa-level-up:before{content:"\f148"}.fa-arrow-up:before{content:"\f062"}.fa-arrow-up-1-9:before,.fa-sort-numeric-up:before{content:"\f163"}.fa-arrow-up-9-1:before,.fa-sort-numeric-up-alt:before{content:"\f887"}.fa-arrow-up-a-z:before,.fa-sort-alpha-up:before{content:"\f15e"}.fa-arrow-up-from-bracket:before{content:"\e09a"}.fa-arrow-up-from-ground-water:before{content:"\e4b5"}.fa-arrow-up-from-water-pump:before{content:"\e4b6"}.fa-arrow-up-long:before,.fa-long-arrow-up:before{content:"\f176"}.fa-arrow-up-right-dots:before{content:"\e4b7"}.fa-arrow-up-right-from-square:before,.fa-external-link:before{content:"\f08e"}.fa-arrow-up-short-wide:before,.fa-sort-amount-up-alt:before{content:"\f885"}.fa-arrow-up-wide-short:before,.fa-sort-amount-up:before{content:"\f161"}.fa-arrow-up-z-a:before,.fa-sort-alpha-up-alt:before{content:"\f882"}.fa-arrows-down-to-line:before{content:"\e4b8"}.fa-arrows-down-to-people:before{content:"\e4b9"}.fa-arrows-h:before,.fa-arrows-left-right:before{content:"\f07e"}.fa-arrows-left-right-to-line:before{content:"\e4ba"}.fa-arrows-rotate:before,.fa-refresh:before,.fa-sync:before{content:"\f021"}.fa-arrows-spin:before{content:"\e4bb"}.fa-arrows-split-up-and-left:before{content:"\e4bc"}.fa-arrows-to-circle:before{content:"\e4bd"}.fa-arrows-to-dot:before{content:"\e4be"}.fa-arrows-to-eye:before{content:"\e4bf"}.fa-arrows-turn-right:before{content:"\e4c0"}.fa-arrows-turn-to-dots:before{content:"\e4c1"}.fa-arrows-up-down:before,.fa-arrows-v:before{content:"\f07d"}.fa-arrows-up-down-left-right:before,.fa-arrows:before{content:"\f047"}.fa-arrows-up-to-line:before{content:"\e4c2"}.fa-asterisk:before{content:"\2a"}.fa-at:before{content:"\40"}.fa-atom:before{content:"\f5d2"}.fa-audio-description:before{content:"\f29e"}.fa-austral-sign:before{content:"\e0a9"}.fa-award:before{content:"\f559"}.fa-b:before{content:"\42"}.fa-baby:before{content:"\f77c"}.fa-baby-carriage:before,.fa-carriage-baby:before{content:"\f77d"}.fa-backward:before{content:"\f04a"}.fa-backward-fast:before,.fa-fast-backward:before{content:"\f049"}.fa-backward-step:before,.fa-step-backward:before{content:"\f048"}.fa-bacon:before{content:"\f7e5"}.fa-bacteria:before{content:"\e059"}.fa-bacterium:before{content:"\e05a"}.fa-bag-shopping:before,.fa-shopping-bag:before{content:"\f290"}.fa-bahai:before,.fa-haykal:before{content:"\f666"}.fa-baht-sign:before{content:"\e0ac"}.fa-ban:before,.fa-cancel:before{content:"\f05e"}.fa-ban-smoking:before,.fa-smoking-ban:before{content:"\f54d"}.fa-band-aid:before,.fa-bandage:before{content:"\f462"}.fa-barcode:before{content:"\f02a"}.fa-bars:before,.fa-navicon:before{content:"\f0c9"}.fa-bars-progress:before,.fa-tasks-alt:before{content:"\f828"}.fa-bars-staggered:before,.fa-reorder:before,.fa-stream:before{content:"\f550"}.fa-baseball-ball:before,.fa-baseball:before{content:"\f433"}.fa-baseball-bat-ball:before{content:"\f432"}.fa-basket-shopping:before,.fa-shopping-basket:before{content:"\f291"}.fa-basketball-ball:before,.fa-basketball:before{content:"\f434"}.fa-bath:before,.fa-bathtub:before{content:"\f2cd"}.fa-battery-0:before,.fa-battery-empty:before{content:"\f244"}.fa-battery-5:before,.fa-battery-full:before,.fa-battery:before{content:"\f240"}.fa-battery-3:before,.fa-battery-half:before{content:"\f242"}.fa-battery-2:before,.fa-battery-quarter:before{content:"\f243"}.fa-battery-4:before,.fa-battery-three-quarters:before{content:"\f241"}.fa-bed:before{content:"\f236"}.fa-bed-pulse:before,.fa-procedures:before{content:"\f487"}.fa-beer-mug-empty:before,.fa-beer:before{content:"\f0fc"}.fa-bell:before{content:"\f0f3"}.fa-bell-concierge:before,.fa-concierge-bell:before{content:"\f562"}.fa-bell-slash:before{content:"\f1f6"}.fa-bezier-curve:before{content:"\f55b"}.fa-bicycle:before{content:"\f206"}.fa-binoculars:before{content:"\f1e5"}.fa-biohazard:before{content:"\f780"}.fa-bitcoin-sign:before{content:"\e0b4"}.fa-blender:before{content:"\f517"}.fa-blender-phone:before{content:"\f6b6"}.fa-blog:before{content:"\f781"}.fa-bold:before{content:"\f032"}.fa-bolt:before,.fa-zap:before{content:"\f0e7"}.fa-bolt-lightning:before{content:"\e0b7"}.fa-bomb:before{content:"\f1e2"}.fa-bone:before{content:"\f5d7"}.fa-bong:before{content:"\f55c"}.fa-book:before{content:"\f02d"}.fa-atlas:before,.fa-book-atlas:before{content:"\f558"}.fa-bible:before,.fa-book-bible:before{content:"\f647"}.fa-book-bookmark:before{content:"\e0bb"}.fa-book-journal-whills:before,.fa-journal-whills:before{content:"\f66a"}.fa-book-medical:before{content:"\f7e6"}.fa-book-open:before{content:"\f518"}.fa-book-open-reader:before,.fa-book-reader:before{content:"\f5da"}.fa-book-quran:before,.fa-quran:before{content:"\f687"}.fa-book-dead:before,.fa-book-skull:before{content:"\f6b7"}.fa-book-tanakh:before,.fa-tanakh:before{content:"\f827"}.fa-bookmark:before{content:"\f02e"}.fa-border-all:before{content:"\f84c"}.fa-border-none:before{content:"\f850"}.fa-border-style:before,.fa-border-top-left:before{content:"\f853"}.fa-bore-hole:before{content:"\e4c3"}.fa-bottle-droplet:before{content:"\e4c4"}.fa-bottle-water:before{content:"\e4c5"}.fa-bowl-food:before{content:"\e4c6"}.fa-bowl-rice:before{content:"\e2eb"}.fa-bowling-ball:before{content:"\f436"}.fa-box:before{content:"\f466"}.fa-archive:before,.fa-box-archive:before{content:"\f187"}.fa-box-open:before{content:"\f49e"}.fa-box-tissue:before{content:"\e05b"}.fa-boxes-packing:before{content:"\e4c7"}.fa-boxes-alt:before,.fa-boxes-stacked:before,.fa-boxes:before{content:"\f468"}.fa-braille:before{content:"\f2a1"}.fa-brain:before{content:"\f5dc"}.fa-brazilian-real-sign:before{content:"\e46c"}.fa-bread-slice:before{content:"\f7ec"}.fa-bridge:before{content:"\e4c8"}.fa-bridge-circle-check:before{content:"\e4c9"}.fa-bridge-circle-exclamation:before{content:"\e4ca"}.fa-bridge-circle-xmark:before{content:"\e4cb"}.fa-bridge-lock:before{content:"\e4cc"}.fa-bridge-water:before{content:"\e4ce"}.fa-briefcase:before{content:"\f0b1"}.fa-briefcase-medical:before{content:"\f469"}.fa-broom:before{content:"\f51a"}.fa-broom-ball:before,.fa-quidditch-broom-ball:before,.fa-quidditch:before{content:"\f458"}.fa-brush:before{content:"\f55d"}.fa-bucket:before{content:"\e4cf"}.fa-bug:before{content:"\f188"}.fa-bug-slash:before{content:"\e490"}.fa-bugs:before{content:"\e4d0"}.fa-building:before{content:"\f1ad"}.fa-building-circle-arrow-right:before{content:"\e4d1"}.fa-building-circle-check:before{content:"\e4d2"}.fa-building-circle-exclamation:before{content:"\e4d3"}.fa-building-circle-xmark:before{content:"\e4d4"}.fa-bank:before,.fa-building-columns:before,.fa-institution:before,.fa-museum:before,.fa-university:before{content:"\f19c"}.fa-building-flag:before{content:"\e4d5"}.fa-building-lock:before{content:"\e4d6"}.fa-building-ngo:before{content:"\e4d7"}.fa-building-shield:before{content:"\e4d8"}.fa-building-un:before{content:"\e4d9"}.fa-building-user:before{content:"\e4da"}.fa-building-wheat:before{content:"\e4db"}.fa-bullhorn:before{content:"\f0a1"}.fa-bullseye:before{content:"\f140"}.fa-burger:before,.fa-hamburger:before{content:"\f805"}.fa-burst:before{content:"\e4dc"}.fa-bus:before{content:"\f207"}.fa-bus-alt:before,.fa-bus-simple:before{content:"\f55e"}.fa-briefcase-clock:before,.fa-business-time:before{content:"\f64a"}.fa-c:before{content:"\43"}.fa-cable-car:before,.fa-tram:before{content:"\f7da"}.fa-birthday-cake:before,.fa-cake-candles:before,.fa-cake:before{content:"\f1fd"}.fa-calculator:before{content:"\f1ec"}.fa-calendar:before{content:"\f133"}.fa-calendar-check:before{content:"\f274"}.fa-calendar-day:before{content:"\f783"}.fa-calendar-alt:before,.fa-calendar-days:before{content:"\f073"}.fa-calendar-minus:before{content:"\f272"}.fa-calendar-plus:before{content:"\f271"}.fa-calendar-week:before{content:"\f784"}.fa-calendar-times:before,.fa-calendar-xmark:before{content:"\f273"}.fa-camera-alt:before,.fa-camera:before{content:"\f030"}.fa-camera-retro:before{content:"\f083"}.fa-camera-rotate:before{content:"\e0d8"}.fa-campground:before{content:"\f6bb"}.fa-candy-cane:before{content:"\f786"}.fa-cannabis:before{content:"\f55f"}.fa-capsules:before{content:"\f46b"}.fa-automobile:before,.fa-car:before{content:"\f1b9"}.fa-battery-car:before,.fa-car-battery:before{content:"\f5df"}.fa-car-burst:before,.fa-car-crash:before{content:"\f5e1"}.fa-car-on:before{content:"\e4dd"}.fa-car-alt:before,.fa-car-rear:before{content:"\f5de"}.fa-car-side:before{content:"\f5e4"}.fa-car-tunnel:before{content:"\e4de"}.fa-caravan:before{content:"\f8ff"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-caret-up:before{content:"\f0d8"}.fa-carrot:before{content:"\f787"}.fa-cart-arrow-down:before{content:"\f218"}.fa-cart-flatbed:before,.fa-dolly-flatbed:before{content:"\f474"}.fa-cart-flatbed-suitcase:before,.fa-luggage-cart:before{content:"\f59d"}.fa-cart-plus:before{content:"\f217"}.fa-cart-shopping:before,.fa-shopping-cart:before{content:"\f07a"}.fa-cash-register:before{content:"\f788"}.fa-cat:before{content:"\f6be"}.fa-cedi-sign:before{content:"\e0df"}.fa-cent-sign:before{content:"\e3f5"}.fa-certificate:before{content:"\f0a3"}.fa-chair:before{content:"\f6c0"}.fa-blackboard:before,.fa-chalkboard:before{content:"\f51b"}.fa-chalkboard-teacher:before,.fa-chalkboard-user:before{content:"\f51c"}.fa-champagne-glasses:before,.fa-glass-cheers:before{content:"\f79f"}.fa-charging-station:before{content:"\f5e7"}.fa-area-chart:before,.fa-chart-area:before{content:"\f1fe"}.fa-bar-chart:before,.fa-chart-bar:before{content:"\f080"}.fa-chart-column:before{content:"\e0e3"}.fa-chart-gantt:before{content:"\e0e4"}.fa-chart-line:before,.fa-line-chart:before{content:"\f201"}.fa-chart-pie:before,.fa-pie-chart:before{content:"\f200"}.fa-chart-simple:before{content:"\e473"}.fa-check:before{content:"\f00c"}.fa-check-double:before{content:"\f560"}.fa-check-to-slot:before,.fa-vote-yea:before{content:"\f772"}.fa-cheese:before{content:"\f7ef"}.fa-chess:before{content:"\f439"}.fa-chess-bishop:before{content:"\f43a"}.fa-chess-board:before{content:"\f43c"}.fa-chess-king:before{content:"\f43f"}.fa-chess-knight:before{content:"\f441"}.fa-chess-pawn:before{content:"\f443"}.fa-chess-queen:before{content:"\f445"}.fa-chess-rook:before{content:"\f447"}.fa-chevron-down:before{content:"\f078"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-chevron-up:before{content:"\f077"}.fa-child:before{content:"\f1ae"}.fa-child-dress:before{content:"\e59c"}.fa-child-reaching:before{content:"\e59d"}.fa-child-rifle:before{content:"\e4e0"}.fa-children:before{content:"\e4e1"}.fa-church:before{content:"\f51d"}.fa-circle:before{content:"\f111"}.fa-arrow-circle-down:before,.fa-circle-arrow-down:before{content:"\f0ab"}.fa-arrow-circle-left:before,.fa-circle-arrow-left:before{content:"\f0a8"}.fa-arrow-circle-right:before,.fa-circle-arrow-right:before{content:"\f0a9"}.fa-arrow-circle-up:before,.fa-circle-arrow-up:before{content:"\f0aa"}.fa-check-circle:before,.fa-circle-check:before{content:"\f058"}.fa-chevron-circle-down:before,.fa-circle-chevron-down:before{content:"\f13a"}.fa-chevron-circle-left:before,.fa-circle-chevron-left:before{content:"\f137"}.fa-chevron-circle-right:before,.fa-circle-chevron-right:before{content:"\f138"}.fa-chevron-circle-up:before,.fa-circle-chevron-up:before{content:"\f139"}.fa-circle-dollar-to-slot:before,.fa-donate:before{content:"\f4b9"}.fa-circle-dot:before,.fa-dot-circle:before{content:"\f192"}.fa-arrow-alt-circle-down:before,.fa-circle-down:before{content:"\f358"}.fa-circle-exclamation:before,.fa-exclamation-circle:before{content:"\f06a"}.fa-circle-h:before,.fa-hospital-symbol:before{content:"\f47e"}.fa-adjust:before,.fa-circle-half-stroke:before{content:"\f042"}.fa-circle-info:before,.fa-info-circle:before{content:"\f05a"}.fa-arrow-alt-circle-left:before,.fa-circle-left:before{content:"\f359"}.fa-circle-minus:before,.fa-minus-circle:before{content:"\f056"}.fa-circle-nodes:before{content:"\e4e2"}.fa-circle-notch:before{content:"\f1ce"}.fa-circle-pause:before,.fa-pause-circle:before{content:"\f28b"}.fa-circle-play:before,.fa-play-circle:before{content:"\f144"}.fa-circle-plus:before,.fa-plus-circle:before{content:"\f055"}.fa-circle-question:before,.fa-question-circle:before{content:"\f059"}.fa-circle-radiation:before,.fa-radiation-alt:before{content:"\f7ba"}.fa-arrow-alt-circle-right:before,.fa-circle-right:before{content:"\f35a"}.fa-circle-stop:before,.fa-stop-circle:before{content:"\f28d"}.fa-arrow-alt-circle-up:before,.fa-circle-up:before{content:"\f35b"}.fa-circle-user:before,.fa-user-circle:before{content:"\f2bd"}.fa-circle-xmark:before,.fa-times-circle:before,.fa-xmark-circle:before{content:"\f057"}.fa-city:before{content:"\f64f"}.fa-clapperboard:before{content:"\e131"}.fa-clipboard:before{content:"\f328"}.fa-clipboard-check:before{content:"\f46c"}.fa-clipboard-list:before{content:"\f46d"}.fa-clipboard-question:before{content:"\e4e3"}.fa-clipboard-user:before{content:"\f7f3"}.fa-clock-four:before,.fa-clock:before{content:"\f017"}.fa-clock-rotate-left:before,.fa-history:before{content:"\f1da"}.fa-clone:before{content:"\f24d"}.fa-closed-captioning:before{content:"\f20a"}.fa-cloud:before{content:"\f0c2"}.fa-cloud-arrow-down:before,.fa-cloud-download-alt:before,.fa-cloud-download:before{content:"\f0ed"}.fa-cloud-arrow-up:before,.fa-cloud-upload-alt:before,.fa-cloud-upload:before{content:"\f0ee"}.fa-cloud-bolt:before,.fa-thunderstorm:before{content:"\f76c"}.fa-cloud-meatball:before{content:"\f73b"}.fa-cloud-moon:before{content:"\f6c3"}.fa-cloud-moon-rain:before{content:"\f73c"}.fa-cloud-rain:before{content:"\f73d"}.fa-cloud-showers-heavy:before{content:"\f740"}.fa-cloud-showers-water:before{content:"\e4e4"}.fa-cloud-sun:before{content:"\f6c4"}.fa-cloud-sun-rain:before{content:"\f743"}.fa-clover:before{content:"\e139"}.fa-code:before{content:"\f121"}.fa-code-branch:before{content:"\f126"}.fa-code-commit:before{content:"\f386"}.fa-code-compare:before{content:"\e13a"}.fa-code-fork:before{content:"\e13b"}.fa-code-merge:before{content:"\f387"}.fa-code-pull-request:before{content:"\e13c"}.fa-coins:before{content:"\f51e"}.fa-colon-sign:before{content:"\e140"}.fa-comment:before{content:"\f075"}.fa-comment-dollar:before{content:"\f651"}.fa-comment-dots:before,.fa-commenting:before{content:"\f4ad"}.fa-comment-medical:before{content:"\f7f5"}.fa-comment-slash:before{content:"\f4b3"}.fa-comment-sms:before,.fa-sms:before{content:"\f7cd"}.fa-comments:before{content:"\f086"}.fa-comments-dollar:before{content:"\f653"}.fa-compact-disc:before{content:"\f51f"}.fa-compass:before{content:"\f14e"}.fa-compass-drafting:before,.fa-drafting-compass:before{content:"\f568"}.fa-compress:before{content:"\f066"}.fa-computer:before{content:"\e4e5"}.fa-computer-mouse:before,.fa-mouse:before{content:"\f8cc"}.fa-cookie:before{content:"\f563"}.fa-cookie-bite:before{content:"\f564"}.fa-copy:before{content:"\f0c5"}.fa-copyright:before{content:"\f1f9"}.fa-couch:before{content:"\f4b8"}.fa-cow:before{content:"\f6c8"}.fa-credit-card-alt:before,.fa-credit-card:before{content:"\f09d"}.fa-crop:before{content:"\f125"}.fa-crop-alt:before,.fa-crop-simple:before{content:"\f565"}.fa-cross:before{content:"\f654"}.fa-crosshairs:before{content:"\f05b"}.fa-crow:before{content:"\f520"}.fa-crown:before{content:"\f521"}.fa-crutch:before{content:"\f7f7"}.fa-cruzeiro-sign:before{content:"\e152"}.fa-cube:before{content:"\f1b2"}.fa-cubes:before{content:"\f1b3"}.fa-cubes-stacked:before{content:"\e4e6"}.fa-d:before{content:"\44"}.fa-database:before{content:"\f1c0"}.fa-backspace:before,.fa-delete-left:before{content:"\f55a"}.fa-democrat:before{content:"\f747"}.fa-desktop-alt:before,.fa-desktop:before{content:"\f390"}.fa-dharmachakra:before{content:"\f655"}.fa-diagram-next:before{content:"\e476"}.fa-diagram-predecessor:before{content:"\e477"}.fa-diagram-project:before,.fa-project-diagram:before{content:"\f542"}.fa-diagram-successor:before{content:"\e47a"}.fa-diamond:before{content:"\f219"}.fa-diamond-turn-right:before,.fa-directions:before{content:"\f5eb"}.fa-dice:before{content:"\f522"}.fa-dice-d20:before{content:"\f6cf"}.fa-dice-d6:before{content:"\f6d1"}.fa-dice-five:before{content:"\f523"}.fa-dice-four:before{content:"\f524"}.fa-dice-one:before{content:"\f525"}.fa-dice-six:before{content:"\f526"}.fa-dice-three:before{content:"\f527"}.fa-dice-two:before{content:"\f528"}.fa-disease:before{content:"\f7fa"}.fa-display:before{content:"\e163"}.fa-divide:before{content:"\f529"}.fa-dna:before{content:"\f471"}.fa-dog:before{content:"\f6d3"}.fa-dollar-sign:before,.fa-dollar:before,.fa-usd:before{content:"\24"}.fa-dolly-box:before,.fa-dolly:before{content:"\f472"}.fa-dong-sign:before{content:"\e169"}.fa-door-closed:before{content:"\f52a"}.fa-door-open:before{content:"\f52b"}.fa-dove:before{content:"\f4ba"}.fa-compress-alt:before,.fa-down-left-and-up-right-to-center:before{content:"\f422"}.fa-down-long:before,.fa-long-arrow-alt-down:before{content:"\f309"}.fa-download:before{content:"\f019"}.fa-dragon:before{content:"\f6d5"}.fa-draw-polygon:before{content:"\f5ee"}.fa-droplet:before,.fa-tint:before{content:"\f043"}.fa-droplet-slash:before,.fa-tint-slash:before{content:"\f5c7"}.fa-drum:before{content:"\f569"}.fa-drum-steelpan:before{content:"\f56a"}.fa-drumstick-bite:before{content:"\f6d7"}.fa-dumbbell:before{content:"\f44b"}.fa-dumpster:before{content:"\f793"}.fa-dumpster-fire:before{content:"\f794"}.fa-dungeon:before{content:"\f6d9"}.fa-e:before{content:"\45"}.fa-deaf:before,.fa-deafness:before,.fa-ear-deaf:before,.fa-hard-of-hearing:before{content:"\f2a4"}.fa-assistive-listening-systems:before,.fa-ear-listen:before{content:"\f2a2"}.fa-earth-africa:before,.fa-globe-africa:before{content:"\f57c"}.fa-earth-america:before,.fa-earth-americas:before,.fa-earth:before,.fa-globe-americas:before{content:"\f57d"}.fa-earth-asia:before,.fa-globe-asia:before{content:"\f57e"}.fa-earth-europe:before,.fa-globe-europe:before{content:"\f7a2"}.fa-earth-oceania:before,.fa-globe-oceania:before{content:"\e47b"}.fa-egg:before{content:"\f7fb"}.fa-eject:before{content:"\f052"}.fa-elevator:before{content:"\e16d"}.fa-ellipsis-h:before,.fa-ellipsis:before{content:"\f141"}.fa-ellipsis-v:before,.fa-ellipsis-vertical:before{content:"\f142"}.fa-envelope:before{content:"\f0e0"}.fa-envelope-circle-check:before{content:"\e4e8"}.fa-envelope-open:before{content:"\f2b6"}.fa-envelope-open-text:before{content:"\f658"}.fa-envelopes-bulk:before,.fa-mail-bulk:before{content:"\f674"}.fa-equals:before{content:"\3d"}.fa-eraser:before{content:"\f12d"}.fa-ethernet:before{content:"\f796"}.fa-eur:before,.fa-euro-sign:before,.fa-euro:before{content:"\f153"}.fa-exclamation:before{content:"\21"}.fa-expand:before{content:"\f065"}.fa-explosion:before{content:"\e4e9"}.fa-eye:before{content:"\f06e"}.fa-eye-dropper-empty:before,.fa-eye-dropper:before,.fa-eyedropper:before{content:"\f1fb"}.fa-eye-low-vision:before,.fa-low-vision:before{content:"\f2a8"}.fa-eye-slash:before{content:"\f070"}.fa-f:before{content:"\46"}.fa-angry:before,.fa-face-angry:before{content:"\f556"}.fa-dizzy:before,.fa-face-dizzy:before{content:"\f567"}.fa-face-flushed:before,.fa-flushed:before{content:"\f579"}.fa-face-frown:before,.fa-frown:before{content:"\f119"}.fa-face-frown-open:before,.fa-frown-open:before{content:"\f57a"}.fa-face-grimace:before,.fa-grimace:before{content:"\f57f"}.fa-face-grin:before,.fa-grin:before{content:"\f580"}.fa-face-grin-beam:before,.fa-grin-beam:before{content:"\f582"}.fa-face-grin-beam-sweat:before,.fa-grin-beam-sweat:before{content:"\f583"}.fa-face-grin-hearts:before,.fa-grin-hearts:before{content:"\f584"}.fa-face-grin-squint:before,.fa-grin-squint:before{content:"\f585"}.fa-face-grin-squint-tears:before,.fa-grin-squint-tears:before{content:"\f586"}.fa-face-grin-stars:before,.fa-grin-stars:before{content:"\f587"}.fa-face-grin-tears:before,.fa-grin-tears:before{content:"\f588"}.fa-face-grin-tongue:before,.fa-grin-tongue:before{content:"\f589"}.fa-face-grin-tongue-squint:before,.fa-grin-tongue-squint:before{content:"\f58a"}.fa-face-grin-tongue-wink:before,.fa-grin-tongue-wink:before{content:"\f58b"}.fa-face-grin-wide:before,.fa-grin-alt:before{content:"\f581"}.fa-face-grin-wink:before,.fa-grin-wink:before{content:"\f58c"}.fa-face-kiss:before,.fa-kiss:before{content:"\f596"}.fa-face-kiss-beam:before,.fa-kiss-beam:before{content:"\f597"}.fa-face-kiss-wink-heart:before,.fa-kiss-wink-heart:before{content:"\f598"}.fa-face-laugh:before,.fa-laugh:before{content:"\f599"}.fa-face-laugh-beam:before,.fa-laugh-beam:before{content:"\f59a"}.fa-face-laugh-squint:before,.fa-laugh-squint:before{content:"\f59b"}.fa-face-laugh-wink:before,.fa-laugh-wink:before{content:"\f59c"}.fa-face-meh:before,.fa-meh:before{content:"\f11a"}.fa-face-meh-blank:before,.fa-meh-blank:before{content:"\f5a4"}.fa-face-rolling-eyes:before,.fa-meh-rolling-eyes:before{content:"\f5a5"}.fa-face-sad-cry:before,.fa-sad-cry:before{content:"\f5b3"}.fa-face-sad-tear:before,.fa-sad-tear:before{content:"\f5b4"}.fa-face-smile:before,.fa-smile:before{content:"\f118"}.fa-face-smile-beam:before,.fa-smile-beam:before{content:"\f5b8"}.fa-face-smile-wink:before,.fa-smile-wink:before{content:"\f4da"}.fa-face-surprise:before,.fa-surprise:before{content:"\f5c2"}.fa-face-tired:before,.fa-tired:before{content:"\f5c8"}.fa-fan:before{content:"\f863"}.fa-faucet:before{content:"\e005"}.fa-faucet-drip:before{content:"\e006"}.fa-fax:before{content:"\f1ac"}.fa-feather:before{content:"\f52d"}.fa-feather-alt:before,.fa-feather-pointed:before{content:"\f56b"}.fa-ferry:before{content:"\e4ea"}.fa-file:before{content:"\f15b"}.fa-file-arrow-down:before,.fa-file-download:before{content:"\f56d"}.fa-file-arrow-up:before,.fa-file-upload:before{content:"\f574"}.fa-file-audio:before{content:"\f1c7"}.fa-file-circle-check:before{content:"\e5a0"}.fa-file-circle-exclamation:before{content:"\e4eb"}.fa-file-circle-minus:before{content:"\e4ed"}.fa-file-circle-plus:before{content:"\e494"}.fa-file-circle-question:before{content:"\e4ef"}.fa-file-circle-xmark:before{content:"\e5a1"}.fa-file-code:before{content:"\f1c9"}.fa-file-contract:before{content:"\f56c"}.fa-file-csv:before{content:"\f6dd"}.fa-file-excel:before{content:"\f1c3"}.fa-arrow-right-from-file:before,.fa-file-export:before{content:"\f56e"}.fa-file-image:before{content:"\f1c5"}.fa-arrow-right-to-file:before,.fa-file-import:before{content:"\f56f"}.fa-file-invoice:before{content:"\f570"}.fa-file-invoice-dollar:before{content:"\f571"}.fa-file-alt:before,.fa-file-lines:before,.fa-file-text:before{content:"\f15c"}.fa-file-medical:before{content:"\f477"}.fa-file-pdf:before{content:"\f1c1"}.fa-file-edit:before,.fa-file-pen:before{content:"\f31c"}.fa-file-powerpoint:before{content:"\f1c4"}.fa-file-prescription:before{content:"\f572"}.fa-file-shield:before{content:"\e4f0"}.fa-file-signature:before{content:"\f573"}.fa-file-video:before{content:"\f1c8"}.fa-file-medical-alt:before,.fa-file-waveform:before{content:"\f478"}.fa-file-word:before{content:"\f1c2"}.fa-file-archive:before,.fa-file-zipper:before{content:"\f1c6"}.fa-fill:before{content:"\f575"}.fa-fill-drip:before{content:"\f576"}.fa-film:before{content:"\f008"}.fa-filter:before{content:"\f0b0"}.fa-filter-circle-dollar:before,.fa-funnel-dollar:before{content:"\f662"}.fa-filter-circle-xmark:before{content:"\e17b"}.fa-fingerprint:before{content:"\f577"}.fa-fire:before{content:"\f06d"}.fa-fire-burner:before{content:"\e4f1"}.fa-fire-extinguisher:before{content:"\f134"}.fa-fire-alt:before,.fa-fire-flame-curved:before{content:"\f7e4"}.fa-burn:before,.fa-fire-flame-simple:before{content:"\f46a"}.fa-fish:before{content:"\f578"}.fa-fish-fins:before{content:"\e4f2"}.fa-flag:before{content:"\f024"}.fa-flag-checkered:before{content:"\f11e"}.fa-flag-usa:before{content:"\f74d"}.fa-flask:before{content:"\f0c3"}.fa-flask-vial:before{content:"\e4f3"}.fa-floppy-disk:before,.fa-save:before{content:"\f0c7"}.fa-florin-sign:before{content:"\e184"}.fa-folder-blank:before,.fa-folder:before{content:"\f07b"}.fa-folder-closed:before{content:"\e185"}.fa-folder-minus:before{content:"\f65d"}.fa-folder-open:before{content:"\f07c"}.fa-folder-plus:before{content:"\f65e"}.fa-folder-tree:before{content:"\f802"}.fa-font:before{content:"\f031"}.fa-football-ball:before,.fa-football:before{content:"\f44e"}.fa-forward:before{content:"\f04e"}.fa-fast-forward:before,.fa-forward-fast:before{content:"\f050"}.fa-forward-step:before,.fa-step-forward:before{content:"\f051"}.fa-franc-sign:before{content:"\e18f"}.fa-frog:before{content:"\f52e"}.fa-futbol-ball:before,.fa-futbol:before,.fa-soccer-ball:before{content:"\f1e3"}.fa-g:before{content:"\47"}.fa-gamepad:before{content:"\f11b"}.fa-gas-pump:before{content:"\f52f"}.fa-dashboard:before,.fa-gauge-med:before,.fa-gauge:before,.fa-tachometer-alt-average:before{content:"\f624"}.fa-gauge-high:before,.fa-tachometer-alt-fast:before,.fa-tachometer-alt:before{content:"\f625"}.fa-gauge-simple-med:before,.fa-gauge-simple:before,.fa-tachometer-average:before{content:"\f629"}.fa-gauge-simple-high:before,.fa-tachometer-fast:before,.fa-tachometer:before{content:"\f62a"}.fa-gavel:before,.fa-legal:before{content:"\f0e3"}.fa-cog:before,.fa-gear:before{content:"\f013"}.fa-cogs:before,.fa-gears:before{content:"\f085"}.fa-gem:before{content:"\f3a5"}.fa-genderless:before{content:"\f22d"}.fa-ghost:before{content:"\f6e2"}.fa-gift:before{content:"\f06b"}.fa-gifts:before{content:"\f79c"}.fa-glass-water:before{content:"\e4f4"}.fa-glass-water-droplet:before{content:"\e4f5"}.fa-glasses:before{content:"\f530"}.fa-globe:before{content:"\f0ac"}.fa-golf-ball-tee:before,.fa-golf-ball:before{content:"\f450"}.fa-gopuram:before{content:"\f664"}.fa-graduation-cap:before,.fa-mortar-board:before{content:"\f19d"}.fa-greater-than:before{content:"\3e"}.fa-greater-than-equal:before{content:"\f532"}.fa-grip-horizontal:before,.fa-grip:before{content:"\f58d"}.fa-grip-lines:before{content:"\f7a4"}.fa-grip-lines-vertical:before{content:"\f7a5"}.fa-grip-vertical:before{content:"\f58e"}.fa-group-arrows-rotate:before{content:"\e4f6"}.fa-guarani-sign:before{content:"\e19a"}.fa-guitar:before{content:"\f7a6"}.fa-gun:before{content:"\e19b"}.fa-h:before{content:"\48"}.fa-hammer:before{content:"\f6e3"}.fa-hamsa:before{content:"\f665"}.fa-hand-paper:before,.fa-hand:before{content:"\f256"}.fa-hand-back-fist:before,.fa-hand-rock:before{content:"\f255"}.fa-allergies:before,.fa-hand-dots:before{content:"\f461"}.fa-fist-raised:before,.fa-hand-fist:before{content:"\f6de"}.fa-hand-holding:before{content:"\f4bd"}.fa-hand-holding-dollar:before,.fa-hand-holding-usd:before{content:"\f4c0"}.fa-hand-holding-droplet:before,.fa-hand-holding-water:before{content:"\f4c1"}.fa-hand-holding-hand:before{content:"\e4f7"}.fa-hand-holding-heart:before{content:"\f4be"}.fa-hand-holding-medical:before{content:"\e05c"}.fa-hand-lizard:before{content:"\f258"}.fa-hand-middle-finger:before{content:"\f806"}.fa-hand-peace:before{content:"\f25b"}.fa-hand-point-down:before{content:"\f0a7"}.fa-hand-point-left:before{content:"\f0a5"}.fa-hand-point-right:before{content:"\f0a4"}.fa-hand-point-up:before{content:"\f0a6"}.fa-hand-pointer:before{content:"\f25a"}.fa-hand-scissors:before{content:"\f257"}.fa-hand-sparkles:before{content:"\e05d"}.fa-hand-spock:before{content:"\f259"}.fa-handcuffs:before{content:"\e4f8"}.fa-hands:before,.fa-sign-language:before,.fa-signing:before{content:"\f2a7"}.fa-american-sign-language-interpreting:before,.fa-asl-interpreting:before,.fa-hands-american-sign-language-interpreting:before,.fa-hands-asl-interpreting:before{content:"\f2a3"}.fa-hands-bound:before{content:"\e4f9"}.fa-hands-bubbles:before,.fa-hands-wash:before{content:"\e05e"}.fa-hands-clapping:before{content:"\e1a8"}.fa-hands-holding:before{content:"\f4c2"}.fa-hands-holding-child:before{content:"\e4fa"}.fa-hands-holding-circle:before{content:"\e4fb"}.fa-hands-praying:before,.fa-praying-hands:before{content:"\f684"}.fa-handshake:before{content:"\f2b5"}.fa-hands-helping:before,.fa-handshake-angle:before{content:"\f4c4"}.fa-handshake-alt:before,.fa-handshake-simple:before{content:"\f4c6"}.fa-handshake-alt-slash:before,.fa-handshake-simple-slash:before{content:"\e05f"}.fa-handshake-slash:before{content:"\e060"}.fa-hanukiah:before{content:"\f6e6"}.fa-hard-drive:before,.fa-hdd:before{content:"\f0a0"}.fa-hashtag:before{content:"\23"}.fa-hat-cowboy:before{content:"\f8c0"}.fa-hat-cowboy-side:before{content:"\f8c1"}.fa-hat-wizard:before{content:"\f6e8"}.fa-head-side-cough:before{content:"\e061"}.fa-head-side-cough-slash:before{content:"\e062"}.fa-head-side-mask:before{content:"\e063"}.fa-head-side-virus:before{content:"\e064"}.fa-header:before,.fa-heading:before{content:"\f1dc"}.fa-headphones:before{content:"\f025"}.fa-headphones-alt:before,.fa-headphones-simple:before{content:"\f58f"}.fa-headset:before{content:"\f590"}.fa-heart:before{content:"\f004"}.fa-heart-circle-bolt:before{content:"\e4fc"}.fa-heart-circle-check:before{content:"\e4fd"}.fa-heart-circle-exclamation:before{content:"\e4fe"}.fa-heart-circle-minus:before{content:"\e4ff"}.fa-heart-circle-plus:before{content:"\e500"}.fa-heart-circle-xmark:before{content:"\e501"}.fa-heart-broken:before,.fa-heart-crack:before{content:"\f7a9"}.fa-heart-pulse:before,.fa-heartbeat:before{content:"\f21e"}.fa-helicopter:before{content:"\f533"}.fa-helicopter-symbol:before{content:"\e502"}.fa-hard-hat:before,.fa-hat-hard:before,.fa-helmet-safety:before{content:"\f807"}.fa-helmet-un:before{content:"\e503"}.fa-highlighter:before{content:"\f591"}.fa-hill-avalanche:before{content:"\e507"}.fa-hill-rockslide:before{content:"\e508"}.fa-hippo:before{content:"\f6ed"}.fa-hockey-puck:before{content:"\f453"}.fa-holly-berry:before{content:"\f7aa"}.fa-horse:before{content:"\f6f0"}.fa-horse-head:before{content:"\f7ab"}.fa-hospital-alt:before,.fa-hospital-wide:before,.fa-hospital:before{content:"\f0f8"}.fa-hospital-user:before{content:"\f80d"}.fa-hot-tub-person:before,.fa-hot-tub:before{content:"\f593"}.fa-hotdog:before{content:"\f80f"}.fa-hotel:before{content:"\f594"}.fa-hourglass-empty:before,.fa-hourglass:before{content:"\f254"}.fa-hourglass-3:before,.fa-hourglass-end:before{content:"\f253"}.fa-hourglass-2:before,.fa-hourglass-half:before{content:"\f252"}.fa-hourglass-1:before,.fa-hourglass-start:before{content:"\f251"}.fa-home-alt:before,.fa-home-lg-alt:before,.fa-home:before,.fa-house:before{content:"\f015"}.fa-home-lg:before,.fa-house-chimney:before{content:"\e3af"}.fa-house-chimney-crack:before,.fa-house-damage:before{content:"\f6f1"}.fa-clinic-medical:before,.fa-house-chimney-medical:before{content:"\f7f2"}.fa-house-chimney-user:before{content:"\e065"}.fa-house-chimney-window:before{content:"\e00d"}.fa-house-circle-check:before{content:"\e509"}.fa-house-circle-exclamation:before{content:"\e50a"}.fa-house-circle-xmark:before{content:"\e50b"}.fa-house-crack:before{content:"\e3b1"}.fa-house-fire:before{content:"\e50c"}.fa-house-flag:before{content:"\e50d"}.fa-house-flood-water:before{content:"\e50e"}.fa-house-flood-water-circle-arrow-right:before{content:"\e50f"}.fa-house-laptop:before,.fa-laptop-house:before{content:"\e066"}.fa-house-lock:before{content:"\e510"}.fa-house-medical:before{content:"\e3b2"}.fa-house-medical-circle-check:before{content:"\e511"}.fa-house-medical-circle-exclamation:before{content:"\e512"}.fa-house-medical-circle-xmark:before{content:"\e513"}.fa-house-medical-flag:before{content:"\e514"}.fa-house-signal:before{content:"\e012"}.fa-house-tsunami:before{content:"\e515"}.fa-home-user:before,.fa-house-user:before{content:"\e1b0"}.fa-hryvnia-sign:before,.fa-hryvnia:before{content:"\f6f2"}.fa-hurricane:before{content:"\f751"}.fa-i:before{content:"\49"}.fa-i-cursor:before{content:"\f246"}.fa-ice-cream:before{content:"\f810"}.fa-icicles:before{content:"\f7ad"}.fa-heart-music-camera-bolt:before,.fa-icons:before{content:"\f86d"}.fa-id-badge:before{content:"\f2c1"}.fa-drivers-license:before,.fa-id-card:before{content:"\f2c2"}.fa-id-card-alt:before,.fa-id-card-clip:before{content:"\f47f"}.fa-igloo:before{content:"\f7ae"}.fa-image:before{content:"\f03e"}.fa-image-portrait:before,.fa-portrait:before{content:"\f3e0"}.fa-images:before{content:"\f302"}.fa-inbox:before{content:"\f01c"}.fa-indent:before{content:"\f03c"}.fa-indian-rupee-sign:before,.fa-indian-rupee:before,.fa-inr:before{content:"\e1bc"}.fa-industry:before{content:"\f275"}.fa-infinity:before{content:"\f534"}.fa-info:before{content:"\f129"}.fa-italic:before{content:"\f033"}.fa-j:before{content:"\4a"}.fa-jar:before{content:"\e516"}.fa-jar-wheat:before{content:"\e517"}.fa-jedi:before{content:"\f669"}.fa-fighter-jet:before,.fa-jet-fighter:before{content:"\f0fb"}.fa-jet-fighter-up:before{content:"\e518"}.fa-joint:before{content:"\f595"}.fa-jug-detergent:before{content:"\e519"}.fa-k:before{content:"\4b"}.fa-kaaba:before{content:"\f66b"}.fa-key:before{content:"\f084"}.fa-keyboard:before{content:"\f11c"}.fa-khanda:before{content:"\f66d"}.fa-kip-sign:before{content:"\e1c4"}.fa-first-aid:before,.fa-kit-medical:before{content:"\f479"}.fa-kitchen-set:before{content:"\e51a"}.fa-kiwi-bird:before{content:"\f535"}.fa-l:before{content:"\4c"}.fa-land-mine-on:before{content:"\e51b"}.fa-landmark:before{content:"\f66f"}.fa-landmark-alt:before,.fa-landmark-dome:before{content:"\f752"}.fa-landmark-flag:before{content:"\e51c"}.fa-language:before{content:"\f1ab"}.fa-laptop:before{content:"\f109"}.fa-laptop-code:before{content:"\f5fc"}.fa-laptop-file:before{content:"\e51d"}.fa-laptop-medical:before{content:"\f812"}.fa-lari-sign:before{content:"\e1c8"}.fa-layer-group:before{content:"\f5fd"}.fa-leaf:before{content:"\f06c"}.fa-left-long:before,.fa-long-arrow-alt-left:before{content:"\f30a"}.fa-arrows-alt-h:before,.fa-left-right:before{content:"\f337"}.fa-lemon:before{content:"\f094"}.fa-less-than:before{content:"\3c"}.fa-less-than-equal:before{content:"\f537"}.fa-life-ring:before{content:"\f1cd"}.fa-lightbulb:before{content:"\f0eb"}.fa-lines-leaning:before{content:"\e51e"}.fa-chain:before,.fa-link:before{content:"\f0c1"}.fa-chain-broken:before,.fa-chain-slash:before,.fa-link-slash:before,.fa-unlink:before{content:"\f127"}.fa-lira-sign:before{content:"\f195"}.fa-list-squares:before,.fa-list:before{content:"\f03a"}.fa-list-check:before,.fa-tasks:before{content:"\f0ae"}.fa-list-1-2:before,.fa-list-numeric:before,.fa-list-ol:before{content:"\f0cb"}.fa-list-dots:before,.fa-list-ul:before{content:"\f0ca"}.fa-litecoin-sign:before{content:"\e1d3"}.fa-location-arrow:before{content:"\f124"}.fa-location-crosshairs:before,.fa-location:before{content:"\f601"}.fa-location-dot:before,.fa-map-marker-alt:before{content:"\f3c5"}.fa-location-pin:before,.fa-map-marker:before{content:"\f041"}.fa-location-pin-lock:before{content:"\e51f"}.fa-lock:before{content:"\f023"}.fa-lock-open:before{content:"\f3c1"}.fa-locust:before{content:"\e520"}.fa-lungs:before{content:"\f604"}.fa-lungs-virus:before{content:"\e067"}.fa-m:before{content:"\4d"}.fa-magnet:before{content:"\f076"}.fa-magnifying-glass:before,.fa-search:before{content:"\f002"}.fa-magnifying-glass-arrow-right:before{content:"\e521"}.fa-magnifying-glass-chart:before{content:"\e522"}.fa-magnifying-glass-dollar:before,.fa-search-dollar:before{content:"\f688"}.fa-magnifying-glass-location:before,.fa-search-location:before{content:"\f689"}.fa-magnifying-glass-minus:before,.fa-search-minus:before{content:"\f010"}.fa-magnifying-glass-plus:before,.fa-search-plus:before{content:"\f00e"}.fa-manat-sign:before{content:"\e1d5"}.fa-map:before{content:"\f279"}.fa-map-location:before,.fa-map-marked:before{content:"\f59f"}.fa-map-location-dot:before,.fa-map-marked-alt:before{content:"\f5a0"}.fa-map-pin:before{content:"\f276"}.fa-marker:before{content:"\f5a1"}.fa-mars:before{content:"\f222"}.fa-mars-and-venus:before{content:"\f224"}.fa-mars-and-venus-burst:before{content:"\e523"}.fa-mars-double:before{content:"\f227"}.fa-mars-stroke:before{content:"\f229"}.fa-mars-stroke-h:before,.fa-mars-stroke-right:before{content:"\f22b"}.fa-mars-stroke-up:before,.fa-mars-stroke-v:before{content:"\f22a"}.fa-glass-martini-alt:before,.fa-martini-glass:before{content:"\f57b"}.fa-cocktail:before,.fa-martini-glass-citrus:before{content:"\f561"}.fa-glass-martini:before,.fa-martini-glass-empty:before{content:"\f000"}.fa-mask:before{content:"\f6fa"}.fa-mask-face:before{content:"\e1d7"}.fa-mask-ventilator:before{content:"\e524"}.fa-masks-theater:before,.fa-theater-masks:before{content:"\f630"}.fa-mattress-pillow:before{content:"\e525"}.fa-expand-arrows-alt:before,.fa-maximize:before{content:"\f31e"}.fa-medal:before{content:"\f5a2"}.fa-memory:before{content:"\f538"}.fa-menorah:before{content:"\f676"}.fa-mercury:before{content:"\f223"}.fa-comment-alt:before,.fa-message:before{content:"\f27a"}.fa-meteor:before{content:"\f753"}.fa-microchip:before{content:"\f2db"}.fa-microphone:before{content:"\f130"}.fa-microphone-alt:before,.fa-microphone-lines:before{content:"\f3c9"}.fa-microphone-alt-slash:before,.fa-microphone-lines-slash:before{content:"\f539"}.fa-microphone-slash:before{content:"\f131"}.fa-microscope:before{content:"\f610"}.fa-mill-sign:before{content:"\e1ed"}.fa-compress-arrows-alt:before,.fa-minimize:before{content:"\f78c"}.fa-minus:before,.fa-subtract:before{content:"\f068"}.fa-mitten:before{content:"\f7b5"}.fa-mobile-android:before,.fa-mobile-phone:before,.fa-mobile:before{content:"\f3ce"}.fa-mobile-button:before{content:"\f10b"}.fa-mobile-retro:before{content:"\e527"}.fa-mobile-android-alt:before,.fa-mobile-screen:before{content:"\f3cf"}.fa-mobile-alt:before,.fa-mobile-screen-button:before{content:"\f3cd"}.fa-money-bill:before{content:"\f0d6"}.fa-money-bill-1:before,.fa-money-bill-alt:before{content:"\f3d1"}.fa-money-bill-1-wave:before,.fa-money-bill-wave-alt:before{content:"\f53b"}.fa-money-bill-transfer:before{content:"\e528"}.fa-money-bill-trend-up:before{content:"\e529"}.fa-money-bill-wave:before{content:"\f53a"}.fa-money-bill-wheat:before{content:"\e52a"}.fa-money-bills:before{content:"\e1f3"}.fa-money-check:before{content:"\f53c"}.fa-money-check-alt:before,.fa-money-check-dollar:before{content:"\f53d"}.fa-monument:before{content:"\f5a6"}.fa-moon:before{content:"\f186"}.fa-mortar-pestle:before{content:"\f5a7"}.fa-mosque:before{content:"\f678"}.fa-mosquito:before{content:"\e52b"}.fa-mosquito-net:before{content:"\e52c"}.fa-motorcycle:before{content:"\f21c"}.fa-mound:before{content:"\e52d"}.fa-mountain:before{content:"\f6fc"}.fa-mountain-city:before{content:"\e52e"}.fa-mountain-sun:before{content:"\e52f"}.fa-mug-hot:before{content:"\f7b6"}.fa-coffee:before,.fa-mug-saucer:before{content:"\f0f4"}.fa-music:before{content:"\f001"}.fa-n:before{content:"\4e"}.fa-naira-sign:before{content:"\e1f6"}.fa-network-wired:before{content:"\f6ff"}.fa-neuter:before{content:"\f22c"}.fa-newspaper:before{content:"\f1ea"}.fa-not-equal:before{content:"\f53e"}.fa-notdef:before{content:"\e1fe"}.fa-note-sticky:before,.fa-sticky-note:before{content:"\f249"}.fa-notes-medical:before{content:"\f481"}.fa-o:before{content:"\4f"}.fa-object-group:before{content:"\f247"}.fa-object-ungroup:before{content:"\f248"}.fa-oil-can:before{content:"\f613"}.fa-oil-well:before{content:"\e532"}.fa-om:before{content:"\f679"}.fa-otter:before{content:"\f700"}.fa-dedent:before,.fa-outdent:before{content:"\f03b"}.fa-p:before{content:"\50"}.fa-pager:before{content:"\f815"}.fa-paint-roller:before{content:"\f5aa"}.fa-paint-brush:before,.fa-paintbrush:before{content:"\f1fc"}.fa-palette:before{content:"\f53f"}.fa-pallet:before{content:"\f482"}.fa-panorama:before{content:"\e209"}.fa-paper-plane:before{content:"\f1d8"}.fa-paperclip:before{content:"\f0c6"}.fa-parachute-box:before{content:"\f4cd"}.fa-paragraph:before{content:"\f1dd"}.fa-passport:before{content:"\f5ab"}.fa-file-clipboard:before,.fa-paste:before{content:"\f0ea"}.fa-pause:before{content:"\f04c"}.fa-paw:before{content:"\f1b0"}.fa-peace:before{content:"\f67c"}.fa-pen:before{content:"\f304"}.fa-pen-alt:before,.fa-pen-clip:before{content:"\f305"}.fa-pen-fancy:before{content:"\f5ac"}.fa-pen-nib:before{content:"\f5ad"}.fa-pen-ruler:before,.fa-pencil-ruler:before{content:"\f5ae"}.fa-edit:before,.fa-pen-to-square:before{content:"\f044"}.fa-pencil-alt:before,.fa-pencil:before{content:"\f303"}.fa-people-arrows-left-right:before,.fa-people-arrows:before{content:"\e068"}.fa-people-carry-box:before,.fa-people-carry:before{content:"\f4ce"}.fa-people-group:before{content:"\e533"}.fa-people-line:before{content:"\e534"}.fa-people-pulling:before{content:"\e535"}.fa-people-robbery:before{content:"\e536"}.fa-people-roof:before{content:"\e537"}.fa-pepper-hot:before{content:"\f816"}.fa-percent:before,.fa-percentage:before{content:"\25"}.fa-male:before,.fa-person:before{content:"\f183"}.fa-person-arrow-down-to-line:before{content:"\e538"}.fa-person-arrow-up-from-line:before{content:"\e539"}.fa-biking:before,.fa-person-biking:before{content:"\f84a"}.fa-person-booth:before{content:"\f756"}.fa-person-breastfeeding:before{content:"\e53a"}.fa-person-burst:before{content:"\e53b"}.fa-person-cane:before{content:"\e53c"}.fa-person-chalkboard:before{content:"\e53d"}.fa-person-circle-check:before{content:"\e53e"}.fa-person-circle-exclamation:before{content:"\e53f"}.fa-person-circle-minus:before{content:"\e540"}.fa-person-circle-plus:before{content:"\e541"}.fa-person-circle-question:before{content:"\e542"}.fa-person-circle-xmark:before{content:"\e543"}.fa-digging:before,.fa-person-digging:before{content:"\f85e"}.fa-diagnoses:before,.fa-person-dots-from-line:before{content:"\f470"}.fa-female:before,.fa-person-dress:before{content:"\f182"}.fa-person-dress-burst:before{content:"\e544"}.fa-person-drowning:before{content:"\e545"}.fa-person-falling:before{content:"\e546"}.fa-person-falling-burst:before{content:"\e547"}.fa-person-half-dress:before{content:"\e548"}.fa-person-harassing:before{content:"\e549"}.fa-hiking:before,.fa-person-hiking:before{content:"\f6ec"}.fa-person-military-pointing:before{content:"\e54a"}.fa-person-military-rifle:before{content:"\e54b"}.fa-person-military-to-person:before{content:"\e54c"}.fa-person-praying:before,.fa-pray:before{content:"\f683"}.fa-person-pregnant:before{content:"\e31e"}.fa-person-rays:before{content:"\e54d"}.fa-person-rifle:before{content:"\e54e"}.fa-person-running:before,.fa-running:before{content:"\f70c"}.fa-person-shelter:before{content:"\e54f"}.fa-person-skating:before,.fa-skating:before{content:"\f7c5"}.fa-person-skiing:before,.fa-skiing:before{content:"\f7c9"}.fa-person-skiing-nordic:before,.fa-skiing-nordic:before{content:"\f7ca"}.fa-person-snowboarding:before,.fa-snowboarding:before{content:"\f7ce"}.fa-person-swimming:before,.fa-swimmer:before{content:"\f5c4"}.fa-person-through-window:before{content:"\e5a9"}.fa-person-walking:before,.fa-walking:before{content:"\f554"}.fa-person-walking-arrow-loop-left:before{content:"\e551"}.fa-person-walking-arrow-right:before{content:"\e552"}.fa-person-walking-dashed-line-arrow-right:before{content:"\e553"}.fa-person-walking-luggage:before{content:"\e554"}.fa-blind:before,.fa-person-walking-with-cane:before{content:"\f29d"}.fa-peseta-sign:before{content:"\e221"}.fa-peso-sign:before{content:"\e222"}.fa-phone:before{content:"\f095"}.fa-phone-alt:before,.fa-phone-flip:before{content:"\f879"}.fa-phone-slash:before{content:"\f3dd"}.fa-phone-volume:before,.fa-volume-control-phone:before{content:"\f2a0"}.fa-photo-film:before,.fa-photo-video:before{content:"\f87c"}.fa-piggy-bank:before{content:"\f4d3"}.fa-pills:before{content:"\f484"}.fa-pizza-slice:before{content:"\f818"}.fa-place-of-worship:before{content:"\f67f"}.fa-plane:before{content:"\f072"}.fa-plane-arrival:before{content:"\f5af"}.fa-plane-circle-check:before{content:"\e555"}.fa-plane-circle-exclamation:before{content:"\e556"}.fa-plane-circle-xmark:before{content:"\e557"}.fa-plane-departure:before{content:"\f5b0"}.fa-plane-lock:before{content:"\e558"}.fa-plane-slash:before{content:"\e069"}.fa-plane-up:before{content:"\e22d"}.fa-plant-wilt:before{content:"\e5aa"}.fa-plate-wheat:before{content:"\e55a"}.fa-play:before{content:"\f04b"}.fa-plug:before{content:"\f1e6"}.fa-plug-circle-bolt:before{content:"\e55b"}.fa-plug-circle-check:before{content:"\e55c"}.fa-plug-circle-exclamation:before{content:"\e55d"}.fa-plug-circle-minus:before{content:"\e55e"}.fa-plug-circle-plus:before{content:"\e55f"}.fa-plug-circle-xmark:before{content:"\e560"}.fa-add:before,.fa-plus:before{content:"\2b"}.fa-plus-minus:before{content:"\e43c"}.fa-podcast:before{content:"\f2ce"}.fa-poo:before{content:"\f2fe"}.fa-poo-bolt:before,.fa-poo-storm:before{content:"\f75a"}.fa-poop:before{content:"\f619"}.fa-power-off:before{content:"\f011"}.fa-prescription:before{content:"\f5b1"}.fa-prescription-bottle:before{content:"\f485"}.fa-prescription-bottle-alt:before,.fa-prescription-bottle-medical:before{content:"\f486"}.fa-print:before{content:"\f02f"}.fa-pump-medical:before{content:"\e06a"}.fa-pump-soap:before{content:"\e06b"}.fa-puzzle-piece:before{content:"\f12e"}.fa-q:before{content:"\51"}.fa-qrcode:before{content:"\f029"}.fa-question:before{content:"\3f"}.fa-quote-left-alt:before,.fa-quote-left:before{content:"\f10d"}.fa-quote-right-alt:before,.fa-quote-right:before{content:"\f10e"}.fa-r:before{content:"\52"}.fa-radiation:before{content:"\f7b9"}.fa-radio:before{content:"\f8d7"}.fa-rainbow:before{content:"\f75b"}.fa-ranking-star:before{content:"\e561"}.fa-receipt:before{content:"\f543"}.fa-record-vinyl:before{content:"\f8d9"}.fa-ad:before,.fa-rectangle-ad:before{content:"\f641"}.fa-list-alt:before,.fa-rectangle-list:before{content:"\f022"}.fa-rectangle-times:before,.fa-rectangle-xmark:before,.fa-times-rectangle:before,.fa-window-close:before{content:"\f410"}.fa-recycle:before{content:"\f1b8"}.fa-registered:before{content:"\f25d"}.fa-repeat:before{content:"\f363"}.fa-mail-reply:before,.fa-reply:before{content:"\f3e5"}.fa-mail-reply-all:before,.fa-reply-all:before{content:"\f122"}.fa-republican:before{content:"\f75e"}.fa-restroom:before{content:"\f7bd"}.fa-retweet:before{content:"\f079"}.fa-ribbon:before{content:"\f4d6"}.fa-right-from-bracket:before,.fa-sign-out-alt:before{content:"\f2f5"}.fa-exchange-alt:before,.fa-right-left:before{content:"\f362"}.fa-long-arrow-alt-right:before,.fa-right-long:before{content:"\f30b"}.fa-right-to-bracket:before,.fa-sign-in-alt:before{content:"\f2f6"}.fa-ring:before{content:"\f70b"}.fa-road:before{content:"\f018"}.fa-road-barrier:before{content:"\e562"}.fa-road-bridge:before{content:"\e563"}.fa-road-circle-check:before{content:"\e564"}.fa-road-circle-exclamation:before{content:"\e565"}.fa-road-circle-xmark:before{content:"\e566"}.fa-road-lock:before{content:"\e567"}.fa-road-spikes:before{content:"\e568"}.fa-robot:before{content:"\f544"}.fa-rocket:before{content:"\f135"}.fa-rotate:before,.fa-sync-alt:before{content:"\f2f1"}.fa-rotate-back:before,.fa-rotate-backward:before,.fa-rotate-left:before,.fa-undo-alt:before{content:"\f2ea"}.fa-redo-alt:before,.fa-rotate-forward:before,.fa-rotate-right:before{content:"\f2f9"}.fa-route:before{content:"\f4d7"}.fa-feed:before,.fa-rss:before{content:"\f09e"}.fa-rouble:before,.fa-rub:before,.fa-ruble-sign:before,.fa-ruble:before{content:"\f158"}.fa-rug:before{content:"\e569"}.fa-ruler:before{content:"\f545"}.fa-ruler-combined:before{content:"\f546"}.fa-ruler-horizontal:before{content:"\f547"}.fa-ruler-vertical:before{content:"\f548"}.fa-rupee-sign:before,.fa-rupee:before{content:"\f156"}.fa-rupiah-sign:before{content:"\e23d"}.fa-s:before{content:"\53"}.fa-sack-dollar:before{content:"\f81d"}.fa-sack-xmark:before{content:"\e56a"}.fa-sailboat:before{content:"\e445"}.fa-satellite:before{content:"\f7bf"}.fa-satellite-dish:before{content:"\f7c0"}.fa-balance-scale:before,.fa-scale-balanced:before{content:"\f24e"}.fa-balance-scale-left:before,.fa-scale-unbalanced:before{content:"\f515"}.fa-balance-scale-right:before,.fa-scale-unbalanced-flip:before{content:"\f516"}.fa-school:before{content:"\f549"}.fa-school-circle-check:before{content:"\e56b"}.fa-school-circle-exclamation:before{content:"\e56c"}.fa-school-circle-xmark:before{content:"\e56d"}.fa-school-flag:before{content:"\e56e"}.fa-school-lock:before{content:"\e56f"}.fa-cut:before,.fa-scissors:before{content:"\f0c4"}.fa-screwdriver:before{content:"\f54a"}.fa-screwdriver-wrench:before,.fa-tools:before{content:"\f7d9"}.fa-scroll:before{content:"\f70e"}.fa-scroll-torah:before,.fa-torah:before{content:"\f6a0"}.fa-sd-card:before{content:"\f7c2"}.fa-section:before{content:"\e447"}.fa-seedling:before,.fa-sprout:before{content:"\f4d8"}.fa-server:before{content:"\f233"}.fa-shapes:before,.fa-triangle-circle-square:before{content:"\f61f"}.fa-arrow-turn-right:before,.fa-mail-forward:before,.fa-share:before{content:"\f064"}.fa-share-from-square:before,.fa-share-square:before{content:"\f14d"}.fa-share-alt:before,.fa-share-nodes:before{content:"\f1e0"}.fa-sheet-plastic:before{content:"\e571"}.fa-ils:before,.fa-shekel-sign:before,.fa-shekel:before,.fa-sheqel-sign:before,.fa-sheqel:before{content:"\f20b"}.fa-shield-blank:before,.fa-shield:before{content:"\f132"}.fa-shield-cat:before{content:"\e572"}.fa-shield-dog:before{content:"\e573"}.fa-shield-alt:before,.fa-shield-halved:before{content:"\f3ed"}.fa-shield-heart:before{content:"\e574"}.fa-shield-virus:before{content:"\e06c"}.fa-ship:before{content:"\f21a"}.fa-shirt:before,.fa-t-shirt:before,.fa-tshirt:before{content:"\f553"}.fa-shoe-prints:before{content:"\f54b"}.fa-shop:before,.fa-store-alt:before{content:"\f54f"}.fa-shop-lock:before{content:"\e4a5"}.fa-shop-slash:before,.fa-store-alt-slash:before{content:"\e070"}.fa-shower:before{content:"\f2cc"}.fa-shrimp:before{content:"\e448"}.fa-random:before,.fa-shuffle:before{content:"\f074"}.fa-shuttle-space:before,.fa-space-shuttle:before{content:"\f197"}.fa-sign-hanging:before,.fa-sign:before{content:"\f4d9"}.fa-signal-5:before,.fa-signal-perfect:before,.fa-signal:before{content:"\f012"}.fa-signature:before{content:"\f5b7"}.fa-map-signs:before,.fa-signs-post:before{content:"\f277"}.fa-sim-card:before{content:"\f7c4"}.fa-sink:before{content:"\e06d"}.fa-sitemap:before{content:"\f0e8"}.fa-skull:before{content:"\f54c"}.fa-skull-crossbones:before{content:"\f714"}.fa-slash:before{content:"\f715"}.fa-sleigh:before{content:"\f7cc"}.fa-sliders-h:before,.fa-sliders:before{content:"\f1de"}.fa-smog:before{content:"\f75f"}.fa-smoking:before{content:"\f48d"}.fa-snowflake:before{content:"\f2dc"}.fa-snowman:before{content:"\f7d0"}.fa-snowplow:before{content:"\f7d2"}.fa-soap:before{content:"\e06e"}.fa-socks:before{content:"\f696"}.fa-solar-panel:before{content:"\f5ba"}.fa-sort:before,.fa-unsorted:before{content:"\f0dc"}.fa-sort-desc:before,.fa-sort-down:before{content:"\f0dd"}.fa-sort-asc:before,.fa-sort-up:before{content:"\f0de"}.fa-spa:before{content:"\f5bb"}.fa-pastafarianism:before,.fa-spaghetti-monster-flying:before{content:"\f67b"}.fa-spell-check:before{content:"\f891"}.fa-spider:before{content:"\f717"}.fa-spinner:before{content:"\f110"}.fa-splotch:before{content:"\f5bc"}.fa-spoon:before,.fa-utensil-spoon:before{content:"\f2e5"}.fa-spray-can:before{content:"\f5bd"}.fa-air-freshener:before,.fa-spray-can-sparkles:before{content:"\f5d0"}.fa-square:before{content:"\f0c8"}.fa-external-link-square:before,.fa-square-arrow-up-right:before{content:"\f14c"}.fa-caret-square-down:before,.fa-square-caret-down:before{content:"\f150"}.fa-caret-square-left:before,.fa-square-caret-left:before{content:"\f191"}.fa-caret-square-right:before,.fa-square-caret-right:before{content:"\f152"}.fa-caret-square-up:before,.fa-square-caret-up:before{content:"\f151"}.fa-check-square:before,.fa-square-check:before{content:"\f14a"}.fa-envelope-square:before,.fa-square-envelope:before{content:"\f199"}.fa-square-full:before{content:"\f45c"}.fa-h-square:before,.fa-square-h:before{content:"\f0fd"}.fa-minus-square:before,.fa-square-minus:before{content:"\f146"}.fa-square-nfi:before{content:"\e576"}.fa-parking:before,.fa-square-parking:before{content:"\f540"}.fa-pen-square:before,.fa-pencil-square:before,.fa-square-pen:before{content:"\f14b"}.fa-square-person-confined:before{content:"\e577"}.fa-phone-square:before,.fa-square-phone:before{content:"\f098"}.fa-phone-square-alt:before,.fa-square-phone-flip:before{content:"\f87b"}.fa-plus-square:before,.fa-square-plus:before{content:"\f0fe"}.fa-poll-h:before,.fa-square-poll-horizontal:before{content:"\f682"}.fa-poll:before,.fa-square-poll-vertical:before{content:"\f681"}.fa-square-root-alt:before,.fa-square-root-variable:before{content:"\f698"}.fa-rss-square:before,.fa-square-rss:before{content:"\f143"}.fa-share-alt-square:before,.fa-square-share-nodes:before{content:"\f1e1"}.fa-external-link-square-alt:before,.fa-square-up-right:before{content:"\f360"}.fa-square-virus:before{content:"\e578"}.fa-square-xmark:before,.fa-times-square:before,.fa-xmark-square:before{content:"\f2d3"}.fa-rod-asclepius:before,.fa-rod-snake:before,.fa-staff-aesculapius:before,.fa-staff-snake:before{content:"\e579"}.fa-stairs:before{content:"\e289"}.fa-stamp:before{content:"\f5bf"}.fa-stapler:before{content:"\e5af"}.fa-star:before{content:"\f005"}.fa-star-and-crescent:before{content:"\f699"}.fa-star-half:before{content:"\f089"}.fa-star-half-alt:before,.fa-star-half-stroke:before{content:"\f5c0"}.fa-star-of-david:before{content:"\f69a"}.fa-star-of-life:before{content:"\f621"}.fa-gbp:before,.fa-pound-sign:before,.fa-sterling-sign:before{content:"\f154"}.fa-stethoscope:before{content:"\f0f1"}.fa-stop:before{content:"\f04d"}.fa-stopwatch:before{content:"\f2f2"}.fa-stopwatch-20:before{content:"\e06f"}.fa-store:before{content:"\f54e"}.fa-store-slash:before{content:"\e071"}.fa-street-view:before{content:"\f21d"}.fa-strikethrough:before{content:"\f0cc"}.fa-stroopwafel:before{content:"\f551"}.fa-subscript:before{content:"\f12c"}.fa-suitcase:before{content:"\f0f2"}.fa-medkit:before,.fa-suitcase-medical:before{content:"\f0fa"}.fa-suitcase-rolling:before{content:"\f5c1"}.fa-sun:before{content:"\f185"}.fa-sun-plant-wilt:before{content:"\e57a"}.fa-superscript:before{content:"\f12b"}.fa-swatchbook:before{content:"\f5c3"}.fa-synagogue:before{content:"\f69b"}.fa-syringe:before{content:"\f48e"}.fa-t:before{content:"\54"}.fa-table:before{content:"\f0ce"}.fa-table-cells:before,.fa-th:before{content:"\f00a"}.fa-table-cells-large:before,.fa-th-large:before{content:"\f009"}.fa-columns:before,.fa-table-columns:before{content:"\f0db"}.fa-table-list:before,.fa-th-list:before{content:"\f00b"}.fa-ping-pong-paddle-ball:before,.fa-table-tennis-paddle-ball:before,.fa-table-tennis:before{content:"\f45d"}.fa-tablet-android:before,.fa-tablet:before{content:"\f3fb"}.fa-tablet-button:before{content:"\f10a"}.fa-tablet-alt:before,.fa-tablet-screen-button:before{content:"\f3fa"}.fa-tablets:before{content:"\f490"}.fa-digital-tachograph:before,.fa-tachograph-digital:before{content:"\f566"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-tape:before{content:"\f4db"}.fa-tarp:before{content:"\e57b"}.fa-tarp-droplet:before{content:"\e57c"}.fa-cab:before,.fa-taxi:before{content:"\f1ba"}.fa-teeth:before{content:"\f62e"}.fa-teeth-open:before{content:"\f62f"}.fa-temperature-arrow-down:before,.fa-temperature-down:before{content:"\e03f"}.fa-temperature-arrow-up:before,.fa-temperature-up:before{content:"\e040"}.fa-temperature-0:before,.fa-temperature-empty:before,.fa-thermometer-0:before,.fa-thermometer-empty:before{content:"\f2cb"}.fa-temperature-4:before,.fa-temperature-full:before,.fa-thermometer-4:before,.fa-thermometer-full:before{content:"\f2c7"}.fa-temperature-2:before,.fa-temperature-half:before,.fa-thermometer-2:before,.fa-thermometer-half:before{content:"\f2c9"}.fa-temperature-high:before{content:"\f769"}.fa-temperature-low:before{content:"\f76b"}.fa-temperature-1:before,.fa-temperature-quarter:before,.fa-thermometer-1:before,.fa-thermometer-quarter:before{content:"\f2ca"}.fa-temperature-3:before,.fa-temperature-three-quarters:before,.fa-thermometer-3:before,.fa-thermometer-three-quarters:before{content:"\f2c8"}.fa-tenge-sign:before,.fa-tenge:before{content:"\f7d7"}.fa-tent:before{content:"\e57d"}.fa-tent-arrow-down-to-line:before{content:"\e57e"}.fa-tent-arrow-left-right:before{content:"\e57f"}.fa-tent-arrow-turn-left:before{content:"\e580"}.fa-tent-arrows-down:before{content:"\e581"}.fa-tents:before{content:"\e582"}.fa-terminal:before{content:"\f120"}.fa-text-height:before{content:"\f034"}.fa-remove-format:before,.fa-text-slash:before{content:"\f87d"}.fa-text-width:before{content:"\f035"}.fa-thermometer:before{content:"\f491"}.fa-thumbs-down:before{content:"\f165"}.fa-thumbs-up:before{content:"\f164"}.fa-thumb-tack:before,.fa-thumbtack:before{content:"\f08d"}.fa-ticket:before{content:"\f145"}.fa-ticket-alt:before,.fa-ticket-simple:before{content:"\f3ff"}.fa-timeline:before{content:"\e29c"}.fa-toggle-off:before{content:"\f204"}.fa-toggle-on:before{content:"\f205"}.fa-toilet:before{content:"\f7d8"}.fa-toilet-paper:before{content:"\f71e"}.fa-toilet-paper-slash:before{content:"\e072"}.fa-toilet-portable:before{content:"\e583"}.fa-toilets-portable:before{content:"\e584"}.fa-toolbox:before{content:"\f552"}.fa-tooth:before{content:"\f5c9"}.fa-torii-gate:before{content:"\f6a1"}.fa-tornado:before{content:"\f76f"}.fa-broadcast-tower:before,.fa-tower-broadcast:before{content:"\f519"}.fa-tower-cell:before{content:"\e585"}.fa-tower-observation:before{content:"\e586"}.fa-tractor:before{content:"\f722"}.fa-trademark:before{content:"\f25c"}.fa-traffic-light:before{content:"\f637"}.fa-trailer:before{content:"\e041"}.fa-train:before{content:"\f238"}.fa-subway:before,.fa-train-subway:before{content:"\f239"}.fa-train-tram:before{content:"\e5b4"}.fa-transgender-alt:before,.fa-transgender:before{content:"\f225"}.fa-trash:before{content:"\f1f8"}.fa-trash-arrow-up:before,.fa-trash-restore:before{content:"\f829"}.fa-trash-alt:before,.fa-trash-can:before{content:"\f2ed"}.fa-trash-can-arrow-up:before,.fa-trash-restore-alt:before{content:"\f82a"}.fa-tree:before{content:"\f1bb"}.fa-tree-city:before{content:"\e587"}.fa-exclamation-triangle:before,.fa-triangle-exclamation:before,.fa-warning:before{content:"\f071"}.fa-trophy:before{content:"\f091"}.fa-trowel:before{content:"\e589"}.fa-trowel-bricks:before{content:"\e58a"}.fa-truck:before{content:"\f0d1"}.fa-truck-arrow-right:before{content:"\e58b"}.fa-truck-droplet:before{content:"\e58c"}.fa-shipping-fast:before,.fa-truck-fast:before{content:"\f48b"}.fa-truck-field:before{content:"\e58d"}.fa-truck-field-un:before{content:"\e58e"}.fa-truck-front:before{content:"\e2b7"}.fa-ambulance:before,.fa-truck-medical:before{content:"\f0f9"}.fa-truck-monster:before{content:"\f63b"}.fa-truck-moving:before{content:"\f4df"}.fa-truck-pickup:before{content:"\f63c"}.fa-truck-plane:before{content:"\e58f"}.fa-truck-loading:before,.fa-truck-ramp-box:before{content:"\f4de"}.fa-teletype:before,.fa-tty:before{content:"\f1e4"}.fa-try:before,.fa-turkish-lira-sign:before,.fa-turkish-lira:before{content:"\e2bb"}.fa-level-down-alt:before,.fa-turn-down:before{content:"\f3be"}.fa-level-up-alt:before,.fa-turn-up:before{content:"\f3bf"}.fa-television:before,.fa-tv-alt:before,.fa-tv:before{content:"\f26c"}.fa-u:before{content:"\55"}.fa-umbrella:before{content:"\f0e9"}.fa-umbrella-beach:before{content:"\f5ca"}.fa-underline:before{content:"\f0cd"}.fa-universal-access:before{content:"\f29a"}.fa-unlock:before{content:"\f09c"}.fa-unlock-alt:before,.fa-unlock-keyhole:before{content:"\f13e"}.fa-arrows-alt-v:before,.fa-up-down:before{content:"\f338"}.fa-arrows-alt:before,.fa-up-down-left-right:before{content:"\f0b2"}.fa-long-arrow-alt-up:before,.fa-up-long:before{content:"\f30c"}.fa-expand-alt:before,.fa-up-right-and-down-left-from-center:before{content:"\f424"}.fa-external-link-alt:before,.fa-up-right-from-square:before{content:"\f35d"}.fa-upload:before{content:"\f093"}.fa-user:before{content:"\f007"}.fa-user-astronaut:before{content:"\f4fb"}.fa-user-check:before{content:"\f4fc"}.fa-user-clock:before{content:"\f4fd"}.fa-user-doctor:before,.fa-user-md:before{content:"\f0f0"}.fa-user-cog:before,.fa-user-gear:before{content:"\f4fe"}.fa-user-graduate:before{content:"\f501"}.fa-user-friends:before,.fa-user-group:before{content:"\f500"}.fa-user-injured:before{content:"\f728"}.fa-user-alt:before,.fa-user-large:before{content:"\f406"}.fa-user-alt-slash:before,.fa-user-large-slash:before{content:"\f4fa"}.fa-user-lock:before{content:"\f502"}.fa-user-minus:before{content:"\f503"}.fa-user-ninja:before{content:"\f504"}.fa-user-nurse:before{content:"\f82f"}.fa-user-edit:before,.fa-user-pen:before{content:"\f4ff"}.fa-user-plus:before{content:"\f234"}.fa-user-secret:before{content:"\f21b"}.fa-user-shield:before{content:"\f505"}.fa-user-slash:before{content:"\f506"}.fa-user-tag:before{content:"\f507"}.fa-user-tie:before{content:"\f508"}.fa-user-times:before,.fa-user-xmark:before{content:"\f235"}.fa-users:before{content:"\f0c0"}.fa-users-between-lines:before{content:"\e591"}.fa-users-cog:before,.fa-users-gear:before{content:"\f509"}.fa-users-line:before{content:"\e592"}.fa-users-rays:before{content:"\e593"}.fa-users-rectangle:before{content:"\e594"}.fa-users-slash:before{content:"\e073"}.fa-users-viewfinder:before{content:"\e595"}.fa-cutlery:before,.fa-utensils:before{content:"\f2e7"}.fa-v:before{content:"\56"}.fa-shuttle-van:before,.fa-van-shuttle:before{content:"\f5b6"}.fa-vault:before{content:"\e2c5"}.fa-vector-square:before{content:"\f5cb"}.fa-venus:before{content:"\f221"}.fa-venus-double:before{content:"\f226"}.fa-venus-mars:before{content:"\f228"}.fa-vest:before{content:"\e085"}.fa-vest-patches:before{content:"\e086"}.fa-vial:before{content:"\f492"}.fa-vial-circle-check:before{content:"\e596"}.fa-vial-virus:before{content:"\e597"}.fa-vials:before{content:"\f493"}.fa-video-camera:before,.fa-video:before{content:"\f03d"}.fa-video-slash:before{content:"\f4e2"}.fa-vihara:before{content:"\f6a7"}.fa-virus:before{content:"\e074"}.fa-virus-covid:before{content:"\e4a8"}.fa-virus-covid-slash:before{content:"\e4a9"}.fa-virus-slash:before{content:"\e075"}.fa-viruses:before{content:"\e076"}.fa-voicemail:before{content:"\f897"}.fa-volcano:before{content:"\f770"}.fa-volleyball-ball:before,.fa-volleyball:before{content:"\f45f"}.fa-volume-high:before,.fa-volume-up:before{content:"\f028"}.fa-volume-down:before,.fa-volume-low:before{content:"\f027"}.fa-volume-off:before{content:"\f026"}.fa-volume-mute:before,.fa-volume-times:before,.fa-volume-xmark:before{content:"\f6a9"}.fa-vr-cardboard:before{content:"\f729"}.fa-w:before{content:"\57"}.fa-walkie-talkie:before{content:"\f8ef"}.fa-wallet:before{content:"\f555"}.fa-magic:before,.fa-wand-magic:before{content:"\f0d0"}.fa-magic-wand-sparkles:before,.fa-wand-magic-sparkles:before{content:"\e2ca"}.fa-wand-sparkles:before{content:"\f72b"}.fa-warehouse:before{content:"\f494"}.fa-water:before{content:"\f773"}.fa-ladder-water:before,.fa-swimming-pool:before,.fa-water-ladder:before{content:"\f5c5"}.fa-wave-square:before{content:"\f83e"}.fa-weight-hanging:before{content:"\f5cd"}.fa-weight-scale:before,.fa-weight:before{content:"\f496"}.fa-wheat-alt:before,.fa-wheat-awn:before{content:"\e2cd"}.fa-wheat-awn-circle-exclamation:before{content:"\e598"}.fa-wheelchair:before{content:"\f193"}.fa-wheelchair-alt:before,.fa-wheelchair-move:before{content:"\e2ce"}.fa-glass-whiskey:before,.fa-whiskey-glass:before{content:"\f7a0"}.fa-wifi-3:before,.fa-wifi-strong:before,.fa-wifi:before{content:"\f1eb"}.fa-wind:before{content:"\f72e"}.fa-window-maximize:before{content:"\f2d0"}.fa-window-minimize:before{content:"\f2d1"}.fa-window-restore:before{content:"\f2d2"}.fa-wine-bottle:before{content:"\f72f"}.fa-wine-glass:before{content:"\f4e3"}.fa-wine-glass-alt:before,.fa-wine-glass-empty:before{content:"\f5ce"}.fa-krw:before,.fa-won-sign:before,.fa-won:before{content:"\f159"}.fa-worm:before{content:"\e599"}.fa-wrench:before{content:"\f0ad"}.fa-x:before{content:"\58"}.fa-x-ray:before{content:"\f497"}.fa-close:before,.fa-multiply:before,.fa-remove:before,.fa-times:before,.fa-xmark:before{content:"\f00d"}.fa-xmarks-lines:before{content:"\e59a"}.fa-y:before{content:"\59"}.fa-cny:before,.fa-jpy:before,.fa-rmb:before,.fa-yen-sign:before,.fa-yen:before{content:"\f157"}.fa-yin-yang:before{content:"\f6ad"}.fa-z:before{content:"\5a"}.fa-sr-only,.fa-sr-only-focusable:not(:focus),.sr-only,.sr-only-focusable:not(:focus){position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}:host,:root{--fa-font-brands:normal 400 1em/1 "Font Awesome 6 Brands"}@font-face{font-family:"Font Awesome 6 Brands";font-style:normal;font-weight:400;font-display:block;src:url(../webfonts/fa-brands-400.woff2) format("woff2"),url(../webfonts/fa-brands-400.ttf) format("truetype")}.fa-brands,.fab{font-family:"Font Awesome 6 Brands";font-weight:400}.fa-42-group:before,.fa-innosoft:before{content:"\e080"}.fa-500px:before{content:"\f26e"}.fa-accessible-icon:before{content:"\f368"}.fa-accusoft:before{content:"\f369"}.fa-adn:before{content:"\f170"}.fa-adversal:before{content:"\f36a"}.fa-affiliatetheme:before{content:"\f36b"}.fa-airbnb:before{content:"\f834"}.fa-algolia:before{content:"\f36c"}.fa-alipay:before{content:"\f642"}.fa-amazon:before{content:"\f270"}.fa-amazon-pay:before{content:"\f42c"}.fa-amilia:before{content:"\f36d"}.fa-android:before{content:"\f17b"}.fa-angellist:before{content:"\f209"}.fa-angrycreative:before{content:"\f36e"}.fa-angular:before{content:"\f420"}.fa-app-store:before{content:"\f36f"}.fa-app-store-ios:before{content:"\f370"}.fa-apper:before{content:"\f371"}.fa-apple:before{content:"\f179"}.fa-apple-pay:before{content:"\f415"}.fa-artstation:before{content:"\f77a"}.fa-asymmetrik:before{content:"\f372"}.fa-atlassian:before{content:"\f77b"}.fa-audible:before{content:"\f373"}.fa-autoprefixer:before{content:"\f41c"}.fa-avianex:before{content:"\f374"}.fa-aviato:before{content:"\f421"}.fa-aws:before{content:"\f375"}.fa-bandcamp:before{content:"\f2d5"}.fa-battle-net:before{content:"\f835"}.fa-behance:before{content:"\f1b4"}.fa-bilibili:before{content:"\e3d9"}.fa-bimobject:before{content:"\f378"}.fa-bitbucket:before{content:"\f171"}.fa-bitcoin:before{content:"\f379"}.fa-bity:before{content:"\f37a"}.fa-black-tie:before{content:"\f27e"}.fa-blackberry:before{content:"\f37b"}.fa-blogger:before{content:"\f37c"}.fa-blogger-b:before{content:"\f37d"}.fa-bluetooth:before{content:"\f293"}.fa-bluetooth-b:before{content:"\f294"}.fa-bootstrap:before{content:"\f836"}.fa-bots:before{content:"\e340"}.fa-btc:before{content:"\f15a"}.fa-buffer:before{content:"\f837"}.fa-buromobelexperte:before{content:"\f37f"}.fa-buy-n-large:before{content:"\f8a6"}.fa-buysellads:before{content:"\f20d"}.fa-canadian-maple-leaf:before{content:"\f785"}.fa-cc-amazon-pay:before{content:"\f42d"}.fa-cc-amex:before{content:"\f1f3"}.fa-cc-apple-pay:before{content:"\f416"}.fa-cc-diners-club:before{content:"\f24c"}.fa-cc-discover:before{content:"\f1f2"}.fa-cc-jcb:before{content:"\f24b"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-cc-paypal:before{content:"\f1f4"}.fa-cc-stripe:before{content:"\f1f5"}.fa-cc-visa:before{content:"\f1f0"}.fa-centercode:before{content:"\f380"}.fa-centos:before{content:"\f789"}.fa-chrome:before{content:"\f268"}.fa-chromecast:before{content:"\f838"}.fa-cloudflare:before{content:"\e07d"}.fa-cloudscale:before{content:"\f383"}.fa-cloudsmith:before{content:"\f384"}.fa-cloudversify:before{content:"\f385"}.fa-cmplid:before{content:"\e360"}.fa-codepen:before{content:"\f1cb"}.fa-codiepie:before{content:"\f284"}.fa-confluence:before{content:"\f78d"}.fa-connectdevelop:before{content:"\f20e"}.fa-contao:before{content:"\f26d"}.fa-cotton-bureau:before{content:"\f89e"}.fa-cpanel:before{content:"\f388"}.fa-creative-commons:before{content:"\f25e"}.fa-creative-commons-by:before{content:"\f4e7"}.fa-creative-commons-nc:before{content:"\f4e8"}.fa-creative-commons-nc-eu:before{content:"\f4e9"}.fa-creative-commons-nc-jp:before{content:"\f4ea"}.fa-creative-commons-nd:before{content:"\f4eb"}.fa-creative-commons-pd:before{content:"\f4ec"}.fa-creative-commons-pd-alt:before{content:"\f4ed"}.fa-creative-commons-remix:before{content:"\f4ee"}.fa-creative-commons-sa:before{content:"\f4ef"}.fa-creative-commons-sampling:before{content:"\f4f0"}.fa-creative-commons-sampling-plus:before{content:"\f4f1"}.fa-creative-commons-share:before{content:"\f4f2"}.fa-creative-commons-zero:before{content:"\f4f3"}.fa-critical-role:before{content:"\f6c9"}.fa-css3:before{content:"\f13c"}.fa-css3-alt:before{content:"\f38b"}.fa-cuttlefish:before{content:"\f38c"}.fa-d-and-d:before{content:"\f38d"}.fa-d-and-d-beyond:before{content:"\f6ca"}.fa-dailymotion:before{content:"\e052"}.fa-dashcube:before{content:"\f210"}.fa-deezer:before{content:"\e077"}.fa-delicious:before{content:"\f1a5"}.fa-deploydog:before{content:"\f38e"}.fa-deskpro:before{content:"\f38f"}.fa-dev:before{content:"\f6cc"}.fa-deviantart:before{content:"\f1bd"}.fa-dhl:before{content:"\f790"}.fa-diaspora:before{content:"\f791"}.fa-digg:before{content:"\f1a6"}.fa-digital-ocean:before{content:"\f391"}.fa-discord:before{content:"\f392"}.fa-discourse:before{content:"\f393"}.fa-dochub:before{content:"\f394"}.fa-docker:before{content:"\f395"}.fa-draft2digital:before{content:"\f396"}.fa-dribbble:before{content:"\f17d"}.fa-dropbox:before{content:"\f16b"}.fa-drupal:before{content:"\f1a9"}.fa-dyalog:before{content:"\f399"}.fa-earlybirds:before{content:"\f39a"}.fa-ebay:before{content:"\f4f4"}.fa-edge:before{content:"\f282"}.fa-edge-legacy:before{content:"\e078"}.fa-elementor:before{content:"\f430"}.fa-ello:before{content:"\f5f1"}.fa-ember:before{content:"\f423"}.fa-empire:before{content:"\f1d1"}.fa-envira:before{content:"\f299"}.fa-erlang:before{content:"\f39d"}.fa-ethereum:before{content:"\f42e"}.fa-etsy:before{content:"\f2d7"}.fa-evernote:before{content:"\f839"}.fa-expeditedssl:before{content:"\f23e"}.fa-facebook:before{content:"\f09a"}.fa-facebook-f:before{content:"\f39e"}.fa-facebook-messenger:before{content:"\f39f"}.fa-fantasy-flight-games:before{content:"\f6dc"}.fa-fedex:before{content:"\f797"}.fa-fedora:before{content:"\f798"}.fa-figma:before{content:"\f799"}.fa-firefox:before{content:"\f269"}.fa-firefox-browser:before{content:"\e007"}.fa-first-order:before{content:"\f2b0"}.fa-first-order-alt:before{content:"\f50a"}.fa-firstdraft:before{content:"\f3a1"}.fa-flickr:before{content:"\f16e"}.fa-flipboard:before{content:"\f44d"}.fa-fly:before{content:"\f417"}.fa-font-awesome-flag:before,.fa-font-awesome-logo-full:before,.fa-font-awesome:before{content:"\f2b4"}.fa-fonticons:before{content:"\f280"}.fa-fonticons-fi:before{content:"\f3a2"}.fa-fort-awesome:before{content:"\f286"}.fa-fort-awesome-alt:before{content:"\f3a3"}.fa-forumbee:before{content:"\f211"}.fa-foursquare:before{content:"\f180"}.fa-free-code-camp:before{content:"\f2c5"}.fa-freebsd:before{content:"\f3a4"}.fa-fulcrum:before{content:"\f50b"}.fa-galactic-republic:before{content:"\f50c"}.fa-galactic-senate:before{content:"\f50d"}.fa-get-pocket:before{content:"\f265"}.fa-gg:before{content:"\f260"}.fa-gg-circle:before{content:"\f261"}.fa-git:before{content:"\f1d3"}.fa-git-alt:before{content:"\f841"}.fa-github:before{content:"\f09b"}.fa-github-alt:before{content:"\f113"}.fa-gitkraken:before{content:"\f3a6"}.fa-gitlab:before{content:"\f296"}.fa-gitter:before{content:"\f426"}.fa-glide:before{content:"\f2a5"}.fa-glide-g:before{content:"\f2a6"}.fa-gofore:before{content:"\f3a7"}.fa-golang:before{content:"\e40f"}.fa-goodreads:before{content:"\f3a8"}.fa-goodreads-g:before{content:"\f3a9"}.fa-google:before{content:"\f1a0"}.fa-google-drive:before{content:"\f3aa"}.fa-google-pay:before{content:"\e079"}.fa-google-play:before{content:"\f3ab"}.fa-google-plus:before{content:"\f2b3"}.fa-google-plus-g:before{content:"\f0d5"}.fa-google-wallet:before{content:"\f1ee"}.fa-gratipay:before{content:"\f184"}.fa-grav:before{content:"\f2d6"}.fa-gripfire:before{content:"\f3ac"}.fa-grunt:before{content:"\f3ad"}.fa-guilded:before{content:"\e07e"}.fa-gulp:before{content:"\f3ae"}.fa-hacker-news:before{content:"\f1d4"}.fa-hackerrank:before{content:"\f5f7"}.fa-hashnode:before{content:"\e499"}.fa-hips:before{content:"\f452"}.fa-hire-a-helper:before{content:"\f3b0"}.fa-hive:before{content:"\e07f"}.fa-hooli:before{content:"\f427"}.fa-hornbill:before{content:"\f592"}.fa-hotjar:before{content:"\f3b1"}.fa-houzz:before{content:"\f27c"}.fa-html5:before{content:"\f13b"}.fa-hubspot:before{content:"\f3b2"}.fa-ideal:before{content:"\e013"}.fa-imdb:before{content:"\f2d8"}.fa-instagram:before{content:"\f16d"}.fa-instalod:before{content:"\e081"}.fa-intercom:before{content:"\f7af"}.fa-internet-explorer:before{content:"\f26b"}.fa-invision:before{content:"\f7b0"}.fa-ioxhost:before{content:"\f208"}.fa-itch-io:before{content:"\f83a"}.fa-itunes:before{content:"\f3b4"}.fa-itunes-note:before{content:"\f3b5"}.fa-java:before{content:"\f4e4"}.fa-jedi-order:before{content:"\f50e"}.fa-jenkins:before{content:"\f3b6"}.fa-jira:before{content:"\f7b1"}.fa-joget:before{content:"\f3b7"}.fa-joomla:before{content:"\f1aa"}.fa-js:before{content:"\f3b8"}.fa-jsfiddle:before{content:"\f1cc"}.fa-kaggle:before{content:"\f5fa"}.fa-keybase:before{content:"\f4f5"}.fa-keycdn:before{content:"\f3ba"}.fa-kickstarter:before{content:"\f3bb"}.fa-kickstarter-k:before{content:"\f3bc"}.fa-korvue:before{content:"\f42f"}.fa-laravel:before{content:"\f3bd"}.fa-lastfm:before{content:"\f202"}.fa-leanpub:before{content:"\f212"}.fa-less:before{content:"\f41d"}.fa-line:before{content:"\f3c0"}.fa-linkedin:before{content:"\f08c"}.fa-linkedin-in:before{content:"\f0e1"}.fa-linode:before{content:"\f2b8"}.fa-linux:before{content:"\f17c"}.fa-lyft:before{content:"\f3c3"}.fa-magento:before{content:"\f3c4"}.fa-mailchimp:before{content:"\f59e"}.fa-mandalorian:before{content:"\f50f"}.fa-markdown:before{content:"\f60f"}.fa-mastodon:before{content:"\f4f6"}.fa-maxcdn:before{content:"\f136"}.fa-mdb:before{content:"\f8ca"}.fa-medapps:before{content:"\f3c6"}.fa-medium-m:before,.fa-medium:before{content:"\f23a"}.fa-medrt:before{content:"\f3c8"}.fa-meetup:before{content:"\f2e0"}.fa-megaport:before{content:"\f5a3"}.fa-mendeley:before{content:"\f7b3"}.fa-meta:before{content:"\e49b"}.fa-microblog:before{content:"\e01a"}.fa-microsoft:before{content:"\f3ca"}.fa-mix:before{content:"\f3cb"}.fa-mixcloud:before{content:"\f289"}.fa-mixer:before{content:"\e056"}.fa-mizuni:before{content:"\f3cc"}.fa-modx:before{content:"\f285"}.fa-monero:before{content:"\f3d0"}.fa-napster:before{content:"\f3d2"}.fa-neos:before{content:"\f612"}.fa-nfc-directional:before{content:"\e530"}.fa-nfc-symbol:before{content:"\e531"}.fa-nimblr:before{content:"\f5a8"}.fa-node:before{content:"\f419"}.fa-node-js:before{content:"\f3d3"}.fa-npm:before{content:"\f3d4"}.fa-ns8:before{content:"\f3d5"}.fa-nutritionix:before{content:"\f3d6"}.fa-octopus-deploy:before{content:"\e082"}.fa-odnoklassniki:before{content:"\f263"}.fa-old-republic:before{content:"\f510"}.fa-opencart:before{content:"\f23d"}.fa-openid:before{content:"\f19b"}.fa-opera:before{content:"\f26a"}.fa-optin-monster:before{content:"\f23c"}.fa-orcid:before{content:"\f8d2"}.fa-osi:before{content:"\f41a"}.fa-padlet:before{content:"\e4a0"}.fa-page4:before{content:"\f3d7"}.fa-pagelines:before{content:"\f18c"}.fa-palfed:before{content:"\f3d8"}.fa-patreon:before{content:"\f3d9"}.fa-paypal:before{content:"\f1ed"}.fa-perbyte:before{content:"\e083"}.fa-periscope:before{content:"\f3da"}.fa-phabricator:before{content:"\f3db"}.fa-phoenix-framework:before{content:"\f3dc"}.fa-phoenix-squadron:before{content:"\f511"}.fa-php:before{content:"\f457"}.fa-pied-piper:before{content:"\f2ae"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-pied-piper-hat:before{content:"\f4e5"}.fa-pied-piper-pp:before{content:"\f1a7"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-p:before{content:"\f231"}.fa-pix:before{content:"\e43a"}.fa-playstation:before{content:"\f3df"}.fa-product-hunt:before{content:"\f288"}.fa-pushed:before{content:"\f3e1"}.fa-python:before{content:"\f3e2"}.fa-qq:before{content:"\f1d6"}.fa-quinscape:before{content:"\f459"}.fa-quora:before{content:"\f2c4"}.fa-r-project:before{content:"\f4f7"}.fa-raspberry-pi:before{content:"\f7bb"}.fa-ravelry:before{content:"\f2d9"}.fa-react:before{content:"\f41b"}.fa-reacteurope:before{content:"\f75d"}.fa-readme:before{content:"\f4d5"}.fa-rebel:before{content:"\f1d0"}.fa-red-river:before{content:"\f3e3"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-alien:before{content:"\f281"}.fa-redhat:before{content:"\f7bc"}.fa-renren:before{content:"\f18b"}.fa-replyd:before{content:"\f3e6"}.fa-researchgate:before{content:"\f4f8"}.fa-resolving:before{content:"\f3e7"}.fa-rev:before{content:"\f5b2"}.fa-rocketchat:before{content:"\f3e8"}.fa-rockrms:before{content:"\f3e9"}.fa-rust:before{content:"\e07a"}.fa-safari:before{content:"\f267"}.fa-salesforce:before{content:"\f83b"}.fa-sass:before{content:"\f41e"}.fa-schlix:before{content:"\f3ea"}.fa-screenpal:before{content:"\e570"}.fa-scribd:before{content:"\f28a"}.fa-searchengin:before{content:"\f3eb"}.fa-sellcast:before{content:"\f2da"}.fa-sellsy:before{content:"\f213"}.fa-servicestack:before{content:"\f3ec"}.fa-shirtsinbulk:before{content:"\f214"}.fa-shopify:before{content:"\e057"}.fa-shopware:before{content:"\f5b5"}.fa-simplybuilt:before{content:"\f215"}.fa-sistrix:before{content:"\f3ee"}.fa-sith:before{content:"\f512"}.fa-sitrox:before{content:"\e44a"}.fa-sketch:before{content:"\f7c6"}.fa-skyatlas:before{content:"\f216"}.fa-skype:before{content:"\f17e"}.fa-slack-hash:before,.fa-slack:before{content:"\f198"}.fa-slideshare:before{content:"\f1e7"}.fa-snapchat-ghost:before,.fa-snapchat:before{content:"\f2ab"}.fa-soundcloud:before{content:"\f1be"}.fa-sourcetree:before{content:"\f7d3"}.fa-space-awesome:before{content:"\e5ac"}.fa-speakap:before{content:"\f3f3"}.fa-speaker-deck:before{content:"\f83c"}.fa-spotify:before{content:"\f1bc"}.fa-behance-square:before,.fa-square-behance:before{content:"\f1b5"}.fa-dribbble-square:before,.fa-square-dribbble:before{content:"\f397"}.fa-facebook-square:before,.fa-square-facebook:before{content:"\f082"}.fa-square-font-awesome:before{content:"\e5ad"}.fa-font-awesome-alt:before,.fa-square-font-awesome-stroke:before{content:"\f35c"}.fa-git-square:before,.fa-square-git:before{content:"\f1d2"}.fa-github-square:before,.fa-square-github:before{content:"\f092"}.fa-gitlab-square:before,.fa-square-gitlab:before{content:"\e5ae"}.fa-google-plus-square:before,.fa-square-google-plus:before{content:"\f0d4"}.fa-hacker-news-square:before,.fa-square-hacker-news:before{content:"\f3af"}.fa-instagram-square:before,.fa-square-instagram:before{content:"\e055"}.fa-js-square:before,.fa-square-js:before{content:"\f3b9"}.fa-lastfm-square:before,.fa-square-lastfm:before{content:"\f203"}.fa-odnoklassniki-square:before,.fa-square-odnoklassniki:before{content:"\f264"}.fa-pied-piper-square:before,.fa-square-pied-piper:before{content:"\e01e"}.fa-pinterest-square:before,.fa-square-pinterest:before{content:"\f0d3"}.fa-reddit-square:before,.fa-square-reddit:before{content:"\f1a2"}.fa-snapchat-square:before,.fa-square-snapchat:before{content:"\f2ad"}.fa-square-steam:before,.fa-steam-square:before{content:"\f1b7"}.fa-square-tumblr:before,.fa-tumblr-square:before{content:"\f174"}.fa-square-twitter:before,.fa-twitter-square:before{content:"\f081"}.fa-square-viadeo:before,.fa-viadeo-square:before{content:"\f2aa"}.fa-square-vimeo:before,.fa-vimeo-square:before{content:"\f194"}.fa-square-whatsapp:before,.fa-whatsapp-square:before{content:"\f40c"}.fa-square-xing:before,.fa-xing-square:before{content:"\f169"}.fa-square-youtube:before,.fa-youtube-square:before{content:"\f431"}.fa-squarespace:before{content:"\f5be"}.fa-stack-exchange:before{content:"\f18d"}.fa-stack-overflow:before{content:"\f16c"}.fa-stackpath:before{content:"\f842"}.fa-staylinked:before{content:"\f3f5"}.fa-steam:before{content:"\f1b6"}.fa-steam-symbol:before{content:"\f3f6"}.fa-sticker-mule:before{content:"\f3f7"}.fa-strava:before{content:"\f428"}.fa-stripe:before{content:"\f429"}.fa-stripe-s:before{content:"\f42a"}.fa-studiovinari:before{content:"\f3f8"}.fa-stumbleupon:before{content:"\f1a4"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-superpowers:before{content:"\f2dd"}.fa-supple:before{content:"\f3f9"}.fa-suse:before{content:"\f7d6"}.fa-swift:before{content:"\f8e1"}.fa-symfony:before{content:"\f83d"}.fa-teamspeak:before{content:"\f4f9"}.fa-telegram-plane:before,.fa-telegram:before{content:"\f2c6"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-the-red-yeti:before{content:"\f69d"}.fa-themeco:before{content:"\f5c6"}.fa-themeisle:before{content:"\f2b2"}.fa-think-peaks:before{content:"\f731"}.fa-tiktok:before{content:"\e07b"}.fa-trade-federation:before{content:"\f513"}.fa-trello:before{content:"\f181"}.fa-tumblr:before{content:"\f173"}.fa-twitch:before{content:"\f1e8"}.fa-twitter:before{content:"\f099"}.fa-typo3:before{content:"\f42b"}.fa-uber:before{content:"\f402"}.fa-ubuntu:before{content:"\f7df"}.fa-uikit:before{content:"\f403"}.fa-umbraco:before{content:"\f8e8"}.fa-uncharted:before{content:"\e084"}.fa-uniregistry:before{content:"\f404"}.fa-unity:before{content:"\e049"}.fa-unsplash:before{content:"\e07c"}.fa-untappd:before{content:"\f405"}.fa-ups:before{content:"\f7e0"}.fa-usb:before{content:"\f287"}.fa-usps:before{content:"\f7e1"}.fa-ussunnah:before{content:"\f407"}.fa-vaadin:before{content:"\f408"}.fa-viacoin:before{content:"\f237"}.fa-viadeo:before{content:"\f2a9"}.fa-viber:before{content:"\f409"}.fa-vimeo:before{content:"\f40a"}.fa-vimeo-v:before{content:"\f27d"}.fa-vine:before{content:"\f1ca"}.fa-vk:before{content:"\f189"}.fa-vnv:before{content:"\f40b"}.fa-vuejs:before{content:"\f41f"}.fa-watchman-monitoring:before{content:"\e087"}.fa-waze:before{content:"\f83f"}.fa-weebly:before{content:"\f5cc"}.fa-weibo:before{content:"\f18a"}.fa-weixin:before{content:"\f1d7"}.fa-whatsapp:before{content:"\f232"}.fa-whmcs:before{content:"\f40d"}.fa-wikipedia-w:before{content:"\f266"}.fa-windows:before{content:"\f17a"}.fa-wirsindhandwerk:before,.fa-wsh:before{content:"\e2d0"}.fa-wix:before{content:"\f5cf"}.fa-wizards-of-the-coast:before{content:"\f730"}.fa-wodu:before{content:"\e088"}.fa-wolf-pack-battalion:before{content:"\f514"}.fa-wordpress:before{content:"\f19a"}.fa-wordpress-simple:before{content:"\f411"}.fa-wpbeginner:before{content:"\f297"}.fa-wpexplorer:before{content:"\f2de"}.fa-wpforms:before{content:"\f298"}.fa-rendact:before,.fa-wpressr:before{content:"\f3e4"}.fa-xbox:before{content:"\f412"}.fa-xing:before{content:"\f168"}.fa-y-combinator:before{content:"\f23b"}.fa-yahoo:before{content:"\f19e"}.fa-yammer:before{content:"\f840"}.fa-yandex:before{content:"\f413"}.fa-yandex-international:before{content:"\f414"}.fa-yarn:before{content:"\f7e3"}.fa-yelp:before{content:"\f1e9"}.fa-yoast:before{content:"\f2b1"}.fa-youtube:before{content:"\f167"}.fa-zhihu:before{content:"\f63f"}:host,:root{--fa-font-regular:normal 400 1em/1 "Font Awesome 6 Free"}@font-face{font-family:"Font Awesome 6 Free";font-style:normal;font-weight:400;font-display:block;src:url(../webfonts/fa-regular-400.woff2) format("woff2"),url(../webfonts/fa-regular-400.ttf) format("truetype")}.fa-regular,.far{font-family:"Font Awesome 6 Free";font-weight:400}:host,:root{--fa-font-solid:normal 900 1em/1 "Font Awesome 6 Free"}@font-face{font-family:"Font Awesome 6 Free";font-style:normal;font-weight:900;font-display:block;src:url(../webfonts/fa-solid-900.woff2) format("woff2"),url(../webfonts/fa-solid-900.ttf) format("truetype")}.fa-solid,.fas{font-family:"Font Awesome 6 Free";font-weight:900}@font-face{font-family:"Font Awesome 5 Brands";font-display:block;font-weight:400;src:url(../webfonts/fa-brands-400.woff2) format("woff2"),url(../webfonts/fa-brands-400.ttf) format("truetype")}@font-face{font-family:"Font Awesome 5 Free";font-display:block;font-weight:900;src:url(../webfonts/fa-solid-900.woff2) format("woff2"),url(../webfonts/fa-solid-900.ttf) format("truetype")}@font-face{font-family:"Font Awesome 5 Free";font-display:block;font-weight:400;src:url(../webfonts/fa-regular-400.woff2) format("woff2"),url(../webfonts/fa-regular-400.ttf) format("truetype")}@font-face{font-family:"FontAwesome";font-display:block;src:url(../webfonts/fa-solid-900.woff2) format("woff2"),url(../webfonts/fa-solid-900.ttf) format("truetype")}@font-face{font-family:"FontAwesome";font-display:block;src:url(../webfonts/fa-brands-400.woff2) format("woff2"),url(../webfonts/fa-brands-400.ttf) format("truetype")}@font-face{font-family:"FontAwesome";font-display:block;src:url(../webfonts/fa-regular-400.woff2) format("woff2"),url(../webfonts/fa-regular-400.ttf) format("truetype");unicode-range:u+f003,u+f006,u+f014,u+f016-f017,u+f01a-f01b,u+f01d,u+f022,u+f03e,u+f044,u+f046,u+f05c-f05d,u+f06e,u+f070,u+f087-f088,u+f08a,u+f094,u+f096-f097,u+f09d,u+f0a0,u+f0a2,u+f0a4-f0a7,u+f0c5,u+f0c7,u+f0e5-f0e6,u+f0eb,u+f0f6-f0f8,u+f10c,u+f114-f115,u+f118-f11a,u+f11c-f11d,u+f133,u+f147,u+f14e,u+f150-f152,u+f185-f186,u+f18e,u+f190-f192,u+f196,u+f1c1-f1c9,u+f1d9,u+f1db,u+f1e3,u+f1ea,u+f1f7,u+f1f9,u+f20a,u+f247-f248,u+f24a,u+f24d,u+f255-f25b,u+f25d,u+f271-f274,u+f278,u+f27b,u+f28c,u+f28e,u+f29c,u+f2b5,u+f2b7,u+f2ba,u+f2bc,u+f2be,u+f2c0-f2c1,u+f2c3,u+f2d0,u+f2d2,u+f2d4,u+f2dc}@font-face{font-family:"FontAwesome";font-display:block;src:url(../webfonts/fa-v4compatibility.woff2) format("woff2"),url(../webfonts/fa-v4compatibility.ttf) format("truetype");unicode-range:u+f041,u+f047,u+f065-f066,u+f07d-f07e,u+f080,u+f08b,u+f08e,u+f090,u+f09a,u+f0ac,u+f0ae,u+f0b2,u+f0d0,u+f0d6,u+f0e4,u+f0ec,u+f10a-f10b,u+f123,u+f13e,u+f148-f149,u+f14c,u+f156,u+f15e,u+f160-f161,u+f163,u+f175-f178,u+f195,u+f1f8,u+f219,u+f27a} \ No newline at end of file diff --git a/v0.10.x/_static/vendor/fontawesome/6.1.2/webfonts/fa-brands-400.ttf b/v0.10.x/_static/vendor/fontawesome/6.1.2/webfonts/fa-brands-400.ttf new file mode 100644 index 000000000..24ca8b17c Binary files /dev/null and b/v0.10.x/_static/vendor/fontawesome/6.1.2/webfonts/fa-brands-400.ttf differ diff --git a/v0.10.x/_static/vendor/fontawesome/6.1.2/webfonts/fa-brands-400.woff2 b/v0.10.x/_static/vendor/fontawesome/6.1.2/webfonts/fa-brands-400.woff2 new file mode 100644 index 000000000..e67e5cd53 Binary files /dev/null and b/v0.10.x/_static/vendor/fontawesome/6.1.2/webfonts/fa-brands-400.woff2 differ diff --git a/v0.10.x/_static/vendor/fontawesome/6.1.2/webfonts/fa-regular-400.ttf b/v0.10.x/_static/vendor/fontawesome/6.1.2/webfonts/fa-regular-400.ttf new file mode 100644 index 000000000..c5ac00957 Binary files /dev/null and b/v0.10.x/_static/vendor/fontawesome/6.1.2/webfonts/fa-regular-400.ttf differ diff --git a/v0.10.x/_static/vendor/fontawesome/6.1.2/webfonts/fa-regular-400.woff2 b/v0.10.x/_static/vendor/fontawesome/6.1.2/webfonts/fa-regular-400.woff2 new file mode 100644 index 000000000..7dca1d907 Binary files /dev/null and b/v0.10.x/_static/vendor/fontawesome/6.1.2/webfonts/fa-regular-400.woff2 differ diff --git a/v0.10.x/_static/vendor/fontawesome/6.1.2/webfonts/fa-solid-900.ttf b/v0.10.x/_static/vendor/fontawesome/6.1.2/webfonts/fa-solid-900.ttf new file mode 100644 index 000000000..43ba1cc7d Binary files /dev/null and b/v0.10.x/_static/vendor/fontawesome/6.1.2/webfonts/fa-solid-900.ttf differ diff --git a/v0.10.x/_static/vendor/fontawesome/6.1.2/webfonts/fa-solid-900.woff2 b/v0.10.x/_static/vendor/fontawesome/6.1.2/webfonts/fa-solid-900.woff2 new file mode 100644 index 000000000..4a7f96652 Binary files /dev/null and b/v0.10.x/_static/vendor/fontawesome/6.1.2/webfonts/fa-solid-900.woff2 differ diff --git a/v0.10.x/_static/vendor/fontawesome/6.1.2/webfonts/fa-v4compatibility.ttf b/v0.10.x/_static/vendor/fontawesome/6.1.2/webfonts/fa-v4compatibility.ttf new file mode 100644 index 000000000..243bc25bd Binary files /dev/null and b/v0.10.x/_static/vendor/fontawesome/6.1.2/webfonts/fa-v4compatibility.ttf differ diff --git a/v0.10.x/_static/vendor/fontawesome/6.1.2/webfonts/fa-v4compatibility.woff2 b/v0.10.x/_static/vendor/fontawesome/6.1.2/webfonts/fa-v4compatibility.woff2 new file mode 100644 index 000000000..e18a16d59 Binary files /dev/null and b/v0.10.x/_static/vendor/fontawesome/6.1.2/webfonts/fa-v4compatibility.woff2 differ diff --git a/v0.10.x/_static/vendor/fonts.css b/v0.10.x/_static/vendor/fonts.css new file mode 100644 index 000000000..8ac21d0f3 --- /dev/null +++ b/v0.10.x/_static/vendor/fonts.css @@ -0,0 +1,2 @@ +/* Impoting Syncopate for new logos */ +@import url('https://fonts.googleapis.com/css2?family=Syncopate:wght@700&display=swap'); diff --git a/v0.10.x/_static/vendor/full-video.css b/v0.10.x/_static/vendor/full-video.css new file mode 100644 index 000000000..af0f5d99a --- /dev/null +++ b/v0.10.x/_static/vendor/full-video.css @@ -0,0 +1,64 @@ +@import url('https://fonts.googleapis.com/css?family=Montserrat:400,600'); + +body { + font-family: 'Montserrat', sans-serif; + color: #2D3E50; +} +section { + max-width: 57%; + margin: auto; + text-align: center; +} +.wrapper { + height: 100vh; + display: flex; + align-items: center; + color: #FFF; +} +.video-wrap { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + overflow: hidden; +} +.video-wrap video { + min-width: 100%; + min-height: 100%; +} +.overlay { + z-index: 1; + height: 100%; + width: 100%; + top: 0; + left: 0; + background: #2D3E50; + position: absolute; + opacity: .2; +} +.landing-text { + z-index: 2; +} +h1 { + font-weight: 600; + font-size: 380%; +} +h3 { + font-size: 230%; + font-weight: 400; + margin-top: -4%; + padding-bottom: 3%; +} +.btn { + text-decoration: none; + color: #FFF; + font-size: 140%; + background: #2A80B9; + padding: 2% 3%; + border-radius: 5px; +} +p { + font-size: 130%; + padding: 3%; +} diff --git a/v0.10.x/_static/vendor/gallery.css b/v0.10.x/_static/vendor/gallery.css new file mode 100644 index 000000000..1c17453af --- /dev/null +++ b/v0.10.x/_static/vendor/gallery.css @@ -0,0 +1,101 @@ +.gallery { + padding: 30px; +} + +.gallery a:hover { + text-decoration: none; + color:black +} + +.gallery-title { + display: flex; + justify-content: center; + letter-spacing: 1.5px; + font-size: 27px; + font-weight: bold; +} + +.gallery-box-container { + display: flex; + flex-wrap: wrap; + justify-content: center; +} + +.gallery-box-content { + height: 450px; + min-width: 275px; + width: 350px; + margin: 30px auto; + border-radius: 3px; +} + +.gallery a { + color: rgb(1, 50, 67) !important; +} + +.gallery-box-title { + margin: 15px; + font-size: 16px; + text-transform: uppercase; + font-weight: bold; + text-align: center; +} + +.gallery-box-text { + margin: 30px 15px; + font-size: 14px; +} + +@media only screen and (max-width: 1300px) { + .gallery-box-container { + justify-content: center; + } +} + +@media only screen and (min-width: 600px) and (max-width: 700px) { + .gallery-box-container { + flex-direction: column; + align-items: center; + } +} + +@media only screen and (max-width: 600px) { + .gallery-title { + margin: 0; + } + .gallery-box-content { + width: auto; + } +} + +.gallery-underline { + display: inline-block; + vertical-align: middle; + -webkit-transform: perspective(1px) translateZ(0); + transform: perspective(1px) translateZ(0); + /* Black, with 10% opacity */ + box-shadow: 0px 8px 15px rgba(0, 0, 0, 0.1); + position: relative; + overflow: hidden; +} + +.gallery-underline:before { + content: ""; + position: absolute; + z-index: -1; + left: 0; + right: 100%; + bottom: 0; + background: rgb(1, 50, 67); + height: 4px; + -webkit-transition-property: right; + transition-property: right; + -webkit-transition-duration: 0.3s; + transition-duration: 0.3s; + -webkit-transition-timing-function: ease-out; + transition-timing-function: ease-out; +} + +.gallery-underline:hover:before, .gallery-underline:focus:before, .gallery-underline:active:before { + right: 0; +} diff --git a/v0.10.x/_static/vendor/icons.css b/v0.10.x/_static/vendor/icons.css new file mode 100644 index 000000000..ed7944a4b --- /dev/null +++ b/v0.10.x/_static/vendor/icons.css @@ -0,0 +1 @@ +@font-face{font-family:'FontAwesome';src:url('../fonts/fontawesome-webfont.eot?v=4.6.3');src:url('../fonts/fontawesome-webfont.eot?#iefix&v=4.6.3') format('embedded-opentype'),url('../fonts/fontawesome-webfont.woff2?v=4.6.3') format('woff2'),url('../fonts/fontawesome-webfont.woff?v=4.6.3') format('woff'),url('../fonts/fontawesome-webfont.ttf?v=4.6.3') format('truetype'),url('../fonts/fontawesome-webfont.svg?v=4.6.3#fontawesomeregular') format('svg');font-weight:normal;font-style:normal;}.fa{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;}.fa-lg{font-size:1.33333333em;line-height:0.75em;vertical-align:-15%;}.fa-2x{font-size:2em;}.fa-3x{font-size:3em;}.fa-4x{font-size:4em;}.fa-5x{font-size:5em;}.fa-fw{width:1.28571429em;text-align:center;}.fa-ul{padding-left:0;margin-left:2.14285714em;list-style-type:none;}.fa-ul>li{position:relative;}.fa-li{position:absolute;left:-2.14285714em;width:2.14285714em;top:0.14285714em;text-align:center;}.fa-li.fa-lg{left:-1.85714286em;}.fa-border{padding:.2em .25em .15em;border:solid 0.08em #eeeeee;border-radius:.1em;}.fa-pull-left{float:left;}.fa-pull-right{float:right;}.fa.fa-pull-left{margin-right:.3em;}.fa.fa-pull-right{margin-left:.3em;}.pull-right{float:right;}.pull-left{float:left;}.fa.pull-left{margin-right:.3em;}.fa.pull-right{margin-left:.3em;}.fa-spin{-webkit-animation:fa-spin 2s infinite linear;animation:fa-spin 2s infinite linear;}.fa-pulse{-webkit-animation:fa-spin 1s infinite steps(8);animation:fa-spin 1s infinite steps(8);}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg);}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg);}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg);}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg);}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg);}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg);}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg);}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";-webkit-transform:scale(-1,1);-ms-transform:scale(-1,1);transform:scale(-1,1);}.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)";-webkit-transform:scale(1,-1);-ms-transform:scale(1,-1);transform:scale(1,-1);}:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270,:root .fa-flip-horizontal,:root .fa-flip-vertical{filter:none;}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle;}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center;}.fa-stack-1x{line-height:inherit;}.fa-stack-2x{font-size:2em;}.fa-inverse{color:#ffffff;}.fa-glass:before{content:"\f000";}.fa-music:before{content:"\f001";}.fa-search:before{content:"\f002";}.fa-envelope-o:before{content:"\f003";}.fa-heart:before{content:"\f004";}.fa-star:before{content:"\f005";}.fa-star-o:before{content:"\f006";}.fa-user:before{content:"\f007";}.fa-film:before{content:"\f008";}.fa-th-large:before{content:"\f009";}.fa-th:before{content:"\f00a";}.fa-th-list:before{content:"\f00b";}.fa-check:before{content:"\f00c";}.fa-remove:before,.fa-close:before,.fa-times:before{content:"\f00d";}.fa-search-plus:before{content:"\f00e";}.fa-search-minus:before{content:"\f010";}.fa-power-off:before{content:"\f011";}.fa-signal:before{content:"\f012";}.fa-gear:before,.fa-cog:before{content:"\f013";}.fa-trash-o:before{content:"\f014";}.fa-home:before{content:"\f015";}.fa-file-o:before{content:"\f016";}.fa-clock-o:before{content:"\f017";}.fa-road:before{content:"\f018";}.fa-download:before{content:"\f019";}.fa-arrow-circle-o-down:before{content:"\f01a";}.fa-arrow-circle-o-up:before{content:"\f01b";}.fa-inbox:before{content:"\f01c";}.fa-play-circle-o:before{content:"\f01d";}.fa-rotate-right:before,.fa-repeat:before{content:"\f01e";}.fa-refresh:before{content:"\f021";}.fa-list-alt:before{content:"\f022";}.fa-lock:before{content:"\f023";}.fa-flag:before{content:"\f024";}.fa-headphones:before{content:"\f025";}.fa-volume-off:before{content:"\f026";}.fa-volume-down:before{content:"\f027";}.fa-volume-up:before{content:"\f028";}.fa-qrcode:before{content:"\f029";}.fa-barcode:before{content:"\f02a";}.fa-tag:before{content:"\f02b";}.fa-tags:before{content:"\f02c";}.fa-book:before{content:"\f02d";}.fa-bookmark:before{content:"\f02e";}.fa-print:before{content:"\f02f";}.fa-camera:before{content:"\f030";}.fa-font:before{content:"\f031";}.fa-bold:before{content:"\f032";}.fa-italic:before{content:"\f033";}.fa-text-height:before{content:"\f034";}.fa-text-width:before{content:"\f035";}.fa-align-left:before{content:"\f036";}.fa-align-center:before{content:"\f037";}.fa-align-right:before{content:"\f038";}.fa-align-justify:before{content:"\f039";}.fa-list:before{content:"\f03a";}.fa-dedent:before,.fa-outdent:before{content:"\f03b";}.fa-indent:before{content:"\f03c";}.fa-video-camera:before{content:"\f03d";}.fa-photo:before,.fa-image:before,.fa-picture-o:before{content:"\f03e";}.fa-pencil:before{content:"\f040";}.fa-map-marker:before{content:"\f041";}.fa-adjust:before{content:"\f042";}.fa-tint:before{content:"\f043";}.fa-edit:before,.fa-pencil-square-o:before{content:"\f044";}.fa-share-square-o:before{content:"\f045";}.fa-check-square-o:before{content:"\f046";}.fa-arrows:before{content:"\f047";}.fa-step-backward:before{content:"\f048";}.fa-fast-backward:before{content:"\f049";}.fa-backward:before{content:"\f04a";}.fa-play:before{content:"\f04b";}.fa-pause:before{content:"\f04c";}.fa-stop:before{content:"\f04d";}.fa-forward:before{content:"\f04e";}.fa-fast-forward:before{content:"\f050";}.fa-step-forward:before{content:"\f051";}.fa-eject:before{content:"\f052";}.fa-chevron-left:before{content:"\f053";}.fa-chevron-right:before{content:"\f054";}.fa-plus-circle:before{content:"\f055";}.fa-minus-circle:before{content:"\f056";}.fa-times-circle:before{content:"\f057";}.fa-check-circle:before{content:"\f058";}.fa-question-circle:before{content:"\f059";}.fa-info-circle:before{content:"\f05a";}.fa-crosshairs:before{content:"\f05b";}.fa-times-circle-o:before{content:"\f05c";}.fa-check-circle-o:before{content:"\f05d";}.fa-ban:before{content:"\f05e";}.fa-arrow-left:before{content:"\f060";}.fa-arrow-right:before{content:"\f061";}.fa-arrow-up:before{content:"\f062";}.fa-arrow-down:before{content:"\f063";}.fa-mail-forward:before,.fa-share:before{content:"\f064";}.fa-expand:before{content:"\f065";}.fa-compress:before{content:"\f066";}.fa-plus:before{content:"\f067";}.fa-minus:before{content:"\f068";}.fa-asterisk:before{content:"\f069";}.fa-exclamation-circle:before{content:"\f06a";}.fa-gift:before{content:"\f06b";}.fa-leaf:before{content:"\f06c";}.fa-fire:before{content:"\f06d";}.fa-eye:before{content:"\f06e";}.fa-eye-slash:before{content:"\f070";}.fa-warning:before,.fa-exclamation-triangle:before{content:"\f071";}.fa-plane:before{content:"\f072";}.fa-calendar:before{content:"\f073";}.fa-random:before{content:"\f074";}.fa-comment:before{content:"\f075";}.fa-magnet:before{content:"\f076";}.fa-chevron-up:before{content:"\f077";}.fa-chevron-down:before{content:"\f078";}.fa-retweet:before{content:"\f079";}.fa-shopping-cart:before{content:"\f07a";}.fa-folder:before{content:"\f07b";}.fa-folder-open:before{content:"\f07c";}.fa-arrows-v:before{content:"\f07d";}.fa-arrows-h:before{content:"\f07e";}.fa-bar-chart-o:before,.fa-bar-chart:before{content:"\f080";}.fa-twitter-square:before{content:"\f081";}.fa-facebook-square:before{content:"\f082";}.fa-camera-retro:before{content:"\f083";}.fa-key:before{content:"\f084";}.fa-gears:before,.fa-cogs:before{content:"\f085";}.fa-comments:before{content:"\f086";}.fa-thumbs-o-up:before{content:"\f087";}.fa-thumbs-o-down:before{content:"\f088";}.fa-star-half:before{content:"\f089";}.fa-heart-o:before{content:"\f08a";}.fa-sign-out:before{content:"\f08b";}.fa-linkedin-square:before{content:"\f08c";}.fa-thumb-tack:before{content:"\f08d";}.fa-external-link:before{content:"\f08e";}.fa-sign-in:before{content:"\f090";}.fa-trophy:before{content:"\f091";}.fa-github-square:before{content:"\f092";}.fa-upload:before{content:"\f093";}.fa-lemon-o:before{content:"\f094";}.fa-phone:before{content:"\f095";}.fa-square-o:before{content:"\f096";}.fa-bookmark-o:before{content:"\f097";}.fa-phone-square:before{content:"\f098";}.fa-twitter:before{content:"\f099";}.fa-facebook-f:before,.fa-facebook:before{content:"\f09a";}.fa-github:before{content:"\f09b";}.fa-unlock:before{content:"\f09c";}.fa-credit-card:before{content:"\f09d";}.fa-feed:before,.fa-rss:before{content:"\f09e";}.fa-hdd-o:before{content:"\f0a0";}.fa-bullhorn:before{content:"\f0a1";}.fa-bell:before{content:"\f0f3";}.fa-certificate:before{content:"\f0a3";}.fa-hand-o-right:before{content:"\f0a4";}.fa-hand-o-left:before{content:"\f0a5";}.fa-hand-o-up:before{content:"\f0a6";}.fa-hand-o-down:before{content:"\f0a7";}.fa-arrow-circle-left:before{content:"\f0a8";}.fa-arrow-circle-right:before{content:"\f0a9";}.fa-arrow-circle-up:before{content:"\f0aa";}.fa-arrow-circle-down:before{content:"\f0ab";}.fa-globe:before{content:"\f0ac";}.fa-wrench:before{content:"\f0ad";}.fa-tasks:before{content:"\f0ae";}.fa-filter:before{content:"\f0b0";}.fa-briefcase:before{content:"\f0b1";}.fa-arrows-alt:before{content:"\f0b2";}.fa-group:before,.fa-users:before{content:"\f0c0";}.fa-chain:before,.fa-link:before{content:"\f0c1";}.fa-cloud:before{content:"\f0c2";}.fa-flask:before{content:"\f0c3";}.fa-cut:before,.fa-scissors:before{content:"\f0c4";}.fa-copy:before,.fa-files-o:before{content:"\f0c5";}.fa-paperclip:before{content:"\f0c6";}.fa-save:before,.fa-floppy-o:before{content:"\f0c7";}.fa-square:before{content:"\f0c8";}.fa-navicon:before,.fa-reorder:before,.fa-bars:before{content:"\f0c9";}.fa-list-ul:before{content:"\f0ca";}.fa-list-ol:before{content:"\f0cb";}.fa-strikethrough:before{content:"\f0cc";}.fa-underline:before{content:"\f0cd";}.fa-table:before{content:"\f0ce";}.fa-magic:before{content:"\f0d0";}.fa-truck:before{content:"\f0d1";}.fa-pinterest:before{content:"\f0d2";}.fa-pinterest-square:before{content:"\f0d3";}.fa-google-plus-square:before{content:"\f0d4";}.fa-google-plus:before{content:"\f0d5";}.fa-money:before{content:"\f0d6";}.fa-caret-down:before{content:"\f0d7";}.fa-caret-up:before{content:"\f0d8";}.fa-caret-left:before{content:"\f0d9";}.fa-caret-right:before{content:"\f0da";}.fa-columns:before{content:"\f0db";}.fa-unsorted:before,.fa-sort:before{content:"\f0dc";}.fa-sort-down:before,.fa-sort-desc:before{content:"\f0dd";}.fa-sort-up:before,.fa-sort-asc:before{content:"\f0de";}.fa-envelope:before{content:"\f0e0";}.fa-linkedin:before{content:"\f0e1";}.fa-rotate-left:before,.fa-undo:before{content:"\f0e2";}.fa-legal:before,.fa-gavel:before{content:"\f0e3";}.fa-dashboard:before,.fa-tachometer:before{content:"\f0e4";}.fa-comment-o:before{content:"\f0e5";}.fa-comments-o:before{content:"\f0e6";}.fa-flash:before,.fa-bolt:before{content:"\f0e7";}.fa-sitemap:before{content:"\f0e8";}.fa-umbrella:before{content:"\f0e9";}.fa-paste:before,.fa-clipboard:before{content:"\f0ea";}.fa-lightbulb-o:before{content:"\f0eb";}.fa-exchange:before{content:"\f0ec";}.fa-cloud-download:before{content:"\f0ed";}.fa-cloud-upload:before{content:"\f0ee";}.fa-user-md:before{content:"\f0f0";}.fa-stethoscope:before{content:"\f0f1";}.fa-suitcase:before{content:"\f0f2";}.fa-bell-o:before{content:"\f0a2";}.fa-coffee:before{content:"\f0f4";}.fa-cutlery:before{content:"\f0f5";}.fa-file-text-o:before{content:"\f0f6";}.fa-building-o:before{content:"\f0f7";}.fa-hospital-o:before{content:"\f0f8";}.fa-ambulance:before{content:"\f0f9";}.fa-medkit:before{content:"\f0fa";}.fa-fighter-jet:before{content:"\f0fb";}.fa-beer:before{content:"\f0fc";}.fa-h-square:before{content:"\f0fd";}.fa-plus-square:before{content:"\f0fe";}.fa-angle-double-left:before{content:"\f100";}.fa-angle-double-right:before{content:"\f101";}.fa-angle-double-up:before{content:"\f102";}.fa-angle-double-down:before{content:"\f103";}.fa-angle-left:before{content:"\f104";}.fa-angle-right:before{content:"\f105";}.fa-angle-up:before{content:"\f106";}.fa-angle-down:before{content:"\f107";}.fa-desktop:before{content:"\f108";}.fa-laptop:before{content:"\f109";}.fa-tablet:before{content:"\f10a";}.fa-mobile-phone:before,.fa-mobile:before{content:"\f10b";}.fa-circle-o:before{content:"\f10c";}.fa-quote-left:before{content:"\f10d";}.fa-quote-right:before{content:"\f10e";}.fa-spinner:before{content:"\f110";}.fa-circle:before{content:"\f111";}.fa-mail-reply:before,.fa-reply:before{content:"\f112";}.fa-github-alt:before{content:"\f113";}.fa-folder-o:before{content:"\f114";}.fa-folder-open-o:before{content:"\f115";}.fa-smile-o:before{content:"\f118";}.fa-frown-o:before{content:"\f119";}.fa-meh-o:before{content:"\f11a";}.fa-gamepad:before{content:"\f11b";}.fa-keyboard-o:before{content:"\f11c";}.fa-flag-o:before{content:"\f11d";}.fa-flag-checkered:before{content:"\f11e";}.fa-terminal:before{content:"\f120";}.fa-code:before{content:"\f121";}.fa-mail-reply-all:before,.fa-reply-all:before{content:"\f122";}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:"\f123";}.fa-location-arrow:before{content:"\f124";}.fa-crop:before{content:"\f125";}.fa-code-fork:before{content:"\f126";}.fa-unlink:before,.fa-chain-broken:before{content:"\f127";}.fa-question:before{content:"\f128";}.fa-info:before{content:"\f129";}.fa-exclamation:before{content:"\f12a";}.fa-superscript:before{content:"\f12b";}.fa-subscript:before{content:"\f12c";}.fa-eraser:before{content:"\f12d";}.fa-puzzle-piece:before{content:"\f12e";}.fa-microphone:before{content:"\f130";}.fa-microphone-slash:before{content:"\f131";}.fa-shield:before{content:"\f132";}.fa-calendar-o:before{content:"\f133";}.fa-fire-extinguisher:before{content:"\f134";}.fa-rocket:before{content:"\f135";}.fa-maxcdn:before{content:"\f136";}.fa-chevron-circle-left:before{content:"\f137";}.fa-chevron-circle-right:before{content:"\f138";}.fa-chevron-circle-up:before{content:"\f139";}.fa-chevron-circle-down:before{content:"\f13a";}.fa-html5:before{content:"\f13b";}.fa-css3:before{content:"\f13c";}.fa-anchor:before{content:"\f13d";}.fa-unlock-alt:before{content:"\f13e";}.fa-bullseye:before{content:"\f140";}.fa-ellipsis-h:before{content:"\f141";}.fa-ellipsis-v:before{content:"\f142";}.fa-rss-square:before{content:"\f143";}.fa-play-circle:before{content:"\f144";}.fa-ticket:before{content:"\f145";}.fa-minus-square:before{content:"\f146";}.fa-minus-square-o:before{content:"\f147";}.fa-level-up:before{content:"\f148";}.fa-level-down:before{content:"\f149";}.fa-check-square:before{content:"\f14a";}.fa-pencil-square:before{content:"\f14b";}.fa-external-link-square:before{content:"\f14c";}.fa-share-square:before{content:"\f14d";}.fa-compass:before{content:"\f14e";}.fa-toggle-down:before,.fa-caret-square-o-down:before{content:"\f150";}.fa-toggle-up:before,.fa-caret-square-o-up:before{content:"\f151";}.fa-toggle-right:before,.fa-caret-square-o-right:before{content:"\f152";}.fa-euro:before,.fa-eur:before{content:"\f153";}.fa-gbp:before{content:"\f154";}.fa-dollar:before,.fa-usd:before{content:"\f155";}.fa-rupee:before,.fa-inr:before{content:"\f156";}.fa-cny:before,.fa-rmb:before,.fa-yen:before,.fa-jpy:before{content:"\f157";}.fa-ruble:before,.fa-rouble:before,.fa-rub:before{content:"\f158";}.fa-won:before,.fa-krw:before{content:"\f159";}.fa-bitcoin:before,.fa-btc:before{content:"\f15a";}.fa-file:before{content:"\f15b";}.fa-file-text:before{content:"\f15c";}.fa-sort-alpha-asc:before{content:"\f15d";}.fa-sort-alpha-desc:before{content:"\f15e";}.fa-sort-amount-asc:before{content:"\f160";}.fa-sort-amount-desc:before{content:"\f161";}.fa-sort-numeric-asc:before{content:"\f162";}.fa-sort-numeric-desc:before{content:"\f163";}.fa-thumbs-up:before{content:"\f164";}.fa-thumbs-down:before{content:"\f165";}.fa-youtube-square:before{content:"\f166";}.fa-youtube:before{content:"\f167";}.fa-xing:before{content:"\f168";}.fa-xing-square:before{content:"\f169";}.fa-youtube-play:before{content:"\f16a";}.fa-dropbox:before{content:"\f16b";}.fa-stack-overflow:before{content:"\f16c";}.fa-instagram:before{content:"\f16d";}.fa-flickr:before{content:"\f16e";}.fa-adn:before{content:"\f170";}.fa-bitbucket:before{content:"\f171";}.fa-bitbucket-square:before{content:"\f172";}.fa-tumblr:before{content:"\f173";}.fa-tumblr-square:before{content:"\f174";}.fa-long-arrow-down:before{content:"\f175";}.fa-long-arrow-up:before{content:"\f176";}.fa-long-arrow-left:before{content:"\f177";}.fa-long-arrow-right:before{content:"\f178";}.fa-apple:before{content:"\f179";}.fa-windows:before{content:"\f17a";}.fa-android:before{content:"\f17b";}.fa-linux:before{content:"\f17c";}.fa-dribbble:before{content:"\f17d";}.fa-skype:before{content:"\f17e";}.fa-foursquare:before{content:"\f180";}.fa-trello:before{content:"\f181";}.fa-female:before{content:"\f182";}.fa-male:before{content:"\f183";}.fa-gittip:before,.fa-gratipay:before{content:"\f184";}.fa-sun-o:before{content:"\f185";}.fa-moon-o:before{content:"\f186";}.fa-archive:before{content:"\f187";}.fa-bug:before{content:"\f188";}.fa-vk:before{content:"\f189";}.fa-weibo:before{content:"\f18a";}.fa-renren:before{content:"\f18b";}.fa-pagelines:before{content:"\f18c";}.fa-stack-exchange:before{content:"\f18d";}.fa-arrow-circle-o-right:before{content:"\f18e";}.fa-arrow-circle-o-left:before{content:"\f190";}.fa-toggle-left:before,.fa-caret-square-o-left:before{content:"\f191";}.fa-dot-circle-o:before{content:"\f192";}.fa-wheelchair:before{content:"\f193";}.fa-vimeo-square:before{content:"\f194";}.fa-turkish-lira:before,.fa-try:before{content:"\f195";}.fa-plus-square-o:before{content:"\f196";}.fa-space-shuttle:before{content:"\f197";}.fa-slack:before{content:"\f198";}.fa-envelope-square:before{content:"\f199";}.fa-wordpress:before{content:"\f19a";}.fa-openid:before{content:"\f19b";}.fa-institution:before,.fa-bank:before,.fa-university:before{content:"\f19c";}.fa-mortar-board:before,.fa-graduation-cap:before{content:"\f19d";}.fa-yahoo:before{content:"\f19e";}.fa-google:before{content:"\f1a0";}.fa-reddit:before{content:"\f1a1";}.fa-reddit-square:before{content:"\f1a2";}.fa-stumbleupon-circle:before{content:"\f1a3";}.fa-stumbleupon:before{content:"\f1a4";}.fa-delicious:before{content:"\f1a5";}.fa-digg:before{content:"\f1a6";}.fa-pied-piper-pp:before{content:"\f1a7";}.fa-pied-piper-alt:before{content:"\f1a8";}.fa-drupal:before{content:"\f1a9";}.fa-joomla:before{content:"\f1aa";}.fa-language:before{content:"\f1ab";}.fa-fax:before{content:"\f1ac";}.fa-building:before{content:"\f1ad";}.fa-child:before{content:"\f1ae";}.fa-paw:before{content:"\f1b0";}.fa-spoon:before{content:"\f1b1";}.fa-cube:before{content:"\f1b2";}.fa-cubes:before{content:"\f1b3";}.fa-behance:before{content:"\f1b4";}.fa-behance-square:before{content:"\f1b5";}.fa-steam:before{content:"\f1b6";}.fa-steam-square:before{content:"\f1b7";}.fa-recycle:before{content:"\f1b8";}.fa-automobile:before,.fa-car:before{content:"\f1b9";}.fa-cab:before,.fa-taxi:before{content:"\f1ba";}.fa-tree:before{content:"\f1bb";}.fa-spotify:before{content:"\f1bc";}.fa-deviantart:before{content:"\f1bd";}.fa-soundcloud:before{content:"\f1be";}.fa-database:before{content:"\f1c0";}.fa-file-pdf-o:before{content:"\f1c1";}.fa-file-word-o:before{content:"\f1c2";}.fa-file-excel-o:before{content:"\f1c3";}.fa-file-powerpoint-o:before{content:"\f1c4";}.fa-file-photo-o:before,.fa-file-picture-o:before,.fa-file-image-o:before{content:"\f1c5";}.fa-file-zip-o:before,.fa-file-archive-o:before{content:"\f1c6";}.fa-file-sound-o:before,.fa-file-audio-o:before{content:"\f1c7";}.fa-file-movie-o:before,.fa-file-video-o:before{content:"\f1c8";}.fa-file-code-o:before{content:"\f1c9";}.fa-vine:before{content:"\f1ca";}.fa-codepen:before{content:"\f1cb";}.fa-jsfiddle:before{content:"\f1cc";}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-saver:before,.fa-support:before,.fa-life-ring:before{content:"\f1cd";}.fa-circle-o-notch:before{content:"\f1ce";}.fa-ra:before,.fa-resistance:before,.fa-rebel:before{content:"\f1d0";}.fa-ge:before,.fa-empire:before{content:"\f1d1";}.fa-git-square:before{content:"\f1d2";}.fa-git:before{content:"\f1d3";}.fa-y-combinator-square:before,.fa-yc-square:before,.fa-hacker-news:before{content:"\f1d4";}.fa-tencent-weibo:before{content:"\f1d5";}.fa-qq:before{content:"\f1d6";}.fa-wechat:before,.fa-weixin:before{content:"\f1d7";}.fa-send:before,.fa-paper-plane:before{content:"\f1d8";}.fa-send-o:before,.fa-paper-plane-o:before{content:"\f1d9";}.fa-history:before{content:"\f1da";}.fa-circle-thin:before{content:"\f1db";}.fa-header:before{content:"\f1dc";}.fa-paragraph:before{content:"\f1dd";}.fa-sliders:before{content:"\f1de";}.fa-share-alt:before{content:"\f1e0";}.fa-share-alt-square:before{content:"\f1e1";}.fa-bomb:before{content:"\f1e2";}.fa-soccer-ball-o:before,.fa-futbol-o:before{content:"\f1e3";}.fa-tty:before{content:"\f1e4";}.fa-binoculars:before{content:"\f1e5";}.fa-plug:before{content:"\f1e6";}.fa-slideshare:before{content:"\f1e7";}.fa-twitch:before{content:"\f1e8";}.fa-yelp:before{content:"\f1e9";}.fa-newspaper-o:before{content:"\f1ea";}.fa-wifi:before{content:"\f1eb";}.fa-calculator:before{content:"\f1ec";}.fa-paypal:before{content:"\f1ed";}.fa-google-wallet:before{content:"\f1ee";}.fa-cc-visa:before{content:"\f1f0";}.fa-cc-mastercard:before{content:"\f1f1";}.fa-cc-discover:before{content:"\f1f2";}.fa-cc-amex:before{content:"\f1f3";}.fa-cc-paypal:before{content:"\f1f4";}.fa-cc-stripe:before{content:"\f1f5";}.fa-bell-slash:before{content:"\f1f6";}.fa-bell-slash-o:before{content:"\f1f7";}.fa-trash:before{content:"\f1f8";}.fa-copyright:before{content:"\f1f9";}.fa-at:before{content:"\f1fa";}.fa-eyedropper:before{content:"\f1fb";}.fa-paint-brush:before{content:"\f1fc";}.fa-birthday-cake:before{content:"\f1fd";}.fa-area-chart:before{content:"\f1fe";}.fa-pie-chart:before{content:"\f200";}.fa-line-chart:before{content:"\f201";}.fa-lastfm:before{content:"\f202";}.fa-lastfm-square:before{content:"\f203";}.fa-toggle-off:before{content:"\f204";}.fa-toggle-on:before{content:"\f205";}.fa-bicycle:before{content:"\f206";}.fa-bus:before{content:"\f207";}.fa-ioxhost:before{content:"\f208";}.fa-angellist:before{content:"\f209";}.fa-cc:before{content:"\f20a";}.fa-shekel:before,.fa-sheqel:before,.fa-ils:before{content:"\f20b";}.fa-meanpath:before{content:"\f20c";}.fa-buysellads:before{content:"\f20d";}.fa-connectdevelop:before{content:"\f20e";}.fa-dashcube:before{content:"\f210";}.fa-forumbee:before{content:"\f211";}.fa-leanpub:before{content:"\f212";}.fa-sellsy:before{content:"\f213";}.fa-shirtsinbulk:before{content:"\f214";}.fa-simplybuilt:before{content:"\f215";}.fa-skyatlas:before{content:"\f216";}.fa-cart-plus:before{content:"\f217";}.fa-cart-arrow-down:before{content:"\f218";}.fa-diamond:before{content:"\f219";}.fa-ship:before{content:"\f21a";}.fa-user-secret:before{content:"\f21b";}.fa-motorcycle:before{content:"\f21c";}.fa-street-view:before{content:"\f21d";}.fa-heartbeat:before{content:"\f21e";}.fa-venus:before{content:"\f221";}.fa-mars:before{content:"\f222";}.fa-mercury:before{content:"\f223";}.fa-intersex:before,.fa-transgender:before{content:"\f224";}.fa-transgender-alt:before{content:"\f225";}.fa-venus-double:before{content:"\f226";}.fa-mars-double:before{content:"\f227";}.fa-venus-mars:before{content:"\f228";}.fa-mars-stroke:before{content:"\f229";}.fa-mars-stroke-v:before{content:"\f22a";}.fa-mars-stroke-h:before{content:"\f22b";}.fa-neuter:before{content:"\f22c";}.fa-genderless:before{content:"\f22d";}.fa-facebook-official:before{content:"\f230";}.fa-pinterest-p:before{content:"\f231";}.fa-whatsapp:before{content:"\f232";}.fa-server:before{content:"\f233";}.fa-user-plus:before{content:"\f234";}.fa-user-times:before{content:"\f235";}.fa-hotel:before,.fa-bed:before{content:"\f236";}.fa-viacoin:before{content:"\f237";}.fa-train:before{content:"\f238";}.fa-subway:before{content:"\f239";}.fa-medium:before{content:"\f23a";}.fa-yc:before,.fa-y-combinator:before{content:"\f23b";}.fa-optin-monster:before{content:"\f23c";}.fa-opencart:before{content:"\f23d";}.fa-expeditedssl:before{content:"\f23e";}.fa-battery-4:before,.fa-battery-full:before{content:"\f240";}.fa-battery-3:before,.fa-battery-three-quarters:before{content:"\f241";}.fa-battery-2:before,.fa-battery-half:before{content:"\f242";}.fa-battery-1:before,.fa-battery-quarter:before{content:"\f243";}.fa-battery-0:before,.fa-battery-empty:before{content:"\f244";}.fa-mouse-pointer:before{content:"\f245";}.fa-i-cursor:before{content:"\f246";}.fa-object-group:before{content:"\f247";}.fa-object-ungroup:before{content:"\f248";}.fa-sticky-note:before{content:"\f249";}.fa-sticky-note-o:before{content:"\f24a";}.fa-cc-jcb:before{content:"\f24b";}.fa-cc-diners-club:before{content:"\f24c";}.fa-clone:before{content:"\f24d";}.fa-balance-scale:before{content:"\f24e";}.fa-hourglass-o:before{content:"\f250";}.fa-hourglass-1:before,.fa-hourglass-start:before{content:"\f251";}.fa-hourglass-2:before,.fa-hourglass-half:before{content:"\f252";}.fa-hourglass-3:before,.fa-hourglass-end:before{content:"\f253";}.fa-hourglass:before{content:"\f254";}.fa-hand-grab-o:before,.fa-hand-rock-o:before{content:"\f255";}.fa-hand-stop-o:before,.fa-hand-paper-o:before{content:"\f256";}.fa-hand-scissors-o:before{content:"\f257";}.fa-hand-lizard-o:before{content:"\f258";}.fa-hand-spock-o:before{content:"\f259";}.fa-hand-pointer-o:before{content:"\f25a";}.fa-hand-peace-o:before{content:"\f25b";}.fa-trademark:before{content:"\f25c";}.fa-registered:before{content:"\f25d";}.fa-creative-commons:before{content:"\f25e";}.fa-gg:before{content:"\f260";}.fa-gg-circle:before{content:"\f261";}.fa-tripadvisor:before{content:"\f262";}.fa-odnoklassniki:before{content:"\f263";}.fa-odnoklassniki-square:before{content:"\f264";}.fa-get-pocket:before{content:"\f265";}.fa-wikipedia-w:before{content:"\f266";}.fa-safari:before{content:"\f267";}.fa-chrome:before{content:"\f268";}.fa-firefox:before{content:"\f269";}.fa-opera:before{content:"\f26a";}.fa-internet-explorer:before{content:"\f26b";}.fa-tv:before,.fa-television:before{content:"\f26c";}.fa-contao:before{content:"\f26d";}.fa-500px:before{content:"\f26e";}.fa-amazon:before{content:"\f270";}.fa-calendar-plus-o:before{content:"\f271";}.fa-calendar-minus-o:before{content:"\f272";}.fa-calendar-times-o:before{content:"\f273";}.fa-calendar-check-o:before{content:"\f274";}.fa-industry:before{content:"\f275";}.fa-map-pin:before{content:"\f276";}.fa-map-signs:before{content:"\f277";}.fa-map-o:before{content:"\f278";}.fa-map:before{content:"\f279";}.fa-commenting:before{content:"\f27a";}.fa-commenting-o:before{content:"\f27b";}.fa-houzz:before{content:"\f27c";}.fa-vimeo:before{content:"\f27d";}.fa-black-tie:before{content:"\f27e";}.fa-fonticons:before{content:"\f280";}.fa-reddit-alien:before{content:"\f281";}.fa-edge:before{content:"\f282";}.fa-credit-card-alt:before{content:"\f283";}.fa-codiepie:before{content:"\f284";}.fa-modx:before{content:"\f285";}.fa-fort-awesome:before{content:"\f286";}.fa-usb:before{content:"\f287";}.fa-product-hunt:before{content:"\f288";}.fa-mixcloud:before{content:"\f289";}.fa-scribd:before{content:"\f28a";}.fa-pause-circle:before{content:"\f28b";}.fa-pause-circle-o:before{content:"\f28c";}.fa-stop-circle:before{content:"\f28d";}.fa-stop-circle-o:before{content:"\f28e";}.fa-shopping-bag:before{content:"\f290";}.fa-shopping-basket:before{content:"\f291";}.fa-hashtag:before{content:"\f292";}.fa-bluetooth:before{content:"\f293";}.fa-bluetooth-b:before{content:"\f294";}.fa-percent:before{content:"\f295";}.fa-gitlab:before{content:"\f296";}.fa-wpbeginner:before{content:"\f297";}.fa-wpforms:before{content:"\f298";}.fa-envira:before{content:"\f299";}.fa-universal-access:before{content:"\f29a";}.fa-wheelchair-alt:before{content:"\f29b";}.fa-question-circle-o:before{content:"\f29c";}.fa-blind:before{content:"\f29d";}.fa-audio-description:before{content:"\f29e";}.fa-volume-control-phone:before{content:"\f2a0";}.fa-braille:before{content:"\f2a1";}.fa-assistive-listening-systems:before{content:"\f2a2";}.fa-asl-interpreting:before,.fa-american-sign-language-interpreting:before{content:"\f2a3";}.fa-deafness:before,.fa-hard-of-hearing:before,.fa-deaf:before{content:"\f2a4";}.fa-glide:before{content:"\f2a5";}.fa-glide-g:before{content:"\f2a6";}.fa-signing:before,.fa-sign-language:before{content:"\f2a7";}.fa-low-vision:before{content:"\f2a8";}.fa-viadeo:before{content:"\f2a9";}.fa-viadeo-square:before{content:"\f2aa";}.fa-snapchat:before{content:"\f2ab";}.fa-snapchat-ghost:before{content:"\f2ac";}.fa-snapchat-square:before{content:"\f2ad";}.fa-pied-piper:before{content:"\f2ae";}.fa-first-order:before{content:"\f2b0";}.fa-yoast:before{content:"\f2b1";}.fa-themeisle:before{content:"\f2b2";}.fa-google-plus-circle:before,.fa-google-plus-official:before{content:"\f2b3";}.fa-fa:before,.fa-font-awesome:before{content:"\f2b4";}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0;}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto;}@font-face{font-family:'simple-line-icons';src:url('../fonts/simple-line-icons.eot?thkwh4');src:url('../fonts/simple-line-icons.eot?thkwh4#iefix') format('embedded-opentype'),url('../fonts/simple-line-icons.ttf?thkwh4') format('truetype'),url('../fonts/simple-line-icons.woff?thkwh4') format('woff'),url('../fonts/simple-line-icons.svg?thkwh4#simple-line-icons') format('svg');font-weight:normal;font-style:normal;}.sl{font-family:'simple-line-icons'!important;speak:none;font-style:normal;font-weight:normal;font-variant:normal;text-transform:none;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;}.sl-icon-user-female:before{content:"\e000";}.sl-icon-people:before{content:"\e001";}.sl-icon-user-follow:before{content:"\e002";}.sl-icon-user-following:before{content:"\e003";}.sl-icon-user-unfollow:before{content:"\e004";}.sl-icon-user:before{content:"\e005";}.sl-icon-trophy:before{content:"\e006";}.sl-icon-speedometer:before{content:"\e007";}.sl-icon-social-youtube:before{content:"\e008";}.sl-icon-social-twitter:before{content:"\e009";}.sl-icon-social-tumblr:before{content:"\e00a";}.sl-icon-social-facebook:before{content:"\e00b";}.sl-icon-social-dropbox:before{content:"\e00c";}.sl-icon-social-dribbble:before{content:"\e00d";}.sl-icon-shield:before{content:"\e00e";}.sl-icon-screen-tablet:before{content:"\e00f";}.sl-icon-screen-smartphone:before{content:"\e010";}.sl-icon-screen-desktop:before{content:"\e011";}.sl-icon-plane:before{content:"\e012";}.sl-icon-notebook:before{content:"\e013";}.sl-icon-mustache:before{content:"\e014";}.sl-icon-mouse:before{content:"\e015";}.sl-icon-magnet:before{content:"\e016";}.sl-icon-magic-wand:before{content:"\e017";}.sl-icon-hourglass:before{content:"\e018";}.sl-icon-graduation:before{content:"\e019";}.sl-icon-ghost:before{content:"\e01a";}.sl-icon-game-controller:before{content:"\e01b";}.sl-icon-fire:before{content:"\e01c";}.sl-icon-eyeglass:before{content:"\e01d";}.sl-icon-envelope-open:before{content:"\e01e";}.sl-icon-envolope-letter:before{content:"\e01f";}.sl-icon-energy:before{content:"\e020";}.sl-icon-emotsmile:before{content:"\e021";}.sl-icon-disc:before{content:"\e022";}.sl-icon-cursor-move:before{content:"\e023";}.sl-icon-crop:before{content:"\e024";}.sl-icon-credit-card:before{content:"\e025";}.sl-icon-chemistry:before{content:"\e026";}.sl-icon-bell:before{content:"\e027";}.sl-icon-badge:before{content:"\e028";}.sl-icon-anchor:before{content:"\e029";}.sl-icon-wallet:before{content:"\e02a";}.sl-icon-vector:before{content:"\e02b";}.sl-icon-speech:before{content:"\e02c";}.sl-icon-puzzle:before{content:"\e02d";}.sl-icon-printer:before{content:"\e02e";}.sl-icon-present:before{content:"\e02f";}.sl-icon-playlist:before{content:"\e030";}.sl-icon-pin:before{content:"\e031";}.sl-icon-picture:before{content:"\e032";}.sl-icon-map:before{content:"\e033";}.sl-icon-layers:before{content:"\e034";}.sl-icon-handbag:before{content:"\e035";}.sl-icon-globe-alt:before{content:"\e036";}.sl-icon-globe:before{content:"\e037";}.sl-icon-frame:before{content:"\e038";}.sl-icon-folder-alt:before{content:"\e039";}.sl-icon-film:before{content:"\e03a";}.sl-icon-feed:before{content:"\e03b";}.sl-icon-earphones-alt:before{content:"\e03c";}.sl-icon-earphones:before{content:"\e03d";}.sl-icon-drop:before{content:"\e03e";}.sl-icon-drawar:before{content:"\e03f";}.sl-icon-docs:before{content:"\e040";}.sl-icon-directions:before{content:"\e041";}.sl-icon-direction:before{content:"\e042";}.sl-icon-diamond:before{content:"\e043";}.sl-icon-cup:before{content:"\e044";}.sl-icon-compass:before{content:"\e045";}.sl-icon-call-out:before{content:"\e046";}.sl-icon-call-in:before{content:"\e047";}.sl-icon-call-end:before{content:"\e048";}.sl-icon-calculator:before{content:"\e049";}.sl-icon-bubbles:before{content:"\e04a";}.sl-icon-briefcase:before{content:"\e04b";}.sl-icon-book-open:before{content:"\e04c";}.sl-icon-basket-loaded:before{content:"\e04d";}.sl-icon-basket:before{content:"\e04e";}.sl-icon-bag:before{content:"\e04f";}.sl-icon-action-undo:before{content:"\e050";}.sl-icon-action-redo:before{content:"\e051";}.sl-icon-wrench:before{content:"\e052";}.sl-icon-umbrella:before{content:"\e053";}.sl-icon-trash:before{content:"\e054";}.sl-icon-tag:before{content:"\e055";}.sl-icon-support:before{content:"\e056";}.sl-icon-size-fullscreen:before{content:"\e057";}.sl-icon-size-actual:before{content:"\e058";}.sl-icon-shuffle:before{content:"\e059";}.sl-icon-share-alt:before{content:"\e05a";}.sl-icon-share:before{content:"\e05b";}.sl-icon-rocket:before{content:"\e05c";}.sl-icon-question:before{content:"\e05d";}.sl-icon-pie-chart:before{content:"\e05e";}.sl-icon-pencil:before{content:"\e05f";}.sl-icon-note:before{content:"\e060";}.sl-icon-music-tone-alt:before{content:"\e061";}.sl-icon-music-tone:before{content:"\e062";}.sl-icon-microphone:before{content:"\e063";}.sl-icon-loop:before{content:"\e064";}.sl-icon-logout:before{content:"\e065";}.sl-icon-login:before{content:"\e066";}.sl-icon-list:before{content:"\e067";}.sl-icon-like:before{content:"\e068";}.sl-icon-home:before{content:"\e069";}.sl-icon-grid:before{content:"\e06a";}.sl-icon-graph:before{content:"\e06b";}.sl-icon-equalizer:before{content:"\e06c";}.sl-icon-dislike:before{content:"\e06d";}.sl-icon-cursor:before{content:"\e06e";}.sl-icon-control-start:before{content:"\e06f";}.sl-icon-control-rewind:before{content:"\e070";}.sl-icon-control-play:before{content:"\e071";}.sl-icon-control-pause:before{content:"\e072";}.sl-icon-control-forward:before{content:"\e073";}.sl-icon-control-end:before{content:"\e074";}.sl-icon-calender:before{content:"\e075";}.sl-icon-bulb:before{content:"\e076";}.sl-icon-chart:before{content:"\e077";}.sl-icon-arrow-up-circle:before{content:"\e078";}.sl-icon-arrow-right-circle:before{content:"\e079";}.sl-icon-arrow-left-circle:before{content:"\e07a";}.sl-icon-arrow-down-circle:before{content:"\e07b";}.sl-icon-ban:before{content:"\e07c";}.sl-icon-bubble:before{content:"\e07d";}.sl-icon-camrecorder:before{content:"\e07e";}.sl-icon-camera:before{content:"\e07f";}.sl-icon-check:before{content:"\e080";}.sl-icon-clock:before{content:"\e081";}.sl-icon-close:before{content:"\e082";}.sl-icon-cloud-download:before{content:"\e083";}.sl-icon-cloud-upload:before{content:"\e084";}.sl-icon-doc:before{content:"\e085";}.sl-icon-envolope:before{content:"\e086";}.sl-icon-eye:before{content:"\e087";}.sl-icon-flag:before{content:"\e088";}.sl-icon-folder:before{content:"\e089";}.sl-icon-heart:before{content:"\e08a";}.sl-icon-info:before{content:"\e08b";}.sl-icon-key:before{content:"\e08c";}.sl-icon-link:before{content:"\e08d";}.sl-icon-lock:before{content:"\e08e";}.sl-icon-lock-open:before{content:"\e08f";}.sl-icon-magnifier:before{content:"\e090";}.sl-icon-magnifier-add:before{content:"\e091";}.sl-icon-magnifier-remove:before{content:"\e092";}.sl-icon-paper-clip:before{content:"\e093";}.sl-icon-paper-plane:before{content:"\e094";}.sl-icon-plus:before{content:"\e095";}.sl-icon-power:before{content:"\e097";}.sl-icon-refresh:before{content:"\e098";}.sl-icon-reload:before{content:"\e099";}.sl-icon-settings:before{content:"\e09a";}.sl-icon-star:before{content:"\e09b";}.sl-icon-symble-female:before{content:"\e09c";}.sl-icon-symbol-male:before{content:"\e09d";}.sl-icon-target:before{content:"\e09e";}.sl-icon-volume-1:before{content:"\e09f";}.sl-icon-volume-2:before{content:"\e0a0";}.sl-icon-volume-off:before{content:"\e0a1";}.sl-icon-phone:before{content:"\e600";}.sl-icon-Menu:before{content:"\e601";}.sl-icon-optionsvertical:before{content:"\e602";}.sl-icon-options:before{content:"\e603";}.sl-icon-arrow-down:before{content:"\e604";}.sl-icon-arrow-left:before{content:"\e605";}.sl-icon-arrow-right:before{content:"\e606";}.sl-icon-arrow-up:before{content:"\e607";}.sl-icon-thumbs-up:before{content:"\e80d";}.sl-icon-location:before{content:"\e810";} diff --git a/v0.10.x/_static/vendor/installtext.css b/v0.10.x/_static/vendor/installtext.css new file mode 100644 index 000000000..22e759fa4 --- /dev/null +++ b/v0.10.x/_static/vendor/installtext.css @@ -0,0 +1,57 @@ +#banner { + display: flex; + justify-content: center; + align-items: center; + width: 100vw; + min-height: 45px; + background-color: var(--colorPrimaryDark); + /* background-color: #fff; */ + color: var(--colorSecondaryLight); + white-space: nowrap; + text-align: center; + } + #banner-title { + display: flex; + justify-content: center; + letter-spacing: 1px; + font-size: 27px; + font-weight: bold; + margin: 10px; + margin-right: 20px; + color: #fff; + } + @media screen and (min-width: 769px) { + #banner-title { + padding-top: 20px; + font-size: 27px; + } + } + + @media screen and (max-width: 600px) { + #banner-title { + font-size: 20px; + } + } + + #banner-start { + text-align: center; + padding: 40px 0; + } + @media screen and (min-width: 769px) { + #banner-start { + padding: 40px 0; + font-size: 18px; + } + } + #banner-start-command { + background: #a00; + font-family: "Source Code Pro", Monaco, Menlo, Consolas, monospace; + /* color: var(--colorPrimaryDark); */ + display: inline-block; + padding: 15px 20px; + } + #banner-start-command:before { + content: "$"; + opacity: 0.5; + padding-right: 10px; + } diff --git a/v0.10.x/_static/vendor/keyfeatures.css b/v0.10.x/_static/vendor/keyfeatures.css new file mode 100644 index 000000000..1d66cff82 --- /dev/null +++ b/v0.10.x/_static/vendor/keyfeatures.css @@ -0,0 +1,111 @@ +.keyfeatures { + margin: 15px 0; +} + +.keyfeatures .container { + display: flex; + flex-direction: column; +} + +.keyfeatures-box-container { + display: flex; + flex-wrap: wrap; + justify-content: center; +} + +.keyfeatures-box-content { + height: 200px; + min-width: 275px; + width: 335px; + margin: 25px auto; + border-radius: 3px; +} + +.keyfeatures-box-title { + margin: 15px; + font-size: 16px; + text-transform: uppercase; +} + +.keyfeatures-box-text > a { + color: var(--colorPrimary); +} + +.keyfeatures-box-text { + margin: 15px; + font-size: 14px; + height: 6em; + overflow: hidden; +} + +.keyfeatures-box-text:after { + content: ""; + text-align: right; + position: absolute; + bottom:30px; + right: 0; + width: 70%; + height: 1.2em; + background: linear-gradient(to right, rgba(255, 255, 255, 0), rgba(255, 255, 255, 1) 50%); +} + +.keyfeatures-box-content:hover > .keyfeatures-box-text, .keyfeatures-box-content:focus > .keyfeatures-box-text, .keyfeatures-box-content:active > .keyfeatures-box-text { + color: var(--colorSecondaryDark); +} + +@media only screen and (max-width: 1280px) { + .keyfeatures .container { + align-items: center; + justify-content: center; + } + + .keyfeatures-box-container { + justify-content: center; + } +} + +@media only screen and (max-width: 1090px) { + .keyfeatures .container { + margin: 0 6vw; + } +} + +@media only screen and (max-width: 425px) { + .keyfeatures .container { + align-items: center; + justify-content: center; + margin: 0 10%; + } +} + +.keyfeatures-underline { + display: inline-block; + vertical-align: middle; + -webkit-transform: perspective(1px) translateZ(0); + transform: perspective(1px) translateZ(0); + /* Black, with 10% opacity */ + box-shadow: 0px 8px 15px var(--colorShadow); + position: relative; + overflow: hidden; +} + +.keyfeatures-underline:before { + content: ""; + position: absolute; + z-index: -1; + left: 0; + right: 100%; + bottom: 0; + background: #aa0000; + height: 4px; + -webkit-transition-property: right; + transition-property: right; + -webkit-transition-duration: 0.3s; + transition-duration: 0.3s; + -webkit-transition-timing-function: ease-out; + transition-timing-function: ease-out; +} + +.keyfeatures-underline:hover:before, .keyfeatures-underline:focus:before, .keyfeatures-underline:active:before { + right: 0; +} diff --git a/v0.10.x/_static/vendor/new-promotions.css b/v0.10.x/_static/vendor/new-promotions.css new file mode 100644 index 000000000..83668c091 --- /dev/null +++ b/v0.10.x/_static/vendor/new-promotions.css @@ -0,0 +1,19516 @@ +.no-m-top { + margin-top: 0 !important +} + +.xs-m-top { + margin-top: 8px !important +} + +.sm-m-top { + margin-top: 24px !important +} + +.md-m-top { + margin-top: 32px !important +} + +.ml-m-top { + margin-top: 40px !important +} + +.lg-m-top { + margin-top: 80px !important +} + +.xl-m-top { + margin-top: 104px !important +} + +.no-m-left { + margin-left: 0 !important +} + +.xs-m-left { + margin-left: 8px !important +} + +.sm-m-left { + margin-left: 24px !important +} + +.md-m-left { + margin-left: 32px !important +} + +.ml-m-left { + margin-left: 40px !important +} + +.lg-m-left { + margin-left: 80px !important +} + +.xl-m-left { + margin-left: 104px !important +} + +.no-m-right { + margin-right: 0 !important +} + +.xs-m-right { + margin-right: 8px !important +} + +.sm-m-right { + margin-right: 24px !important +} + +.md-m-right { + margin-right: 32px !important +} + +.ml-m-right { + margin-right: 40px !important +} + +.lg-m-right { + margin-right: 80px !important +} + +.xl-m-right { + margin-right: 104px !important +} + +.no-m-bottom { + margin-bottom: 0 !important +} + +.xs-m-bottom { + margin-bottom: 8px !important +} + +.sm-m-bottom { + margin-bottom: 24px !important +} + +.md-m-bottom { + margin-bottom: 32px !important +} + +.ml-m-bottom { + margin-bottom: 40px !important +} + +.lg-m-bottom { + margin-bottom: 80px !important +} + +.xl-m-bottom { + margin-bottom: 104px !important +} + +.no-p-top { + padding-top: 0 !important +} + +.xs-p-top { + padding-top: 8px !important +} + +.sm-p-top { + padding-top: 24px !important +} + +.md-p-top { + padding-top: 32px !important +} + +.ml-p-top { + padding-top: 40px !important +} + +.lg-p-top { + padding-top: 80px !important +} + +.xl-p-top { + padding-top: 104px !important +} + +.no-p-left { + padding-left: 0 !important +} + +.xs-p-left { + padding-left: 8px !important +} + +.sm-p-left { + padding-left: 24px !important +} + +.md-p-left { + padding-left: 32px !important +} + +.ml-p-left { + padding-left: 40px !important +} + +.lg-p-left { + padding-left: 80px !important +} + +.xl-p-left { + padding-left: 104px !important +} + +.no-p-right { + padding-right: 0 !important +} + +.xs-p-right { + padding-right: 8px !important +} + +.sm-p-right { + padding-right: 24px !important +} + +.md-p-right { + padding-right: 32px !important +} + +.ml-p-right { + padding-right: 40px !important +} + +.lg-p-right { + padding-right: 80px !important +} + +.xl-p-right { + padding-right: 104px !important +} + +.no-p-bottom { + padding-bottom: 0 !important +} + +.xs-p-bottom { + padding-bottom: 8px !important +} + +.sm-p-bottom { + padding-bottom: 24px !important +} + +.md-p-bottom { + padding-bottom: 32px !important +} + +.ml-p-bottom { + padding-bottom: 40px !important +} + +.lg-p-bottom { + padding-bottom: 80px !important +} + +.xl-p-bottom { + padding-bottom: 104px !important +} + +.bg-white { + background-color: #fff +} + +.bg-black { + background-color: #000 +} + +.bg-light-grey { + background-color: #ededed +} + +.bg-medium-grey { + background-color: #d8d8d8 +} + +.bg-dark-grey { + background-color: #212121 +} + +.color-white { + color: #fff +} + +.color-black { + color: #000 +} + +.color-light-grey { + color: #ededed +} + +.color-medium-grey { + color: #d8d8d8 +} + +.color-dark-grey { + color: #212121 +} + +html { + line-height: 1.15; + -webkit-text-size-adjust: 100% +} + +body { + margin: 0 +} + +h1 { + font-size: 2em; + margin: .67em 0 +} + +hr { + -webkit-box-sizing: content-box; + box-sizing: content-box; + height: 0; + overflow: visible +} + +pre { + font-family: monospace, monospace; + font-size: 1em +} + +a { + background-color: transparent +} + +abbr[title] { + border-bottom: none; + text-decoration: underline; + -webkit-text-decoration: underline dotted; + text-decoration: underline dotted +} + +b, +strong { + font-weight: bolder +} + +code, +kbd, +samp { + font-family: monospace, monospace; + font-size: 1em +} + +small { + font-size: 80% +} + +sub, +sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline +} + +sub { + bottom: -.25em +} + +sup { + top: -.5em +} + +img { + border-style: none +} + +button, +input, +optgroup, +select, +textarea { + font-family: inherit; + font-size: 100%; + line-height: 1.15; + margin: 0 +} + +button, +input { + overflow: visible +} + +button, +select { + text-transform: none +} + +[type=button], +[type=reset], +[type=submit], +button { + -webkit-appearance: button +} + +[type=button]::-moz-focus-inner, +[type=reset]::-moz-focus-inner, +[type=submit]::-moz-focus-inner, +button::-moz-focus-inner { + border-style: none; + padding: 0 +} + +[type=button]:-moz-focusring, +[type=reset]:-moz-focusring, +[type=submit]:-moz-focusring, +button:-moz-focusring { + outline: 1px dotted ButtonText +} + +fieldset { + padding: .35em .75em .625em +} + +legend { + -webkit-box-sizing: border-box; + box-sizing: border-box; + color: inherit; + display: table; + max-width: 100%; + padding: 0; + white-space: normal +} + +progress { + vertical-align: baseline +} + +textarea { + overflow: auto +} + +[type=checkbox], +[type=radio] { + -webkit-box-sizing: border-box; + box-sizing: border-box; + padding: 0 +} + +[type=number]::-webkit-inner-spin-button, +[type=number]::-webkit-outer-spin-button { + height: auto +} + +[type=search] { + -webkit-appearance: textfield; + outline-offset: -2px +} + +[type=search]::-webkit-search-decoration { + -webkit-appearance: none +} + +::-webkit-file-upload-button { + -webkit-appearance: button; + font: inherit +} + +details { + display: block +} + +summary { + display: list-item +} + +template { + display: none +} + +[hidden] { + display: none +} + +.container { + -webkit-box-sizing: border-box; + box-sizing: border-box; + max-width: 1230px; + margin: 0 auto +} + +.container-fluid { + margin-right: auto; + margin-left: auto; + padding-right: 15px; + padding-left: 15px +} + +.row { + -webkit-box-sizing: border-box; + box-sizing: border-box; + display: -webkit-box; + display: -moz-flex; + display: -ms-flexbox; + display: flex; + -webkit-box-flex: 0; + -moz-flex: 0 1 auto; + -ms-flex: 0 1 auto; + flex: 0 1 auto; + -webkit-box-direction: normal; + -webkit-box-orient: horizontal; + -moz-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; + -ms-flex-wrap: wrap; + flex-wrap: wrap; + margin-right: -15px; + margin-left: -15px +} + +.row.reverse { + -webkit-box-direction: reverse; + -webkit-box-orient: horizontal; + -moz-flex-direction: row-reverse; + -ms-flex-direction: row-reverse; + flex-direction: row-reverse +} + +.col.reverse { + -webkit-box-direction: reverse; + -webkit-box-orient: vertical; + -moz-flex-direction: column-reverse; + -ms-flex-direction: column-reverse; + flex-direction: column-reverse +} + +.col-xs { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + -ms-flex-preferred-size: auto; + flex-basis: auto +} + +.col-xs-1 { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + -ms-flex-preferred-size: 8.3333333333%; + flex-basis: 8.3333333333%; + max-width: 8.3333333333% +} + +.col-xs-2 { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + -ms-flex-preferred-size: 16.6666666667%; + flex-basis: 16.6666666667%; + max-width: 16.6666666667% +} + +.col-xs-3 { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + -ms-flex-preferred-size: 25%; + flex-basis: 25%; + max-width: 25% +} + +.col-xs-4 { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + -ms-flex-preferred-size: 33.3333333333%; + flex-basis: 33.3333333333%; + max-width: 33.3333333333% +} + +.col-xs-5 { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + -ms-flex-preferred-size: 41.6666666667%; + flex-basis: 41.6666666667%; + max-width: 41.6666666667% +} + +.col-xs-6 { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + -ms-flex-preferred-size: 50%; + flex-basis: 50%; + max-width: 50% +} + +.col-xs-7 { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + -ms-flex-preferred-size: 58.3333333333%; + flex-basis: 58.3333333333%; + max-width: 58.3333333333% +} + +.col-xs-8 { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + -ms-flex-preferred-size: 66.6666666667%; + flex-basis: 66.6666666667%; + max-width: 66.6666666667% +} + +.col-xs-9 { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + -ms-flex-preferred-size: 75%; + flex-basis: 75%; + max-width: 75% +} + +.col-xs-10 { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + -ms-flex-preferred-size: 83.3333333333%; + flex-basis: 83.3333333333%; + max-width: 83.3333333333% +} + +.col-xs-11 { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + -ms-flex-preferred-size: 91.6666666667%; + flex-basis: 91.6666666667%; + max-width: 91.6666666667% +} + +.col-xs-12 { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + -ms-flex-preferred-size: 100%; + flex-basis: 100%; + max-width: 100% +} + +.col-xs-offset-0 { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + margin-left: 0 +} + +.col-xs-offset-1 { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + margin-left: 8.3333333333% +} + +.col-xs-offset-2 { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + margin-left: 16.6666666667% +} + +.col-xs-offset-3 { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + margin-left: 25% +} + +.col-xs-offset-4 { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + margin-left: 33.3333333333% +} + +.col-xs-offset-5 { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + margin-left: 41.6666666667% +} + +.col-xs-offset-6 { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + margin-left: 50% +} + +.col-xs-offset-7 { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + margin-left: 58.3333333333% +} + +.col-xs-offset-8 { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + margin-left: 66.6666666667% +} + +.col-xs-offset-9 { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + margin-left: 75% +} + +.col-xs-offset-10 { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + margin-left: 83.3333333333% +} + +.col-xs-offset-11 { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + margin-left: 91.6666666667% +} + +.col-xs-offset-12 { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + margin-left: 100% +} + +.col-xs { + -webkit-box-flex: 1; + -moz-flex-grow: 1; + -ms-flex-positive: 1; + flex-grow: 1; + -ms-flex-preferred-size: 0; + flex-basis: 0; + max-width: 100% +} + +.start-xs { + -webkit-box-pack: start; + -ms-flex-pack: start; + -moz-justify-content: flex-start; + justify-content: flex-start; + text-align: left +} + +.center-xs { + -webkit-box-pack: center; + -ms-flex-pack: center; + -moz-justify-content: center; + justify-content: center; + text-align: center +} + +.end-xs { + -webkit-box-pack: end; + -ms-flex-pack: end; + -moz-justify-content: flex-end; + justify-content: flex-end; + text-align: right +} + +.top-xs { + -webkit-box-align: start; + -ms-flex-align: start; + -moz-align-items: flex-start; + -webkit-box-align: flex-start; + -ms-flex-align: flex-start; + align-items: flex-start +} + +.middle-xs { + -webkit-box-align: center; + -ms-flex-align: center; + -moz-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center +} + +.bottom-xs { + -webkit-box-align: end; + -ms-flex-align: end; + -moz-align-items: flex-end; + -webkit-box-align: flex-end; + -ms-flex-align: flex-end; + align-items: flex-end +} + +.around-xs { + -ms-flex-pack: distribute; + -moz-justify-content: space-around; + justify-content: space-around +} + +.between-xs { + -webkit-box-pack: justify; + -ms-flex-pack: justify; + -moz-justify-content: space-between; + justify-content: space-between +} + +.first-xs { + -webkit-box-ordinal-group: 0; + -ms-flex-order: -1; + order: -1 +} + +.last-xs { + -webkit-box-ordinal-group: 2; + -ms-flex-order: 1; + order: 1 +} + +@media only screen and (min-width:48em) { + .container { + width: 46rem + } + + .col-sm { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + -ms-flex-preferred-size: auto; + flex-basis: auto + } + + .col-sm-1 { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + -ms-flex-preferred-size: 8.3333333333%; + flex-basis: 8.3333333333%; + max-width: 8.3333333333% + } + + .col-sm-2 { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + -ms-flex-preferred-size: 16.6666666667%; + flex-basis: 16.6666666667%; + max-width: 16.6666666667% + } + + .col-sm-3 { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + -ms-flex-preferred-size: 25%; + flex-basis: 25%; + max-width: 25% + } + + .col-sm-4 { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + -ms-flex-preferred-size: 33.3333333333%; + flex-basis: 33.3333333333%; + max-width: 33.3333333333% + } + + .col-sm-5 { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + -ms-flex-preferred-size: 41.6666666667%; + flex-basis: 41.6666666667%; + max-width: 41.6666666667% + } + + .col-sm-6 { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + -ms-flex-preferred-size: 50%; + flex-basis: 50%; + max-width: 50% + } + + .col-sm-7 { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + -ms-flex-preferred-size: 58.3333333333%; + flex-basis: 58.3333333333%; + max-width: 58.3333333333% + } + + .col-sm-8 { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + -ms-flex-preferred-size: 66.6666666667%; + flex-basis: 66.6666666667%; + max-width: 66.6666666667% + } + + .col-sm-9 { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + -ms-flex-preferred-size: 75%; + flex-basis: 75%; + max-width: 75% + } + + .col-sm-10 { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + -ms-flex-preferred-size: 83.3333333333%; + flex-basis: 83.3333333333%; + max-width: 83.3333333333% + } + + .col-sm-11 { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + -ms-flex-preferred-size: 91.6666666667%; + flex-basis: 91.6666666667%; + max-width: 91.6666666667% + } + + .col-sm-12 { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + -ms-flex-preferred-size: 100%; + flex-basis: 100%; + max-width: 100% + } + + .col-sm-offset-0 { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + margin-left: 0 + } + + .col-sm-offset-1 { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + margin-left: 8.3333333333% + } + + .col-sm-offset-2 { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + margin-left: 16.6666666667% + } + + .col-sm-offset-3 { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + margin-left: 25% + } + + .col-sm-offset-4 { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + margin-left: 33.3333333333% + } + + .col-sm-offset-5 { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + margin-left: 41.6666666667% + } + + .col-sm-offset-6 { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + margin-left: 50% + } + + .col-sm-offset-7 { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + margin-left: 58.3333333333% + } + + .col-sm-offset-8 { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + margin-left: 66.6666666667% + } + + .col-sm-offset-9 { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + margin-left: 75% + } + + .col-sm-offset-10 { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + margin-left: 83.3333333333% + } + + .col-sm-offset-11 { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + margin-left: 91.6666666667% + } + + .col-sm-offset-12 { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + margin-left: 100% + } + + .col-sm { + -webkit-box-flex: 1; + -moz-flex-grow: 1; + -ms-flex-positive: 1; + flex-grow: 1; + -ms-flex-preferred-size: 0; + flex-basis: 0; + max-width: 100% + } + + .start-sm { + -webkit-box-pack: start; + -ms-flex-pack: start; + -moz-justify-content: flex-start; + justify-content: flex-start; + text-align: left + } + + .center-sm { + -webkit-box-pack: center; + -ms-flex-pack: center; + -moz-justify-content: center; + justify-content: center; + text-align: center + } + + .end-sm { + -webkit-box-pack: end; + -ms-flex-pack: end; + -moz-justify-content: flex-end; + justify-content: flex-end; + text-align: right + } + + .top-sm { + -webkit-box-align: start; + -ms-flex-align: start; + -moz-align-items: flex-start; + -webkit-box-align: flex-start; + -ms-flex-align: flex-start; + align-items: flex-start + } + + .middle-sm { + -webkit-box-align: center; + -ms-flex-align: center; + -moz-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center + } + + .bottom-sm { + -webkit-box-align: end; + -ms-flex-align: end; + -moz-align-items: flex-end; + -webkit-box-align: flex-end; + -ms-flex-align: flex-end; + align-items: flex-end + } + + .around-sm { + -ms-flex-pack: distribute; + -moz-justify-content: space-around; + justify-content: space-around + } + + .between-sm { + -webkit-box-pack: justify; + -ms-flex-pack: justify; + -moz-justify-content: space-between; + justify-content: space-between + } + + .first-sm { + -webkit-box-ordinal-group: 0; + -ms-flex-order: -1; + order: -1 + } + + .last-sm { + -webkit-box-ordinal-group: 2; + -ms-flex-order: 1; + order: 1 + } +} + +@media only screen and (min-width:62.85em) { + .container { + width: 61rem + } + + .col-md { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + -ms-flex-preferred-size: auto; + flex-basis: auto + } + + .col-md-1 { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + -ms-flex-preferred-size: 8.3333333333%; + flex-basis: 8.3333333333%; + max-width: 8.3333333333% + } + + .col-md-2 { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + -ms-flex-preferred-size: 16.6666666667%; + flex-basis: 16.6666666667%; + max-width: 16.6666666667% + } + + .col-md-3 { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + -ms-flex-preferred-size: 25%; + flex-basis: 25%; + max-width: 25% + } + + .col-md-4 { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + -ms-flex-preferred-size: 33.3333333333%; + flex-basis: 33.3333333333%; + max-width: 33.3333333333% + } + + .col-md-5 { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + -ms-flex-preferred-size: 41.6666666667%; + flex-basis: 41.6666666667%; + max-width: 41.6666666667% + } + + .col-md-6 { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + -ms-flex-preferred-size: 50%; + flex-basis: 50%; + max-width: 50% + } + + .col-md-7 { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + -ms-flex-preferred-size: 58.3333333333%; + flex-basis: 58.3333333333%; + max-width: 58.3333333333% + } + + .col-md-8 { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + -ms-flex-preferred-size: 66.6666666667%; + flex-basis: 66.6666666667%; + max-width: 66.6666666667% + } + + .col-md-9 { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + -ms-flex-preferred-size: 75%; + flex-basis: 75%; + max-width: 75% + } + + .col-md-10 { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + -ms-flex-preferred-size: 83.3333333333%; + flex-basis: 83.3333333333%; + max-width: 83.3333333333% + } + + .col-md-11 { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + -ms-flex-preferred-size: 91.6666666667%; + flex-basis: 91.6666666667%; + max-width: 91.6666666667% + } + + .col-md-12 { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + -ms-flex-preferred-size: 100%; + flex-basis: 100%; + max-width: 100% + } + + .col-md-offset-0 { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + margin-left: 0 + } + + .col-md-offset-1 { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + margin-left: 8.3333333333% + } + + .col-md-offset-2 { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + margin-left: 16.6666666667% + } + + .col-md-offset-3 { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + margin-left: 25% + } + + .col-md-offset-4 { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + margin-left: 33.3333333333% + } + + .col-md-offset-5 { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + margin-left: 41.6666666667% + } + + .col-md-offset-6 { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + margin-left: 50% + } + + .col-md-offset-7 { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + margin-left: 58.3333333333% + } + + .col-md-offset-8 { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + margin-left: 66.6666666667% + } + + .col-md-offset-9 { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + margin-left: 75% + } + + .col-md-offset-10 { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + margin-left: 83.3333333333% + } + + .col-md-offset-11 { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + margin-left: 91.6666666667% + } + + .col-md-offset-12 { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + margin-left: 100% + } + + .col-md { + -webkit-box-flex: 1; + -moz-flex-grow: 1; + -ms-flex-positive: 1; + flex-grow: 1; + -ms-flex-preferred-size: 0; + flex-basis: 0; + max-width: 100% + } + + .start-md { + -webkit-box-pack: start; + -ms-flex-pack: start; + -moz-justify-content: flex-start; + justify-content: flex-start; + text-align: left + } + + .center-md { + -webkit-box-pack: center; + -ms-flex-pack: center; + -moz-justify-content: center; + justify-content: center; + text-align: center + } + + .end-md { + -webkit-box-pack: end; + -ms-flex-pack: end; + -moz-justify-content: flex-end; + justify-content: flex-end; + text-align: right + } + + .top-md { + -webkit-box-align: start; + -ms-flex-align: start; + -moz-align-items: flex-start; + -webkit-box-align: flex-start; + -ms-flex-align: flex-start; + align-items: flex-start + } + + .middle-md { + -webkit-box-align: center; + -ms-flex-align: center; + -moz-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center + } + + .bottom-md { + -webkit-box-align: end; + -ms-flex-align: end; + -moz-align-items: flex-end; + -webkit-box-align: flex-end; + -ms-flex-align: flex-end; + align-items: flex-end + } + + .around-md { + -ms-flex-pack: distribute; + -moz-justify-content: space-around; + justify-content: space-around + } + + .between-md { + -webkit-box-pack: justify; + -ms-flex-pack: justify; + -moz-justify-content: space-between; + justify-content: space-between + } + + .first-md { + -webkit-box-ordinal-group: 0; + -ms-flex-order: -1; + order: -1 + } + + .last-md { + -webkit-box-ordinal-group: 2; + -ms-flex-order: 1; + order: 1 + } +} + +@media only screen and (min-width:78.7em) { + .container { + width: 76.875rem + } + + .col-lg { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + -ms-flex-preferred-size: auto; + flex-basis: auto + } + + .col-lg-1 { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + -ms-flex-preferred-size: 8.3333333333%; + flex-basis: 8.3333333333%; + max-width: 8.3333333333% + } + + .col-lg-2 { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + -ms-flex-preferred-size: 16.6666666667%; + flex-basis: 16.6666666667%; + max-width: 16.6666666667% + } + + .col-lg-3 { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + -ms-flex-preferred-size: 25%; + flex-basis: 25%; + max-width: 25% + } + + .col-lg-4 { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + -ms-flex-preferred-size: 33.3333333333%; + flex-basis: 33.3333333333%; + max-width: 33.3333333333% + } + + .col-lg-5 { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + -ms-flex-preferred-size: 41.6666666667%; + flex-basis: 41.6666666667%; + max-width: 41.6666666667% + } + + .col-lg-6 { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + -ms-flex-preferred-size: 50%; + flex-basis: 50%; + max-width: 50% + } + + .col-lg-7 { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + -ms-flex-preferred-size: 58.3333333333%; + flex-basis: 58.3333333333%; + max-width: 58.3333333333% + } + + .col-lg-8 { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + -ms-flex-preferred-size: 66.6666666667%; + flex-basis: 66.6666666667%; + max-width: 66.6666666667% + } + + .col-lg-9 { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + -ms-flex-preferred-size: 75%; + flex-basis: 75%; + max-width: 75% + } + + .col-lg-10 { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + -ms-flex-preferred-size: 83.3333333333%; + flex-basis: 83.3333333333%; + max-width: 83.3333333333% + } + + .col-lg-11 { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + -ms-flex-preferred-size: 91.6666666667%; + flex-basis: 91.6666666667%; + max-width: 91.6666666667% + } + + .col-lg-12 { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + -ms-flex-preferred-size: 100%; + flex-basis: 100%; + max-width: 100% + } + + .col-lg-offset-0 { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + margin-left: 0 + } + + .col-lg-offset-1 { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + margin-left: 8.3333333333% + } + + .col-lg-offset-2 { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + margin-left: 16.6666666667% + } + + .col-lg-offset-3 { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + margin-left: 25% + } + + .col-lg-offset-4 { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + margin-left: 33.3333333333% + } + + .col-lg-offset-5 { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + margin-left: 41.6666666667% + } + + .col-lg-offset-6 { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + margin-left: 50% + } + + .col-lg-offset-7 { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + margin-left: 58.3333333333% + } + + .col-lg-offset-8 { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + margin-left: 66.6666666667% + } + + .col-lg-offset-9 { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + margin-left: 75% + } + + .col-lg-offset-10 { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + margin-left: 83.3333333333% + } + + .col-lg-offset-11 { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + margin-left: 91.6666666667% + } + + .col-lg-offset-12 { + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-flex: 0; + -moz-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding-right: 15px; + padding-left: 15px; + margin-left: 100% + } + + .col-lg { + -webkit-box-flex: 1; + -moz-flex-grow: 1; + -ms-flex-positive: 1; + flex-grow: 1; + -ms-flex-preferred-size: 0; + flex-basis: 0; + max-width: 100% + } + + .start-lg { + -webkit-box-pack: start; + -ms-flex-pack: start; + -moz-justify-content: flex-start; + justify-content: flex-start; + text-align: left + } + + .center-lg { + -webkit-box-pack: center; + -ms-flex-pack: center; + -moz-justify-content: center; + justify-content: center; + text-align: center + } + + .end-lg { + -webkit-box-pack: end; + -ms-flex-pack: end; + -moz-justify-content: flex-end; + justify-content: flex-end; + text-align: right + } + + .top-lg { + -webkit-box-align: start; + -ms-flex-align: start; + -moz-align-items: flex-start; + -webkit-box-align: flex-start; + -ms-flex-align: flex-start; + align-items: flex-start + } + + .middle-lg { + -webkit-box-align: center; + -ms-flex-align: center; + -moz-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center + } + + .bottom-lg { + -webkit-box-align: end; + -ms-flex-align: end; + -moz-align-items: flex-end; + -webkit-box-align: flex-end; + -ms-flex-align: flex-end; + align-items: flex-end + } + + .around-lg { + -ms-flex-pack: distribute; + -moz-justify-content: space-around; + justify-content: space-around + } + + .between-lg { + -webkit-box-pack: justify; + -ms-flex-pack: justify; + -moz-justify-content: space-between; + justify-content: space-between + } + + .first-lg { + -webkit-box-ordinal-group: 0; + -ms-flex-order: -1; + order: -1 + } + + .last-lg { + -webkit-box-ordinal-group: 2; + -ms-flex-order: 1; + order: 1 + } +} + +*, +html { + -webkit-box-sizing: border-box; + box-sizing: border-box +} + +*, +::after, +::before { + -webkit-box-sizing: inherit; + box-sizing: inherit +} + +body, +html { + height: 100% +} + +img { + max-width: 100%; + height: auto; + vertical-align: bottom +} + +@media only screen and (max-width:48em) { + .hidden-on-mobile { + display: none !important + } +} + +@media only screen and (max-width:48em) { + .show-on-mobile { + display: block + } +} + +@media only screen and (min-width:48em) { + .show-on-mobile { + display: none + } +} + +.container { + padding: 0 15px +} + +@media only screen and (min-width:48em) { + .container { + padding: 0 + } +} + +.container .container-no-padding { + padding: 0 !important +} + +.embed-responsive { + position: relative; + display: block; + height: 0; + padding: 0; + overflow: hidden +} + +.embed-responsive .embed-responsive-item, +.embed-responsive embed, +.embed-responsive iframe, +.embed-responsive object, +.embed-responsive video { + position: absolute; + top: 0; + bottom: 0; + left: 0; + width: 100%; + height: 100%; + border: 0 +} + +.embed-responsive-21by9 { + padding-bottom: 42.8571428571% +} + +.embed-responsive-16by9 { + padding-bottom: 56.25% +} + +.embed-responsive-4by3 { + padding-bottom: 75% +} + +.embed-responsive-1by1 { + padding-bottom: 100% +} + +.fancybox-opened .fancybox-skin { + -webkit-box-shadow: 0 0 50px rgba(0, 0, 0, .9); + box-shadow: 0 0 50px rgba(0, 0, 0, .9) +} + +.fancybox-image, +.fancybox-inner, +.fancybox-nav, +.fancybox-nav span, +.fancybox-outer, +.fancybox-skin, +.fancybox-tmp, +.fancybox-wrap, +.fancybox-wrap iframe, +.fancybox-wrap object { + padding: 0; + margin: 0; + border: 0; + outline: 0; + vertical-align: top +} + +.fancybox-wrap { + position: absolute; + top: 0; + left: 0; + z-index: 8020 +} + +.fancybox-skin { + position: relative; + background: #fff; + color: #455463; + text-shadow: none +} + +.fancybox-opened { + z-index: 8030 +} + +.fancybox-opened .fancybox-skin { + -webkit-box-shadow: 0 10px 25px rgba(0, 0, 0, .5); + box-shadow: 0 10px 25px rgba(0, 0, 0, .5) +} + +.fancybox-inner, +.fancybox-outer { + position: relative +} + +.fancybox-inner { + overflow: hidden; + text-align: left +} + +.fancybox-type-iframe .fancybox-inner { + -webkit-overflow-scrolling: touch +} + +.fancybox-error { + color: #444; + margin: 0; + padding: 15px; + white-space: nowrap +} + +.fancybox-iframe, +.fancybox-image { + display: block; + width: 100%; + height: 100% +} + +.fancybox-image { + max-width: 100%; + max-height: 100% +} + +#fancybox-loading { + width: 48px; + height: 50px; + position: fixed; + left: 50%; + top: 50%; + z-index: 8060; + margin: -25px 0 0 -24px; + /* background: url(/themes/unity/build/css/../../images/ui/icons/other/cube48x50.png) 0 0 no-repeat */ +} + +#fancybox-loading:after { + content: ""; + width: 78px; + height: 78px; + display: block; + border: 2px solid transparent; + border-top-color: #ffeb3b; + -webkit-border-radius: 50%; + moz-border-radius: 50%; + border-radius: 50%; + position: absolute; + top: -15px; + left: -13px; + -webkit-animation: spin 1s infinite cubic-bezier(.25, .1, .25, 1); + animation: spin 1s infinite cubic-bezier(.25, .1, .25, 1) +} + +.fancybox-close { + height: 40px; + position: absolute; + bottom: -50px; + right: 0; + cursor: pointer; + z-index: 8060; + text-decoration: none !important +} + +.fancybox-close:before { + font-family: material-design-iconic-font; + content: "\f136"; + color: #fff; + font-size: 240%; + line-height: 40px; + letter-spacing: -3px +} + +.fancybox-nav { + position: absolute; + top: 0; + width: 40%; + height: 100%; + cursor: pointer; + text-decoration: none; + background: 0 0; + -webkit-tap-highlight-color: transparent; + z-index: 8040 +} + +.fancybox-prev { + left: 0 +} + +.fancybox-next { + right: 0 +} + +.fancybox-nav span { + width: 50px; + height: 50px; + position: absolute; + top: 50%; + margin: -25px 0 0 0; + cursor: pointer; + z-index: 8040; + border-radius: 50% +} + +.fancybox-nav:hover span { + opacity: 1 +} + +.fancybox-nav span:before { + font-family: entypo-plus; + content: "\e97e"; + color: #fff; + font-size: 240% +} + +.fancybox-prev span { + left: -70px +} + +.fancybox-prev span:before { + left: -70px; + content: "\e929" +} + +.fancybox-next span { + right: -70px +} + +.fancybox-next span:before { + right: -70px; + content: "\e92a" +} + +.fancybox-tmp { + position: absolute; + top: -9999px; + left: -9999px; + visibility: hidden +} + +.fancybox-lock { + overflow: hidden +} + +.fancybox-overlay { + position: absolute; + top: 0; + left: 0; + overflow: hidden; + display: none; + z-index: 8010; + background: rgba(0, 0, 0, .9) +} + +.fancybox-overlay-fixed { + position: fixed; + bottom: 0; + right: 0 +} + +.fancybox-lock .fancybox-overlay { + overflow: auto; + overflow-y: scroll +} + +.fancybox-title { + visibility: hidden; + position: relative; + text-shadow: none; + z-index: 8050 +} + +.fancybox-opened .fancybox-title { + visibility: visible +} + +.fancybox-title-float-wrap { + width: 100%; + padding: 0 50px 0 0; + position: absolute; + bottom: 0; + left: 0; + margin-bottom: -50px; + z-index: 8050; + text-align: left +} + +.fancybox-title-float-wrap .child { + width: 100%; + display: inline-block; + color: #fff; + line-height: 40px; + font-size: 1.125em; + text-overflow: ellipsis; + white-space: nowrap; + overflow: hidden +} + +.fancybox-title-outside-wrap { + position: relative; + margin-top: 10px; + color: #fff +} + +.fancybox-title-inside-wrap { + padding-top: 10px +} + +.fancybox-title-over-wrap { + position: absolute; + bottom: 0; + left: 0; + color: #fff; + padding: 10px; + background: #222c37; + background: rgba(34, 44, 55, .9) +} + +@-webkit-keyframes spin { + from { + -webkit-transform: rotate(0) + } + + to { + -webkit-transform: rotate(-360deg) + } +} + +@keyframes spin { + from { + -webkit-transform: rotate(0); + transform: rotate(0) + } + + to { + -webkit-transform: rotate(-360deg); + transform: rotate(-360deg) + } +} +/* +@font-face { + font-family: Material-Design-Iconic-Font; + src: url(/themes/unity/build/css/../../build/fonts/material-design-iconic-font/Material-Design-Iconic-Font.woff2?v=2.2.0) format("woff2"), url(/themes/unity/build/css/../../build/fonts/material-design-iconic-font/Material-Design-Iconic-Font.woff?v=2.2.0) format("woff"), url(/themes/unity/build/css/../../build/fonts/material-design-iconic-font/Material-Design-Iconic-Font.ttf?v=2.2.0) format("truetype"); + font-weight: 400; + font-style: normal +} */ + +.mdi { + display: inline-block; + /* font: normal normal normal 14px/1 Material-Design-Iconic-Font; */ + font-size: inherit; + text-rendering: auto; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale +} + +.mdi-hc-lg { + font-size: 1.3333333333em; + line-height: .75em; + vertical-align: -15% +} + +.mdi-hc-2x { + font-size: 2em +} + +.mdi-hc-3x { + font-size: 3em +} + +.mdi-hc-4x { + font-size: 4em +} + +.mdi-hc-5x { + font-size: 5em +} + +.mdi-hc-fw { + width: 1.2857142857em; + text-align: center +} + +.mdi-hc-ul { + padding-left: 0; + margin-left: 2.1428571429em; + list-style-type: none +} + +.mdi-hc-ul>li { + position: relative +} + +.mdi-hc-li { + position: absolute; + left: -2.1428571429em; + width: 2.1428571429em; + top: .1428571429em; + text-align: center +} + +.mdi-hc-li.mdi-hc-lg { + left: -1.8571428571em +} + +.mdi-hc-border { + padding: .1em .25em; + border: solid .1em #9e9e9e; + border-radius: 2px +} + +.mdi-hc-border-circle { + padding: .1em .25em; + border: solid .1em #9e9e9e; + border-radius: 50% +} + +.mdi.pull-left { + float: left; + margin-right: .15em +} + +.mdi.pull-right { + float: right; + margin-left: .15em +} + +.mdi-hc-spin { + -webkit-animation: zmdi-spin 1.5s infinite linear; + animation: zmdi-spin 1.5s infinite linear +} + +.mdi-hc-spin-reverse { + -webkit-animation: zmdi-spin-reverse 1.5s infinite linear; + animation: zmdi-spin-reverse 1.5s infinite linear +} + +@-webkit-keyframes zmdi-spin { + 0% { + -webkit-transform: rotate(0); + transform: rotate(0) + } + + 100% { + -webkit-transform: rotate(359deg); + transform: rotate(359deg) + } +} + +@keyframes zmdi-spin { + 0% { + -webkit-transform: rotate(0); + transform: rotate(0) + } + + 100% { + -webkit-transform: rotate(359deg); + transform: rotate(359deg) + } +} + +@-webkit-keyframes zmdi-spin-reverse { + 0% { + -webkit-transform: rotate(0); + transform: rotate(0) + } + + 100% { + -webkit-transform: rotate(-359deg); + transform: rotate(-359deg) + } +} + +@keyframes zmdi-spin-reverse { + 0% { + -webkit-transform: rotate(0); + transform: rotate(0) + } + + 100% { + -webkit-transform: rotate(-359deg); + transform: rotate(-359deg) + } +} + +.mdi-hc-rotate-90 { + -webkit-transform: rotate(90deg); + transform: rotate(90deg) +} + +.mdi-hc-rotate-180 { + -webkit-transform: rotate(180deg); + transform: rotate(180deg) +} + +.mdi-hc-rotate-270 { + -webkit-transform: rotate(270deg); + transform: rotate(270deg) +} + +.mdi-hc-flip-horizontal { + -webkit-transform: scale(-1, 1); + transform: scale(-1, 1) +} + +.mdi-hc-flip-vertical { + -webkit-transform: scale(1, -1); + transform: scale(1, -1) +} + +.mdi-hc-stack { + position: relative; + display: inline-block; + width: 2em; + height: 2em; + line-height: 2em; + vertical-align: middle +} + +.mdi-hc-stack-1x, +.mdi-hc-stack-2x { + position: absolute; + left: 0; + width: 100%; + text-align: center +} + +.mdi-hc-stack-1x { + line-height: inherit +} + +.mdi-hc-stack-2x { + font-size: 2em +} + +.mdi-hc-inverse { + color: #fff +} + +.mdi-3d-rotation:before { + content: "\f101" +} + +.mdi-airplane-off:before { + content: "\f102" +} + +.mdi-airplane:before { + content: "\f103" +} + +.mdi-album:before { + content: "\f104" +} + +.mdi-archive:before { + content: "\f105" +} + +.mdi-assignment-account:before { + content: "\f106" +} + +.mdi-assignment-alert:before { + content: "\f107" +} + +.mdi-assignment-check:before { + content: "\f108" +} + +.mdi-assignment-o:before { + content: "\f109" +} + +.mdi-assignment-return:before { + content: "\f10a" +} + +.mdi-assignment-returned:before { + content: "\f10b" +} + +.mdi-assignment:before { + content: "\f10c" +} + +.mdi-attachment-alt:before { + content: "\f10d" +} + +.mdi-attachment:before { + content: "\f10e" +} + +.mdi-audio:before { + content: "\f10f" +} + +.mdi-badge-check:before { + content: "\f110" +} + +.mdi-balance-wallet:before { + content: "\f111" +} + +.mdi-balance:before { + content: "\f112" +} + +.mdi-battery-alert:before { + content: "\f113" +} + +.mdi-battery-flash:before { + content: "\f114" +} + +.mdi-battery-unknown:before { + content: "\f115" +} + +.mdi-battery:before { + content: "\f116" +} + +.mdi-bike:before { + content: "\f117" +} + +.mdi-block-alt:before { + content: "\f118" +} + +.mdi-block:before { + content: "\f119" +} + +.mdi-boat:before { + content: "\f11a" +} + +.mdi-book-image:before { + content: "\f11b" +} + +.mdi-book:before { + content: "\f11c" +} + +.mdi-bookmark-outline:before { + content: "\f11d" +} + +.mdi-bookmark:before { + content: "\f11e" +} + +.mdi-brush:before { + content: "\f11f" +} + +.mdi-bug:before { + content: "\f120" +} + +.mdi-bus:before { + content: "\f121" +} + +.mdi-cake:before { + content: "\f122" +} + +.mdi-car-taxi:before { + content: "\f123" +} + +.mdi-car-wash:before { + content: "\f124" +} + +.mdi-car:before { + content: "\f125" +} + +.mdi-card-giftcard:before { + content: "\f126" +} + +.mdi-card-membership:before { + content: "\f127" +} + +.mdi-card-travel:before { + content: "\f128" +} + +.mdi-card:before { + content: "\f129" +} + +.mdi-case-check:before { + content: "\f12a" +} + +.mdi-case-download:before { + content: "\f12b" +} + +.mdi-case-play:before { + content: "\f12c" +} + +.mdi-case:before { + content: "\f12d" +} + +.mdi-cast-connected:before { + content: "\f12e" +} + +.mdi-cast:before { + content: "\f12f" +} + +.mdi-chart-donut:before { + content: "\f130" +} + +.mdi-chart:before { + content: "\f131" +} + +.mdi-city-alt:before { + content: "\f132" +} + +.mdi-city:before { + content: "\f133" +} + +.mdi-close-circle-o:before { + content: "\f134" +} + +.mdi-close-circle:before { + content: "\f135" +} + +.mdi-close:before { + content: "\f136" +} + +.mdi-cocktail:before { + content: "\f137" +} + +.mdi-code-setting:before { + content: "\f138" +} + +.mdi-code-smartphone:before { + content: "\f139" +} + +.mdi-code:before { + content: "\f13a" +} + +.mdi-coffee:before { + content: "\f13b" +} + +.mdi-collection-bookmark:before { + content: "\f13c" +} + +.mdi-collection-case-play:before { + content: "\f13d" +} + +.mdi-collection-folder-image:before { + content: "\f13e" +} + +.mdi-collection-image-o:before { + content: "\f13f" +} + +.mdi-collection-image:before { + content: "\f140" +} + +.mdi-collection-item-1:before { + content: "\f141" +} + +.mdi-collection-item-2:before { + content: "\f142" +} + +.mdi-collection-item-3:before { + content: "\f143" +} + +.mdi-collection-item-4:before { + content: "\f144" +} + +.mdi-collection-item-5:before { + content: "\f145" +} + +.mdi-collection-item-6:before { + content: "\f146" +} + +.mdi-collection-item-7:before { + content: "\f147" +} + +.mdi-collection-item-8:before { + content: "\f148" +} + +.mdi-collection-item-9-plus:before { + content: "\f149" +} + +.mdi-collection-item-9:before { + content: "\f14a" +} + +.mdi-collection-item:before { + content: "\f14b" +} + +.mdi-collection-music:before { + content: "\f14c" +} + +.mdi-collection-pdf:before { + content: "\f14d" +} + +.mdi-collection-plus:before { + content: "\f14e" +} + +.mdi-collection-speaker:before { + content: "\f14f" +} + +.mdi-collection-text:before { + content: "\f150" +} + +.mdi-collection-video:before { + content: "\f151" +} + +.mdi-compass:before { + content: "\f152" +} + +.mdi-cutlery:before { + content: "\f153" +} + +.mdi-delete:before { + content: "\f154" +} + +.mdi-dialpad:before { + content: "\f155" +} + +.mdi-dns:before { + content: "\f156" +} + +.mdi-drink:before { + content: "\f157" +} + +.mdi-edit:before { + content: "\f158" +} + +.mdi-email-open:before { + content: "\f159" +} + +.mdi-email:before { + content: "\f15a" +} + +.mdi-eye-off:before { + content: "\f15b" +} + +.mdi-eye:before { + content: "\f15c" +} + +.mdi-eyedropper:before { + content: "\f15d" +} + +.mdi-favorite-outline:before { + content: "\f15e" +} + +.mdi-favorite:before { + content: "\f15f" +} + +.mdi-filter-list:before { + content: "\f160" +} + +.mdi-fire:before { + content: "\f161" +} + +.mdi-flag:before { + content: "\f162" +} + +.mdi-flare:before { + content: "\f163" +} + +.mdi-flash-auto:before { + content: "\f164" +} + +.mdi-flash-off:before { + content: "\f165" +} + +.mdi-flash:before { + content: "\f166" +} + +.mdi-flip:before { + content: "\f167" +} + +.mdi-flower-alt:before { + content: "\f168" +} + +.mdi-flower:before { + content: "\f169" +} + +.mdi-font:before { + content: "\f16a" +} + +.mdi-fullscreen-alt:before { + content: "\f16b" +} + +.mdi-fullscreen-exit:before { + content: "\f16c" +} + +.mdi-fullscreen:before { + content: "\f16d" +} + +.mdi-functions:before { + content: "\f16e" +} + +.mdi-gas-station:before { + content: "\f16f" +} + +.mdi-gesture:before { + content: "\f170" +} + +.mdi-globe-alt:before { + content: "\f171" +} + +.mdi-globe-lock:before { + content: "\f172" +} + +.mdi-globe:before { + content: "\f173" +} + +.mdi-graduation-cap:before { + content: "\f174" +} + +.mdi-home:before { + content: "\f175" +} + +.mdi-hospital-alt:before { + content: "\f176" +} + +.mdi-hospital:before { + content: "\f177" +} + +.mdi-hotel:before { + content: "\f178" +} + +.mdi-hourglass-alt:before { + content: "\f179" +} + +.mdi-hourglass-outline:before { + content: "\f17a" +} + +.mdi-hourglass:before { + content: "\f17b" +} + +.mdi-http:before { + content: "\f17c" +} + +.mdi-image-alt:before { + content: "\f17d" +} + +.mdi-image-o:before { + content: "\f17e" +} + +.mdi-image:before { + content: "\f17f" +} + +.mdi-inbox:before { + content: "\f180" +} + +.mdi-invert-colors-off:before { + content: "\f181" +} + +.mdi-invert-colors:before { + content: "\f182" +} + +.mdi-key:before { + content: "\f183" +} + +.mdi-label-alt-outline:before { + content: "\f184" +} + +.mdi-label-alt:before { + content: "\f185" +} + +.mdi-label-heart:before { + content: "\f186" +} + +.mdi-label:before { + content: "\f187" +} + +.mdi-labels:before { + content: "\f188" +} + +.mdi-lamp:before { + content: "\f189" +} + +.mdi-landscape:before { + content: "\f18a" +} + +.mdi-layers-off:before { + content: "\f18b" +} + +.mdi-layers:before { + content: "\f18c" +} + +.mdi-library:before { + content: "\f18d" +} + +.mdi-link:before { + content: "\f18e" +} + +.mdi-lock-open:before { + content: "\f18f" +} + +.mdi-lock-outline:before { + content: "\f190" +} + +.mdi-lock:before { + content: "\f191" +} + +.mdi-mail-reply-all:before { + content: "\f192" +} + +.mdi-mail-reply:before { + content: "\f193" +} + +.mdi-mail-send:before { + content: "\f194" +} + +.mdi-mall:before { + content: "\f195" +} + +.mdi-map:before { + content: "\f196" +} + +.mdi-menu:before { + content: "\f197" +} + +.mdi-money-box:before { + content: "\f198" +} + +.mdi-money-off:before { + content: "\f199" +} + +.mdi-money:before { + content: "\f19a" +} + +.mdi-more-vert:before { + content: "\f19b" +} + +.mdi-more:before { + content: "\f19c" +} + +.mdi-movie-alt:before { + content: "\f19d" +} + +.mdi-movie:before { + content: "\f19e" +} + +.mdi-nature-people:before { + content: "\f19f" +} + +.mdi-nature:before { + content: "\f1a0" +} + +.mdi-navigation:before { + content: "\f1a1" +} + +.mdi-open-in-browser:before { + content: "\f1a2" +} + +.mdi-open-in-new:before { + content: "\f1a3" +} + +.mdi-palette:before { + content: "\f1a4" +} + +.mdi-parking:before { + content: "\f1a5" +} + +.mdi-pin-account:before { + content: "\f1a6" +} + +.mdi-pin-assistant:before { + content: "\f1a7" +} + +.mdi-pin-drop:before { + content: "\f1a8" +} + +.mdi-pin-help:before { + content: "\f1a9" +} + +.mdi-pin-off:before { + content: "\f1aa" +} + +.mdi-pin:before { + content: "\f1ab" +} + +.mdi-pizza:before { + content: "\f1ac" +} + +.mdi-plaster:before { + content: "\f1ad" +} + +.mdi-power-setting:before { + content: "\f1ae" +} + +.mdi-power:before { + content: "\f1af" +} + +.mdi-print:before { + content: "\f1b0" +} + +.mdi-puzzle-piece:before { + content: "\f1b1" +} + +.mdi-quote:before { + content: "\f1b2" +} + +.mdi-railway:before { + content: "\f1b3" +} + +.mdi-receipt:before { + content: "\f1b4" +} + +.mdi-refresh-alt:before { + content: "\f1b5" +} + +.mdi-refresh-sync-alert:before { + content: "\f1b6" +} + +.mdi-refresh-sync-off:before { + content: "\f1b7" +} + +.mdi-refresh-sync:before { + content: "\f1b8" +} + +.mdi-refresh:before { + content: "\f1b9" +} + +.mdi-roller:before { + content: "\f1ba" +} + +.mdi-ruler:before { + content: "\f1bb" +} + +.mdi-scissors:before { + content: "\f1bc" +} + +.mdi-screen-rotation-lock:before { + content: "\f1bd" +} + +.mdi-screen-rotation:before { + content: "\f1be" +} + +.mdi-search-for:before { + content: "\f1bf" +} + +.mdi-search-in-file:before { + content: "\f1c0" +} + +.mdi-search-in-page:before { + content: "\f1c1" +} + +.mdi-search-replace:before { + content: "\f1c2" +} + +.mdi-search:before { + content: "\f1c3" +} + +.mdi-seat:before { + content: "\f1c4" +} + +.mdi-settings-square:before { + content: "\f1c5" +} + +.mdi-settings:before { + content: "\f1c6" +} + +.mdi-shield-check:before { + content: "\f1c7" +} + +.mdi-shield-security:before { + content: "\f1c8" +} + +.mdi-shopping-basket:before { + content: "\f1c9" +} + +.mdi-shopping-cart-plus:before { + content: "\f1ca" +} + +.mdi-shopping-cart:before { + content: "\f1cb" +} + +.mdi-sign-in:before { + content: "\f1cc" +} + +.mdi-sort-amount-asc:before { + content: "\f1cd" +} + +.mdi-sort-amount-desc:before { + content: "\f1ce" +} + +.mdi-sort-asc:before { + content: "\f1cf" +} + +.mdi-sort-desc:before { + content: "\f1d0" +} + +.mdi-spellcheck:before { + content: "\f1d1" +} + +.mdi-storage:before { + content: "\f1d2" +} + +.mdi-store-24:before { + content: "\f1d3" +} + +.mdi-store:before { + content: "\f1d4" +} + +.mdi-subway:before { + content: "\f1d5" +} + +.mdi-sun:before { + content: "\f1d6" +} + +.mdi-tab-unselected:before { + content: "\f1d7" +} + +.mdi-tab:before { + content: "\f1d8" +} + +.mdi-tag-close:before { + content: "\f1d9" +} + +.mdi-tag-more:before { + content: "\f1da" +} + +.mdi-tag:before { + content: "\f1db" +} + +.mdi-thumb-down:before { + content: "\f1dc" +} + +.mdi-thumb-up-down:before { + content: "\f1dd" +} + +.mdi-thumb-up:before { + content: "\f1de" +} + +.mdi-ticket-star:before { + content: "\f1df" +} + +.mdi-toll:before { + content: "\f1e0" +} + +.mdi-toys:before { + content: "\f1e1" +} + +.mdi-traffic:before { + content: "\f1e2" +} + +.mdi-translate:before { + content: "\f1e3" +} + +.mdi-triangle-down:before { + content: "\f1e4" +} + +.mdi-triangle-up:before { + content: "\f1e5" +} + +.mdi-truck:before { + content: "\f1e6" +} + +.mdi-turning-sign:before { + content: "\f1e7" +} + +.mdi-wallpaper:before { + content: "\f1e8" +} + +.mdi-washing-machine:before { + content: "\f1e9" +} + +.mdi-window-maximize:before { + content: "\f1ea" +} + +.mdi-window-minimize:before { + content: "\f1eb" +} + +.mdi-window-restore:before { + content: "\f1ec" +} + +.mdi-wrench:before { + content: "\f1ed" +} + +.mdi-zoom-in:before { + content: "\f1ee" +} + +.mdi-zoom-out:before { + content: "\f1ef" +} + +.mdi-alert-circle-o:before { + content: "\f1f0" +} + +.mdi-alert-circle:before { + content: "\f1f1" +} + +.mdi-alert-octagon:before { + content: "\f1f2" +} + +.mdi-alert-polygon:before { + content: "\f1f3" +} + +.mdi-alert-triangle:before { + content: "\f1f4" +} + +.mdi-help-outline:before { + content: "\f1f5" +} + +.mdi-help:before { + content: "\f1f6" +} + +.mdi-info-outline:before { + content: "\f1f7" +} + +.mdi-info:before { + content: "\f1f8" +} + +.mdi-notifications-active:before { + content: "\f1f9" +} + +.mdi-notifications-add:before { + content: "\f1fa" +} + +.mdi-notifications-none:before { + content: "\f1fb" +} + +.mdi-notifications-off:before { + content: "\f1fc" +} + +.mdi-notifications-paused:before { + content: "\f1fd" +} + +.mdi-notifications:before { + content: "\f1fe" +} + +.mdi-account-add:before { + content: "\f1ff" +} + +.mdi-account-box-mail:before { + content: "\f200" +} + +.mdi-account-box-o:before { + content: "\f201" +} + +.mdi-account-box-phone:before { + content: "\f202" +} + +.mdi-account-box:before { + content: "\f203" +} + +.mdi-account-calendar:before { + content: "\f204" +} + +.mdi-account-circle:before { + content: "\f205" +} + +.mdi-account-o:before { + content: "\f206" +} + +.mdi-account:before { + content: "\f207" +} + +.mdi-accounts-add:before { + content: "\f208" +} + +.mdi-accounts-alt:before { + content: "\f209" +} + +.mdi-accounts-list-alt:before { + content: "\f20a" +} + +.mdi-accounts-list:before { + content: "\f20b" +} + +.mdi-accounts-outline:before { + content: "\f20c" +} + +.mdi-accounts:before { + content: "\f20d" +} + +.mdi-face:before { + content: "\f20e" +} + +.mdi-female:before { + content: "\f20f" +} + +.mdi-male-alt:before { + content: "\f210" +} + +.mdi-male-female:before { + content: "\f211" +} + +.mdi-male:before { + content: "\f212" +} + +.mdi-mood-bad:before { + content: "\f213" +} + +.mdi-mood:before { + content: "\f214" +} + +.mdi-run:before { + content: "\f215" +} + +.mdi-walk:before { + content: "\f216" +} + +.mdi-cloud-box:before { + content: "\f217" +} + +.mdi-cloud-circle:before { + content: "\f218" +} + +.mdi-cloud-done:before { + content: "\f219" +} + +.mdi-cloud-download:before { + content: "\f21a" +} + +.mdi-cloud-off:before { + content: "\f21b" +} + +.mdi-cloud-outline-alt:before { + content: "\f21c" +} + +.mdi-cloud-outline:before { + content: "\f21d" +} + +.mdi-cloud-upload:before { + content: "\f21e" +} + +.mdi-cloud:before { + content: "\f21f" +} + +.mdi-download:before { + content: "\f220" +} + +.mdi-file-plus:before { + content: "\f221" +} + +.mdi-file-text:before { + content: "\f222" +} + +.mdi-file:before { + content: "\f223" +} + +.mdi-folder-outline:before { + content: "\f224" +} + +.mdi-folder-person:before { + content: "\f225" +} + +.mdi-folder-star-alt:before { + content: "\f226" +} + +.mdi-folder-star:before { + content: "\f227" +} + +.mdi-folder:before { + content: "\f228" +} + +.mdi-gif:before { + content: "\f229" +} + +.mdi-upload:before { + content: "\f22a" +} + +.mdi-border-all:before { + content: "\f22b" +} + +.mdi-border-bottom:before { + content: "\f22c" +} + +.mdi-border-clear:before { + content: "\f22d" +} + +.mdi-border-color:before { + content: "\f22e" +} + +.mdi-border-horizontal:before { + content: "\f22f" +} + +.mdi-border-inner:before { + content: "\f230" +} + +.mdi-border-left:before { + content: "\f231" +} + +.mdi-border-outer:before { + content: "\f232" +} + +.mdi-border-right:before { + content: "\f233" +} + +.mdi-border-style:before { + content: "\f234" +} + +.mdi-border-top:before { + content: "\f235" +} + +.mdi-border-vertical:before { + content: "\f236" +} + +.mdi-copy:before { + content: "\f237" +} + +.mdi-crop:before { + content: "\f238" +} + +.mdi-format-align-center:before { + content: "\f239" +} + +.mdi-format-align-justify:before { + content: "\f23a" +} + +.mdi-format-align-left:before { + content: "\f23b" +} + +.mdi-format-align-right:before { + content: "\f23c" +} + +.mdi-format-bold:before { + content: "\f23d" +} + +.mdi-format-clear-all:before { + content: "\f23e" +} + +.mdi-format-clear:before { + content: "\f23f" +} + +.mdi-format-color-fill:before { + content: "\f240" +} + +.mdi-format-color-reset:before { + content: "\f241" +} + +.mdi-format-color-text:before { + content: "\f242" +} + +.mdi-format-indent-decrease:before { + content: "\f243" +} + +.mdi-format-indent-increase:before { + content: "\f244" +} + +.mdi-format-italic:before { + content: "\f245" +} + +.mdi-format-line-spacing:before { + content: "\f246" +} + +.mdi-format-list-bulleted:before { + content: "\f247" +} + +.mdi-format-list-numbered:before { + content: "\f248" +} + +.mdi-format-ltr:before { + content: "\f249" +} + +.mdi-format-rtl:before { + content: "\f24a" +} + +.mdi-format-size:before { + content: "\f24b" +} + +.mdi-format-strikethrough-s:before { + content: "\f24c" +} + +.mdi-format-strikethrough:before { + content: "\f24d" +} + +.mdi-format-subject:before { + content: "\f24e" +} + +.mdi-format-underlined:before { + content: "\f24f" +} + +.mdi-format-valign-bottom:before { + content: "\f250" +} + +.mdi-format-valign-center:before { + content: "\f251" +} + +.mdi-format-valign-top:before { + content: "\f252" +} + +.mdi-redo:before { + content: "\f253" +} + +.mdi-select-all:before { + content: "\f254" +} + +.mdi-space-bar:before { + content: "\f255" +} + +.mdi-text-format:before { + content: "\f256" +} + +.mdi-transform:before { + content: "\f257" +} + +.mdi-undo:before { + content: "\f258" +} + +.mdi-wrap-text:before { + content: "\f259" +} + +.mdi-comment-alert:before { + content: "\f25a" +} + +.mdi-comment-alt-text:before { + content: "\f25b" +} + +.mdi-comment-alt:before { + content: "\f25c" +} + +.mdi-comment-edit:before { + content: "\f25d" +} + +.mdi-comment-image:before { + content: "\f25e" +} + +.mdi-comment-list:before { + content: "\f25f" +} + +.mdi-comment-more:before { + content: "\f260" +} + +.mdi-comment-outline:before { + content: "\f261" +} + +.mdi-comment-text-alt:before { + content: "\f262" +} + +.mdi-comment-text:before { + content: "\f263" +} + +.mdi-comment-video:before { + content: "\f264" +} + +.mdi-comment:before { + content: "\f265" +} + +.mdi-comments:before { + content: "\f266" +} + +.mdi-check-all:before { + content: "\f267" +} + +.mdi-check-circle-u:before { + content: "\f268" +} + +.mdi-check-circle:before { + content: "\f269" +} + +.mdi-check-square:before { + content: "\f26a" +} + +.mdi-check:before { + content: "\f26b" +} + +.mdi-circle-o:before { + content: "\f26c" +} + +.mdi-circle:before { + content: "\f26d" +} + +.mdi-dot-circle-alt:before { + content: "\f26e" +} + +.mdi-dot-circle:before { + content: "\f26f" +} + +.mdi-minus-circle-outline:before { + content: "\f270" +} + +.mdi-minus-circle:before { + content: "\f271" +} + +.mdi-minus-square:before { + content: "\f272" +} + +.mdi-minus:before { + content: "\f273" +} + +.mdi-plus-circle-o-duplicate:before { + content: "\f274" +} + +.mdi-plus-circle-o:before { + content: "\f275" +} + +.mdi-plus-circle:before { + content: "\f276" +} + +.mdi-plus-square:before { + content: "\f277" +} + +.mdi-plus:before { + content: "\f278" +} + +.mdi-square-o:before { + content: "\f279" +} + +.mdi-star-circle:before { + content: "\f27a" +} + +.mdi-star-half:before { + content: "\f27b" +} + +.mdi-star-outline:before { + content: "\f27c" +} + +.mdi-star:before { + content: "\f27d" +} + +.mdi-bluetooth-connected:before { + content: "\f27e" +} + +.mdi-bluetooth-off:before { + content: "\f27f" +} + +.mdi-bluetooth-search:before { + content: "\f280" +} + +.mdi-bluetooth-setting:before { + content: "\f281" +} + +.mdi-bluetooth:before { + content: "\f282" +} + +.mdi-camera-add:before { + content: "\f283" +} + +.mdi-camera-alt:before { + content: "\f284" +} + +.mdi-camera-bw:before { + content: "\f285" +} + +.mdi-camera-front:before { + content: "\f286" +} + +.mdi-camera-mic:before { + content: "\f287" +} + +.mdi-camera-party-mode:before { + content: "\f288" +} + +.mdi-camera-rear:before { + content: "\f289" +} + +.mdi-camera-roll:before { + content: "\f28a" +} + +.mdi-camera-switch:before { + content: "\f28b" +} + +.mdi-camera:before { + content: "\f28c" +} + +.mdi-card-alert:before { + content: "\f28d" +} + +.mdi-card-off:before { + content: "\f28e" +} + +.mdi-card-sd:before { + content: "\f28f" +} + +.mdi-card-sim:before { + content: "\f290" +} + +.mdi-desktop-mac:before { + content: "\f291" +} + +.mdi-desktop-windows:before { + content: "\f292" +} + +.mdi-device-hub:before { + content: "\f293" +} + +.mdi-devices-off:before { + content: "\f294" +} + +.mdi-devices:before { + content: "\f295" +} + +.mdi-dock:before { + content: "\f296" +} + +.mdi-floppy:before { + content: "\f297" +} + +.mdi-gamepad:before { + content: "\f298" +} + +.mdi-gps-dot:before { + content: "\f299" +} + +.mdi-gps-off:before { + content: "\f29a" +} + +.mdi-gps:before { + content: "\f29b" +} + +.mdi-headset-mic:before { + content: "\f29c" +} + +.mdi-headset:before { + content: "\f29d" +} + +.mdi-input-antenna:before { + content: "\f29e" +} + +.mdi-input-composite:before { + content: "\f29f" +} + +.mdi-input-hdmi:before { + content: "\f2a0" +} + +.mdi-input-power:before { + content: "\f2a1" +} + +.mdi-input-svideo:before { + content: "\f2a2" +} + +.mdi-keyboard-hide:before { + content: "\f2a3" +} + +.mdi-keyboard:before { + content: "\f2a4" +} + +.mdi-laptop-chromebook:before { + content: "\f2a5" +} + +.mdi-laptop-mac:before { + content: "\f2a6" +} + +.mdi-laptop:before { + content: "\f2a7" +} + +.mdi-mic-off:before { + content: "\f2a8" +} + +.mdi-mic-outline:before { + content: "\f2a9" +} + +.mdi-mic-setting:before { + content: "\f2aa" +} + +.mdi-mic:before { + content: "\f2ab" +} + +.mdi-mouse:before { + content: "\f2ac" +} + +.mdi-network-alert:before { + content: "\f2ad" +} + +.mdi-network-locked:before { + content: "\f2ae" +} + +.mdi-network-off:before { + content: "\f2af" +} + +.mdi-network-outline:before { + content: "\f2b0" +} + +.mdi-network-setting:before { + content: "\f2b1" +} + +.mdi-network:before { + content: "\f2b2" +} + +.mdi-phone-bluetooth:before { + content: "\f2b3" +} + +.mdi-phone-end:before { + content: "\f2b4" +} + +.mdi-phone-forwarded:before { + content: "\f2b5" +} + +.mdi-phone-in-talk:before { + content: "\f2b6" +} + +.mdi-phone-locked:before { + content: "\f2b7" +} + +.mdi-phone-missed:before { + content: "\f2b8" +} + +.mdi-phone-msg:before { + content: "\f2b9" +} + +.mdi-phone-paused:before { + content: "\f2ba" +} + +.mdi-phone-ring:before { + content: "\f2bb" +} + +.mdi-phone-setting:before { + content: "\f2bc" +} + +.mdi-phone-sip:before { + content: "\f2bd" +} + +.mdi-phone:before { + content: "\f2be" +} + +.mdi-portable-wifi-changes:before { + content: "\f2bf" +} + +.mdi-portable-wifi-off:before { + content: "\f2c0" +} + +.mdi-portable-wifi:before { + content: "\f2c1" +} + +.mdi-radio:before { + content: "\f2c2" +} + +.mdi-reader:before { + content: "\f2c3" +} + +.mdi-remote-control-alt:before { + content: "\f2c4" +} + +.mdi-remote-control:before { + content: "\f2c5" +} + +.mdi-router:before { + content: "\f2c6" +} + +.mdi-scanner:before { + content: "\f2c7" +} + +.mdi-smartphone-android:before { + content: "\f2c8" +} + +.mdi-smartphone-download:before { + content: "\f2c9" +} + +.mdi-smartphone-erase:before { + content: "\f2ca" +} + +.mdi-smartphone-info:before { + content: "\f2cb" +} + +.mdi-smartphone-iphone:before { + content: "\f2cc" +} + +.mdi-smartphone-landscape-lock:before { + content: "\f2cd" +} + +.mdi-smartphone-landscape:before { + content: "\f2ce" +} + +.mdi-smartphone-lock:before { + content: "\f2cf" +} + +.mdi-smartphone-portrait-lock:before { + content: "\f2d0" +} + +.mdi-smartphone-ring:before { + content: "\f2d1" +} + +.mdi-smartphone-setting:before { + content: "\f2d2" +} + +.mdi-smartphone-setup:before { + content: "\f2d3" +} + +.mdi-smartphone:before { + content: "\f2d4" +} + +.mdi-speaker:before { + content: "\f2d5" +} + +.mdi-tablet-android:before { + content: "\f2d6" +} + +.mdi-tablet-mac:before { + content: "\f2d7" +} + +.mdi-tablet:before { + content: "\f2d8" +} + +.mdi-tv-alt-play:before { + content: "\f2d9" +} + +.mdi-tv-list:before { + content: "\f2da" +} + +.mdi-tv-play:before { + content: "\f2db" +} + +.mdi-tv:before { + content: "\f2dc" +} + +.mdi-usb:before { + content: "\f2dd" +} + +.mdi-videocam-off:before { + content: "\f2de" +} + +.mdi-videocam-switch:before { + content: "\f2df" +} + +.mdi-videocam:before { + content: "\f2e0" +} + +.mdi-watch:before { + content: "\f2e1" +} + +.mdi-wifi-alt-2:before { + content: "\f2e2" +} + +.mdi-wifi-alt:before { + content: "\f2e3" +} + +.mdi-wifi-info:before { + content: "\f2e4" +} + +.mdi-wifi-lock:before { + content: "\f2e5" +} + +.mdi-wifi-off:before { + content: "\f2e6" +} + +.mdi-wifi-outline:before { + content: "\f2e7" +} + +.mdi-wifi:before { + content: "\f2e8" +} + +.mdi-arrow-left-bottom:before { + content: "\f2e9" +} + +.mdi-arrow-left:before { + content: "\f2ea" +} + +.mdi-arrow-merge:before { + content: "\f2eb" +} + +.mdi-arrow-missed:before { + content: "\f2ec" +} + +.mdi-arrow-right-top:before { + content: "\f2ed" +} + +.mdi-arrow-right:before { + content: "\f2ee" +} + +.mdi-arrow-split:before { + content: "\f2ef" +} + +.mdi-arrows:before { + content: "\f2f0" +} + +.mdi-caret-down-circle:before { + content: "\f2f1" +} + +.mdi-caret-down:before { + content: "\f2f2" +} + +.mdi-caret-left-circle:before { + content: "\f2f3" +} + +.mdi-caret-left:before { + content: "\f2f4" +} + +.mdi-caret-right-circle:before { + content: "\f2f5" +} + +.mdi-caret-right:before { + content: "\f2f6" +} + +.mdi-caret-up-circle:before { + content: "\f2f7" +} + +.mdi-caret-up:before { + content: "\f2f8" +} + +.mdi-chevron-down:before { + content: "\f2f9" +} + +.mdi-chevron-left:before { + content: "\f2fa" +} + +.mdi-chevron-right:before { + content: "\f2fb" +} + +.mdi-chevron-up:before { + content: "\f2fc" +} + +.mdi-forward:before { + content: "\f2fd" +} + +.mdi-long-arrow-down:before { + content: "\f2fe" +} + +.mdi-long-arrow-left:before { + content: "\f2ff" +} + +.mdi-long-arrow-return:before { + content: "\f300" +} + +.mdi-long-arrow-right:before { + content: "\f301" +} + +.mdi-long-arrow-tab:before { + content: "\f302" +} + +.mdi-long-arrow-up:before { + content: "\f303" +} + +.mdi-rotate-ccw:before { + content: "\f304" +} + +.mdi-rotate-cw:before { + content: "\f305" +} + +.mdi-rotate-left:before { + content: "\f306" +} + +.mdi-rotate-right:before { + content: "\f307" +} + +.mdi-square-down:before { + content: "\f308" +} + +.mdi-square-right:before { + content: "\f309" +} + +.mdi-swap-alt:before { + content: "\f30a" +} + +.mdi-swap-vertical-circle:before { + content: "\f30b" +} + +.mdi-swap-vertical:before { + content: "\f30c" +} + +.mdi-swap:before { + content: "\f30d" +} + +.mdi-trending-down:before { + content: "\f30e" +} + +.mdi-trending-flat:before { + content: "\f30f" +} + +.mdi-trending-up:before { + content: "\f310" +} + +.mdi-unfold-less:before { + content: "\f311" +} + +.mdi-unfold-more:before { + content: "\f312" +} + +.mdi-apps:before { + content: "\f313" +} + +.mdi-grid-off:before { + content: "\f314" +} + +.mdi-grid:before { + content: "\f315" +} + +.mdi-view-agenda:before { + content: "\f316" +} + +.mdi-view-array:before { + content: "\f317" +} + +.mdi-view-carousel:before { + content: "\f318" +} + +.mdi-view-column:before { + content: "\f319" +} + +.mdi-view-comfy:before { + content: "\f31a" +} + +.mdi-view-compact:before { + content: "\f31b" +} + +.mdi-view-dashboard:before { + content: "\f31c" +} + +.mdi-view-day:before { + content: "\f31d" +} + +.mdi-view-headline:before { + content: "\f31e" +} + +.mdi-view-list-alt:before { + content: "\f31f" +} + +.mdi-view-list:before { + content: "\f320" +} + +.mdi-view-module:before { + content: "\f321" +} + +.mdi-view-quilt:before { + content: "\f322" +} + +.mdi-view-stream:before { + content: "\f323" +} + +.mdi-view-subtitles:before { + content: "\f324" +} + +.mdi-view-toc:before { + content: "\f325" +} + +.mdi-view-web:before { + content: "\f326" +} + +.mdi-view-week:before { + content: "\f327" +} + +.mdi-widgets:before { + content: "\f328" +} + +.mdi-alarm-check:before { + content: "\f329" +} + +.mdi-alarm-off:before { + content: "\f32a" +} + +.mdi-alarm-plus:before { + content: "\f32b" +} + +.mdi-alarm-snooze:before { + content: "\f32c" +} + +.mdi-alarm:before { + content: "\f32d" +} + +.mdi-calendar-alt:before { + content: "\f32e" +} + +.mdi-calendar-check:before { + content: "\f32f" +} + +.mdi-calendar-close:before { + content: "\f330" +} + +.mdi-calendar-note:before { + content: "\f331" +} + +.mdi-calendar:before { + content: "\f332" +} + +.mdi-time-countdown:before { + content: "\f333" +} + +.mdi-time-interval:before { + content: "\f334" +} + +.mdi-time-restore-setting:before { + content: "\f335" +} + +.mdi-time-restore:before { + content: "\f336" +} + +.mdi-time:before { + content: "\f337" +} + +.mdi-timer-off:before { + content: "\f338" +} + +.mdi-timer:before { + content: "\f339" +} + +.mdi-android-alt:before { + content: "\f33a" +} + +.mdi-android:before { + content: "\f33b" +} + +.mdi-apple:before { + content: "\f33c" +} + +.mdi-behance:before { + content: "\f33d" +} + +.mdi-codepen:before { + content: "\f33e" +} + +.mdi-dribbble:before { + content: "\f33f" +} + +.mdi-dropbox:before { + content: "\f340" +} + +.mdi-evernote:before { + content: "\f341" +} + +.mdi-facebook-box:before { + content: "\f342" +} + +.mdi-facebook:before { + content: "\f343" +} + +.mdi-github-box:before { + content: "\f344" +} + +.mdi-github:before { + content: "\f345" +} + +.mdi-google-drive:before { + content: "\f346" +} + +.mdi-google-earth:before { + content: "\f347" +} + +.mdi-google-glass:before { + content: "\f348" +} + +.mdi-google-maps:before { + content: "\f349" +} + +.mdi-google-pages:before { + content: "\f34a" +} + +.mdi-google-play:before { + content: "\f34b" +} + +.mdi-google-plus-box:before { + content: "\f34c" +} + +.mdi-google-plus:before { + content: "\f34d" +} + +.mdi-google:before { + content: "\f34e" +} + +.mdi-instagram:before { + content: "\f34f" +} + +.mdi-language-css3:before { + content: "\f350" +} + +.mdi-language-html5:before { + content: "\f351" +} + +.mdi-language-javascript:before { + content: "\f352" +} + +.mdi-language-python-alt:before { + content: "\f353" +} + +.mdi-language-python:before { + content: "\f354" +} + +.mdi-lastfm:before { + content: "\f355" +} + +.mdi-linkedin-box:before { + content: "\f356" +} + +.mdi-paypal:before { + content: "\f357" +} + +.mdi-pinterest-box:before { + content: "\f358" +} + +.mdi-pocket:before { + content: "\f359" +} + +.mdi-polymer:before { + content: "\f35a" +} + +.mdi-share:before { + content: "\f35b" +} + +.mdi-stackoverflow:before { + content: "\f35c" +} + +.mdi-steam-square:before { + content: "\f35d" +} + +.mdi-steam:before { + content: "\f35e" +} + +.mdi-twitter-box:before { + content: "\f35f" +} + +.mdi-twitter:before { + content: "\f360" +} + +.mdi-vk:before { + content: "\f361" +} + +.mdi-wikipedia:before { + content: "\f362" +} + +.mdi-windows:before { + content: "\f363" +} + +.mdi-aspect-ratio-alt:before { + content: "\f364" +} + +.mdi-aspect-ratio:before { + content: "\f365" +} + +.mdi-blur-circular:before { + content: "\f366" +} + +.mdi-blur-linear:before { + content: "\f367" +} + +.mdi-blur-off:before { + content: "\f368" +} + +.mdi-blur:before { + content: "\f369" +} + +.mdi-brightness-2:before { + content: "\f36a" +} + +.mdi-brightness-3:before { + content: "\f36b" +} + +.mdi-brightness-4:before { + content: "\f36c" +} + +.mdi-brightness-5:before { + content: "\f36d" +} + +.mdi-brightness-6:before { + content: "\f36e" +} + +.mdi-brightness-7:before { + content: "\f36f" +} + +.mdi-brightness-auto:before { + content: "\f370" +} + +.mdi-brightness-setting:before { + content: "\f371" +} + +.mdi-broken-image:before { + content: "\f372" +} + +.mdi-center-focus-strong:before { + content: "\f373" +} + +.mdi-center-focus-weak:before { + content: "\f374" +} + +.mdi-compare:before { + content: "\f375" +} + +.mdi-crop-16-9:before { + content: "\f376" +} + +.mdi-crop-3-2:before { + content: "\f377" +} + +.mdi-crop-5-4:before { + content: "\f378" +} + +.mdi-crop-7-5:before { + content: "\f379" +} + +.mdi-crop-din:before { + content: "\f37a" +} + +.mdi-crop-free:before { + content: "\f37b" +} + +.mdi-crop-landscape:before { + content: "\f37c" +} + +.mdi-crop-portrait:before { + content: "\f37d" +} + +.mdi-crop-square:before { + content: "\f37e" +} + +.mdi-exposure-alt:before { + content: "\f37f" +} + +.mdi-exposure:before { + content: "\f380" +} + +.mdi-filter-b-and-w:before { + content: "\f381" +} + +.mdi-filter-center-focus:before { + content: "\f382" +} + +.mdi-filter-frames:before { + content: "\f383" +} + +.mdi-filter-tilt-shift:before { + content: "\f384" +} + +.mdi-gradient:before { + content: "\f385" +} + +.mdi-grain:before { + content: "\f386" +} + +.mdi-graphic-eq:before { + content: "\f387" +} + +.mdi-hdr-off:before { + content: "\f388" +} + +.mdi-hdr-strong:before { + content: "\f389" +} + +.mdi-hdr-weak:before { + content: "\f38a" +} + +.mdi-hdr:before { + content: "\f38b" +} + +.mdi-iridescent:before { + content: "\f38c" +} + +.mdi-leak-off:before { + content: "\f38d" +} + +.mdi-leak:before { + content: "\f38e" +} + +.mdi-looks:before { + content: "\f38f" +} + +.mdi-loupe:before { + content: "\f390" +} + +.mdi-panorama-horizontal:before { + content: "\f391" +} + +.mdi-panorama-vertical:before { + content: "\f392" +} + +.mdi-panorama-wide-angle:before { + content: "\f393" +} + +.mdi-photo-size-select-large:before { + content: "\f394" +} + +.mdi-photo-size-select-small:before { + content: "\f395" +} + +.mdi-picture-in-picture:before { + content: "\f396" +} + +.mdi-slideshow:before { + content: "\f397" +} + +.mdi-texture:before { + content: "\f398" +} + +.mdi-tonality:before { + content: "\f399" +} + +.mdi-vignette:before { + content: "\f39a" +} + +.mdi-wb-auto:before { + content: "\f39b" +} + +.mdi-eject-alt:before { + content: "\f39c" +} + +.mdi-eject:before { + content: "\f39d" +} + +.mdi-equalizer:before { + content: "\f39e" +} + +.mdi-fast-forward:before { + content: "\f39f" +} + +.mdi-fast-rewind:before { + content: "\f3a0" +} + +.mdi-forward-10:before { + content: "\f3a1" +} + +.mdi-forward-30:before { + content: "\f3a2" +} + +.mdi-forward-5:before { + content: "\f3a3" +} + +.mdi-hearing:before { + content: "\f3a4" +} + +.mdi-pause-circle-outline:before { + content: "\f3a5" +} + +.mdi-pause-circle:before { + content: "\f3a6" +} + +.mdi-pause:before { + content: "\f3a7" +} + +.mdi-play-circle-outline:before { + content: "\f3a8" +} + +.mdi-play-circle:before { + content: "\f3a9" +} + +.mdi-play:before { + content: "\f3aa" +} + +.mdi-playlist-audio:before { + content: "\f3ab" +} + +.mdi-playlist-plus:before { + content: "\f3ac" +} + +.mdi-repeat-one:before { + content: "\f3ad" +} + +.mdi-repeat:before { + content: "\f3ae" +} + +.mdi-replay-10:before { + content: "\f3af" +} + +.mdi-replay-30:before { + content: "\f3b0" +} + +.mdi-replay-5:before { + content: "\f3b1" +} + +.mdi-replay:before { + content: "\f3b2" +} + +.mdi-shuffle:before { + content: "\f3b3" +} + +.mdi-skip-next:before { + content: "\f3b4" +} + +.mdi-skip-previous:before { + content: "\f3b5" +} + +.mdi-stop:before { + content: "\f3b6" +} + +.mdi-surround-sound:before { + content: "\f3b7" +} + +.mdi-tune:before { + content: "\f3b8" +} + +.mdi-volume-down:before { + content: "\f3b9" +} + +.mdi-volume-mute:before { + content: "\f3ba" +} + +.mdi-volume-off:before { + content: "\f3bb" +} + +.mdi-volume-up:before { + content: "\f3bc" +} + +.mdi-n-1-square:before { + content: "\f3bd" +} + +.mdi-n-2-square:before { + content: "\f3be" +} + +.mdi-n-3-square:before { + content: "\f3bf" +} + +.mdi-n-4-square:before { + content: "\f3c0" +} + +.mdi-n-5-square:before { + content: "\f3c1" +} + +.mdi-n-6-square:before { + content: "\f3c2" +} + +.mdi-neg-1:before { + content: "\f3c3" +} + +.mdi-neg-2:before { + content: "\f3c4" +} + +.mdi-plus-1:before { + content: "\f3c5" +} + +.mdi-plus-2:before { + content: "\f3c6" +} + +.mdi-sec-10:before { + content: "\f3c7" +} + +.mdi-sec-3:before { + content: "\f3c8" +} + +.mdi-zero:before { + content: "\f3c9" +} + +.mdi-airline-seat-flat-angled:before { + content: "\f3ca" +} + +.mdi-airline-seat-flat:before { + content: "\f3cb" +} + +.mdi-airline-seat-individual-suite:before { + content: "\f3cc" +} + +.mdi-airline-seat-legroom-extra:before { + content: "\f3cd" +} + +.mdi-airline-seat-legroom-normal:before { + content: "\f3ce" +} + +.mdi-airline-seat-legroom-reduced:before { + content: "\f3cf" +} + +.mdi-airline-seat-recline-extra:before { + content: "\f3d0" +} + +.mdi-airline-seat-recline-normal:before { + content: "\f3d1" +} + +.mdi-airplay:before { + content: "\f3d2" +} + +.mdi-closed-caption:before { + content: "\f3d3" +} + +.mdi-confirmation-number:before { + content: "\f3d4" +} + +.mdi-developer-board:before { + content: "\f3d5" +} + +.mdi-disc-full:before { + content: "\f3d6" +} + +.mdi-explicit:before { + content: "\f3d7" +} + +.mdi-flight-land:before { + content: "\f3d8" +} + +.mdi-flight-takeoff:before { + content: "\f3d9" +} + +.mdi-flip-to-back:before { + content: "\f3da" +} + +.mdi-flip-to-front:before { + content: "\f3db" +} + +.mdi-group-work:before { + content: "\f3dc" +} + +.mdi-hd:before { + content: "\f3dd" +} + +.mdi-hq:before { + content: "\f3de" +} + +.mdi-markunread-mailbox:before { + content: "\f3df" +} + +.mdi-memory:before { + content: "\f3e0" +} + +.mdi-nfc:before { + content: "\f3e1" +} + +.mdi-play-for-work:before { + content: "\f3e2" +} + +.mdi-power-input:before { + content: "\f3e3" +} + +.mdi-present-to-all:before { + content: "\f3e4" +} + +.mdi-satellite:before { + content: "\f3e5" +} + +.mdi-tap-and-play:before { + content: "\f3e6" +} + +.mdi-vibration:before { + content: "\f3e7" +} + +.mdi-voicemail:before { + content: "\f3e8" +} + +.mdi-group:before { + content: "\f3e9" +} + +.mdi-rss:before { + content: "\f3ea" +} + +.mdi-shape:before { + content: "\f3eb" +} + +.mdi-spinner:before { + content: "\f3ec" +} + +.mdi-ungroup:before { + content: "\f3ed" +} + +.mdi-500px:before { + content: "\f3ee" +} + +.mdi-8tracks:before { + content: "\f3ef" +} + +.mdi-amazon:before { + content: "\f3f0" +} + +.mdi-blogger:before { + content: "\f3f1" +} + +.mdi-delicious:before { + content: "\f3f2" +} + +.mdi-disqus:before { + content: "\f3f3" +} + +.mdi-flattr:before { + content: "\f3f4" +} + +.mdi-flickr:before { + content: "\f3f5" +} + +.mdi-github-alt:before { + content: "\f3f6" +} + +.mdi-google-old:before { + content: "\f3f7" +} + +.mdi-linkedin:before { + content: "\f3f8" +} + +.mdi-odnoklassniki:before { + content: "\f3f9" +} + +.mdi-outlook:before { + content: "\f3fa" +} + +.mdi-paypal-alt:before { + content: "\f3fb" +} + +.mdi-pinterest:before { + content: "\f3fc" +} + +.mdi-playstation:before { + content: "\f3fd" +} + +.mdi-reddit:before { + content: "\f3fe" +} + +.mdi-skype:before { + content: "\f3ff" +} + +.mdi-slideshare:before { + content: "\f400" +} + +.mdi-soundcloud:before { + content: "\f401" +} + +.mdi-tumblr:before { + content: "\f402" +} + +.mdi-twitch:before { + content: "\f403" +} + +.mdi-vimeo:before { + content: "\f404" +} + +.mdi-whatsapp:before { + content: "\f405" +} + +.mdi-xbox:before { + content: "\f406" +} + +.mdi-yahoo:before { + content: "\f407" +} + +.mdi-youtube-play:before { + content: "\f408" +} + +.mdi-youtube:before { + content: "\f409" +} + +.mdi-3d-rotation:before { + content: "\f101" +} + +.mdi-airplane-off:before { + content: "\f102" +} + +.mdi-airplane:before { + content: "\f103" +} + +.mdi-album:before { + content: "\f104" +} + +.mdi-archive:before { + content: "\f105" +} + +.mdi-assignment-account:before { + content: "\f106" +} + +.mdi-assignment-alert:before { + content: "\f107" +} + +.mdi-assignment-check:before { + content: "\f108" +} + +.mdi-assignment-o:before { + content: "\f109" +} + +.mdi-assignment-return:before { + content: "\f10a" +} + +.mdi-assignment-returned:before { + content: "\f10b" +} + +.mdi-assignment:before { + content: "\f10c" +} + +.mdi-attachment-alt:before { + content: "\f10d" +} + +.mdi-attachment:before { + content: "\f10e" +} + +.mdi-audio:before { + content: "\f10f" +} + +.mdi-badge-check:before { + content: "\f110" +} + +.mdi-balance-wallet:before { + content: "\f111" +} + +.mdi-balance:before { + content: "\f112" +} + +.mdi-battery-alert:before { + content: "\f113" +} + +.mdi-battery-flash:before { + content: "\f114" +} + +.mdi-battery-unknown:before { + content: "\f115" +} + +.mdi-battery:before { + content: "\f116" +} + +.mdi-bike:before { + content: "\f117" +} + +.mdi-block-alt:before { + content: "\f118" +} + +.mdi-block:before { + content: "\f119" +} + +.mdi-boat:before { + content: "\f11a" +} + +.mdi-book-image:before { + content: "\f11b" +} + +.mdi-book:before { + content: "\f11c" +} + +.mdi-bookmark-outline:before { + content: "\f11d" +} + +.mdi-bookmark:before { + content: "\f11e" +} + +.mdi-brush:before { + content: "\f11f" +} + +.mdi-bug:before { + content: "\f120" +} + +.mdi-bus:before { + content: "\f121" +} + +.mdi-cake:before { + content: "\f122" +} + +.mdi-car-taxi:before { + content: "\f123" +} + +.mdi-car-wash:before { + content: "\f124" +} + +.mdi-car:before { + content: "\f125" +} + +.mdi-card-giftcard:before { + content: "\f126" +} + +.mdi-card-membership:before { + content: "\f127" +} + +.mdi-card-travel:before { + content: "\f128" +} + +.mdi-card:before { + content: "\f129" +} + +.mdi-case-check:before { + content: "\f12a" +} + +.mdi-case-download:before { + content: "\f12b" +} + +.mdi-case-play:before { + content: "\f12c" +} + +.mdi-case:before { + content: "\f12d" +} + +.mdi-cast-connected:before { + content: "\f12e" +} + +.mdi-cast:before { + content: "\f12f" +} + +.mdi-chart-donut:before { + content: "\f130" +} + +.mdi-chart:before { + content: "\f131" +} + +.mdi-city-alt:before { + content: "\f132" +} + +.mdi-city:before { + content: "\f133" +} + +.mdi-close-circle-o:before { + content: "\f134" +} + +.mdi-close-circle:before { + content: "\f135" +} + +.mdi-close:before { + content: "\f136" +} + +.mdi-cocktail:before { + content: "\f137" +} + +.mdi-code-setting:before { + content: "\f138" +} + +.mdi-code-smartphone:before { + content: "\f139" +} + +.mdi-code:before { + content: "\f13a" +} + +.mdi-coffee:before { + content: "\f13b" +} + +.mdi-collection-bookmark:before { + content: "\f13c" +} + +.mdi-collection-case-play:before { + content: "\f13d" +} + +.mdi-collection-folder-image:before { + content: "\f13e" +} + +.mdi-collection-image-o:before { + content: "\f13f" +} + +.mdi-collection-image:before { + content: "\f140" +} + +.mdi-collection-item-1:before { + content: "\f141" +} + +.mdi-collection-item-2:before { + content: "\f142" +} + +.mdi-collection-item-3:before { + content: "\f143" +} + +.mdi-collection-item-4:before { + content: "\f144" +} + +.mdi-collection-item-5:before { + content: "\f145" +} + +.mdi-collection-item-6:before { + content: "\f146" +} + +.mdi-collection-item-7:before { + content: "\f147" +} + +.mdi-collection-item-8:before { + content: "\f148" +} + +.mdi-collection-item-9-plus:before { + content: "\f149" +} + +.mdi-collection-item-9:before { + content: "\f14a" +} + +.mdi-collection-item:before { + content: "\f14b" +} + +.mdi-collection-music:before { + content: "\f14c" +} + +.mdi-collection-pdf:before { + content: "\f14d" +} + +.mdi-collection-plus:before { + content: "\f14e" +} + +.mdi-collection-speaker:before { + content: "\f14f" +} + +.mdi-collection-text:before { + content: "\f150" +} + +.mdi-collection-video:before { + content: "\f151" +} + +.mdi-compass:before { + content: "\f152" +} + +.mdi-cutlery:before { + content: "\f153" +} + +.mdi-delete:before { + content: "\f154" +} + +.mdi-dialpad:before { + content: "\f155" +} + +.mdi-dns:before { + content: "\f156" +} + +.mdi-drink:before { + content: "\f157" +} + +.mdi-edit:before { + content: "\f158" +} + +.mdi-email-open:before { + content: "\f159" +} + +.mdi-email:before { + content: "\f15a" +} + +.mdi-eye-off:before { + content: "\f15b" +} + +.mdi-eye:before { + content: "\f15c" +} + +.mdi-eyedropper:before { + content: "\f15d" +} + +.mdi-favorite-outline:before { + content: "\f15e" +} + +.mdi-favorite:before { + content: "\f15f" +} + +.mdi-filter-list:before { + content: "\f160" +} + +.mdi-fire:before { + content: "\f161" +} + +.mdi-flag:before { + content: "\f162" +} + +.mdi-flare:before { + content: "\f163" +} + +.mdi-flash-auto:before { + content: "\f164" +} + +.mdi-flash-off:before { + content: "\f165" +} + +.mdi-flash:before { + content: "\f166" +} + +.mdi-flip:before { + content: "\f167" +} + +.mdi-flower-alt:before { + content: "\f168" +} + +.mdi-flower:before { + content: "\f169" +} + +.mdi-font:before { + content: "\f16a" +} + +.mdi-fullscreen-alt:before { + content: "\f16b" +} + +.mdi-fullscreen-exit:before { + content: "\f16c" +} + +.mdi-fullscreen:before { + content: "\f16d" +} + +.mdi-functions:before { + content: "\f16e" +} + +.mdi-gas-station:before { + content: "\f16f" +} + +.mdi-gesture:before { + content: "\f170" +} + +.mdi-globe-alt:before { + content: "\f171" +} + +.mdi-globe-lock:before { + content: "\f172" +} + +.mdi-globe:before { + content: "\f173" +} + +.mdi-graduation-cap:before { + content: "\f174" +} + +.mdi-home:before { + content: "\f175" +} + +.mdi-hospital-alt:before { + content: "\f176" +} + +.mdi-hospital:before { + content: "\f177" +} + +.mdi-hotel:before { + content: "\f178" +} + +.mdi-hourglass-alt:before { + content: "\f179" +} + +.mdi-hourglass-outline:before { + content: "\f17a" +} + +.mdi-hourglass:before { + content: "\f17b" +} + +.mdi-http:before { + content: "\f17c" +} + +.mdi-image-alt:before { + content: "\f17d" +} + +.mdi-image-o:before { + content: "\f17e" +} + +.mdi-image:before { + content: "\f17f" +} + +.mdi-inbox:before { + content: "\f180" +} + +.mdi-invert-colors-off:before { + content: "\f181" +} + +.mdi-invert-colors:before { + content: "\f182" +} + +.mdi-key:before { + content: "\f183" +} + +.mdi-label-alt-outline:before { + content: "\f184" +} + +.mdi-label-alt:before { + content: "\f185" +} + +.mdi-label-heart:before { + content: "\f186" +} + +.mdi-label:before { + content: "\f187" +} + +.mdi-labels:before { + content: "\f188" +} + +.mdi-lamp:before { + content: "\f189" +} + +.mdi-landscape:before { + content: "\f18a" +} + +.mdi-layers-off:before { + content: "\f18b" +} + +.mdi-layers:before { + content: "\f18c" +} + +.mdi-library:before { + content: "\f18d" +} + +.mdi-link:before { + content: "\f18e" +} + +.mdi-lock-open:before { + content: "\f18f" +} + +.mdi-lock-outline:before { + content: "\f190" +} + +.mdi-lock:before { + content: "\f191" +} + +.mdi-mail-reply-all:before { + content: "\f192" +} + +.mdi-mail-reply:before { + content: "\f193" +} + +.mdi-mail-send:before { + content: "\f194" +} + +.mdi-mall:before { + content: "\f195" +} + +.mdi-map:before { + content: "\f196" +} + +.mdi-menu:before { + content: "\f197" +} + +.mdi-money-box:before { + content: "\f198" +} + +.mdi-money-off:before { + content: "\f199" +} + +.mdi-money:before { + content: "\f19a" +} + +.mdi-more-vert:before { + content: "\f19b" +} + +.mdi-more:before { + content: "\f19c" +} + +.mdi-movie-alt:before { + content: "\f19d" +} + +.mdi-movie:before { + content: "\f19e" +} + +.mdi-nature-people:before { + content: "\f19f" +} + +.mdi-nature:before { + content: "\f1a0" +} + +.mdi-navigation:before { + content: "\f1a1" +} + +.mdi-open-in-browser:before { + content: "\f1a2" +} + +.mdi-open-in-new:before { + content: "\f1a3" +} + +.mdi-palette:before { + content: "\f1a4" +} + +.mdi-parking:before { + content: "\f1a5" +} + +.mdi-pin-account:before { + content: "\f1a6" +} + +.mdi-pin-assistant:before { + content: "\f1a7" +} + +.mdi-pin-drop:before { + content: "\f1a8" +} + +.mdi-pin-help:before { + content: "\f1a9" +} + +.mdi-pin-off:before { + content: "\f1aa" +} + +.mdi-pin:before { + content: "\f1ab" +} + +.mdi-pizza:before { + content: "\f1ac" +} + +.mdi-plaster:before { + content: "\f1ad" +} + +.mdi-power-setting:before { + content: "\f1ae" +} + +.mdi-power:before { + content: "\f1af" +} + +.mdi-print:before { + content: "\f1b0" +} + +.mdi-puzzle-piece:before { + content: "\f1b1" +} + +.mdi-quote:before { + content: "\f1b2" +} + +.mdi-railway:before { + content: "\f1b3" +} + +.mdi-receipt:before { + content: "\f1b4" +} + +.mdi-refresh-alt:before { + content: "\f1b5" +} + +.mdi-refresh-sync-alert:before { + content: "\f1b6" +} + +.mdi-refresh-sync-off:before { + content: "\f1b7" +} + +.mdi-refresh-sync:before { + content: "\f1b8" +} + +.mdi-refresh:before { + content: "\f1b9" +} + +.mdi-roller:before { + content: "\f1ba" +} + +.mdi-ruler:before { + content: "\f1bb" +} + +.mdi-scissors:before { + content: "\f1bc" +} + +.mdi-screen-rotation-lock:before { + content: "\f1bd" +} + +.mdi-screen-rotation:before { + content: "\f1be" +} + +.mdi-search-for:before { + content: "\f1bf" +} + +.mdi-search-in-file:before { + content: "\f1c0" +} + +.mdi-search-in-page:before { + content: "\f1c1" +} + +.mdi-search-replace:before { + content: "\f1c2" +} + +.mdi-search:before { + content: "\f1c3" +} + +.mdi-seat:before { + content: "\f1c4" +} + +.mdi-settings-square:before { + content: "\f1c5" +} + +.mdi-settings:before { + content: "\f1c6" +} + +.mdi-shield-check:before { + content: "\f1c7" +} + +.mdi-shield-security:before { + content: "\f1c8" +} + +.mdi-shopping-basket:before { + content: "\f1c9" +} + +.mdi-shopping-cart-plus:before { + content: "\f1ca" +} + +.mdi-shopping-cart:before { + content: "\f1cb" +} + +.mdi-sign-in:before { + content: "\f1cc" +} + +.mdi-sort-amount-asc:before { + content: "\f1cd" +} + +.mdi-sort-amount-desc:before { + content: "\f1ce" +} + +.mdi-sort-asc:before { + content: "\f1cf" +} + +.mdi-sort-desc:before { + content: "\f1d0" +} + +.mdi-spellcheck:before { + content: "\f1d1" +} + +.mdi-storage:before { + content: "\f1d2" +} + +.mdi-store-24:before { + content: "\f1d3" +} + +.mdi-store:before { + content: "\f1d4" +} + +.mdi-subway:before { + content: "\f1d5" +} + +.mdi-sun:before { + content: "\f1d6" +} + +.mdi-tab-unselected:before { + content: "\f1d7" +} + +.mdi-tab:before { + content: "\f1d8" +} + +.mdi-tag-close:before { + content: "\f1d9" +} + +.mdi-tag-more:before { + content: "\f1da" +} + +.mdi-tag:before { + content: "\f1db" +} + +.mdi-thumb-down:before { + content: "\f1dc" +} + +.mdi-thumb-up-down:before { + content: "\f1dd" +} + +.mdi-thumb-up:before { + content: "\f1de" +} + +.mdi-ticket-star:before { + content: "\f1df" +} + +.mdi-toll:before { + content: "\f1e0" +} + +.mdi-toys:before { + content: "\f1e1" +} + +.mdi-traffic:before { + content: "\f1e2" +} + +.mdi-translate:before { + content: "\f1e3" +} + +.mdi-triangle-down:before { + content: "\f1e4" +} + +.mdi-triangle-up:before { + content: "\f1e5" +} + +.mdi-truck:before { + content: "\f1e6" +} + +.mdi-turning-sign:before { + content: "\f1e7" +} + +.mdi-wallpaper:before { + content: "\f1e8" +} + +.mdi-washing-machine:before { + content: "\f1e9" +} + +.mdi-window-maximize:before { + content: "\f1ea" +} + +.mdi-window-minimize:before { + content: "\f1eb" +} + +.mdi-window-restore:before { + content: "\f1ec" +} + +.mdi-wrench:before { + content: "\f1ed" +} + +.mdi-zoom-in:before { + content: "\f1ee" +} + +.mdi-zoom-out:before { + content: "\f1ef" +} + +.mdi-alert-circle-o:before { + content: "\f1f0" +} + +.mdi-alert-circle:before { + content: "\f1f1" +} + +.mdi-alert-octagon:before { + content: "\f1f2" +} + +.mdi-alert-polygon:before { + content: "\f1f3" +} + +.mdi-alert-triangle:before { + content: "\f1f4" +} + +.mdi-help-outline:before { + content: "\f1f5" +} + +.mdi-help:before { + content: "\f1f6" +} + +.mdi-info-outline:before { + content: "\f1f7" +} + +.mdi-info:before { + content: "\f1f8" +} + +.mdi-notifications-active:before { + content: "\f1f9" +} + +.mdi-notifications-add:before { + content: "\f1fa" +} + +.mdi-notifications-none:before { + content: "\f1fb" +} + +.mdi-notifications-off:before { + content: "\f1fc" +} + +.mdi-notifications-paused:before { + content: "\f1fd" +} + +.mdi-notifications:before { + content: "\f1fe" +} + +.mdi-account-add:before { + content: "\f1ff" +} + +.mdi-account-box-mail:before { + content: "\f200" +} + +.mdi-account-box-o:before { + content: "\f201" +} + +.mdi-account-box-phone:before { + content: "\f202" +} + +.mdi-account-box:before { + content: "\f203" +} + +.mdi-account-calendar:before { + content: "\f204" +} + +.mdi-account-circle:before { + content: "\f205" +} + +.mdi-account-o:before { + content: "\f206" +} + +.mdi-account:before { + content: "\f207" +} + +.mdi-accounts-add:before { + content: "\f208" +} + +.mdi-accounts-alt:before { + content: "\f209" +} + +.mdi-accounts-list-alt:before { + content: "\f20a" +} + +.mdi-accounts-list:before { + content: "\f20b" +} + +.mdi-accounts-outline:before { + content: "\f20c" +} + +.mdi-accounts:before { + content: "\f20d" +} + +.mdi-face:before { + content: "\f20e" +} + +.mdi-female:before { + content: "\f20f" +} + +.mdi-male-alt:before { + content: "\f210" +} + +.mdi-male-female:before { + content: "\f211" +} + +.mdi-male:before { + content: "\f212" +} + +.mdi-mood-bad:before { + content: "\f213" +} + +.mdi-mood:before { + content: "\f214" +} + +.mdi-run:before { + content: "\f215" +} + +.mdi-walk:before { + content: "\f216" +} + +.mdi-cloud-box:before { + content: "\f217" +} + +.mdi-cloud-circle:before { + content: "\f218" +} + +.mdi-cloud-done:before { + content: "\f219" +} + +.mdi-cloud-download:before { + content: "\f21a" +} + +.mdi-cloud-off:before { + content: "\f21b" +} + +.mdi-cloud-outline-alt:before { + content: "\f21c" +} + +.mdi-cloud-outline:before { + content: "\f21d" +} + +.mdi-cloud-upload:before { + content: "\f21e" +} + +.mdi-cloud:before { + content: "\f21f" +} + +.mdi-download:before { + content: "\f220" +} + +.mdi-file-plus:before { + content: "\f221" +} + +.mdi-file-text:before { + content: "\f222" +} + +.mdi-file:before { + content: "\f223" +} + +.mdi-folder-outline:before { + content: "\f224" +} + +.mdi-folder-person:before { + content: "\f225" +} + +.mdi-folder-star-alt:before { + content: "\f226" +} + +.mdi-folder-star:before { + content: "\f227" +} + +.mdi-folder:before { + content: "\f228" +} + +.mdi-gif:before { + content: "\f229" +} + +.mdi-upload:before { + content: "\f22a" +} + +.mdi-border-all:before { + content: "\f22b" +} + +.mdi-border-bottom:before { + content: "\f22c" +} + +.mdi-border-clear:before { + content: "\f22d" +} + +.mdi-border-color:before { + content: "\f22e" +} + +.mdi-border-horizontal:before { + content: "\f22f" +} + +.mdi-border-inner:before { + content: "\f230" +} + +.mdi-border-left:before { + content: "\f231" +} + +.mdi-border-outer:before { + content: "\f232" +} + +.mdi-border-right:before { + content: "\f233" +} + +.mdi-border-style:before { + content: "\f234" +} + +.mdi-border-top:before { + content: "\f235" +} + +.mdi-border-vertical:before { + content: "\f236" +} + +.mdi-copy:before { + content: "\f237" +} + +.mdi-crop:before { + content: "\f238" +} + +.mdi-format-align-center:before { + content: "\f239" +} + +.mdi-format-align-justify:before { + content: "\f23a" +} + +.mdi-format-align-left:before { + content: "\f23b" +} + +.mdi-format-align-right:before { + content: "\f23c" +} + +.mdi-format-bold:before { + content: "\f23d" +} + +.mdi-format-clear-all:before { + content: "\f23e" +} + +.mdi-format-clear:before { + content: "\f23f" +} + +.mdi-format-color-fill:before { + content: "\f240" +} + +.mdi-format-color-reset:before { + content: "\f241" +} + +.mdi-format-color-text:before { + content: "\f242" +} + +.mdi-format-indent-decrease:before { + content: "\f243" +} + +.mdi-format-indent-increase:before { + content: "\f244" +} + +.mdi-format-italic:before { + content: "\f245" +} + +.mdi-format-line-spacing:before { + content: "\f246" +} + +.mdi-format-list-bulleted:before { + content: "\f247" +} + +.mdi-format-list-numbered:before { + content: "\f248" +} + +.mdi-format-ltr:before { + content: "\f249" +} + +.mdi-format-rtl:before { + content: "\f24a" +} + +.mdi-format-size:before { + content: "\f24b" +} + +.mdi-format-strikethrough-s:before { + content: "\f24c" +} + +.mdi-format-strikethrough:before { + content: "\f24d" +} + +.mdi-format-subject:before { + content: "\f24e" +} + +.mdi-format-underlined:before { + content: "\f24f" +} + +.mdi-format-valign-bottom:before { + content: "\f250" +} + +.mdi-format-valign-center:before { + content: "\f251" +} + +.mdi-format-valign-top:before { + content: "\f252" +} + +.mdi-redo:before { + content: "\f253" +} + +.mdi-select-all:before { + content: "\f254" +} + +.mdi-space-bar:before { + content: "\f255" +} + +.mdi-text-format:before { + content: "\f256" +} + +.mdi-transform:before { + content: "\f257" +} + +.mdi-undo:before { + content: "\f258" +} + +.mdi-wrap-text:before { + content: "\f259" +} + +.mdi-comment-alert:before { + content: "\f25a" +} + +.mdi-comment-alt-text:before { + content: "\f25b" +} + +.mdi-comment-alt:before { + content: "\f25c" +} + +.mdi-comment-edit:before { + content: "\f25d" +} + +.mdi-comment-image:before { + content: "\f25e" +} + +.mdi-comment-list:before { + content: "\f25f" +} + +.mdi-comment-more:before { + content: "\f260" +} + +.mdi-comment-outline:before { + content: "\f261" +} + +.mdi-comment-text-alt:before { + content: "\f262" +} + +.mdi-comment-text:before { + content: "\f263" +} + +.mdi-comment-video:before { + content: "\f264" +} + +.mdi-comment:before { + content: "\f265" +} + +.mdi-comments:before { + content: "\f266" +} + +.mdi-check-all:before { + content: "\f267" +} + +.mdi-check-circle-u:before { + content: "\f268" +} + +.mdi-check-circle:before { + content: "\f269" +} + +.mdi-check-square:before { + content: "\f26a" +} + +.mdi-check:before { + content: "\f26b" +} + +.mdi-circle-o:before { + content: "\f26c" +} + +.mdi-circle:before { + content: "\f26d" +} + +.mdi-dot-circle-alt:before { + content: "\f26e" +} + +.mdi-dot-circle:before { + content: "\f26f" +} + +.mdi-minus-circle-outline:before { + content: "\f270" +} + +.mdi-minus-circle:before { + content: "\f271" +} + +.mdi-minus-square:before { + content: "\f272" +} + +.mdi-minus:before { + content: "\f273" +} + +.mdi-plus-circle-o-duplicate:before { + content: "\f274" +} + +.mdi-plus-circle-o:before { + content: "\f275" +} + +.mdi-plus-circle:before { + content: "\f276" +} + +.mdi-plus-square:before { + content: "\f277" +} + +.mdi-plus:before { + content: "\f278" +} + +.mdi-square-o:before { + content: "\f279" +} + +.mdi-star-circle:before { + content: "\f27a" +} + +.mdi-star-half:before { + content: "\f27b" +} + +.mdi-star-outline:before { + content: "\f27c" +} + +.mdi-star:before { + content: "\f27d" +} + +.mdi-bluetooth-connected:before { + content: "\f27e" +} + +.mdi-bluetooth-off:before { + content: "\f27f" +} + +.mdi-bluetooth-search:before { + content: "\f280" +} + +.mdi-bluetooth-setting:before { + content: "\f281" +} + +.mdi-bluetooth:before { + content: "\f282" +} + +.mdi-camera-add:before { + content: "\f283" +} + +.mdi-camera-alt:before { + content: "\f284" +} + +.mdi-camera-bw:before { + content: "\f285" +} + +.mdi-camera-front:before { + content: "\f286" +} + +.mdi-camera-mic:before { + content: "\f287" +} + +.mdi-camera-party-mode:before { + content: "\f288" +} + +.mdi-camera-rear:before { + content: "\f289" +} + +.mdi-camera-roll:before { + content: "\f28a" +} + +.mdi-camera-switch:before { + content: "\f28b" +} + +.mdi-camera:before { + content: "\f28c" +} + +.mdi-card-alert:before { + content: "\f28d" +} + +.mdi-card-off:before { + content: "\f28e" +} + +.mdi-card-sd:before { + content: "\f28f" +} + +.mdi-card-sim:before { + content: "\f290" +} + +.mdi-desktop-mac:before { + content: "\f291" +} + +.mdi-desktop-windows:before { + content: "\f292" +} + +.mdi-device-hub:before { + content: "\f293" +} + +.mdi-devices-off:before { + content: "\f294" +} + +.mdi-devices:before { + content: "\f295" +} + +.mdi-dock:before { + content: "\f296" +} + +.mdi-floppy:before { + content: "\f297" +} + +.mdi-gamepad:before { + content: "\f298" +} + +.mdi-gps-dot:before { + content: "\f299" +} + +.mdi-gps-off:before { + content: "\f29a" +} + +.mdi-gps:before { + content: "\f29b" +} + +.mdi-headset-mic:before { + content: "\f29c" +} + +.mdi-headset:before { + content: "\f29d" +} + +.mdi-input-antenna:before { + content: "\f29e" +} + +.mdi-input-composite:before { + content: "\f29f" +} + +.mdi-input-hdmi:before { + content: "\f2a0" +} + +.mdi-input-power:before { + content: "\f2a1" +} + +.mdi-input-svideo:before { + content: "\f2a2" +} + +.mdi-keyboard-hide:before { + content: "\f2a3" +} + +.mdi-keyboard:before { + content: "\f2a4" +} + +.mdi-laptop-chromebook:before { + content: "\f2a5" +} + +.mdi-laptop-mac:before { + content: "\f2a6" +} + +.mdi-laptop:before { + content: "\f2a7" +} + +.mdi-mic-off:before { + content: "\f2a8" +} + +.mdi-mic-outline:before { + content: "\f2a9" +} + +.mdi-mic-setting:before { + content: "\f2aa" +} + +.mdi-mic:before { + content: "\f2ab" +} + +.mdi-mouse:before { + content: "\f2ac" +} + +.mdi-network-alert:before { + content: "\f2ad" +} + +.mdi-network-locked:before { + content: "\f2ae" +} + +.mdi-network-off:before { + content: "\f2af" +} + +.mdi-network-outline:before { + content: "\f2b0" +} + +.mdi-network-setting:before { + content: "\f2b1" +} + +.mdi-network:before { + content: "\f2b2" +} + +.mdi-phone-bluetooth:before { + content: "\f2b3" +} + +.mdi-phone-end:before { + content: "\f2b4" +} + +.mdi-phone-forwarded:before { + content: "\f2b5" +} + +.mdi-phone-in-talk:before { + content: "\f2b6" +} + +.mdi-phone-locked:before { + content: "\f2b7" +} + +.mdi-phone-missed:before { + content: "\f2b8" +} + +.mdi-phone-msg:before { + content: "\f2b9" +} + +.mdi-phone-paused:before { + content: "\f2ba" +} + +.mdi-phone-ring:before { + content: "\f2bb" +} + +.mdi-phone-setting:before { + content: "\f2bc" +} + +.mdi-phone-sip:before { + content: "\f2bd" +} + +.mdi-phone:before { + content: "\f2be" +} + +.mdi-portable-wifi-changes:before { + content: "\f2bf" +} + +.mdi-portable-wifi-off:before { + content: "\f2c0" +} + +.mdi-portable-wifi:before { + content: "\f2c1" +} + +.mdi-radio:before { + content: "\f2c2" +} + +.mdi-reader:before { + content: "\f2c3" +} + +.mdi-remote-control-alt:before { + content: "\f2c4" +} + +.mdi-remote-control:before { + content: "\f2c5" +} + +.mdi-router:before { + content: "\f2c6" +} + +.mdi-scanner:before { + content: "\f2c7" +} + +.mdi-smartphone-android:before { + content: "\f2c8" +} + +.mdi-smartphone-download:before { + content: "\f2c9" +} + +.mdi-smartphone-erase:before { + content: "\f2ca" +} + +.mdi-smartphone-info:before { + content: "\f2cb" +} + +.mdi-smartphone-iphone:before { + content: "\f2cc" +} + +.mdi-smartphone-landscape-lock:before { + content: "\f2cd" +} + +.mdi-smartphone-landscape:before { + content: "\f2ce" +} + +.mdi-smartphone-lock:before { + content: "\f2cf" +} + +.mdi-smartphone-portrait-lock:before { + content: "\f2d0" +} + +.mdi-smartphone-ring:before { + content: "\f2d1" +} + +.mdi-smartphone-setting:before { + content: "\f2d2" +} + +.mdi-smartphone-setup:before { + content: "\f2d3" +} + +.mdi-smartphone:before { + content: "\f2d4" +} + +.mdi-speaker:before { + content: "\f2d5" +} + +.mdi-tablet-android:before { + content: "\f2d6" +} + +.mdi-tablet-mac:before { + content: "\f2d7" +} + +.mdi-tablet:before { + content: "\f2d8" +} + +.mdi-tv-alt-play:before { + content: "\f2d9" +} + +.mdi-tv-list:before { + content: "\f2da" +} + +.mdi-tv-play:before { + content: "\f2db" +} + +.mdi-tv:before { + content: "\f2dc" +} + +.mdi-usb:before { + content: "\f2dd" +} + +.mdi-videocam-off:before { + content: "\f2de" +} + +.mdi-videocam-switch:before { + content: "\f2df" +} + +.mdi-videocam:before { + content: "\f2e0" +} + +.mdi-watch:before { + content: "\f2e1" +} + +.mdi-wifi-alt-2:before { + content: "\f2e2" +} + +.mdi-wifi-alt:before { + content: "\f2e3" +} + +.mdi-wifi-info:before { + content: "\f2e4" +} + +.mdi-wifi-lock:before { + content: "\f2e5" +} + +.mdi-wifi-off:before { + content: "\f2e6" +} + +.mdi-wifi-outline:before { + content: "\f2e7" +} + +.mdi-wifi:before { + content: "\f2e8" +} + +.mdi-arrow-left-bottom:before { + content: "\f2e9" +} + +.mdi-arrow-left:before { + content: "\f2ea" +} + +.mdi-arrow-merge:before { + content: "\f2eb" +} + +.mdi-arrow-missed:before { + content: "\f2ec" +} + +.mdi-arrow-right-top:before { + content: "\f2ed" +} + +.mdi-arrow-right:before { + content: "\f2ee" +} + +.mdi-arrow-split:before { + content: "\f2ef" +} + +.mdi-arrows:before { + content: "\f2f0" +} + +.mdi-caret-down-circle:before { + content: "\f2f1" +} + +.mdi-caret-down:before { + content: "\f2f2" +} + +.mdi-caret-left-circle:before { + content: "\f2f3" +} + +.mdi-caret-left:before { + content: "\f2f4" +} + +.mdi-caret-right-circle:before { + content: "\f2f5" +} + +.mdi-caret-right:before { + content: "\f2f6" +} + +.mdi-caret-up-circle:before { + content: "\f2f7" +} + +.mdi-caret-up:before { + content: "\f2f8" +} + +.mdi-chevron-down:before { + content: "\f2f9" +} + +.mdi-chevron-left:before { + content: "\f2fa" +} + +.mdi-chevron-right:before { + content: "\f2fb" +} + +.mdi-chevron-up:before { + content: "\f2fc" +} + +.mdi-forward:before { + content: "\f2fd" +} + +.mdi-long-arrow-down:before { + content: "\f2fe" +} + +.mdi-long-arrow-left:before { + content: "\f2ff" +} + +.mdi-long-arrow-return:before { + content: "\f300" +} + +.mdi-long-arrow-right:before { + content: "\f301" +} + +.mdi-long-arrow-tab:before { + content: "\f302" +} + +.mdi-long-arrow-up:before { + content: "\f303" +} + +.mdi-rotate-ccw:before { + content: "\f304" +} + +.mdi-rotate-cw:before { + content: "\f305" +} + +.mdi-rotate-left:before { + content: "\f306" +} + +.mdi-rotate-right:before { + content: "\f307" +} + +.mdi-square-down:before { + content: "\f308" +} + +.mdi-square-right:before { + content: "\f309" +} + +.mdi-swap-alt:before { + content: "\f30a" +} + +.mdi-swap-vertical-circle:before { + content: "\f30b" +} + +.mdi-swap-vertical:before { + content: "\f30c" +} + +.mdi-swap:before { + content: "\f30d" +} + +.mdi-trending-down:before { + content: "\f30e" +} + +.mdi-trending-flat:before { + content: "\f30f" +} + +.mdi-trending-up:before { + content: "\f310" +} + +.mdi-unfold-less:before { + content: "\f311" +} + +.mdi-unfold-more:before { + content: "\f312" +} + +.mdi-apps:before { + content: "\f313" +} + +.mdi-grid-off:before { + content: "\f314" +} + +.mdi-grid:before { + content: "\f315" +} + +.mdi-view-agenda:before { + content: "\f316" +} + +.mdi-view-array:before { + content: "\f317" +} + +.mdi-view-carousel:before { + content: "\f318" +} + +.mdi-view-column:before { + content: "\f319" +} + +.mdi-view-comfy:before { + content: "\f31a" +} + +.mdi-view-compact:before { + content: "\f31b" +} + +.mdi-view-dashboard:before { + content: "\f31c" +} + +.mdi-view-day:before { + content: "\f31d" +} + +.mdi-view-headline:before { + content: "\f31e" +} + +.mdi-view-list-alt:before { + content: "\f31f" +} + +.mdi-view-list:before { + content: "\f320" +} + +.mdi-view-module:before { + content: "\f321" +} + +.mdi-view-quilt:before { + content: "\f322" +} + +.mdi-view-stream:before { + content: "\f323" +} + +.mdi-view-subtitles:before { + content: "\f324" +} + +.mdi-view-toc:before { + content: "\f325" +} + +.mdi-view-web:before { + content: "\f326" +} + +.mdi-view-week:before { + content: "\f327" +} + +.mdi-widgets:before { + content: "\f328" +} + +.mdi-alarm-check:before { + content: "\f329" +} + +.mdi-alarm-off:before { + content: "\f32a" +} + +.mdi-alarm-plus:before { + content: "\f32b" +} + +.mdi-alarm-snooze:before { + content: "\f32c" +} + +.mdi-alarm:before { + content: "\f32d" +} + +.mdi-calendar-alt:before { + content: "\f32e" +} + +.mdi-calendar-check:before { + content: "\f32f" +} + +.mdi-calendar-close:before { + content: "\f330" +} + +.mdi-calendar-note:before { + content: "\f331" +} + +.mdi-calendar:before { + content: "\f332" +} + +.mdi-time-countdown:before { + content: "\f333" +} + +.mdi-time-interval:before { + content: "\f334" +} + +.mdi-time-restore-setting:before { + content: "\f335" +} + +.mdi-time-restore:before { + content: "\f336" +} + +.mdi-time:before { + content: "\f337" +} + +.mdi-timer-off:before { + content: "\f338" +} + +.mdi-timer:before { + content: "\f339" +} + +.mdi-android-alt:before { + content: "\f33a" +} + +.mdi-android:before { + content: "\f33b" +} + +.mdi-apple:before { + content: "\f33c" +} + +.mdi-behance:before { + content: "\f33d" +} + +.mdi-codepen:before { + content: "\f33e" +} + +.mdi-dribbble:before { + content: "\f33f" +} + +.mdi-dropbox:before { + content: "\f340" +} + +.mdi-evernote:before { + content: "\f341" +} + +.mdi-facebook-box:before { + content: "\f342" +} + +.mdi-facebook:before { + content: "\f343" +} + +.mdi-github-box:before { + content: "\f344" +} + +.mdi-github:before { + content: "\f345" +} + +.mdi-google-drive:before { + content: "\f346" +} + +.mdi-google-earth:before { + content: "\f347" +} + +.mdi-google-glass:before { + content: "\f348" +} + +.mdi-google-maps:before { + content: "\f349" +} + +.mdi-google-pages:before { + content: "\f34a" +} + +.mdi-google-play:before { + content: "\f34b" +} + +.mdi-google-plus-box:before { + content: "\f34c" +} + +.mdi-google-plus:before { + content: "\f34d" +} + +.mdi-google:before { + content: "\f34e" +} + +.mdi-instagram:before { + content: "\f34f" +} + +.mdi-language-css3:before { + content: "\f350" +} + +.mdi-language-html5:before { + content: "\f351" +} + +.mdi-language-javascript:before { + content: "\f352" +} + +.mdi-language-python-alt:before { + content: "\f353" +} + +.mdi-language-python:before { + content: "\f354" +} + +.mdi-lastfm:before { + content: "\f355" +} + +.mdi-linkedin-box:before { + content: "\f356" +} + +.mdi-paypal:before { + content: "\f357" +} + +.mdi-pinterest-box:before { + content: "\f358" +} + +.mdi-pocket:before { + content: "\f359" +} + +.mdi-polymer:before { + content: "\f35a" +} + +.mdi-share:before { + content: "\f35b" +} + +.mdi-stackoverflow:before { + content: "\f35c" +} + +.mdi-steam-square:before { + content: "\f35d" +} + +.mdi-steam:before { + content: "\f35e" +} + +.mdi-twitter-box:before { + content: "\f35f" +} + +.mdi-twitter:before { + content: "\f360" +} + +.mdi-vk:before { + content: "\f361" +} + +.mdi-wikipedia:before { + content: "\f362" +} + +.mdi-windows:before { + content: "\f363" +} + +.mdi-aspect-ratio-alt:before { + content: "\f364" +} + +.mdi-aspect-ratio:before { + content: "\f365" +} + +.mdi-blur-circular:before { + content: "\f366" +} + +.mdi-blur-linear:before { + content: "\f367" +} + +.mdi-blur-off:before { + content: "\f368" +} + +.mdi-blur:before { + content: "\f369" +} + +.mdi-brightness-2:before { + content: "\f36a" +} + +.mdi-brightness-3:before { + content: "\f36b" +} + +.mdi-brightness-4:before { + content: "\f36c" +} + +.mdi-brightness-5:before { + content: "\f36d" +} + +.mdi-brightness-6:before { + content: "\f36e" +} + +.mdi-brightness-7:before { + content: "\f36f" +} + +.mdi-brightness-auto:before { + content: "\f370" +} + +.mdi-brightness-setting:before { + content: "\f371" +} + +.mdi-broken-image:before { + content: "\f372" +} + +.mdi-center-focus-strong:before { + content: "\f373" +} + +.mdi-center-focus-weak:before { + content: "\f374" +} + +.mdi-compare:before { + content: "\f375" +} + +.mdi-crop-16-9:before { + content: "\f376" +} + +.mdi-crop-3-2:before { + content: "\f377" +} + +.mdi-crop-5-4:before { + content: "\f378" +} + +.mdi-crop-7-5:before { + content: "\f379" +} + +.mdi-crop-din:before { + content: "\f37a" +} + +.mdi-crop-free:before { + content: "\f37b" +} + +.mdi-crop-landscape:before { + content: "\f37c" +} + +.mdi-crop-portrait:before { + content: "\f37d" +} + +.mdi-crop-square:before { + content: "\f37e" +} + +.mdi-exposure-alt:before { + content: "\f37f" +} + +.mdi-exposure:before { + content: "\f380" +} + +.mdi-filter-b-and-w:before { + content: "\f381" +} + +.mdi-filter-center-focus:before { + content: "\f382" +} + +.mdi-filter-frames:before { + content: "\f383" +} + +.mdi-filter-tilt-shift:before { + content: "\f384" +} + +.mdi-gradient:before { + content: "\f385" +} + +.mdi-grain:before { + content: "\f386" +} + +.mdi-graphic-eq:before { + content: "\f387" +} + +.mdi-hdr-off:before { + content: "\f388" +} + +.mdi-hdr-strong:before { + content: "\f389" +} + +.mdi-hdr-weak:before { + content: "\f38a" +} + +.mdi-hdr:before { + content: "\f38b" +} + +.mdi-iridescent:before { + content: "\f38c" +} + +.mdi-leak-off:before { + content: "\f38d" +} + +.mdi-leak:before { + content: "\f38e" +} + +.mdi-looks:before { + content: "\f38f" +} + +.mdi-loupe:before { + content: "\f390" +} + +.mdi-panorama-horizontal:before { + content: "\f391" +} + +.mdi-panorama-vertical:before { + content: "\f392" +} + +.mdi-panorama-wide-angle:before { + content: "\f393" +} + +.mdi-photo-size-select-large:before { + content: "\f394" +} + +.mdi-photo-size-select-small:before { + content: "\f395" +} + +.mdi-picture-in-picture:before { + content: "\f396" +} + +.mdi-slideshow:before { + content: "\f397" +} + +.mdi-texture:before { + content: "\f398" +} + +.mdi-tonality:before { + content: "\f399" +} + +.mdi-vignette:before { + content: "\f39a" +} + +.mdi-wb-auto:before { + content: "\f39b" +} + +.mdi-eject-alt:before { + content: "\f39c" +} + +.mdi-eject:before { + content: "\f39d" +} + +.mdi-equalizer:before { + content: "\f39e" +} + +.mdi-fast-forward:before { + content: "\f39f" +} + +.mdi-fast-rewind:before { + content: "\f3a0" +} + +.mdi-forward-10:before { + content: "\f3a1" +} + +.mdi-forward-30:before { + content: "\f3a2" +} + +.mdi-forward-5:before { + content: "\f3a3" +} + +.mdi-hearing:before { + content: "\f3a4" +} + +.mdi-pause-circle-outline:before { + content: "\f3a5" +} + +.mdi-pause-circle:before { + content: "\f3a6" +} + +.mdi-pause:before { + content: "\f3a7" +} + +.mdi-play-circle-outline:before { + content: "\f3a8" +} + +.mdi-play-circle:before { + content: "\f3a9" +} + +.mdi-play:before { + content: "\f3aa" +} + +.mdi-playlist-audio:before { + content: "\f3ab" +} + +.mdi-playlist-plus:before { + content: "\f3ac" +} + +.mdi-repeat-one:before { + content: "\f3ad" +} + +.mdi-repeat:before { + content: "\f3ae" +} + +.mdi-replay-10:before { + content: "\f3af" +} + +.mdi-replay-30:before { + content: "\f3b0" +} + +.mdi-replay-5:before { + content: "\f3b1" +} + +.mdi-replay:before { + content: "\f3b2" +} + +.mdi-shuffle:before { + content: "\f3b3" +} + +.mdi-skip-next:before { + content: "\f3b4" +} + +.mdi-skip-previous:before { + content: "\f3b5" +} + +.mdi-stop:before { + content: "\f3b6" +} + +.mdi-surround-sound:before { + content: "\f3b7" +} + +.mdi-tune:before { + content: "\f3b8" +} + +.mdi-volume-down:before { + content: "\f3b9" +} + +.mdi-volume-mute:before { + content: "\f3ba" +} + +.mdi-volume-off:before { + content: "\f3bb" +} + +.mdi-volume-up:before { + content: "\f3bc" +} + +.mdi-n-1-square:before { + content: "\f3bd" +} + +.mdi-n-2-square:before { + content: "\f3be" +} + +.mdi-n-3-square:before { + content: "\f3bf" +} + +.mdi-n-4-square:before { + content: "\f3c0" +} + +.mdi-n-5-square:before { + content: "\f3c1" +} + +.mdi-n-6-square:before { + content: "\f3c2" +} + +.mdi-neg-1:before { + content: "\f3c3" +} + +.mdi-neg-2:before { + content: "\f3c4" +} + +.mdi-plus-1:before { + content: "\f3c5" +} + +.mdi-plus-2:before { + content: "\f3c6" +} + +.mdi-sec-10:before { + content: "\f3c7" +} + +.mdi-sec-3:before { + content: "\f3c8" +} + +.mdi-zero:before { + content: "\f3c9" +} + +.mdi-airline-seat-flat-angled:before { + content: "\f3ca" +} + +.mdi-airline-seat-flat:before { + content: "\f3cb" +} + +.mdi-airline-seat-individual-suite:before { + content: "\f3cc" +} + +.mdi-airline-seat-legroom-extra:before { + content: "\f3cd" +} + +.mdi-airline-seat-legroom-normal:before { + content: "\f3ce" +} + +.mdi-airline-seat-legroom-reduced:before { + content: "\f3cf" +} + +.mdi-airline-seat-recline-extra:before { + content: "\f3d0" +} + +.mdi-airline-seat-recline-normal:before { + content: "\f3d1" +} + +.mdi-airplay:before { + content: "\f3d2" +} + +.mdi-closed-caption:before { + content: "\f3d3" +} + +.mdi-confirmation-number:before { + content: "\f3d4" +} + +.mdi-developer-board:before { + content: "\f3d5" +} + +.mdi-disc-full:before { + content: "\f3d6" +} + +.mdi-explicit:before { + content: "\f3d7" +} + +.mdi-flight-land:before { + content: "\f3d8" +} + +.mdi-flight-takeoff:before { + content: "\f3d9" +} + +.mdi-flip-to-back:before { + content: "\f3da" +} + +.mdi-flip-to-front:before { + content: "\f3db" +} + +.mdi-group-work:before { + content: "\f3dc" +} + +.mdi-hd:before { + content: "\f3dd" +} + +.mdi-hq:before { + content: "\f3de" +} + +.mdi-markunread-mailbox:before { + content: "\f3df" +} + +.mdi-memory:before { + content: "\f3e0" +} + +.mdi-nfc:before { + content: "\f3e1" +} + +.mdi-play-for-work:before { + content: "\f3e2" +} + +.mdi-power-input:before { + content: "\f3e3" +} + +.mdi-present-to-all:before { + content: "\f3e4" +} + +.mdi-satellite:before { + content: "\f3e5" +} + +.mdi-tap-and-play:before { + content: "\f3e6" +} + +.mdi-vibration:before { + content: "\f3e7" +} + +.mdi-voicemail:before { + content: "\f3e8" +} + +.mdi-group:before { + content: "\f3e9" +} + +.mdi-rss:before { + content: "\f3ea" +} + +.mdi-shape:before { + content: "\f3eb" +} + +.mdi-spinner:before { + content: "\f3ec" +} + +.mdi-ungroup:before { + content: "\f3ed" +} + +.mdi-500px:before { + content: "\f3ee" +} + +.mdi-8tracks:before { + content: "\f3ef" +} + +.mdi-amazon:before { + content: "\f3f0" +} + +.mdi-blogger:before { + content: "\f3f1" +} + +.mdi-delicious:before { + content: "\f3f2" +} + +.mdi-disqus:before { + content: "\f3f3" +} + +.mdi-flattr:before { + content: "\f3f4" +} + +.mdi-flickr:before { + content: "\f3f5" +} + +.mdi-github-alt:before { + content: "\f3f6" +} + +.mdi-google-old:before { + content: "\f3f7" +} + +.mdi-linkedin:before { + content: "\f3f8" +} + +.mdi-odnoklassniki:before { + content: "\f3f9" +} + +.mdi-outlook:before { + content: "\f3fa" +} + +.mdi-paypal-alt:before { + content: "\f3fb" +} + +.mdi-pinterest:before { + content: "\f3fc" +} + +.mdi-playstation:before { + content: "\f3fd" +} + +.mdi-reddit:before { + content: "\f3fe" +} + +.mdi-skype:before { + content: "\f3ff" +} + +.mdi-slideshare:before { + content: "\f400" +} + +.mdi-soundcloud:before { + content: "\f401" +} + +.mdi-tumblr:before { + content: "\f402" +} + +.mdi-twitch:before { + content: "\f403" +} + +.mdi-vimeo:before { + content: "\f404" +} + +.mdi-whatsapp:before { + content: "\f405" +} + +.mdi-xbox:before { + content: "\f406" +} + +.mdi-yahoo:before { + content: "\f407" +} + +.mdi-youtube-play:before { + content: "\f408" +} + +.mdi-youtube:before { + content: "\f409" +} + +.mdi-import-export:before { + content: "\f30c" +} + +.mdi-swap-vertical-:before { + content: "\f30c" +} + +.mdi-airplanemode-inactive:before { + content: "\f102" +} + +.mdi-airplanemode-active:before { + content: "\f103" +} + +.mdi-rate-review:before { + content: "\f103" +} + +.mdi-comment-sign:before { + content: "\f25a" +} + +.mdi-network-warning:before { + content: "\f2ad" +} + +.mdi-shopping-cart-add:before { + content: "\f1ca" +} + +.mdi-file-add:before { + content: "\f221" +} + +.mdi-network-wifi-scan:before { + content: "\f2e4" +} + +.mdi-collection-add:before { + content: "\f14e" +} + +.mdi-format-playlist-add:before { + content: "\f3ac" +} + +.mdi-format-queue-music:before { + content: "\f3ab" +} + +.mdi-plus-box:before { + content: "\f277" +} + +.mdi-tag-backspace:before { + content: "\f1d9" +} + +.mdi-alarm-add:before { + content: "\f32b" +} + +.mdi-battery-charging:before { + content: "\f114" +} + +.mdi-daydream-setting:before { + content: "\f217" +} + +.mdi-more-horiz:before { + content: "\f19c" +} + +.mdi-book-photo:before { + content: "\f11b" +} + +.mdi-incandescent:before { + content: "\f189" +} + +.mdi-wb-iridescent:before { + content: "\f38c" +} + +.mdi-calendar-remove:before { + content: "\f330" +} + +.mdi-refresh-sync-disabled:before { + content: "\f1b7" +} + +.mdi-refresh-sync-problem:before { + content: "\f1b6" +} + +.mdi-crop-original:before { + content: "\f17e" +} + +.mdi-power-off:before { + content: "\f1af" +} + +.mdi-power-off-setting:before { + content: "\f1ae" +} + +.mdi-leak-remove:before { + content: "\f38d" +} + +.mdi-star-border:before { + content: "\f27c" +} + +.mdi-brightness-low:before { + content: "\f36d" +} + +.mdi-brightness-medium:before { + content: "\f36e" +} + +.mdi-brightness-high:before { + content: "\f36f" +} + +.mdi-smartphone-portrait:before { + content: "\f2d4" +} + +.mdi-live-tv:before { + content: "\f2d9" +} + +.mdi-format-textdirection-l-to-r:before { + content: "\f249" +} + +.mdi-format-textdirection-r-to-l:before { + content: "\f24a" +} + +.mdi-arrow-back:before { + content: "\f2ea" +} + +.mdi-arrow-forward:before { + content: "\f2ee" +} + +.mdi-arrow-in:before { + content: "\f2e9" +} + +.mdi-arrow-out:before { + content: "\f2ed" +} + +.mdi-rotate-90-degrees-ccw:before { + content: "\f304" +} + +.mdi-adb:before { + content: "\f33a" +} + +.mdi-network-wifi:before { + content: "\f2e8" +} + +.mdi-network-wifi-alt:before { + content: "\f2e3" +} + +.mdi-network-wifi-lock:before { + content: "\f2e5" +} + +.mdi-network-wifi-off:before { + content: "\f2e6" +} + +.mdi-network-wifi-outline:before { + content: "\f2e7" +} + +.mdi-network-wifi-info:before { + content: "\f2e4" +} + +.mdi-layers-clear:before { + content: "\f18b" +} + +.mdi-colorize:before { + content: "\f15d" +} + +.mdi-format-paint:before { + content: "\f1ba" +} + +.mdi-format-quote:before { + content: "\f1b2" +} + +.mdi-camera-monochrome-photos:before { + content: "\f285" +} + +.mdi-sort-by-alpha:before { + content: "\f1cf" +} + +.mdi-folder-shared:before { + content: "\f225" +} + +.mdi-folder-special:before { + content: "\f226" +} + +.mdi-comment-dots:before { + content: "\f260" +} + +.mdi-reorder:before { + content: "\f31e" +} + +.mdi-dehaze:before { + content: "\f197" +} + +.mdi-sort:before { + content: "\f1ce" +} + +.mdi-pages:before { + content: "\f34a" +} + +.mdi-stack-overflow:before { + content: "\f35c" +} + +.mdi-calendar-account:before { + content: "\f204" +} + +.mdi-paste:before { + content: "\f109" +} + +.mdi-cut:before { + content: "\f1bc" +} + +.mdi-save:before { + content: "\f297" +} + +.mdi-smartphone-code:before { + content: "\f139" +} + +.mdi-directions-bike:before { + content: "\f117" +} + +.mdi-directions-boat:before { + content: "\f11a" +} + +.mdi-directions-bus:before { + content: "\f121" +} + +.mdi-directions-car:before { + content: "\f125" +} + +.mdi-directions-railway:before { + content: "\f1b3" +} + +.mdi-directions-run:before { + content: "\f215" +} + +.mdi-directions-subway:before { + content: "\f1d5" +} + +.mdi-directions-walk:before { + content: "\f216" +} + +.mdi-local-hotel:before { + content: "\f178" +} + +.mdi-local-activity:before { + content: "\f1df" +} + +.mdi-local-play:before { + content: "\f1df" +} + +.mdi-local-airport:before { + content: "\f103" +} + +.mdi-local-atm:before { + content: "\f198" +} + +.mdi-local-bar:before { + content: "\f137" +} + +.mdi-local-cafe:before { + content: "\f13b" +} + +.mdi-local-car-wash:before { + content: "\f124" +} + +.mdi-local-convenience-store:before { + content: "\f1d3" +} + +.mdi-local-dining:before { + content: "\f153" +} + +.mdi-local-drink:before { + content: "\f157" +} + +.mdi-local-florist:before { + content: "\f168" +} + +.mdi-local-gas-station:before { + content: "\f16f" +} + +.mdi-local-grocery-store:before { + content: "\f1cb" +} + +.mdi-local-hospital:before { + content: "\f177" +} + +.mdi-local-laundry-service:before { + content: "\f1e9" +} + +.mdi-local-library:before { + content: "\f18d" +} + +.mdi-local-mall:before { + content: "\f195" +} + +.mdi-local-movies:before { + content: "\f19d" +} + +.mdi-local-offer:before { + content: "\f187" +} + +.mdi-local-parking:before { + content: "\f1a5" +} + +.mdi-local-parking:before { + content: "\f1a5" +} + +.mdi-local-pharmacy:before { + content: "\f176" +} + +.mdi-local-phone:before { + content: "\f2be" +} + +.mdi-local-pizza:before { + content: "\f1ac" +} + +.mdi-local-post-office:before { + content: "\f15a" +} + +.mdi-local-printshop:before { + content: "\f1b0" +} + +.mdi-local-see:before { + content: "\f28c" +} + +.mdi-local-shipping:before { + content: "\f1e6" +} + +.mdi-local-store:before { + content: "\f1d4" +} + +.mdi-local-taxi:before { + content: "\f123" +} + +.mdi-local-wc:before { + content: "\f211" +} + +.mdi-my-location:before { + content: "\f299" +} + +.mdi-directions:before { + content: "\f1e7" +} + +.gsc-control-cse, +div.gsc-input-box, +div.gsc-result-info, +div.gsc-results, +div.gsc-tabsArea, +table.gsc-table-result { + font: 16px/135% Roboto, sans-serif !important; + font-weight: 300 !important; + margin: 0 +} + +.search-box table tbody td, +.search-box table tbody tr, +div.gsc-control-cse, +form.gsc-search-box, +table.gsc-resultsHeader, +table.gsc-search-box, +td.gsc-input, +td.gsib_a { + padding: 0 !important; + margin: 0 !important; + background: 0 0 !important; + border: 0 !important +} + +.search-box table tbody tr:hover { + background: 0 0 !important +} + +form.gsc-search-box { + padding: 0 30px 0 30px !important +} + +table.gsc-search-box { + position: relative +} + +table.gsc-search-box td { + padding: 0 +} + +div.gsc-input-box { + background: #fff; + height: 46px; + border: #ececec 1px solid; + -webkit-box-shadow: none; + box-shadow: none; + border-radius: 3px +} + +div.gsc-input-box:hover { + border-color: #9e9e9e +} + +div.gsc-input-box-focus { + border-color: #2196f3 !important +} + +input.gsc-input { + width: 100% !important; + height: 44px !important; + font-size: 1.0625em !important; + padding: 0 13px !important; + margin: 0 !important; + border: none; + background: #fff none 0 0 no-repeat !important; + -webkit-box-shadow: none !important; + box-shadow: none !important +} + +td.gsc-search-button { + width: 0 !important +} + +input.gsc-search-button { + width: 46px !important; + height: 46px !important; + margin: 0 !important; + padding: 0 !important; + border: 0 !important; + position: absolute; + top: 0; + right: 0; + background: #222c37 url(/themes/unity/build/css/../images/sprites/core-sprite.png) -282px 14px no-repeat !important; + border-radius: 0 3px 3px 0 !important +} + +div.gsc-clear-button { + display: none +} + +a.gsst_a { + padding: 4px 50px 0 0 !important +} + +span.gscb_a { + line-height: 38px; + color: #99a0a7 !important +} + +a.gsst_a:hover span.gscb_a { + color: #222c37 !important +} + +td.gssb_e { + -webkit-box-shadow: none !important; + box-shadow: none !important +} + +table.gsc-completion-container { + border: #e9ebec 1px solid !important; + -webkit-box-shadow: none !important; + box-shadow: none !important; + font-size: 1em +} + +td.gssb_a { + padding: 5px 15px !important +} + +div.gsc-tabsArea { + margin: 15px 0 10px 0 !important; + height: auto !important; + border: 0 !important; + padding: 0 30px +} + +.gsc-tabsArea>div { + height: auto !important; + overflow: visible !important +} + +div.gsc-tabHeader { + height: 26px !important; + line-height: 26px !important; + padding: 0 0 0 25px !important; + margin: 0 15px 5px 0; + border: 0 !important; + position: relative !important; + font-weight: 300 !important; + text-align: left; + font-size: .9375em !important; + outline: 0 +} + +div.gsc-tabHeader:before { + content: ""; + width: 16px; + height: 16px; + display: block; + border: #ececec 1px solid; + position: absolute; + top: 3px; + left: 0; + background: #fff; + border-radius: 50% +} + +div.gsc-tabHeader:after { + content: ""; + display: block; + width: 8px; + height: 8px; + position: absolute; + left: 5px; + top: 8px; + border-radius: 50% +} + +div.gsc-tabHeader:hover:after { + background-color: #ececec +} + +div.gsc-tabhActive, +div.gsc-tabhInactive { + background-color: transparent !important +} + +div.gsc-tabhActive:after, +div.gsc-tabhActive:hover:after { + background-color: #2196f3 +} + +div.gsc-above-wrapper-area { + border-bottom: 1px solid #e9ebec; + padding: 5px 30px 0 30px +} + +div.gsc-result-info { + margin: 0; + padding: 0; + color: #5a5a5b; + font-size: .9375em !important +} + +div.gsc-results { + width: 100% !important +} + +.gsc-results .gsc-imageResult, +.gsc-webResult.gsc-result { + background-color: #fff !important; + border-color: transparent !important +} + +.gsc-webResult .gsc-result { + padding: 30px !important; + border-bottom: #ececec 1px solid !important +} + +div.gs-visibleUrl, +div.gsc-results, +div.gsc-thumbnail-inside, +div.gsc-url-top { + padding: 0 !important +} + +.gsc-result .gs-title, +a.gs-title { + display: block; + height: auto !important; + text-decoration: none !important +} + +a.gs-title, +a.gs-title b { + color: #222c37 !important; + font-size: 1.0625em !important; + font-weight: 700; + margin: 0 0 10px 0 !important; + text-decoration: none !important +} + +a.gs-title:hover, +a.gs-title:hover b { + color: #222c37 !important; + text-decoration: underline !important +} + +a.gs-title:active, +a.gs-title:active b, +a.gs-title:focus, +a.gs-title:focus b { + color: #222c37 !important; + text-decoration: underline !important +} + +div.gs-visibleUrl { + display: none !important +} + +div.gs-snippet { + margin: 0 !important; + color: #5a5a5b !important; + font-size: .9375em !important +} + +div.gs-per-result-labels { + font-size: .875em !important; + display: none +} + +div.gs-per-result-labels, +div.gs-per-result-labels a { + color: #9e9e9e !important +} + +div.gs-per-result-labels a.gs-label:hover { + text-decoration: underline !important +} + +div.gs-per-result-labels span:first-child:after { + content: ":" +} + +div.gs-no-results-result div.gs-snippet { + padding: 5px 10px !important; + border: 0 !important; + background-color: #fffbd8 !important; + font-size: .875em !important +} + +div.gsc-thumbnail-left { + display: none !important +} + +div.gsc-results div.gsc-cursor-box { + margin: 0 !important; + padding: 30px +} + +div.gsc-results div.gsc-cursor { + display: inline !important +} + +div.gsc-results div.gsc-cursor-box div.gsc-cursor-page { + min-width: 36px; + height: 36px; + line-height: 36px; + float: left; + margin: 0 6px 5px 0 !important; + display: block !important; + padding: 0 !important; + font-size: .9375em !important; + text-decoration: none !important; + border: #e9ebec 1px solid !important; + outline: 0; + color: #5a5a5b !important; + text-align: center; + background: #fff !important; + border-radius: 3px +} + +div.gsc-results div.gsc-cursor-box div.gsc-cursor-page:hover { + border-color: #9e9e9e !important; + color: #5a5a5b !important +} + +div.gsc-results div.gsc-cursor-box div.gsc-cursor-page:active { + border-color: #2196f3 !important; + color: #5a5a5b !important +} + +div.gsc-results div.gsc-cursor-box div.gsc-cursor-current-page, +div.gsc-results div.gsc-cursor-box div.gsc-cursor-current-page:hover { + color: #fff !important; + background: #2196f3 !important; + border-color: #2196f3 !important; + font-weight: 300 !important +} + +@media only screen and (min-width:150px) and (max-width:767px) { + form.gsc-search-box { + padding: 0 20px !important + } + + div.gsc-tabsArea { + padding: 0 20px + } + + div.gsc-above-wrapper-area { + padding: 5px 20px 0 20px + } + + .gsc-webResult .gsc-result { + padding: 15px !important + } + + div.gsc-results div.gsc-cursor-box { + padding: 20px + } +} + +@media only screen and (-moz-min-device-pixel-ratio:2), +only screen and (-o-min-device-pixel-ratio:2/1), +only screen and (-webkit-min-device-pixel-ratio:2), +only screen and (min-device-pixel-ratio:2) { + input.gsc-search-button { + background-image: url(/themes/unity/build/css/../images/sprites/core-sprite@2x.png); + background-size: 500px 500px + } +} + +body, +html { + height: 100% +} + +div#master-wrapper { + width: 100%; + min-height: 100%; + margin: 0 auto; + position: relative +} + +section.main-wrapper { + width: 100%; + max-width: 1920px; + padding: 74px 0 0 0; + position: relative; + margin: 0 auto +} + +div.main-content { + width: 100% +} + +.has-sidebar div.main-content { + float: left; + padding: 0 0 0 350px; + position: relative +} + +div.content-wrapper { + width: 100%; + max-width: 1280px; + margin: 0 auto; + text-align: left; + padding: 30px +} + +div#content-wrapper { + padding: 30px 30px 130px 30px +} + +.has-sidebar div#content-wrapper, +.has-sidebar div.content-wrapper { + max-width: 1570px; + margin: 0; + padding: 30px +} + +header.main-header { + width: 100%; + height: 74px; + padding: 0 30px; + background: #000; + position: absolute; + top: 0; + left: 0; + z-index: 10 +} + +header.main-header div.wrap { + width: 100%; + max-width: 1160px; + margin: 0 auto +} + +.has-sidebar header.main-header div.wrap { + max-width: 1800px +} + +.has-background header.main-header { + background: #000 +} + +header.main-header a.unity-logo { + width: 87px; + height: 32px; + display: block; + float: left; + top: 21px; + left: 30px; + margin: 21px 0; + margin-right: 10px !important; + background: url(/themes/unity/build/css/../images/ui/unity-logo-white.svg) 0 0 no-repeat; + background-size: 100% 100% +} + +header.main-header a.unity-logo-black { + width: 87px; + height: 32px; + display: block; + float: left; + top: 21px; + left: 30px; + margin: 21px 0; + margin-right: 10px !important; + background: url(/themes/unity/build/css/../images/ui/unity-logo-black.svg) 0 0 no-repeat; + background-size: 100% 100% +} + +header.main-header a.app-name, +header.main-header a.app-name:hover { + height: 32px; + line-height: 26px; + display: block; + float: left; + margin: 21px 15px 21px 0; + color: #222c37; + font-weight: 100; + font-size: 1.875em; + text-decoration: none +} + +header.main-header a.app-name span.status { + background: #9e9e9e; + color: #fff; + font-size: .3em; + padding: 2px 5px; + position: relative; + top: -10px; + text-transform: uppercase; + font-weight: 400; + border-radius: 3px +} + +header.main-header.headroom--pinned { + top: 0; + position: fixed; + -webkit-transform: translateY(0); + transform: translateY(0); + -webkit-transition: all .2s linear; + transition: all .2s linear +} + +header.main-header.headroom--unpinned { + -webkit-transform: translateY(-100%); + transform: translateY(-100%) +} + +header.main-header.headroom--top { + position: absolute +} + +.header-static header.main-header { + position: absolute; + -webkit-transform: none; + transform: none +} + +header.main-header div.main-tools { + float: right +} + +header.main-header a.tool-search div.icon { + background-position: -140px 0 +} + +header.main-header a.tool-notifications div.icon { + background-position: -192px 0; + float: left +} + +header.main-header a.tool-cart div.icon { + width: 26px; + background-position: -244px 0; + float: left +} + +header.main-header a.tool-cart div.has-items:after { + content: ""; + width: 8px; + height: 0; + display: block; + position: absolute; + top: 6px; + left: 10px; + border-top: #e91e63 5px solid; + border-left: transparent 2px solid; + border-right: transparent 2px solid +} + +header.main-header a.tool div.count { + height: 18px; + line-height: 20px; + padding: 0 5px; + margin: 8px 0 8px 5px; + float: left; + font-size: .675em; + font-weight: 900; + color: #fff; + text-align: center; + background: #e91e63; + border-radius: 3px +} + +header.main-header a.tool div.count.empty { + background: #737373; + color: #a5a5a5 +} + +header.main-header a.user-icon { + float: left; + display: block; + margin: 20px 0 +} + +header.main-header a.user-icon img.avatar { + width: 34px; + height: 34px; + border-radius: 50% +} + +header.main-header a.user-icon div.avatar { + width: 34px; + height: 34px; + line-height: 34px; + color: #fff; + text-align: center; + font-size: .9375em; + text-transform: uppercase; + border-radius: 50%; + background: #e91e63; + background: linear-gradient(45deg, #e91e63 0, #ff9800 100%, #e91e63 100%) +} + +div.header-panel { + width: 600px; + text-align: left; + overflow-y: auto; + background: #f5f8f9; + position: fixed; + top: 74px; + bottom: 0; + right: -100%; + z-index: 50; + -webkit-transition: right .3s; + transition: right .3s; + -webkit-overflow-scrolling: touch; + -webkit-box-shadow: 0 0 15px rgba(34, 44, 55, .25); + box-shadow: 0 0 15px rgba(34, 44, 55, .25) +} + +.dashboard div.header-panel { + border-top: #f5f8f9 1px solid +} + +div.header-panel.speed-in { + right: 0 +} + +div.overlay, +div.panel-overlay { + width: 100%; + min-height: 100%; + position: fixed; + top: 0; + left: 0; + z-index: 4; + background: rgba(34, 44, 55, .6); + cursor: pointer; + display: none +} + +div.panel-overlay.is-visible { + display: block; + -webkit-animation: cd-fade-in .4s; + animation: cd-fade-in .4s +} + +@-webkit-keyframes cd-fade-in { + 0% { + opacity: 0 + } + + 100% { + opacity: 1 + } +} + +@keyframes cd-fade-in { + 0% { + opacity: 0 + } + + 100% { + opacity: 1 + } +} + +div.header-panel div.panel-content { + height: 100%; + padding: 30px +} + +div.search-panel div.panel-content { + padding: 0 +} + +div.search-panel div.panel-content h4 { + padding: 30px 30px 0 30px +} + +div.user-panel div.panel-content { + padding: 30px 0 +} + +div.user-panel img.avatar { + width: 96px; + height: 96px; + margin: 0 auto 20px auto; + border-radius: 50% +} + +div.user-panel div.avatar { + width: 96px; + height: 96px; + line-height: 96px; + margin: 0 auto 20px auto; + color: #fff; + text-align: center; + text-transform: uppercase; + font-size: 2.5em; + border-radius: 50%; + background: #e91e63; + background: linear-gradient(45deg, #e91e63 0, #ff9800 100%, #e91e63 100%) +} + +div.user-panel h3 { + padding: 0 30px 30px 30px; + margin: 0; + border-bottom: #fff 1px solid; + font-weight: 700 +} + +div.user-panel div.links { + margin: 0 0 30px 0 +} + +div.user-panel div.link { + width: 100%; + float: left; + border-bottom: #fff 1px solid +} + +div.user-panel a.link { + width: 100%; + display: block; + color: #5a5a5b; + padding: 30px; + -webkit-transition: all .1s; + transition: all .1s +} + +div.user-panel a.link:hover { + background: #fff; + text-decoration: none +} + +div.user-panel a.link div.icon { + margin: 0 0 20px 0 +} + +div.user-panel a.link div.icon:before { + font-size: 200% +} + +div.user-panel a.link h4 { + font-weight: 300 +} + +div.user-panel a.link small { + margin: 0 +} + +div.user-panel div.sign-in { + padding: 0 30px +} + +div.main-navigation { + float: left; + text-align: left; + position: relative; + z-index: 10 +} + +div.main-navigation nav { + padding: 7px 30px 7px 45px +} + +div.main-navigation ul { + list-style: none; + position: relative; + margin: 0 +} + +div.main-navigation ul li { + float: left; + padding: 0 30px 0 0; + font-size: 1em +} + +div.main-navigation ul li:before { + display: none +} + +div.main-navigation ul li a { + height: 60px; + line-height: 60px; + float: left; + display: block; + color: #fff; + text-decoration: none +} + +div.main-navigation ul li a:hover { + color: #2196f3 +} + +div.main-navigation ul li a.selected { + color: #2196f3 +} + +div.sidebar-navigation { + width: 350px; + padding: 0 0 30px 30px; + position: absolute; + top: 104px; + left: 0; + z-index: 2 +} + +div.sidebar-navigation nav { + padding: 30px 0 30px 30px; + text-align: left +} + +div.sidebar-navigation ul { + margin: 0 0 20px 0; + list-style: none +} + +div.sidebar-navigation ul li { + width: 100%; + float: left; + padding: 0; + margin: 0 0 20px 0; + font-size: 1.125em +} + +div.sidebar-navigation ul li:before { + display: none +} + +div.sidebar-navigation ul li a { + float: left; + display: block; + text-decoration: none; + color: #222c37 +} + +div.sidebar-navigation ul li a:active, +div.sidebar-navigation ul li a:focus { + color: #309df4; + text-decoration: none; + outline: 0 +} + +div.sidebar-navigation ul li a.selected, +div.sidebar-navigation ul li a:hover { + color: #2196f3 +} + +div.sidebar-navigation ul li ul { + width: 100%; + display: block; + float: left; + padding: 20px 0 5px 0; + margin: 15px 0 0 0; + background: #fff; + position: relative +} + +div.sidebar-navigation ul li ul:before { + content: ""; + display: block; + position: absolute; + top: -20px; + left: 15px; + border: transparent 10px solid; + border-bottom-color: #fff +} + +div.sidebar-navigation ul li ul li { + font-size: .875em; + margin: 0 0 15px 0; + padding: 0 20px +} + +div.sidebar-navigation ul li ul li.subheader { + padding: 0 20px 15px 20px; + font-weight: 700; + border-bottom: #f5f8f9 1px solid +} + +div.sidebar-navigation ul li ul li.divider { + padding: 0; + border-bottom: #f5f8f9 1px solid +} + +div.sidebar-navigation ul li ul li a.c-re { + color: #f44336 +} + +div.sidebar-navigation small { + padding: 0 0 0 30px; + margin: 0 0 30px 0; + text-align: left; + font-size: .875em +} + +div.background { + width: 100%; + position: absolute; + top: 0; + left: 0; + z-index: -1; + background: 50% 0 no-repeat; + background-size: cover +} + +div.hero { + width: 100%; + margin: 0 auto; + text-align: left; + position: relative +} + +div.hero .gw { + padding-top: 60px +} + +footer.main-footer { + width: 100%; + position: absolute; + bottom: 0; + left: 0; + z-index: 3; + text-align: left +} + +.has-sidebar footer.main-footer .gw { + max-width: 1920px; + margin: 0 auto; + padding: 0 30px +} + +footer.main-footer div.wrapper { + background: #000; + padding: 10px 0 +} + +footer.main-footer .unity-logo { + width: 87px; + height: 32px; + display: block; + float: left; + top: 21px; + left: 30px; + margin: 0 0 21px; + margin-right: 10px; + background: url(/themes/unity/build/css/../images/ui/unity-logo-white.min.svg) 0 0 no-repeat; + background-size: 100% 100% +} + +footer.main-footer .unity-logo-black { + width: 87px; + height: 32px; + display: block; + float: left; + top: 21px; + left: 30px; + margin: 0 0 21px; + margin-right: 10px; + background: url(/themes/unity/build/css/../images/ui/unity-logo-black.min.svg) 0 0 no-repeat; + background-size: 100% 100% +} + +footer.main-footer div.wrapper small { + float: left; + margin: 0; + color: #9e9e9e +} + +footer.main-footer div.wrapper ul { + list-style-type: none; + float: left; + margin: 0 +} + +footer.main-footer div.wrapper ul li { + float: left; + margin: 0 0 0 15px; + font-size: .8125em; + padding: 0; + line-height: 1.3em +} + +footer.main-footer div.wrapper ul li:before { + display: none +} + +footer.main-footer div.social { + float: right; + margin: 0 0 20px 0 +} + +footer.main-footer div.social a.icon { + width: 35px; + height: 35px; + float: left; + margin: 0 0 0 10px; + display: block; + text-indent: -9999em; + background: url(/themes/unity/build/css/../images/sprites/core-sprite.png) 0 0 no-repeat; + border-radius: 50% +} + +footer.main-footer div.social a.facebook { + background-position: 0 -77px +} + +footer.main-footer div.social a.facebook:hover { + background-color: #3664a2 +} + +footer.main-footer div.social a.twitter { + background-position: -35px -77px +} + +footer.main-footer div.social a.twitter:hover { + background-color: #55acee +} + +footer.main-footer div.social a.googleplus { + background-position: -70px -77px +} + +footer.main-footer div.social a.googleplus:hover { + background-color: #dd4b39 +} + +footer.main-footer div.social a.instagram { + background-position: -72px -77px +} + +footer.main-footer div.social a.instagram:hover { + background-color: #c44070 +} + +footer.main-footer div.social a.linkedin { + background-position: -105px -77px +} + +footer.main-footer div.social a.linkedin:hover { + background-color: #0977b5 +} + +footer.main-footer div.social a.youtube { + background-position: -140px -77px +} + +footer.main-footer div.social a.youtube:hover { + background-color: #e52d27 +} + +footer.main-footer div.language-selector { + float: right +} + +footer.main-footer div.language-selector a { + text-decoration: none +} + +div.footer-tool { + width: 100%; + height: 100%; + position: fixed; + left: 0; + top: 100%; + z-index: 999; + overflow: auto; + text-align: center; + background: #222c37; + -webkit-backface-visibility: hidden; + backface-visibility: hidden; + -webkit-overflow-scrolling: touch; + -webkit-transition: top .3s; + transition: top .3s +} + +div.footer-tool.is-visible { + top: 0 +} + +div.footer-tool div.close { + width: 40px; + height: 40px; + position: absolute; + top: 20px; + right: 20px; + z-index: 4; + cursor: pointer +} + +div.footer-tool div.close::after, +div.footer-tool div.close::before { + content: ""; + display: block; + width: 40px; + height: 3px; + top: 50%; + left: 50%; + margin: -1px 0 0 -20px; + position: absolute; + background: #fff; + -webkit-transform: rotate(45deg); + transform: rotate(45deg) +} + +div.footer-tool div.close::after { + -webkit-transform: rotate(-45deg); + transform: rotate(-45deg) +} + +div.footer-tool div.wrap { + width: 100%; + position: absolute; + top: 50%; + left: 50%; + z-index: 3; + -webkit-transform: translateY(-50%) translateX(-50%); + transform: translateY(-50%) translateX(-50%) +} + +div.footer-language .g7 { + padding-top: 60px; + margin: 0 0 1px 0 +} + +div.footer-language .g5 { + padding-top: 0; + margin: 0 0 1px 0 +} + +div.footer-language img { + float: right +} + +div.footer-language ul { + list-style: none; + text-align: center; + border-top: #434b55 1px solid; + border-left: #434b55 1px solid; + padding: 0; + overflow: hidden +} + +div.footer-language ul li { + width: 33.3333333333%; + display: block; + float: left; + padding: 0; + margin: 0; + font-size: 1.125em; + border-right: #434b55 1px solid; + border-bottom: #434b55 1px solid +} + +div.footer-language ul li:before { + display: none +} + +div.footer-language ul li a { + height: 60px; + line-height: 60px; + display: block; + color: #fff; + text-decoration: none +} + +div.footer-language ul li a:hover { + background: #434b55 +} + +div.error-code { + padding: 75px; + color: #fff; + font-size: 7em; + font-weight: 700; + text-align: center; + display: inline-block; + background: #e91e63; + background: linear-gradient(45deg, #e91e63 0, #ff9800 100%) +} + +@media only screen and (min-width:150px) and (max-width:1279px) { + .dashboard header.main-header { + padding: 0 30px + } + + .has-sidebar div#content-wrapper, + .has-sidebar div.content-wrapper { + padding: 30px 0 + } + + div.sidebar-navigation { + padding: 0 0 30px 0 + } + + .has-sidebar footer.main-footer .gw { + padding: 0 + } +} + +@media only screen and (min-width:150px) and (max-width:1023px) { + section.main-wrapper { + padding: 60px 0 0 0 + } + + .has-sidebar div.main-content { + padding: 0 + } + + .has-sidebar div.content-wrapper, + div.content-wrapper { + padding: 10px + } + + div#content-wrapper { + padding: 10px 10px 100px 10px + } + + .has-sidebar div#content-wrapper { + padding: 10px + } + + header.main-header { + height: 60px; + padding: 0 17px 0 30px + } + + .dashboard header.main-header { + padding: 0 17px 0 30px + } + + header.main-header a.unity-logo, + header.main-header a.unity-logo-black { + margin: 15px 10px 15px 0 + } + + header.main-header a.app-name, + header.main-header a.app-name:hover { + margin: 15px 15px 15px 0 + } + + div.main-navigation, + div.sidebar-navigation { + display: none + } + + div.header-panel { + top: 60px + } + + header.main-header a.user-icon { + padding: 13px + } + + header.main-header a.tool { + margin: 13px 13px 13px 0 + } + + header.main-header a.user-icon { + margin: 0 + } + + header.main-header a.tool-menu { + width: 34px; + height: 34px; + position: relative; + display: block; + margin: 13px 0 + } + + header.main-header a.tool-menu div.icon { + width: 20px; + height: 2px; + position: absolute; + top: 16px; + left: 7px; + margin: 0; + background: #222c37; + -webkit-transition: .3s; + transition: .3s + } + + header.main-header a.tool-menu div.icon:after, + header.main-header a.tool-menu div.icon:before { + content: ""; + width: 20px; + height: 2px; + display: block; + position: absolute; + left: 0; + background: #222c37; + -webkit-transition: .3s; + transition: .3s; + -webkit-transform-origin: 1px center; + transform-origin: 1px center + } + + header.main-header a.tool-menu div.icon:before { + top: -5px + } + + header.main-header a.tool-menu div.icon:after { + top: 5px + } + + div.mobile-navigation ul { + list-style: none; + padding: 0; + margin: 0 + } + + div.mobile-navigation ul li { + font-size: 1.25em; + padding: 0; + margin: 0 0 20px 0 + } + + div.mobile-navigation ul li:before { + display: none + } + + div.mobile-navigation ul li a { + color: #222c37 + } + + div.mobile-navigation ul li a:active, + div.mobile-navigation ul li a:focus { + color: #309df4; + text-decoration: none; + outline: 0 + } + + div.mobile-navigation ul li a.selected, + div.mobile-navigation ul li a:hover { + color: #2196f3; + text-decoration: none + } + + div.mobile-navigation ul li ul { + width: 100%; + display: block; + padding: 20px 0 5px 0; + margin: 15px 0 20px 0; + background: #fff; + position: relative + } + + div.mobile-navigation ul li ul:before { + content: ""; + display: block; + position: absolute; + top: -20px; + left: 15px; + border: transparent 10px solid; + border-bottom-color: #fff + } + + div.mobile-navigation ul li ul li { + font-size: .75em; + margin: 0; + padding: 0 20px 10px 20px + } + + div.mobile-navigation ul li ul li.subheader { + font-weight: 700; + margin: 0 0 15px 0; + border-bottom: #f5f8f9 1px solid + } + + div.mobile-navigation ul li ul li.divider { + margin: 0 0 10px 0; + padding: 0; + border-bottom: #f5f8f9 1px solid + } + + div.mobile-navigation ul li ul li a.c-re { + color: #f44336 + } + + div.hero .gw { + padding-top: 60px + } + + footer.main-footer div.wrapper { + padding: 20px 0 + } + + footer.main-footer .copyright { + display: none + } + + .has-sidebar footer.main-footer .gw, + footer.main-footer .gw { + padding: 0 10px + } +} + +@media only screen and (min-width:150px) and (max-width:767px) { + + .dashboard header.main-header, + header.main-header { + padding: 0 7px 0 20px + } + + div.content-wrapper { + padding: 10px 5px + } + + div#content-wrapper { + padding: 10px 5px 50px 5px + } + + .has-sidebar div#content-wrapper, + .has-sidebar div.content-wrapper { + padding: 10px 5px + } + + div.header-panel { + width: 300px + } + + div.header-panel div.panel-content { + padding: 20px + } + + div.search-panel div.panel-content { + padding: 0 + } + + div.search-panel div.panel-content h4 { + padding: 20px 20px 0 20px + } + + div.user-panel div.panel-content { + padding: 20px 0 + } + + div.user-panel div.avatar, + div.user-panel img.avatar { + width: 48px; + height: 48px; + line-height: 48px; + font-size: 1.5em; + margin: 0 auto 10px auto + } + + div.user-panel h3 { + padding: 0 20px 20px 20px + } + + div.user-panel div.links { + margin: 0 0 20px 0 + } + + div.user-panel div.link { + width: 100%; + border-right: 0 + } + + div.user-panel a div.icon { + margin: 0 0 10px 0 + } + + div.hero .gw { + padding-top: 30px + } + + footer.main-footer div.wrapper { + padding: 20px 0 + } + + footer.main-footer div.gw { + text-align: center + } + + footer.main-footer .g5, + footer.main-footer .g7 { + width: 100%; + padding-top: 10px !important; + padding-bottom: 10px !important + } + + footer.main-footer .unity-logo { + display: none + } + + footer.main-footer div.language-selector, + footer.main-footer div.social, + footer.main-footer div.social a.icon, + footer.main-footer div.wrapper small, + footer.main-footer div.wrapper ul, + footer.main-footer div.wrapper ul li { + float: none; + display: inline-block + } + + footer.main-footer div.wrapper ul li { + margin: 0 0 0 10px + } + + footer.main-footer div.social { + margin: 0 0 10px 0 + } + + footer.main-footer div.social a.icon { + margin: 0 3px + } + + div.footer-language img { + float: none; + margin: 0 auto + } + + .m-clear:after { + visibility: hidden; + display: block; + font-size: 0; + content: " "; + clear: both; + height: 0 + } + + .m-clear { + display: inline-table; + clear: both + } +} + +@media only screen and (min-width:150px) and (max-width:479px) { + + .dashboard header.main-header, + header.main-header { + padding: 0 0 0 10px + } + + div.content-wrapper { + padding: 10px 0 + } + + div#content-wrapper { + padding: 10px 0 50px 0 + } + + .has-sidebar div#content-wrapper, + .has-sidebar div.content-wrapper { + padding: 10px 0 + } + + header.main-header a.unity-logo { + width: 36px; + height: 32px; + display: block; + float: left; + margin-right: 10px !important; + background: url(/themes/unity/build/css/../images/ui/unity-icon-white.min.svg) 0 0 no-repeat; + background-size: 100% 100% + } + + header.main-header a.unity-logo-black { + width: 36px; + height: 32px; + display: block; + float: left; + margin-right: 10px !important; + background: url(/themes/unity/build/css/../images/ui/unity-icon-black.min.svg) 0 0 no-repeat; + background-size: 100% 100% + } + + header.main-header a.app-name, + header.main-header a.app-name:hover { + line-height: 30px + } + + div.header-panel { + width: 98% + } + + div.hero .gw { + padding-top: 20px + } + + header.main-header a.user-icon { + padding: 13px 10px + } + + header.main-header a.tool { + margin: 13px 10px 13px 0 + } + + header.main-header a.tool-menu { + margin: 13px 0 + } + + header.main-header a.user-icon { + margin: 0 + } + + footer.main-footer div.wrapper { + padding: 10px 0 + } + + footer.main-footer .g5, + footer.main-footer .g7 { + width: 100%; + padding-top: 10px !important; + padding-bottom: 10px !important + } + + footer.main-footer div.wrapper ul { + width: 100% + } + + footer.main-footer div.wrapper ul li { + margin: 0 5px + } + + div.footer-language ul li { + width: 50% + } + + div.footer-language .g5 { + display: none + } +} + +@media only screen and (-moz-min-device-pixel-ratio:2), +only screen and (-o-min-device-pixel-ratio:2/1), +only screen and (-webkit-min-device-pixel-ratio:2), +only screen and (min-device-pixel-ratio:2) { + + footer.main-footer div.social a.icon, + header.main-header div.main-tools a.tool div.icon, + input.gsc-search-button { + background-image: url(/themes/unity/build/css/../images/sprites/core-sprite@2x.png); + background-size: 500px 500px + } +} + +div.gradient { + width: 100%; + height: 100%; + position: absolute; + bottom: 0; + left: 0; + z-index: 2 +} + +div.hero div.gradient { + width: auto; + height: auto; + position: absolute; + left: 0; + right: 0; + bottom: 0; + height: 75%; + z-index: -1 +} + +ul.tabs li { + font-size: 1.0625em +} + +ul.tabs li a { + padding: 0 60px +} + +ul.tabs.center li { + display: inline-block; + float: none; + margin: 0; + vertical-align: top +} + +div.tab-content { + background: #fff +} + +div.loading-inline { + width: 0; + height: 3px; + position: absolute; + top: 0; + left: 0; + z-index: 10; + background: #cddc39; + background: -webkit-gradient(linear, left top, right top, from(#cddc39), to(#00bcd4)); + background: linear-gradient(to right, #cddc39 0, #00bcd4 100%); + -webkit-animation: pong cubic-bezier(.77, 0, .175, 1) 3s infinite; + animation: pong cubic-bezier(.77, 0, .175, 1) 3s infinite +} + +@-webkit-keyframes pong { + 25% { + width: 100% + } + + 50% { + width: 0; + left: auto; + right: 0 + } + + 75% { + width: 100% + } + + 100% { + width: 0; + right: auto; + left: 0 + } +} + +@keyframes pong { + 25% { + width: 100% + } + + 50% { + width: 0; + left: auto; + right: 0 + } + + 75% { + width: 100% + } + + 100% { + width: 0; + right: auto; + left: 0 + } +} + +div.play { + display: block; + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 15; + text-align: center; + background: -webkit-gradient(linear, left top, left bottom, from(rgba(0, 0, 0, 0)), color-stop(50%, rgba(17, 22, 28, .5)), to(rgba(34, 44, 55, .5))); + background: linear-gradient(to bottom, rgba(0, 0, 0, 0) 0, rgba(17, 22, 28, .5) 50%, rgba(34, 44, 55, .5) 100%) +} + +div.play:before { + width: 58px; + height: 62px; + line-height: 62px; + position: absolute; + top: 50%; + left: 50%; + z-index: 20; + border: #fff 2px solid; + cursor: pointer; + font-family: entypo-plus; + content: "\e936"; + color: #fff; + font-size: 200%; + padding: 0 0 0 4px; + -webkit-transform: translate(-50%, -50%); + transform: translate(-50%, -50%); + border-radius: 50% +} + +div.play.small:before { + width: 42px; + height: 46px; + font-size: 175%; + line-height: 46px; + padding: 0 0 0 4px +} + +div.plus { + display: block; + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 15; + text-align: center; + background: -webkit-gradient(linear, left top, left bottom, from(rgba(0, 0, 0, 0)), color-stop(50%, rgba(17, 22, 28, .5)), to(rgba(34, 44, 55, .5))); + background: linear-gradient(to bottom, rgba(0, 0, 0, 0) 0, rgba(17, 22, 28, .5) 50%, rgba(34, 44, 55, .5) 100%) +} + +div.plus:before { + width: 62px; + height: 62px; + line-height: 62px; + position: absolute; + top: 50%; + left: 50%; + z-index: 20; + border: #fff 2px solid; + cursor: pointer; + font-family: entypo-plus; + content: "\e9f7"; + color: #fff; + font-size: 200%; + -webkit-transform: translate(-50%, -50%); + transform: translate(-50%, -50%); + border-radius: 50% +} + +div.plus.small:before { + width: 46px; + height: 46px; + font-size: 175%; + line-height: 46px +} + +.close-icon { + width: 24px; + height: 24px; + display: block; + position: absolute; + top: 20px; + right: 20px; + margin: 0; + z-index: 13; + cursor: pointer +} + +.close-icon::after, +.close-icon::before { + content: ""; + display: block; + width: 30px; + height: 2px; + top: 50%; + left: 50%; + margin: -1px 0 0 -15px; + position: absolute; + background: #fff; + -webkit-transform: rotate(45deg); + transform: rotate(45deg) +} + +.close-icon::after { + -webkit-transform: rotate(-45deg); + transform: rotate(-45deg) +} + +.close-icon.big { + width: 38px; + height: 38px +} + +.close-icon.big::after, +.close-icon.big::before { + width: 50px; + height: 2px; + margin: -1px 0 0 -25px +} + +a.expand { + display: block; + float: left; + color: #5a5a5b; + font-size: 1.125em; + text-decoration: none; + padding: 0 0 0 40px; + position: relative +} + +a.expanded { + font-weight: 700 +} + +a.expand:before, +a.expanded:before { + content: "\e926"; + display: block; + width: 23px; + height: 23px; + line-height: 24px; + padding: 1px 0 0 1px; + position: absolute; + top: 2px; + left: 0; + background: #ececec; + font-size: 115%; + text-align: center; + font-family: entypo-plus; + border-radius: 50% +} + +a.expanded:before { + content: "\e924"; + width: 24px; + padding: 1px 0 0 0; + font-weight: 300; + color: #fff; + background: #009688 +} + +div.faq a.expand { + margin: 0 0 15px 0 +} + +div.faq div.info { + padding: 0 0 15px 40px +} + +div.faq div.info p { + font-size: 1.0625em +} + +div.faq div.info ul li { + font-size: 1.0625em +} + +div.gradient-diamond { + position: absolute; + bottom: -50px; + left: 50%; + margin: 0 0 0 -50px; + border: transparent 50px solid; + border-right-color: #f5f8f9; + border-left-color: #f5f8f9; + border-bottom-color: #f5f8f9 +} + +div.gradient-diamond:before { + content: ""; + width: 2000px; + height: 100px; + background: #f5f8f9; + position: absolute; + bottom: -50px; + left: 50px +} + +div.gradient-diamond:after { + content: ""; + width: 2000px; + height: 100px; + background: #f5f8f9; + position: absolute; + bottom: -50px; + right: 50px +} + +div.gradient-diamond.white { + border-right-color: #fff; + border-left-color: #fff; + border-bottom-color: #fff +} + +div.gradient-diamond.white:after, +div.gradient-diamond.white:before { + background: #fff +} + +div.diamond-regular { + width: 44px; + height: 44px; + border: #222c37 1px solid; + margin: 0 auto 30px auto; + overflow: hidden; + position: relative; + -webkit-transform: rotate(45deg); + transform: rotate(45deg) +} + +div.diamond-regular div.content { + width: 60px; + height: 60px; + line-height: 60px; + display: block; + position: absolute; + top: 50%; + left: 50%; + margin: -30px 0 0 -30px; + text-align: center; + -webkit-transform: rotate(45deg); + transform: rotate(-45deg) +} + +div.diamond-regular div.content div.icon:before { + line-height: 64px; + font-size: 1em +} + +div.diamond-regular div.content div.text { + font-size: 1.5em; + color: #222c37 +} + +div.diamond-regular div.content div.text:before { + line-height: 64px +} + +div.platform-icon { + width: 60px; + height: 60px; + margin: 5px; + float: left; + display: inline; + padding: 5px; + background: #fff +} + +div.g-center div.platform-icon { + float: none; + display: inline-block +} + +div.platform-icon a, +div.platform-icon div.logo { + width: 50px; + height: 50px; + display: block; + background-image: url(/themes/unity/build/css/../images/sprites/platform-logos.png); + background-color: #fff +} + +div.platform-icon .win { + background-position: 0 0 +} + +div.platform-icon .pc { + background-position: 0 0 +} + +div.platform-icon .winphone8 { + background-position: 0 -50px +} + +div.platform-icon .windowsphone8 { + background-position: 0 -50px +} + +div.platform-icon .winstore { + background-position: 0 -100px +} + +div.platform-icon .windowsstore { + background-position: 0 -100px +} + +div.platform-icon .windowsstoreapps { + background-position: 0 -100px +} + +div.platform-icon .mac { + background-position: 0 -150px +} + +div.platform-icon .linux { + background-position: 0 -200px +} + +div.platform-icon .web { + background-position: 0 -250px +} + +div.platform-icon .unitywebplayer { + background-position: 0 -250px +} + +div.platform-icon .ios { + background-position: 0 -300px +} + +div.platform-icon .android { + background-position: 0 -350px +} + +div.platform-icon .blackberry { + background-position: 0 -400px +} + +div.platform-icon .wiiu { + background-position: 0 -450px +} + +div.platform-icon .ps3 { + background-position: 0 -500px +} + +div.platform-icon .playstation3 { + background-position: 0 -500px +} + +div.platform-icon .ps4 { + background-position: 0 -550px +} + +div.platform-icon .playstation4 { + background-position: 0 -550px +} + +div.platform-icon .xbox { + background-position: 0 -600px +} + +div.platform-icon .facebook { + background-position: 0 -650px +} + +div.platform-icon .playstationvita { + background-position: 0 -700px +} + +div.platform-icon .unity { + background-position: 0 -750px +} + +div.platform-icon .xboxone { + background-position: 0 -800px +} + +div.platform-icon .xbox360 { + background-position: 0 -850px +} + +div.platform-icon .tizen { + background-position: 0 -900px +} + +div.platform-icon .psmobile { + background-position: 0 -950px +} + +div.platform-icon .teamlicense { + background-position: 0 -1000px +} + +div.platform-icon .oculus { + background-position: 0 -1050px +} + +div.platform-icon .oculusright { + background-position: 0 -1050px +} + +div.platform-icon .oculusrift { + background-position: 0 -1050px +} + +div.platform-icon .webgl { + background-position: 0 -1100px +} + +div.platform-icon .samsungtv { + background-position: 0 -1150px +} + +div.platform-icon .gearvr { + background-position: 0 -1200px +} + +div.platform-icon .androidtv { + background-position: 0 -1250px +} + +div.platform-icon .hololens { + background-position: 0 -1300px +} + +div.platform-icon .universal-windows { + background-position: 0 -1350px +} + +div.platform-icon .playstationvr { + background-position: 0 -1400px +} + +div.platform-icon .tvos { + background-position: 0 -1450px +} + +div.platform-icon .nintendo3ds { + background-position: 0 -1500px +} + +div.platform-icon .vive { + background-position: 0 -1550px +} + +div.platform-icon .cardboard { + background-position: 0 -1600px +} + +div.platform-icon .daydream { + background-position: 0 -1650px +} + +div.platform-icon .nintendo-switch { + background-position: 0 -1700px +} + +div.platform-icon .fireos { + background-position: 0 -1750px +} + +div.platform-icon .fb-gameroom { + background-position: 0 -1800px +} + +div.testimonials-slider { + position: relative; + padding: 0 0 40px 0 !important; + margin: 0 0 20px 0 +} + +div.testimonials-slider .slick-list { + padding: 0 !important +} + +div.testimonials-slider div.testimonial { + width: 100%; + padding: 100px 0; + position: relative +} + +div.testimonials-slider div.testimonial div.background { + bottom: 0; + z-index: 1 +} + +div.testimonials-slider div.testimonial div.gradient { + width: 100%; + height: 100%; + position: absolute; + bottom: 0; + left: 0; + z-index: 2 +} + +div.testimonials-slider div.testimonial div.top-gradient { + width: 100%; + position: absolute; + top: 0; + bottom: 0; + left: 0; + z-index: 2; + background: -webkit-gradient(linear, left top, left bottom, from(#222c37), color-stop(33%, rgba(34, 44, 55, .7)), to(rgba(34, 44, 55, 0))); + background: linear-gradient(to bottom, #222c37 0, rgba(34, 44, 55, .7) 33%, rgba(34, 44, 55, 0) 100%) +} + +div.testimonials-slider div.testimonial div.content { + position: relative; + z-index: 3 +} + +div.testimonials-slider div.testimonial div.quote { + max-width: 1024px; + width: 100%; + margin: 0 auto 60px auto; + padding: 0 60px +} + +div.testimonials-slider div.testimonial div.quote h4 { + padding: 0 44px; + margin: 70px 0; + position: relative; + font-size: 1.75em; + line-height: 1.3em; + text-align: center; + color: #fff +} + +div.testimonials-slider div.testimonial div.quote h4:after, +div.testimonials-slider div.testimonial div.quote h4:before { + content: ""; + width: 44px; + height: 35px !important; + display: block; + position: absolute; + bottom: -35px; + right: -30px; + z-index: 1; + height: auto; + background: url(/themes/unity/build/css/../images/ui/quotemarks.png) -44px 0 no-repeat +} + +div.testimonials-slider div.testimonial div.quote h4:before { + top: -35px; + bottom: auto; + right: auto; + left: -30px; + background-position: 0 0 +} + +div.testimonials-slider div.testimonial img { + margin: 0 auto 30px auto +} + +div.testimonials-slider div.testimonial p { + color: #fff +} + +div.testimonials-slider .slick-dots { + width: 100%; + height: 80px; + position: absolute; + left: 0; + bottom: 0; + z-index: 4; + text-align: center +} + +div.testimonials-slider .slick-dots li { + width: 60px; + height: 60px; + margin: 10px 25px; + overflow: hidden; + -webkit-transition: all .2s; + transition: all .2s; + -webkit-transform: rotate(45deg); + transform: rotate(45deg) +} + +div.testimonials-slider .slick-dots li a { + width: 114px; + height: 114px; + display: block; + position: absolute; + top: 50%; + left: 50%; + margin: -57px 0 0 -57px; + background-position: 50% 50%; + -webkit-transform: rotate(45deg); + transform: rotate(-45deg); + filter: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg'><filter id='grayscale'><feColorMatrix type='matrix' values='0.3333 0.3333 0.3333 0 0 0.3333 0.3333 0.3333 0 0 0.3333 0.3333 0.3333 0 0 0 0 0 1 0'/></filter></svg>#grayscale"); + filter: gray; + -webkit-filter: grayscale(100%) +} + +div.testimonials-slider .slick-dots li.slick-active { + width: 80px; + height: 80px; + margin: 0 15px +} + +div.testimonials-slider .slick-dots li.slick-active a, +div.testimonials-slider .slick-dots li:hover a { + filter: none; + -webkit-filter: grayscale(0) +} + +.not-found .ml-30 { + margin-left: -30px !important +} + +.not-found form.gsc-search-box { + padding: 0 !important +} + +.not-found div.gsc-tabsArea { + padding: 0 !important +} + +.not-found div.gsc-above-wrapper-area { + padding: 5px 0 0 0 !important +} + +.not-found div.gsc-results div.gsc-cursor-box { + padding: 30px 0 !important +} + +.not-found table tbody td { + font-size: 1em +} + +.not-found .search-container h4 { + font-size: 1.25em; + font-weight: 300; + line-height: 1.3em +} + +@media only screen and (min-width:150px) and (max-width:767px) { + div.testimonials-slider div.testimonial { + padding: 0 0 75px 0 + } + + div.testimonials-slider div.testimonial div.quote { + padding: 0 60px + } + + div.testimonials-slider div.testimonial div.quote h4 { + padding: 0 24px; + margin: 70px 0; + font-size: 1.5em + } + + div.testimonials-slider div.testimonial div.quote h4:after, + div.testimonials-slider div.testimonial div.quote h4:before { + -webkit-transform: scale(.5); + transform: scale(.5) + } + + div.testimonials-slider .slick-dots { + width: 100%; + height: 60px; + bottom: 5px + } + + div.testimonials-slider .slick-dots li { + width: 40px; + height: 40px; + margin: 5px 15px + } + + div.testimonials-slider .slick-dots li a { + width: 114px; + height: 114px; + margin: -57px 0 0 -57px + } + + div.testimonials-slider .slick-dots li.slick-active { + width: 50px; + height: 50px; + margin: 0 10px + } + + div.gradient-diamond { + bottom: -30px; + left: 50%; + margin: 0 0 0 -30px; + border-width: 30px + } + + div.gradient-diamond:before { + height: 60px; + bottom: -30px; + left: 30px + } + + div.gradient-diamond:after { + height: 60px; + bottom: -30px; + right: 30px + } +} + +@media only screen and (min-width:150px) and (max-width:479px) { + div.testimonials-slider div.testimonial div.quote { + padding: 0 30px + } + + div.testimonials-slider div.testimonial div.quote h4 { + padding: 0; + margin: 70px 0; + font-size: 1.25em + } +} + +@media only screen and (-moz-min-device-pixel-ratio:2), +only screen and (-o-min-device-pixel-ratio:2/1), +only screen and (-webkit-min-device-pixel-ratio:2), +only screen and (min-device-pixel-ratio:2) { + + div.platform-icon a, + div.platform-icon div.logo { + background-image: url(/themes/unity/build/css/../images/sprites/platform-logos@2x.png); + background-size: 50px 2000px + } + + div.testimonials-slider div.testimonial div.quote h4:after, + div.testimonials-slider div.testimonial div.quote h4:before { + background-image: url(/themes/unity/build/css/../images/ui/quotemarks@2x.png); + background-size: 88px 35px + } +} + +.txt-r { + text-align: right !important +} + +.txt-l { + text-align: left !important +} + +.txt-c { + text-align: center !important +} + +.fw100 { + font-weight: 100 +} + +.fw300, +.nb { + font-weight: 300 +} + +.fw400 { + font-weight: 400 +} + +.fw500 { + font-weight: 500 +} + +.b, +.fw700 { + font-weight: 700 !important +} + +.i { + font-style: italic +} + +.txt-ellipsis { + text-overflow: ellipsis; + white-space: nowrap; + overflow: hidden +} + +.txt-upper { + text-transform: uppercase +} + +.txt-noupper { + text-transform: none +} + +.txt-tdu { + text-decoration: underline +} + +.txt-tdn { + text-decoration: none +} + +.txt-tdn:hover { + text-decoration: none +} + +.lh24 { + line-height: 24px +} + +.lh30 { + line-height: 30px +} + +.lh36 { + line-height: 36px +} + +.lh40 { + line-height: 40px +} + +.lh42 { + line-height: 42px +} + +.lh46 { + line-height: 46px +} + +.lh50 { + line-height: 50px +} + +.lh60 { + line-height: 60px +} + +.c-db { + color: #222c37 +} + +.c-db.light { + color: #d3d5d7 +} + +.c-ma { + color: #e91e63 !important +} + +.c-ma.light { + color: #fbd2e0 +} + +.c-li { + color: #cddc39 +} + +.c-li.light { + color: #f5f8d7 +} + +.c-cy { + color: #00bcd4 !important +} + +.c-cy.light { + color: #ccf2f6 +} + +.c-re { + color: #f44336 +} + +.c-re.light { + color: #fdd9d7 +} + +.c-pu { + color: #9c27b0 +} + +.c-pu.light { + color: #ebd4ef +} + +.c-bl { + color: #2196f3 +} + +.c-bl.light { + color: #d3eafd +} + +.c-te { + color: #009688 !important +} + +.c-te.light { + color: #cceae7 +} + +.c-gr { + color: #8ac249 !important +} + +.c-gr.light { + color: #e8f3db +} + +.c-ye { + color: #ffeb3b +} + +.c-ye.light { + color: #fffbd8 +} + +.c-or { + color: #ff9800 +} + +.c-or.light { + color: #ffeacc +} + +.c-dg { + color: #5a5a5b !important +} + +.c-dg.light { + color: #dedede +} + +.c-mg { + color: #9e9e9e +} + +.c-mg.light { + color: #ececec +} + +.c-lg { + color: #f5f8f9 +} + +.c-lg.light { + color: #fdfefe +} + +.c-wh { + color: #fff !important +} + +.hide { + display: none !important +} + +.hidden { + visibility: hidden !important; + opacity: 0 !important +} + +.inbl { + display: inline-block +} + +.w100 { + width: 100% !important +} + +.rel { + position: relative +} + +.overflow-hidden { + overflow: hidden +} + +.left { + float: left !important +} + +.right { + float: right !important +} + +.nobox { + -webkit-box-sizing: content-box; + box-sizing: content-box +} + +.flex-wrap { + display: -ms-flexbox !important; + display: -webkit-box !important; + display: flex !important; + -ms-flex-wrap: wrap; + flex-wrap: wrap +} + +.flex-col { + display: -ms-flexbox !important; + display: -webkit-box !important; + display: flex !important +} + +.br50 { + border-radius: 50% +} + +.br3 { + border-radius: 3px +} + +.bb { + border-bottom: #ececec 1px solid +} + +.bt { + border-top: #ececec 1px solid +} + +.bt0 { + border-top: 0 !important +} + +.btl { + border-top: #f5f8f9 1px solid +} + +.bbw { + border-bottom: #fff 1px solid +} + +.bbl { + border-bottom: #f5f8f9 1px solid +} + +.bbd { + border-bottom: #222c37 1px solid +} + +.ba { + border: #ececec 1px solid +} + +.bb0 { + border-bottom: 0 +} + +.b0 { + border: 0 !important +} + +.m0a { + margin: 0 auto !important +} + +.m0 { + margin: 0 !important +} + +.mb0 { + margin-bottom: 0 !important +} + +.mb1 { + margin-bottom: 1px !important +} + +.mb5 { + margin-bottom: 5px !important +} + +.mb10 { + margin-bottom: 10px !important +} + +.mb15 { + margin-bottom: 15px !important +} + +.mb20 { + margin-bottom: 20px !important +} + +.mb30 { + margin-bottom: 30px !important +} + +.mb40 { + margin-bottom: 40px !important +} + +.mt0 { + margin-top: 0 !important +} + +.mt1 { + margin-top: 1px !important +} + +.mt5 { + margin-top: 5px !important +} + +.mt10 { + margin-top: 10px !important +} + +.mt15 { + margin-top: 15px !important +} + +.mt20 { + margin-top: 20px !important +} + +.mt30 { + margin-top: 30px !important +} + +.mt40 { + margin-top: 40px !important +} + +.mr0 { + margin-right: 0 !important +} + +.mr1 { + margin-right: 1px !important +} + +.mr5 { + margin-right: 5px !important +} + +.mr10 { + margin-right: 10px !important +} + +.mr15 { + margin-right: 15px !important +} + +.mr20 { + margin-right: 20px !important +} + +.mr30 { + margin-right: 30px !important +} + +.mr40 { + margin-right: 40px !important +} + +.ml0 { + margin-left: 0 !important +} + +.ml1 { + margin-left: 1px !important +} + +.ml5 { + margin-left: 5px !important +} + +.ml10 { + margin-left: 10px !important +} + +.ml15 { + margin-left: 15px !important +} + +.ml20 { + margin-left: 20px !important +} + +.ml30 { + margin-left: 30px !important +} + +.ml40 { + margin-left: 40px !important +} + +.p0 { + padding: 0 !important +} + +.p1 { + padding: 1px !important +} + +.p5 { + padding: 5px !important +} + +.p10 { + padding: 10px !important +} + +.p15 { + padding: 15px !important +} + +.p20 { + padding: 20px !important +} + +.p30 { + padding: 30px !important +} + +.pr0 { + padding-right: 0 !important +} + +.pr1 { + padding-right: 1px !important +} + +.pr5 { + padding-right: 5px !important +} + +.pr10 { + padding-right: 10px !important +} + +.pr15 { + padding-right: 15px !important +} + +.pr20 { + padding-right: 20px !important +} + +.pr30 { + padding-right: 30px !important +} + +.pl0 { + padding-left: 0 !important +} + +.pl1 { + padding-left: 1px !important +} + +.pl5 { + padding-left: 5px !important +} + +.pl10 { + padding-left: 10px !important +} + +.pl15 { + padding-left: 15px !important +} + +.pl20 { + padding-left: 20px !important +} + +.pl30 { + padding-left: 30px !important +} + +.pb0 { + padding-bottom: 0 !important +} + +.pb1 { + padding-bottom: 1px !important +} + +.pb5 { + padding-bottom: 5px !important +} + +.pb10 { + padding-bottom: 10px !important +} + +.pb15 { + padding-bottom: 15px !important +} + +.pb20 { + padding-bottom: 20px !important +} + +.pb30 { + padding-bottom: 30px !important +} + +.pt0 { + padding-top: 0 !important +} + +.pt1 { + padding-top: 1px !important +} + +.pt5 { + padding-top: 5px !important +} + +.pt10 { + padding-top: 10px !important +} + +.pt15 { + padding-top: 15px !important +} + +.pt20 { + padding-top: 20px !important +} + +.pt30 { + padding-top: 30px !important +} + +.bg-db { + background-color: #222c37 +} + +.bg-db.light { + background-color: #d3d5d7 +} + +.bg-ma { + background-color: #e91e63 +} + +.bg-ma.light { + background-color: #fbd2e0 +} + +.bg-li { + background-color: #cddc39 +} + +.bg-li.light { + background-color: #f5f8d7 +} + +.bg-cy { + background-color: #00bcd4 +} + +.bg-cy.light { + background-color: #ccf2f6 +} + +.bg-re { + background-color: #f44336 +} + +.bg-re.light { + background-color: #fdd9d7 +} + +.bg-pu { + background-color: #9c27b0 +} + +.bg-pu.light { + background-color: #ebd4ef +} + +.bg-bl { + background-color: #2196f3 +} + +.bg-bl.light { + background-color: #d3eafd +} + +.bg-te { + background-color: #009688 +} + +.bg-te.light { + background-color: #cceae7 +} + +.bg-gr { + background-color: #8ac249 +} + +.bg-gr.light { + background-color: #e8f3db !important +} + +.bg-ye { + background-color: #ffeb3b +} + +.bg-ye.light { + background-color: #fffbd8 !important +} + +.bg-or { + background-color: #ff9800 +} + +.bg-or.light { + background-color: #ffeacc !important +} + +.bg-dg { + background-color: #5a5a5b +} + +.bg-dg.light { + background-color: #dedede +} + +.bg-mg { + background-color: #9e9e9e +} + +.bg-mg.light { + background-color: #ececec +} + +.bg-lg { + background-color: #f5f8f9 +} + +.bg-lg.light { + background-color: #fdfefe +} + +.bg-wh { + background-color: #fff +} + +.unity-logo { + background-image: url(/themes/unity/build/css/../../images/ui/unity-logo-white.svg); + background-size: 100% 100% +} + +.relative { + position: relative +} + +a { + text-decoration: none; + color: #2196f3 +} + +a:hover { + text-decoration: none +} + +.block { + display: block +} + +.inline-block { + display: inline-block +} + +.inline { + display: inline +} + +.hidden { + display: none +} + +.overflow-y-hide { + overflow-y: hidden +} + +.overflow-y-auto { + overflow-y: auto +} + +.overflow-y-scroll { + overflow-y: scroll +} + +.overflow-y-visible { + overflow-y: visible +} + +.overflow-x-hide { + overflow-x: hidden +} + +.overflow-x-auto { + overflow-x: auto +} + +.overflow-x-scroll { + overflow-x: scroll +} + +.overflow-x-visible { + overflow-x: visible +} + +.overflow-hide { + overflow: hidden +} + +.overflow-auto { + overflow: auto +} + +.overflow-scroll { + overflow: scroll +} + +.overflow-visible { + overflow: visible +} + +.visually-hidden { + position: absolute !important; + clip: rect(1px, 1px, 1px, 1px); + overflow: hidden; + height: 1px; + width: 1px; + word-wrap: normal +} + +.visually-hidden.focusable:active, +.visually-hidden.focusable:focus { + position: static !important; + clip: auto; + overflow: visible; + height: auto; + width: auto +} + +.invisible { + visibility: hidden +} + +html { + font-size: 100% +} + +body { + font-size: 1rem; + line-height: 1.5rem; + font-weight: 400; + font-family: Inter, sans-serif; + -webkit-text-size-adjust: none; + -ms-text-size-adjust: none; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + color: #000 +} + +.extra, +h1, +h2, +h3, +h4, +h5, +h6 { + color: #000; + margin: 0; + padding: 0 +} + +.extra { + font-size: 3rem; + line-height: 3.5rem; + font-weight: 900 +} + +@media only screen and (min-width:62.85em) { + .extra { + font-size: 4rem; + line-height: 4.5rem; + font-weight: 900 + } +} + +.h1, +h1 { + font-size: 2.5rem; + line-height: 3rem; + font-weight: 700 +} + +@media only screen and (min-width:62.85em) { + + .h1, + h1 { + font-size: 2.75rem; + line-height: 3.25rem + } +} + +.h2, +h2 { + font-size: 2rem; + line-height: 2.5rem; + font-weight: 700 +} + +@media only screen and (min-width:62.85em) { + + .h2, + h2 { + font-size: 2.5rem; + line-height: 3rem + } +} + +.h3, +h3 { + font-size: 1.75rem; + line-height: 2.25rem; + font-weight: 700 +} + +@media only screen and (min-width:62.85em) { + + .h3, + h3 { + font-size: 2rem; + line-height: 2.5rem + } +} + +.h4, +h4 { + font-size: 1.5rem; + line-height: 2rem; + font-weight: 500 +} + +@media only screen and (min-width:62.85em) { + + .h4, + h4 { + font-size: 1.875rem; + line-height: 2.375rem + } +} + +.h5, +h5 { + font-size: 1.25rem; + line-height: 1.75rem; + font-weight: 600 +} + +@media only screen and (min-width:62.85em) { + + .h5, + h5 { + font-size: 1.5rem; + line-height: 2rem; + font-weight: 600 + } +} + +.large { + font-size: 1.125rem; + line-height: 2rem; + font-weight: 400 +} + +.small, +small { + font-size: .75rem; + line-height: 1.25rem +} + +@media only screen and (min-width:62.85em) { + + .small, + small { + font-size: .875rem; + line-height: 1.25rem + } +} + +.subhead { + font-size: .75rem; + line-height: 1.25rem; + font-weight: 600; + letter-spacing: .5px; + text-transform: uppercase +} + +@media only screen and (min-width:62.85em) { + .subhead { + font-size: .875rem; + line-height: 1.25rem; + font-weight: 400 + } +} + +.caption, +caption, +figcaption { + font-size: .875rem; + line-height: 1.25rem; + font-weight: 400; + font-style: italic; + color: #8a8a8a +} + +ul.no-bullets, +ul.no-bullets li { + list-style: none; + margin: 0; + padding: 0 +} + +ul li { + line-height: 1.5em; + padding-bottom: 10px +} + +.list-2-columns { + -webkit-column-count: 2; + -moz-column-count: 2; + column-count: 2; + -webkit-column-gap: 30px; + -moz-column-gap: 30px; + column-gap: 30px +} + +.weight-thin { + font-weight: 100 +} + +.weight-extralight { + font-weight: 200 +} + +.weight-light { + font-weight: 300 +} + +.weight-normal { + font-weight: 400 +} + +.weight-medium { + font-weight: 500 +} + +.weight-semibold { + font-weight: 600 +} + +.weight-bold { + font-weight: 700 +} + +.weight-extrabold { + font-weight: 800 +} + +.weight-heavy { + font-weight: 900 +} + +a.link { + color: #2196f3; + text-decoration: none +} + +a.link:hover { + cursor: pointer +} + +.img-shadow { + -webkit-box-shadow: 0 5px 10px 0 rgba(0, 0, 0, .1); + box-shadow: 0 5px 10px 0 rgba(0, 0, 0, .1) +} + +.img-rounded { + border-radius: 6px +} + +.has-overlay { + position: relative +} + +.has-overlay::before { + content: ""; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color: #000; + z-index: 1 +} + +.has-overlay--darken-30::before { + opacity: .3 +} + +.has-overlay--darken-50::before { + opacity: .5 +} + +.has-overlay__inner { + position: relative; + z-index: 1 +} + +ul.slick-dots { + margin: 0; + padding: 0; + text-align: center +} + +ul.slick-dots li { + width: 10px; + height: 10px; + margin: 0 5px; + padding: 0; + display: inline-block; + position: relative; + cursor: pointer +} + +ul.slick-dots li::before { + display: none +} + +ul.slick-dots li button { + display: block; + width: 12px; + height: 12px; + padding: 0; + cursor: pointer; + background: rgba(0, 0, 0, .1); + color: transparent; + border: 0; + border-radius: 50%; + outline: 0; + font-size: 0; + line-height: 0; + -webkit-appearance: none +} + +ul.slick-dots li.slick-active button { + background: #2196f3; + border-color: transparent +} + +.slick-slider .slick-next, +.slick-slider .slick-prev { + color: rgba(0, 0, 0, .4); + -webkit-transition: color .3s; + transition: color .3s; + cursor: pointer; + font-size: 4.375rem +} + +.slick-slider .slick-next { + position: absolute; + top: calc(50% - 75px); + right: -50px +} + +.slick-slider .slick-prev { + position: absolute; + top: 50%; + top: calc(50% - 75px); + left: -50px +} + +#block-globalnav { + position: relative +} + +.component-subnav { + display: none; + position: absolute; + z-index: 100; + padding-top: 55px; + background-color: #000; + width: 100% +} + +@media only screen and (min-width:48em) { + .component-subnav { + display: block + } +} + +@media only screen and (min-width:62.85em) { + .component-subnav { + padding-top: 72px + } +} + +.component-subnav ul { + list-style-type: none; + height: 25px; + overflow: hidden; + padding-left: 15px +} + +.component-subnav li { + display: inline-block; + padding-bottom: 20px; + padding-right: 16px +} + +@media only screen and (min-width:62.85em) { + .component-subnav li { + padding-right: 40px + } +} + +.component-subnav li a { + font-size: .875rem; + line-height: 1.375rem; + font-weight: 400; + color: #fff +} + +.component-subnav li a:hover { + color: #2196f3 +} + +@media only screen and (min-width:62.85em) { + .component-subnav li a { + font-size: 1rem; + line-height: 1.5rem; + font-weight: 400 + } +} + +.component-subnav li a.is-active { + font-weight: 500; + color: #2196f3 +} + +.component-footer { + background: #000; + color: #fff; + padding: 64px 0 +} + +.component-footer__label { + font-size: 1rem; + line-height: 1.375rem; + color: #f5f5f5; + margin-bottom: 8px +} + +.component-footer .component-newsletter__inline { + display: inline-block +} + +.component-footer .component-newsletter__fields { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -ms-flex-direction: column; + flex-direction: column; + -webkit-box-pack: justify; + -ms-flex-pack: justify; + justify-content: space-between +} + +.component-footer .component-newsletter__fields input { + font-size: .75rem; + line-height: 1.5rem; + background-color: transparent; + color: #d8d8d8; + padding: 8px 12px +} + +.component-footer .component-newsletter__fields input:focus { + border-color: #2196f3 +} + +.component-footer .component-newsletter__fields input::-webkit-input-placeholder { + color: #d8d8d8 +} + +.component-footer .component-newsletter__fields input::-moz-placeholder { + color: #d8d8d8 +} + +.component-footer .component-newsletter__fields input::-ms-input-placeholder { + color: #d8d8d8 +} + +.component-footer .component-newsletter__fields input::placeholder { + color: #d8d8d8 +} + +.component-footer .component-newsletter__fields input[type=submit] { + font-size: 1rem; + line-height: 1.5rem; + background-color: #2196f3; + color: #fff; + font-weight: 500; + margin-bottom: 24px; + width: 100% +} + +@media only screen and (min-width:62.85em) { + .component-footer .component-newsletter__fields input[type=submit] { + margin-bottom: 15px; + width: 30% + } +} + +@media only screen and (min-width:62.85em) { + .component-footer .component-newsletter__fields input { + display: inline-block; + margin-right: 8px + } +} + +@media only screen and (min-width:62.85em) { + .component-footer .component-newsletter__fields { + -webkit-box-orient: horizontal; + -webkit-box-direction: normal; + -ms-flex-direction: row; + flex-direction: row + } +} + +.component-footer .component-newsletter__checkbox { + margin: 10px 0 0 +} + +.component-footer .component-newsletter__checkbox label { + font-size: .875rem; + line-height: 1.25rem; + color: #f5f5f5; + cursor: pointer; + position: relative +} + +.component-footer .component-newsletter__checkbox label::before { + background-color: transparent; + border: 2px solid #767676; + border-radius: 3px; + content: ""; + cursor: pointer; + display: inline-block; + margin-right: 10px; + padding: 7px; + position: relative; + vertical-align: middle +} + +.component-footer .component-newsletter__checkbox label:hover::before { + background-color: #2196f3; + border: 2px solid #2196f3 +} + +.component-footer .component-newsletter__checkbox label span { + position: relative; + display: inline-block; + top: -20px; + left: 30px; + padding-right: 30px +} + +.component-footer .component-newsletter__checkbox input[type=checkbox] { + margin-right: 8px; + padding: 0; + height: initial; + width: initial; + margin-bottom: 0; + display: none; + cursor: pointer +} + +.component-footer .component-newsletter__checkbox input:checked+label::after { + content: ""; + display: block; + position: absolute; + top: 2px; + left: 6px; + width: 7px; + height: 13px; + border: solid #000; + border-width: 0 2px 2px 0; + -webkit-transform: rotate(45deg); + transform: rotate(45deg) +} + +.component-footer .component-newsletter__checkbox input:checked+label::before { + background-color: #2196f3; + border: 2px solid #2196f3 +} + +.component-footer__language .links { + -webkit-column-count: 4; + -moz-column-count: 4; + column-count: 4; + -webkit-column-gap: 8px; + -moz-column-gap: 8px; + column-gap: 8px; + margin-bottom: 24px +} + +.component-footer__language .links li { + font-size: 1rem; + line-height: 1.5rem; + color: #767676 +} + +@media only screen and (min-width:48em) { + .component-footer__language .links { + margin-bottom: 0 + } +} + +@media only screen and (min-width:78.7em) { + .component-footer__language .links { + -webkit-column-count: 5; + -moz-column-count: 5; + column-count: 5 + } +} + +.component-footer__line { + display: block; + width: 100%; + border: 0; + border-top: 1px solid #666; + margin: 40px 0 +} + +.component-footer__list.no-bullets { + margin-bottom: 20px +} + +.component-footer__menu { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -ms-flex-direction: column; + flex-direction: column +} + +.component-footer__menu .visually-hidden { + height: 0 +} + +.component-footer__menu ul { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-orient: horizontal; + -webkit-box-direction: normal; + -ms-flex-direction: row; + flex-direction: row; + -ms-flex-wrap: wrap; + flex-wrap: wrap; + -webkit-box-pack: justify; + -ms-flex-pack: justify; + justify-content: space-between; + margin: 0; + margin-bottom: 20px; + padding: 0 +} + +.component-footer__menu li { + font-size: .875rem; + line-height: 1.5rem; + list-style: none; + margin: 0; + padding: 0; + -ms-flex-preferred-size: 50%; + flex-basis: 50% +} + +.component-footer__menu li ul { + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -ms-flex-direction: column; + flex-direction: column +} + +.component-footer__menu li ul li { + font-size: .75rem; + -webkit-box-flex: 1; + -ms-flex: 1 0 auto; + flex: 1 0 auto +} + +@media only screen and (min-width:62.85em) { + .component-footer__menu li { + font-size: 1rem; + -ms-flex-preferred-size: 33%; + flex-basis: 33% + } + + .component-footer__menu li ul li { + font-size: .875rem + } +} + +@media only screen and (min-width:78.7em) { + .component-footer__menu li { + font-size: 1rem; + -ms-flex-preferred-size: 16.6%; + flex-basis: 16.6% + } + + .component-footer__menu li ul li { + font-size: .875rem + } +} + +@media only screen and (min-width:48em) { + .component-footer__social { + padding: 0 + } +} + +.component-footer .component-social-links a { + display: inline-block; + margin: 6px 16px 0 0 +} + +.component-footer .component-social-links svg { + height: 19px; + max-width: 18px; + opacity: .5; + -webkit-transition: opacity .2s; + transition: opacity .2s +} + +.component-footer .component-social-links svg:hover { + opacity: 1; + -webkit-transition: opacity .2s; + transition: opacity .2s +} + +.component-footer__small { + font-size: .875rem; + margin-bottom: 24px; + color: #999 +} + +.component-footer__small-legal { + color: #fff +} + +.component-footer__copy { + margin-top: 40px; + margin-bottom: 8px +} + +@media only screen and (min-width:62.85em) { + .component-footer__copy { + margin: 0 + } +} + +.component-footer a { + color: #999; + text-decoration: none +} + +.component-footer .error { + color: #e91e63 +} + +.component-footer__legal { + margin-bottom: 24px +} + +.component-footer__legal li { + display: inline +} + +.component-footer__legal li a { + font-size: .875rem; + line-height: 1.5rem; + margin-right: 16px; + color: #999 +} + +.component-footer__legal #ot-sdk-btn.ot-sdk-show-settings { + color: #999; + border: none; + padding: inherit; + font-size: inherit; + line-height: inherit; + -webkit-transition: none; + transition: none +} + +.component-footer__legal #ot-sdk-btn.ot-sdk-show-settings:hover { + background: 0 0; + color: #999 +} + +@media only screen and (min-width:62.85em) { + .component-footer__legal { + margin: 0 + } +} + +.contextual-panel__cog { + width: 50px; + height: 50px; + background: #2196f3; + position: absolute; + top: calc(50vh - 20px); + left: 240px; + z-index: 9999; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + cursor: pointer; + -webkit-transition: background .2s ease-in-out; + transition: background .2s ease-in-out; + border-top-right-radius: 6px; + border-bottom-right-radius: 6px +} + +.contextual-panel__cog:hover { + background-color: #0c7cd5; + -webkit-transition: background .2s ease-in-out; + transition: background .2s ease-in-out +} + +.contextual-panel__scroll-container { + overflow: auto; + height: 100% +} + +.contextual-panel__sidebar { + width: 240px; + height: 100%; + background: #fff; + position: fixed; + left: 0; + top: 0; + bottom: 0; + border-right: 1px solid #f5f5f5; + -webkit-transform: translateX(-240px); + transform: translateX(-240px); + z-index: 9999; + -webkit-transition: -webkit-transform .3s ease-in-out; + transition: -webkit-transform .3s ease-in-out; + transition: transform .3s ease-in-out; + transition: transform .3s ease-in-out, -webkit-transform .3s ease-in-out +} + +.contextual-panel--open .contextual-panel__sidebar { + -webkit-transform: translateX(0); + transform: translateX(0); + -webkit-transition: -webkit-transform .3s ease-in-out; + transition: -webkit-transform .3s ease-in-out; + transition: transform .3s ease-in-out; + transition: transform .3s ease-in-out, -webkit-transform .3s ease-in-out +} + +.contextual-panel__inner { + padding: 30px 10px 30px 30px; + background-color: #000; + color: #fff +} + +.contextual-panel__username { + color: #fff; + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden +} + +.contextual-panel__group { + padding: 10px 10px 10px 20px; + font-weight: 700; + background: #f5f5f5 +} + +.contextual-panel__tabs .visually-hidden { + display: none +} + +.contextual-panel__tabs li, +.contextual-panel__tabs ul { + margin: 0; + padding: 0; + list-style: none +} + +.contextual-panel__tabs a { + font-size: .875rem; + display: block; + border-bottom: 1px solid #f5f5f5; + padding: 10px 10px 10px 40px; + text-decoration: none; + color: #9b9b9b +} + +.contextual-panel__tabs a:hover { + background: #2196f3; + color: #fff +} + +.contextual-panel__tabs a.is-active { + color: #000 +} + +body.not-found #main { + padding-top: 100px +} + +img[src*="insight.adsrvr.org"], +img[src*="vidassets.terminus.services"] { + display: none +} + +*, +html { + -webkit-box-sizing: border-box; + box-sizing: border-box +} + +*, +::after, +::before { + -webkit-box-sizing: inherit; + box-sizing: inherit +} + +body, +html { + height: 100% +} + +img { + max-width: 100%; + height: auto; + vertical-align: bottom +} + +@media only screen and (max-width:48em) { + .hidden-on-mobile { + display: none !important + } +} + +@media only screen and (max-width:48em) { + .show-on-mobile { + display: block + } +} + +@media only screen and (min-width:48em) { + .show-on-mobile { + display: none + } +} + +.container { + padding: 0 15px +} + +@media only screen and (min-width:48em) { + .container { + padding: 0 + } +} + +.container .container-no-padding { + padding: 0 !important +} + +.component-tabs .title { + padding-top: 40px; + padding-bottom: 40px +} + +@media only screen and (min-width:48em) { + .component-tabs .title { + padding-top: 80px; + padding-bottom: 80px + } +} + +.component-tabs .tab-subtitle { + margin-bottom: 0; + padding-bottom: 10px +} + +.component-tabs p { + margin-top: 0 +} + +.component-tabs .hl { + border-bottom: 1px solid #dcdcdc +} + +.component-faqs { + padding: 80px 0 +} + +.component-faqs__intro { + margin-bottom: 60px +} + +.component-faqs__title { + margin-bottom: 32px +} + +.component-faqs__summary p:first-child { + margin-top: 0 +} + +.component-faqs__buttons { + margin-top: 40px +} + +.component-faqs__buttons a { + margin-right: 20px +} + +.component-faqs__buttons a:last-child { + margin-right: 0 +} + +.component-faqs .faq-question { + margin-top: 10px; + margin-bottom: 10px; + display: inline-block; + margin-left: 10px; + font-weight: 700; + vertical-align: middle; + max-width: 85% +} + +.component-faqs .faq-question:hover { + cursor: pointer +} + +.component-faqs .mdi { + -webkit-transition: -webkit-transform .2s ease-in-out; + transition: -webkit-transform .2s ease-in-out; + transition: transform .2s ease-in-out; + transition: transform .2s ease-in-out, -webkit-transform .2s ease-in-out; + vertical-align: middle; + color: #2196f3 +} + +.component-faqs .mdi:hover { + cursor: pointer +} + +.component-faqs .rotate { + -webkit-transform: rotate(-180deg); + transform: rotate(-180deg) +} + +.component-faqs .answer-wrapper { + display: none +} + +.component-faqs .answer-wrapper p { + margin: 0 0 15px 22px +} + +.component-faqs .visible { + display: initial +} + +.component-faqs.bg-dark-grey { + color: #fff +} + +.component-faqs.bg-dark-grey .component-faqs__subsection-title, +.component-faqs.bg-dark-grey .component-faqs__title { + color: #fff +} + +.btn-link { + font-weight: 600; + color: #2196f3; + text-decoration: none +} + +.btn { + font-size: 1rem; + line-height: 1.5rem; + display: inline-block; + vertical-align: middle; + white-space: nowrap; + font-weight: 600; + padding: 12px 16px; + border-radius: 4px; + text-align: center; + text-decoration: none; + cursor: pointer; + border: 0; + outline: 0; + -webkit-transition: background-color .4s ease; + transition: background-color .4s ease; + min-width: 96px +} + +.btn.btn-medium { + padding: 8px 16px +} + +.btn.btn-small { + padding: 4px 16px +} + +.btn-black { + background-color: #000; + color: #fff +} + +.btn-black:hover { + background-color: #1a1a1a; + text-decoration: none +} + +.btn-white { + background-color: #fff; + color: #000 +} + +.btn-white:hover { + background-color: #fff; + text-decoration: none +} + +.btn-blue { + background-color: #2196f3; + color: #fff +} + +.btn-blue:hover { + background-color: #309df4; + text-decoration: none +} + +.btn-cyan { + background-color: #00bcd4; + color: #fff +} + +.btn-cyan:hover { + background-color: #00cae3; + text-decoration: none +} + +.btn-grey { + background-color: #9b9b9b; + color: #fff +} + +.btn-grey:hover { + background-color: #a3a3a3; + text-decoration: none +} + +.btn-outline { + font-size: 1rem; + display: inline-block; + vertical-align: middle; + white-space: nowrap; + font-weight: 600; + background-color: transparent; + padding: 10px 16px; + border-radius: 4px; + text-align: center; + text-decoration: none; + cursor: pointer; + border: transparent 2px solid; + outline: 0; + -webkit-transition: border .4s ease; + transition: border .4s ease; + min-width: 96px +} + +.btn-outline.btn-medium { + padding: 6px 16px +} + +.btn-outline.btn-small { + padding: 2px 16px +} + +.btn-outline-black { + border-color: #000; + color: #000 +} + +.btn-outline-black:hover { + border-color: #0d0d0d; + text-decoration: none +} + +.btn-outline-white { + border-color: #fff; + color: #fff +} + +.btn-outline-white:hover { + border-color: #39a1f4; + text-decoration: none +} + +.btn-outline-cyan { + border-color: #00bcd4; + color: #00bcd4 +} + +.btn-outline-cyan:hover { + border-color: #00d3ee; + text-decoration: none +} + +.btn-outline-blue { + border-color: #2196f3; + color: #2196f3 +} + +.btn-outline-blue:hover { + border-color: #39a1f4; + text-decoration: none +} + +.btn.btn-block { + display: block; + width: 100% +} + +.btn.disabled, +.btn.disabled:active, +.btn.disabled:focus, +.btn.disabled:hover, +.btn:disabled { + background-color: #737373 !important; + color: #a5a5a5 !important; + cursor: default +} + +.component-segment { + padding: 60px 0; + background-color: #000; + max-width: 1600px; + margin: 0 auto +} + +@media only screen and (min-width:48em) { + .component-segment { + padding: 120px 0 + } +} + +.component-segment__title { + margin-bottom: 8px +} + +.component-segment__image-background { + color: #fff; + background-repeat: no-repeat; + background-size: cover; + background-position: center +} + +.component-segment__has-overlay { + -webkit-box-shadow: inset 0 0 0 1000px rgba(0, 0, 0, .5); + box-shadow: inset 0 0 0 1000px rgba(0, 0, 0, .5) +} + +@media print { + .component-segment { + background: #fff; + -webkit-box-shadow: none; + box-shadow: none + } +} + +.component-pager__items { + float: right; + list-style-type: none +} + +.component-pager__item { + display: inline-block; + vertical-align: middle; + padding-left: 25px; + padding-bottom: 0 +} + +.component-pager__item-link { + color: #9b9b9b +} + +.component-pager__item-icon { + font-size: 1.625rem; + color: #9b9b9b +} + +@media only screen and (min-width:48em) { + .component .slick-remove-dots .slick-dots { + display: none !important + } +} + +.component .slick-remove-dots-totally .slick-dots { + display: none !important +} + +.sections .section:first-of-type { + padding-top: 136px +} + +.sections .section:first-of-type.section--event-hero, +.sections .section:first-of-type.section--hero, +.sections .section:first-of-type.section--hero-verticals { + padding-top: 0 +} + +.component-cards.component-cards-carousel { + padding: 40px 0 +} + +@media only screen and (min-width:48em) { + .component-cards.component-cards-carousel { + padding: 56px 0 + } +} + +.component-cards.component-cards-carousel h2 { + margin-bottom: 24px +} + +.component-cards.component-cards-carousel .slick-dots { + margin-top: -5px +} + +.component-cards.component-cards-carousel .component-card { + margin-bottom: 60px !important +} + +.component-cards.component-cards-stacked { + padding: 40px 0 50px +} + +@media only screen and (min-width:48em) { + .component-cards.component-cards-stacked { + padding: 56px 0 + } +} + +.component-cards.component-cards-stacked h2 { + margin-bottom: 24px +} + +.component-cards .component-card { + margin-bottom: 30px !important +} + +.component-views-2-up .component-card__date { + padding-bottom: 35px +} + +.component-verticals { + background-color: #fff; + padding: 80px 0 0; + margin-bottom: 60px +} + +@media only screen and (min-width:48em) { + .component-verticals { + margin-bottom: 100px; + padding: 100px 0 0 + } +} + +.component-verticals__buttons { + margin-top: 32px +} + +@media only screen and (min-width:48em) { + .component-verticals__buttons { + margin-top: 0 + } +} + +.component-verticals .btn { + display: block +} + +@media only screen and (min-width:48em) { + .component-verticals .btn { + display: inline-block + } +} + +.component-verticals .btn-outline { + display: block; + margin-left: 0; + margin-top: 20px +} + +@media only screen and (min-width:48em) { + .component-verticals .btn-outline { + margin-left: 20px; + margin-top: 0; + display: inline-block + } +} + +.component-verticals__top { + padding-bottom: 20px +} + +.component-verticals__column { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -ms-flex-direction: column; + flex-direction: column; + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center +} + +@media only screen and (min-width:48em) { + .component-verticals__column { + min-height: 240px + } +} + +.component-verticals__bottom { + padding-top: 30px +} + +.component-verticals__image { + position: relative; + margin-bottom: 15px +} + +.component-verticals__image img { + border-radius: 6px +} + +.component-verticals__flex { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-orient: horizontal; + -webkit-box-direction: normal; + -ms-flex-flow: row wrap; + flex-flow: row wrap; + -webkit-box-pack: justify; + -ms-flex-pack: justify; + justify-content: space-between; + list-style: none; + margin: 0; + padding: 0 +} + +.component-verticals__flex-item { + border-bottom: 1px solid #ededed; + margin-bottom: 20px +} + +@media only screen and (min-width:48em) { + .component-verticals__flex-item { + margin-bottom: 0; + border-bottom: none; + width: 25%; + -webkit-box-flex: 1; + -ms-flex: 1 1 auto; + flex: 1 1 auto; + position: relative + } +} + +@media only screen and (min-width:48em) { + .component-verticals__flex-item+.component-verticals__flex-item { + border-left: solid 1px #ededed + } +} + +.component-solution { + display: block; + padding: 0 10px; + color: #000; + text-decoration: none; + height: 100% +} + +@media only screen and (min-width:48em) { + .component-solution { + padding: 0 30px + } +} + +.component-solution__wrapper { + height: 100%; + padding-bottom: 25px; + position: relative; + z-index: 1 +} + +.component-solution__title { + font-size: 1.125rem; + line-height: 1.5rem; + font-weight: 600; + margin-bottom: 4px +} + +@media only screen and (min-width:48em) { + .component-solution__title { + margin-bottom: 24px; + min-height: 45px + } +} + +.component-solution__text { + padding-bottom: 20px; + position: static +} + +@media only screen and (min-width:48em) { + .component-solution__text { + margin-top: 20px + } +} + +.component-solution__link { + font-size: 1rem; + line-height: 1.1875rem; + font-weight: 500; + color: #2196f3; + display: block +} + +@media only screen and (min-width:48em) { + .component-solution__link { + position: absolute; + bottom: -1px + } +} + +.component-solution:hover .component-solution__link { + color: #2196f3 +} + +.diff-responsive-table-wrapper .component-hero--overlay { + position: relative +} + +.diff-controls { + z-index: 3 +} + +.component-overview { + padding-top: 40px +} + +.component-overview--slim-padding { + padding-top: 20px; + padding-bottom: 20px +} + +.component-overview--item { + font-size: 1rem +} + +.component-overview--title { + font-size: 1.5rem +} + +.overview-bulletpoints { + display: grid; + list-style: none; + padding-left: 0; + padding-bottom: 40px; + margin: 0; + grid-template-columns: repeat(auto-fill, minmax(216px, 1fr)); + grid-gap: 40px 30px; + border-bottom: 1px solid #f5f5f5 +} + +.overview-bulletpoints li { + padding-bottom: 0 +} + +.overview-bulletpoint { + padding: 0 +} + +.component-slideshow { + padding: 40px 0 +} + +@media only screen and (min-width:48em) { + .component-slideshow { + padding: 80px 0 + } +} + +.component-slideshow__intro { + margin-bottom: 40px +} + +@media only screen and (min-width:48em) { + .component-slideshow__intro { + margin-bottom: 102px + } +} + +.component-slideshow__intro-title { + margin-bottom: 16px +} + +.component-slideshow__intro-summary p:first-child { + margin-top: 0 +} + +.component-slideshow__entry { + margin-top: 30px +} + +@media only screen and (min-width:48em) { + .component-slideshow__entry { + margin-top: 0 + } +} + +.component-slideshow__entry-title { + margin-bottom: 24px +} + +.component-slideshow__entry-summary p:first-child { + margin-top: 0 +} + +.component-slideshow__pager { + margin-top: 60px +} + +@media only screen and (min-width:48em) { + .component-slideshow__pager { + margin-top: 120px + } +} + +.component-slideshow__pager .slick-list { + margin: 0 -15px +} + +.component-slideshow__pager .slick-track { + width: 100% +} + +.component-slideshow__pager img { + margin: 0 15px +} + +.component-slideshow__pager img:hover { + cursor: pointer +} + +.component-slideshow__pager.slick-slider .slick-next, +.component-slideshow__pager.slick-slider .slick-prev { + top: calc(70% - 75px) +} + +.component-tabs { + border-top: 1px solid #dcdcdc; + border-bottom: 1px solid #dcdcdc; + padding: 40px 0 +} + +@media only screen and (min-width:48em) { + .component-tabs { + padding: 80px 0 + } +} + +.component-tabs--intro { + padding-bottom: 0 +} + +@media only screen and (min-width:48em) { + .component-tabs--intro { + padding-bottom: 40px + } +} + +.component-tabs--intro__title { + margin-bottom: 24px +} + +.component-tabs--menu, +.component-tabs--menu li { + list-style: none; + margin: 0; + padding: 0 +} + +.component-tabs--menu li a { + display: block; + padding: 12px 10px 12px 24px; + border-radius: 4px; + -webkit-transition: background-color .1s ease-in-out; + transition: background-color .1s ease-in-out; + color: #000 +} + +.component-tabs--menu li a.active { + font-weight: 500; + background: rgba(33, 150, 243, .1); + color: #2196f3; + -webkit-transition: background-color .1s ease-in-out; + transition: background-color .1s ease-in-out +} + +.component-tabs--sidebar { + padding-top: 80px +} + +@media only screen and (max-width:48em) { + .component-tabs--sidebar { + display: none + } +} + +.component-tabs__sidebar-title { + margin-bottom: 45px +} + +.component-tabs--main .component-tabs--section { + border-bottom: 1px solid #dcdcdc; + padding-top: 80px; + padding-bottom: 80px +} + +.component-tabs--main .component-tabs--section.last { + border-bottom: 0 +} + +.component-tabs .vidyard-wrapper, +.component-tabs .youtube-wrapper { + position: relative +} + +.component-tabs .vidyard-wrapper:hover, +.component-tabs .youtube-wrapper:hover { + cursor: pointer +} + +.component-tabs .mdi { + position: absolute; + color: #fff; + font-size: 3.5em; + top: 50%; + left: 50%; + -webkit-transform: translate(-50%, -50%); + transform: translate(-50%, -50%) +} + +.component-tabs .mdi:hover { + cursor: pointer +} + +.component-tabs .vidyard-player-container { + display: none !important +} + +.component-testimonials { + padding: 48px 0 +} + +@media only screen and (min-width:48em) { + .component-testimonials { + padding: 56px 0 + } +} + +.component-testimonials h2 { + margin-bottom: 40px +} + +.component-testimonials.bg-dark-grey .slick-slider .slick-next, +.component-testimonials.bg-dark-grey .slick-slider .slick-prev, +.component-testimonials.bg-dark-grey h2 { + color: #fff +} + +.component-testimonials.bg-dark-grey .slick-dots li:not(.slick-active) button { + background: rgba(255, 255, 255, .3) +} + +.component-testimonials .geysir-field-paragraph-wrapper { + min-height: 120px +} + +.component-testimonials--item { + background: #fafafa; + padding: 32px; + height: 100%; + width: 100%; + border-radius: 12px +} + +@media only screen and (min-width:48em) { + .component-testimonials--item { + display: -webkit-box; + display: -ms-flexbox; + display: flex + } +} + +.component-testimonials--item .testimonial-quote-image { + margin-right: 32px; + margin-bottom: 20px; + -ms-flex-negative: 0; + flex-shrink: 0 +} + +@media only screen and (min-width:48em) { + .component-testimonials--item .testimonial-quote-image { + margin-bottom: 0 + } +} + +.component-testimonials--item .testimonial-quote-text { + font-size: 1rem; + line-height: 1.5rem; + font-weight: 400; + color: #000 +} + +@media only screen and (min-width:48em) { + .component-testimonials--item .testimonial-quote-text { + font-size: 1.125rem; + line-height: 2rem + } +} + +.component-testimonials--item .testimonial-quote-text p { + margin: 0; + padding: 0 +} + +.component-testimonials--item .testimonial-quote-author { + font-size: .875rem; + line-height: 1.25rem; + font-style: italic; + color: rgba(0, 0, 0, .5); + padding-left: 20px; + position: relative +} + +.component-testimonials--item .testimonial-quote-author::before { + content: "—"; + display: block; + position: absolute; + left: 0; + top: 0; + width: 20px; + height: 10px +} + +.component-testimonials--item .testimonial-quote-link a { + font-weight: 500; + text-decoration: none; + color: #2196f3 +} + +.items-single .component-testimonials--item { + padding: 32px +} + +@media only screen and (min-width:48em) { + .items-single .component-testimonials--item { + padding: 48px + } +} + +.component-testimonials .slick-slider .slick-track { + display: -webkit-box; + display: -ms-flexbox; + display: flex +} + +.component-testimonials .slick-slider .slick-track .slick-slide { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + height: auto; + margin: 0 15px +} + +.component-testimonials .slick-slider .slick-list { + margin: 0 -15px +} + +.component-testimonials .slick-slider .slick-slider .slick-next, +.component-testimonials .slick-slider .slick-slider .slick-prev { + top: 50% +} + +.component-testimonials .slick-slider .slick-dots { + position: relative; + top: 28px; + padding-bottom: 28px +} + +.component-testimonials-persons .testimonial-quote-image img { + border-radius: 100%; + width: 48px; + height: 48px +} + +@media only screen and (min-width:48em) { + .component-testimonials-persons .testimonial-quote-image img { + width: 96px; + height: 96px + } +} + +.component-testimonials-studios .testimonial-quote-image img { + width: 64px; + height: auto +} + +@media only screen and (min-width:48em) { + .component-testimonials-studios .testimonial-quote-image img { + width: 96px + } +} + +.component-text-image { + padding: 40px 0 +} + +@media only screen and (min-width:48em) { + .component-text-image { + padding: 56px 0 + } +} + +.component-text-image.bg-dark-grey { + color: #fff +} + +.component-text-image.bg-dark-grey h2 { + color: #fff +} + +.component-text-image .btn, +.component-text-image .btn-outline { + margin-right: 15px +} + +.component-text-image__image { + margin-bottom: 30px +} + +@media only screen and (min-width:48em) { + .component-text-image__image { + margin-bottom: 0 + } +} + +.component-text-iframe { + padding: 40px 0 +} + +@media only screen and (min-width:48em) { + .component-text-iframe { + padding: 80px 0 + } +} + +.component-text-iframe.bg-dark-grey { + color: #fff +} + +.component-text-iframe.bg-dark-grey h2 { + color: #fff +} + +.component-text-iframe .btn, +.component-text-iframe .btn-outline { + margin-right: 15px +} + +@media only screen and (min-width:62.85em) { + + .component-text-iframe .btn, + .component-text-iframe .btn-outline { + margin-bottom: 40px + } +} + +.component-text-iframe__frame { + margin-bottom: 30px +} + +@media only screen and (min-width:48em) { + .component-text-iframe__frame { + margin-bottom: 0 + } +} + +.component-text-video { + padding: 40px 0 +} + +@media only screen and (min-width:48em) { + .component-text-video { + padding: 56px 0 + } +} + +.component-text-video.bg-dark-grey { + color: #fff +} + +.component-text-video.bg-dark-grey h2 { + color: #fff +} + +.component-text-video .btn, +.component-text-video .btn-outline { + margin-right: 15px +} + +.component-text-video__image { + margin-bottom: 30px +} + +@media only screen and (min-width:48em) { + .component-text-video__image { + margin-bottom: 0 + } +} + +.component-text-video__image .caption { + margin: 5px 0 0; + font-style: italic +} + +.component-text-map { + padding: 80px 0 +} + +.component-text-map.bg-dark-grey { + color: #fff +} + +.component-text-map.bg-dark-grey h2 { + color: #fff +} + +.component-text-map .location-title { + font-size: 1.125rem; + line-height: 1.5rem; + font-weight: 500; + margin: 10px 0 +} + +.component-text-map .location-content { + font-size: .875rem; + line-height: 1rem; + font-weight: 400 +} + +.component-text-map .location-content p { + margin-top: 0; + margin-bottom: 10px +} + +.component-text-map .btn, +.component-text-map .btn-outline { + margin: 0 15px 15px 0; + line-height: 1.5rem +} + +@media only screen and (min-width:48em) { + + .component-text-map .btn, + .component-text-map .btn-outline { + margin-bottom: 0 + } +} + +.component-text-map .geolocation-common-map-container { + border-radius: 6px +} + +.component-text-map .geolocation-common-map-locations { + display: none +} + +.component-text-map .gm-style-iw { + max-width: 350px +} + +.dk-select, +.dk-select-multi { + font-size: 1rem; + line-height: 1.5rem; + position: relative; + display: inline-block; + vertical-align: middle; + line-height: 1.5em; + cursor: pointer; + width: 100% +} + +.dk-selected { + width: 100%; + white-space: nowrap; + overflow: hidden; + position: relative; + background-color: #fff; + border: 1px solid rgba(0, 0, 0, .42); + border-radius: 4px; + padding: 14px 12px; + text-overflow: ellipsis; + outline: 0 +} + +.dk-selected:hover { + border: 1px solid rgba(0, 0, 0, .87); + outline: 0 +} + +.dk-selected:focus { + outline: 0 +} + +.dk-selected::before { + top: 50%; + border: solid transparent; + border-width: 5px 5px 0; + border-top-color: rgba(0, 0, 0, .42); + margin: -.125em 14px 0 0 +} + +.dk-selected::after { + top: 0; + height: 100%; + margin: 0 20px 0 0 +} + +.dk-selected::after, +.dk-selected::before { + content: ""; + display: block; + position: absolute; + right: 0 +} + +.dk-selected.-disabled { + color: #bbb +} + +.dk-select .dk-select-options { + font-size: 1rem; + line-height: 1.5rem; + position: absolute; + display: none; + left: 0; + right: 0 +} + +.dk-select-open-up .dk-select-options { + border-radius: 4px 4px 0 0; + bottom: 100% +} + +.dk-select-open-down .dk-select-options { + border-radius: 0 0 4px 4px; + top: 100% +} + +.dk-select-multi .dk-select-options { + max-height: 10em +} + +.dk-select-options { + background-color: #fff; + border-radius: 4px; + list-style: none; + margin: 0; + max-height: 10.5em; + overflow-x: hidden; + overflow-y: auto; + padding: 0; + width: auto; + z-index: 100; + -webkit-box-shadow: 0 5px 10px 0 rgba(0, 0, 0, .1), 0 2px 5px 0 rgba(0, 0, 0, .1); + box-shadow: 0 5px 10px 0 rgba(0, 0, 0, .1), 0 2px 5px 0 rgba(0, 0, 0, .1) +} + +.dk-option-selected { + background-color: rgba(0, 0, 0, .09); + color: #000 +} + +.dk-select-options-highlight .dk-option-selected { + background-color: rgba(0, 0, 0, .09); + color: #000 +} + +.dk-option { + padding: 12px 16px 10px 16px +} + +.dk-select-options .dk-option-highlight { + background-color: #2196f3; + color: #fff +} + +.dk-select-options .dk-option-disabled { + color: #bbb; + background-color: transparent +} + +.dk-select-options .dk-option-hidden { + display: none +} + +.dk-optgroup { + border: solid rgba(0, 0, 0, .42); + border-width: 1px 0; + padding: .25em 0; + margin-top: .25em +} + +.dk-optgroup+.dk-option { + margin-top: .25em +} + +.dk-optgroup+.dk-optgroup { + border-top-width: 0; + margin-top: 0 +} + +.dk-optgroup:nth-child(2) { + padding-top: 0; + border-top: 0; + margin-top: 0 +} + +.dk-optgroup:last-child { + border-bottom-width: 0; + margin-bottom: 0; + padding-bottom: 0 +} + +.dk-optgroup-disabled { + opacity: .6; + color: #bbb; + cursor: not-allowed +} + +.dk-optgroup-label { + padding: 0 .5em .25em; + font-weight: 700; + width: 100% +} + +.dk-optgroup-options { + list-style: none; + padding-left: 0 +} + +.dk-optgroup-options li { + padding-left: 1.2em +} + +.dk-select-open-up .dk-selected { + border-top-left-radius: 0; + border-top-right-radius: 0; + border-color: #2196f3 +} + +.dk-select-open-down .dk-selected { + border-bottom-left-radius: 0; + border-bottom-right-radius: 0; + border-color: #2196f3 +} + +.dk-select-open-down .dk-selected::before, +.dk-select-open-up .dk-selected::before { + border-width: 0 .25em .25em; + border-bottom-color: #2196f3 +} + +.dk-select-open-down .dk-selected::after, +.dk-select-open-up .dk-selected::after { + border-left-color: #2196f3 +} + +.dk-select-multi:focus .dk-select-options, +.dk-select-open-down .dk-select-options, +.dk-select-open-up .dk-select-options { + display: block; + border-color: #2196f3 +} + +.dk-select-multi:focus, +.dk-select-multi:hover { + outline: 0 +} + +.dk-selected:focus::before, +.dk-selected:hover::before { + border-top-color: #2196f3 +} + +.dk-selected:focus::after, +.dk-selected:hover::after { + border-left-color: #2196f3 +} + +.dk-select-disabled { + opacity: .6; + color: #bbb; + cursor: not-allowed +} + +.dk-select-disabled .dk-selected:focus, +.dk-select-disabled .dk-selected:hover { + border-color: inherit +} + +.dk-select-disabled .dk-selected:focus::before, +.dk-select-disabled .dk-selected:hover::before { + border-top-color: inherit +} + +.dk-select-disabled .dk-selected:focus::after, +.dk-select-disabled .dk-selected:hover::after { + border-left-color: inherit +} + +select[data-dkcacheid] { + display: none +} + +.component-eloqua-form { + padding: 40px 0 +} + +@media only screen and (min-width:48em) { + .component-eloqua-form { + padding: 80px 0 + } +} + +.elq-form .grid-layout-col { + width: 100% +} + +.elq-form p.field-p { + margin: 0 +} + +.elq-form h3.heading { + font-size: 1.25rem; + line-height: 1.75rem; + font-weight: 500; + padding-top: 16px +} + +@media only screen and (min-width:62.85em) { + .elq-form h3.heading { + font-size: 1.5rem; + line-height: 2rem + } +} + +.elq-form textarea { + resize: vertical +} + +.elq-form .form-element-layout, +.elq-form .form-item { + margin: 0 +} + +.elq-form .form-element-layout:hover label.elq-label, +.elq-form .form-element-layout:hover label.label-position, +.elq-form .form-item:hover label.elq-label, +.elq-form .form-item:hover label.label-position { + color: rgba(0, 0, 0, .87) +} + +.elq-form .form-element-layout.focus label.elq-label, +.elq-form .form-element-layout.focus label.label-position, +.elq-form .form-item.focus label.elq-label, +.elq-form .form-item.focus label.label-position { + color: #2196f3 +} + +.elq-form .form-element-layout .field-wrapper, +.elq-form .form-item .field-wrapper { + margin: 0 0 24px +} + +.elq-form .single-checkbox-row { + margin-left: 0; + margin-right: 0 +} + +.elq-form .form-design-field, +.elq-form .form-element-layout { + margin: 0 0 24px +} + +.elq-form .LV_valid { + display: none +} + +.elq-form .LV_invalid { + font-size: .75rem; + line-height: 1.5rem; + font-weight: 400; + color: #f44336 +} + +.elq-form .instructions.default { + font-size: .75rem; + margin-top: 4px +} + +.elq-form .LV_invalid_field, +.elq-form .LV_invalid_field:active, +.elq-form .LV_invalid_field:hover, +.elq-form .LV_valid_field, +.elq-form .LV_valid_field:active, +.elq-form .LV_valid_field:hover { + outline: 0 !important +} + +.elq-form .field-group { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -ms-flex-wrap: wrap; + flex-wrap: wrap; + margin: 0 -8px +} + +.elq-form .field-group>label { + font-size: 1rem; + color: #000; + width: 100%; + -webkit-box-flex: 1; + -ms-flex-positive: 1; + flex-grow: 1; + margin: 16px 0 12px 8px +} + +.elq-form ._50 { + width: 50%; + -webkit-box-flex: 1; + -ms-flex: 1; + flex: 1; + padding: 0 8px +} + +.elq-form ._25 { + width: 25%; + -webkit-box-flex: 1; + -ms-flex: 1; + flex: 1; + padding: 0 8px +} + +.elq-form select[multiple] { + width: 100%; + border-radius: 4px; + border: 0; + outline: 0; + -webkit-box-shadow: 0 5px 10px 0 rgba(0, 0, 0, .1), 0 2px 5px 0 rgba(0, 0, 0, .1); + box-shadow: 0 5px 10px 0 rgba(0, 0, 0, .1), 0 2px 5px 0 rgba(0, 0, 0, .1) +} + +.elq-form select[multiple]:hover { + outline: 0 +} + +.elq-form select[multiple] option { + padding: 12px 16px 10px 16px +} + +.elq-form .radio-option+label.instructions { + font-size: .75rem; + margin: -10px 0 0 33px; + color: #000 +} + +.elq-form .checkbox-span+label.instructions { + font-size: .75rem; + margin: -10px 0 0 33px; + color: #000 +} + +.component-unify-schedule { + padding: 40px 0 +} + +@media only screen and (min-width:48em) { + .component-unify-schedule { + padding: 80px 0 + } +} + +.component-unify-schedule .mdi-chevron-down, +.component-unify-schedule .mdi-chevron-up { + font-size: 1.75rem; + color: #2196f3; + cursor: pointer +} + +.component-unify-schedule__title { + margin-bottom: 24px +} + +.component-unify-schedule__summary p:first-child { + margin-top: 0 +} + +.component-unify-schedule__buttons { + margin-top: 40px +} + +.component-unify-schedule__buttons a { + margin-right: 20px +} + +.component-unify-schedule__buttons a:last-child { + margin-right: 0 +} + +.component-unify-schedule__intro { + margin-bottom: 60px +} + +.rooms-tabs { + padding-bottom: 48px +} + +.rooms-tabs ul { + list-style: none; + margin: 24px 0 0; + padding: 0 +} + +.rooms-tabs ul li { + list-style: none; + margin: 0 8px 8px 0; + padding: 0; + display: inline-block +} + +.rooms-tabs ul li:last-child { + margin: 0 +} + +.rooms-tabs .rooms-filter { + cursor: pointer +} + +.rooms-tabs .rooms-filter .schedule-chevron-filter { + margin-left: 10px; + top: 3px +} + +.rooms-tabs a { + font-size: .875rem; + display: inline-block; + padding: 8px 12px; + background: #ededed; + color: #000; + border-radius: 24px; + cursor: pointer +} + +.rooms-tabs a.selected { + background: #2196f3; + color: #fff +} + +.rooms-container { + border-top: 1px solid #dcdcdc +} + +.session { + padding: 48px 0; + border-bottom: 1px solid #dcdcdc +} + +.session .title { + margin-bottom: 4px +} + +.session .time { + font-size: 1rem; + line-height: 2rem; + font-weight: 500 +} + +.session .time .schedule-chevron-session { + float: right +} + +@media only screen and (min-width:48em) { + .session .time .schedule-chevron-session { + display: none + } +} + +.session .speaker { + cursor: pointer +} + +.session .description { + margin-top: 24px +} + +.session .btn { + margin-top: 40px +} + +.session .inline-meta { + margin-top: 10px +} + +@media only screen and (min-width:48em) { + .session .inline-meta { + margin-top: 0; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-orient: horizontal; + -webkit-box-direction: normal; + -ms-flex-direction: row; + flex-direction: row + } +} + +@media only screen and (min-width:48em) { + .session .inline-meta__item { + margin-right: 20px + } + + .session .inline-meta__item:last-child { + margin-right: 0 + } +} + +.session .toggle { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: end; + -ms-flex-pack: end; + justify-content: flex-end +} + +.session .speakers { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-orient: horizontal; + -webkit-box-direction: normal; + -ms-flex-direction: row; + flex-direction: row; + margin-top: 60px +} + +.session .speakers>div { + font-size: .875rem; + line-height: 1.5rem; + margin-right: 32px; + color: #5a5a5b +} + +.session .speakers>div:last-child { + margin-right: 0 +} + +.session .speakers>div .name { + font-size: 1rem; + line-height: 1.5rem; + display: block +} + +.speaker { + position: relative +} + +.speaker-popup { + width: 100%; + margin-bottom: 20px; + padding: 32px; + border-radius: 6px; + background: #f9f9f9; + color: #000 +} + +.speaker-popup::after { + display: none +} + +@media only screen and (min-width:48em) { + .speaker-popup::after { + display: block; + content: ""; + position: absolute; + width: 0; + height: 0; + margin-left: -.5em; + bottom: -18px; + left: 50%; + -webkit-box-sizing: border-box; + box-sizing: border-box; + border: 10px solid #000; + border-color: transparent transparent #f9f9f9 #f9f9f9; + -webkit-transform-origin: 0 0; + transform-origin: 0 0; + -webkit-transform: rotate(-45deg); + transform: rotate(-45deg); + -webkit-box-shadow: -3px 3px 6px 0 rgba(0, 0, 0, .07); + box-shadow: -3px 3px 6px 0 rgba(0, 0, 0, .07) + } +} + +@media only screen and (min-width:48em) { + .speaker-popup { + width: 600px; + position: absolute; + bottom: 50px; + left: -250px; + -webkit-box-shadow: 0 5px 10px 0 rgba(0, 0, 0, .1); + box-shadow: 0 5px 10px 0 rgba(0, 0, 0, .1); + margin-bottom: 0 + } +} + +.speaker-popup__grid { + display: -webkit-box; + display: -ms-flexbox; + display: flex +} + +.speaker-popup__details { + width: 100%; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -ms-flex-direction: column; + flex-direction: column; + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center +} + +.speaker-popup__image { + width: 96px; + height: 96px; + border-radius: 100%; + margin-right: 24px +} + +.speaker-popup__company { + margin: 0 +} + +.speaker-popup__summary { + max-height: 150px; + overflow: auto; + margin-top: 32px +} + +@media only screen and (min-width:48em) { + .speaker-popup__summary::after { + content: ""; + width: 100%; + height: 40px; + display: block; + position: absolute; + left: 0; + bottom: 20px; + background-image: -webkit-gradient(linear, left bottom, left top, from(#f9f9f9), to(rgba(238, 238, 238, 0))); + background-image: linear-gradient(0deg, #f9f9f9 0, rgba(238, 238, 238, 0) 100%) + } +} + +.component-unify-speakers { + padding: 40px 0 +} + +@media only screen and (min-width:48em) { + .component-unify-speakers { + padding: 80px 0 + } +} + +.component-unify-speakers__item { + margin-bottom: 30px +} + +.component-unify-speakers__secondary { + margin-top: -10px +} + +.component-unify-speakers__less, +.component-unify-speakers__more { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center +} + +.component-unify-speakers__title { + margin-bottom: 24px +} + +.component-unify-speakers__summary p:first-child { + margin-top: 0 +} + +.component-unify-speakers__intro { + margin-bottom: 60px +} + +.component-speakers-card { + display: block; + overflow: hidden; + position: relative; + border-radius: 6px; + height: 100%; + max-width: 512px +} + +.component-speakers-card:hover .component-speakers-card__overlay { + background-color: rgba(0, 0, 0, .3); + -webkit-transition: background-color .3s ease-in-out; + transition: background-color .3s ease-in-out +} + +.component-speakers-card:hover .component-speakers-card__company, +.component-speakers-card:hover .component-speakers-card__name, +.component-speakers-card:hover .component-speakers-card__position { + opacity: 1 +} + +.component-speakers-card__image { + height: 100% +} + +.component-speakers-card__overlay { + background-color: transparent; + -webkit-transition: background-color .3s ease-in-out; + transition: background-color .3s ease-in-out; + width: 100%; + height: 100%; + position: absolute +} + +.component-speakers-card__content { + position: absolute; + left: 24px; + bottom: 40px; + margin-right: 24px +} + +.component-speakers-card__badge { + font-size: .875rem; + line-height: 1.25rem; + position: absolute; + top: 8px; + right: 8px; + padding: 6px 12px; + color: #fff; + background: #2196f3; + border-radius: 24px; + z-index: 2 +} + +@media only screen and (min-width:48em) { + .component-speakers-card__badge { + top: 24px; + right: 24px + } +} + +.component-speakers-card__name { + font-size: 1.125rem; + line-height: 1.5rem; + font-weight: 500; + opacity: 0; + color: #fff +} + +.component-speakers-card__company { + font-size: 1rem; + line-height: 1.5rem; + font-weight: 500; + opacity: 0; + color: #fff; + margin-bottom: 15px +} + +.component-speakers-card__position { + font-size: .875rem; + line-height: 1.25rem; + opacity: 0; + color: #fff +} + +.component-sponsors { + padding: 40px 0 50px +} + +@media only screen and (min-width:48em) { + .component-sponsors { + padding: 80px 0 + } +} + +.component-sponsors h2 { + margin-bottom: 24px +} + +.component-sponsors__subhead { + margin-bottom: 20px +} + +.component-sponsors__summary p:first-child { + margin-top: 0 +} + +.component-sponsors__buttons { + margin-top: 40px +} + +.component-sponsors__buttons a { + margin-right: 20px +} + +.component-sponsors__buttons a:last-child { + margin-right: 0 +} + +.component-sponsors__item { + height: 100px; + margin-bottom: 30px +} + +.component-sponsors__image { + height: 100%; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center +} + +.component-material-tabs { + margin: 0 0 30px; + position: relative; + height: 60px; + -webkit-overflow-scrolling: touch; + overflow-x: scroll; + overflow-y: hidden; + white-space: nowrap +} + +@media only screen and (min-width:48em) { + .component-material-tabs { + margin: 0 0 60px; + -webkit-overflow-scrolling: none; + overflow: hidden + } +} + +.component-material-tabs ul { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + padding: 0 +} + +@media only screen and (min-width:48em) { + .component-material-tabs ul { + display: block + } +} + +.component-material-tabs li { + margin-right: 15px; + display: inline-block; + height: 40px; + padding: 0 +} + +.component-material-tabs li:last-child { + margin-right: 0 +} + +.component-material-tabs a { + font-size: 1.125rem; + line-height: 2.5rem; + padding: 9px 0; + height: 40px; + color: #000; + cursor: pointer +} + +.component-material-tabs a.selected { + color: #2196f3 +} + +.component-material-tabs .js-tab-underline { + display: none +} + +@media only screen and (min-width:48em) { + .component-material-tabs .js-tab-underline { + display: block; + width: 1px; + height: 2px; + position: absolute; + left: 15px; + bottom: 0; + background: #2196f3; + -webkit-transition: .3s ease-in-out; + transition: .3s ease-in-out; + will-change: width + } +} + +.component-promotion-large { + display: block; + width: 100%; + height: 157px; + position: relative; + border-radius: 6px; + background-repeat: no-repeat; + background-size: cover; + background-position: center; + -webkit-transition: background-size 1s; + transition: background-size 1s; + -webkit-backface-visibility: hidden; + backface-visibility: hidden; + overflow: hidden; + color: #fff; + text-decoration: none +} + +@media only screen and (min-width:48em) { + .component-promotion-large:hover { + background-size: 115% 115%; + -webkit-transition: background-color 1s, background-size 1s; + transition: background-color 1s, background-size 1s + } +} + +.component-promotion-large::before { + content: ""; + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + background: rgba(0, 0, 0, .2); + border-radius: 6px; + -webkit-transition: background-color 1s; + transition: background-color 1s +} + +@media only screen and (min-width:48em) { + .component-promotion-large { + background-position: top left; + background-size: 100% 100%; + height: 415px + } +} + +@media only screen and (min-width:62.85em) { + .component-promotion-large { + height: 367px + } +} + +@media only screen and (min-width:78.7em) { + .component-promotion-large { + height: 456px + } +} + +.component-promotion-large:hover::before { + background: rgba(0, 0, 0, .8) +} + +.component-promotion-large__data { + width: 100%; + height: 100%; + position: absolute; + z-index: 1; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -ms-flex-direction: column; + flex-direction: column; + -webkit-box-pack: end; + -ms-flex-pack: end; + justify-content: flex-end; + padding: 0 24px 24px +} + +@media only screen and (min-width:78.7em) { + .component-promotion-large__data { + padding: 0 40px 40px + } +} + +.component-promotion-large__title { + margin-bottom: 8px +} + +.component-promotion-large__summary { + display: none +} + +@media only screen and (min-width:48em) { + .component-promotion-large__summary { + font-size: 1rem; + line-height: 1.5rem; + display: block + } +} + +@media only screen and (min-width:62.85em) { + .component-promotion-large__summary { + font-size: 1.125rem; + line-height: 2rem + } +} + +.component-promotion-medium { + display: block; + width: 100%; + height: 157px; + position: relative; + border-radius: 6px; + background-repeat: no-repeat; + background-size: cover; + background-position: center; + -webkit-transition: background-size 1s; + transition: background-size 1s; + -webkit-backface-visibility: hidden; + backface-visibility: hidden; + overflow: hidden; + color: #fff; + text-decoration: none +} + +@media only screen and (min-width:48em) { + .component-promotion-medium:hover { + background-size: 115% 115%; + -webkit-transition: background-color 1s, background-size 1s; + transition: background-color 1s, background-size 1s + } +} + +.component-promotion-medium::before { + content: ""; + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + background: rgba(0, 0, 0, .2); + border-radius: 6px; + -webkit-transition: background-color 1s; + transition: background-color 1s +} + +@media only screen and (min-width:48em) { + .component-promotion-medium { + background-position: top left; + background-size: 100% 100%; + height: 198px + } +} + +@media only screen and (min-width:62.85em) { + .component-promotion-medium { + height: 170px + } +} + +@media only screen and (min-width:78.7em) { + .component-promotion-medium { + height: 213px + } +} + +.component-promotion-medium:hover::before { + background: rgba(0, 0, 0, .8) +} + +.component-promotion-medium__data { + width: 100%; + height: 100%; + position: absolute; + padding: 0 24px 24px; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -ms-flex-direction: column; + flex-direction: column; + -webkit-box-pack: end; + -ms-flex-pack: end; + justify-content: flex-end +} + +.component-promotion-medium__title { + margin-bottom: 8px +} + +.component-promotion-medium__summary { + display: none +} + +@media only screen and (min-width:48em) { + .component-promotion-medium__summary { + font-size: .875rem; + line-height: 1.375rem; + display: block + } +} + +@media only screen and (min-width:62.85em) { + .component-promotion-medium__summary { + font-size: 1rem; + line-height: 1.5rem + } +} + +.component-promotion-compact { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + color: #000; + border-bottom: 1px solid #f5f5f5; + padding-bottom: 20px; + margin-bottom: 20px +} + +@media only screen and (min-width:48em) { + .component-promotion-compact { + margin-bottom: 0; + padding-bottom: 15px + } +} + +@media only screen and (min-width:62.85em) { + .component-promotion-compact { + padding-bottom: 30px + } +} + +.component-promotion-compact__image { + display: none; + width: 140px; + height: 140px; + margin-right: 20px +} + +@media only screen and (min-width:78.7em) { + .component-promotion-compact__image { + display: block + } +} + +.component-promotion-compact__image img { + border-radius: 6px +} + +.component-promotion-compact__data { + -webkit-box-flex: 1; + -ms-flex: 1; + flex: 1 +} + +.component-promotion-compact__title { + font-size: 1rem; + line-height: 1.5rem; + font-weight: 700; + margin-bottom: 8px +} + +.component-promotion-compact__summary { + font-size: .875rem; + line-height: 1.25rem +} + +.component-promotions { + padding: 60px 0 +} + +@media only screen and (min-width:48em) { + .component-promotions { + padding: 80px 0 120px + } +} + +.component-promotions__title { + margin-bottom: 10px +} + +@media only screen and (min-width:48em) { + .component-promotions__title { + margin-bottom: 30px + } +} + +.promotions-list-compact { + border-top: 1px solid #f5f5f5; + padding-top: 20px; + margin-top: 20px +} + +@media only screen and (min-width:48em) { + .promotions-list-compact { + padding-top: 15px; + margin-top: 15px + } +} + +@media only screen and (min-width:62.85em) { + .promotions-list-compact { + padding-top: 30px; + margin-top: 30px + } +} + +.promotions-list-compact .views-row { + width: 100% +} + +.promotions-list-large { + margin-bottom: 20px +} + +@media only screen and (min-width:48em) { + .promotions-list-large { + margin-bottom: 15px + } +} + +@media only screen and (min-width:62.85em) { + .promotions-list-large { + margin-bottom: 0 + } +} + +.promotions-list-large .views-row { + width: 100% +} + +@media only screen and (min-width:62.85em) { + .promotions-list-medium .views-row:nth-child(1) { + margin-bottom: 30px + } +} + +.promotions-list-medium .views-row { + margin-bottom: 20px +} + +@media only screen and (min-width:48em) { + .promotions-list-medium .views-row { + margin-bottom: 0 + } +} + +.component-showcase { + padding: 60px 0; + background-color: #000; + background-repeat: no-repeat; + background-size: cover; + -webkit-transition: .5s to background-image; + transition: .5s to background-image; + color: #fff +} + +@media only screen and (min-width:48em) { + .component-showcase { + padding: 120px 0 + } +} + +.component-showcase__title { + margin-bottom: 4px +} + +.component-showcase__buttons { + margin-top: 40px +} + +.component-showcase__buttons .btn, +.component-showcase__buttons .btn-outline { + margin-right: 15px +} + +@media only screen and (min-width:62.85em) { + + .component-showcase__buttons .btn, + .component-showcase__buttons .btn-outline { + margin-bottom: 40px + } +} + +.component-showcase ul.slick-dots li button { + background: rgba(255, 255, 255, .3) +} + +.component-showcase ul.slick-dots li.slick-active button { + background: #2196f3 +} + +.component-showcase-tiles { + margin-top: 40px +} + +@media only screen and (min-width:48em) { + .component-showcase-tiles { + margin-top: 60px + } +} + +@media only screen and (min-width:62.85em) { + .component-showcase-tiles__expanded { + -webkit-box-pack: justify; + -ms-flex-pack: justify; + justify-content: space-between + } +} + +.component-showcase-tiles__item { + margin-bottom: 40px +} + +.component-showcase-tile { + display: block; + border: 3px solid #fff; + background-clip: padding-box; + border-radius: 6px; + -webkit-transition: background-color .4s, color .4s; + transition: background-color .4s, color .4s; + color: #fff; + padding: 24px; + height: 236px; + position: relative +} + +@media only screen and (min-width:48em) { + .component-showcase-tile { + height: 284px + } +} + +.component-showcase-tile--selected, +.component-showcase-tile:hover { + cursor: pointer; + background-color: #fff; + border: 3px solid #fff; + background-clip: padding-box; + -webkit-transition: background-color .4s, color .4s; + transition: background-color .4s, color .4s +} + +.component-showcase-tile--selected .component-showcase-tile__byline, +.component-showcase-tile--selected .component-showcase-tile__summary, +.component-showcase-tile--selected .component-showcase-tile__title, +.component-showcase-tile:hover .component-showcase-tile__byline, +.component-showcase-tile:hover .component-showcase-tile__summary, +.component-showcase-tile:hover .component-showcase-tile__title { + color: #000 +} + +.component-showcase-tile--selected .component-showcase-tile__link, +.component-showcase-tile--selected .component-showcase-tile__summary, +.component-showcase-tile:hover .component-showcase-tile__link, +.component-showcase-tile:hover .component-showcase-tile__summary { + display: block +} + +.component-showcase-tile__title { + color: #fff +} + +.component-showcase-tile__summary { + display: none; + margin-top: 16px +} + +.component-showcase-tile__link { + font-size: 1rem; + color: #2196f3; + display: none; + position: absolute; + bottom: 24px; + left: 24px +} + +.component-social-stats { + margin-top: 56px; + margin-bottom: 56px; + background: #f5f5f5 +} + +@media only screen and (min-width:62.85em) { + .component-social-stats { + border-radius: 6px + } +} + +.component-social-stats.bg-dark-grey { + background: #242424; + color: #fff +} + +.component-social-stats .inner { + padding: 24px 0; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -ms-flex-wrap: wrap; + flex-wrap: wrap; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -ms-flex-direction: column; + flex-direction: column +} + +@media only screen and (min-width:48em) { + .component-social-stats .inner { + padding: 16px 24px; + -ms-flex-line-pack: center; + align-content: center + } +} + +@media only screen and (min-width:62.85em) { + .component-social-stats .inner { + -ms-flex-wrap: nowrap; + flex-wrap: nowrap; + -webkit-box-orient: horizontal; + -webkit-box-direction: normal; + -ms-flex-direction: row; + flex-direction: row; + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center + } +} + +.social-stat { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + max-width: 388px; + -webkit-box-flex: 1; + -ms-flex: 1; + flex: 1; + margin-bottom: 24px; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center +} + +.social-stat:last-child { + margin-bottom: 0; + margin-right: 0 +} + +@media only screen and (min-width:62.85em) { + .social-stat { + margin-bottom: 0; + margin-right: 32px + } +} + +.social-stat .mdi { + font-size: 1.25rem; + line-height: 1.25rem; + color: #3ac561; + margin-right: 16px; + min-width: 32px; + min-height: 32px; + background: #fff; + border-radius: 100%; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center +} + +@media only screen and (min-width:62.85em) { + .social-stat .mdi { + background: 0 0; + min-width: auto; + min-height: auto; + display: inline-block + } +} + +.bg-dark-grey .social-stat .mdi { + background: #000 +} + +@media only screen and (min-width:62.85em) { + .bg-dark-grey .social-stat .mdi { + background: 0 0 + } +} + +.social-stat p { + font-size: .875rem; + line-height: 1.25rem; + margin: 0 +} + +.video-wrapper { + position: relative; + padding-bottom: 0 +} + +.video-wrapper .mdi { + position: absolute; + color: #fff; + font-size: 3.5em; + top: 50%; + left: 50%; + -webkit-transform: translate(-50%, -50%); + transform: translate(-50%, -50%) +} + +.video-wrapper .vidyard-lightbox-image { + display: none +} + +.video-wrapper .vidyard-player-container { + position: absolute +} + +.video-wrapper .vidyard-player-container .play-button { + display: none !important +} + +.video-wrapper .vidyard-player-embed { + display: block !important +} + +.component-title { + margin-bottom: 16px +} + +.component-layout-section .layout__one-column { + padding-bottom: 32px +} + +@media only screen and (min-width:48em) { + .component-layout-section .layout__one-column { + padding-bottom: 40px + } +} + +.component-layout-section .layout__one-column--p-top { + padding-top: 32px +} + +@media only screen and (min-width:48em) { + .component-layout-section .layout__one-column--p-top { + padding-top: 40px + } +} + +@media only screen and (min-width:78.7em) { + .component-layout-section .layout__one-column--p-top { + padding-top: 56px + } +} + +.component-layout-section .layout__one-column--p-bottom { + padding-bottom: 32px +} + +@media only screen and (min-width:48em) { + .component-layout-section .layout__one-column--p-bottom { + padding-bottom: 40px + } +} + +@media only screen and (min-width:78.7em) { + .component-layout-section .layout__one-column--p-bottom { + padding-bottom: 56px + } +} + +.component-layout-section .layout__one-column>.paragraph:last-child { + margin-bottom: 0 !important +} + +.component-layout-section .layout__two-columns { + padding-top: 32px; + padding-bottom: 32px +} + +@media only screen and (min-width:48em) { + .component-layout-section .layout__two-columns { + padding-top: 40px; + padding-bottom: 40px + } +} + +@media only screen and (min-width:78.7em) { + .component-layout-section .layout__two-columns { + padding-top: 56px; + padding-bottom: 56px + } +} + +.component-layout-section .layout__region:last-of-type>.paragraph:last-child { + margin-bottom: 0 !important +} + +@media only screen and (min-width:62.85em) { + .component-layout-section .layout__region>.paragraph:last-child { + margin-bottom: 0 !important + } +} + +.component-layout-section .layout__region p:last-of-type { + margin: 0 +} + +.component-layout-section .layout__region .row.mobile-reverse { + -webkit-box-orient: vertical; + -webkit-box-direction: reverse; + -ms-flex-direction: column-reverse; + flex-direction: column-reverse +} + +@media only screen and (min-width:48em) { + .component-layout-section .layout__region .row.mobile-reverse { + -webkit-box-orient: initial; + -webkit-box-direction: initial; + -ms-flex-direction: initial; + flex-direction: initial + } +} + +.component-layout-section .layout__region p { + margin-top: 0 +} + +.component-layout-section .layout__region .btn, +.component-layout-section .layout__region .btn-outline { + margin-right: 15px; + margin-bottom: 20px; + display: block +} + +@media only screen and (min-width:48em) { + + .component-layout-section .layout__region .btn, + .component-layout-section .layout__region .btn-outline { + margin-bottom: 0; + display: inline-block + } +} + +.component-layout-section .bg-dark-grey { + color: #fff +} + +.component-layout-section .bg-dark-grey h2 { + color: #fff +} + +@media only screen and (max-width:48em) { + .component-layout-section .mb40 { + margin-bottom: 32px !important + } +} + +@media only screen and (max-width:48em) { + .component-layout-section .xs-m-bottom { + margin-bottom: 4px !important + } +} + +.component-card { + position: relative; + overflow: hidden; + border-radius: 6px; + min-width: 150px; + max-width: 640px; + background: 0 0 +} + +.component-card__subhead { + color: #212121 +} + +.component-card__title { + margin-bottom: 4px +} + +.component-card__subtitle { + font-size: .875rem; + line-height: 1.25rem; + color: #8a8a8a; + margin-bottom: 24px +} + +.component-card__image { + margin-bottom: 24px +} + +.component-card__content { + position: relative; + padding: 0 0 40px +} + +.component-card__date { + font-size: .875rem; + color: #5a5a5b +} + +.component-card__description { + margin: 0 0 30px +} + +.component-card__description p { + margin: 0 0 1rem +} + +.component-card__description p:last-child { + margin: 0 +} + +.component-card__link { + position: absolute; + bottom: 32px; + left: 0 +} + +.component-card__link a { + text-decoration: none; + color: #2196f3; + margin-right: 20px; + font-weight: 500 +} + +.component-card__link a:hover { + cursor: pointer +} + +.component-card--video a.fancy-video, +.component-card--video a.vidyard-video { + display: block; + position: relative +} + +.component-card--video a.fancy-video .component-card-play-icon, +.component-card--video a.vidyard-video .component-card-play-icon { + position: absolute; + left: calc(50% - 23px); + top: calc(50% - 27px) +} + +.component-card--video a.fancy-video:hover, +.component-card--video a.vidyard-video:hover { + cursor: pointer +} + +.component-card .vidyard-player-container { + display: none !important +} + +.component-card--icon .component-card-content { + padding: 32px 32px 60px +} + +.component-card--icon .mdi { + font-size: 2.25rem; + margin-bottom: 24px +} + +.component-cards__summary p { + margin: 0 +} + +.component-cards__space-top { + margin-top: 32px +} + +.component-cards .slick-item:focus { + outline: 0 +} + +.component-cards--has-shadow .component-card { + background: #fff; + -webkit-box-shadow: 0 5px 10px 0 rgba(0, 0, 0, .1); + box-shadow: 0 5px 10px 0 rgba(0, 0, 0, .1) +} + +.component-cards--has-shadow .component-card__image { + margin-bottom: 0 +} + +.component-cards--has-shadow .component-card__content { + padding: 24px 32px 40px +} + +.component-cards--has-shadow .component-card__link { + left: 32px +} + +.component-cards--hide-shadow.bg-dark-grey .component-card__title { + color: #fff +} + +.component-cards--hide-shadow.bg-dark-grey .component-card__description { + color: #d8d8d8 +} + +.component-cards--hide-shadow.bg-dark-grey .component-card__subhead { + color: #9b9b9b +} + +.component-cards--hide-shadow.bg-dark-grey .component-card--icon .mdi { + color: #9b9b9b +} + +.component-cards.bg-dark-grey .cards-section-title { + color: #fff +} + +.component-cards.bg-dark-grey .component-cards__summary { + color: #fafafa +} + +.component-cards.bg-dark-grey .slick-slider .slick-next, +.component-cards.bg-dark-grey .slick-slider .slick-prev { + color: #6b6b6b +} + +.component-cards.bg-dark-grey .slick-dots button { + background: #6b6b6b +} + +.component-cards.bg-dark-grey .slick-dots li.slick-active button { + background: #2196f3 +} + +.component-faq-item { + padding-right: 8px +} + +.component-faq-item__title { + font-size: 1rem; + line-height: 1.5rem; + font-weight: 500; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + position: relative; + margin-bottom: 0; + padding: 20px 0 20px 46px; + cursor: pointer +} + +.component-faq-item__title::before { + font-size: 1.375rem; + content: "\f2f9"; + font-family: Material-Design-Iconic-Font, sans-serif; + position: absolute; + left: 0; + width: 24px; + height: 24px; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; + color: #2196f3; + top: 32px; + margin-top: -12px; + -webkit-transition: -webkit-transform 250ms ease-in-out; + transition: -webkit-transform 250ms ease-in-out; + transition: transform 250ms ease-in-out; + transition: transform 250ms ease-in-out, -webkit-transform 250ms ease-in-out +} + +.component-faq-item__body { + padding-bottom: 8px; + padding-left: 48px; + display: none +} + +.component-faq-item__body p { + margin-top: 0 +} + +.component-faq-item__body li, +.component-faq-item__body p { + font-size: 1rem; + line-height: 1.5rem +} + +.component-faq-item__toggle-checkbox { + position: absolute; + opacity: 0; + z-index: -1 +} + +.component-faq-item__toggle-checkbox:checked+.component-faq-item__title::before { + -webkit-transform: rotate(180deg); + transform: rotate(180deg) +} + +.component-faq-item__toggle-checkbox:checked~.component-faq-item__body { + display: block +} + +.component-fluid-tab { + background-color: #e3eff8; + padding: 2px 25px 0; + list-style-type: none; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + height: 46px; + border-radius: 4px 4px 0 0; + color: #2196f3; + white-space: nowrap; + cursor: pointer; + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; + position: static +} + +.component-fluid-tab:not(:last-child) { + margin-right: 15px +} + +.component-fluid-tab::before { + display: none +} + +@media only screen and (min-width:48em) { + .component-fluid-tab { + position: relative; + padding-left: 45px; + padding-right: 45px; + min-width: 340px + } +} + +.component-fluid-tab__footnote { + font-size: .6875rem; + line-height: 1rem; + font-weight: 700; + text-align: center; + position: absolute; + -webkit-transform: translateY(100%); + transform: translateY(100%); + top: 0; + left: 0; + display: none; + width: 100%; + padding: 8px 15px 0 +} + +@media only screen and (min-width:48em) { + .component-fluid-tab__footnote { + width: auto; + -webkit-transform: translate(-50%, 100%); + transform: translate(-50%, 100%); + margin-left: 50% + } +} + +.component-fluid-tab--is-active { + height: 48px; + border: 2px solid #2196f3; + border-bottom: 0; + background-color: #fff; + font-weight: 500; + font-size: 18px; + color: #0a0b09; + text-align: center; + line-height: 24px; + margin-bottom: -2px; + padding-top: 0 +} + +.component-fluid-tab--is-active .component-fluid-tab__footnote { + display: block +} + +.component-icon--white { + color: #fff +} + +.component-icon--rich-black { + color: #000 +} + +.component-icon--blue { + color: #2196f3 +} + +.component-icon--dark-charcoal { + color: #242424 +} + +.component-icon--charcoal { + color: #383838 +} + +.component-icon--stone { + color: #383838 +} + +.component-icon--grey { + color: #9b9b9b +} + +.component-icon--dark-grey { + color: #212121 +} + +.component-icon--medium-grey { + color: #d8d8d8 +} + +.component-icon--light-grey { + color: #ededed +} + +.component-icon--pale-grey { + color: #f5f5f5 +} + +.component-infoline { + margin: 0 +} + +.component-infoline__text { + margin: 0 +} + +.component-infoline__text::before { + font-size: 1.5rem; + margin-right: 8px; + position: relative; + top: 3px; + font-family: Material-Design-Iconic-Font, sans-serif; + content: "\f1f7" +} + +.component-list-item { + font-size: .8125rem; + line-height: 1.8125rem; + position: relative; + padding-bottom: 0; + font-weight: 400; + list-style-type: none +} + +.component-list-item::before { + font-size: 1.3125rem; + display: block; + position: absolute; + -webkit-transform: translateX(-100%); + transform: translateX(-100%); + font-family: Material-Design-Iconic-Font, sans-serif; + left: -9px +} + +.component-list-item--icon-bullet::before { + font-size: .375rem; + content: "\f26d" +} + +.component-list-item--icon-check::before { + content: "\f26b" +} + +.component-list-item--icon-dash::before { + content: "\f273" +} + +.component-list-item--icon-plus::before { + content: "\f278" +} + +.component-list-item--is-nested::before { + font-size: .9375rem; + left: -7px +} + +.component-list-item--is-nested.component-list-item--icon-bullet::before { + font-size: .25rem +} + +.component-list-item--icon-color-blue::before { + color: #2196f3 +} + +.component-list-item--icon-color-black::before { + color: #000 +} + +.component-list-item--font-weight-medium { + font-weight: 500 +} + +.component-list { + padding-left: 24px +} + +.component-list--is-nested { + padding-top: 0; + padding-left: 18px; + margin-top: 0; + margin-bottom: 0 +} + +.component-product-card-large { + color: #fff; + background: #212121; + border-radius: 6px; + padding: 0 24px +} + +@media only screen and (min-width:62.85em) { + .component-product-card-large { + padding: 0 + } +} + +.component-product-card-large h3 { + color: #fff; + margin-bottom: 16px +} + +.component-product-card-large .subhead { + margin-bottom: 8px +} + +.component-product-card-large .column-text-right { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + padding-top: 32px; + padding-bottom: 32px +} + +@media only screen and (min-width:62.85em) { + .component-product-card-large .column-text-right { + min-height: 446px; + -webkit-box-sizing: border-box; + box-sizing: border-box + } +} + +.component-product-card-large__wrapper { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -ms-flex-wrap: wrap; + flex-wrap: wrap; + -ms-flex-item-align: center; + align-self: center; + -webkit-box-pack: left; + -ms-flex-pack: left; + justify-content: left; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -ms-flex-direction: column; + flex-direction: column +} + +.component-product-card-large__image { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; + margin-bottom: 24px +} + +@media only screen and (min-width:62.85em) { + .component-product-card-large__image { + margin-bottom: 0 + } +} + +.component-product-card-large__buttons { + margin-top: 32px; + display: block +} + +@media only screen and (min-width:62.85em) { + .component-product-card-large__buttons { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-orient: horizontal; + -webkit-box-direction: normal; + -ms-flex-direction: row; + flex-direction: row + } +} + +.component-product-card-large__buttons .btn { + display: block; + margin-bottom: 20px +} + +.component-product-card-large__buttons .btn:last-child { + margin-bottom: 0 +} + +@media only screen and (min-width:62.85em) { + .component-product-card-large__buttons .btn { + margin-bottom: auto; + margin-right: 24px + } +} + +.component-product-card-large--bg-white { + background: #fff +} + +.component-product-card-large--bg-light-grey { + background: #ededed +} + +.component-product-card-large--bg-medium-grey { + background: #d8d8d8 +} + +.component-product-card-large--bg-light-grey, +.component-product-card-large--bg-medium-grey, +.component-product-card-large--bg-white { + color: #242424 +} + +.component-product-card-large--bg-light-grey h3, +.component-product-card-large--bg-medium-grey h3, +.component-product-card-large--bg-white h3 { + color: #242424 +} + +.component-product-card-large--bg-light-grey .btn-outline, +.component-product-card-large--bg-medium-grey .btn-outline, +.component-product-card-large--bg-white .btn-outline { + border-color: #2196f3; + color: #2196f3 +} + +.component-product-card-large--bg-light-grey .btn-outline:hover, +.component-product-card-large--bg-medium-grey .btn-outline:hover, +.component-product-card-large--bg-white .btn-outline:hover { + border-color: #212121 +} + +.component-product-card { + border-radius: 6px; + background: #f5f5f5; + padding: 40px 24px 32px; + position: relative; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -ms-flex-direction: column; + flex-direction: column; + -webkit-box-pack: justify; + -ms-flex-pack: justify; + justify-content: space-between +} + +.component-product-card__image { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; + margin: 0 0 24px; + height: 120px +} + +.component-product-card__image img { + max-height: 120px +} + +.component-product-card__label { + position: absolute; + top: 0; + left: 0; + background-color: #e0f436; + padding: 8px; + z-index: 2; + font-weight: 700 +} + +.component-product-card__title { + font-size: 1.25rem; + line-height: 2rem; + font-weight: 500; + margin: 0 0 8px +} + +.component-product-card__text { + font-size: .875rem; + line-height: 1.25rem; + margin-bottom: 48px +} + +.component-product-card__readmore { + font-size: .75rem; + line-height: 2.5rem +} + +.component-product-card__actions { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -ms-flex-wrap: wrap; + flex-wrap: wrap +} + +.component-product-card__link { + font-size: .75rem; + line-height: 2.5rem; + margin-bottom: 8px +} + +.component-product-card .btn { + margin-right: 24px +} + +.component-select { + min-width: 200px; + position: relative; + margin-bottom: 16px +} + +.component-select__current, +.component-select__options { + border-radius: 4px +} + +.component-select__current { + font-size: .75rem; + line-height: 1.5rem; + background-color: rgba(0, 0, 0, .09); + color: rgba(0, 0, 0, .54); + height: 35px; + padding: 5px 30px 5px 10px; + cursor: pointer; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + position: relative; + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden +} + +.component-select__current::after { + font-size: 1.5rem; + display: block; + font-family: Material-Design-Iconic-Font, sans-serif; + content: "\f2f9"; + position: absolute; + top: 6px; + right: 10px; + -webkit-transition: -webkit-transform .25s ease-in-out; + transition: -webkit-transform .25s ease-in-out; + transition: transform .25s ease-in-out; + transition: transform .25s ease-in-out, -webkit-transform .25s ease-in-out +} + +.component-select__current--is-active { + color: #2196f3; + background-color: #e3eff8 +} + +.component-select__current--is-active::after { + -webkit-transform: rotate(180deg); + transform: rotate(180deg) +} + +.component-select__current--is-disabled { + cursor: default +} + +.component-select__current--is-disabled::after { + display: none +} + +.component-select__options-container { + display: none; + position: absolute; + left: 0; + right: 0; + margin: 1px 0 0; + padding: 0; + list-style-type: none; + background: #fff; + -webkit-box-shadow: 0 5px 10px 0 rgba(0, 0, 0, .1), 0 2px 5px 0 rgba(0, 0, 0, .1); + box-shadow: 0 5px 10px 0 rgba(0, 0, 0, .1), 0 2px 5px 0 rgba(0, 0, 0, .1); + border-radius: 4px +} + +.component-select .component-select__current--is-active+.component-select__options-container { + display: block; + z-index: 1 +} + +.component-select__option { + font-size: .75rem; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + padding: 8px 10px; + cursor: pointer; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none +} + +.component-select__option:hover { + background-color: #ededed +} + +.component-select__option::before { + display: none +} + +.component-select__option--is-active { + background-color: #e3eff8 +} + +.component-select__option--is-active:first-child, +.component-select__option:hover:first-child { + border-radius: 4px 4px 0 0 +} + +.component-select__option--is-active:last-child, +.component-select__option:hover:last-child { + border-radius: 0 0 4px 4px +} + +.component-caption { + margin: 10px 0 0 +} + +.component-caption__message { + font-size: .875rem; + line-height: 1.25rem; + font-weight: 400; + font-style: italic; + color: #8a8a8a +} + +.component-large { + font-size: 1.125rem; + line-height: 2rem; + font-weight: 400 +} + +.component-strapline { + font-size: .75rem; + line-height: 1.25rem; + font-weight: 600; + margin-bottom: 8px; + letter-spacing: .5px; + text-transform: uppercase +} + +@media only screen and (min-width:62.85em) { + .component-strapline { + font-size: .875rem; + line-height: 1.25rem; + font-weight: 400 + } +} + +.component-upcoming-events-filter { + padding-top: 16px +} + +@media only screen and (min-width:48em) { + .component-upcoming-events-filter { + padding-top: 72px + } +} + +.component-upcoming-events-filter__title { + margin-bottom: 30px +} + +@media only screen and (min-width:62.85em) { + .component-upcoming-events-filter__dropdown { + display: block !important + } +} + +.component-upcoming-events-filter__minimize i { + display: inline-block; + color: #2196f3; + vertical-align: middle; + margin-left: 2px; + font-size: 1.25rem +} + +@media only screen and (min-width:62.85em) { + .component-upcoming-events-filter__minimize i { + display: none + } +} + +.component-upcoming-events-filter__minimize.flip i { + -webkit-transform: rotate(180deg); + transform: rotate(180deg) +} + +.component-upcoming-events-filter__minimize .subhead { + display: inline-block; + margin-bottom: 0 +} + +@media only screen and (min-width:48em) { + .component-upcoming-events-filter__minimize .subhead { + margin-top: 38px + } +} + +@media only screen and (min-width:62.85em) { + .component-upcoming-events-filter__minimize .subhead { + display: block + } +} + +.component-upcoming-events-filter .js-form-item { + width: 100% +} + +.component-upcoming-events-filter .ms-options-wrap, +.component-upcoming-events-filter .ms-options-wrap * { + -webkit-box-sizing: border-box; + box-sizing: border-box +} + +.component-upcoming-events-filter .ms-options-wrap { + position: relative +} + +.component-upcoming-events-filter .ms-options-wrap.ms-active button { + background-color: #e8f4fd; + color: #2196f3 +} + +.component-upcoming-events-filter .ms-options-wrap.ms-active button::after { + color: #2196f3; + content: "\f2fc" +} + +.component-upcoming-events-filter .ms-options-wrap.ms-active .ms-options { + display: block; + min-height: 165px !important; + height: 165px +} + +.component-upcoming-events-filter .ms-options-wrap button { + position: relative; + width: 100%; + text-align: left; + background-color: #ededed; + border-radius: 6px; + border-style: none; + padding: 16px 20px; + margin-top: 1px; + color: #5a5a5b; + white-space: nowrap; + outline: 0 +} + +.component-upcoming-events-filter .ms-options-wrap button::after { + font-size: 1.5rem; + content: "\f2f9"; + font-family: Material-Design-Iconic-Font, sans-serif; + vertical-align: top; + position: absolute; + right: 10px; + top: 12px; + color: #5a5a5b +} + +.component-upcoming-events-filter .ms-options-wrap button[disabled] { + background-color: #e5e9ed; + color: grey; + opacity: .6 +} + +.component-upcoming-events-filter .ms-options-wrap .ms-options { + position: absolute; + width: 100%; + z-index: 100; + left: 0; + right: 0; + margin: 0 auto; + margin-top: 1px; + margin-bottom: 20px; + background: #fff; + -webkit-box-shadow: 0 5px 10px 0 rgba(0, 0, 0, .1); + box-shadow: 0 5px 10px 0 rgba(0, 0, 0, .1); + overflow: auto; + display: none; + border-radius: 6px +} + +.component-upcoming-events-filter .ms-options-wrap .ms-options.hide-checkbox input[type=checkbox] { + position: absolute !important; + height: 1px; + width: 1px; + overflow: hidden; + clip: rect(1px 1px 1px 1px); + clip: rect(1px, 1px, 1px, 1px) +} + +.component-upcoming-events-filter .ms-options-wrap ul { + position: relative; + margin-bottom: 12px; + padding: 0 +} + +.component-upcoming-events-filter .ms-options-wrap ul label { + color: inherit; + cursor: pointer; + display: block; + position: relative; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + vertical-align: middle +} + +.component-upcoming-events-filter .ms-options-wrap ul label span { + position: relative; + top: 1px +} + +.component-upcoming-events-filter .ms-options-wrap ul label::before { + width: 20px; + height: 20px; + border: 2px solid rgba(0, 0, 0, .5); + margin: 0; + content: ""; + display: inline-block; + -webkit-transition: all .3s ease; + transition: all .3s ease; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + will-change: background-color, border-color; + margin-right: 12px; + border-radius: 3px; + vertical-align: middle; + background-color: #fff +} + +.component-upcoming-events-filter .ms-options-wrap ul label::after { + top: 9px; + left: 8px; + width: 14px; + border: 2px solid #fff; + height: 7px; + content: ""; + position: absolute; + -webkit-transform: scale(0, 0) rotate(-45deg) translateZ(0); + transform: scale(0, 0) rotate(-45deg) translateZ(0); + -webkit-transition: all .3s ease; + transition: all .3s ease; + will-change: transform; + -webkit-transform-origin: bottom left; + transform-origin: bottom left; + border-top-style: none; + border-right-style: none +} + +.component-upcoming-events-filter .ms-options-wrap ul input[type=checkbox] { + display: none +} + +.component-upcoming-events-filter .ms-options-wrap ul input[type=checkbox]:checked+label::before { + background-color: #2196f3; + border-color: #2196f3 +} + +.component-upcoming-events-filter .ms-options-wrap ul input[type=checkbox]:checked+label::after { + -webkit-transform: scale(1, 1) rotate(-45deg) translateZ(0); + transform: scale(1, 1) rotate(-45deg) translateZ(0) +} + +.component-upcoming-events-filter .ms-options-wrap ul li { + list-style-type: none; + padding: 0 0 10px; + margin: 0 +} + +.component-upcoming-events-filter .ms-options-wrap ul li.ms-hidden { + display: none +} + +.component-upcoming-events-filter .ms-options-wrap ul label { + position: relative; + width: 100%; + padding: 4px 4px 4px 20px; + display: -webkit-box; + display: -ms-flexbox; + display: flex +} + +.component-upcoming-events-filter .ms-options-wrap ul label.focused, +.component-upcoming-events-filter .ms-options-wrap ul label:hover { + background-color: #ededed +} + +.component-upcoming-events-filter .ms-options-wrap ul label::after { + left: 28px; + top: 12px; + margin-top: -1px +} + +.component-upcoming-events-filter .ms-options-wrap ul label::before { + -webkit-box-flex: 0; + -ms-flex: none; + flex: none; + margin-top: -2px +} + +.component-upcoming-events-filter .ms-options-wrap ul input[type=checkbox] { + margin: 0 5px 0 0; + position: absolute; + left: 4px; + top: 7px +} + +.component-upcoming-events-filter .views-auto-submit-click { + display: none +} + +.component-upcoming-events-item::after { + display: none; + position: absolute; + content: ""; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: rgba(255, 255, 255, .5) +} + +@media only screen and (min-width:62.85em) { + .component-upcoming-events-item { + margin-bottom: 30px + } +} + +.component-upcoming-events-item ul { + list-style-type: none; + padding-left: 0 +} + +.component-upcoming-events-item ul li { + padding: 32px 0 +} + +.component-upcoming-events-item ul li:not(:last-child) { + border-bottom: 1px solid #d8d8d8 +} + +.component-upcoming-events-item p { + margin-top: 0 +} + +.component-upcoming-events-item__title { + margin-bottom: 10px +} + +.component-upcoming-events-item__title:hover { + cursor: pointer +} + +.component-upcoming-events-item__subheader { + margin-bottom: 3px +} + +@media only screen and (min-width:62.85em) { + .component-upcoming-events-item__address { + margin-bottom: 0 + } +} + +.component-upcoming-events-item__address .address { + margin-bottom: 5px +} + +.component-upcoming-events-item__chevron { + text-align: right +} + +.component-upcoming-events-item__chevron i { + font-size: 1.5rem; + color: #2196f3 +} + +.component-upcoming-events-item__chevron i:hover { + cursor: pointer +} + +.component-upcoming-events-item__when { + margin-bottom: 20px +} + +.component-upcoming-events-item__when .weight-medium { + margin-top: 15px +} + +@media only screen and (min-width:62.85em) { + .component-upcoming-events-item__when .weight-medium { + margin-top: 0 + } +} + +.component-upcoming-events-item__date { + margin-bottom: 5px +} + +.component-upcoming-events-item .calendar i { + font-size: 1rem; + margin-right: 10px; + vertical-align: text-top +} + +.component-upcoming-events-item .address-map-link::before { + font-size: 1rem; + font-family: Material-Design-Iconic-Font, sans-serif; + content: "\f1ab"; + margin-right: 10px; + vertical-align: top +} + +.component-upcoming-events-item__button-wrapper { + margin-top: 25px +} + +.component-upcoming-events-item__button-wrapper a { + margin-bottom: 25px +} + +.component-upcoming-events-item__button-wrapper a:nth-child(1) { + margin-right: 20px +} + +@media only screen and (min-width:62.85em) { + .component-upcoming-events-item__button-wrapper a { + margin-bottom: 0 + } +} + +.component-upcoming-events-loader { + position: fixed; + left: 0; + right: 0; + text-align: center; + width: 100%; + height: 100%; + z-index: 101; + top: 0; + bottom: 0 +} + +.component-upcoming-events-loader::after { + position: absolute; + content: ""; + display: block; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: rgba(255, 255, 255, .5) +} + +@-webkit-keyframes circular-loader { + 0% { + -webkit-transform: rotate(0); + transform: rotate(0) + } + + 100% { + -webkit-transform: rotate(360deg); + transform: rotate(360deg) + } +} + +@keyframes circular-loader { + 0% { + -webkit-transform: rotate(0); + transform: rotate(0) + } + + 100% { + -webkit-transform: rotate(360deg); + transform: rotate(360deg) + } +} + +.component-upcoming-events-loader .circular-loader { + position: absolute; + width: 50px; + height: 50px; + z-index: 1; + top: 50%; + left: 50%; + -webkit-transform: translate(-50%, -50%); + transform: translate(-50%, -50%) +} + +.component-upcoming-events-loader .circular-loader div { + -webkit-box-sizing: border-box; + box-sizing: border-box; + display: block; + position: absolute; + width: 40px; + height: 40px; + margin: 4px; + border: 4px solid #2196f3; + border-radius: 50%; + -webkit-animation: circular-loader 1.2s cubic-bezier(.5, 0, .5, 1) infinite; + animation: circular-loader 1.2s cubic-bezier(.5, 0, .5, 1) infinite; + border-color: #2196f3 transparent transparent transparent +} + +.component-upcoming-events-loader .circular-loader div:nth-child(1) { + -webkit-animation-delay: -.45s; + animation-delay: -.45s +} + +.component-upcoming-events-loader .circular-loader div:nth-child(2) { + -webkit-animation-delay: -.3s; + animation-delay: -.3s +} + +.component-upcoming-events-loader .circular-loader div:nth-child(3) { + -webkit-animation-delay: -.15s; + animation-delay: -.15s +} + +.component-announcement { + font-size: .875rem; + background-color: #2196f3; + color: #fff; + padding: 24px 0 +} + +@media only screen and (min-width:62.85em) { + .component-announcement { + padding: 12px 0 + } +} + +.component-announcement a { + margin-left: 8px; + color: #fff; + text-decoration: underline +} + +.component-announcement a:hover { + text-decoration: underline +} + +.component-callout { + padding: 48px 0 +} + +@media only screen and (min-width:48em) { + .component-callout { + padding: 56px 0 + } +} + +.component-callout__inner { + position: relative; + padding: 60px 40px; + border-radius: 6px; + overflow: hidden; + color: #fff; + background-repeat: no-repeat; + background-size: cover; + background-position: center; + background-image: url(/themes/unity/build/css/../../images/default/pagebuilder-callout.jpg) +} + +@media only screen and (min-width:48em) { + .component-callout__inner { + padding: 120px 0 + } +} + +.component-callout__description, +.component-callout__title { + color: #fff +} + +.component-callout--overlay { + -webkit-box-shadow: rgba(0, 0, 0, .5) 0 0 0 1000px inset; + box-shadow: rgba(0, 0, 0, .5) 0 0 0 1000px inset +} + +.component-callout__buttons a:nth-child(1) { + display: block; + margin-bottom: 20px +} + +@media only screen and (min-width:48em) { + .component-callout__buttons a:nth-child(1) { + margin-right: 20px; + margin-bottom: 0; + display: inline-block + } +} + +.component-callout__buttons a:nth-child(2) { + display: block +} + +@media only screen and (min-width:48em) { + .component-callout__buttons a:nth-child(2) { + display: inline-block + } +} + +@media print { + .component-callout { + background: #fff; + -webkit-box-shadow: none; + box-shadow: none + } + + .component-callout .buttons { + display: none + } +} + +.pattern-faq { + padding-top: 80px; + padding-bottom: 80px +} + +.pattern-faq__title { + margin-bottom: 40px; + letter-spacing: 0 +} + +.pattern-faq__subtitle { + font-size: 1.5rem; + line-height: 2rem; + font-weight: 500; + margin-bottom: 25px +} + +.component-feature-grid { + padding: 120px 0 200px; + background-color: #f5f5f5; + background-size: 250%; + background-repeat: no-repeat; + background-position: bottom right +} + +@media only screen and (min-width:48em) { + .component-feature-grid { + padding: 64px 0 312px; + background-size: 75% + } +} + +.component-feature-grid__benefit { + margin-bottom: 32px +} + +.component-feature-grid__benefit:last-of-type { + margin-bottom: 0 +} + +.component-feature-grid .component-infoline { + margin-top: 40px +} + +@media only screen and (min-width:48em) { + .component-feature-grid { + padding: 120px 0 200px; + background-color: #f5f5f5; + background-size: auto; + background-repeat: no-repeat; + background-position: bottom right + } + + .component-feature-grid__benefit, + .component-feature-grid__benefit:last-of-type { + margin-bottom: 48px + } + + .component-feature-grid .component-infoline { + margin-top: 0 + } +} + +.component-feature-grid__tagline { + margin: 24px 0 48px +} + +.component-feature-grid__headline { + margin-bottom: 4px +} + +.component-feature-grid__subheadline { + margin-bottom: 16px +} + +.component-feature-grid__link { + font-weight: 500 +} + +.component-feature-grid--dark { + background-color: #212121 +} + +.component-feature-grid--dark .component-infoline__text, +.component-feature-grid--dark .large, +.component-feature-grid--dark .small, +.component-feature-grid--dark h2, +.component-feature-grid--dark h5 { + color: #f2f2f2 +} + +@media print { + .component-feature-grid { + background: #fff + } + + .component-feature-grid__title { + color: #000 + } +} + +.component-featured-tiles { + padding: 40px 0 +} + +@media only screen and (min-width:62.85em) { + .component-featured-tiles { + padding: 56px 0 + } +} + +.component-featured-tiles__title { + padding-top: 20px +} + +@media only screen and (min-width:62.85em) { + .component-featured-tiles__title { + padding-top: 56px + } +} + +.component-featured-tiles__tile-wrapper { + padding-bottom: 30px +} + +.component-featured-tiles__tile-container { + position: relative +} + +.component-featured-tiles__tile-inner { + border-radius: 6px; + padding: 20px; + background-repeat: no-repeat; + background-size: cover; + background-position: center; + overflow: hidden; + min-height: initial; + position: relative +} + +@media only screen and (min-width:62.85em) { + .component-featured-tiles__tile-inner { + min-height: 315px; + padding: 40px 40px 0 + } +} + +.component-featured-tiles__tile-inner h2, +.component-featured-tiles__tile-inner p { + color: #fff +} + +.component-featured-tiles__tile-inner h2 { + font-weight: 800 +} + +.component-featured-tiles__tile-inner p { + margin-top: 5px +} + +@media only screen and (min-width:62.85em) { + .component-featured-tiles__tile-inner p { + padding-bottom: 100px + } +} + +.component-featured-tiles__button-wrapper { + position: relative; + bottom: initial +} + +@media only screen and (min-width:62.85em) { + .component-featured-tiles__button-wrapper { + position: absolute; + bottom: 35px + } +} + +.component-featured-tiles__button-wrapper a { + margin-top: 10px +} + +@media only screen and (min-width:62.85em) { + .component-featured-tiles__button-wrapper a { + margin-top: 25px + } +} + +.component-featured-tiles__button-wrapper a:nth-child(1) { + margin-right: 20px +} + +.component-fluid-tabs { + margin-top: 30px +} + +.component-fluid-tabs .container { + padding: 0 +} + +.component-fluid-tabs__header { + border-bottom: 2px solid #2196f3; + margin-bottom: 55px +} + +.component-fluid-tabs__tab-group { + padding: 0; + margin: 0 15px; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-align: end; + -ms-flex-align: end; + align-items: flex-end; + position: relative +} + +@media only screen and (min-width:48em) { + .component-fluid-tabs__tab-group { + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; + margin: 0 + } +} + +.component-fluid-tabs__content { + display: none +} + +.component-fluid-tabs__content--is-active { + display: block +} + +.component-event-hero { + padding-top: 250px +} + +.component-event-hero__event-logo { + margin-top: 100px +} + +.component-event-hero__event-logo img { + max-width: 80vw; + margin-bottom: 35px +} + +@media only screen and (min-width:48em) { + .component-event-hero__event-logo img { + max-width: 480px + } +} + +.component-event-hero__event-info { + font-size: 1.5rem; + line-height: 1.75rem; + font-weight: 500; + margin: 24px 0 30px +} + +.component-event-hero__partnership-logo { + margin-top: 100px; + text-align: center +} + +.component-hero-pricing { + padding-top: 0; + padding-bottom: 0 +} + +.component-hero-pricing .component-hero--has-no-subhead { + margin-top: 0 +} + +.component-hero-pricing .component-hero__text { + margin-bottom: 24px +} + +.component-hero-pricing .component-hero__buttons { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + margin-top: 16px +} + +@media only screen and (min-width:48em) { + .component-hero-pricing .component-hero__buttons { + margin-top: 24px + } +} + +.component-hero-pricing__eligibility { + color: #c2c2c2 +} + +@media only screen and (min-width:48em) { + .component-hero-pricing__price-row { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center + } +} + +.component-hero-pricing__price { + font-size: 1.75rem; + line-height: 1.25rem; + margin: 0 16px 16px 0; + vertical-align: middle; + display: block +} + +@media only screen and (min-width:48em) { + .component-hero-pricing__price { + display: inline-block; + margin-bottom: 0 + } +} + +.component-hero-pricing .component-select { + display: inline-block; + min-width: 200px; + background-color: rgba(155, 155, 155, .2); + margin-bottom: 0 +} + +.component-hero-pricing .component-select__current { + color: #c2c2c2; + border-radius: 3px +} + +.component-hero-pricing .component-select__option { + background-color: #000 +} + +.component-hero-pricing .component-select__option:hover { + background-color: #212121 +} + +.component-hero-image-right-video .video-embed-field-responsive-video { + position: absolute; + top: 0; + bottom: 0; + left: 0; + width: 100%; + height: 100%; + border: 0 +} + +.component-hero-image-right-video .column-video-right .caption { + margin-top: 5px +} + +.component-hero-image-right-video .hero-video-right { + max-width: 420px; + max-height: 300px; + overflow: hidden; + position: relative; + padding-top: 20px +} + +@media only screen and (min-width:62.85em) { + .component-hero-image-right-video .hero-video-right { + padding-top: 0 + } +} + +.component-hero { + padding-top: 95px; + padding-bottom: 60px; + position: relative; + text-align: left; + color: #fff; + background: #000 50% 50% no-repeat; + background-size: cover; + overflow: hidden +} + +@media only screen and (min-width:48em) { + .component-hero { + padding-top: 122px; + padding-bottom: 144px + } +} + +.component-hero--slim-padding { + padding-bottom: 35px +} + +@media only screen and (min-width:48em) { + .component-hero--slim-padding { + padding-top: 138px + } +} + +.component-hero .container { + position: relative; + z-index: 3 +} + +.component-hero__logo { + max-width: 210px; + max-height: initial; + margin: 25px 0 +} + +.component-hero__logo img { + max-height: 150px; + width: auto +} + +@media only screen and (min-width:62.85em) { + .component-hero__logo { + max-width: 300px + } + + .component-hero__logo img { + max-height: 125px + } +} + +@media only screen and (min-width:48em) { + .component-hero__content--has-no-subhead { + margin-top: 131px + } +} + +@media only screen and (min-width:48em) { + .component-hero__content--has-subhead { + margin-top: 112px + } +} + +.component-hero__content--slim-padding { + padding-top: 16px; + padding-bottom: 30px +} + +.component-hero__buttons a:nth-child(1), +.component-hero__buttons span:nth-child(1) { + display: block; + margin-bottom: 20px +} + +@media only screen and (min-width:48em) { + + .component-hero__buttons a:nth-child(1), + .component-hero__buttons span:nth-child(1) { + margin-right: 20px; + margin-bottom: 0; + display: inline-block + } +} + +.component-hero__buttons a:nth-child(2), +.component-hero__buttons span:nth-child(2) { + display: block +} + +@media only screen and (min-width:48em) { + + .component-hero__buttons a:nth-child(2), + .component-hero__buttons span:nth-child(2) { + display: inline-block + } +} + +.component-hero__buttons--white-background a:nth-child(2), +.component-hero__buttons--white-background span:nth-child(2) { + color: #2196f3; + border-color: #2196f3 +} + +.component-hero--overlay { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + z-index: 2; + background-color: rgba(0, 0, 0, .3) +} + +.component-hero .controls-wrapper { + display: none !important +} + +.component-hero p { + color: #fff; + margin: 0 0 10px +} + +.component-hero__subhead { + color: #fff; + margin-bottom: 8px +} + +.component-hero__subhead--white-background { + color: #000 +} + +.component-hero__title { + color: #fff; + margin-bottom: 16px; + -webkit-hyphens: auto; + -ms-hyphens: auto; + hyphens: auto +} + +.component-hero__title--white-background { + color: #000 +} + +.component-hero__text--white-background p { + color: #000 +} + +.component-hero__video-background .video { + pointer-events: none; + width: 100%; + height: 100%; + position: absolute; + overflow: hidden; + z-index: 0; + top: 0 +} + +.component-hero__video-background .video img { + top: 0; + position: absolute; + -webkit-transform: translate(-17%); + transform: translate(-17%); + display: none !important; + max-width: 155% !important +} + +@media only screen and (min-width:48em) { + .component-hero__video-background .video img { + -webkit-transform: initial; + transform: initial; + max-width: 100% !important + } +} + +.component-hero__video-background .video.hero-video-wrapper { + -webkit-transform: translate(-20%); + transform: translate(-20%); + width: 150% +} + +@media only screen and (min-width:78.7em) { + .component-hero__video-background .video.hero-video-wrapper { + -webkit-transform: initial; + transform: initial; + width: 100% + } +} + +.component-hero__video-background .video .vidyard-player-embed { + display: none +} + +@media only screen and (min-width:48em) { + .component-hero__video-background .video .vidyard-player-embed { + display: initial + } +} + +.component-hero__video-background .video .vidyard-player-container { + opacity: 0 +} + +.component-hero__video-background .video .fade { + opacity: 1; + -webkit-transition: opacity .3s ease-in-out; + transition: opacity .3s ease-in-out +} + +.component-hero__video-background .video iframe { + border: 0; + height: 100vw; + position: absolute; + -webkit-transform: translate(-50%, -50%); + transform: translate(-50%, -50%); + width: 100%; + display: none !important; + left: 50% !important; + top: 50% !important +} + +@media only screen and (min-width:62.85em) { + .component-hero__video-background .video iframe { + width: 150%; + display: block !important + } +} + +@media only screen and (min-width:78.7em) { + .component-hero__video-background .video iframe { + width: 130% + } +} + +.component-hero.component-hero-image-right-video .video-embed-field-responsive-video { + position: absolute; + top: 0; + bottom: 0; + left: 0; + width: 100%; + height: 100%; + border: 0 +} + +.component-hero.component-hero-image-right-video .column-video-right .caption { + margin-top: 5px +} + +.component-hero.component-hero-image-right-video .hero-video-right { + max-width: 420px; + max-height: 300px; + overflow: hidden; + position: relative +} + +.component-hero.component-hero-image-right-video .hero-video-right .mdi { + position: absolute; + color: #fff; + font-size: 3.5em; + top: 50%; + left: 50%; + -webkit-transform: translate(-50%, -50%); + transform: translate(-50%, -50%) +} + +@media print { + .component-hero { + padding-bottom: 2cm; + color: #000 !important + } + + .component-hero .hero-title { + padding-top: 2cm + } + + .component-hero--buttons { + display: none + } +} + +.component-logo-garden { + background: #212121; + padding: 80px 0 +} + +.component-logo-garden h2 { + color: #fff +} + +.component-logo-garden__logos { + margin-top: 12px; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: justify; + -ms-flex-pack: justify; + justify-content: space-between; + -webkit-box-orient: horizontal; + -webkit-box-direction: normal; + -ms-flex-flow: row wrap; + flex-flow: row wrap +} + +@media only screen and (max-width:48em) { + .component-logo-garden__logos { + -webkit-box-pack: space-evenly; + -ms-flex-pack: space-evenly; + justify-content: space-evenly + } +} + +.component-logo-garden__logo-container { + -webkit-box-flex: 1; + -ms-flex: 1 1 96px; + flex: 1 1 96px; + max-height: 48px; + height: auto; + max-width: 96px; + width: auto; + margin: 36px 96px 0 0; + text-align: center +} + +@media only screen and (max-width:48em) { + .component-logo-garden__logo-container { + margin: 36px 42px 0 0 + } +} + +@media only screen and (min-width:78.7em) { + .component-logo-garden__logo-container { + -webkit-box-flex: 1; + -ms-flex: 1 1 112px; + flex: 1 1 112px; + max-width: 112px; + margin: 36px 112px 0 0 + } +} + +@media only screen and (min-width:62.85em) { + .component-logo-garden__logo-container:nth-of-type(5n) { + margin-right: 0; + text-align: right + } +} + +@media only screen and (min-width:62.85em) { + .component-logo-garden__logo-container:nth-of-type(5n+1) { + text-align: left + } +} + +.component-logo-garden__logo { + max-height: 48px; + max-width: 88px +} + +@media print { + .component-logo-garden h2 { + color: #000 + } + + .component-logo-garden__logo { + -webkit-filter: invert(1); + filter: invert(1) + } +} + +.component-onpage { + display: none; + height: 72px; + width: 100%; + padding: 16px 0 +} + +@media only screen and (min-width:78.7em) { + .component-onpage { + display: block + } +} + +.component-onpage--sticky { + position: fixed; + top: 0; + z-index: 9999 +} + +.component-onpage--dark { + background: #000; + color: #fff +} + +.component-onpage--dark .component-onpage__link { + color: #fff +} + +.component-onpage--dark .component-onpage__link:hover { + color: #2196f3 +} + +.component-onpage--light { + background: #ededed; + color: #000 +} + +.component-onpage--light .component-onpage__link { + color: #000 +} + +.component-onpage--light .component-onpage__link:hover { + color: #2196f3 +} + +.component-onpage__action { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: end; + -ms-flex-pack: end; + justify-content: flex-end +} + +.component-onpage__link { + height: 100%; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + padding: 10px 0; + letter-spacing: .5px +} + +.component-onpage ul { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + padding: 0; + margin: 0 +} + +@media only screen and (min-width:48em) { + .component-onpage ul { + display: block + } +} + +.component-onpage li { + margin-right: 40px; + display: inline-block; + height: 40px; + padding: 0 +} + +.component-onpage li:last-child { + margin-right: 0 +} + +.component-promo-banner { + position: relative; + padding: 50px 0 40px; + color: #fff; + background-color: #723bb6; + background-size: cover; + background-position: center +} + +.component-promo-banner.survey { + background-color: #ededed; + color: #383838 +} + +.component-promo-banner.survey .component-promo-banner__btn-close { + background-image: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPCEtLSBHZW5lcmF0b3I6IEFkb2JlIElsbHVzdHJhdG9yIDI0LjAuMywgU1ZHIEV4cG9ydCBQbHVnLUluIC4gU1ZHIFZlcnNpb246IDYuMDAgQnVpbGQgMCkgIC0tPgo8c3ZnIHZlcnNpb249IjEuMSIgaWQ9IkxheWVyXzEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IgoJIHZpZXdCb3g9IjAgMCAyNCAyNCIgc3R5bGU9ImVuYWJsZS1iYWNrZ3JvdW5kOm5ldyAwIDAgMjQgMjQ7IiB4bWw6c3BhY2U9InByZXNlcnZlIj4KPHN0eWxlIHR5cGU9InRleHQvY3NzIj4KCS5zdDB7ZmlsbDojMzgzODM4O30KCS5zdDF7ZmlsbDpub25lO30KPC9zdHlsZT4KPHBhdGggY2xhc3M9InN0MCIgZD0iTTE5LDYuNEwxNy42LDVMMTIsMTAuNkw2LjQsNUw1LDYuNGw1LjYsNS42TDUsMTcuNkw2LjQsMTlsNS42LTUuNmw1LjYsNS42bDEuNC0xLjRMMTMuNCwxMkwxOSw2LjR6Ii8+CjxwYXRoIGNsYXNzPSJzdDEiIGQ9Ik0wLDBoMjR2MjRIMFYweiIvPgo8L3N2Zz4K) +} + +.component-promo-banner.survey .component-promo-banner__link:hover { + background-color: #fff; + border-color: #2196f3; + color: #2196f3 +} + +.component-promo-banner.survey .component-promo-banner__body { + font-size: 1rem; + line-height: 2rem; + font-weight: 400 +} + +@media only screen and (min-width:48em) { + .component-promo-banner.survey { + padding: 1rem + } +} + +.component-promo-banner.promotion { + background-color: #723bb6 +} + +@media only screen and (min-width:48em) { + .component-promo-banner.promotion { + padding: 23px 0 + } +} + +.component-promo-banner.promotion::before { + content: ""; + position: absolute; + left: 0; + top: 0; + width: 100%; + height: 100%; + background: #000; + opacity: .3 +} + +@media only screen and (min-width:62.85em) { + .component-promo-banner.promotion::before { + display: none + } +} + +.component-promo-banner.hide { + display: none +} + +.component-promo-banner__text { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + position: relative; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -ms-flex-direction: column; + flex-direction: column; + -webkit-box-align: start; + -ms-flex-align: start; + align-items: flex-start +} + +@media only screen and (min-width:62.85em) { + .component-promo-banner__text { + -webkit-box-orient: horizontal; + -webkit-box-direction: normal; + -ms-flex-direction: row; + flex-direction: row; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center + } +} + +.component-promo-banner__title { + font-size: 1.875rem; + line-height: 2.375rem; + font-weight: 900; + color: #fff +} + +.component-promo-banner__separator { + display: none +} + +@media only screen and (min-width:62.85em) { + .component-promo-banner__separator { + display: block; + width: 2px; + height: 48px; + margin: 0 40px; + background-color: #fff + } +} + +.component-promo-banner__body { + display: none; + font-size: 1.125rem; + line-height: 2rem; + font-weight: 600 +} + +@media only screen and (min-width:62.85em) { + .component-promo-banner__body { + display: block + } +} + +.component-promo-banner__body-mobile { + display: block; + position: relative; + font-size: 1.125rem; + line-height: 2rem; + font-weight: 600 +} + +@media only screen and (min-width:62.85em) { + .component-promo-banner__body-mobile { + display: none + } +} + +.component-promo-banner__buttons { + margin-top: 20px; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: end; + -ms-flex-pack: end; + justify-content: flex-end; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center +} + +@media only screen and (min-width:62.85em) { + .component-promo-banner__buttons { + margin-top: 0; + position: relative + } +} + +.component-promo-banner__link { + width: 100%; + -webkit-transition: all .4s ease; + transition: all .4s ease; + position: relative +} + +@media only screen and (min-width:62.85em) { + .component-promo-banner__link { + width: auto + } +} + +.component-promo-banner__link:hover { + background-color: #fff; + border-color: #fff; + color: #2196f3 +} + +.component-promo-banner__btn-close { + position: absolute; + top: 20px; + right: 20px; + width: 20px; + height: 20px; + background-image: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPCEtLSBHZW5lcmF0b3I6IEFkb2JlIElsbHVzdHJhdG9yIDI0LjAuMywgU1ZHIEV4cG9ydCBQbHVnLUluIC4gU1ZHIFZlcnNpb246IDYuMDAgQnVpbGQgMCkgIC0tPgo8c3ZnIHZlcnNpb249IjEuMSIgaWQ9IkxheWVyXzEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IgoJIHZpZXdCb3g9IjAgMCAyNCAyNCIgc3R5bGU9ImVuYWJsZS1iYWNrZ3JvdW5kOm5ldyAwIDAgMjQgMjQ7IiB4bWw6c3BhY2U9InByZXNlcnZlIj4KPHN0eWxlIHR5cGU9InRleHQvY3NzIj4KCS5zdDB7ZmlsbDojRkZGRkZGO30KCS5zdDF7ZmlsbDpub25lO30KPC9zdHlsZT4KPHBhdGggY2xhc3M9InN0MCIgZD0iTTE5LDYuNEwxNy42LDVMMTIsMTAuNkw2LjQsNUw1LDYuNGw1LjYsNS42TDUsMTcuNkw2LjQsMTlsNS42LTUuNmw1LjYsNS42bDEuNC0xLjRMMTMuNCwxMkwxOSw2LjR6Ii8+CjxwYXRoIGNsYXNzPSJzdDEiIGQ9Ik0wLDBoMjR2MjRIMFYweiIvPgo8L3N2Zz4K); + background-position: center; + cursor: pointer +} + +@media only screen and (min-width:62.85em) { + .component-promo-banner__btn-close { + position: relative; + top: auto; + right: auto; + display: block; + margin-left: 24px + } +} + +.component-promo-banner .row { + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center +} + +.component-segment { + padding: 60px 0; + background-color: #000 +} + +@media only screen and (min-width:48em) { + .component-segment { + padding: 120px 0 + } +} + +.component-segment__title { + margin-bottom: 8px +} + +.component-segment__image-background { + color: #fff; + background-repeat: no-repeat; + background-size: cover; + background-position: center +} + +.component-segment--overlay { + -webkit-box-shadow: inset 0 0 0 1000px rgba(0, 0, 0, .5); + box-shadow: inset 0 0 0 1000px rgba(0, 0, 0, .5) +} + +@media print { + .component-segment { + background: #fff; + -webkit-box-shadow: none; + box-shadow: none + } +} + +.sections .section:first-of-type.section--breadcrumbs { + padding-top: 83px +} + +.section--breadcrumbs { + background: #212121; + color: #ededed; + padding: .75rem 0; + font-size: 14px; + line-height: 20px; + white-space: nowrap +} + +.unity-brand-header--light .section--breadcrumbs { + background: #f5f5f5; + color: #212121 +} + +.section--breadcrumbs a { + color: #ededed; + text-decoration: none +} + +.section--breadcrumbs a:hover { + text-decoration: underline +} + +.unity-brand-header--light .section--breadcrumbs a { + color: #212121 +} + +.breadcrumbs { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + justify-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center +} + +.breadcrumbs .mobile__parent-breadcrumb { + color: #ededed; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center +} + +@media only screen and (min-width:48em) { + .breadcrumbs .mobile__parent-breadcrumb { + display: none + } +} + +.breadcrumbs .mobile__parent-breadcrumb a { + display: inline-block; + overflow: hidden; + text-overflow: ellipsis; + max-width: 370px +} + +.breadcrumbs .mobile__parent-breadcrumb .mdi-chevron-left { + margin: 0 .625rem; + font-size: 1.25rem; + color: #ededed +} + +.breadcrumbs .breadcrumb__list { + max-width: 705px; + padding: 0; + margin: 0; + list-style-type: none; + display: none +} + +@media only screen and (min-width:48em) { + .breadcrumbs .breadcrumb__list { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + position: relative + } +} + +.breadcrumbs .breadcrumb__list .breadcrumb__item { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -ms-flex-wrap: nowrap; + flex-wrap: nowrap; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center +} + +.breadcrumbs .breadcrumb__list .breadcrumb__item .mdi-chevron-right { + margin: 0 .625rem; + font-size: 1.25rem; + color: #ededed +} + +.breadcrumbs .breadcrumb__list .breadcrumb__item.last-item { + font-style: italic; + display: inline-block; + overflow: hidden; + text-overflow: ellipsis; + min-width: 150px +} + +.breadcrumbs .mdi-more-horiz { + font-size: 1.5rem; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + width: 30px; + height: 30px; + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; + border-radius: 2px; + position: relative; + cursor: pointer +} + +.breadcrumbs .mdi-more-horiz:hover { + background-color: #fff +} + +.unity-brand-header--light .breadcrumbs .mdi-more-horiz:hover { + background-color: #ededed +} + +.unity-brand-header--light .breadcrumbs .mdi-more-horiz { + color: #212121 +} + +.breadcrumbs .mdi-more-horiz:hover~.breadcrumb__dropdown-wrapper { + display: block +} + +.breadcrumb__dropdown { + position: relative; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center +} + +.breadcrumb__dropdown .mdi-chevron-right { + padding: 0 .625rem; + font-size: 1.25rem; + color: #ededed +} + +.breadcrumb__dropdown-wrapper { + display: none; + position: absolute; + padding-top: 5px; + left: 0; + top: 30px; + z-index: 1 +} + +.breadcrumb__dropdown-wrapper:hover { + display: block +} + +.breadcrumb__dropdown-wrapper .breadcrumb__dropdown-list { + list-style: none; + padding: 8px 0; + font-size: 14px; + line-height: 20px; + border-radius: 2px; + background-color: #000; + width: 300px +} + +.unity-brand-header--light .breadcrumb__dropdown-wrapper .breadcrumb__dropdown-list { + background-color: #000; + -webkit-box-shadow: 0 0 5px #0000000d; + box-shadow: 0 0 5px #0000000d; + color: #ededed +} + +.breadcrumb__dropdown-wrapper .breadcrumb__dropdown-list .breadcrumb__link-dropdown a { + color: #ededed; + white-space: normal; + background-color: #000; + display: inline-block; + padding: 8px 32px; + width: 100%; + font-size: 14px +} + +.breadcrumb__dropdown-wrapper .breadcrumb__dropdown-list .breadcrumb__link-dropdown a:hover { + background-color: #212121; + text-decoration: none +} + +.unity-brand-header--light .breadcrumb__dropdown-wrapper .breadcrumb__dropdown-list .breadcrumb__link-dropdown a:hover { + background-color: #ededed +} + +.unity-brand-header--light .breadcrumb__dropdown-wrapper .breadcrumb__dropdown-list .breadcrumb__link-dropdown a { + background-color: #fff; + color: #212121 +} + +.features-grid a { + color: #000 +} + +.features-grid a:hover { + color: #2196f3; + text-decoration: underline +} + +.features-grid .feature-category h3 { + margin-bottom: 1rem +} + +.features-grid .feature-category h3 a { + color: #000; + font-weight: 600; + font-size: 1.5rem; + line-height: 2rem +} + +.features-grid .feature-category ul { + list-style: none; + padding-left: 0 +} + +.features-grid .feature-category ul li { + padding-bottom: .5rem +} + +.features-grid .feature-category li, +.features-grid .feature-category li a { + font-style: normal; + font-weight: 400; + font-size: 18px; + line-height: 32px +} + +.featured-product-list__title--has-button { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: justify; + -ms-flex-pack: justify; + justify-content: space-between; + -webkit-box-align: start; + -ms-flex-align: start; + align-items: flex-start +} + +.featured-product-list__title-button { + line-height: 1.5; + -webkit-box-flex: 0; + -ms-flex: 0 0 auto; + flex: 0 0 auto +} + +.cookies-dialog { + background-color: #000000; + color: #ffffff; + width: 100%; + position: fixed; + bottom: 0; + z-index: 100; + padding: 15px 0 +} + +@media only screen and (min-width:62.85em) { + .cookies-dialog { + padding: 10px 0; + } +} + +.cookies-dialog__wrapper { + display: block; +} + +@media only screen and (min-width:62.85em) { + .cookies-dialog__wrapper { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: space-evenly; + -ms-flex-pack: space-evenly; + justify-content: space-evenly + } +} + +.cookies-dialog__got-it { + width: 100%; +} + +@media only screen and (min-width:62.85em) { + .cookies-dialog__got-it { + width: auto; + } +} diff --git a/v0.10.x/_static/vendor/news.css b/v0.10.x/_static/vendor/news.css new file mode 100644 index 000000000..4f4afea00 --- /dev/null +++ b/v0.10.x/_static/vendor/news.css @@ -0,0 +1,48 @@ +.news-container { + display: flex; + justify-content: center; + align-items: center; + width: 100vw; + min-height: 45px; + background-color: var(--colorPrimaryDark); + color: var(--colorSecondaryLight); + white-space: nowrap; +} + +.news-container a { + color: var(--colorSecondaryLight); +} + +.news-container a:hover { + color: var(--colorSecondaryLight); +} + +.news-title { + display: flex; + letter-spacing: 1.5px; + font-size: 27px; + font-weight: bold; + margin: 10px; + margin-right: 20px; +} + +@media only screen and (max-width: 1300px) { + .news-container { + white-space: unset; + } + + .news-title { + text-align: center; + } +} + +@media only screen and (max-width: 1090px) { + .news-container { + flex-direction: column; + padding: 30px; + } + + .news-date { + text-align: center; + } +} diff --git a/v0.10.x/_static/vendor/posts.css b/v0.10.x/_static/vendor/posts.css new file mode 100644 index 000000000..80e1952a4 --- /dev/null +++ b/v0.10.x/_static/vendor/posts.css @@ -0,0 +1,29 @@ +.post-list article { + padding-top: 1.5rem; + padding-bottom: 1.5rem; +} + +.post-list .post-title { + font-size: 1.25rem; + text-transform: uppercase; + letter-spacing: 1.5px; + font-weight: bold; + padding-bottom: 0.5rem; +} + +.post-author { + color: var(--colorSecondaryDark); + display: inline; +} + +.post-author:not(:first-child):before { + content: ", "; +} + +.post-list .post-date { + color: var(--colorSecondaryDark); +} + +.post-list .post-summary { + padding-top: 0.5rem; +} diff --git a/v0.10.x/_static/vendor/sphinx-footer.css b/v0.10.x/_static/vendor/sphinx-footer.css new file mode 100644 index 000000000..d7f552802 --- /dev/null +++ b/v0.10.x/_static/vendor/sphinx-footer.css @@ -0,0 +1,756 @@ +.footer-h5 { + padding-left: 10px; + border-left: 3px solid white; + color: white; +} + +#footer-columns ul { + padding-left: 0px; + list-style-type: none; +} + +.footer-link { + font-size: smaller; +} + + +/* Now with pyData 0.10.1 version the class name on footer changed to .bd-footer */ +.bd-footer { + background-color: rgb(153, 0, 0); + padding: 3rem 1.5rem 6rem; +} + +.footer { + background-color: rgb(153, 0, 0); + padding: 3rem 1.5rem 6rem; +} + +.footer-column { + display: block; + flex-basis: 0; + flex-grow: 1; + flex-shrink: 1; + padding: 0.75rem; } + .footer-columns.is-mobile > .footer-column.is-narrow { + flex: none; } + .footer-columns.is-mobile > .footer-column.is-full { + flex: none; + width: 100%; } + .footer-columns.is-mobile > .footer-column.is-three-quarters { + flex: none; + width: 75%; } + .footer-columns.is-mobile > .footer-column.is-two-thirds { + flex: none; + width: 66.6666%; } + .footer-columns.is-mobile > .footer-column.is-half { + flex: none; + width: 50%; } + .footer-columns.is-mobile > .footer-column.is-one-third { + flex: none; + width: 33.3333%; } + .footer-columns.is-mobile > .footer-column.is-one-quarter { + flex: none; + width: 25%; } + .footer-columns.is-mobile > .footer-column.is-one-fifth { + flex: none; + width: 20%; } + .footer-columns.is-mobile > .footer-column.is-two-fifths { + flex: none; + width: 40%; } + .footer-columns.is-mobile > .footer-column.is-three-fifths { + flex: none; + width: 60%; } + .footer-columns.is-mobile > .footer-column.is-four-fifths { + flex: none; + width: 80%; } + .footer-columns.is-mobile > .footer-column.is-offset-three-quarters { + margin-left: 75%; } + .footer-columns.is-mobile > .footer-column.is-offset-two-thirds { + margin-left: 66.6666%; } + .footer-columns.is-mobile > .footer-column.is-offset-half { + margin-left: 50%; } + .footer-columns.is-mobile > .footer-column.is-offset-one-third { + margin-left: 33.3333%; } + .footer-columns.is-mobile > .footer-column.is-offset-one-quarter { + margin-left: 25%; } + .footer-columns.is-mobile > .footer-column.is-offset-one-fifth { + margin-left: 20%; } + .footer-columns.is-mobile > .footer-column.is-offset-two-fifths { + margin-left: 40%; } + .footer-columns.is-mobile > .footer-column.is-offset-three-fifths { + margin-left: 60%; } + .footer-columns.is-mobile > .footer-column.is-offset-four-fifths { + margin-left: 80%; } + .footer-columns.is-mobile > .footer-column.is-1 { + flex: none; + width: 8.33333333%; } + .footer-columns.is-mobile > .footer-column.is-offset-1 { + margin-left: 8.33333333%; } + .footer-columns.is-mobile > .footer-column.is-2 { + flex: none; + width: 16.66666667%; } + .footer-columns.is-mobile > .footer-column.is-offset-2 { + margin-left: 16.66666667%; } + .footer-columns.is-mobile > .footer-column.is-3 { + flex: none; + width: 25%; } + .footer-columns.is-mobile > .footer-column.is-offset-3 { + margin-left: 25%; } + .footer-columns.is-mobile > .footer-column.is-4 { + flex: none; + width: 33.33333333%; } + .footer-columns.is-mobile > .footer-column.is-offset-4 { + margin-left: 33.33333333%; } + .footer-columns.is-mobile > .footer-column.is-5 { + flex: none; + width: 41.66666667%; } + .footer-columns.is-mobile > .footer-column.is-offset-5 { + margin-left: 41.66666667%; } + .footer-columns.is-mobile > .footer-column.is-6 { + flex: none; + width: 50%; } + .footer-columns.is-mobile > .footer-column.is-offset-6 { + margin-left: 50%; } + .footer-columns.is-mobile > .footer-column.is-7 { + flex: none; + width: 58.33333333%; } + .footer-columns.is-mobile > .footer-column.is-offset-7 { + margin-left: 58.33333333%; } + .footer-columns.is-mobile > .footer-column.is-8 { + flex: none; + width: 66.66666667%; } + .footer-columns.is-mobile > .footer-column.is-offset-8 { + margin-left: 66.66666667%; } + .footer-columns.is-mobile > .footer-column.is-9 { + flex: none; + width: 75%; } + .footer-columns.is-mobile > .footer-column.is-offset-9 { + margin-left: 75%; } + .footer-columns.is-mobile > .footer-column.is-10 { + flex: none; + width: 83.33333333%; } + .footer-columns.is-mobile > .footer-column.is-offset-10 { + margin-left: 83.33333333%; } + .footer-columns.is-mobile > .footer-column.is-11 { + flex: none; + width: 91.66666667%; } + .footer-columns.is-mobile > .footer-column.is-offset-11 { + margin-left: 91.66666667%; } + .footer-columns.is-mobile > .footer-column.is-12 { + flex: none; + width: 100%; } + .footer-columns.is-mobile > .footer-column.is-offset-12 { + margin-left: 100%; } + @media screen and (max-width: 768px) { + .footer-column.is-narrow-mobile { + flex: none; } + .footer-column.is-full-mobile { + flex: none; + width: 100%; } + .footer-column.is-three-quarters-mobile { + flex: none; + width: 75%; } + .footer-column.is-two-thirds-mobile { + flex: none; + width: 66.6666%; } + .footer-column.is-half-mobile { + flex: none; + width: 50%; } + .footer-column.is-one-third-mobile { + flex: none; + width: 33.3333%; } + .footer-column.is-one-quarter-mobile { + flex: none; + width: 25%; } + .footer-column.is-one-fifth-mobile { + flex: none; + width: 20%; } + .footer-column.is-two-fifths-mobile { + flex: none; + width: 40%; } + .footer-column.is-three-fifths-mobile { + flex: none; + width: 60%; } + .footer-column.is-four-fifths-mobile { + flex: none; + width: 80%; } + .footer-column.is-offset-three-quarters-mobile { + margin-left: 75%; } + .footer-column.is-offset-two-thirds-mobile { + margin-left: 66.6666%; } + .footer-column.is-offset-half-mobile { + margin-left: 50%; } + .footer-column.is-offset-one-third-mobile { + margin-left: 33.3333%; } + .footer-column.is-offset-one-quarter-mobile { + margin-left: 25%; } + .footer-column.is-offset-one-fifth-mobile { + margin-left: 20%; } + .footer-column.is-offset-two-fifths-mobile { + margin-left: 40%; } + .footer-column.is-offset-three-fifths-mobile { + margin-left: 60%; } + .footer-column.is-offset-four-fifths-mobile { + margin-left: 80%; } + .footer-column.is-1-mobile { + flex: none; + width: 8.33333333%; } + .footer-column.is-offset-1-mobile { + margin-left: 8.33333333%; } + .footer-column.is-2-mobile { + flex: none; + width: 16.66666667%; } + .footer-column.is-offset-2-mobile { + margin-left: 16.66666667%; } + .footer-column.is-3-mobile { + flex: none; + width: 25%; } + .footer-column.is-offset-3-mobile { + margin-left: 25%; } + .footer-column.is-4-mobile { + flex: none; + width: 33.33333333%; } + .footer-column.is-offset-4-mobile { + margin-left: 33.33333333%; } + .footer-column.is-5-mobile { + flex: none; + width: 41.66666667%; } + .footer-column.is-offset-5-mobile { + margin-left: 41.66666667%; } + .footer-column.is-6-mobile { + flex: none; + width: 50%; } + .footer-column.is-offset-6-mobile { + margin-left: 50%; } + .footer-column.is-7-mobile { + flex: none; + width: 58.33333333%; } + .footer-column.is-offset-7-mobile { + margin-left: 58.33333333%; } + .footer-column.is-8-mobile { + flex: none; + width: 66.66666667%; } + .footer-column.is-offset-8-mobile { + margin-left: 66.66666667%; } + .footer-column.is-9-mobile { + flex: none; + width: 75%; } + .footer-column.is-offset-9-mobile { + margin-left: 75%; } + .footer-column.is-10-mobile { + flex: none; + width: 83.33333333%; } + .footer-column.is-offset-10-mobile { + margin-left: 83.33333333%; } + .footer-column.is-11-mobile { + flex: none; + width: 91.66666667%; } + .footer-column.is-offset-11-mobile { + margin-left: 91.66666667%; } + .footer-column.is-12-mobile { + flex: none; + width: 100%; } + .footer-column.is-offset-12-mobile { + margin-left: 100%; } } + @media screen and (min-width: 769px), print { + .footer-column.is-narrow, .footer-column.is-narrow-tablet { + flex: none; } + .footer-column.is-full, .footer-column.is-full-tablet { + flex: none; + width: 100%; } + .footer-column.is-three-quarters, .footer-column.is-three-quarters-tablet { + flex: none; + width: 75%; } + .footer-column.is-two-thirds, .footer-column.is-two-thirds-tablet { + flex: none; + width: 66.6666%; } + .footer-column.is-half, .footer-column.is-half-tablet { + flex: none; + width: 50%; } + .footer-column.is-one-third, .footer-column.is-one-third-tablet { + flex: none; + width: 33.3333%; } + .footer-column.is-one-quarter, .footer-column.is-one-quarter-tablet { + flex: none; + width: 25%; } + .footer-column.is-one-fifth, .footer-column.is-one-fifth-tablet { + flex: none; + width: 20%; } + .footer-column.is-two-fifths, .footer-column.is-two-fifths-tablet { + flex: none; + width: 40%; } + .footer-column.is-three-fifths, .footer-column.is-three-fifths-tablet { + flex: none; + width: 60%; } + .footer-column.is-four-fifths, .footer-column.is-four-fifths-tablet { + flex: none; + width: 80%; } + .footer-column.is-offset-three-quarters, .footer-column.is-offset-three-quarters-tablet { + margin-left: 75%; } + .footer-column.is-offset-two-thirds, .footer-column.is-offset-two-thirds-tablet { + margin-left: 66.6666%; } + .footer-column.is-offset-half, .footer-column.is-offset-half-tablet { + margin-left: 50%; } + .footer-column.is-offset-one-third, .footer-column.is-offset-one-third-tablet { + margin-left: 33.3333%; } + .footer-column.is-offset-one-quarter, .footer-column.is-offset-one-quarter-tablet { + margin-left: 25%; } + .footer-column.is-offset-one-fifth, .footer-column.is-offset-one-fifth-tablet { + margin-left: 20%; } + .footer-column.is-offset-two-fifths, .footer-column.is-offset-two-fifths-tablet { + margin-left: 40%; } + .footer-column.is-offset-three-fifths, .footer-column.is-offset-three-fifths-tablet { + margin-left: 60%; } + .footer-column.is-offset-four-fifths, .footer-column.is-offset-four-fifths-tablet { + margin-left: 80%; } + .footer-column.is-1, .footer-column.is-1-tablet { + flex: none; + width: 8.33333333%; } + .footer-column.is-offset-1, .footer-column.is-offset-1-tablet { + margin-left: 8.33333333%; } + .footer-column.is-2, .footer-column.is-2-tablet { + flex: none; + width: 16.66666667%; } + .footer-column.is-offset-2, .footer-column.is-offset-2-tablet { + margin-left: 16.66666667%; } + .footer-column.is-3, .footer-column.is-3-tablet { + flex: none; + width: 25%; } + .footer-column.is-offset-3, .footer-column.is-offset-3-tablet { + margin-left: 25%; } + .footer-column.is-4, .footer-column.is-4-tablet { + flex: none; + width: 33.33333333%; } + .footer-column.is-offset-4, .footer-column.is-offset-4-tablet { + margin-left: 33.33333333%; } + .footer-column.is-5, .footer-column.is-5-tablet { + flex: none; + width: 41.66666667%; } + .footer-column.is-offset-5, .footer-column.is-offset-5-tablet { + margin-left: 41.66666667%; } + .footer-column.is-6, .footer-column.is-6-tablet { + flex: none; + width: 50%; } + .footer-column.is-offset-6, .footer-column.is-offset-6-tablet { + margin-left: 50%; } + .footer-column.is-7, .footer-column.is-7-tablet { + flex: none; + width: 58.33333333%; } + .footer-column.is-offset-7, .footer-column.is-offset-7-tablet { + margin-left: 58.33333333%; } + .footer-column.is-8, .footer-column.is-8-tablet { + flex: none; + width: 66.66666667%; } + .footer-column.is-offset-8, .footer-column.is-offset-8-tablet { + margin-left: 66.66666667%; } + .footer-column.is-9, .footer-column.is-9-tablet { + flex: none; + width: 75%; } + .footer-column.is-offset-9, .footer-column.is-offset-9-tablet { + margin-left: 75%; } + .footer-column.is-10, .footer-column.is-10-tablet { + flex: none; + width: 83.33333333%; } + .footer-column.is-offset-10, .footer-column.is-offset-10-tablet { + margin-left: 83.33333333%; } + .footer-column.is-11, .footer-column.is-11-tablet { + flex: none; + width: 91.66666667%; } + .footer-column.is-offset-11, .footer-column.is-offset-11-tablet { + margin-left: 91.66666667%; } + .footer-column.is-12, .footer-column.is-12-tablet { + flex: none; + width: 100%; } + .footer-column.is-offset-12, .footer-column.is-offset-12-tablet { + margin-left: 100%; } } + @media screen and (max-width: 1087px) { + .footer-column.is-narrow-touch { + flex: none; } + .footer-column.is-full-touch { + flex: none; + width: 100%; } + .footer-column.is-three-quarters-touch { + flex: none; + width: 75%; } + .footer-column.is-two-thirds-touch { + flex: none; + width: 66.6666%; } + .footer-column.is-half-touch { + flex: none; + width: 50%; } + .footer-column.is-one-third-touch { + flex: none; + width: 33.3333%; } + .footer-column.is-one-quarter-touch { + flex: none; + width: 25%; } + .footer-column.is-one-fifth-touch { + flex: none; + width: 20%; } + .footer-column.is-two-fifths-touch { + flex: none; + width: 40%; } + .footer-column.is-three-fifths-touch { + flex: none; + width: 60%; } + .footer-column.is-four-fifths-touch { + flex: none; + width: 80%; } + .footer-column.is-offset-three-quarters-touch { + margin-left: 75%; } + .footer-column.is-offset-two-thirds-touch { + margin-left: 66.6666%; } + .footer-column.is-offset-half-touch { + margin-left: 50%; } + .footer-column.is-offset-one-third-touch { + margin-left: 33.3333%; } + .footer-column.is-offset-one-quarter-touch { + margin-left: 25%; } + .footer-column.is-offset-one-fifth-touch { + margin-left: 20%; } + .footer-column.is-offset-two-fifths-touch { + margin-left: 40%; } + .footer-column.is-offset-three-fifths-touch { + margin-left: 60%; } + .footer-column.is-offset-four-fifths-touch { + margin-left: 80%; } + .footer-column.is-1-touch { + flex: none; + width: 8.33333333%; } + .footer-column.is-offset-1-touch { + margin-left: 8.33333333%; } + .footer-column.is-2-touch { + flex: none; + width: 16.66666667%; } + .footer-column.is-offset-2-touch { + margin-left: 16.66666667%; } + .footer-column.is-3-touch { + flex: none; + width: 25%; } + .footer-column.is-offset-3-touch { + margin-left: 25%; } + .footer-column.is-4-touch { + flex: none; + width: 33.33333333%; } + .footer-column.is-offset-4-touch { + margin-left: 33.33333333%; } + .footer-column.is-5-touch { + flex: none; + width: 41.66666667%; } + .footer-column.is-offset-5-touch { + margin-left: 41.66666667%; } + .footer-column.is-6-touch { + flex: none; + width: 50%; } + .footer-column.is-offset-6-touch { + margin-left: 50%; } + .footer-column.is-7-touch { + flex: none; + width: 58.33333333%; } + .footer-column.is-offset-7-touch { + margin-left: 58.33333333%; } + .footer-column.is-8-touch { + flex: none; + width: 66.66666667%; } + .footer-column.is-offset-8-touch { + margin-left: 66.66666667%; } + .footer-column.is-9-touch { + flex: none; + width: 75%; } + .footer-column.is-offset-9-touch { + margin-left: 75%; } + .footer-column.is-10-touch { + flex: none; + width: 83.33333333%; } + .footer-column.is-offset-10-touch { + margin-left: 83.33333333%; } + .footer-column.is-11-touch { + flex: none; + width: 91.66666667%; } + .footer-column.is-offset-11-touch { + margin-left: 91.66666667%; } + .footer-column.is-12-touch { + flex: none; + width: 100%; } + .footer-column.is-offset-12-touch { + margin-left: 100%; } } + @media screen and (min-width: 1088px) { + .footer-column.is-narrow-desktop { + flex: none; } + .footer-column.is-full-desktop { + flex: none; + width: 100%; } + .footer-column.is-three-quarters-desktop { + flex: none; + width: 75%; } + .footer-column.is-two-thirds-desktop { + flex: none; + width: 66.6666%; } + .footer-column.is-half-desktop { + flex: none; + width: 50%; } + .footer-column.is-one-third-desktop { + flex: none; + width: 33.3333%; } + .footer-column.is-one-quarter-desktop { + flex: none; + width: 25%; } + .footer-column.is-one-fifth-desktop { + flex: none; + width: 20%; } + .footer-column.is-two-fifths-desktop { + flex: none; + width: 40%; } + .footer-column.is-three-fifths-desktop { + flex: none; + width: 60%; } + .footer-column.is-four-fifths-desktop { + flex: none; + width: 80%; } + .footer-column.is-offset-three-quarters-desktop { + margin-left: 75%; } + .footer-column.is-offset-two-thirds-desktop { + margin-left: 66.6666%; } + .footer-column.is-offset-half-desktop { + margin-left: 50%; } + .footer-column.is-offset-one-third-desktop { + margin-left: 33.3333%; } + .footer-column.is-offset-one-quarter-desktop { + margin-left: 25%; } + .footer-column.is-offset-one-fifth-desktop { + margin-left: 20%; } + .footer-column.is-offset-two-fifths-desktop { + margin-left: 40%; } + .footer-column.is-offset-three-fifths-desktop { + margin-left: 60%; } + .footer-column.is-offset-four-fifths-desktop { + margin-left: 80%; } + .footer-column.is-1-desktop { + flex: none; + width: 8.33333333%; } + .footer-column.is-offset-1-desktop { + margin-left: 8.33333333%; } + .footer-column.is-2-desktop { + flex: none; + width: 16.66666667%; } + .footer-column.is-offset-2-desktop { + margin-left: 16.66666667%; } + .footer-column.is-3-desktop { + flex: none; + width: 25%; } + .footer-column.is-offset-3-desktop { + margin-left: 25%; } + .footer-column.is-4-desktop { + flex: none; + width: 33.33333333%; } + .footer-column.is-offset-4-desktop { + margin-left: 33.33333333%; } + .footer-column.is-5-desktop { + flex: none; + width: 41.66666667%; } + .footer-column.is-offset-5-desktop { + margin-left: 41.66666667%; } + .footer-column.is-6-desktop { + flex: none; + width: 50%; } + .footer-column.is-offset-6-desktop { + margin-left: 50%; } + .footer-column.is-7-desktop { + flex: none; + width: 58.33333333%; } + .footer-column.is-offset-7-desktop { + margin-left: 58.33333333%; } + .footer-column.is-8-desktop { + flex: none; + width: 66.66666667%; } + .footer-column.is-offset-8-desktop { + margin-left: 66.66666667%; } + .footer-column.is-9-desktop { + flex: none; + width: 75%; } + .footer-column.is-offset-9-desktop { + margin-left: 75%; } + .footer-column.is-10-desktop { + flex: none; + width: 83.33333333%; } + .footer-column.is-offset-10-desktop { + margin-left: 83.33333333%; } + .footer-column.is-11-desktop { + flex: none; + width: 91.66666667%; } + .footer-column.is-offset-11-desktop { + margin-left: 91.66666667%; } + .footer-column.is-12-desktop { + flex: none; + width: 100%; } + .footer-column.is-offset-12-desktop { + margin-left: 100%; } } + @media screen and (min-width: 1280px) { + .footer-column.is-narrow-widescreen { + flex: none; } + .footer-column.is-full-widescreen { + flex: none; + width: 100%; } + .footer-column.is-three-quarters-widescreen { + flex: none; + width: 75%; } + .footer-column.is-two-thirds-widescreen { + flex: none; + width: 66.6666%; } + .footer-column.is-half-widescreen { + flex: none; + width: 50%; } + .footer-column.is-one-third-widescreen { + flex: none; + width: 33.3333%; } + .footer-column.is-one-quarter-widescreen { + flex: none; + width: 25%; } + .footer-column.is-one-fifth-widescreen { + flex: none; + width: 20%; } + .footer-column.is-two-fifths-widescreen { + flex: none; + width: 40%; } + .footer-column.is-three-fifths-widescreen { + flex: none; + width: 60%; } + .footer-column.is-four-fifths-widescreen { + flex: none; + width: 80%; } + .footer-column.is-offset-three-quarters-widescreen { + margin-left: 75%; } + .footer-column.is-offset-two-thirds-widescreen { + margin-left: 66.6666%; } + .footer-column.is-offset-half-widescreen { + margin-left: 50%; } + .footer-column.is-offset-one-third-widescreen { + margin-left: 33.3333%; } + .footer-column.is-offset-one-quarter-widescreen { + margin-left: 25%; } + .footer-column.is-offset-one-fifth-widescreen { + margin-left: 20%; } + .footer-column.is-offset-two-fifths-widescreen { + margin-left: 40%; } + .footer-column.is-offset-three-fifths-widescreen { + margin-left: 60%; } + .footer-column.is-offset-four-fifths-widescreen { + margin-left: 80%; } + .footer-column.is-1-widescreen { + flex: none; + width: 8.33333333%; } + .footer-column.is-offset-1-widescreen { + margin-left: 8.33333333%; } + .footer-column.is-2-widescreen { + flex: none; + width: 16.66666667%; } + .footer-column.is-offset-2-widescreen { + margin-left: 16.66666667%; } + .footer-column.is-3-widescreen { + flex: none; + width: 25%; } + .footer-column.is-offset-3-widescreen { + margin-left: 25%; } + .footer-column.is-4-widescreen { + flex: none; + width: 33.33333333%; } + .footer-column.is-offset-4-widescreen { + margin-left: 33.33333333%; } + .footer-column.is-5-widescreen { + flex: none; + width: 41.66666667%; } + .footer-column.is-offset-5-widescreen { + margin-left: 41.66666667%; } + .footer-column.is-6-widescreen { + flex: none; + width: 50%; } + .footer-column.is-offset-6-widescreen { + margin-left: 50%; } + .footer-column.is-7-widescreen { + flex: none; + width: 58.33333333%; } + .footer-column.is-offset-7-widescreen { + margin-left: 58.33333333%; } + .footer-column.is-8-widescreen { + flex: none; + width: 66.66666667%; } + .footer-column.is-offset-8-widescreen { + margin-left: 66.66666667%; } + .footer-column.is-9-widescreen { + flex: none; + width: 75%; } + .footer-column.is-offset-9-widescreen { + margin-left: 75%; } + .footer-column.is-10-widescreen { + flex: none; + width: 83.33333333%; } + .footer-column.is-offset-10-widescreen { + margin-left: 83.33333333%; } + .footer-column.is-11-widescreen { + flex: none; + width: 91.66666667%; } + .footer-column.is-offset-11-widescreen { + margin-left: 91.66666667%; } + .footer-column.is-12-widescreen { + flex: none; + width: 100%; } + .footer-column.is-offset-12-widescreen { + margin-left: 100%; } } + .footer-columns { + margin-left: -0.75rem; + margin-right: -0.75rem; + margin-top: -0.75rem; } + .footer-columns:last-child { + margin-bottom: -0.75rem; } + .footer-columns:not(:last-child) { + margin-bottom: calc(1.5rem - 0.75rem); } + .footer-columns.is-centered { + justify-content: center; } + .footer-columns.is-gapless { + margin-left: 0; + margin-right: 0; + margin-top: 0; } + .footer-columns.is-gapless > .footer-column { + margin: 0; + padding: 0 !important; } + .footer-columns.is-gapless:not(:last-child) { + margin-bottom: 1.5rem; } + .footer-columns.is-gapless:last-child { + margin-bottom: 0; } + .footer-columns.is-mobile { + display: flex; } + .footer-columns.is-multiline { + flex-wrap: wrap; } + .footer-columns.is-vcentered { + align-items: center; } + @media screen and (min-width: 769px), print { + .footer-columns:not(.is-desktop) { + display: flex; } } + @media screen and (min-width: 1088px) { + .footer-columns.is-desktop { + display: flex; } } + .footer-columns.is-variable { + --columnGap: 0.75rem; + margin-left: calc(-1 * var(--columnGap)); + margin-right: calc(-1 * var(--columnGap)); } + .footer-columns.is-variable .footer-column { + padding-left: var(--columnGap); + padding-right: var(--columnGap); } + .footer-columns.is-variable.is-0 { + --columnGap: 0rem; } + .footer-columns.is-variable.is-1 { + --columnGap: 0.25rem; } + .footer-columns.is-variable.is-2 { + --columnGap: 0.5rem; } + .footer-columns.is-variable.is-3 { + --columnGap: 0.75rem; } + .footer-columns.is-variable.is-4 { + --columnGap: 1rem; } + .footer-columns.is-variable.is-5 { + --columnGap: 1.25rem; } + .footer-columns.is-variable.is-6 { + --columnGap: 1.5rem; } + .footer-columns.is-variable.is-7 { + --columnGap: 1.75rem; } + .footer-columns.is-variable.is-8 { + --columnGap: 2rem; } diff --git a/v0.10.x/_static/vendor/style.css b/v0.10.x/_static/vendor/style.css new file mode 100644 index 000000000..46d904384 --- /dev/null +++ b/v0.10.x/_static/vendor/style.css @@ -0,0 +1,7115 @@ +/*! bulma.io v0.7.0 | MIT License | github.com/jgthms/bulma */ +@keyframes spinAround { + from { + transform: rotate(0deg); } + to { + transform: rotate(359deg); } } + +.tabs, .pagination-previous, +.pagination-next, +.pagination-link, +.pagination-ellipsis, .breadcrumb, .file, .button, .is-unselectable, .modal-close, .delete { + -webkit-touch-callout: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; } + +.navbar-link::after, .select:not(.is-multiple):not(.is-loading)::after { + border: 3px solid transparent; + border-radius: 2px; + border-right: 0; + border-top: 0; + content: " "; + display: block; + height: 0.625em; + margin-top: -0.4375em; + pointer-events: none; + position: absolute; + top: 50%; + transform: rotate(-45deg); + transform-origin: center; + width: 0.625em; } + +.tabs:not(:last-child), .message:not(:last-child), .level:not(:last-child), .breadcrumb:not(:last-child), .highlight:not(:last-child), .block:not(:last-child), .title:not(:last-child), +.subtitle:not(:last-child), .table-container:not(:last-child), .table:not(:last-child), .progress:not(:last-child), .notification:not(:last-child), .content:not(:last-child), .box:not(:last-child) { + margin-bottom: 1.5rem; } + +.modal-close, .delete { + -moz-appearance: none; + -webkit-appearance: none; + background-color: rgba(10, 10, 10, 0.2); + border: none; + border-radius: 290486px; + cursor: pointer; + display: inline-block; + flex-grow: 0; + flex-shrink: 0; + font-size: 0; + height: 20px; + max-height: 20px; + max-width: 20px; + min-height: 20px; + min-width: 20px; + outline: none; + position: relative; + vertical-align: top; + width: 20px; } + .modal-close::before, .delete::before, .modal-close::after, .delete::after { + background-color: white; + content: ""; + display: block; + left: 50%; + position: absolute; + top: 50%; + transform: translateX(-50%) translateY(-50%) rotate(45deg); + transform-origin: center center; } + .modal-close::before, .delete::before { + height: 2px; + width: 50%; } + .modal-close::after, .delete::after { + height: 50%; + width: 2px; } + .modal-close:hover, .delete:hover, .modal-close:focus, .delete:focus { + background-color: rgba(10, 10, 10, 0.3); } + .modal-close:active, .delete:active { + background-color: rgba(10, 10, 10, 0.4); } + .is-small.modal-close, .is-small.delete { + height: 16px; + max-height: 16px; + max-width: 16px; + min-height: 16px; + min-width: 16px; + width: 16px; } + .is-medium.modal-close, .is-medium.delete { + height: 24px; + max-height: 24px; + max-width: 24px; + min-height: 24px; + min-width: 24px; + width: 24px; } + .is-large.modal-close, .is-large.delete { + height: 32px; + max-height: 32px; + max-width: 32px; + min-height: 32px; + min-width: 32px; + width: 32px; } + +.loader, .control.is-loading::after, .select.is-loading::after, .button.is-loading::after { + animation: spinAround 500ms infinite linear; + border: 2px solid #dbdbdb; + border-radius: 290486px; + border-right-color: transparent; + border-top-color: transparent; + content: ""; + display: block; + height: 1em; + position: relative; + width: 1em; } + +.hero-video, .modal-background, .modal, .image.is-square img, .image.is-1by1 img, .image.is-5by4 img, .image.is-4by3 img, .image.is-3by2 img, .image.is-5by3 img, .image.is-16by9 img, .image.is-2by1 img, .image.is-3by1 img, .image.is-4by5 img, .image.is-3by4 img, .image.is-2by3 img, .image.is-3by5 img, .image.is-9by16 img, .image.is-1by2 img, .image.is-1by3 img, .is-overlay { + bottom: 0; + left: 0; + position: absolute; + right: 0; + top: 0; } + +.pagination-previous, +.pagination-next, +.pagination-link, +.pagination-ellipsis, .file-cta, +.file-name, .select select, .input, +.textarea, .button { + -moz-appearance: none; + -webkit-appearance: none; + align-items: center; + border: 1px solid transparent; + border-radius: 4px; + box-shadow: none; + display: inline-flex; + font-size: 1rem; + height: 2.25em; + justify-content: flex-start; + line-height: 1.5; + padding-bottom: calc(0.375em - 1px); + padding-left: calc(0.625em - 1px); + padding-right: calc(0.625em - 1px); + padding-top: calc(0.375em - 1px); + position: relative; + vertical-align: top; } + .pagination-previous:focus, + .pagination-next:focus, + .pagination-link:focus, + .pagination-ellipsis:focus, .file-cta:focus, + .file-name:focus, .select select:focus, .input:focus, + .textarea:focus, .button:focus, .is-focused.pagination-previous, + .is-focused.pagination-next, + .is-focused.pagination-link, + .is-focused.pagination-ellipsis, .is-focused.file-cta, + .is-focused.file-name, .select select.is-focused, .is-focused.input, + .is-focused.textarea, .is-focused.button, .pagination-previous:active, + .pagination-next:active, + .pagination-link:active, + .pagination-ellipsis:active, .file-cta:active, + .file-name:active, .select select:active, .input:active, + .textarea:active, .button:active, .is-active.pagination-previous, + .is-active.pagination-next, + .is-active.pagination-link, + .is-active.pagination-ellipsis, .is-active.file-cta, + .is-active.file-name, .select select.is-active, .is-active.input, + .is-active.textarea, .is-active.button { + outline: none; } + [disabled].pagination-previous, + [disabled].pagination-next, + [disabled].pagination-link, + [disabled].pagination-ellipsis, [disabled].file-cta, + [disabled].file-name, .select select[disabled], [disabled].input, + [disabled].textarea, [disabled].button { + cursor: not-allowed; } + +/*! minireset.css v0.0.3 | MIT License | github.com/jgthms/minireset.css */ +html, +body, +p, +ol, +ul, +li, +dl, +dt, +dd, +blockquote, +figure, +fieldset, +legend, +textarea, +pre, +iframe, +hr, +h1, +h2, +h3, +h4, +h5, +h6 { + margin: 0; + padding: 0; } + +h1, +h2, +h3, +h4, +h5, +h6 { + font-size: 100%; + font-weight: normal; } + +ul { + list-style: none; } + +button, +input, +select, +textarea { + margin: 0; } + +html { + box-sizing: border-box; } + +*, *::before, *::after { + box-sizing: inherit; } + +img, +audio, +video { + height: auto; + max-width: 100%; } + +iframe { + border: 0; } + +table { + border-collapse: collapse; + border-spacing: 0; } + +td, +th { + padding: 0; + text-align: left; } + +html { + background-color: white; + font-size: 16px; + -moz-osx-font-smoothing: grayscale; + -webkit-font-smoothing: antialiased; + min-width: 300px; + overflow-x: hidden; + overflow-y: scroll; + text-rendering: optimizeLegibility; + text-size-adjust: 100%; } + +article, +aside, +figure, +footer, +header, +hgroup, +section { + display: block; } + +body, +button, +input, +select, +textarea { + font-family: BlinkMacSystemFont, -apple-system, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", "Helvetica", "Arial", sans-serif; } + +code, +pre { + -moz-osx-font-smoothing: auto; + -webkit-font-smoothing: auto; + font-family: monospace; } + +body { + color: #4a4a4a; + font-size: 1rem; + font-weight: 400; + line-height: 1.5; } + +a { + color: #3273dc; + cursor: pointer; + text-decoration: none; } + a strong { + color: currentColor; } + a:hover { + color: #363636; } + +code { + background-color: whitesmoke; + color: #ff3860; + font-size: 0.875em; + font-weight: normal; + padding: 0.25em 0.5em 0.25em; } + +hr { + background-color: whitesmoke; + border: none; + display: block; + height: 2px; + margin: 1.5rem 0; } + +img { + height: auto; + max-width: 100%; } + +input[type="checkbox"], +input[type="radio"] { + vertical-align: baseline; } + +small { + font-size: 0.875em; } + +span { + font-style: inherit; + font-weight: inherit; } + +strong { + color: #363636; + font-weight: 700; } + +pre { + -webkit-overflow-scrolling: touch; + background-color: whitesmoke; + color: #4a4a4a; + font-size: 0.875em; + overflow-x: auto; + padding: 1.25rem 1.5rem; + white-space: pre; + word-wrap: normal; } + pre code { + background-color: transparent; + color: currentColor; + font-size: 1em; + padding: 0; } + +table td, +table th { + text-align: left; + vertical-align: top; } + +table th { + color: #363636; } + +.is-clearfix::after { + clear: both; + content: " "; + display: table; } + +.is-pulled-left { + float: left !important; } + +.is-pulled-right { + float: right !important; } + +.is-clipped { + overflow: hidden !important; } + +.is-size-1 { + font-size: 3rem !important; } + +.is-size-2 { + font-size: 2.5rem !important; } + +.is-size-3 { + font-size: 2rem !important; } + +.is-size-4 { + font-size: 1.5rem !important; } + +.is-size-5 { + font-size: 1.25rem !important; } + +.is-size-6 { + font-size: 1rem !important; } + +.is-size-7 { + font-size: 0.75rem !important; } + +@media screen and (max-width: 768px) { + .is-size-1-mobile { + font-size: 3rem !important; } + .is-size-2-mobile { + font-size: 2.5rem !important; } + .is-size-3-mobile { + font-size: 2rem !important; } + .is-size-4-mobile { + font-size: 1.5rem !important; } + .is-size-5-mobile { + font-size: 1.25rem !important; } + .is-size-6-mobile { + font-size: 1rem !important; } + .is-size-7-mobile { + font-size: 0.75rem !important; } } + +@media screen and (min-width: 769px), print { + .is-size-1-tablet { + font-size: 3rem !important; } + .is-size-2-tablet { + font-size: 2.5rem !important; } + .is-size-3-tablet { + font-size: 2rem !important; } + .is-size-4-tablet { + font-size: 1.5rem !important; } + .is-size-5-tablet { + font-size: 1.25rem !important; } + .is-size-6-tablet { + font-size: 1rem !important; } + .is-size-7-tablet { + font-size: 0.75rem !important; } } + +@media screen and (max-width: 1087px) { + .is-size-1-touch { + font-size: 3rem !important; } + .is-size-2-touch { + font-size: 2.5rem !important; } + .is-size-3-touch { + font-size: 2rem !important; } + .is-size-4-touch { + font-size: 1.5rem !important; } + .is-size-5-touch { + font-size: 1.25rem !important; } + .is-size-6-touch { + font-size: 1rem !important; } + .is-size-7-touch { + font-size: 0.75rem !important; } } + +@media screen and (min-width: 1088px) { + .is-size-1-desktop { + font-size: 3rem !important; } + .is-size-2-desktop { + font-size: 2.5rem !important; } + .is-size-3-desktop { + font-size: 2rem !important; } + .is-size-4-desktop { + font-size: 1.5rem !important; } + .is-size-5-desktop { + font-size: 1.25rem !important; } + .is-size-6-desktop { + font-size: 1rem !important; } + .is-size-7-desktop { + font-size: 0.75rem !important; } } + +@media screen and (min-width: 1280px) { + .is-size-1-widescreen { + font-size: 3rem !important; } + .is-size-2-widescreen { + font-size: 2.5rem !important; } + .is-size-3-widescreen { + font-size: 2rem !important; } + .is-size-4-widescreen { + font-size: 1.5rem !important; } + .is-size-5-widescreen { + font-size: 1.25rem !important; } + .is-size-6-widescreen { + font-size: 1rem !important; } + .is-size-7-widescreen { + font-size: 0.75rem !important; } } + +.has-text-centered { + text-align: center !important; } + +.has-text-justified { + text-align: justify !important; } + +.has-text-left { + text-align: left !important; } + +.has-text-right { + text-align: right !important; } + +@media screen and (max-width: 768px) { + .has-text-centered-mobile { + text-align: center !important; } } + +@media screen and (min-width: 769px), print { + .has-text-centered-tablet { + text-align: center !important; } } + +@media screen and (min-width: 769px) and (max-width: 1087px) { + .has-text-centered-tablet-only { + text-align: center !important; } } + +@media screen and (max-width: 1087px) { + .has-text-centered-touch { + text-align: center !important; } } + +@media screen and (min-width: 1088px) { + .has-text-centered-desktop { + text-align: center !important; } } + +@media screen and (min-width: 1088px) and (max-width: 1279px) { + .has-text-centered-desktop-only { + text-align: center !important; } } + +@media screen and (min-width: 1280px) { + .has-text-centered-widescreen { + text-align: center !important; } } + +@media screen and (max-width: 768px) { + .has-text-justified-mobile { + text-align: justify !important; } } + +@media screen and (min-width: 769px), print { + .has-text-justified-tablet { + text-align: justify !important; } } + +@media screen and (min-width: 769px) and (max-width: 1087px) { + .has-text-justified-tablet-only { + text-align: justify !important; } } + +@media screen and (max-width: 1087px) { + .has-text-justified-touch { + text-align: justify !important; } } + +@media screen and (min-width: 1088px) { + .has-text-justified-desktop { + text-align: justify !important; } } + +@media screen and (min-width: 1088px) and (max-width: 1279px) { + .has-text-justified-desktop-only { + text-align: justify !important; } } + +@media screen and (min-width: 1280px) { + .has-text-justified-widescreen { + text-align: justify !important; } } + +@media screen and (max-width: 768px) { + .has-text-left-mobile { + text-align: left !important; } } + +@media screen and (min-width: 769px), print { + .has-text-left-tablet { + text-align: left !important; } } + +@media screen and (min-width: 769px) and (max-width: 1087px) { + .has-text-left-tablet-only { + text-align: left !important; } } + +@media screen and (max-width: 1087px) { + .has-text-left-touch { + text-align: left !important; } } + +@media screen and (min-width: 1088px) { + .has-text-left-desktop { + text-align: left !important; } } + +@media screen and (min-width: 1088px) and (max-width: 1279px) { + .has-text-left-desktop-only { + text-align: left !important; } } + +@media screen and (min-width: 1280px) { + .has-text-left-widescreen { + text-align: left !important; } } + +@media screen and (max-width: 768px) { + .has-text-right-mobile { + text-align: right !important; } } + +@media screen and (min-width: 769px), print { + .has-text-right-tablet { + text-align: right !important; } } + +@media screen and (min-width: 769px) and (max-width: 1087px) { + .has-text-right-tablet-only { + text-align: right !important; } } + +@media screen and (max-width: 1087px) { + .has-text-right-touch { + text-align: right !important; } } + +@media screen and (min-width: 1088px) { + .has-text-right-desktop { + text-align: right !important; } } + +@media screen and (min-width: 1088px) and (max-width: 1279px) { + .has-text-right-desktop-only { + text-align: right !important; } } + +@media screen and (min-width: 1280px) { + .has-text-right-widescreen { + text-align: right !important; } } + +.is-capitalized { + text-transform: capitalize !important; } + +.is-lowercase { + text-transform: lowercase !important; } + +.is-uppercase { + text-transform: uppercase !important; } + +.is-italic { + font-style: italic !important; } + +.has-text-white { + color: white !important; } + +a.has-text-white:hover, a.has-text-white:focus { + color: #e6e6e6 !important; } + +.has-background-white { + background-color: white !important; } + +.has-text-black { + color: #0a0a0a !important; } + +a.has-text-black:hover, a.has-text-black:focus { + color: black !important; } + +.has-background-black { + background-color: #0a0a0a !important; } + +.has-text-light { + color: whitesmoke !important; } + +a.has-text-light:hover, a.has-text-light:focus { + color: #dbdbdb !important; } + +.has-background-light { + background-color: whitesmoke !important; } + +.has-text-dark { + color: #363636 !important; } + +a.has-text-dark:hover, a.has-text-dark:focus { + color: #1c1c1c !important; } + +.has-background-dark { + background-color: #363636 !important; } + +.has-text-primary { + color: #00d1b2 !important; } + +a.has-text-primary:hover, a.has-text-primary:focus { + color: #009e86 !important; } + +.has-background-primary { + background-color: #00d1b2 !important; } + +.has-text-link { + color: #3273dc !important; } + +a.has-text-link:hover, a.has-text-link:focus { + color: #205bbc !important; } + +.has-background-link { + background-color: #3273dc !important; } + +.has-text-info { + color: #209cee !important; } + +a.has-text-info:hover, a.has-text-info:focus { + color: #0f81cc !important; } + +.has-background-info { + background-color: #209cee !important; } + +.has-text-success { + color: #23d160 !important; } + +a.has-text-success:hover, a.has-text-success:focus { + color: #1ca64c !important; } + +.has-background-success { + background-color: #23d160 !important; } + +.has-text-warning { + color: #ffdd57 !important; } + +a.has-text-warning:hover, a.has-text-warning:focus { + color: #ffd324 !important; } + +.has-background-warning { + background-color: #ffdd57 !important; } + +.has-text-danger { + color: #ff3860 !important; } + +a.has-text-danger:hover, a.has-text-danger:focus { + color: #ff0537 !important; } + +.has-background-danger { + background-color: #ff3860 !important; } + +.has-text-black-bis { + color: #121212 !important; } + +.has-text-black-ter { + color: #242424 !important; } + +.has-text-grey-darker { + color: #363636 !important; } + +.has-text-grey-dark { + color: #4a4a4a !important; } + +.has-text-grey { + color: #7a7a7a !important; } + +.has-text-grey-light { + color: #b5b5b5 !important; } + +.has-text-grey-lighter { + color: #dbdbdb !important; } + +.has-text-white-ter { + color: whitesmoke !important; } + +.has-text-white-bis { + color: #fafafa !important; } + +.has-text-weight-light { + font-weight: 300 !important; } + +.has-text-weight-normal { + font-weight: 400 !important; } + +.has-text-weight-semibold { + font-weight: 600 !important; } + +.has-text-weight-bold { + font-weight: 700 !important; } + +.is-block { + display: block !important; } + +@media screen and (max-width: 768px) { + .is-block-mobile { + display: block !important; } } + +@media screen and (min-width: 769px), print { + .is-block-tablet { + display: block !important; } } + +@media screen and (min-width: 769px) and (max-width: 1087px) { + .is-block-tablet-only { + display: block !important; } } + +@media screen and (max-width: 1087px) { + .is-block-touch { + display: block !important; } } + +@media screen and (min-width: 1088px) { + .is-block-desktop { + display: block !important; } } + +@media screen and (min-width: 1088px) and (max-width: 1279px) { + .is-block-desktop-only { + display: block !important; } } + +@media screen and (min-width: 1280px) { + .is-block-widescreen { + display: block !important; } } + +.is-flex { + display: flex !important; } + +@media screen and (max-width: 768px) { + .is-flex-mobile { + display: flex !important; } } + +@media screen and (min-width: 769px), print { + .is-flex-tablet { + display: flex !important; } } + +@media screen and (min-width: 769px) and (max-width: 1087px) { + .is-flex-tablet-only { + display: flex !important; } } + +@media screen and (max-width: 1087px) { + .is-flex-touch { + display: flex !important; } } + +@media screen and (min-width: 1088px) { + .is-flex-desktop { + display: flex !important; } } + +@media screen and (min-width: 1088px) and (max-width: 1279px) { + .is-flex-desktop-only { + display: flex !important; } } + +@media screen and (min-width: 1280px) { + .is-flex-widescreen { + display: flex !important; } } + +.is-inline { + display: inline !important; } + +@media screen and (max-width: 768px) { + .is-inline-mobile { + display: inline !important; } } + +@media screen and (min-width: 769px), print { + .is-inline-tablet { + display: inline !important; } } + +@media screen and (min-width: 769px) and (max-width: 1087px) { + .is-inline-tablet-only { + display: inline !important; } } + +@media screen and (max-width: 1087px) { + .is-inline-touch { + display: inline !important; } } + +@media screen and (min-width: 1088px) { + .is-inline-desktop { + display: inline !important; } } + +@media screen and (min-width: 1088px) and (max-width: 1279px) { + .is-inline-desktop-only { + display: inline !important; } } + +@media screen and (min-width: 1280px) { + .is-inline-widescreen { + display: inline !important; } } + +.is-inline-block { + display: inline-block !important; } + +@media screen and (max-width: 768px) { + .is-inline-block-mobile { + display: inline-block !important; } } + +@media screen and (min-width: 769px), print { + .is-inline-block-tablet { + display: inline-block !important; } } + +@media screen and (min-width: 769px) and (max-width: 1087px) { + .is-inline-block-tablet-only { + display: inline-block !important; } } + +@media screen and (max-width: 1087px) { + .is-inline-block-touch { + display: inline-block !important; } } + +@media screen and (min-width: 1088px) { + .is-inline-block-desktop { + display: inline-block !important; } } + +@media screen and (min-width: 1088px) and (max-width: 1279px) { + .is-inline-block-desktop-only { + display: inline-block !important; } } + +@media screen and (min-width: 1280px) { + .is-inline-block-widescreen { + display: inline-block !important; } } + +.is-inline-flex { + display: inline-flex !important; } + +@media screen and (max-width: 768px) { + .is-inline-flex-mobile { + display: inline-flex !important; } } + +@media screen and (min-width: 769px), print { + .is-inline-flex-tablet { + display: inline-flex !important; } } + +@media screen and (min-width: 769px) and (max-width: 1087px) { + .is-inline-flex-tablet-only { + display: inline-flex !important; } } + +@media screen and (max-width: 1087px) { + .is-inline-flex-touch { + display: inline-flex !important; } } + +@media screen and (min-width: 1088px) { + .is-inline-flex-desktop { + display: inline-flex !important; } } + +@media screen and (min-width: 1088px) and (max-width: 1279px) { + .is-inline-flex-desktop-only { + display: inline-flex !important; } } + +@media screen and (min-width: 1280px) { + .is-inline-flex-widescreen { + display: inline-flex !important; } } + +.is-hidden { + display: none !important; } + +@media screen and (max-width: 768px) { + .is-hidden-mobile { + display: none !important; } } + +@media screen and (min-width: 769px), print { + .is-hidden-tablet { + display: none !important; } } + +@media screen and (min-width: 769px) and (max-width: 1087px) { + .is-hidden-tablet-only { + display: none !important; } } + +@media screen and (max-width: 1087px) { + .is-hidden-touch { + display: none !important; } } + +@media screen and (min-width: 1088px) { + .is-hidden-desktop { + display: none !important; } } + +@media screen and (min-width: 1088px) and (max-width: 1279px) { + .is-hidden-desktop-only { + display: none !important; } } + +@media screen and (min-width: 1280px) { + .is-hidden-widescreen { + display: none !important; } } + +.is-invisible { + visibility: hidden !important; } + +@media screen and (max-width: 768px) { + .is-invisible-mobile { + visibility: hidden !important; } } + +@media screen and (min-width: 769px), print { + .is-invisible-tablet { + visibility: hidden !important; } } + +@media screen and (min-width: 769px) and (max-width: 1087px) { + .is-invisible-tablet-only { + visibility: hidden !important; } } + +@media screen and (max-width: 1087px) { + .is-invisible-touch { + visibility: hidden !important; } } + +@media screen and (min-width: 1088px) { + .is-invisible-desktop { + visibility: hidden !important; } } + +@media screen and (min-width: 1088px) and (max-width: 1279px) { + .is-invisible-desktop-only { + visibility: hidden !important; } } + +@media screen and (min-width: 1280px) { + .is-invisible-widescreen { + visibility: hidden !important; } } + +.is-marginless { + margin: 0 !important; } + +.is-paddingless { + padding: 0 !important; } + +.is-radiusless { + border-radius: 0 !important; } + +.is-shadowless { + box-shadow: none !important; } + +.box { + background-color: white; + border-radius: 6px; + box-shadow: 0 2px 3px rgba(10, 10, 10, 0.1), 0 0 0 1px rgba(10, 10, 10, 0.1); + color: #4a4a4a; + display: block; + padding: 1.25rem; } + +a.box:hover, a.box:focus { + box-shadow: 0 2px 3px rgba(10, 10, 10, 0.1), 0 0 0 1px #3273dc; } + +a.box:active { + box-shadow: inset 0 1px 2px rgba(10, 10, 10, 0.2), 0 0 0 1px #3273dc; } + +.button { + background-color: white; + border-color: #dbdbdb; + border-width: 1px; + color: #363636; + cursor: pointer; + justify-content: center; + padding-bottom: calc(0.375em - 1px); + padding-left: 0.75em; + padding-right: 0.75em; + padding-top: calc(0.375em - 1px); + text-align: center; + white-space: nowrap; } + .button strong { + color: inherit; } + .button .icon, .button .icon.is-small, .button .icon.is-medium, .button .icon.is-large { + height: 1.5em; + width: 1.5em; } + .button .icon:first-child:not(:last-child) { + margin-left: calc(-0.375em - 1px); + margin-right: 0.1875em; } + .button .icon:last-child:not(:first-child) { + margin-left: 0.1875em; + margin-right: calc(-0.375em - 1px); } + .button .icon:first-child:last-child { + margin-left: calc(-0.375em - 1px); + margin-right: calc(-0.375em - 1px); } + .button:hover, .button.is-hovered { + border-color: #b5b5b5; + color: #363636; } + .button:focus, .button.is-focused { + border-color: #3273dc; + color: #363636; } + .button:focus:not(:active), .button.is-focused:not(:active) { + box-shadow: 0 0 0 0.125em rgba(50, 115, 220, 0.25); } + .button:active, .button.is-active { + border-color: #4a4a4a; + color: #363636; } + .button.is-text { + background-color: transparent; + border-color: transparent; + color: #4a4a4a; + text-decoration: underline; } + .button.is-text:hover, .button.is-text.is-hovered, .button.is-text:focus, .button.is-text.is-focused { + background-color: whitesmoke; + color: #363636; } + .button.is-text:active, .button.is-text.is-active { + background-color: #e8e8e8; + color: #363636; } + .button.is-text[disabled] { + background-color: transparent; + border-color: transparent; + box-shadow: none; } + .button.is-white { + background-color: white; + border-color: transparent; + color: #0a0a0a; } + .button.is-white:hover, .button.is-white.is-hovered { + background-color: #f9f9f9; + border-color: transparent; + color: #0a0a0a; } + .button.is-white:focus, .button.is-white.is-focused { + border-color: transparent; + color: #0a0a0a; } + .button.is-white:focus:not(:active), .button.is-white.is-focused:not(:active) { + box-shadow: 0 0 0 0.125em rgba(255, 255, 255, 0.25); } + .button.is-white:active, .button.is-white.is-active { + background-color: #f2f2f2; + border-color: transparent; + color: #0a0a0a; } + .button.is-white[disabled] { + background-color: white; + border-color: transparent; + box-shadow: none; } + .button.is-white.is-inverted { + background-color: #0a0a0a; + color: white; } + .button.is-white.is-inverted:hover { + background-color: black; } + .button.is-white.is-inverted[disabled] { + background-color: #0a0a0a; + border-color: transparent; + box-shadow: none; + color: white; } + .button.is-white.is-loading::after { + border-color: transparent transparent #0a0a0a #0a0a0a !important; } + .button.is-white.is-outlined { + background-color: transparent; + border-color: white; + color: white; } + .button.is-white.is-outlined:hover, .button.is-white.is-outlined:focus { + background-color: white; + border-color: white; + color: #0a0a0a; } + .button.is-white.is-outlined.is-loading::after { + border-color: transparent transparent white white !important; } + .button.is-white.is-outlined[disabled] { + background-color: transparent; + border-color: white; + box-shadow: none; + color: white; } + .button.is-white.is-inverted.is-outlined { + background-color: transparent; + border-color: #0a0a0a; + color: #0a0a0a; } + .button.is-white.is-inverted.is-outlined:hover, .button.is-white.is-inverted.is-outlined:focus { + background-color: #0a0a0a; + color: white; } + .button.is-white.is-inverted.is-outlined[disabled] { + background-color: transparent; + border-color: #0a0a0a; + box-shadow: none; + color: #0a0a0a; } + .button.is-black { + background-color: #0a0a0a; + border-color: transparent; + color: white; } + .button.is-black:hover, .button.is-black.is-hovered { + background-color: #040404; + border-color: transparent; + color: white; } + .button.is-black:focus, .button.is-black.is-focused { + border-color: transparent; + color: white; } + .button.is-black:focus:not(:active), .button.is-black.is-focused:not(:active) { + box-shadow: 0 0 0 0.125em rgba(10, 10, 10, 0.25); } + .button.is-black:active, .button.is-black.is-active { + background-color: black; + border-color: transparent; + color: white; } + .button.is-black[disabled] { + background-color: #0a0a0a; + border-color: transparent; + box-shadow: none; } + .button.is-black.is-inverted { + background-color: white; + color: #0a0a0a; } + .button.is-black.is-inverted:hover { + background-color: #f2f2f2; } + .button.is-black.is-inverted[disabled] { + background-color: white; + border-color: transparent; + box-shadow: none; + color: #0a0a0a; } + .button.is-black.is-loading::after { + border-color: transparent transparent white white !important; } + .button.is-black.is-outlined { + background-color: transparent; + border-color: #0a0a0a; + color: #0a0a0a; } + .button.is-black.is-outlined:hover, .button.is-black.is-outlined:focus { + background-color: #0a0a0a; + border-color: #0a0a0a; + color: white; } + .button.is-black.is-outlined.is-loading::after { + border-color: transparent transparent #0a0a0a #0a0a0a !important; } + .button.is-black.is-outlined[disabled] { + background-color: transparent; + border-color: #0a0a0a; + box-shadow: none; + color: #0a0a0a; } + .button.is-black.is-inverted.is-outlined { + background-color: transparent; + border-color: white; + color: white; } + .button.is-black.is-inverted.is-outlined:hover, .button.is-black.is-inverted.is-outlined:focus { + background-color: white; + color: #0a0a0a; } + .button.is-black.is-inverted.is-outlined[disabled] { + background-color: transparent; + border-color: white; + box-shadow: none; + color: white; } + .button.is-light { + background-color: whitesmoke; + border-color: transparent; + color: #363636; } + .button.is-light:hover, .button.is-light.is-hovered { + background-color: #eeeeee; + border-color: transparent; + color: #363636; } + .button.is-light:focus, .button.is-light.is-focused { + border-color: transparent; + color: #363636; } + .button.is-light:focus:not(:active), .button.is-light.is-focused:not(:active) { + box-shadow: 0 0 0 0.125em rgba(245, 245, 245, 0.25); } + .button.is-light:active, .button.is-light.is-active { + background-color: #e8e8e8; + border-color: transparent; + color: #363636; } + .button.is-light[disabled] { + background-color: whitesmoke; + border-color: transparent; + box-shadow: none; } + .button.is-light.is-inverted { + background-color: #363636; + color: whitesmoke; } + .button.is-light.is-inverted:hover { + background-color: #292929; } + .button.is-light.is-inverted[disabled] { + background-color: #363636; + border-color: transparent; + box-shadow: none; + color: whitesmoke; } + .button.is-light.is-loading::after { + border-color: transparent transparent #363636 #363636 !important; } + .button.is-light.is-outlined { + background-color: transparent; + border-color: whitesmoke; + color: whitesmoke; } + .button.is-light.is-outlined:hover, .button.is-light.is-outlined:focus { + background-color: whitesmoke; + border-color: whitesmoke; + color: #363636; } + .button.is-light.is-outlined.is-loading::after { + border-color: transparent transparent whitesmoke whitesmoke !important; } + .button.is-light.is-outlined[disabled] { + background-color: transparent; + border-color: whitesmoke; + box-shadow: none; + color: whitesmoke; } + .button.is-light.is-inverted.is-outlined { + background-color: transparent; + border-color: #363636; + color: #363636; } + .button.is-light.is-inverted.is-outlined:hover, .button.is-light.is-inverted.is-outlined:focus { + background-color: #363636; + color: whitesmoke; } + .button.is-light.is-inverted.is-outlined[disabled] { + background-color: transparent; + border-color: #363636; + box-shadow: none; + color: #363636; } + .button.is-dark { + background-color: #363636; + border-color: transparent; + color: whitesmoke; } + .button.is-dark:hover, .button.is-dark.is-hovered { + background-color: #2f2f2f; + border-color: transparent; + color: whitesmoke; } + .button.is-dark:focus, .button.is-dark.is-focused { + border-color: transparent; + color: whitesmoke; } + .button.is-dark:focus:not(:active), .button.is-dark.is-focused:not(:active) { + box-shadow: 0 0 0 0.125em rgba(54, 54, 54, 0.25); } + .button.is-dark:active, .button.is-dark.is-active { + background-color: #292929; + border-color: transparent; + color: whitesmoke; } + .button.is-dark[disabled] { + background-color: #363636; + border-color: transparent; + box-shadow: none; } + .button.is-dark.is-inverted { + background-color: whitesmoke; + color: #363636; } + .button.is-dark.is-inverted:hover { + background-color: #e8e8e8; } + .button.is-dark.is-inverted[disabled] { + background-color: whitesmoke; + border-color: transparent; + box-shadow: none; + color: #363636; } + .button.is-dark.is-loading::after { + border-color: transparent transparent whitesmoke whitesmoke !important; } + .button.is-dark.is-outlined { + background-color: transparent; + border-color: #363636; + color: #363636; } + .button.is-dark.is-outlined:hover, .button.is-dark.is-outlined:focus { + background-color: #363636; + border-color: #363636; + color: whitesmoke; } + .button.is-dark.is-outlined.is-loading::after { + border-color: transparent transparent #363636 #363636 !important; } + .button.is-dark.is-outlined[disabled] { + background-color: transparent; + border-color: #363636; + box-shadow: none; + color: #363636; } + .button.is-dark.is-inverted.is-outlined { + background-color: transparent; + border-color: whitesmoke; + color: whitesmoke; } + .button.is-dark.is-inverted.is-outlined:hover, .button.is-dark.is-inverted.is-outlined:focus { + background-color: whitesmoke; + color: #363636; } + .button.is-dark.is-inverted.is-outlined[disabled] { + background-color: transparent; + border-color: whitesmoke; + box-shadow: none; + color: whitesmoke; } + .button.is-primary { + background-color: #00d1b2; + border-color: transparent; + color: #fff; } + .button.is-primary:hover, .button.is-primary.is-hovered { + background-color: #00c4a7; + border-color: transparent; + color: #fff; } + .button.is-primary:focus, .button.is-primary.is-focused { + border-color: transparent; + color: #fff; } + .button.is-primary:focus:not(:active), .button.is-primary.is-focused:not(:active) { + box-shadow: 0 0 0 0.125em rgba(0, 209, 178, 0.25); } + .button.is-primary:active, .button.is-primary.is-active { + background-color: #00b89c; + border-color: transparent; + color: #fff; } + .button.is-primary[disabled] { + background-color: #00d1b2; + border-color: transparent; + box-shadow: none; } + .button.is-primary.is-inverted { + background-color: #fff; + color: #00d1b2; } + .button.is-primary.is-inverted:hover { + background-color: #f2f2f2; } + .button.is-primary.is-inverted[disabled] { + background-color: #fff; + border-color: transparent; + box-shadow: none; + color: #00d1b2; } + .button.is-primary.is-loading::after { + border-color: transparent transparent #fff #fff !important; } + .button.is-primary.is-outlined { + background-color: transparent; + border-color: #00d1b2; + color: #00d1b2; } + .button.is-primary.is-outlined:hover, .button.is-primary.is-outlined:focus { + background-color: #00d1b2; + border-color: #00d1b2; + color: #fff; } + .button.is-primary.is-outlined.is-loading::after { + border-color: transparent transparent #00d1b2 #00d1b2 !important; } + .button.is-primary.is-outlined[disabled] { + background-color: transparent; + border-color: #00d1b2; + box-shadow: none; + color: #00d1b2; } + .button.is-primary.is-inverted.is-outlined { + background-color: transparent; + border-color: #fff; + color: #fff; } + .button.is-primary.is-inverted.is-outlined:hover, .button.is-primary.is-inverted.is-outlined:focus { + background-color: #fff; + color: #00d1b2; } + .button.is-primary.is-inverted.is-outlined[disabled] { + background-color: transparent; + border-color: #fff; + box-shadow: none; + color: #fff; } + .button.is-link { + background-color: #3273dc; + border-color: transparent; + color: #fff; } + .button.is-link:hover, .button.is-link.is-hovered { + background-color: #276cda; + border-color: transparent; + color: #fff; } + .button.is-link:focus, .button.is-link.is-focused { + border-color: transparent; + color: #fff; } + .button.is-link:focus:not(:active), .button.is-link.is-focused:not(:active) { + box-shadow: 0 0 0 0.125em rgba(50, 115, 220, 0.25); } + .button.is-link:active, .button.is-link.is-active { + background-color: #2366d1; + border-color: transparent; + color: #fff; } + .button.is-link[disabled] { + background-color: #3273dc; + border-color: transparent; + box-shadow: none; } + .button.is-link.is-inverted { + background-color: #fff; + color: #3273dc; } + .button.is-link.is-inverted:hover { + background-color: #f2f2f2; } + .button.is-link.is-inverted[disabled] { + background-color: #fff; + border-color: transparent; + box-shadow: none; + color: #3273dc; } + .button.is-link.is-loading::after { + border-color: transparent transparent #fff #fff !important; } + .button.is-link.is-outlined { + background-color: transparent; + border-color: #3273dc; + color: #3273dc; } + .button.is-link.is-outlined:hover, .button.is-link.is-outlined:focus { + background-color: #3273dc; + border-color: #3273dc; + color: #fff; } + .button.is-link.is-outlined.is-loading::after { + border-color: transparent transparent #3273dc #3273dc !important; } + .button.is-link.is-outlined[disabled] { + background-color: transparent; + border-color: #3273dc; + box-shadow: none; + color: #3273dc; } + .button.is-link.is-inverted.is-outlined { + background-color: transparent; + border-color: #fff; + color: #fff; } + .button.is-link.is-inverted.is-outlined:hover, .button.is-link.is-inverted.is-outlined:focus { + background-color: #fff; + color: #3273dc; } + .button.is-link.is-inverted.is-outlined[disabled] { + background-color: transparent; + border-color: #fff; + box-shadow: none; + color: #fff; } + .button.is-info { + background-color: #209cee; + border-color: transparent; + color: #fff; } + .button.is-info:hover, .button.is-info.is-hovered { + background-color: #1496ed; + border-color: transparent; + color: #fff; } + .button.is-info:focus, .button.is-info.is-focused { + border-color: transparent; + color: #fff; } + .button.is-info:focus:not(:active), .button.is-info.is-focused:not(:active) { + box-shadow: 0 0 0 0.125em rgba(32, 156, 238, 0.25); } + .button.is-info:active, .button.is-info.is-active { + background-color: #118fe4; + border-color: transparent; + color: #fff; } + .button.is-info[disabled] { + background-color: #209cee; + border-color: transparent; + box-shadow: none; } + .button.is-info.is-inverted { + background-color: #fff; + color: #209cee; } + .button.is-info.is-inverted:hover { + background-color: #f2f2f2; } + .button.is-info.is-inverted[disabled] { + background-color: #fff; + border-color: transparent; + box-shadow: none; + color: #209cee; } + .button.is-info.is-loading::after { + border-color: transparent transparent #fff #fff !important; } + .button.is-info.is-outlined { + background-color: transparent; + border-color: #209cee; + color: #209cee; } + .button.is-info.is-outlined:hover, .button.is-info.is-outlined:focus { + background-color: #209cee; + border-color: #209cee; + color: #fff; } + .button.is-info.is-outlined.is-loading::after { + border-color: transparent transparent #209cee #209cee !important; } + .button.is-info.is-outlined[disabled] { + background-color: transparent; + border-color: #209cee; + box-shadow: none; + color: #209cee; } + .button.is-info.is-inverted.is-outlined { + background-color: transparent; + border-color: #fff; + color: #fff; } + .button.is-info.is-inverted.is-outlined:hover, .button.is-info.is-inverted.is-outlined:focus { + background-color: #fff; + color: #209cee; } + .button.is-info.is-inverted.is-outlined[disabled] { + background-color: transparent; + border-color: #fff; + box-shadow: none; + color: #fff; } + .button.is-success { + background-color: #23d160; + border-color: transparent; + color: #fff; } + .button.is-success:hover, .button.is-success.is-hovered { + background-color: #22c65b; + border-color: transparent; + color: #fff; } + .button.is-success:focus, .button.is-success.is-focused { + border-color: transparent; + color: #fff; } + .button.is-success:focus:not(:active), .button.is-success.is-focused:not(:active) { + box-shadow: 0 0 0 0.125em rgba(35, 209, 96, 0.25); } + .button.is-success:active, .button.is-success.is-active { + background-color: #20bc56; + border-color: transparent; + color: #fff; } + .button.is-success[disabled] { + background-color: #23d160; + border-color: transparent; + box-shadow: none; } + .button.is-success.is-inverted { + background-color: #fff; + color: #23d160; } + .button.is-success.is-inverted:hover { + background-color: #f2f2f2; } + .button.is-success.is-inverted[disabled] { + background-color: #fff; + border-color: transparent; + box-shadow: none; + color: #23d160; } + .button.is-success.is-loading::after { + border-color: transparent transparent #fff #fff !important; } + .button.is-success.is-outlined { + background-color: transparent; + border-color: #23d160; + color: #23d160; } + .button.is-success.is-outlined:hover, .button.is-success.is-outlined:focus { + background-color: #23d160; + border-color: #23d160; + color: #fff; } + .button.is-success.is-outlined.is-loading::after { + border-color: transparent transparent #23d160 #23d160 !important; } + .button.is-success.is-outlined[disabled] { + background-color: transparent; + border-color: #23d160; + box-shadow: none; + color: #23d160; } + .button.is-success.is-inverted.is-outlined { + background-color: transparent; + border-color: #fff; + color: #fff; } + .button.is-success.is-inverted.is-outlined:hover, .button.is-success.is-inverted.is-outlined:focus { + background-color: #fff; + color: #23d160; } + .button.is-success.is-inverted.is-outlined[disabled] { + background-color: transparent; + border-color: #fff; + box-shadow: none; + color: #fff; } + .button.is-warning { + background-color: #ffdd57; + border-color: transparent; + color: rgba(0, 0, 0, 0.7); } + .button.is-warning:hover, .button.is-warning.is-hovered { + background-color: #ffdb4a; + border-color: transparent; + color: rgba(0, 0, 0, 0.7); } + .button.is-warning:focus, .button.is-warning.is-focused { + border-color: transparent; + color: rgba(0, 0, 0, 0.7); } + .button.is-warning:focus:not(:active), .button.is-warning.is-focused:not(:active) { + box-shadow: 0 0 0 0.125em rgba(255, 221, 87, 0.25); } + .button.is-warning:active, .button.is-warning.is-active { + background-color: #ffd83d; + border-color: transparent; + color: rgba(0, 0, 0, 0.7); } + .button.is-warning[disabled] { + background-color: #ffdd57; + border-color: transparent; + box-shadow: none; } + .button.is-warning.is-inverted { + background-color: rgba(0, 0, 0, 0.7); + color: #ffdd57; } + .button.is-warning.is-inverted:hover { + background-color: rgba(0, 0, 0, 0.7); } + .button.is-warning.is-inverted[disabled] { + background-color: rgba(0, 0, 0, 0.7); + border-color: transparent; + box-shadow: none; + color: #ffdd57; } + .button.is-warning.is-loading::after { + border-color: transparent transparent rgba(0, 0, 0, 0.7) rgba(0, 0, 0, 0.7) !important; } + .button.is-warning.is-outlined { + background-color: transparent; + border-color: #ffdd57; + color: #ffdd57; } + .button.is-warning.is-outlined:hover, .button.is-warning.is-outlined:focus { + background-color: #ffdd57; + border-color: #ffdd57; + color: rgba(0, 0, 0, 0.7); } + .button.is-warning.is-outlined.is-loading::after { + border-color: transparent transparent #ffdd57 #ffdd57 !important; } + .button.is-warning.is-outlined[disabled] { + background-color: transparent; + border-color: #ffdd57; + box-shadow: none; + color: #ffdd57; } + .button.is-warning.is-inverted.is-outlined { + background-color: transparent; + border-color: rgba(0, 0, 0, 0.7); + color: rgba(0, 0, 0, 0.7); } + .button.is-warning.is-inverted.is-outlined:hover, .button.is-warning.is-inverted.is-outlined:focus { + background-color: rgba(0, 0, 0, 0.7); + color: #ffdd57; } + .button.is-warning.is-inverted.is-outlined[disabled] { + background-color: transparent; + border-color: rgba(0, 0, 0, 0.7); + box-shadow: none; + color: rgba(0, 0, 0, 0.7); } + .button.is-danger { + background-color: #ff3860; + border-color: transparent; + color: #fff; } + .button.is-danger:hover, .button.is-danger.is-hovered { + background-color: #ff2b56; + border-color: transparent; + color: #fff; } + .button.is-danger:focus, .button.is-danger.is-focused { + border-color: transparent; + color: #fff; } + .button.is-danger:focus:not(:active), .button.is-danger.is-focused:not(:active) { + box-shadow: 0 0 0 0.125em rgba(255, 56, 96, 0.25); } + .button.is-danger:active, .button.is-danger.is-active { + background-color: #ff1f4b; + border-color: transparent; + color: #fff; } + .button.is-danger[disabled] { + background-color: #ff3860; + border-color: transparent; + box-shadow: none; } + .button.is-danger.is-inverted { + background-color: #fff; + color: #ff3860; } + .button.is-danger.is-inverted:hover { + background-color: #f2f2f2; } + .button.is-danger.is-inverted[disabled] { + background-color: #fff; + border-color: transparent; + box-shadow: none; + color: #ff3860; } + .button.is-danger.is-loading::after { + border-color: transparent transparent #fff #fff !important; } + .button.is-danger.is-outlined { + background-color: transparent; + border-color: #ff3860; + color: #ff3860; } + .button.is-danger.is-outlined:hover, .button.is-danger.is-outlined:focus { + background-color: #ff3860; + border-color: #ff3860; + color: #fff; } + .button.is-danger.is-outlined.is-loading::after { + border-color: transparent transparent #ff3860 #ff3860 !important; } + .button.is-danger.is-outlined[disabled] { + background-color: transparent; + border-color: #ff3860; + box-shadow: none; + color: #ff3860; } + .button.is-danger.is-inverted.is-outlined { + background-color: transparent; + border-color: #fff; + color: #fff; } + .button.is-danger.is-inverted.is-outlined:hover, .button.is-danger.is-inverted.is-outlined:focus { + background-color: #fff; + color: #ff3860; } + .button.is-danger.is-inverted.is-outlined[disabled] { + background-color: transparent; + border-color: #fff; + box-shadow: none; + color: #fff; } + .button.is-small { + border-radius: 2px; + font-size: 0.75rem; } + .button.is-medium { + font-size: 1.25rem; } + .button.is-large { + font-size: 1.5rem; } + .button[disabled] { + background-color: white; + border-color: #dbdbdb; + box-shadow: none; + opacity: 0.5; } + .button.is-fullwidth { + display: flex; + width: 100%; } + .button.is-loading { + color: transparent !important; + pointer-events: none; } + .button.is-loading::after { + position: absolute; + left: calc(50% - (1em / 2)); + top: calc(50% - (1em / 2)); + position: absolute !important; } + .button.is-static { + background-color: whitesmoke; + border-color: #dbdbdb; + color: #7a7a7a; + box-shadow: none; + pointer-events: none; } + .button.is-rounded { + border-radius: 290486px; + padding-left: 1em; + padding-right: 1em; } + +.buttons { + align-items: center; + display: flex; + flex-wrap: wrap; + justify-content: flex-start; } + .buttons .button { + margin-bottom: 0.5rem; } + .buttons .button:not(:last-child) { + margin-right: 0.5rem; } + .buttons:last-child { + margin-bottom: -0.5rem; } + .buttons:not(:last-child) { + margin-bottom: 1rem; } + .buttons.has-addons .button:not(:first-child) { + border-bottom-left-radius: 0; + border-top-left-radius: 0; } + .buttons.has-addons .button:not(:last-child) { + border-bottom-right-radius: 0; + border-top-right-radius: 0; + margin-right: -1px; } + .buttons.has-addons .button:last-child { + margin-right: 0; } + .buttons.has-addons .button:hover, .buttons.has-addons .button.is-hovered { + z-index: 2; } + .buttons.has-addons .button:focus, .buttons.has-addons .button.is-focused, .buttons.has-addons .button:active, .buttons.has-addons .button.is-active, .buttons.has-addons .button.is-selected { + z-index: 3; } + .buttons.has-addons .button:focus:hover, .buttons.has-addons .button.is-focused:hover, .buttons.has-addons .button:active:hover, .buttons.has-addons .button.is-active:hover, .buttons.has-addons .button.is-selected:hover { + z-index: 4; } + .buttons.has-addons .button.is-expanded { + flex-grow: 1; } + .buttons.is-centered { + justify-content: center; } + .buttons.is-right { + justify-content: flex-end; } + +.container { + margin: 0 auto; + position: relative; } + @media screen and (min-width: 1088px) { + .container { + max-width: 960px; + width: 960px; } + .container.is-fluid { + margin-left: 64px; + margin-right: 64px; + max-width: none; + width: auto; } } + @media screen and (max-width: 1279px) { + .container.is-widescreen { + max-width: 1152px; + width: auto; } } + @media screen and (min-width: 1280px) { + .container { + max-width: 1152px; + width: 1152px; } } +.content li + li { + margin-top: 0.25em; } + +.content p:not(:last-child), +.content dl:not(:last-child), +.content ol:not(:last-child), +.content ul:not(:last-child), +.content blockquote:not(:last-child), +.content pre:not(:last-child), +.content table:not(:last-child) { + margin-bottom: 1em; } + +.content h1, +.content h2, +.content h3, +.content h4, +.content h5, +.content h6 { + color: #363636; + font-weight: 600; + line-height: 1.125; } + +.content h1 { + font-size: 2em; + margin-bottom: 0.5em; } + .content h1:not(:first-child) { + margin-top: 1em; } + +.content h2 { + font-size: 1.75em; + margin-bottom: 0.5714em; } + .content h2:not(:first-child) { + margin-top: 1.1428em; } + +.content h3 { + font-size: 1.5em; + margin-bottom: 0.6666em; } + .content h3:not(:first-child) { + margin-top: 1.3333em; } + +.content h4 { + font-size: 1.25em; + margin-bottom: 0.8em; } + +.content h5 { + font-size: 1.125em; + margin-bottom: 0.8888em; } + +.content h6 { + font-size: 1em; + margin-bottom: 1em; } + +.content blockquote { + background-color: whitesmoke; + border-left: 5px solid #dbdbdb; + padding: 1.25em 1.5em; } + +.content ol { + list-style: decimal outside; + margin-left: 2em; + margin-top: 1em; } + +.content ul { + list-style: disc outside; + margin-left: 2em; + margin-top: 1em; } + .content ul ul { + list-style-type: circle; + margin-top: 0.5em; } + .content ul ul ul { + list-style-type: square; } + +.content dd { + margin-left: 2em; } + +.content figure { + margin-left: 2em; + margin-right: 2em; + text-align: center; } + .content figure:not(:first-child) { + margin-top: 2em; } + .content figure:not(:last-child) { + margin-bottom: 2em; } + .content figure img { + display: inline-block; } + .content figure figcaption { + font-style: italic; } + +.content pre { + -webkit-overflow-scrolling: touch; + overflow-x: auto; + padding: 1.25em 1.5em; + white-space: pre; + word-wrap: normal; } + +.content sup, +.content sub { + font-size: 75%; } + +.content table { + width: 100%; } + .content table td, + .content table th { + border: 1px solid #dbdbdb; + border-width: 0 0 1px; + padding: 0.5em 0.75em; + vertical-align: top; } + .content table th { + color: #363636; + text-align: left; } + .content table thead td, + .content table thead th { + border-width: 0 0 2px; + color: #363636; } + .content table tfoot td, + .content table tfoot th { + border-width: 2px 0 0; + color: #363636; } + .content table tbody tr:last-child td, + .content table tbody tr:last-child th { + border-bottom-width: 0; } + +.content.is-small { + font-size: 0.75rem; } + +.content.is-medium { + font-size: 1.25rem; } + +.content.is-large { + font-size: 1.5rem; } + +.input, +.textarea { + background-color: white; + border-color: #dbdbdb; + color: #363636; + box-shadow: inset 0 1px 2px rgba(10, 10, 10, 0.1); + max-width: 100%; + width: 100%; } + .input::-moz-placeholder, + .textarea::-moz-placeholder { + color: rgba(54, 54, 54, 0.3); } + .input::-webkit-input-placeholder, + .textarea::-webkit-input-placeholder { + color: rgba(54, 54, 54, 0.3); } + .input:-moz-placeholder, + .textarea:-moz-placeholder { + color: rgba(54, 54, 54, 0.3); } + .input:-ms-input-placeholder, + .textarea:-ms-input-placeholder { + color: rgba(54, 54, 54, 0.3); } + .input:hover, .input.is-hovered, + .textarea:hover, + .textarea.is-hovered { + border-color: #b5b5b5; } + .input:focus, .input.is-focused, .input:active, .input.is-active, + .textarea:focus, + .textarea.is-focused, + .textarea:active, + .textarea.is-active { + border-color: #3273dc; + box-shadow: 0 0 0 0.125em rgba(50, 115, 220, 0.25); } + .input[disabled], + .textarea[disabled] { + background-color: whitesmoke; + border-color: whitesmoke; + box-shadow: none; + color: #7a7a7a; } + .input[disabled]::-moz-placeholder, + .textarea[disabled]::-moz-placeholder { + color: rgba(122, 122, 122, 0.3); } + .input[disabled]::-webkit-input-placeholder, + .textarea[disabled]::-webkit-input-placeholder { + color: rgba(122, 122, 122, 0.3); } + .input[disabled]:-moz-placeholder, + .textarea[disabled]:-moz-placeholder { + color: rgba(122, 122, 122, 0.3); } + .input[disabled]:-ms-input-placeholder, + .textarea[disabled]:-ms-input-placeholder { + color: rgba(122, 122, 122, 0.3); } + .input[readonly], + .textarea[readonly] { + box-shadow: none; } + .input.is-white, + .textarea.is-white { + border-color: white; } + .input.is-white:focus, .input.is-white.is-focused, .input.is-white:active, .input.is-white.is-active, + .textarea.is-white:focus, + .textarea.is-white.is-focused, + .textarea.is-white:active, + .textarea.is-white.is-active { + box-shadow: 0 0 0 0.125em rgba(255, 255, 255, 0.25); } + .input.is-black, + .textarea.is-black { + border-color: #0a0a0a; } + .input.is-black:focus, .input.is-black.is-focused, .input.is-black:active, .input.is-black.is-active, + .textarea.is-black:focus, + .textarea.is-black.is-focused, + .textarea.is-black:active, + .textarea.is-black.is-active { + box-shadow: 0 0 0 0.125em rgba(10, 10, 10, 0.25); } + .input.is-light, + .textarea.is-light { + border-color: whitesmoke; } + .input.is-light:focus, .input.is-light.is-focused, .input.is-light:active, .input.is-light.is-active, + .textarea.is-light:focus, + .textarea.is-light.is-focused, + .textarea.is-light:active, + .textarea.is-light.is-active { + box-shadow: 0 0 0 0.125em rgba(245, 245, 245, 0.25); } + .input.is-dark, + .textarea.is-dark { + border-color: #363636; } + .input.is-dark:focus, .input.is-dark.is-focused, .input.is-dark:active, .input.is-dark.is-active, + .textarea.is-dark:focus, + .textarea.is-dark.is-focused, + .textarea.is-dark:active, + .textarea.is-dark.is-active { + box-shadow: 0 0 0 0.125em rgba(54, 54, 54, 0.25); } + .input.is-primary, + .textarea.is-primary { + border-color: #00d1b2; } + .input.is-primary:focus, .input.is-primary.is-focused, .input.is-primary:active, .input.is-primary.is-active, + .textarea.is-primary:focus, + .textarea.is-primary.is-focused, + .textarea.is-primary:active, + .textarea.is-primary.is-active { + box-shadow: 0 0 0 0.125em rgba(0, 209, 178, 0.25); } + .input.is-link, + .textarea.is-link { + border-color: #3273dc; } + .input.is-link:focus, .input.is-link.is-focused, .input.is-link:active, .input.is-link.is-active, + .textarea.is-link:focus, + .textarea.is-link.is-focused, + .textarea.is-link:active, + .textarea.is-link.is-active { + box-shadow: 0 0 0 0.125em rgba(50, 115, 220, 0.25); } + .input.is-info, + .textarea.is-info { + border-color: #209cee; } + .input.is-info:focus, .input.is-info.is-focused, .input.is-info:active, .input.is-info.is-active, + .textarea.is-info:focus, + .textarea.is-info.is-focused, + .textarea.is-info:active, + .textarea.is-info.is-active { + box-shadow: 0 0 0 0.125em rgba(32, 156, 238, 0.25); } + .input.is-success, + .textarea.is-success { + border-color: #23d160; } + .input.is-success:focus, .input.is-success.is-focused, .input.is-success:active, .input.is-success.is-active, + .textarea.is-success:focus, + .textarea.is-success.is-focused, + .textarea.is-success:active, + .textarea.is-success.is-active { + box-shadow: 0 0 0 0.125em rgba(35, 209, 96, 0.25); } + .input.is-warning, + .textarea.is-warning { + border-color: #ffdd57; } + .input.is-warning:focus, .input.is-warning.is-focused, .input.is-warning:active, .input.is-warning.is-active, + .textarea.is-warning:focus, + .textarea.is-warning.is-focused, + .textarea.is-warning:active, + .textarea.is-warning.is-active { + box-shadow: 0 0 0 0.125em rgba(255, 221, 87, 0.25); } + .input.is-danger, + .textarea.is-danger { + border-color: #ff3860; } + .input.is-danger:focus, .input.is-danger.is-focused, .input.is-danger:active, .input.is-danger.is-active, + .textarea.is-danger:focus, + .textarea.is-danger.is-focused, + .textarea.is-danger:active, + .textarea.is-danger.is-active { + box-shadow: 0 0 0 0.125em rgba(255, 56, 96, 0.25); } + .input.is-small, + .textarea.is-small { + border-radius: 2px; + font-size: 0.75rem; } + .input.is-medium, + .textarea.is-medium { + font-size: 1.25rem; } + .input.is-large, + .textarea.is-large { + font-size: 1.5rem; } + .input.is-fullwidth, + .textarea.is-fullwidth { + display: block; + width: 100%; } + .input.is-inline, + .textarea.is-inline { + display: inline; + width: auto; } + +.input.is-rounded { + border-radius: 290486px; + padding-left: 1em; + padding-right: 1em; } + +.input.is-static { + background-color: transparent; + border-color: transparent; + box-shadow: none; + padding-left: 0; + padding-right: 0; } + +.textarea { + display: block; + max-width: 100%; + min-width: 100%; + padding: 0.625em; + resize: vertical; } + .textarea:not([rows]) { + max-height: 600px; + min-height: 120px; } + .textarea[rows] { + height: initial; } + .textarea.has-fixed-size { + resize: none; } + +.checkbox, +.radio { + cursor: pointer; + display: inline-block; + line-height: 1.25; + position: relative; } + .checkbox input, + .radio input { + cursor: pointer; } + .checkbox:hover, + .radio:hover { + color: #363636; } + .checkbox[disabled], + .radio[disabled] { + color: #7a7a7a; + cursor: not-allowed; } + +.radio + .radio { + margin-left: 0.5em; } + +.select { + display: inline-block; + max-width: 100%; + position: relative; + vertical-align: top; } + .select:not(.is-multiple) { + height: 2.25em; } + .select:not(.is-multiple):not(.is-loading)::after { + border-color: #3273dc; + right: 1.125em; + z-index: 4; } + .select.is-rounded select { + border-radius: 290486px; + padding-left: 1em; } + .select select { + background-color: white; + border-color: #dbdbdb; + color: #363636; + cursor: pointer; + display: block; + font-size: 1em; + max-width: 100%; + outline: none; } + .select select::-moz-placeholder { + color: rgba(54, 54, 54, 0.3); } + .select select::-webkit-input-placeholder { + color: rgba(54, 54, 54, 0.3); } + .select select:-moz-placeholder { + color: rgba(54, 54, 54, 0.3); } + .select select:-ms-input-placeholder { + color: rgba(54, 54, 54, 0.3); } + .select select:hover, .select select.is-hovered { + border-color: #b5b5b5; } + .select select:focus, .select select.is-focused, .select select:active, .select select.is-active { + border-color: #3273dc; + box-shadow: 0 0 0 0.125em rgba(50, 115, 220, 0.25); } + .select select[disabled] { + background-color: whitesmoke; + border-color: whitesmoke; + box-shadow: none; + color: #7a7a7a; } + .select select[disabled]::-moz-placeholder { + color: rgba(122, 122, 122, 0.3); } + .select select[disabled]::-webkit-input-placeholder { + color: rgba(122, 122, 122, 0.3); } + .select select[disabled]:-moz-placeholder { + color: rgba(122, 122, 122, 0.3); } + .select select[disabled]:-ms-input-placeholder { + color: rgba(122, 122, 122, 0.3); } + .select select::-ms-expand { + display: none; } + .select select[disabled]:hover { + border-color: whitesmoke; } + .select select:not([multiple]) { + padding-right: 2.5em; } + .select select[multiple] { + height: initial; + padding: 0; } + .select select[multiple] option { + padding: 0.5em 1em; } + .select:not(.is-multiple):not(.is-loading):hover::after { + border-color: #363636; } + .select.is-white:not(:hover)::after { + border-color: white; } + .select.is-white select { + border-color: white; } + .select.is-white select:hover, .select.is-white select.is-hovered { + border-color: #f2f2f2; } + .select.is-white select:focus, .select.is-white select.is-focused, .select.is-white select:active, .select.is-white select.is-active { + box-shadow: 0 0 0 0.125em rgba(255, 255, 255, 0.25); } + .select.is-black:not(:hover)::after { + border-color: #0a0a0a; } + .select.is-black select { + border-color: #0a0a0a; } + .select.is-black select:hover, .select.is-black select.is-hovered { + border-color: black; } + .select.is-black select:focus, .select.is-black select.is-focused, .select.is-black select:active, .select.is-black select.is-active { + box-shadow: 0 0 0 0.125em rgba(10, 10, 10, 0.25); } + .select.is-light:not(:hover)::after { + border-color: whitesmoke; } + .select.is-light select { + border-color: whitesmoke; } + .select.is-light select:hover, .select.is-light select.is-hovered { + border-color: #e8e8e8; } + .select.is-light select:focus, .select.is-light select.is-focused, .select.is-light select:active, .select.is-light select.is-active { + box-shadow: 0 0 0 0.125em rgba(245, 245, 245, 0.25); } + .select.is-dark:not(:hover)::after { + border-color: #363636; } + .select.is-dark select { + border-color: #363636; } + .select.is-dark select:hover, .select.is-dark select.is-hovered { + border-color: #292929; } + .select.is-dark select:focus, .select.is-dark select.is-focused, .select.is-dark select:active, .select.is-dark select.is-active { + box-shadow: 0 0 0 0.125em rgba(54, 54, 54, 0.25); } + .select.is-primary:not(:hover)::after { + border-color: #00d1b2; } + .select.is-primary select { + border-color: #00d1b2; } + .select.is-primary select:hover, .select.is-primary select.is-hovered { + border-color: #00b89c; } + .select.is-primary select:focus, .select.is-primary select.is-focused, .select.is-primary select:active, .select.is-primary select.is-active { + box-shadow: 0 0 0 0.125em rgba(0, 209, 178, 0.25); } + .select.is-link:not(:hover)::after { + border-color: #3273dc; } + .select.is-link select { + border-color: #3273dc; } + .select.is-link select:hover, .select.is-link select.is-hovered { + border-color: #2366d1; } + .select.is-link select:focus, .select.is-link select.is-focused, .select.is-link select:active, .select.is-link select.is-active { + box-shadow: 0 0 0 0.125em rgba(50, 115, 220, 0.25); } + .select.is-info:not(:hover)::after { + border-color: #209cee; } + .select.is-info select { + border-color: #209cee; } + .select.is-info select:hover, .select.is-info select.is-hovered { + border-color: #118fe4; } + .select.is-info select:focus, .select.is-info select.is-focused, .select.is-info select:active, .select.is-info select.is-active { + box-shadow: 0 0 0 0.125em rgba(32, 156, 238, 0.25); } + .select.is-success:not(:hover)::after { + border-color: #23d160; } + .select.is-success select { + border-color: #23d160; } + .select.is-success select:hover, .select.is-success select.is-hovered { + border-color: #20bc56; } + .select.is-success select:focus, .select.is-success select.is-focused, .select.is-success select:active, .select.is-success select.is-active { + box-shadow: 0 0 0 0.125em rgba(35, 209, 96, 0.25); } + .select.is-warning:not(:hover)::after { + border-color: #ffdd57; } + .select.is-warning select { + border-color: #ffdd57; } + .select.is-warning select:hover, .select.is-warning select.is-hovered { + border-color: #ffd83d; } + .select.is-warning select:focus, .select.is-warning select.is-focused, .select.is-warning select:active, .select.is-warning select.is-active { + box-shadow: 0 0 0 0.125em rgba(255, 221, 87, 0.25); } + .select.is-danger:not(:hover)::after { + border-color: #ff3860; } + .select.is-danger select { + border-color: #ff3860; } + .select.is-danger select:hover, .select.is-danger select.is-hovered { + border-color: #ff1f4b; } + .select.is-danger select:focus, .select.is-danger select.is-focused, .select.is-danger select:active, .select.is-danger select.is-active { + box-shadow: 0 0 0 0.125em rgba(255, 56, 96, 0.25); } + .select.is-small { + border-radius: 2px; + font-size: 0.75rem; } + .select.is-medium { + font-size: 1.25rem; } + .select.is-large { + font-size: 1.5rem; } + .select.is-disabled::after { + border-color: #7a7a7a; } + .select.is-fullwidth { + width: 100%; } + .select.is-fullwidth select { + width: 100%; } + .select.is-loading::after { + margin-top: 0; + position: absolute; + right: 0.625em; + top: 0.625em; + transform: none; } + .select.is-loading.is-small:after { + font-size: 0.75rem; } + .select.is-loading.is-medium:after { + font-size: 1.25rem; } + .select.is-loading.is-large:after { + font-size: 1.5rem; } + +.file { + align-items: stretch; + display: flex; + justify-content: flex-start; + position: relative; } + .file.is-white .file-cta { + background-color: white; + border-color: transparent; + color: #0a0a0a; } + .file.is-white:hover .file-cta, .file.is-white.is-hovered .file-cta { + background-color: #f9f9f9; + border-color: transparent; + color: #0a0a0a; } + .file.is-white:focus .file-cta, .file.is-white.is-focused .file-cta { + border-color: transparent; + box-shadow: 0 0 0.5em rgba(255, 255, 255, 0.25); + color: #0a0a0a; } + .file.is-white:active .file-cta, .file.is-white.is-active .file-cta { + background-color: #f2f2f2; + border-color: transparent; + color: #0a0a0a; } + .file.is-black .file-cta { + background-color: #0a0a0a; + border-color: transparent; + color: white; } + .file.is-black:hover .file-cta, .file.is-black.is-hovered .file-cta { + background-color: #040404; + border-color: transparent; + color: white; } + .file.is-black:focus .file-cta, .file.is-black.is-focused .file-cta { + border-color: transparent; + box-shadow: 0 0 0.5em rgba(10, 10, 10, 0.25); + color: white; } + .file.is-black:active .file-cta, .file.is-black.is-active .file-cta { + background-color: black; + border-color: transparent; + color: white; } + .file.is-light .file-cta { + background-color: whitesmoke; + border-color: transparent; + color: #363636; } + .file.is-light:hover .file-cta, .file.is-light.is-hovered .file-cta { + background-color: #eeeeee; + border-color: transparent; + color: #363636; } + .file.is-light:focus .file-cta, .file.is-light.is-focused .file-cta { + border-color: transparent; + box-shadow: 0 0 0.5em rgba(245, 245, 245, 0.25); + color: #363636; } + .file.is-light:active .file-cta, .file.is-light.is-active .file-cta { + background-color: #e8e8e8; + border-color: transparent; + color: #363636; } + .file.is-dark .file-cta { + background-color: #363636; + border-color: transparent; + color: whitesmoke; } + .file.is-dark:hover .file-cta, .file.is-dark.is-hovered .file-cta { + background-color: #2f2f2f; + border-color: transparent; + color: whitesmoke; } + .file.is-dark:focus .file-cta, .file.is-dark.is-focused .file-cta { + border-color: transparent; + box-shadow: 0 0 0.5em rgba(54, 54, 54, 0.25); + color: whitesmoke; } + .file.is-dark:active .file-cta, .file.is-dark.is-active .file-cta { + background-color: #292929; + border-color: transparent; + color: whitesmoke; } + .file.is-primary .file-cta { + background-color: #00d1b2; + border-color: transparent; + color: #fff; } + .file.is-primary:hover .file-cta, .file.is-primary.is-hovered .file-cta { + background-color: #00c4a7; + border-color: transparent; + color: #fff; } + .file.is-primary:focus .file-cta, .file.is-primary.is-focused .file-cta { + border-color: transparent; + box-shadow: 0 0 0.5em rgba(0, 209, 178, 0.25); + color: #fff; } + .file.is-primary:active .file-cta, .file.is-primary.is-active .file-cta { + background-color: #00b89c; + border-color: transparent; + color: #fff; } + .file.is-link .file-cta { + background-color: #3273dc; + border-color: transparent; + color: #fff; } + .file.is-link:hover .file-cta, .file.is-link.is-hovered .file-cta { + background-color: #276cda; + border-color: transparent; + color: #fff; } + .file.is-link:focus .file-cta, .file.is-link.is-focused .file-cta { + border-color: transparent; + box-shadow: 0 0 0.5em rgba(50, 115, 220, 0.25); + color: #fff; } + .file.is-link:active .file-cta, .file.is-link.is-active .file-cta { + background-color: #2366d1; + border-color: transparent; + color: #fff; } + .file.is-info .file-cta { + background-color: #209cee; + border-color: transparent; + color: #fff; } + .file.is-info:hover .file-cta, .file.is-info.is-hovered .file-cta { + background-color: #1496ed; + border-color: transparent; + color: #fff; } + .file.is-info:focus .file-cta, .file.is-info.is-focused .file-cta { + border-color: transparent; + box-shadow: 0 0 0.5em rgba(32, 156, 238, 0.25); + color: #fff; } + .file.is-info:active .file-cta, .file.is-info.is-active .file-cta { + background-color: #118fe4; + border-color: transparent; + color: #fff; } + .file.is-success .file-cta { + background-color: #23d160; + border-color: transparent; + color: #fff; } + .file.is-success:hover .file-cta, .file.is-success.is-hovered .file-cta { + background-color: #22c65b; + border-color: transparent; + color: #fff; } + .file.is-success:focus .file-cta, .file.is-success.is-focused .file-cta { + border-color: transparent; + box-shadow: 0 0 0.5em rgba(35, 209, 96, 0.25); + color: #fff; } + .file.is-success:active .file-cta, .file.is-success.is-active .file-cta { + background-color: #20bc56; + border-color: transparent; + color: #fff; } + .file.is-warning .file-cta { + background-color: #ffdd57; + border-color: transparent; + color: rgba(0, 0, 0, 0.7); } + .file.is-warning:hover .file-cta, .file.is-warning.is-hovered .file-cta { + background-color: #ffdb4a; + border-color: transparent; + color: rgba(0, 0, 0, 0.7); } + .file.is-warning:focus .file-cta, .file.is-warning.is-focused .file-cta { + border-color: transparent; + box-shadow: 0 0 0.5em rgba(255, 221, 87, 0.25); + color: rgba(0, 0, 0, 0.7); } + .file.is-warning:active .file-cta, .file.is-warning.is-active .file-cta { + background-color: #ffd83d; + border-color: transparent; + color: rgba(0, 0, 0, 0.7); } + .file.is-danger .file-cta { + background-color: #ff3860; + border-color: transparent; + color: #fff; } + .file.is-danger:hover .file-cta, .file.is-danger.is-hovered .file-cta { + background-color: #ff2b56; + border-color: transparent; + color: #fff; } + .file.is-danger:focus .file-cta, .file.is-danger.is-focused .file-cta { + border-color: transparent; + box-shadow: 0 0 0.5em rgba(255, 56, 96, 0.25); + color: #fff; } + .file.is-danger:active .file-cta, .file.is-danger.is-active .file-cta { + background-color: #ff1f4b; + border-color: transparent; + color: #fff; } + .file.is-small { + font-size: 0.75rem; } + .file.is-medium { + font-size: 1.25rem; } + .file.is-medium .file-icon .fa { + font-size: 21px; } + .file.is-large { + font-size: 1.5rem; } + .file.is-large .file-icon .fa { + font-size: 28px; } + .file.has-name .file-cta { + border-bottom-right-radius: 0; + border-top-right-radius: 0; } + .file.has-name .file-name { + border-bottom-left-radius: 0; + border-top-left-radius: 0; } + .file.has-name.is-empty .file-cta { + border-radius: 4px; } + .file.has-name.is-empty .file-name { + display: none; } + .file.is-boxed .file-label { + flex-direction: column; } + .file.is-boxed .file-cta { + flex-direction: column; + height: auto; + padding: 1em 3em; } + .file.is-boxed .file-name { + border-width: 0 1px 1px; } + .file.is-boxed .file-icon { + height: 1.5em; + width: 1.5em; } + .file.is-boxed .file-icon .fa { + font-size: 21px; } + .file.is-boxed.is-small .file-icon .fa { + font-size: 14px; } + .file.is-boxed.is-medium .file-icon .fa { + font-size: 28px; } + .file.is-boxed.is-large .file-icon .fa { + font-size: 35px; } + .file.is-boxed.has-name .file-cta { + border-radius: 4px 4px 0 0; } + .file.is-boxed.has-name .file-name { + border-radius: 0 0 4px 4px; + border-width: 0 1px 1px; } + .file.is-centered { + justify-content: center; } + .file.is-fullwidth .file-label { + width: 100%; } + .file.is-fullwidth .file-name { + flex-grow: 1; + max-width: none; } + .file.is-right { + justify-content: flex-end; } + .file.is-right .file-cta { + border-radius: 0 4px 4px 0; } + .file.is-right .file-name { + border-radius: 4px 0 0 4px; + border-width: 1px 0 1px 1px; + order: -1; } + +.file-label { + align-items: stretch; + display: flex; + cursor: pointer; + justify-content: flex-start; + overflow: hidden; + position: relative; } + .file-label:hover .file-cta { + background-color: #eeeeee; + color: #363636; } + .file-label:hover .file-name { + border-color: #d5d5d5; } + .file-label:active .file-cta { + background-color: #e8e8e8; + color: #363636; } + .file-label:active .file-name { + border-color: #cfcfcf; } + +.file-input { + height: 0.01em; + left: 0; + outline: none; + position: absolute; + top: 0; + width: 0.01em; } + +.file-cta, +.file-name { + border-color: #dbdbdb; + border-radius: 4px; + font-size: 1em; + padding-left: 1em; + padding-right: 1em; + white-space: nowrap; } + +.file-cta { + background-color: whitesmoke; + color: #4a4a4a; } + +.file-name { + border-color: #dbdbdb; + border-style: solid; + border-width: 1px 1px 1px 0; + display: block; + max-width: 16em; + overflow: hidden; + text-align: left; + text-overflow: ellipsis; } + +.file-icon { + align-items: center; + display: flex; + height: 1em; + justify-content: center; + margin-right: 0.5em; + width: 1em; } + .file-icon .fa { + font-size: 14px; } + +.label { + color: #363636; + display: block; + font-size: 1rem; + font-weight: 700; } + .label:not(:last-child) { + margin-bottom: 0.5em; } + .label.is-small { + font-size: 0.75rem; } + .label.is-medium { + font-size: 1.25rem; } + .label.is-large { + font-size: 1.5rem; } + +.help { + display: block; + font-size: 0.75rem; + margin-top: 0.25rem; } + .help.is-white { + color: white; } + .help.is-black { + color: #0a0a0a; } + .help.is-light { + color: whitesmoke; } + .help.is-dark { + color: #363636; } + .help.is-primary { + color: #00d1b2; } + .help.is-link { + color: #3273dc; } + .help.is-info { + color: #209cee; } + .help.is-success { + color: #23d160; } + .help.is-warning { + color: #ffdd57; } + .help.is-danger { + color: #ff3860; } + +.field:not(:last-child) { + margin-bottom: 0.75rem; } + +.field.has-addons { + display: flex; + justify-content: flex-start; } + .field.has-addons .control:not(:last-child) { + margin-right: -1px; } + .field.has-addons .control:not(:first-child):not(:last-child) .button, + .field.has-addons .control:not(:first-child):not(:last-child) .input, + .field.has-addons .control:not(:first-child):not(:last-child) .select select { + border-radius: 0; } + .field.has-addons .control:first-child .button, + .field.has-addons .control:first-child .input, + .field.has-addons .control:first-child .select select { + border-bottom-right-radius: 0; + border-top-right-radius: 0; } + .field.has-addons .control:last-child .button, + .field.has-addons .control:last-child .input, + .field.has-addons .control:last-child .select select { + border-bottom-left-radius: 0; + border-top-left-radius: 0; } + .field.has-addons .control .button:hover, .field.has-addons .control .button.is-hovered, + .field.has-addons .control .input:hover, + .field.has-addons .control .input.is-hovered, + .field.has-addons .control .select select:hover, + .field.has-addons .control .select select.is-hovered { + z-index: 2; } + .field.has-addons .control .button:focus, .field.has-addons .control .button.is-focused, .field.has-addons .control .button:active, .field.has-addons .control .button.is-active, + .field.has-addons .control .input:focus, + .field.has-addons .control .input.is-focused, + .field.has-addons .control .input:active, + .field.has-addons .control .input.is-active, + .field.has-addons .control .select select:focus, + .field.has-addons .control .select select.is-focused, + .field.has-addons .control .select select:active, + .field.has-addons .control .select select.is-active { + z-index: 3; } + .field.has-addons .control .button:focus:hover, .field.has-addons .control .button.is-focused:hover, .field.has-addons .control .button:active:hover, .field.has-addons .control .button.is-active:hover, + .field.has-addons .control .input:focus:hover, + .field.has-addons .control .input.is-focused:hover, + .field.has-addons .control .input:active:hover, + .field.has-addons .control .input.is-active:hover, + .field.has-addons .control .select select:focus:hover, + .field.has-addons .control .select select.is-focused:hover, + .field.has-addons .control .select select:active:hover, + .field.has-addons .control .select select.is-active:hover { + z-index: 4; } + .field.has-addons .control.is-expanded { + flex-grow: 1; } + .field.has-addons.has-addons-centered { + justify-content: center; } + .field.has-addons.has-addons-right { + justify-content: flex-end; } + .field.has-addons.has-addons-fullwidth .control { + flex-grow: 1; + flex-shrink: 0; } + +.field.is-grouped { + display: flex; + justify-content: flex-start; } + .field.is-grouped > .control { + flex-shrink: 0; } + .field.is-grouped > .control:not(:last-child) { + margin-bottom: 0; + margin-right: 0.75rem; } + .field.is-grouped > .control.is-expanded { + flex-grow: 1; + flex-shrink: 1; } + .field.is-grouped.is-grouped-centered { + justify-content: center; } + .field.is-grouped.is-grouped-right { + justify-content: flex-end; } + .field.is-grouped.is-grouped-multiline { + flex-wrap: wrap; } + .field.is-grouped.is-grouped-multiline > .control:last-child, .field.is-grouped.is-grouped-multiline > .control:not(:last-child) { + margin-bottom: 0.75rem; } + .field.is-grouped.is-grouped-multiline:last-child { + margin-bottom: -0.75rem; } + .field.is-grouped.is-grouped-multiline:not(:last-child) { + margin-bottom: 0; } + +@media screen and (min-width: 769px), print { + .field.is-horizontal { + display: flex; } } + +.field-label .label { + font-size: inherit; } + +@media screen and (max-width: 768px) { + .field-label { + margin-bottom: 0.5rem; } } + +@media screen and (min-width: 769px), print { + .field-label { + flex-basis: 0; + flex-grow: 1; + flex-shrink: 0; + margin-right: 1.5rem; + text-align: right; } + .field-label.is-small { + font-size: 0.75rem; + padding-top: 0.375em; } + .field-label.is-normal { + padding-top: 0.375em; } + .field-label.is-medium { + font-size: 1.25rem; + padding-top: 0.375em; } + .field-label.is-large { + font-size: 1.5rem; + padding-top: 0.375em; } } + +.field-body .field .field { + margin-bottom: 0; } + +@media screen and (min-width: 769px), print { + .field-body { + display: flex; + flex-basis: 0; + flex-grow: 5; + flex-shrink: 1; } + .field-body .field { + margin-bottom: 0; } + .field-body > .field { + flex-shrink: 1; } + .field-body > .field:not(.is-narrow) { + flex-grow: 1; } + .field-body > .field:not(:last-child) { + margin-right: 0.75rem; } } + +.control { + font-size: 1rem; + position: relative; + text-align: left; } + .control.has-icon .icon { + color: #dbdbdb; + height: 2.25em; + pointer-events: none; + position: absolute; + top: 0; + width: 2.25em; + z-index: 4; } + .control.has-icon .input:focus + .icon { + color: #7a7a7a; } + .control.has-icon .input.is-small + .icon { + font-size: 0.75rem; } + .control.has-icon .input.is-medium + .icon { + font-size: 1.25rem; } + .control.has-icon .input.is-large + .icon { + font-size: 1.5rem; } + .control.has-icon:not(.has-icon-right) .icon { + left: 0; } + .control.has-icon:not(.has-icon-right) .input { + padding-left: 2.25em; } + .control.has-icon.has-icon-right .icon { + right: 0; } + .control.has-icon.has-icon-right .input { + padding-right: 2.25em; } + .control.has-icons-left .input:focus ~ .icon, + .control.has-icons-left .select:focus ~ .icon, .control.has-icons-right .input:focus ~ .icon, + .control.has-icons-right .select:focus ~ .icon { + color: #7a7a7a; } + .control.has-icons-left .input.is-small ~ .icon, + .control.has-icons-left .select.is-small ~ .icon, .control.has-icons-right .input.is-small ~ .icon, + .control.has-icons-right .select.is-small ~ .icon { + font-size: 0.75rem; } + .control.has-icons-left .input.is-medium ~ .icon, + .control.has-icons-left .select.is-medium ~ .icon, .control.has-icons-right .input.is-medium ~ .icon, + .control.has-icons-right .select.is-medium ~ .icon { + font-size: 1.25rem; } + .control.has-icons-left .input.is-large ~ .icon, + .control.has-icons-left .select.is-large ~ .icon, .control.has-icons-right .input.is-large ~ .icon, + .control.has-icons-right .select.is-large ~ .icon { + font-size: 1.5rem; } + .control.has-icons-left .icon, .control.has-icons-right .icon { + color: #dbdbdb; + height: 2.25em; + pointer-events: none; + position: absolute; + top: 0; + width: 2.25em; + z-index: 4; } + .control.has-icons-left .input, + .control.has-icons-left .select select { + padding-left: 2.25em; } + .control.has-icons-left .icon.is-left { + left: 0; } + .control.has-icons-right .input, + .control.has-icons-right .select select { + padding-right: 2.25em; } + .control.has-icons-right .icon.is-right { + right: 0; } + .control.is-loading::after { + position: absolute !important; + right: 0.625em; + top: 0.625em; + z-index: 4; } + .control.is-loading.is-small:after { + font-size: 0.75rem; } + .control.is-loading.is-medium:after { + font-size: 1.25rem; } + .control.is-loading.is-large:after { + font-size: 1.5rem; } + +.icon { + align-items: center; + display: inline-flex; + justify-content: center; + height: 1.5rem; + width: 1.5rem; } + .icon.is-small { + height: 1rem; + width: 1rem; } + .icon.is-medium { + height: 2rem; + width: 2rem; } + .icon.is-large { + height: 3rem; + width: 3rem; } + +.image { + display: block; + position: relative; } + .image img { + display: block; + height: auto; + width: 100%; } + .image img.is-rounded { + border-radius: 290486px; } + .image.is-square img, .image.is-1by1 img, .image.is-5by4 img, .image.is-4by3 img, .image.is-3by2 img, .image.is-5by3 img, .image.is-16by9 img, .image.is-2by1 img, .image.is-3by1 img, .image.is-4by5 img, .image.is-3by4 img, .image.is-2by3 img, .image.is-3by5 img, .image.is-9by16 img, .image.is-1by2 img, .image.is-1by3 img { + height: 100%; + width: 100%; } + .image.is-square, .image.is-1by1 { + padding-top: 100%; } + .image.is-5by4 { + padding-top: 80%; } + .image.is-4by3 { + padding-top: 75%; } + .image.is-3by2 { + padding-top: 66.6666%; } + .image.is-5by3 { + padding-top: 60%; } + .image.is-16by9 { + padding-top: 56.25%; } + .image.is-2by1 { + padding-top: 50%; } + .image.is-3by1 { + padding-top: 33.3333%; } + .image.is-4by5 { + padding-top: 125%; } + .image.is-3by4 { + padding-top: 133.3333%; } + .image.is-2by3 { + padding-top: 150%; } + .image.is-3by5 { + padding-top: 166.6666%; } + .image.is-9by16 { + padding-top: 177.7777%; } + .image.is-1by2 { + padding-top: 200%; } + .image.is-1by3 { + padding-top: 300%; } + .image.is-16x16 { + height: 16px; + width: 16px; } + .image.is-24x24 { + height: 24px; + width: 24px; } + .image.is-32x32 { + height: 32px; + width: 32px; } + .image.is-48x48 { + height: 48px; + width: 48px; } + .image.is-64x64 { + height: 64px; + width: 64px; } + .image.is-96x96 { + height: 96px; + width: 96px; } + .image.is-128x128 { + height: 128px; + width: 128px; } + +.notification { + background-color: whitesmoke; + border-radius: 4px; + padding: 1.25rem 2.5rem 1.25rem 1.5rem; + position: relative; } + .notification a:not(.button) { + color: currentColor; + text-decoration: underline; } + .notification strong { + color: currentColor; } + .notification code, + .notification pre { + background: white; } + .notification pre code { + background: transparent; } + .notification > .delete { + position: absolute; + right: 0.5rem; + top: 0.5rem; } + .notification .title, + .notification .subtitle, + .notification .content { + color: currentColor; } + .notification.is-white { + background-color: white; + color: #0a0a0a; } + .notification.is-black { + background-color: #0a0a0a; + color: white; } + .notification.is-light { + background-color: whitesmoke; + color: #363636; } + .notification.is-dark { + background-color: #363636; + color: whitesmoke; } + .notification.is-primary { + background-color: #00d1b2; + color: #fff; } + .notification.is-link { + background-color: #3273dc; + color: #fff; } + .notification.is-info { + background-color: #209cee; + color: #fff; } + .notification.is-success { + background-color: #23d160; + color: #fff; } + .notification.is-warning { + background-color: #ffdd57; + color: rgba(0, 0, 0, 0.7); } + .notification.is-danger { + background-color: #ff3860; + color: #fff; } + +.progress { + -moz-appearance: none; + -webkit-appearance: none; + border: none; + border-radius: 290486px; + display: block; + height: 1rem; + overflow: hidden; + padding: 0; + width: 100%; } + .progress::-webkit-progress-bar { + background-color: #dbdbdb; } + .progress::-webkit-progress-value { + background-color: #4a4a4a; } + .progress::-moz-progress-bar { + background-color: #4a4a4a; } + .progress::-ms-fill { + background-color: #4a4a4a; + border: none; } + .progress.is-white::-webkit-progress-value { + background-color: white; } + .progress.is-white::-moz-progress-bar { + background-color: white; } + .progress.is-white::-ms-fill { + background-color: white; } + .progress.is-black::-webkit-progress-value { + background-color: #0a0a0a; } + .progress.is-black::-moz-progress-bar { + background-color: #0a0a0a; } + .progress.is-black::-ms-fill { + background-color: #0a0a0a; } + .progress.is-light::-webkit-progress-value { + background-color: whitesmoke; } + .progress.is-light::-moz-progress-bar { + background-color: whitesmoke; } + .progress.is-light::-ms-fill { + background-color: whitesmoke; } + .progress.is-dark::-webkit-progress-value { + background-color: #363636; } + .progress.is-dark::-moz-progress-bar { + background-color: #363636; } + .progress.is-dark::-ms-fill { + background-color: #363636; } + .progress.is-primary::-webkit-progress-value { + background-color: #00d1b2; } + .progress.is-primary::-moz-progress-bar { + background-color: #00d1b2; } + .progress.is-primary::-ms-fill { + background-color: #00d1b2; } + .progress.is-link::-webkit-progress-value { + background-color: #3273dc; } + .progress.is-link::-moz-progress-bar { + background-color: #3273dc; } + .progress.is-link::-ms-fill { + background-color: #3273dc; } + .progress.is-info::-webkit-progress-value { + background-color: #209cee; } + .progress.is-info::-moz-progress-bar { + background-color: #209cee; } + .progress.is-info::-ms-fill { + background-color: #209cee; } + .progress.is-success::-webkit-progress-value { + background-color: #23d160; } + .progress.is-success::-moz-progress-bar { + background-color: #23d160; } + .progress.is-success::-ms-fill { + background-color: #23d160; } + .progress.is-warning::-webkit-progress-value { + background-color: #ffdd57; } + .progress.is-warning::-moz-progress-bar { + background-color: #ffdd57; } + .progress.is-warning::-ms-fill { + background-color: #ffdd57; } + .progress.is-danger::-webkit-progress-value { + background-color: #ff3860; } + .progress.is-danger::-moz-progress-bar { + background-color: #ff3860; } + .progress.is-danger::-ms-fill { + background-color: #ff3860; } + .progress.is-small { + height: 0.75rem; } + .progress.is-medium { + height: 1.25rem; } + .progress.is-large { + height: 1.5rem; } + +.table { + background-color: white; + color: #363636; } + .table td, + .table th { + border: 1px solid #dbdbdb; + border-width: 0 0 1px; + padding: 0.5em 0.75em; + vertical-align: top; } + .table td.is-white, + .table th.is-white { + background-color: white; + border-color: white; + color: #0a0a0a; } + .table td.is-black, + .table th.is-black { + background-color: #0a0a0a; + border-color: #0a0a0a; + color: white; } + .table td.is-light, + .table th.is-light { + background-color: whitesmoke; + border-color: whitesmoke; + color: #363636; } + .table td.is-dark, + .table th.is-dark { + background-color: #363636; + border-color: #363636; + color: whitesmoke; } + .table td.is-primary, + .table th.is-primary { + background-color: #00d1b2; + border-color: #00d1b2; + color: #fff; } + .table td.is-link, + .table th.is-link { + background-color: #3273dc; + border-color: #3273dc; + color: #fff; } + .table td.is-info, + .table th.is-info { + background-color: #209cee; + border-color: #209cee; + color: #fff; } + .table td.is-success, + .table th.is-success { + background-color: #23d160; + border-color: #23d160; + color: #fff; } + .table td.is-warning, + .table th.is-warning { + background-color: #ffdd57; + border-color: #ffdd57; + color: rgba(0, 0, 0, 0.7); } + .table td.is-danger, + .table th.is-danger { + background-color: #ff3860; + border-color: #ff3860; + color: #fff; } + .table td.is-narrow, + .table th.is-narrow { + white-space: nowrap; + width: 1%; } + .table td.is-selected, + .table th.is-selected { + background-color: #00d1b2; + color: #fff; } + .table td.is-selected a, + .table td.is-selected strong, + .table th.is-selected a, + .table th.is-selected strong { + color: currentColor; } + .table th { + color: #363636; + text-align: left; } + .table tr.is-selected { + background-color: #00d1b2; + color: #fff; } + .table tr.is-selected a, + .table tr.is-selected strong { + color: currentColor; } + .table tr.is-selected td, + .table tr.is-selected th { + border-color: #fff; + color: currentColor; } + .table thead td, + .table thead th { + border-width: 0 0 2px; + color: #363636; } + .table tfoot td, + .table tfoot th { + border-width: 2px 0 0; + color: #363636; } + .table tbody tr:last-child td, + .table tbody tr:last-child th { + border-bottom-width: 0; } + .table.is-bordered td, + .table.is-bordered th { + border-width: 1px; } + .table.is-bordered tr:last-child td, + .table.is-bordered tr:last-child th { + border-bottom-width: 1px; } + .table.is-fullwidth { + width: 100%; } + .table.is-hoverable tbody tr:not(.is-selected):hover { + background-color: #fafafa; } + .table.is-hoverable.is-striped tbody tr:not(.is-selected):hover { + background-color: whitesmoke; } + .table.is-narrow td, + .table.is-narrow th { + padding: 0.25em 0.5em; } + .table.is-striped tbody tr:not(.is-selected):nth-child(even) { + background-color: #fafafa; } + +.table-container { + -webkit-overflow-scrolling: touch; + overflow: auto; + overflow-y: hidden; + max-width: 100%; } + +.tags { + align-items: center; + display: flex; + flex-wrap: wrap; + justify-content: flex-start; } + .tags .tag { + margin-bottom: 0.5rem; } + .tags .tag:not(:last-child) { + margin-right: 0.5rem; } + .tags:last-child { + margin-bottom: -0.5rem; } + .tags:not(:last-child) { + margin-bottom: 1rem; } + .tags.has-addons .tag { + margin-right: 0; } + .tags.has-addons .tag:not(:first-child) { + border-bottom-left-radius: 0; + border-top-left-radius: 0; } + .tags.has-addons .tag:not(:last-child) { + border-bottom-right-radius: 0; + border-top-right-radius: 0; } + .tags.is-centered { + justify-content: center; } + .tags.is-centered .tag { + margin-right: 0.25rem; + margin-left: 0.25rem; } + .tags.is-right { + justify-content: flex-end; } + .tags.is-right .tag:not(:first-child) { + margin-left: 0.5rem; } + .tags.is-right .tag:not(:last-child) { + margin-right: 0; } + +.tag:not(body) { + align-items: center; + background-color: whitesmoke; + border-radius: 4px; + color: #4a4a4a; + display: inline-flex; + font-size: 0.75rem; + height: 2em; + justify-content: center; + line-height: 1.5; + padding-left: 0.75em; + padding-right: 0.75em; + white-space: nowrap; } + .tag:not(body) .delete { + margin-left: 0.25rem; + margin-right: -0.375rem; } + .tag:not(body).is-white { + background-color: white; + color: #0a0a0a; } + .tag:not(body).is-black { + background-color: #0a0a0a; + color: white; } + .tag:not(body).is-light { + background-color: whitesmoke; + color: #363636; } + .tag:not(body).is-dark { + background-color: #363636; + color: whitesmoke; } + .tag:not(body).is-primary { + background-color: #00d1b2; + color: #fff; } + .tag:not(body).is-link { + background-color: #3273dc; + color: #fff; } + .tag:not(body).is-info { + background-color: #209cee; + color: #fff; } + .tag:not(body).is-success { + background-color: #23d160; + color: #fff; } + .tag:not(body).is-warning { + background-color: #ffdd57; + color: rgba(0, 0, 0, 0.7); } + .tag:not(body).is-danger { + background-color: #ff3860; + color: #fff; } + .tag:not(body).is-medium { + font-size: 1rem; } + .tag:not(body).is-large { + font-size: 1.25rem; } + .tag:not(body) .icon:first-child:not(:last-child) { + margin-left: -0.375em; + margin-right: 0.1875em; } + .tag:not(body) .icon:last-child:not(:first-child) { + margin-left: 0.1875em; + margin-right: -0.375em; } + .tag:not(body) .icon:first-child:last-child { + margin-left: -0.375em; + margin-right: -0.375em; } + .tag:not(body).is-delete { + margin-left: 1px; + padding: 0; + position: relative; + width: 2em; } + .tag:not(body).is-delete::before, .tag:not(body).is-delete::after { + background-color: currentColor; + content: ""; + display: block; + left: 50%; + position: absolute; + top: 50%; + transform: translateX(-50%) translateY(-50%) rotate(45deg); + transform-origin: center center; } + .tag:not(body).is-delete::before { + height: 1px; + width: 50%; } + .tag:not(body).is-delete::after { + height: 50%; + width: 1px; } + .tag:not(body).is-delete:hover, .tag:not(body).is-delete:focus { + background-color: #e8e8e8; } + .tag:not(body).is-delete:active { + background-color: #dbdbdb; } + .tag:not(body).is-rounded { + border-radius: 290486px; } + +a.tag:hover { + text-decoration: underline; } + +.title, +.subtitle { + word-break: break-word; } + .title em, + .title span, + .subtitle em, + .subtitle span { + font-weight: inherit; } + .title sub, + .subtitle sub { + font-size: 0.75em; } + .title sup, + .subtitle sup { + font-size: 0.75em; } + .title .tag, + .subtitle .tag { + vertical-align: middle; } + +.title { + color: #363636; + font-size: 2rem; + font-weight: 600; + line-height: 1.125; } + .title strong { + color: inherit; + font-weight: inherit; } + .title + .highlight { + margin-top: -0.75rem; } + .title:not(.is-spaced) + .subtitle { + margin-top: -1.25rem; } + .title.is-1 { + font-size: 3rem; } + .title.is-2 { + font-size: 2.5rem; } + .title.is-3 { + font-size: 2rem; } + .title.is-4 { + font-size: 1.5rem; } + .title.is-5 { + font-size: 1.25rem; } + .title.is-6 { + font-size: 1rem; } + .title.is-7 { + font-size: 0.75rem; } + +.subtitle { + color: #4a4a4a; + font-size: 1.25rem; + font-weight: 400; + line-height: 1.25; } + .subtitle strong { + color: #363636; + font-weight: 600; } + .subtitle:not(.is-spaced) + .title { + margin-top: -1.25rem; } + .subtitle.is-1 { + font-size: 3rem; } + .subtitle.is-2 { + font-size: 2.5rem; } + .subtitle.is-3 { + font-size: 2rem; } + .subtitle.is-4 { + font-size: 1.5rem; } + .subtitle.is-5 { + font-size: 1.25rem; } + .subtitle.is-6 { + font-size: 1rem; } + .subtitle.is-7 { + font-size: 0.75rem; } + +.heading { + display: block; + font-size: 11px; + letter-spacing: 1px; + margin-bottom: 5px; + text-transform: uppercase; } + +.highlight { + font-weight: 400; + max-width: 100%; + overflow: hidden; + padding: 0; } + .highlight pre { + overflow: auto; + max-width: 100%; } + +.number { + align-items: center; + background-color: whitesmoke; + border-radius: 290486px; + display: inline-flex; + font-size: 1.25rem; + height: 2em; + justify-content: center; + margin-right: 1.5rem; + min-width: 2.5em; + padding: 0.25rem 0.5rem; + text-align: center; + vertical-align: top; } + +.breadcrumb { + font-size: 1rem; + white-space: nowrap; } + .breadcrumb a { + align-items: center; + color: #3273dc; + display: flex; + justify-content: center; + padding: 0 0.75em; } + .breadcrumb a:hover { + color: #363636; } + .breadcrumb li { + align-items: center; + display: flex; } + .breadcrumb li:first-child a { + padding-left: 0; } + .breadcrumb li.is-active a { + color: #363636; + cursor: default; + pointer-events: none; } + .breadcrumb li + li::before { + color: #b5b5b5; + content: "\0002f"; } + .breadcrumb ul, + .breadcrumb ol { + align-items: flex-start; + display: flex; + flex-wrap: wrap; + justify-content: flex-start; } + .breadcrumb .icon:first-child { + margin-right: 0.5em; } + .breadcrumb .icon:last-child { + margin-left: 0.5em; } + .breadcrumb.is-centered ol, + .breadcrumb.is-centered ul { + justify-content: center; } + .breadcrumb.is-right ol, + .breadcrumb.is-right ul { + justify-content: flex-end; } + .breadcrumb.is-small { + font-size: 0.75rem; } + .breadcrumb.is-medium { + font-size: 1.25rem; } + .breadcrumb.is-large { + font-size: 1.5rem; } + .breadcrumb.has-arrow-separator li + li::before { + content: "\02192"; } + .breadcrumb.has-bullet-separator li + li::before { + content: "\02022"; } + .breadcrumb.has-dot-separator li + li::before { + content: "\000b7"; } + .breadcrumb.has-succeeds-separator li + li::before { + content: "\0227B"; } + +.card { + background-color: white; + box-shadow: 0 2px 3px rgba(10, 10, 10, 0.1), 0 0 0 1px rgba(10, 10, 10, 0.1); + color: #4a4a4a; + max-width: 100%; + position: relative; } + +.card-header { + background-color: none; + align-items: stretch; + box-shadow: 0 1px 2px rgba(10, 10, 10, 0.1); + display: flex; } + +.card-header-title { + align-items: center; + color: #363636; + display: flex; + flex-grow: 1; + font-weight: 700; + padding: 0.75rem; } + .card-header-title.is-centered { + justify-content: center; } + +.card-header-icon { + align-items: center; + cursor: pointer; + display: flex; + justify-content: center; + padding: 0.75rem; } + +.card-image { + display: block; + position: relative; } + +.card-content { + background-color: none; + padding: 1.5rem; } + +.card-footer { + background-color: none; + border-top: 1px solid #dbdbdb; + align-items: stretch; + display: flex; } + +.card-footer-item { + align-items: center; + display: flex; + flex-basis: 0; + flex-grow: 1; + flex-shrink: 0; + justify-content: center; + padding: 0.75rem; } + .card-footer-item:not(:last-child) { + border-right: 1px solid #dbdbdb; } + +.card .media:not(:last-child) { + margin-bottom: 0.75rem; } + +.dropdown { + display: inline-flex; + position: relative; + vertical-align: top; } + .dropdown.is-active .dropdown-menu, .dropdown.is-hoverable:hover .dropdown-menu { + display: block; } + .dropdown.is-right .dropdown-menu { + left: auto; + right: 0; } + .dropdown.is-up .dropdown-menu { + bottom: 100%; + padding-bottom: 4px; + padding-top: initial; + top: auto; } + +.dropdown-menu { + display: none; + left: 0; + min-width: 12rem; + padding-top: 4px; + position: absolute; + top: 100%; + z-index: 20; } + +.dropdown-content { + background-color: white; + border-radius: 4px; + box-shadow: 0 2px 3px rgba(10, 10, 10, 0.1), 0 0 0 1px rgba(10, 10, 10, 0.1); + padding-bottom: 0.5rem; + padding-top: 0.5rem; } + +.dropdown-item { + color: #4a4a4a; + display: block; + font-size: 0.875rem; + line-height: 1.5; + padding: 0.375rem 1rem; + position: relative; } + +a.dropdown-item { + padding-right: 3rem; + white-space: nowrap; } + a.dropdown-item:hover { + background-color: whitesmoke; + color: #0a0a0a; } + a.dropdown-item.is-active { + background-color: #3273dc; + color: #fff; } + +.dropdown-divider { + background-color: #dbdbdb; + border: none; + display: block; + height: 1px; + margin: 0.5rem 0; } + +.level { + align-items: center; + justify-content: space-between; } + .level code { + border-radius: 4px; } + .level img { + display: inline-block; + vertical-align: top; } + .level.is-mobile { + display: flex; } + .level.is-mobile .level-left, + .level.is-mobile .level-right { + display: flex; } + .level.is-mobile .level-left + .level-right { + margin-top: 0; } + .level.is-mobile .level-item { + margin-right: 0.75rem; } + .level.is-mobile .level-item:not(:last-child) { + margin-bottom: 0; } + .level.is-mobile .level-item:not(.is-narrow) { + flex-grow: 1; } + @media screen and (min-width: 769px), print { + .level { + display: flex; } + .level > .level-item:not(.is-narrow) { + flex-grow: 1; } } +.level-item { + align-items: center; + display: flex; + flex-basis: auto; + flex-grow: 0; + flex-shrink: 0; + justify-content: center; } + .level-item .title, + .level-item .subtitle { + margin-bottom: 0; } + @media screen and (max-width: 768px) { + .level-item:not(:last-child) { + margin-bottom: 0.75rem; } } +.level-left, +.level-right { + flex-basis: auto; + flex-grow: 0; + flex-shrink: 0; } + .level-left .level-item.is-flexible, + .level-right .level-item.is-flexible { + flex-grow: 1; } + @media screen and (min-width: 769px), print { + .level-left .level-item:not(:last-child), + .level-right .level-item:not(:last-child) { + margin-right: 0.75rem; } } +.level-left { + align-items: center; + justify-content: flex-start; } + @media screen and (max-width: 768px) { + .level-left + .level-right { + margin-top: 1.5rem; } } + @media screen and (min-width: 769px), print { + .level-left { + display: flex; } } +.level-right { + align-items: center; + justify-content: flex-end; } + @media screen and (min-width: 769px), print { + .level-right { + display: flex; } } +.media { + align-items: flex-start; + display: flex; + text-align: left; } + .media .content:not(:last-child) { + margin-bottom: 0.75rem; } + .media .media { + border-top: 1px solid rgba(219, 219, 219, 0.5); + display: flex; + padding-top: 0.75rem; } + .media .media .content:not(:last-child), + .media .media .control:not(:last-child) { + margin-bottom: 0.5rem; } + .media .media .media { + padding-top: 0.5rem; } + .media .media .media + .media { + margin-top: 0.5rem; } + .media + .media { + border-top: 1px solid rgba(219, 219, 219, 0.5); + margin-top: 1rem; + padding-top: 1rem; } + .media.is-large + .media { + margin-top: 1.5rem; + padding-top: 1.5rem; } + +.media-left, +.media-right { + flex-basis: auto; + flex-grow: 0; + flex-shrink: 0; } + +.media-left { + margin-right: 1rem; } + +.media-right { + margin-left: 1rem; } + +.media-content { + flex-basis: auto; + flex-grow: 1; + flex-shrink: 1; + text-align: left; } + +.menu { + font-size: 1rem; } + .menu.is-small { + font-size: 0.75rem; } + .menu.is-medium { + font-size: 1.25rem; } + .menu.is-large { + font-size: 1.5rem; } + +.menu-list { + line-height: 1.25; } + .menu-list a { + border-radius: 2px; + color: #4a4a4a; + display: block; + padding: 0.5em 0.75em; } + .menu-list a:hover { + background-color: whitesmoke; + color: #363636; } + .menu-list a.is-active { + background-color: #3273dc; + color: #fff; } + .menu-list li ul { + border-left: 1px solid #dbdbdb; + margin: 0.75em; + padding-left: 0.75em; } + +.menu-label { + color: #7a7a7a; + font-size: 0.75em; + letter-spacing: 0.1em; + text-transform: uppercase; } + .menu-label:not(:first-child) { + margin-top: 1em; } + .menu-label:not(:last-child) { + margin-bottom: 1em; } + +.message { + background-color: whitesmoke; + border-radius: 4px; + font-size: 1rem; } + .message strong { + color: currentColor; } + .message a:not(.button):not(.tag) { + color: currentColor; + text-decoration: underline; } + .message.is-small { + font-size: 0.75rem; } + .message.is-medium { + font-size: 1.25rem; } + .message.is-large { + font-size: 1.5rem; } + .message.is-white { + background-color: white; } + .message.is-white .message-header { + background-color: white; + color: #0a0a0a; } + .message.is-white .message-body { + border-color: white; + color: #4d4d4d; } + .message.is-black { + background-color: #fafafa; } + .message.is-black .message-header { + background-color: #0a0a0a; + color: white; } + .message.is-black .message-body { + border-color: #0a0a0a; + color: #090909; } + .message.is-light { + background-color: #fafafa; } + .message.is-light .message-header { + background-color: whitesmoke; + color: #363636; } + .message.is-light .message-body { + border-color: whitesmoke; + color: #505050; } + .message.is-dark { + background-color: #fafafa; } + .message.is-dark .message-header { + background-color: #363636; + color: whitesmoke; } + .message.is-dark .message-body { + border-color: #363636; + color: #2a2a2a; } + .message.is-primary { + background-color: #f5fffd; } + .message.is-primary .message-header { + background-color: #00d1b2; + color: #fff; } + .message.is-primary .message-body { + border-color: #00d1b2; + color: #021310; } + .message.is-link { + background-color: #f6f9fe; } + .message.is-link .message-header { + background-color: #3273dc; + color: #fff; } + .message.is-link .message-body { + border-color: #3273dc; + color: #22509a; } + .message.is-info { + background-color: #f6fbfe; } + .message.is-info .message-header { + background-color: #209cee; + color: #fff; } + .message.is-info .message-body { + border-color: #209cee; + color: #12537e; } + .message.is-success { + background-color: #f6fef9; } + .message.is-success .message-header { + background-color: #23d160; + color: #fff; } + .message.is-success .message-body { + border-color: #23d160; + color: #0e301a; } + .message.is-warning { + background-color: #fffdf5; } + .message.is-warning .message-header { + background-color: #ffdd57; + color: rgba(0, 0, 0, 0.7); } + .message.is-warning .message-body { + border-color: #ffdd57; + color: #3b3108; } + .message.is-danger { + background-color: #fff5f7; } + .message.is-danger .message-header { + background-color: #ff3860; + color: #fff; } + .message.is-danger .message-body { + border-color: #ff3860; + color: #cd0930; } + +.message-header { + align-items: center; + background-color: #4a4a4a; + border-radius: 4px 4px 0 0; + color: #fff; + display: flex; + font-weight: 700; + justify-content: space-between; + line-height: 1.25; + padding: 0.75em 1em; + position: relative; } + .message-header .delete { + flex-grow: 0; + flex-shrink: 0; + margin-left: 0.75em; } + .message-header + .message-body { + border-width: 0; + border-top-left-radius: 0; + border-top-right-radius: 0; } + +.message-body { + border-color: #dbdbdb; + border-radius: 4px; + border-style: solid; + border-width: 0 0 0 4px; + color: #4a4a4a; + padding: 1.25em 1.5em; } + .message-body code, + .message-body pre { + background-color: white; } + .message-body pre code { + background-color: transparent; } + +.modal { + align-items: center; + display: none; + justify-content: center; + overflow: hidden; + position: fixed; + z-index: 40; } + .modal.is-active { + display: flex; } + +.modal-background { + background-color: rgba(10, 10, 10, 0.86); } + +.modal-content, +.modal-card { + margin: 0 20px; + max-height: calc(100vh - 160px); + overflow: auto; + position: relative; + width: 100%; } + @media screen and (min-width: 769px), print { + .modal-content, + .modal-card { + margin: 0 auto; + max-height: calc(100vh - 40px); + width: 640px; } } +.modal-close { + background: none; + height: 40px; + position: fixed; + right: 20px; + top: 20px; + width: 40px; } + +.modal-card { + display: flex; + flex-direction: column; + max-height: calc(100vh - 40px); + overflow: hidden; } + +.modal-card-head, +.modal-card-foot { + align-items: center; + background-color: whitesmoke; + display: flex; + flex-shrink: 0; + justify-content: flex-start; + padding: 20px; + position: relative; } + +.modal-card-head { + border-bottom: 1px solid #dbdbdb; + border-top-left-radius: 6px; + border-top-right-radius: 6px; } + +.modal-card-title { + color: #363636; + flex-grow: 1; + flex-shrink: 0; + font-size: 1.5rem; + line-height: 1; } + +.modal-card-foot { + border-bottom-left-radius: 6px; + border-bottom-right-radius: 6px; + border-top: 1px solid #dbdbdb; } + .modal-card-foot .button:not(:last-child) { + margin-right: 10px; } + +.modal-card-body { + -webkit-overflow-scrolling: touch; + background-color: white; + flex-grow: 1; + flex-shrink: 1; + overflow: auto; + padding: 20px; } + +.navbar { + background-color: white; + box-shadow: 0 2px 0 0 whitesmoke; + min-height: 3.25rem; + position: relative; + z-index: 30; } + .navbar.is-white { + background-color: white; + color: #0a0a0a; } + .navbar.is-white .navbar-brand > .navbar-item, + .navbar.is-white .navbar-brand .navbar-link { + color: #0a0a0a; } + .navbar.is-white .navbar-brand > a.navbar-item:hover, .navbar.is-white .navbar-brand > a.navbar-item.is-active, + .navbar.is-white .navbar-brand .navbar-link:hover, + .navbar.is-white .navbar-brand .navbar-link.is-active { + background-color: #f2f2f2; + color: #0a0a0a; } + .navbar.is-white .navbar-brand .navbar-link::after { + border-color: #0a0a0a; } + @media screen and (min-width: 1088px) { + .navbar.is-white .navbar-start > .navbar-item, + .navbar.is-white .navbar-start .navbar-link, + .navbar.is-white .navbar-end > .navbar-item, + .navbar.is-white .navbar-end .navbar-link { + color: #0a0a0a; } + .navbar.is-white .navbar-start > a.navbar-item:hover, .navbar.is-white .navbar-start > a.navbar-item.is-active, + .navbar.is-white .navbar-start .navbar-link:hover, + .navbar.is-white .navbar-start .navbar-link.is-active, + .navbar.is-white .navbar-end > a.navbar-item:hover, + .navbar.is-white .navbar-end > a.navbar-item.is-active, + .navbar.is-white .navbar-end .navbar-link:hover, + .navbar.is-white .navbar-end .navbar-link.is-active { + background-color: #f2f2f2; + color: #0a0a0a; } + .navbar.is-white .navbar-start .navbar-link::after, + .navbar.is-white .navbar-end .navbar-link::after { + border-color: #0a0a0a; } + .navbar.is-white .navbar-item.has-dropdown:hover .navbar-link, + .navbar.is-white .navbar-item.has-dropdown.is-active .navbar-link { + background-color: #f2f2f2; + color: #0a0a0a; } + .navbar.is-white .navbar-dropdown a.navbar-item.is-active { + background-color: white; + color: #0a0a0a; } } + .navbar.is-black { + background-color: #0a0a0a; + color: white; } + .navbar.is-black .navbar-brand > .navbar-item, + .navbar.is-black .navbar-brand .navbar-link { + color: white; } + .navbar.is-black .navbar-brand > a.navbar-item:hover, .navbar.is-black .navbar-brand > a.navbar-item.is-active, + .navbar.is-black .navbar-brand .navbar-link:hover, + .navbar.is-black .navbar-brand .navbar-link.is-active { + background-color: black; + color: white; } + .navbar.is-black .navbar-brand .navbar-link::after { + border-color: white; } + @media screen and (min-width: 1088px) { + .navbar.is-black .navbar-start > .navbar-item, + .navbar.is-black .navbar-start .navbar-link, + .navbar.is-black .navbar-end > .navbar-item, + .navbar.is-black .navbar-end .navbar-link { + color: white; } + .navbar.is-black .navbar-start > a.navbar-item:hover, .navbar.is-black .navbar-start > a.navbar-item.is-active, + .navbar.is-black .navbar-start .navbar-link:hover, + .navbar.is-black .navbar-start .navbar-link.is-active, + .navbar.is-black .navbar-end > a.navbar-item:hover, + .navbar.is-black .navbar-end > a.navbar-item.is-active, + .navbar.is-black .navbar-end .navbar-link:hover, + .navbar.is-black .navbar-end .navbar-link.is-active { + background-color: black; + color: white; } + .navbar.is-black .navbar-start .navbar-link::after, + .navbar.is-black .navbar-end .navbar-link::after { + border-color: white; } + .navbar.is-black .navbar-item.has-dropdown:hover .navbar-link, + .navbar.is-black .navbar-item.has-dropdown.is-active .navbar-link { + background-color: black; + color: white; } + .navbar.is-black .navbar-dropdown a.navbar-item.is-active { + background-color: #0a0a0a; + color: white; } } + .navbar.is-light { + background-color: whitesmoke; + color: #363636; } + .navbar.is-light .navbar-brand > .navbar-item, + .navbar.is-light .navbar-brand .navbar-link { + color: #363636; } + .navbar.is-light .navbar-brand > a.navbar-item:hover, .navbar.is-light .navbar-brand > a.navbar-item.is-active, + .navbar.is-light .navbar-brand .navbar-link:hover, + .navbar.is-light .navbar-brand .navbar-link.is-active { + background-color: #e8e8e8; + color: #363636; } + .navbar.is-light .navbar-brand .navbar-link::after { + border-color: #363636; } + @media screen and (min-width: 1088px) { + .navbar.is-light .navbar-start > .navbar-item, + .navbar.is-light .navbar-start .navbar-link, + .navbar.is-light .navbar-end > .navbar-item, + .navbar.is-light .navbar-end .navbar-link { + color: #363636; } + .navbar.is-light .navbar-start > a.navbar-item:hover, .navbar.is-light .navbar-start > a.navbar-item.is-active, + .navbar.is-light .navbar-start .navbar-link:hover, + .navbar.is-light .navbar-start .navbar-link.is-active, + .navbar.is-light .navbar-end > a.navbar-item:hover, + .navbar.is-light .navbar-end > a.navbar-item.is-active, + .navbar.is-light .navbar-end .navbar-link:hover, + .navbar.is-light .navbar-end .navbar-link.is-active { + background-color: #e8e8e8; + color: #363636; } + .navbar.is-light .navbar-start .navbar-link::after, + .navbar.is-light .navbar-end .navbar-link::after { + border-color: #363636; } + .navbar.is-light .navbar-item.has-dropdown:hover .navbar-link, + .navbar.is-light .navbar-item.has-dropdown.is-active .navbar-link { + background-color: #e8e8e8; + color: #363636; } + .navbar.is-light .navbar-dropdown a.navbar-item.is-active { + background-color: whitesmoke; + color: #363636; } } + .navbar.is-dark { + background-color: #363636; + color: whitesmoke; } + .navbar.is-dark .navbar-brand > .navbar-item, + .navbar.is-dark .navbar-brand .navbar-link { + color: whitesmoke; } + .navbar.is-dark .navbar-brand > a.navbar-item:hover, .navbar.is-dark .navbar-brand > a.navbar-item.is-active, + .navbar.is-dark .navbar-brand .navbar-link:hover, + .navbar.is-dark .navbar-brand .navbar-link.is-active { + background-color: #292929; + color: whitesmoke; } + .navbar.is-dark .navbar-brand .navbar-link::after { + border-color: whitesmoke; } + @media screen and (min-width: 1088px) { + .navbar.is-dark .navbar-start > .navbar-item, + .navbar.is-dark .navbar-start .navbar-link, + .navbar.is-dark .navbar-end > .navbar-item, + .navbar.is-dark .navbar-end .navbar-link { + color: whitesmoke; } + .navbar.is-dark .navbar-start > a.navbar-item:hover, .navbar.is-dark .navbar-start > a.navbar-item.is-active, + .navbar.is-dark .navbar-start .navbar-link:hover, + .navbar.is-dark .navbar-start .navbar-link.is-active, + .navbar.is-dark .navbar-end > a.navbar-item:hover, + .navbar.is-dark .navbar-end > a.navbar-item.is-active, + .navbar.is-dark .navbar-end .navbar-link:hover, + .navbar.is-dark .navbar-end .navbar-link.is-active { + background-color: #292929; + color: whitesmoke; } + .navbar.is-dark .navbar-start .navbar-link::after, + .navbar.is-dark .navbar-end .navbar-link::after { + border-color: whitesmoke; } + .navbar.is-dark .navbar-item.has-dropdown:hover .navbar-link, + .navbar.is-dark .navbar-item.has-dropdown.is-active .navbar-link { + background-color: #292929; + color: whitesmoke; } + .navbar.is-dark .navbar-dropdown a.navbar-item.is-active { + background-color: #363636; + color: whitesmoke; } } + .navbar.is-primary { + background-color: #00d1b2; + color: #fff; } + .navbar.is-primary .navbar-brand > .navbar-item, + .navbar.is-primary .navbar-brand .navbar-link { + color: #fff; } + .navbar.is-primary .navbar-brand > a.navbar-item:hover, .navbar.is-primary .navbar-brand > a.navbar-item.is-active, + .navbar.is-primary .navbar-brand .navbar-link:hover, + .navbar.is-primary .navbar-brand .navbar-link.is-active { + background-color: #00b89c; + color: #fff; } + .navbar.is-primary .navbar-brand .navbar-link::after { + border-color: #fff; } + @media screen and (min-width: 1088px) { + .navbar.is-primary .navbar-start > .navbar-item, + .navbar.is-primary .navbar-start .navbar-link, + .navbar.is-primary .navbar-end > .navbar-item, + .navbar.is-primary .navbar-end .navbar-link { + color: #fff; } + .navbar.is-primary .navbar-start > a.navbar-item:hover, .navbar.is-primary .navbar-start > a.navbar-item.is-active, + .navbar.is-primary .navbar-start .navbar-link:hover, + .navbar.is-primary .navbar-start .navbar-link.is-active, + .navbar.is-primary .navbar-end > a.navbar-item:hover, + .navbar.is-primary .navbar-end > a.navbar-item.is-active, + .navbar.is-primary .navbar-end .navbar-link:hover, + .navbar.is-primary .navbar-end .navbar-link.is-active { + background-color: #00b89c; + color: #fff; } + .navbar.is-primary .navbar-start .navbar-link::after, + .navbar.is-primary .navbar-end .navbar-link::after { + border-color: #fff; } + .navbar.is-primary .navbar-item.has-dropdown:hover .navbar-link, + .navbar.is-primary .navbar-item.has-dropdown.is-active .navbar-link { + background-color: #00b89c; + color: #fff; } + .navbar.is-primary .navbar-dropdown a.navbar-item.is-active { + background-color: #00d1b2; + color: #fff; } } + .navbar.is-link { + background-color: #3273dc; + color: #fff; } + .navbar.is-link .navbar-brand > .navbar-item, + .navbar.is-link .navbar-brand .navbar-link { + color: #fff; } + .navbar.is-link .navbar-brand > a.navbar-item:hover, .navbar.is-link .navbar-brand > a.navbar-item.is-active, + .navbar.is-link .navbar-brand .navbar-link:hover, + .navbar.is-link .navbar-brand .navbar-link.is-active { + background-color: #2366d1; + color: #fff; } + .navbar.is-link .navbar-brand .navbar-link::after { + border-color: #fff; } + @media screen and (min-width: 1088px) { + .navbar.is-link .navbar-start > .navbar-item, + .navbar.is-link .navbar-start .navbar-link, + .navbar.is-link .navbar-end > .navbar-item, + .navbar.is-link .navbar-end .navbar-link { + color: #fff; } + .navbar.is-link .navbar-start > a.navbar-item:hover, .navbar.is-link .navbar-start > a.navbar-item.is-active, + .navbar.is-link .navbar-start .navbar-link:hover, + .navbar.is-link .navbar-start .navbar-link.is-active, + .navbar.is-link .navbar-end > a.navbar-item:hover, + .navbar.is-link .navbar-end > a.navbar-item.is-active, + .navbar.is-link .navbar-end .navbar-link:hover, + .navbar.is-link .navbar-end .navbar-link.is-active { + background-color: #2366d1; + color: #fff; } + .navbar.is-link .navbar-start .navbar-link::after, + .navbar.is-link .navbar-end .navbar-link::after { + border-color: #fff; } + .navbar.is-link .navbar-item.has-dropdown:hover .navbar-link, + .navbar.is-link .navbar-item.has-dropdown.is-active .navbar-link { + background-color: #2366d1; + color: #fff; } + .navbar.is-link .navbar-dropdown a.navbar-item.is-active { + background-color: #3273dc; + color: #fff; } } + .navbar.is-info { + background-color: #209cee; + color: #fff; } + .navbar.is-info .navbar-brand > .navbar-item, + .navbar.is-info .navbar-brand .navbar-link { + color: #fff; } + .navbar.is-info .navbar-brand > a.navbar-item:hover, .navbar.is-info .navbar-brand > a.navbar-item.is-active, + .navbar.is-info .navbar-brand .navbar-link:hover, + .navbar.is-info .navbar-brand .navbar-link.is-active { + background-color: #118fe4; + color: #fff; } + .navbar.is-info .navbar-brand .navbar-link::after { + border-color: #fff; } + @media screen and (min-width: 1088px) { + .navbar.is-info .navbar-start > .navbar-item, + .navbar.is-info .navbar-start .navbar-link, + .navbar.is-info .navbar-end > .navbar-item, + .navbar.is-info .navbar-end .navbar-link { + color: #fff; } + .navbar.is-info .navbar-start > a.navbar-item:hover, .navbar.is-info .navbar-start > a.navbar-item.is-active, + .navbar.is-info .navbar-start .navbar-link:hover, + .navbar.is-info .navbar-start .navbar-link.is-active, + .navbar.is-info .navbar-end > a.navbar-item:hover, + .navbar.is-info .navbar-end > a.navbar-item.is-active, + .navbar.is-info .navbar-end .navbar-link:hover, + .navbar.is-info .navbar-end .navbar-link.is-active { + background-color: #118fe4; + color: #fff; } + .navbar.is-info .navbar-start .navbar-link::after, + .navbar.is-info .navbar-end .navbar-link::after { + border-color: #fff; } + .navbar.is-info .navbar-item.has-dropdown:hover .navbar-link, + .navbar.is-info .navbar-item.has-dropdown.is-active .navbar-link { + background-color: #118fe4; + color: #fff; } + .navbar.is-info .navbar-dropdown a.navbar-item.is-active { + background-color: #209cee; + color: #fff; } } + .navbar.is-success { + background-color: #23d160; + color: #fff; } + .navbar.is-success .navbar-brand > .navbar-item, + .navbar.is-success .navbar-brand .navbar-link { + color: #fff; } + .navbar.is-success .navbar-brand > a.navbar-item:hover, .navbar.is-success .navbar-brand > a.navbar-item.is-active, + .navbar.is-success .navbar-brand .navbar-link:hover, + .navbar.is-success .navbar-brand .navbar-link.is-active { + background-color: #20bc56; + color: #fff; } + .navbar.is-success .navbar-brand .navbar-link::after { + border-color: #fff; } + @media screen and (min-width: 1088px) { + .navbar.is-success .navbar-start > .navbar-item, + .navbar.is-success .navbar-start .navbar-link, + .navbar.is-success .navbar-end > .navbar-item, + .navbar.is-success .navbar-end .navbar-link { + color: #fff; } + .navbar.is-success .navbar-start > a.navbar-item:hover, .navbar.is-success .navbar-start > a.navbar-item.is-active, + .navbar.is-success .navbar-start .navbar-link:hover, + .navbar.is-success .navbar-start .navbar-link.is-active, + .navbar.is-success .navbar-end > a.navbar-item:hover, + .navbar.is-success .navbar-end > a.navbar-item.is-active, + .navbar.is-success .navbar-end .navbar-link:hover, + .navbar.is-success .navbar-end .navbar-link.is-active { + background-color: #20bc56; + color: #fff; } + .navbar.is-success .navbar-start .navbar-link::after, + .navbar.is-success .navbar-end .navbar-link::after { + border-color: #fff; } + .navbar.is-success .navbar-item.has-dropdown:hover .navbar-link, + .navbar.is-success .navbar-item.has-dropdown.is-active .navbar-link { + background-color: #20bc56; + color: #fff; } + .navbar.is-success .navbar-dropdown a.navbar-item.is-active { + background-color: #23d160; + color: #fff; } } + .navbar.is-warning { + background-color: #ffdd57; + color: rgba(0, 0, 0, 0.7); } + .navbar.is-warning .navbar-brand > .navbar-item, + .navbar.is-warning .navbar-brand .navbar-link { + color: rgba(0, 0, 0, 0.7); } + .navbar.is-warning .navbar-brand > a.navbar-item:hover, .navbar.is-warning .navbar-brand > a.navbar-item.is-active, + .navbar.is-warning .navbar-brand .navbar-link:hover, + .navbar.is-warning .navbar-brand .navbar-link.is-active { + background-color: #ffd83d; + color: rgba(0, 0, 0, 0.7); } + .navbar.is-warning .navbar-brand .navbar-link::after { + border-color: rgba(0, 0, 0, 0.7); } + @media screen and (min-width: 1088px) { + .navbar.is-warning .navbar-start > .navbar-item, + .navbar.is-warning .navbar-start .navbar-link, + .navbar.is-warning .navbar-end > .navbar-item, + .navbar.is-warning .navbar-end .navbar-link { + color: rgba(0, 0, 0, 0.7); } + .navbar.is-warning .navbar-start > a.navbar-item:hover, .navbar.is-warning .navbar-start > a.navbar-item.is-active, + .navbar.is-warning .navbar-start .navbar-link:hover, + .navbar.is-warning .navbar-start .navbar-link.is-active, + .navbar.is-warning .navbar-end > a.navbar-item:hover, + .navbar.is-warning .navbar-end > a.navbar-item.is-active, + .navbar.is-warning .navbar-end .navbar-link:hover, + .navbar.is-warning .navbar-end .navbar-link.is-active { + background-color: #ffd83d; + color: rgba(0, 0, 0, 0.7); } + .navbar.is-warning .navbar-start .navbar-link::after, + .navbar.is-warning .navbar-end .navbar-link::after { + border-color: rgba(0, 0, 0, 0.7); } + .navbar.is-warning .navbar-item.has-dropdown:hover .navbar-link, + .navbar.is-warning .navbar-item.has-dropdown.is-active .navbar-link { + background-color: #ffd83d; + color: rgba(0, 0, 0, 0.7); } + .navbar.is-warning .navbar-dropdown a.navbar-item.is-active { + background-color: #ffdd57; + color: rgba(0, 0, 0, 0.7); } } + .navbar.is-danger { + background-color: #ff3860; + color: #fff; } + .navbar.is-danger .navbar-brand > .navbar-item, + .navbar.is-danger .navbar-brand .navbar-link { + color: #fff; } + .navbar.is-danger .navbar-brand > a.navbar-item:hover, .navbar.is-danger .navbar-brand > a.navbar-item.is-active, + .navbar.is-danger .navbar-brand .navbar-link:hover, + .navbar.is-danger .navbar-brand .navbar-link.is-active { + background-color: #ff1f4b; + color: #fff; } + .navbar.is-danger .navbar-brand .navbar-link::after { + border-color: #fff; } + @media screen and (min-width: 1088px) { + .navbar.is-danger .navbar-start > .navbar-item, + .navbar.is-danger .navbar-start .navbar-link, + .navbar.is-danger .navbar-end > .navbar-item, + .navbar.is-danger .navbar-end .navbar-link { + color: #fff; } + .navbar.is-danger .navbar-start > a.navbar-item:hover, .navbar.is-danger .navbar-start > a.navbar-item.is-active, + .navbar.is-danger .navbar-start .navbar-link:hover, + .navbar.is-danger .navbar-start .navbar-link.is-active, + .navbar.is-danger .navbar-end > a.navbar-item:hover, + .navbar.is-danger .navbar-end > a.navbar-item.is-active, + .navbar.is-danger .navbar-end .navbar-link:hover, + .navbar.is-danger .navbar-end .navbar-link.is-active { + background-color: #ff1f4b; + color: #fff; } + .navbar.is-danger .navbar-start .navbar-link::after, + .navbar.is-danger .navbar-end .navbar-link::after { + border-color: #fff; } + .navbar.is-danger .navbar-item.has-dropdown:hover .navbar-link, + .navbar.is-danger .navbar-item.has-dropdown.is-active .navbar-link { + background-color: #ff1f4b; + color: #fff; } + .navbar.is-danger .navbar-dropdown a.navbar-item.is-active { + background-color: #ff3860; + color: #fff; } } + .navbar > .container { + align-items: stretch; + display: flex; + min-height: 3.25rem; + width: 100%; } + .navbar.has-shadow { + box-shadow: 0 2px 3px rgba(10, 10, 10, 0.1); } + .navbar.is-fixed-bottom, .navbar.is-fixed-top { + left: 0; + position: fixed; + right: 0; + z-index: 30; } + .navbar.is-fixed-bottom { + bottom: 0; } + .navbar.is-fixed-bottom.has-shadow { + box-shadow: 0 -2px 3px rgba(10, 10, 10, 0.1); } + .navbar.is-fixed-top { + top: 0; } + +@media screen and (max-width: 600px) { + /* overriding pyData .navbar for mobile version + better placement of hamburger menu */ + .navbar { + padding: 0.5rem 0rem !important; + } + +} + +html.has-navbar-fixed-top, +body.has-navbar-fixed-top { + padding-top: 3.25rem; } + +html.has-navbar-fixed-bottom, +body.has-navbar-fixed-bottom { + padding-bottom: 3.25rem; } + +.navbar-brand, +.navbar-tabs { + align-items: stretch; + display: flex; + flex-shrink: 0; + min-height: 3.25rem; } + +.navbar-brand a.navbar-item:hover { + background-color: transparent; } + +.navbar-tabs { + -webkit-overflow-scrolling: touch; + max-width: 100vw; + overflow-x: auto; + overflow-y: hidden; } + +.navbar-burger { + cursor: pointer; + display: block; + height: 3.25rem; + position: relative; + width: 3.25rem; + margin-left: auto; } + .navbar-burger span { + background-color: currentColor; + display: block; + height: 1px; + left: calc(50% - 8px); + position: absolute; + transform-origin: center; + transition-duration: 86ms; + transition-property: background-color, opacity, transform; + transition-timing-function: ease-out; + width: 16px; } + .navbar-burger span:nth-child(1) { + top: calc(50% - 6px); } + .navbar-burger span:nth-child(2) { + top: calc(50% - 1px); } + .navbar-burger span:nth-child(3) { + top: calc(50% + 4px); } + .navbar-burger:hover { + background-color: rgba(0, 0, 0, 0.05); } + .navbar-burger.is-active span:nth-child(1) { + transform: translateY(5px) rotate(45deg); } + .navbar-burger.is-active span:nth-child(2) { + opacity: 0; } + .navbar-burger.is-active span:nth-child(3) { + transform: translateY(-5px) rotate(-45deg); } + +.navbar-menu { + display: none; } + +.navbar-item, +.navbar-link { + color: #4a4a4a; + display: block; + line-height: 1.5; + padding: 0.5rem 0.75rem; + position: relative; } + .navbar-item .icon:only-child, + .navbar-link .icon:only-child { + margin-left: -0.25rem; + margin-right: -0.25rem; } + +a.navbar-item, +.navbar-link { + cursor: pointer; } + a.navbar-item:hover, a.navbar-item.is-active, + .navbar-link:hover, + .navbar-link.is-active { + background-color: #fafafa; + color: #3273dc; } + +.navbar-item { + display: block; + flex-grow: 0; + flex-shrink: 0; } + .navbar-item img { + max-height: 1.75rem; } + .navbar-item.has-dropdown { + padding: 0; } + .navbar-item.is-expanded { + flex-grow: 1; + flex-shrink: 1; } + .navbar-item.is-tab { + border-bottom: 1px solid transparent; + min-height: 3.25rem; + padding-bottom: calc(0.5rem - 1px); } + .navbar-item.is-tab:hover { + background-color: transparent; + border-bottom-color: #3273dc; } + .navbar-item.is-tab.is-active { + background-color: transparent; + border-bottom-color: #3273dc; + border-bottom-style: solid; + border-bottom-width: 3px; + color: #3273dc; + padding-bottom: calc(0.5rem - 3px); } + +.navbar-content { + flex-grow: 1; + flex-shrink: 1; } + +.navbar-link { + padding-right: 2.5em; } + .navbar-link::after { + border-color: #3273dc; + margin-top: -0.375em; + right: 1.125em; } + +.navbar-dropdown { + font-size: 0.875rem; + padding-bottom: 0.5rem; + padding-top: 0.5rem; } + .navbar-dropdown .navbar-item { + padding-left: 1.5rem; + padding-right: 1.5rem; } + +.navbar-divider { + background-color: whitesmoke; + border: none; + display: none; + height: 2px; + margin: 0.5rem 0; } + +@media screen and (max-width: 1087px) { + .navbar > .container { + display: block; } + .navbar-brand .navbar-item, + .navbar-tabs .navbar-item { + align-items: center; + display: flex; } + .navbar-link::after { + display: none; } + .navbar-menu { + background-color: white; + box-shadow: 0 8px 16px rgba(10, 10, 10, 0.1); + padding: 0.5rem 0; } + .navbar-menu.is-active { + display: block; } + .navbar.is-fixed-bottom-touch, .navbar.is-fixed-top-touch { + left: 0; + position: fixed; + right: 0; + z-index: 30; } + .navbar.is-fixed-bottom-touch { + bottom: 0; } + .navbar.is-fixed-bottom-touch.has-shadow { + box-shadow: 0 -2px 3px rgba(10, 10, 10, 0.1); } + .navbar.is-fixed-top-touch { + top: 0; } + .navbar.is-fixed-top .navbar-menu, .navbar.is-fixed-top-touch .navbar-menu { + -webkit-overflow-scrolling: touch; + max-height: calc(100vh - 3.25rem); + overflow: auto; } + html.has-navbar-fixed-top-touch, + body.has-navbar-fixed-top-touch { + padding-top: 3.25rem; } + html.has-navbar-fixed-bottom-touch, + body.has-navbar-fixed-bottom-touch { + padding-bottom: 3.25rem; } } + +@media screen and (min-width: 1088px) { + .navbar, + .navbar-menu, + .navbar-start, + .navbar-end { + align-items: stretch; + display: flex; } + .navbar { + min-height: 3.25rem; } + .navbar.is-spaced { + padding: 1rem 2rem; } + .navbar.is-spaced .navbar-start, + .navbar.is-spaced .navbar-end { + align-items: center; } + .navbar.is-spaced a.navbar-item, + .navbar.is-spaced .navbar-link { + border-radius: 4px; } + .navbar.is-transparent a.navbar-item:hover, .navbar.is-transparent a.navbar-item.is-active, + .navbar.is-transparent .navbar-link:hover, + .navbar.is-transparent .navbar-link.is-active { + background-color: transparent !important; } + .navbar.is-transparent .navbar-item.has-dropdown.is-active .navbar-link, .navbar.is-transparent .navbar-item.has-dropdown.is-hoverable:hover .navbar-link { + background-color: transparent !important; } + .navbar.is-transparent .navbar-dropdown a.navbar-item:hover { + background-color: whitesmoke; + color: #0a0a0a; } + .navbar.is-transparent .navbar-dropdown a.navbar-item.is-active { + background-color: whitesmoke; + color: #3273dc; } + .navbar-burger { + display: none; } + .navbar-item, + .navbar-link { + align-items: center; + display: flex; } + .navbar-item { + display: flex; } + .navbar-item.has-dropdown { + align-items: stretch; } + .navbar-item.has-dropdown-up .navbar-link::after { + transform: rotate(135deg) translate(0.25em, -0.25em); } + .navbar-item.has-dropdown-up .navbar-dropdown { + border-bottom: 2px solid #dbdbdb; + border-radius: 6px 6px 0 0; + border-top: none; + bottom: 100%; + box-shadow: 0 -8px 8px rgba(10, 10, 10, 0.1); + top: auto; } + .navbar-item.is-active .navbar-dropdown, .navbar-item.is-hoverable:hover .navbar-dropdown { + display: block; } + .navbar.is-spaced .navbar-item.is-active .navbar-dropdown, .navbar-item.is-active .navbar-dropdown.is-boxed, .navbar.is-spaced .navbar-item.is-hoverable:hover .navbar-dropdown, .navbar-item.is-hoverable:hover .navbar-dropdown.is-boxed { + opacity: 1; + pointer-events: auto; + transform: translateY(0); } + .navbar-menu { + flex-grow: 1; + flex-shrink: 0; } + .navbar-start { + justify-content: flex-start; + margin-right: auto; } + .navbar-end { + justify-content: flex-end; + margin-left: auto; } + .navbar-dropdown { + background-color: white; + border-bottom-left-radius: 6px; + border-bottom-right-radius: 6px; + border-top: 2px solid #dbdbdb; + box-shadow: 0 8px 8px rgba(10, 10, 10, 0.1); + display: none; + font-size: 0.875rem; + left: 0; + min-width: 100%; + position: absolute; + top: 100%; + z-index: 20; } + .navbar-dropdown .navbar-item { + padding: 0.375rem 1rem; + white-space: nowrap; } + .navbar-dropdown a.navbar-item { + padding-right: 3rem; } + .navbar-dropdown a.navbar-item:hover { + background-color: whitesmoke; + color: #0a0a0a; } + .navbar-dropdown a.navbar-item.is-active { + background-color: whitesmoke; + color: #3273dc; } + .navbar.is-spaced .navbar-dropdown, .navbar-dropdown.is-boxed { + border-radius: 6px; + border-top: none; + box-shadow: 0 8px 8px rgba(10, 10, 10, 0.1), 0 0 0 1px rgba(10, 10, 10, 0.1); + display: block; + opacity: 0; + pointer-events: none; + top: calc(100% + (-4px)); + transform: translateY(-5px); + transition-duration: 86ms; + transition-property: opacity, transform; } + .navbar-dropdown.is-right { + left: auto; + right: 0; } + .navbar-divider { + display: block; } + .navbar > .container .navbar-brand, + .container > .navbar .navbar-brand { + margin-left: -1rem; } + .navbar > .container .navbar-menu, + .container > .navbar .navbar-menu { + margin-right: -1rem; } + .navbar.is-fixed-bottom-desktop, .navbar.is-fixed-top-desktop { + left: 0; + position: fixed; + right: 0; + z-index: 30; } + .navbar.is-fixed-bottom-desktop { + bottom: 0; } + .navbar.is-fixed-bottom-desktop.has-shadow { + box-shadow: 0 -2px 3px rgba(10, 10, 10, 0.1); } + .navbar.is-fixed-top-desktop { + top: 0; } + html.has-navbar-fixed-top-desktop, + body.has-navbar-fixed-top-desktop { + padding-top: 3.25rem; } + html.has-navbar-fixed-bottom-desktop, + body.has-navbar-fixed-bottom-desktop { + padding-bottom: 3.25rem; } + html.has-spaced-navbar-fixed-top, + body.has-spaced-navbar-fixed-top { + padding-top: 5.25rem; } + html.has-spaced-navbar-fixed-bottom, + body.has-spaced-navbar-fixed-bottom { + padding-bottom: 5.25rem; } + a.navbar-item.is-active, + .navbar-link.is-active { + color: #0a0a0a; } + a.navbar-item.is-active:not(:hover), + .navbar-link.is-active:not(:hover) { + background-color: transparent; } + .navbar-item.has-dropdown:hover .navbar-link, .navbar-item.has-dropdown.is-active .navbar-link { + background-color: #fafafa; } } + +.pagination { + font-size: 1rem; + margin: -0.25rem; } + .pagination.is-small { + font-size: 0.75rem; } + .pagination.is-medium { + font-size: 1.25rem; } + .pagination.is-large { + font-size: 1.5rem; } + .pagination.is-rounded .pagination-previous, + .pagination.is-rounded .pagination-next { + padding-left: 1em; + padding-right: 1em; + border-radius: 290486px; } + .pagination.is-rounded .pagination-link { + border-radius: 290486px; } + +.pagination, +.pagination-list { + align-items: center; + display: flex; + justify-content: center; + text-align: center; } + +.pagination-previous, +.pagination-next, +.pagination-link, +.pagination-ellipsis { + font-size: 1em; + padding-left: 0.5em; + padding-right: 0.5em; + justify-content: center; + margin: 0.25rem; + text-align: center; } + +.pagination-previous, +.pagination-next, +.pagination-link { + border-color: #dbdbdb; + color: #363636; + min-width: 2.25em; } + .pagination-previous:hover, + .pagination-next:hover, + .pagination-link:hover { + border-color: #b5b5b5; + color: #363636; } + .pagination-previous:focus, + .pagination-next:focus, + .pagination-link:focus { + border-color: #3273dc; } + .pagination-previous:active, + .pagination-next:active, + .pagination-link:active { + box-shadow: inset 0 1px 2px rgba(10, 10, 10, 0.2); } + .pagination-previous[disabled], + .pagination-next[disabled], + .pagination-link[disabled] { + background-color: #dbdbdb; + border-color: #dbdbdb; + box-shadow: none; + color: #7a7a7a; + opacity: 0.5; } + +.pagination-previous, +.pagination-next { + padding-left: 0.75em; + padding-right: 0.75em; + white-space: nowrap; } + +.pagination-link.is-current { + background-color: #3273dc; + border-color: #3273dc; + color: #fff; } + +.pagination-ellipsis { + color: #b5b5b5; + pointer-events: none; } + +.pagination-list { + flex-wrap: wrap; } + +@media screen and (max-width: 768px) { + .pagination { + flex-wrap: wrap; } + .pagination-previous, + .pagination-next { + flex-grow: 1; + flex-shrink: 1; } + .pagination-list li { + flex-grow: 1; + flex-shrink: 1; } } + +@media screen and (min-width: 769px), print { + .pagination-list { + flex-grow: 1; + flex-shrink: 1; + justify-content: flex-start; + order: 1; } + .pagination-previous { + order: 2; } + .pagination-next { + order: 3; } + .pagination { + justify-content: space-between; } + .pagination.is-centered .pagination-previous { + order: 1; } + .pagination.is-centered .pagination-list { + justify-content: center; + order: 2; } + .pagination.is-centered .pagination-next { + order: 3; } + .pagination.is-right .pagination-previous { + order: 1; } + .pagination.is-right .pagination-next { + order: 2; } + .pagination.is-right .pagination-list { + justify-content: flex-end; + order: 3; } } + +.panel { + font-size: 1rem; } + .panel:not(:last-child) { + margin-bottom: 1.5rem; } + +.panel-heading, +.panel-tabs, +.panel-block { + border-bottom: 1px solid #dbdbdb; + border-left: 1px solid #dbdbdb; + border-right: 1px solid #dbdbdb; } + .panel-heading:first-child, + .panel-tabs:first-child, + .panel-block:first-child { + border-top: 1px solid #dbdbdb; } + +.panel-heading { + background-color: whitesmoke; + border-radius: 4px 4px 0 0; + color: #363636; + font-size: 1.25em; + font-weight: 300; + line-height: 1.25; + padding: 0.5em 0.75em; } + +.panel-tabs { + align-items: flex-end; + display: flex; + font-size: 0.875em; + justify-content: center; } + .panel-tabs a { + border-bottom: 1px solid #dbdbdb; + margin-bottom: -1px; + padding: 0.5em; } + .panel-tabs a.is-active { + border-bottom-color: #4a4a4a; + color: #363636; } + +.panel-list a { + color: #4a4a4a; } + .panel-list a:hover { + color: #3273dc; } + +.panel-block { + align-items: center; + color: #363636; + display: flex; + justify-content: flex-start; + padding: 0.5em 0.75em; } + .panel-block input[type="checkbox"] { + margin-right: 0.75em; } + .panel-block > .control { + flex-grow: 1; + flex-shrink: 1; + width: 100%; } + .panel-block.is-wrapped { + flex-wrap: wrap; } + .panel-block.is-active { + border-left-color: #3273dc; + color: #363636; } + .panel-block.is-active .panel-icon { + color: #3273dc; } + +a.panel-block, +label.panel-block { + cursor: pointer; } + a.panel-block:hover, + label.panel-block:hover { + background-color: whitesmoke; } + +.panel-icon { + display: inline-block; + font-size: 14px; + height: 1em; + line-height: 1em; + text-align: center; + vertical-align: top; + width: 1em; + color: #7a7a7a; + margin-right: 0.75em; } + .panel-icon .fa { + font-size: inherit; + line-height: inherit; } + +.tabs { + -webkit-overflow-scrolling: touch; + align-items: stretch; + display: flex; + font-size: 1rem; + justify-content: space-between; + overflow: hidden; + overflow-x: auto; + white-space: nowrap; } + .tabs a { + align-items: center; + border-bottom-color: #dbdbdb; + border-bottom-style: solid; + border-bottom-width: 1px; + color: #4a4a4a; + display: flex; + justify-content: center; + margin-bottom: -1px; + padding: 0.5em 1em; + vertical-align: top; } + .tabs a:hover { + border-bottom-color: #363636; + color: #363636; } + .tabs li { + display: block; } + .tabs li.is-active a { + border-bottom-color: #3273dc; + color: #3273dc; } + .tabs ul { + align-items: center; + border-bottom-color: #dbdbdb; + border-bottom-style: solid; + border-bottom-width: 1px; + display: flex; + flex-grow: 1; + flex-shrink: 0; + justify-content: flex-start; } + .tabs ul.is-left { + padding-right: 0.75em; } + .tabs ul.is-center { + flex: none; + justify-content: center; + padding-left: 0.75em; + padding-right: 0.75em; } + .tabs ul.is-right { + justify-content: flex-end; + padding-left: 0.75em; } + .tabs .icon:first-child { + margin-right: 0.5em; } + .tabs .icon:last-child { + margin-left: 0.5em; } + .tabs.is-centered ul { + justify-content: center; } + .tabs.is-right ul { + justify-content: flex-end; } + .tabs.is-boxed a { + border: 1px solid transparent; + border-radius: 4px 4px 0 0; } + .tabs.is-boxed a:hover { + background-color: whitesmoke; + border-bottom-color: #dbdbdb; } + .tabs.is-boxed li.is-active a { + background-color: white; + border-color: #dbdbdb; + border-bottom-color: transparent !important; } + .tabs.is-fullwidth li { + flex-grow: 1; + flex-shrink: 0; } + .tabs.is-toggle a { + border-color: #dbdbdb; + border-style: solid; + border-width: 1px; + margin-bottom: 0; + position: relative; } + .tabs.is-toggle a:hover { + background-color: whitesmoke; + border-color: #b5b5b5; + z-index: 2; } + .tabs.is-toggle li + li { + margin-left: -1px; } + .tabs.is-toggle li:first-child a { + border-radius: 4px 0 0 4px; } + .tabs.is-toggle li:last-child a { + border-radius: 0 4px 4px 0; } + .tabs.is-toggle li.is-active a { + background-color: #3273dc; + border-color: #3273dc; + color: #fff; + z-index: 1; } + .tabs.is-toggle ul { + border-bottom: none; } + .tabs.is-toggle.is-toggle-rounded li:first-child a { + border-bottom-left-radius: 290486px; + border-top-left-radius: 290486px; + padding-left: 1.25em; } + .tabs.is-toggle.is-toggle-rounded li:last-child a { + border-bottom-right-radius: 290486px; + border-top-right-radius: 290486px; + padding-right: 1.25em; } + .tabs.is-small { + font-size: 0.75rem; } + .tabs.is-medium { + font-size: 1.25rem; } + .tabs.is-large { + font-size: 1.5rem; } + +.column { + display: block; + flex-basis: 0; + flex-grow: 1; + flex-shrink: 1; + padding: 0.75rem; } + .columns.is-mobile > .column.is-narrow { + flex: none; } + .columns.is-mobile > .column.is-full { + flex: none; + width: 100%; } + .columns.is-mobile > .column.is-three-quarters { + flex: none; + width: 75%; } + .columns.is-mobile > .column.is-two-thirds { + flex: none; + width: 66.6666%; } + .columns.is-mobile > .column.is-half { + flex: none; + width: 50%; } + .columns.is-mobile > .column.is-one-third { + flex: none; + width: 33.3333%; } + .columns.is-mobile > .column.is-one-quarter { + flex: none; + width: 25%; } + .columns.is-mobile > .column.is-one-fifth { + flex: none; + width: 20%; } + .columns.is-mobile > .column.is-two-fifths { + flex: none; + width: 40%; } + .columns.is-mobile > .column.is-three-fifths { + flex: none; + width: 60%; } + .columns.is-mobile > .column.is-four-fifths { + flex: none; + width: 80%; } + .columns.is-mobile > .column.is-offset-three-quarters { + margin-left: 75%; } + .columns.is-mobile > .column.is-offset-two-thirds { + margin-left: 66.6666%; } + .columns.is-mobile > .column.is-offset-half { + margin-left: 50%; } + .columns.is-mobile > .column.is-offset-one-third { + margin-left: 33.3333%; } + .columns.is-mobile > .column.is-offset-one-quarter { + margin-left: 25%; } + .columns.is-mobile > .column.is-offset-one-fifth { + margin-left: 20%; } + .columns.is-mobile > .column.is-offset-two-fifths { + margin-left: 40%; } + .columns.is-mobile > .column.is-offset-three-fifths { + margin-left: 60%; } + .columns.is-mobile > .column.is-offset-four-fifths { + margin-left: 80%; } + .columns.is-mobile > .column.is-1 { + flex: none; + width: 8.33333333%; } + .columns.is-mobile > .column.is-offset-1 { + margin-left: 8.33333333%; } + .columns.is-mobile > .column.is-2 { + flex: none; + width: 16.66666667%; } + .columns.is-mobile > .column.is-offset-2 { + margin-left: 16.66666667%; } + .columns.is-mobile > .column.is-3 { + flex: none; + width: 25%; } + .columns.is-mobile > .column.is-offset-3 { + margin-left: 25%; } + .columns.is-mobile > .column.is-4 { + flex: none; + width: 33.33333333%; } + .columns.is-mobile > .column.is-offset-4 { + margin-left: 33.33333333%; } + .columns.is-mobile > .column.is-5 { + flex: none; + width: 41.66666667%; } + .columns.is-mobile > .column.is-offset-5 { + margin-left: 41.66666667%; } + .columns.is-mobile > .column.is-6 { + flex: none; + width: 50%; } + .columns.is-mobile > .column.is-offset-6 { + margin-left: 50%; } + .columns.is-mobile > .column.is-7 { + flex: none; + width: 58.33333333%; } + .columns.is-mobile > .column.is-offset-7 { + margin-left: 58.33333333%; } + .columns.is-mobile > .column.is-8 { + flex: none; + width: 66.66666667%; } + .columns.is-mobile > .column.is-offset-8 { + margin-left: 66.66666667%; } + .columns.is-mobile > .column.is-9 { + flex: none; + width: 75%; } + .columns.is-mobile > .column.is-offset-9 { + margin-left: 75%; } + .columns.is-mobile > .column.is-10 { + flex: none; + width: 83.33333333%; } + .columns.is-mobile > .column.is-offset-10 { + margin-left: 83.33333333%; } + .columns.is-mobile > .column.is-11 { + flex: none; + width: 91.66666667%; } + .columns.is-mobile > .column.is-offset-11 { + margin-left: 91.66666667%; } + .columns.is-mobile > .column.is-12 { + flex: none; + width: 100%; } + .columns.is-mobile > .column.is-offset-12 { + margin-left: 100%; } + @media screen and (max-width: 768px) { + .column.is-narrow-mobile { + flex: none; } + .column.is-full-mobile { + flex: none; + width: 100%; } + .column.is-three-quarters-mobile { + flex: none; + width: 75%; } + .column.is-two-thirds-mobile { + flex: none; + width: 66.6666%; } + .column.is-half-mobile { + flex: none; + width: 50%; } + .column.is-one-third-mobile { + flex: none; + width: 33.3333%; } + .column.is-one-quarter-mobile { + flex: none; + width: 25%; } + .column.is-one-fifth-mobile { + flex: none; + width: 20%; } + .column.is-two-fifths-mobile { + flex: none; + width: 40%; } + .column.is-three-fifths-mobile { + flex: none; + width: 60%; } + .column.is-four-fifths-mobile { + flex: none; + width: 80%; } + .column.is-offset-three-quarters-mobile { + margin-left: 75%; } + .column.is-offset-two-thirds-mobile { + margin-left: 66.6666%; } + .column.is-offset-half-mobile { + margin-left: 50%; } + .column.is-offset-one-third-mobile { + margin-left: 33.3333%; } + .column.is-offset-one-quarter-mobile { + margin-left: 25%; } + .column.is-offset-one-fifth-mobile { + margin-left: 20%; } + .column.is-offset-two-fifths-mobile { + margin-left: 40%; } + .column.is-offset-three-fifths-mobile { + margin-left: 60%; } + .column.is-offset-four-fifths-mobile { + margin-left: 80%; } + .column.is-1-mobile { + flex: none; + width: 8.33333333%; } + .column.is-offset-1-mobile { + margin-left: 8.33333333%; } + .column.is-2-mobile { + flex: none; + width: 16.66666667%; } + .column.is-offset-2-mobile { + margin-left: 16.66666667%; } + .column.is-3-mobile { + flex: none; + width: 25%; } + .column.is-offset-3-mobile { + margin-left: 25%; } + .column.is-4-mobile { + flex: none; + width: 33.33333333%; } + .column.is-offset-4-mobile { + margin-left: 33.33333333%; } + .column.is-5-mobile { + flex: none; + width: 41.66666667%; } + .column.is-offset-5-mobile { + margin-left: 41.66666667%; } + .column.is-6-mobile { + flex: none; + width: 50%; } + .column.is-offset-6-mobile { + margin-left: 50%; } + .column.is-7-mobile { + flex: none; + width: 58.33333333%; } + .column.is-offset-7-mobile { + margin-left: 58.33333333%; } + .column.is-8-mobile { + flex: none; + width: 66.66666667%; } + .column.is-offset-8-mobile { + margin-left: 66.66666667%; } + .column.is-9-mobile { + flex: none; + width: 75%; } + .column.is-offset-9-mobile { + margin-left: 75%; } + .column.is-10-mobile { + flex: none; + width: 83.33333333%; } + .column.is-offset-10-mobile { + margin-left: 83.33333333%; } + .column.is-11-mobile { + flex: none; + width: 91.66666667%; } + .column.is-offset-11-mobile { + margin-left: 91.66666667%; } + .column.is-12-mobile { + flex: none; + width: 100%; } + .column.is-offset-12-mobile { + margin-left: 100%; } } + @media screen and (min-width: 769px), print { + .column.is-narrow, .column.is-narrow-tablet { + flex: none; } + .column.is-full, .column.is-full-tablet { + flex: none; + width: 100%; } + .column.is-three-quarters, .column.is-three-quarters-tablet { + flex: none; + width: 75%; } + .column.is-two-thirds, .column.is-two-thirds-tablet { + flex: none; + width: 66.6666%; } + .column.is-half, .column.is-half-tablet { + flex: none; + width: 50%; } + .column.is-one-third, .column.is-one-third-tablet { + flex: none; + width: 33.3333%; } + .column.is-one-quarter, .column.is-one-quarter-tablet { + flex: none; + width: 25%; } + .column.is-one-fifth, .column.is-one-fifth-tablet { + flex: none; + width: 20%; } + .column.is-two-fifths, .column.is-two-fifths-tablet { + flex: none; + width: 40%; } + .column.is-three-fifths, .column.is-three-fifths-tablet { + flex: none; + width: 60%; } + .column.is-four-fifths, .column.is-four-fifths-tablet { + flex: none; + width: 80%; } + .column.is-offset-three-quarters, .column.is-offset-three-quarters-tablet { + margin-left: 75%; } + .column.is-offset-two-thirds, .column.is-offset-two-thirds-tablet { + margin-left: 66.6666%; } + .column.is-offset-half, .column.is-offset-half-tablet { + margin-left: 50%; } + .column.is-offset-one-third, .column.is-offset-one-third-tablet { + margin-left: 33.3333%; } + .column.is-offset-one-quarter, .column.is-offset-one-quarter-tablet { + margin-left: 25%; } + .column.is-offset-one-fifth, .column.is-offset-one-fifth-tablet { + margin-left: 20%; } + .column.is-offset-two-fifths, .column.is-offset-two-fifths-tablet { + margin-left: 40%; } + .column.is-offset-three-fifths, .column.is-offset-three-fifths-tablet { + margin-left: 60%; } + .column.is-offset-four-fifths, .column.is-offset-four-fifths-tablet { + margin-left: 80%; } + .column.is-1, .column.is-1-tablet { + flex: none; + width: 8.33333333%; } + .column.is-offset-1, .column.is-offset-1-tablet { + margin-left: 8.33333333%; } + .column.is-2, .column.is-2-tablet { + flex: none; + width: 16.66666667%; } + .column.is-offset-2, .column.is-offset-2-tablet { + margin-left: 16.66666667%; } + .column.is-3, .column.is-3-tablet { + flex: none; + width: 25%; } + .column.is-offset-3, .column.is-offset-3-tablet { + margin-left: 25%; } + .column.is-4, .column.is-4-tablet { + flex: none; + width: 33.33333333%; } + .column.is-offset-4, .column.is-offset-4-tablet { + margin-left: 33.33333333%; } + .column.is-5, .column.is-5-tablet { + flex: none; + width: 41.66666667%; } + .column.is-offset-5, .column.is-offset-5-tablet { + margin-left: 41.66666667%; } + .column.is-6, .column.is-6-tablet { + flex: none; + width: 50%; } + .column.is-offset-6, .column.is-offset-6-tablet { + margin-left: 50%; } + .column.is-7, .column.is-7-tablet { + flex: none; + width: 58.33333333%; } + .column.is-offset-7, .column.is-offset-7-tablet { + margin-left: 58.33333333%; } + .column.is-8, .column.is-8-tablet { + flex: none; + width: 66.66666667%; } + .column.is-offset-8, .column.is-offset-8-tablet { + margin-left: 66.66666667%; } + .column.is-9, .column.is-9-tablet { + flex: none; + width: 75%; } + .column.is-offset-9, .column.is-offset-9-tablet { + margin-left: 75%; } + .column.is-10, .column.is-10-tablet { + flex: none; + width: 83.33333333%; } + .column.is-offset-10, .column.is-offset-10-tablet { + margin-left: 83.33333333%; } + .column.is-11, .column.is-11-tablet { + flex: none; + width: 91.66666667%; } + .column.is-offset-11, .column.is-offset-11-tablet { + margin-left: 91.66666667%; } + .column.is-12, .column.is-12-tablet { + flex: none; + width: 100%; } + .column.is-offset-12, .column.is-offset-12-tablet { + margin-left: 100%; } } + @media screen and (max-width: 1087px) { + .column.is-narrow-touch { + flex: none; } + .column.is-full-touch { + flex: none; + width: 100%; } + .column.is-three-quarters-touch { + flex: none; + width: 75%; } + .column.is-two-thirds-touch { + flex: none; + width: 66.6666%; } + .column.is-half-touch { + flex: none; + width: 50%; } + .column.is-one-third-touch { + flex: none; + width: 33.3333%; } + .column.is-one-quarter-touch { + flex: none; + width: 25%; } + .column.is-one-fifth-touch { + flex: none; + width: 20%; } + .column.is-two-fifths-touch { + flex: none; + width: 40%; } + .column.is-three-fifths-touch { + flex: none; + width: 60%; } + .column.is-four-fifths-touch { + flex: none; + width: 80%; } + .column.is-offset-three-quarters-touch { + margin-left: 75%; } + .column.is-offset-two-thirds-touch { + margin-left: 66.6666%; } + .column.is-offset-half-touch { + margin-left: 50%; } + .column.is-offset-one-third-touch { + margin-left: 33.3333%; } + .column.is-offset-one-quarter-touch { + margin-left: 25%; } + .column.is-offset-one-fifth-touch { + margin-left: 20%; } + .column.is-offset-two-fifths-touch { + margin-left: 40%; } + .column.is-offset-three-fifths-touch { + margin-left: 60%; } + .column.is-offset-four-fifths-touch { + margin-left: 80%; } + .column.is-1-touch { + flex: none; + width: 8.33333333%; } + .column.is-offset-1-touch { + margin-left: 8.33333333%; } + .column.is-2-touch { + flex: none; + width: 16.66666667%; } + .column.is-offset-2-touch { + margin-left: 16.66666667%; } + .column.is-3-touch { + flex: none; + width: 25%; } + .column.is-offset-3-touch { + margin-left: 25%; } + .column.is-4-touch { + flex: none; + width: 33.33333333%; } + .column.is-offset-4-touch { + margin-left: 33.33333333%; } + .column.is-5-touch { + flex: none; + width: 41.66666667%; } + .column.is-offset-5-touch { + margin-left: 41.66666667%; } + .column.is-6-touch { + flex: none; + width: 50%; } + .column.is-offset-6-touch { + margin-left: 50%; } + .column.is-7-touch { + flex: none; + width: 58.33333333%; } + .column.is-offset-7-touch { + margin-left: 58.33333333%; } + .column.is-8-touch { + flex: none; + width: 66.66666667%; } + .column.is-offset-8-touch { + margin-left: 66.66666667%; } + .column.is-9-touch { + flex: none; + width: 75%; } + .column.is-offset-9-touch { + margin-left: 75%; } + .column.is-10-touch { + flex: none; + width: 83.33333333%; } + .column.is-offset-10-touch { + margin-left: 83.33333333%; } + .column.is-11-touch { + flex: none; + width: 91.66666667%; } + .column.is-offset-11-touch { + margin-left: 91.66666667%; } + .column.is-12-touch { + flex: none; + width: 100%; } + .column.is-offset-12-touch { + margin-left: 100%; } } + @media screen and (min-width: 1088px) { + .column.is-narrow-desktop { + flex: none; } + .column.is-full-desktop { + flex: none; + width: 100%; } + .column.is-three-quarters-desktop { + flex: none; + width: 75%; } + .column.is-two-thirds-desktop { + flex: none; + width: 66.6666%; } + .column.is-half-desktop { + flex: none; + width: 50%; } + .column.is-one-third-desktop { + flex: none; + width: 33.3333%; } + .column.is-one-quarter-desktop { + flex: none; + width: 25%; } + .column.is-one-fifth-desktop { + flex: none; + width: 20%; } + .column.is-two-fifths-desktop { + flex: none; + width: 40%; } + .column.is-three-fifths-desktop { + flex: none; + width: 60%; } + .column.is-four-fifths-desktop { + flex: none; + width: 80%; } + .column.is-offset-three-quarters-desktop { + margin-left: 75%; } + .column.is-offset-two-thirds-desktop { + margin-left: 66.6666%; } + .column.is-offset-half-desktop { + margin-left: 50%; } + .column.is-offset-one-third-desktop { + margin-left: 33.3333%; } + .column.is-offset-one-quarter-desktop { + margin-left: 25%; } + .column.is-offset-one-fifth-desktop { + margin-left: 20%; } + .column.is-offset-two-fifths-desktop { + margin-left: 40%; } + .column.is-offset-three-fifths-desktop { + margin-left: 60%; } + .column.is-offset-four-fifths-desktop { + margin-left: 80%; } + .column.is-1-desktop { + flex: none; + width: 8.33333333%; } + .column.is-offset-1-desktop { + margin-left: 8.33333333%; } + .column.is-2-desktop { + flex: none; + width: 16.66666667%; } + .column.is-offset-2-desktop { + margin-left: 16.66666667%; } + .column.is-3-desktop { + flex: none; + width: 25%; } + .column.is-offset-3-desktop { + margin-left: 25%; } + .column.is-4-desktop { + flex: none; + width: 33.33333333%; } + .column.is-offset-4-desktop { + margin-left: 33.33333333%; } + .column.is-5-desktop { + flex: none; + width: 41.66666667%; } + .column.is-offset-5-desktop { + margin-left: 41.66666667%; } + .column.is-6-desktop { + flex: none; + width: 50%; } + .column.is-offset-6-desktop { + margin-left: 50%; } + .column.is-7-desktop { + flex: none; + width: 58.33333333%; } + .column.is-offset-7-desktop { + margin-left: 58.33333333%; } + .column.is-8-desktop { + flex: none; + width: 66.66666667%; } + .column.is-offset-8-desktop { + margin-left: 66.66666667%; } + .column.is-9-desktop { + flex: none; + width: 75%; } + .column.is-offset-9-desktop { + margin-left: 75%; } + .column.is-10-desktop { + flex: none; + width: 83.33333333%; } + .column.is-offset-10-desktop { + margin-left: 83.33333333%; } + .column.is-11-desktop { + flex: none; + width: 91.66666667%; } + .column.is-offset-11-desktop { + margin-left: 91.66666667%; } + .column.is-12-desktop { + flex: none; + width: 100%; } + .column.is-offset-12-desktop { + margin-left: 100%; } } + @media screen and (min-width: 1280px) { + .column.is-narrow-widescreen { + flex: none; } + .column.is-full-widescreen { + flex: none; + width: 100%; } + .column.is-three-quarters-widescreen { + flex: none; + width: 75%; } + .column.is-two-thirds-widescreen { + flex: none; + width: 66.6666%; } + .column.is-half-widescreen { + flex: none; + width: 50%; } + .column.is-one-third-widescreen { + flex: none; + width: 33.3333%; } + .column.is-one-quarter-widescreen { + flex: none; + width: 25%; } + .column.is-one-fifth-widescreen { + flex: none; + width: 20%; } + .column.is-two-fifths-widescreen { + flex: none; + width: 40%; } + .column.is-three-fifths-widescreen { + flex: none; + width: 60%; } + .column.is-four-fifths-widescreen { + flex: none; + width: 80%; } + .column.is-offset-three-quarters-widescreen { + margin-left: 75%; } + .column.is-offset-two-thirds-widescreen { + margin-left: 66.6666%; } + .column.is-offset-half-widescreen { + margin-left: 50%; } + .column.is-offset-one-third-widescreen { + margin-left: 33.3333%; } + .column.is-offset-one-quarter-widescreen { + margin-left: 25%; } + .column.is-offset-one-fifth-widescreen { + margin-left: 20%; } + .column.is-offset-two-fifths-widescreen { + margin-left: 40%; } + .column.is-offset-three-fifths-widescreen { + margin-left: 60%; } + .column.is-offset-four-fifths-widescreen { + margin-left: 80%; } + .column.is-1-widescreen { + flex: none; + width: 8.33333333%; } + .column.is-offset-1-widescreen { + margin-left: 8.33333333%; } + .column.is-2-widescreen { + flex: none; + width: 16.66666667%; } + .column.is-offset-2-widescreen { + margin-left: 16.66666667%; } + .column.is-3-widescreen { + flex: none; + width: 25%; } + .column.is-offset-3-widescreen { + margin-left: 25%; } + .column.is-4-widescreen { + flex: none; + width: 33.33333333%; } + .column.is-offset-4-widescreen { + margin-left: 33.33333333%; } + .column.is-5-widescreen { + flex: none; + width: 41.66666667%; } + .column.is-offset-5-widescreen { + margin-left: 41.66666667%; } + .column.is-6-widescreen { + flex: none; + width: 50%; } + .column.is-offset-6-widescreen { + margin-left: 50%; } + .column.is-7-widescreen { + flex: none; + width: 58.33333333%; } + .column.is-offset-7-widescreen { + margin-left: 58.33333333%; } + .column.is-8-widescreen { + flex: none; + width: 66.66666667%; } + .column.is-offset-8-widescreen { + margin-left: 66.66666667%; } + .column.is-9-widescreen { + flex: none; + width: 75%; } + .column.is-offset-9-widescreen { + margin-left: 75%; } + .column.is-10-widescreen { + flex: none; + width: 83.33333333%; } + .column.is-offset-10-widescreen { + margin-left: 83.33333333%; } + .column.is-11-widescreen { + flex: none; + width: 91.66666667%; } + .column.is-offset-11-widescreen { + margin-left: 91.66666667%; } + .column.is-12-widescreen { + flex: none; + width: 100%; } + .column.is-offset-12-widescreen { + margin-left: 100%; } } +.columns { + margin-left: -0.75rem; + margin-right: -0.75rem; + margin-top: -0.75rem; } + .columns:last-child { + margin-bottom: -0.75rem; } + .columns:not(:last-child) { + margin-bottom: calc(1.5rem - 0.75rem); } + .columns.is-centered { + justify-content: center; } + .columns.is-gapless { + margin-left: 0; + margin-right: 0; + margin-top: 0; } + .columns.is-gapless > .column { + margin: 0; + padding: 0 !important; } + .columns.is-gapless:not(:last-child) { + margin-bottom: 1.5rem; } + .columns.is-gapless:last-child { + margin-bottom: 0; } + .columns.is-mobile { + display: flex; } + .columns.is-multiline { + flex-wrap: wrap; } + .columns.is-vcentered { + align-items: center; } + @media screen and (min-width: 769px), print { + .columns:not(.is-desktop) { + display: flex; } } + @media screen and (min-width: 1088px) { + .columns.is-desktop { + display: flex; } } +.columns.is-variable { + --columnGap: 0.75rem; + margin-left: calc(-1 * var(--columnGap)); + margin-right: calc(-1 * var(--columnGap)); } + .columns.is-variable .column { + padding-left: var(--columnGap); + padding-right: var(--columnGap); } + .columns.is-variable.is-0 { + --columnGap: 0rem; } + .columns.is-variable.is-1 { + --columnGap: 0.25rem; } + .columns.is-variable.is-2 { + --columnGap: 0.5rem; } + .columns.is-variable.is-3 { + --columnGap: 0.75rem; } + .columns.is-variable.is-4 { + --columnGap: 1rem; } + .columns.is-variable.is-5 { + --columnGap: 1.25rem; } + .columns.is-variable.is-6 { + --columnGap: 1.5rem; } + .columns.is-variable.is-7 { + --columnGap: 1.75rem; } + .columns.is-variable.is-8 { + --columnGap: 2rem; } + +.tile { + align-items: stretch; + display: block; + flex-basis: 0; + flex-grow: 1; + flex-shrink: 1; + min-height: min-content; } + .tile.is-ancestor { + margin-left: -0.75rem; + margin-right: -0.75rem; + margin-top: -0.75rem; } + .tile.is-ancestor:last-child { + margin-bottom: -0.75rem; } + .tile.is-ancestor:not(:last-child) { + margin-bottom: 0.75rem; } + .tile.is-child { + margin: 0 !important; } + .tile.is-parent { + padding: 0.75rem; } + .tile.is-vertical { + flex-direction: column; } + .tile.is-vertical > .tile.is-child:not(:last-child) { + margin-bottom: 1.5rem !important; } + @media screen and (min-width: 769px), print { + .tile:not(.is-child) { + display: flex; } + .tile.is-1 { + flex: none; + width: 8.33333333%; } + .tile.is-2 { + flex: none; + width: 16.66666667%; } + .tile.is-3 { + flex: none; + width: 25%; } + .tile.is-4 { + flex: none; + width: 33.33333333%; } + .tile.is-5 { + flex: none; + width: 41.66666667%; } + .tile.is-6 { + flex: none; + width: 50%; } + .tile.is-7 { + flex: none; + width: 58.33333333%; } + .tile.is-8 { + flex: none; + width: 66.66666667%; } + .tile.is-9 { + flex: none; + width: 75%; } + .tile.is-10 { + flex: none; + width: 83.33333333%; } + .tile.is-11 { + flex: none; + width: 91.66666667%; } + .tile.is-12 { + flex: none; + width: 100%; } } +.hero { + align-items: stretch; + display: flex; + flex-direction: column; + justify-content: space-between; } + .hero .navbar { + background: none; } + .hero .tabs ul { + border-bottom: none; } + .hero.is-white { + background-color: white; + color: #0a0a0a; } + .hero.is-white a:not(.button):not(.dropdown-item):not(.tag), + .hero.is-white strong { + color: inherit; } + .hero.is-white .title { + color: #0a0a0a; } + .hero.is-white .subtitle { + color: rgba(10, 10, 10, 0.9); } + .hero.is-white .subtitle a:not(.button), + .hero.is-white .subtitle strong { + color: #0a0a0a; } + @media screen and (max-width: 1087px) { + .hero.is-white .navbar-menu { + background-color: white; } } + .hero.is-white .navbar-item, + .hero.is-white .navbar-link { + color: rgba(10, 10, 10, 0.7); } + .hero.is-white a.navbar-item:hover, .hero.is-white a.navbar-item.is-active, + .hero.is-white .navbar-link:hover, + .hero.is-white .navbar-link.is-active { + background-color: #f2f2f2; + color: #0a0a0a; } + .hero.is-white .tabs a { + color: #0a0a0a; + opacity: 0.9; } + .hero.is-white .tabs a:hover { + opacity: 1; } + .hero.is-white .tabs li.is-active a { + opacity: 1; } + .hero.is-white .tabs.is-boxed a, .hero.is-white .tabs.is-toggle a { + color: #0a0a0a; } + .hero.is-white .tabs.is-boxed a:hover, .hero.is-white .tabs.is-toggle a:hover { + background-color: rgba(10, 10, 10, 0.1); } + .hero.is-white .tabs.is-boxed li.is-active a, .hero.is-white .tabs.is-boxed li.is-active a:hover, .hero.is-white .tabs.is-toggle li.is-active a, .hero.is-white .tabs.is-toggle li.is-active a:hover { + background-color: #0a0a0a; + border-color: #0a0a0a; + color: white; } + .hero.is-white.is-bold { + background-image: linear-gradient(141deg, #e8e3e4 0%, white 71%, white 100%); } + @media screen and (max-width: 768px) { + .hero.is-white.is-bold .navbar-menu { + background-image: linear-gradient(141deg, #e8e3e4 0%, white 71%, white 100%); } } + .hero.is-black { + background-color: #0a0a0a; + color: white; } + .hero.is-black a:not(.button):not(.dropdown-item):not(.tag), + .hero.is-black strong { + color: inherit; } + .hero.is-black .title { + color: white; } + .hero.is-black .subtitle { + color: rgba(255, 255, 255, 0.9); } + .hero.is-black .subtitle a:not(.button), + .hero.is-black .subtitle strong { + color: white; } + @media screen and (max-width: 1087px) { + .hero.is-black .navbar-menu { + background-color: #0a0a0a; } } + .hero.is-black .navbar-item, + .hero.is-black .navbar-link { + color: rgba(255, 255, 255, 0.7); } + .hero.is-black a.navbar-item:hover, .hero.is-black a.navbar-item.is-active, + .hero.is-black .navbar-link:hover, + .hero.is-black .navbar-link.is-active { + background-color: black; + color: white; } + .hero.is-black .tabs a { + color: white; + opacity: 0.9; } + .hero.is-black .tabs a:hover { + opacity: 1; } + .hero.is-black .tabs li.is-active a { + opacity: 1; } + .hero.is-black .tabs.is-boxed a, .hero.is-black .tabs.is-toggle a { + color: white; } + .hero.is-black .tabs.is-boxed a:hover, .hero.is-black .tabs.is-toggle a:hover { + background-color: rgba(10, 10, 10, 0.1); } + .hero.is-black .tabs.is-boxed li.is-active a, .hero.is-black .tabs.is-boxed li.is-active a:hover, .hero.is-black .tabs.is-toggle li.is-active a, .hero.is-black .tabs.is-toggle li.is-active a:hover { + background-color: white; + border-color: white; + color: #0a0a0a; } + .hero.is-black.is-bold { + background-image: linear-gradient(141deg, black 0%, #0a0a0a 71%, #181616 100%); } + @media screen and (max-width: 768px) { + .hero.is-black.is-bold .navbar-menu { + background-image: linear-gradient(141deg, black 0%, #0a0a0a 71%, #181616 100%); } } + .hero.is-light { + background-color: whitesmoke; + color: #363636; } + .hero.is-light a:not(.button):not(.dropdown-item):not(.tag), + .hero.is-light strong { + color: inherit; } + .hero.is-light .title { + color: #363636; } + .hero.is-light .subtitle { + color: rgba(54, 54, 54, 0.9); } + .hero.is-light .subtitle a:not(.button), + .hero.is-light .subtitle strong { + color: #363636; } + @media screen and (max-width: 1087px) { + .hero.is-light .navbar-menu { + background-color: whitesmoke; } } + .hero.is-light .navbar-item, + .hero.is-light .navbar-link { + color: rgba(54, 54, 54, 0.7); } + .hero.is-light a.navbar-item:hover, .hero.is-light a.navbar-item.is-active, + .hero.is-light .navbar-link:hover, + .hero.is-light .navbar-link.is-active { + background-color: #e8e8e8; + color: #363636; } + .hero.is-light .tabs a { + color: #363636; + opacity: 0.9; } + .hero.is-light .tabs a:hover { + opacity: 1; } + .hero.is-light .tabs li.is-active a { + opacity: 1; } + .hero.is-light .tabs.is-boxed a, .hero.is-light .tabs.is-toggle a { + color: #363636; } + .hero.is-light .tabs.is-boxed a:hover, .hero.is-light .tabs.is-toggle a:hover { + background-color: rgba(10, 10, 10, 0.1); } + .hero.is-light .tabs.is-boxed li.is-active a, .hero.is-light .tabs.is-boxed li.is-active a:hover, .hero.is-light .tabs.is-toggle li.is-active a, .hero.is-light .tabs.is-toggle li.is-active a:hover { + background-color: #363636; + border-color: #363636; + color: whitesmoke; } + .hero.is-light.is-bold { + background-image: linear-gradient(141deg, #dfd8d9 0%, whitesmoke 71%, white 100%); } + @media screen and (max-width: 768px) { + .hero.is-light.is-bold .navbar-menu { + background-image: linear-gradient(141deg, #dfd8d9 0%, whitesmoke 71%, white 100%); } } + .hero.is-dark { + background-color: #363636; + color: whitesmoke; } + .hero.is-dark a:not(.button):not(.dropdown-item):not(.tag), + .hero.is-dark strong { + color: inherit; } + .hero.is-dark .title { + color: whitesmoke; } + .hero.is-dark .subtitle { + color: rgba(245, 245, 245, 0.9); } + .hero.is-dark .subtitle a:not(.button), + .hero.is-dark .subtitle strong { + color: whitesmoke; } + @media screen and (max-width: 1087px) { + .hero.is-dark .navbar-menu { + background-color: #363636; } } + .hero.is-dark .navbar-item, + .hero.is-dark .navbar-link { + color: rgba(245, 245, 245, 0.7); } + .hero.is-dark a.navbar-item:hover, .hero.is-dark a.navbar-item.is-active, + .hero.is-dark .navbar-link:hover, + .hero.is-dark .navbar-link.is-active { + background-color: #292929; + color: whitesmoke; } + .hero.is-dark .tabs a { + color: whitesmoke; + opacity: 0.9; } + .hero.is-dark .tabs a:hover { + opacity: 1; } + .hero.is-dark .tabs li.is-active a { + opacity: 1; } + .hero.is-dark .tabs.is-boxed a, .hero.is-dark .tabs.is-toggle a { + color: whitesmoke; } + .hero.is-dark .tabs.is-boxed a:hover, .hero.is-dark .tabs.is-toggle a:hover { + background-color: rgba(10, 10, 10, 0.1); } + .hero.is-dark .tabs.is-boxed li.is-active a, .hero.is-dark .tabs.is-boxed li.is-active a:hover, .hero.is-dark .tabs.is-toggle li.is-active a, .hero.is-dark .tabs.is-toggle li.is-active a:hover { + background-color: whitesmoke; + border-color: whitesmoke; + color: #363636; } + .hero.is-dark.is-bold { + background-image: linear-gradient(141deg, #1f191a 0%, #363636 71%, #46403f 100%); } + @media screen and (max-width: 768px) { + .hero.is-dark.is-bold .navbar-menu { + background-image: linear-gradient(141deg, #1f191a 0%, #363636 71%, #46403f 100%); } } + .hero.is-primary { + background-color: #00d1b2; + color: #fff; } + .hero.is-primary a:not(.button):not(.dropdown-item):not(.tag), + .hero.is-primary strong { + color: inherit; } + .hero.is-primary .title { + color: #fff; } + .hero.is-primary .subtitle { + color: rgba(255, 255, 255, 0.9); } + .hero.is-primary .subtitle a:not(.button), + .hero.is-primary .subtitle strong { + color: #fff; } + @media screen and (max-width: 1087px) { + .hero.is-primary .navbar-menu { + background-color: #00d1b2; } } + .hero.is-primary .navbar-item, + .hero.is-primary .navbar-link { + color: rgba(255, 255, 255, 0.7); } + .hero.is-primary a.navbar-item:hover, .hero.is-primary a.navbar-item.is-active, + .hero.is-primary .navbar-link:hover, + .hero.is-primary .navbar-link.is-active { + background-color: #00b89c; + color: #fff; } + .hero.is-primary .tabs a { + color: #fff; + opacity: 0.9; } + .hero.is-primary .tabs a:hover { + opacity: 1; } + .hero.is-primary .tabs li.is-active a { + opacity: 1; } + .hero.is-primary .tabs.is-boxed a, .hero.is-primary .tabs.is-toggle a { + color: #fff; } + .hero.is-primary .tabs.is-boxed a:hover, .hero.is-primary .tabs.is-toggle a:hover { + background-color: rgba(10, 10, 10, 0.1); } + .hero.is-primary .tabs.is-boxed li.is-active a, .hero.is-primary .tabs.is-boxed li.is-active a:hover, .hero.is-primary .tabs.is-toggle li.is-active a, .hero.is-primary .tabs.is-toggle li.is-active a:hover { + background-color: #fff; + border-color: #fff; + color: #00d1b2; } + .hero.is-primary.is-bold { + background-image: linear-gradient(141deg, #009e6c 0%, #00d1b2 71%, #00e7eb 100%); } + @media screen and (max-width: 768px) { + .hero.is-primary.is-bold .navbar-menu { + background-image: linear-gradient(141deg, #009e6c 0%, #00d1b2 71%, #00e7eb 100%); } } + .hero.is-link { + background-color: #3273dc; + color: #fff; } + .hero.is-link a:not(.button):not(.dropdown-item):not(.tag), + .hero.is-link strong { + color: inherit; } + .hero.is-link .title { + color: #fff; } + .hero.is-link .subtitle { + color: rgba(255, 255, 255, 0.9); } + .hero.is-link .subtitle a:not(.button), + .hero.is-link .subtitle strong { + color: #fff; } + @media screen and (max-width: 1087px) { + .hero.is-link .navbar-menu { + background-color: #3273dc; } } + .hero.is-link .navbar-item, + .hero.is-link .navbar-link { + color: rgba(255, 255, 255, 0.7); } + .hero.is-link a.navbar-item:hover, .hero.is-link a.navbar-item.is-active, + .hero.is-link .navbar-link:hover, + .hero.is-link .navbar-link.is-active { + background-color: #2366d1; + color: #fff; } + .hero.is-link .tabs a { + color: #fff; + opacity: 0.9; } + .hero.is-link .tabs a:hover { + opacity: 1; } + .hero.is-link .tabs li.is-active a { + opacity: 1; } + .hero.is-link .tabs.is-boxed a, .hero.is-link .tabs.is-toggle a { + color: #fff; } + .hero.is-link .tabs.is-boxed a:hover, .hero.is-link .tabs.is-toggle a:hover { + background-color: rgba(10, 10, 10, 0.1); } + .hero.is-link .tabs.is-boxed li.is-active a, .hero.is-link .tabs.is-boxed li.is-active a:hover, .hero.is-link .tabs.is-toggle li.is-active a, .hero.is-link .tabs.is-toggle li.is-active a:hover { + background-color: #fff; + border-color: #fff; + color: #3273dc; } + .hero.is-link.is-bold { + background-image: linear-gradient(141deg, #1577c6 0%, #3273dc 71%, #4366e5 100%); } + @media screen and (max-width: 768px) { + .hero.is-link.is-bold .navbar-menu { + background-image: linear-gradient(141deg, #1577c6 0%, #3273dc 71%, #4366e5 100%); } } + .hero.is-info { + background-color: #209cee; + color: #fff; } + .hero.is-info a:not(.button):not(.dropdown-item):not(.tag), + .hero.is-info strong { + color: inherit; } + .hero.is-info .title { + color: #fff; } + .hero.is-info .subtitle { + color: rgba(255, 255, 255, 0.9); } + .hero.is-info .subtitle a:not(.button), + .hero.is-info .subtitle strong { + color: #fff; } + @media screen and (max-width: 1087px) { + .hero.is-info .navbar-menu { + background-color: #209cee; } } + .hero.is-info .navbar-item, + .hero.is-info .navbar-link { + color: rgba(255, 255, 255, 0.7); } + .hero.is-info a.navbar-item:hover, .hero.is-info a.navbar-item.is-active, + .hero.is-info .navbar-link:hover, + .hero.is-info .navbar-link.is-active { + background-color: #118fe4; + color: #fff; } + .hero.is-info .tabs a { + color: #fff; + opacity: 0.9; } + .hero.is-info .tabs a:hover { + opacity: 1; } + .hero.is-info .tabs li.is-active a { + opacity: 1; } + .hero.is-info .tabs.is-boxed a, .hero.is-info .tabs.is-toggle a { + color: #fff; } + .hero.is-info .tabs.is-boxed a:hover, .hero.is-info .tabs.is-toggle a:hover { + background-color: rgba(10, 10, 10, 0.1); } + .hero.is-info .tabs.is-boxed li.is-active a, .hero.is-info .tabs.is-boxed li.is-active a:hover, .hero.is-info .tabs.is-toggle li.is-active a, .hero.is-info .tabs.is-toggle li.is-active a:hover { + background-color: #fff; + border-color: #fff; + color: #209cee; } + .hero.is-info.is-bold { + background-image: linear-gradient(141deg, #04a6d7 0%, #209cee 71%, #3287f5 100%); } + @media screen and (max-width: 768px) { + .hero.is-info.is-bold .navbar-menu { + background-image: linear-gradient(141deg, #04a6d7 0%, #209cee 71%, #3287f5 100%); } } + .hero.is-success { + background-color: #23d160; + color: #fff; } + .hero.is-success a:not(.button):not(.dropdown-item):not(.tag), + .hero.is-success strong { + color: inherit; } + .hero.is-success .title { + color: #fff; } + .hero.is-success .subtitle { + color: rgba(255, 255, 255, 0.9); } + .hero.is-success .subtitle a:not(.button), + .hero.is-success .subtitle strong { + color: #fff; } + @media screen and (max-width: 1087px) { + .hero.is-success .navbar-menu { + background-color: #23d160; } } + .hero.is-success .navbar-item, + .hero.is-success .navbar-link { + color: rgba(255, 255, 255, 0.7); } + .hero.is-success a.navbar-item:hover, .hero.is-success a.navbar-item.is-active, + .hero.is-success .navbar-link:hover, + .hero.is-success .navbar-link.is-active { + background-color: #20bc56; + color: #fff; } + .hero.is-success .tabs a { + color: #fff; + opacity: 0.9; } + .hero.is-success .tabs a:hover { + opacity: 1; } + .hero.is-success .tabs li.is-active a { + opacity: 1; } + .hero.is-success .tabs.is-boxed a, .hero.is-success .tabs.is-toggle a { + color: #fff; } + .hero.is-success .tabs.is-boxed a:hover, .hero.is-success .tabs.is-toggle a:hover { + background-color: rgba(10, 10, 10, 0.1); } + .hero.is-success .tabs.is-boxed li.is-active a, .hero.is-success .tabs.is-boxed li.is-active a:hover, .hero.is-success .tabs.is-toggle li.is-active a, .hero.is-success .tabs.is-toggle li.is-active a:hover { + background-color: #fff; + border-color: #fff; + color: #23d160; } + .hero.is-success.is-bold { + background-image: linear-gradient(141deg, #12af2f 0%, #23d160 71%, #2ce28a 100%); } + @media screen and (max-width: 768px) { + .hero.is-success.is-bold .navbar-menu { + background-image: linear-gradient(141deg, #12af2f 0%, #23d160 71%, #2ce28a 100%); } } + .hero.is-warning { + background-color: #ffdd57; + color: rgba(0, 0, 0, 0.7); } + .hero.is-warning a:not(.button):not(.dropdown-item):not(.tag), + .hero.is-warning strong { + color: inherit; } + .hero.is-warning .title { + color: rgba(0, 0, 0, 0.7); } + .hero.is-warning .subtitle { + color: rgba(0, 0, 0, 0.9); } + .hero.is-warning .subtitle a:not(.button), + .hero.is-warning .subtitle strong { + color: rgba(0, 0, 0, 0.7); } + @media screen and (max-width: 1087px) { + .hero.is-warning .navbar-menu { + background-color: #ffdd57; } } + .hero.is-warning .navbar-item, + .hero.is-warning .navbar-link { + color: rgba(0, 0, 0, 0.7); } + .hero.is-warning a.navbar-item:hover, .hero.is-warning a.navbar-item.is-active, + .hero.is-warning .navbar-link:hover, + .hero.is-warning .navbar-link.is-active { + background-color: #ffd83d; + color: rgba(0, 0, 0, 0.7); } + .hero.is-warning .tabs a { + color: rgba(0, 0, 0, 0.7); + opacity: 0.9; } + .hero.is-warning .tabs a:hover { + opacity: 1; } + .hero.is-warning .tabs li.is-active a { + opacity: 1; } + .hero.is-warning .tabs.is-boxed a, .hero.is-warning .tabs.is-toggle a { + color: rgba(0, 0, 0, 0.7); } + .hero.is-warning .tabs.is-boxed a:hover, .hero.is-warning .tabs.is-toggle a:hover { + background-color: rgba(10, 10, 10, 0.1); } + .hero.is-warning .tabs.is-boxed li.is-active a, .hero.is-warning .tabs.is-boxed li.is-active a:hover, .hero.is-warning .tabs.is-toggle li.is-active a, .hero.is-warning .tabs.is-toggle li.is-active a:hover { + background-color: rgba(0, 0, 0, 0.7); + border-color: rgba(0, 0, 0, 0.7); + color: #ffdd57; } + .hero.is-warning.is-bold { + background-image: linear-gradient(141deg, #ffaf24 0%, #ffdd57 71%, #fffa70 100%); } + @media screen and (max-width: 768px) { + .hero.is-warning.is-bold .navbar-menu { + background-image: linear-gradient(141deg, #ffaf24 0%, #ffdd57 71%, #fffa70 100%); } } + .hero.is-danger { + background-color: #ff3860; + color: #fff; } + .hero.is-danger a:not(.button):not(.dropdown-item):not(.tag), + .hero.is-danger strong { + color: inherit; } + .hero.is-danger .title { + color: #fff; } + .hero.is-danger .subtitle { + color: rgba(255, 255, 255, 0.9); } + .hero.is-danger .subtitle a:not(.button), + .hero.is-danger .subtitle strong { + color: #fff; } + @media screen and (max-width: 1087px) { + .hero.is-danger .navbar-menu { + background-color: #ff3860; } } + .hero.is-danger .navbar-item, + .hero.is-danger .navbar-link { + color: rgba(255, 255, 255, 0.7); } + .hero.is-danger a.navbar-item:hover, .hero.is-danger a.navbar-item.is-active, + .hero.is-danger .navbar-link:hover, + .hero.is-danger .navbar-link.is-active { + background-color: #ff1f4b; + color: #fff; } + .hero.is-danger .tabs a { + color: #fff; + opacity: 0.9; } + .hero.is-danger .tabs a:hover { + opacity: 1; } + .hero.is-danger .tabs li.is-active a { + opacity: 1; } + .hero.is-danger .tabs.is-boxed a, .hero.is-danger .tabs.is-toggle a { + color: #fff; } + .hero.is-danger .tabs.is-boxed a:hover, .hero.is-danger .tabs.is-toggle a:hover { + background-color: rgba(10, 10, 10, 0.1); } + .hero.is-danger .tabs.is-boxed li.is-active a, .hero.is-danger .tabs.is-boxed li.is-active a:hover, .hero.is-danger .tabs.is-toggle li.is-active a, .hero.is-danger .tabs.is-toggle li.is-active a:hover { + background-color: #fff; + border-color: #fff; + color: #ff3860; } + .hero.is-danger.is-bold { + background-image: linear-gradient(141deg, #ff0561 0%, #ff3860 71%, #ff5257 100%); } + @media screen and (max-width: 768px) { + .hero.is-danger.is-bold .navbar-menu { + background-image: linear-gradient(141deg, #ff0561 0%, #ff3860 71%, #ff5257 100%); } } + .hero.is-small .hero-body { + padding-bottom: 1.5rem; + padding-top: 1.5rem; } + @media screen and (min-width: 769px), print { + .hero.is-medium .hero-body { + padding-bottom: 9rem; + padding-top: 9rem; } } + @media screen and (min-width: 769px), print { + .hero.is-large .hero-body { + padding-bottom: 18rem; + padding-top: 18rem; } } + .hero.is-halfheight .hero-body, .hero.is-fullheight .hero-body { + align-items: center; + display: flex; } + .hero.is-halfheight .hero-body > .container, .hero.is-fullheight .hero-body > .container { + flex-grow: 1; + flex-shrink: 1; } + .hero.is-halfheight { + min-height: 50vh; } + .hero.is-fullheight { + min-height: 100vh; } + +.hero-video { + overflow: hidden; } + .hero-video video { + left: 50%; + min-height: 100%; + min-width: 100%; + position: absolute; + top: 50%; + transform: translate3d(-50%, -50%, 0); } + .hero-video.is-transparent { + opacity: 0.3; } + @media screen and (max-width: 768px) { + .hero-video { + display: none; } } +.hero-buttons { + margin-top: 1.5rem; } + @media screen and (max-width: 768px) { + .hero-buttons .button { + display: flex; } + .hero-buttons .button:not(:last-child) { + margin-bottom: 0.75rem; } } + @media screen and (min-width: 769px), print { + .hero-buttons { + display: flex; + justify-content: center; } + .hero-buttons .button:not(:last-child) { + margin-right: 1.5rem; } } +.hero-head, +.hero-foot { + flex-grow: 0; + flex-shrink: 0; } + +.hero-body { + flex-grow: 1; + flex-shrink: 0; + padding: 3rem 1.5rem; } + +.section { + padding: 3rem 1.5rem; } + @media screen and (min-width: 1088px) { + .section.is-medium { + padding: 9rem 1.5rem; } + .section.is-large { + padding: 18rem 1.5rem; } } +.footer { + background-color: #fafafa; + padding: 3rem 1.5rem 6rem; } + +/* ========================================================================== +Main SCSS file / Fresh +========================================================================== */ +/* ========================================================================== +Color variables +========================================================================== */ +/* ========================================================================== +Navbar +========================================================================== */ +.navbar.is-fresh { + position: relative; + min-height: 3.8rem; + transition: all .3s; + z-index: 99; } + .navbar.is-fresh .container { + min-height: 4rem; } + .navbar.is-fresh.no-shadow { + box-shadow: none !important; } + .navbar.is-fresh .navbar-burger { + width: 4rem; + height: 4rem; } + .navbar.is-fresh .navbar-brand { + min-height: 4rem; } + .navbar.is-fresh .navbar-brand:hover .navbar-item { + background: transparent !important; } + .navbar.is-fresh .navbar-end { + align-items: center; } + .navbar.is-fresh .navbar-item { + color: #999; } + .navbar.is-fresh .navbar-item.has-dropdown { + padding: 10px 0; } + .navbar.is-fresh .navbar-item.has-dropdown .navbar-link { + color: #999; } + .navbar.is-fresh .navbar-item.has-dropdown .navbar-link:after { + top: 55%; + height: 0.5em; + width: 0.5em; + border-width: 2px; + border-color: #999; } + .navbar.is-fresh .navbar-item.has-dropdown .navbar-dropdown { + top: 3.4rem; + min-width: 220px; + margin-top: 4px; + border-top-color: #F39200; } + .navbar.is-fresh .navbar-item.has-dropdown .navbar-dropdown .navbar-item { + padding: 10px 20px; } + .navbar.is-fresh .navbar-item.has-dropdown:hover .navbar-link { + color: #F39200; } + .navbar.is-fresh .navbar-item.has-dropdown:hover .navbar-link:after { + border-color: #F39200; } + .navbar.is-fresh .navbar-item .signup { + display: block; + line-height: 0; + font-size: .9rem !important; } + .navbar.is-fresh.is-fixed { + position: fixed; + top: 0; + left: 0; + width: 100%; + min-height: 4rem !important; + background: #fff; + box-shadow: 0 0 8px 0 rgba(0, 0, 0, 0.12); } + .navbar.is-fresh.is-fixed a { + color: #444F60; } + .navbar.is-fresh.is-fixed a:hover { + color: #4FC1EA; } + +#navbar-clone { + position: fixed; + top: 0; + left: 0; + width: 100vw; + background: #fff; + transform: translateY(-100%); + z-index: 100; + box-shadow: 0 0 8px 0 rgba(0, 0, 0, 0.12); } + #navbar-clone.is-active { + transform: translateY(0); } + +/* ========================================================================== +Dropdown styles +========================================================================== */ +div.nav-item.is-drop a { + padding-right: 7px; } + +div.nav-item.is-drop:hover .dropContain .dropOut { + opacity: 1; } + +div.nav-item.is-drop:hover, div.nav-item.is-drop:hover a { + border-bottom: 1px solid transparent !important; + color: #F39200; } + +div.nav-item.is-drop:hover .dropContain { + top: 65px; + animation: fadeInUp 0.27s ease-out; } + +span.drop-caret { + position: relative; + top: 5px; } + +div.nav-item.is-drop { + position: relative; } + div.nav-item.is-drop .dropContain { + width: 220px; + position: absolute; + z-index: 3; + left: 50%; + margin-left: -110px; + /* half of width */ + top: -400px; } + div.nav-item.is-drop .dropContain .dropOut { + width: 220px; + background: #fff; + float: left; + position: relative; + margin-top: 15px; + opacity: 0; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: 0 1px 6px rgba(0, 0, 0, 0.15); + -moz-box-shadow: 0 1px 6px rgba(0, 0, 0, 0.15); + box-shadow: 0 1px 6px rgba(0, 0, 0, 0.15); + -webkit-transition: all .5s ease-out; + -moz-transition: all .5s ease-out; + -ms-transition: all .5s ease-out; + -o-transition: all .5s ease-out; + transition: all .5s ease-out; } + div.nav-item.is-drop .dropContain .dropOut .triangle { + width: 0; + height: 0; + position: absolute; + border-left: 8px solid transparent; + border-right: 8px solid transparent; + border-bottom: 8px solid #fff; + top: -8px; + left: 50%; + margin-left: -8px; } + div.nav-item.is-drop .dropContain .dropOut ul li { + text-align: left; + float: left; + width: 200px; + padding: 12px 0 10px 15px; + margin: 0px 10px; + color: #777; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-transition: background .1s ease-out; + -moz-transition: background .1s ease-out; + -ms-transition: background .1s ease-out; + -o-transition: background .1s ease-out; + transition: background .1s ease-out; } + div.nav-item.is-drop .dropContain .dropOut ul li:hover { + background: #EFF4F7; + cursor: pointer; } + div.nav-item.is-drop .dropContain .dropOut ul { + float: left; + padding: 10px 0; } + +/* ========================================================================== +Section Styles +========================================================================== */ +.section.section-light-grey { + background-color: #EFF4F7; } + +.section.section-feature-grey { + background-color: #fbfbfb; } + +.section.section-secondary { + background-color: #F39200; } + +.section.section-half { + height: 75vh !important; } + +.section .title, .section .subtitle { + font-family: 'Open Sans', sans-serif; } + +.section .subtitle.is-muted { + color: #999; } + +.title-wrapper { + max-width: 500px; + margin: 0 auto; } + .title-wrapper .title, .title-wrapper .subtitle { + font-family: 'Open Sans', sans-serif; } + .title-wrapper .subtitle.is-muted { + color: #999; } + +.divider { + height: 3px; + border-radius: 50px; + background: #F39200; + width: 60px; } + .divider.is-centered { + margin: 0 auto; } + +.content-wrapper { + padding: 60px 0; } + +img.pushed-image { + margin-top: -5vh; } + +.media.icon-box { + border-top: none !important; } + .media.icon-box .media-content .content p span { + display: block; } + .media.icon-box .media-content .content p .icon-box-title { + color: #444F60; + font-size: 1.2rem; + font-weight: 600; } + .media.icon-box .media-content .content p .icon-box-text { + color: #A9ABAC; + font-size: 1rem; + font-weight: 400; } + +/* ========================================================================== +Hero styles +========================================================================== */ +.hero-body { + padding-top: 6rem; + padding-bottom: 6rem; } + .hero-body .title, .hero-body .subtitle { + font-family: 'Open Sans', sans-serif; } + .hero-body .title.is-bold { + font-weight: 700; } + .hero-body .subtitle.is-muted { + color: #999; } + +.hero-foot img.partner-logo { + height: 70px; } + +/* ========================================================================== +Fresh Footer +========================================================================== */ +footer.footer-dark { + background: #444F60; + color: #fff; } + footer.footer-dark .columns { + margin-top: 35px; } + footer.footer-dark .footer-logo img { + height: 40px; } + footer.footer-dark .footer-column .footer-header h3 { + font-weight: 500; + font-size: 1.2rem; + text-transform: uppercase; + letter-spacing: 1px; + margin-bottom: 20px; } + footer.footer-dark .footer-column ul.link-list { + line-height: 40px; + font-size: 1.1rem; } + footer.footer-dark .footer-column ul.link-list a { + color: #98a9c3; + font-weight: 400; + transition: all 0.5s; } + footer.footer-dark .footer-column ul.link-list :hover { + color: #fcfcfc; } + footer.footer-dark .footer-column .level-item .icon { + color: #F39200; + transition: all 0.5s; } + footer.footer-dark .footer-column .level-item .icon :hover { + color: #fcfcfc; } + +/* ========================================================================== +Classes to change the feel of bulma buttons +========================================================================== */ +.button { + cursor: pointer; + transition: all 0.5s; } + .button.cta { + font-family: 'Open Sans', sans-serif; + font-size: 1rem; + font-weight: 600; + padding: 26px 40px 26px 40px; } + .button.is-clear { + line-height: 0 !important; } + .button.rounded { + border-radius: 500px; } + .button.raised:hover { + box-shadow: 0 14px 26px -12px rgba(0, 0, 0, 0.42), 0 4px 23px 0px rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(0, 0, 0, 0.2) !important; + opacity: 0.8; } + .button.btn-outlined { + background: transparent; } + .button.signup-button { + font-size: .9rem; + font-weight: 600; + font-family: 'Open Sans', sans-serif; + padding: 24px 26px; + width: 130px; } + +.button.primary-btn { + outline: none; + border-color: #4FC1EA; + background-color: #4FC1EA; + color: #fff; + transition: all 0.5s; } + .button.primary-btn:hover { + color: #fff; } + .button.primary-btn.raised:hover { + box-shadow: 0 14px 26px -12px rgba(79, 193, 234, 0.42), 0 4px 23px 0px rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(79, 193, 234, 0.2) !important; + opacity: 0.8; } + .button.primary-btn.btn-outlined { + border-color: #4FC1EA; + color: #4FC1EA; + background-color: transparent; } + .button.primary-btn.btn-outlined:hover { + color: #fff; + background-color: #4FC1EA; } + +.button.secondary-btn { + outline: none; + border-color: #F39200; + background-color: #F39200; + color: #fff; + transition: all 0.5s; } + .button.secondary-btn:hover { + color: #fff; } + .button.secondary-btn.raised:hover { + box-shadow: 0 14px 26px -12px rgba(243, 146, 0, 0.42), 0 4px 23px 0px rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(243, 146, 0, 0.2) !important; + opacity: 0.8; } + .button.secondary-btn.btn-outlined { + border-color: #F39200; + color: #F39200; + background-color: transparent; } + .button.secondary-btn.btn-outlined:hover { + color: #fff; + background-color: #F39200; } + +.button.button.accent-btn { + outline: none; + border-color: #00efb7; + background-color: #00efb7; + color: #fff; + transition: all 0.5s; } + .button.button.accent-btn:hover { + color: #fff; } + .button.button.accent-btn.raised:hover { + box-shadow: 0 14px 26px -12px rgba(104, 187, 136, 0.42), 0 4px 23px 0px rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(104, 187, 136, 0.2) !important; + opacity: 0.8; } + .button.button.accent-btn.btn-outlined { + border-color: #00efb7; + color: #00efb7; + background-color: transparent; } + .button.button.accent-btn.btn-outlined:hover { + color: #fff; + background-color: #00efb7; } + +/*! _cards.scss v1.0.0 | Commercial License | built on top of bulma.io/Bulmax */ +/* ========================================================================== +Cards and Card content styles +========================================================================== */ +.feature-card { + width: 300px; + height: 320px; + background-color: #fff; + border-radius: 3px; + margin: 0 auto; } + .feature-card .card-title h4 { + font-family: 'Open Sans', sans-serif; + padding-top: 25px; + font-size: 1.2rem; + font-weight: 600; + color: #444F60; } + .feature-card .card-icon img { + height: 120px; + margin-top: 20px; } + .feature-card .card-text { + padding: 0 40px; } + .feature-card .card-text p { + color: #999; } + .feature-card .card-action { + margin-top: 10px; } + .feature-card.is-bordered { + border: 1px solid #ededed; } + +.flex-card { + position: relative; + background-color: #fff; + border: 0; + border-radius: 0.1875rem; + display: inline-block; + position: relative; + overflow: hidden; + width: 100%; + margin-bottom: 20px; } + .flex-card.raised { + box-shadow: 0px 5px 25px 0px rgba(0, 0, 0, 0.2); } + .flex-card .tabs { + padding: 15px 0.7rem; } + .flex-card .navtab-content { + min-height: 190px; } + .flex-card .navtab-content p { + padding: 0 0.8rem 20px; } + .flex-card .navigation-tabs.outlined-pills .tabs.tabs-header.primary { + background-color: #4FC1EA; } + .flex-card .navigation-tabs.outlined-pills .tabs.tabs-header.secondary { + background-color: #F39200; } + .flex-card .navigation-tabs.outlined-pills .tabs.tabs-header.accent { + background-color: #00efb7; } + .flex-card .navigation-tabs.outlined-pills .tabs.tabs-header ul li a { + color: #f2f2f2; } + .flex-card .navigation-tabs.outlined-pills .tabs.tabs-header ul li.is-active a { + color: #fff; + border: 1px solid #fff; + border-bottom-color: #fff !important; } + +/* ========================================================================== +Inputs styles +========================================================================== */ +input.input { + color: #878787; + box-shadow: none !important; + transition: all 0.8s; + padding-bottom: 3px; } + input.input.is-small { + padding-bottom: 2px; + padding-left: 10px; } + input.input.is-medium { + padding-bottom: 5px; } + input.input.is-large { + padding-bottom: 7px; } + input.input:focus, input.input:active { + border-color: #EFF4F7; } + input.input.rounded { + border-radius: 100px; } + input.input.is-primary-focus:focus { + border-color: #4FC1EA; } + input.input.is-primary-focus:focus ~ span.icon i { + color: #4FC1EA; } + input.input.is-secondary-focus:focus { + border-color: #F39200; } + input.input.is-secondary-focus:focus ~ span.icon i { + color: #F39200; } + input.input.is-accent-focus:focus { + border-color: #00efb7; } + input.input.is-accent-focus:focus ~ span.icon i { + color: #00efb7; } + input.input.is-bloody-focus:focus { + border-color: #FC354C; } + input.input.is-bloody-focus:focus ~ span.icon i { + color: #FC354C; } + +.form-footer { + width: 100%; } + +/* ========================================================================== +General Keyframes animations +========================================================================== */ +.animated { + animation-duration: 0.5s; + animation-fill-mode: both; + -webkit-animation-duration: 0.5s; + -webkit-animation-fill-mode: both; } + +.delay-1 { + animation-delay: .25s; } + +.delay-2 { + animation-delay: .5s; } + +.delay-3 { + animation-delay: .75s; } + +.delay-4 { + animation-delay: 1s; } + +@keyframes fadeInLeft { + from { + -webkit-transform: translate3d(20px, 0, 0); + transform: translate3d(20px, 0, 0); + opacity: 0; } + to { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + opacity: 1; } } + +@-webkit-keyframes fadeInLeft { + from { + -webkit-transform: translate3d(20px, 0, 0); + transform: translate3d(20px, 0, 0); + opacity: 0; } + to { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + opacity: 1; } } + +.preFadeInLeft { + opacity: 0; } + +.fadeInLeft { + opacity: 0; + animation-name: fadeInLeft; + -webkit-animation-name: fadeInLeft; } + +@keyframes fadeInUp { + from { + -webkit-transform: translate3d(0, 20px, 0); + transform: translate3d(0, 20px, 0); } + to { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + opacity: 1; } } + +@-webkit-keyframes fadeInUp { + from { + -webkit-transform: translate3d(0, 20px, 0); + transform: translate3d(0, 20px, 0); } + to { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + opacity: 1; } } + +.preFadeInUp { + opacity: 0; } + +.fadeInUp { + opacity: 0; + animation-name: fadeInUp; + -webkit-animation-name: fadeInUp; } + +.gelatine { + animation: gelatine 0.6s; + animation-duration: 0.6s; + -webkit-animation-duration: 0.5s; + animation-fill-mode: both; + -webkit-animation-fill-mode: both; } + +@keyframes gelatine { + from, to { + transform: scale(1, 1); } + 25% { + transform: scale(0.9, 1.1); } + 50% { + transform: scale(1.1, 0.9); } + 75% { + transform: scale(0.95, 1.05); } } + +/* ========================================================================== +Sidebar Styles +========================================================================== */ +.menu-icon-wrapper { + position: relative; + left: 0; + top: 0; + width: 34px; + height: 34px; + pointer-events: none; + transition: 0.1s; } + .menu-icon-wrapper svg { + position: absolute; + top: -18px; + left: -18px; + transform: scale(0.07); + transform-origin: 0 0; } + .menu-icon-wrapper svg path { + stroke: #F39200; + stroke-width: 40px; + stroke-linecap: round; + stroke-linejoin: round; + fill: transparent; + transition: stroke-dasharray 0.5s; } + .menu-icon-wrapper svg path.path1 { + stroke-dashoffset: 5803.15px; + stroke-dasharray: 2901.57px, 2981.57px, 240px; } + .menu-icon-wrapper svg path.path2 { + stroke-dashoffset: 800px; + stroke-dasharray: 400px, 480px, 240px; } + .menu-icon-wrapper svg path.path3 { + stroke-dashoffset: 6993.11px; + stroke-dasharray: 3496.56px, 3576.56px, 240px; } + .menu-icon-wrapper.open svg path.path1 { + stroke-dasharray: 2901.57px, 5258.15px, 240px; } + .menu-icon-wrapper.open svg path.path2 { + stroke-dasharray: 400px, 600px, 0px; } + .menu-icon-wrapper.open svg path.path3 { + stroke-dasharray: 3496.56px, 6448.11px, 240px; } + .menu-icon-wrapper .menu-icon-trigger { + position: relative; + width: 100%; + height: 100%; + cursor: pointer; + pointer-events: auto; + background: none; + border: none; + margin: 0; + padding: 0; } + +.sidebar { + background: #344258; + width: 280px; + height: 100%; + position: fixed; + top: 0; + left: 0; + transform: translateX(-281px); + transition: all .3s; + z-index: 10000; + overflow-y: auto; } + .sidebar.is-active { + transform: translateX(0); } + .sidebar .sidebar-header { + height: 4.25rem; + display: flex; + justify-content: space-between; + align-items: center; + border-bottom: 1px solid #3d4e68; + padding: 0 20px; } + .sidebar .sidebar-header img { + height: 32px; } + .sidebar .sidebar-header a { + width: 24px; + height: 24px; } + .sidebar .sidebar-header svg { + stroke: #fff; + transform: rotate(0); + transition: all .3s; + cursor: pointer; } + .sidebar .sidebar-header svg:hover { + stroke: #F39200; + transform: rotate(180deg); } + .sidebar .inner { + position: relative; } + .sidebar .inner .sidebar-menu { + margin: 0; + padding: 0; + max-width: 400px; + list-style: none; + list-style-type: none; + font-family: 'Open Sans', sans-serif !important; } + .sidebar .inner .sidebar-menu li a { + padding: 20px 25px; + display: block; + text-decoration: none; + color: #fff; } + .sidebar .inner .sidebar-menu li a:hover { + padding: 20px 25px; + display: block; + text-decoration: none; + color: #fff; } + .sidebar .inner .sidebar-menu li a span { + margin-right: 20px; + color: #fff; } + .sidebar .inner .sidebar-menu li.have-children ul { + padding: 0px; } + .sidebar .inner .sidebar-menu li.have-children li a { + background-color: #2b3648; + padding-left: 62px; + border-bottom: 1px solid #303d52; + font-size: .8rem; } + .sidebar .inner .sidebar-menu li.have-children li a:hover { + color: #4FC1EA; + padding-left: 62px; } + .sidebar .inner .sidebar-menu li.have-children span::after { + position: absolute; + top: 27px; + right: 30px; + content: "\f054"; + color: #fff; + transition: all .5s; + font-weight: 200 !important; + font-size: .8rem; } + .sidebar .inner li.have-children, .sidebar .inner li { + position: relative; } + .sidebar .inner li.have-children.active > a, .sidebar .inner li.have-children.active > a span, .sidebar .inner li.have-children.active > a span:after { + color: #F39200; } + .sidebar .inner li.active.have-children span::after { + -moz-transform: rotate(90deg); + -o-transform: rotate(90deg); + -webkit-transform: rotate(90deg); + transform: rotate(90deg); } + .sidebar .inner .sidebar-menu .have-children > ul { + display: none; } + +/* ========================================================================== +Testimonials Styles +========================================================================== */ +.testimonial { + position: relative; + overflow: hidden; + margin: 10px auto; + min-width: 220px; + max-width: 310px; + width: 100%; + color: #333; + text-align: left; + box-shadow: none !important; } + .testimonial * { + -webkit-box-sizing: border-box; + box-sizing: border-box; } + .testimonial img { + max-width: 100%; + height: 80px; + width: 80px; + border-radius: 50%; + margin-right: 5px; + display: block; + z-index: 1; + position: absolute; + right: 60%; } + .testimonial blockquote { + margin: 0; + display: block; + border-radius: 8px; + position: relative; + background-color: #fcfcfc; + padding: 30px 50px 65px 50px; + font-size: 1.2rem; + font-weight: 500; + margin: 0 0 -40px; + line-height: 1.6em; + box-shadow: 0 0 5px rgba(0, 0, 0, 0.15); } + .testimonial blockquote:before, .testimonial blockquote:after { + font-family: 'FontAwesome'; + content: "\f10d"; + position: absolute; + font-size: 20px; + opacity: 0.3; + font-style: normal; } + .testimonial blockquote:before { + top: 35px; + left: 20px; } + .testimonial blockquote:after { + content: "\f10e"; + right: 20px; + bottom: 35px; } + .testimonial .author { + margin: 0; + height: 80px; + display: block; + text-align: left; + color: #fff; + padding: 0 35px; + position: relative; + z-index: 0; } + .testimonial .author h5, .testimonial .author span { + left: 50%; + position: absolute; + opacity: 0.8; + padding: 3px 5px; } + .testimonial .author h5 { + text-transform: capitalize; + bottom: 60%; + margin: 0; + font-weight: 600; + font-size: 1.2rem; + color: #444F60; } + .testimonial .author span { + font-size: 0.8em; + color: #fff; + top: 50%; } + +/* ========================================================================== +Responsive Styles +========================================================================== */ +@media (max-width: 767px) { + .landing-caption { + text-align: center; } + .navbar-menu .is-static { + position: absolute; + width: 100%; } + .navbar-menu .is-fixed { + position: fixed; + width: 100%; } + .navbar-menu .navbar-item { + text-align: center !important; } + .navbar-menu .navbar-item .signup-button { + width: 100% !important; } + .navbar-menu .navbar-link { + padding: 10px 20px !important; } + .title.section-title { + font-size: 2rem !important; } + .level-left.level-social { + display: flex; + justify-content: flex-start; } + .pushed-image { + margin-top: 0 !important; } + .testimonial { + margin: 0 auto; } } + +@media only screen and (min-device-width: 768px) and (max-device-width: 1024px) and (orientation: portrait) { + .landing-caption { + text-align: center; } + .navbar-menu .is-static { + position: absolute; + width: 100%; } + .navbar-menu .is-fixed { + position: fixed; + width: 100%; } + .navbar-menu .navbar-item { + text-align: center !important; } + .navbar-menu .navbar-item .signup-button { + width: 100% !important; } + .navbar-menu .navbar-link { + padding: 10px 20px !important; } + .pushed-image { + margin-top: 0 !important; } + .testimonial { + margin: 0 auto; } + .is-centered-tablet-portrait { + text-align: center !important; } + .is-centered-tablet-portrait .divider { + margin: 0 auto !important; } } + +section:focus { + outline: none !important; } + +button:focus, button:active { + outline: none; } + +#preloader { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: #fff; + z-index: 99; } + +#status { + width: 200px; + height: 200px; + position: absolute; + left: 50%; + top: 50%; + background-image: url(../images/loaders/rings.svg); + background-size: 80px 80px; + background-repeat: no-repeat; + background-position: center; + margin: -100px 0 0 -100px; } + +#backtotop { + position: fixed; + right: 0; + opacity: 0; + visibility: hidden; + bottom: 25px; + margin: 0 25px 0 0; + z-index: 9999; + transition: 0.35s; + transform: scale(0.7); + transition: all 0.5s; } + +#backtotop.visible { + opacity: 1; + visibility: visible; + transform: scale(1); } + +#backtotop.visible a:hover { + outline: none; + opacity: 0.9; + background: #F39200; } + +#backtotop a { + outline: none; + text-decoration: none; + border: 0 none; + display: block; + width: 46px; + height: 46px; + background-color: #66676b; + opacity: 1; + transition: all 0.3s; + border-radius: 50%; + text-align: center; + font-size: 26px; } + +body #backtotop a { + outline: none; + color: #fff; } + +#backtotop a:after { + outline: none; + content: "\f106"; + font-family: "Font Awesome 5 Free"; + font-weight: 900; + position: relative; + display: block; + top: 50%; + -webkit-transform: translateY(-55%); + transform: translateY(-55%); } + +.is-disabled { + pointer-events: none; + opacity: 0.4; + cursor: default !important; } + +.is-hidden { + display: none !important; } + +.stuck { + position: fixed !important; + top: 0 !important; + z-index: 2 !important; } + +.light-text { + color: #fff !important; } + +.mb-20 { + margin-bottom: 20px; } + +.mb-40 { + margin-bottom: 40px; } + +.mb-60 { + margin-bottom: 60px; } + +.mt-20 { + margin-top: 20px; } + +.mt-40 { + margin-top: 40px; } + +.mt-50 { + margin-top: 50px; } + +.mt-60 { + margin-top: 60px; } + +.ml-30 { + margin-left: 30px; } + +.huge-pb { + padding-bottom: 100px; } + +.pb-20 { + padding-bottom: 20px !important; } + +.pb-40 { + padding-bottom: 40px !important; } + +::-webkit-input-placeholder { + /* Chrome/Opera/Safari */ + color: #cecece; } + +::-moz-placeholder { + /* Firefox 19+ */ + color: #cecece; } + +:-ms-input-placeholder { + /* IE 10+ */ + color: #cecece; } + +:-moz-placeholder { + /* Firefox 18- */ + color: #cecece; } + +/*# sourceMappingURL=style.css.map */ diff --git a/v0.10.x/_static/vendor/styles.css b/v0.10.x/_static/vendor/styles.css new file mode 100644 index 000000000..1587eef19 --- /dev/null +++ b/v0.10.x/_static/vendor/styles.css @@ -0,0 +1,361 @@ +body { + font-family: var(--fontFamily), sans-serif; +} + +em { + color: var(--colorPrimaryDark) !important; +} + +/* This color came from uikit; we re-specify it here + to show how to override it for the content section */ +.content-padding a { + color: var(--colorContentLink); +} + +.flex-row { + display: flex; + flex-direction: row; +} + +.flex-column { + display: flex; + flex-direction: column; + justify-content: center; +} + +.hero-container { + width: 100vw; +} + +.hero-container { + width: 100vw; +} + +.hero-content { + display: flex; + flex-direction: column; +} + +.hero-title-content { + display: flex; + flex-direction: row; + width: 100%; + max-width: 1200px; + margin: 6vh auto; + justify-content: space-around; +} + +.hero-headline { + display: flex; + flex-direction: row; +} + +.hero-title { + display: flex; + flex-direction: column; + align-items: center; + margin-bottom: 2vh; +} + +.hero-logo { + height: 225px; + margin-left: -15px; + margin-top: -35px; +} + +.logo-text { + margin: 0; + font-family: 'Syncopate', sans-serif; + font-weight: 700; + font-size: 42px; + color: #000; + text-transform: uppercase; + letter-spacing: 16px; + cursor: default; + margin-top: -10px; +} + +.hero-subtitle { + font-size: 1em; + max-width: 550px; +} + +.hero-cta { + padding: 15px 0; + display: block; +} + +.cta-button { + width: 175px; + height: 45px; + font-size: 11px; + text-transform: uppercase; + letter-spacing: 1.5px; + font-weight: 500; + color: var(--colorSecondaryLight); + background-color: var(--colorPrimaryDark); + border: none; + border-radius: 25px; + outline: none; + /* Black, with 10% opacity */ + box-shadow: 0px 8px 15px var(--colorShadow); + cursor: pointer; +} + +.navbar-item { + color: var(--colorPrimaryDark) !important; + text-decoration: none !important; +} + +.navbar-item:hover { + color: var(--colorPrimaryLight) !important; +} + +#navbar-logo { + height: 60px; + max-height: 60px; + padding-right: 16px; +} + +#navbar-logo-text { + font-family: 'Syncopate', sans-serif; + font-weight: 700; + font-size: 20px; + margin-top: 8px; + letter-spacing: 8px; +} + +#feature-card { + height: 475px; +} +#backtotop.visible #backtotop-color:hover { + background: var(--colorHighlight); +} + +.mt-30 { + margin-top: 30px; +} + +h2 { + font-size: 1.5em; + font-weight: bold; + padding-top: 15px; +} + +h3 { + font-size: 1.2em; + font-weight: bold; + padding-top: 10px; +} + +p { + padding-top: 5px; +} + +.content-container ul { + list-style-type: circle; + padding: 10px; + margin-left: 15px; +} + +.content-container ol { + padding: 10px; + margin-left: 15px; +} + +@media only screen and (max-width: 1090px) { + .hero-content { + flex-direction: column; + padding: 0; + align-items: center; + } + + .hero-title-content { + flex-direction: column; + align-items: center; + } + + .hero-cta { + display: flex; + justify-content: center; + } +} + +@media only screen and (max-width: 600px) { + .flex-column { + margin: 0 30px; + } + + .hero-title { + font-size: 4em; + margin-bottom: 2vh; + width: 100vw; + justify-content: center; + } + + .hero-logo { + max-height: 100px; + } + + .logo-text { + font-size: 30px; + } + + .hero-cta { + display: flex; + justify-content: center; + } + + .hero-title-content { + margin: 2vh auto; + } + + .hero-logo:first-of-type { + padding: 0; + } + + #navbar-logo { + height: 50px; + max-height: 50px; + padding-right: 16px; + } + + #navbar-logo-text { + font-family: 'Syncopate', sans-serif; + font-weight: 700; + font-size: 20px; + margin-top: 8px; + letter-spacing: 8px; + } +} + +@media only screen and (max-width: 400px) { + .hero-logo { + max-height: 100px; + } +} + +@media only screen and (max-width: 320px) { + .hero-logo { + max-height: 40px; + } + +} + +/* Footer */ +#footer { + background-color: var(--colorPrimaryDark); +} + +.footer-logo-column { + display: flex; + justify-content: center; + padding: 20px 5vw; + font-size: 1rem; +} + +#footer-logo { + height: 75px; +} + +.link-column { + display: block; + flex-basis: 0; + flex-grow: 1; + flex-shrink: 1; +} + +.footer-link, .footer-link:hover { + font-size: 1rem; + color: var(--colorSecondary); +} + +.footer-actions { + max-width: 25vw; + margin: 20px 25px; +} + +.footer-actions > p { + padding-top: 0; +} + +.footer-actions p { + margin: 0; + color: var(--colorSecondary); +} + +.social-media-icons { + display: flex; +} + +.copyright { + font-size: 12px; + color: var(--colorSecondary); +} + +figcaption { + text-align: center; +} + +.csfigcaption { + text-align: center; +} + +.fig-center { + text-align: center; + display: block; + margin-left: auto; + margin-right: auto; + width: 80%; +} + +blockquote { + margin: 10px; +} + +blockquote p { + padding: 15px; + background: var(--colorSecondary); + border-radius: 5px; +} + +blockquote p::before { + content: '\201C'; +} + +blockquote p::after { + content: '\201D'; +} + +@media only screen and (max-width: 850px) { + + .footer-column ul.link-list li.link-list { + width: calc(50% - 24px); + display: inline-block; + } + + .footer-actions { + max-width: 100%; + margin: 0; + display: flex; + justify-content: space-between; + } +} + +div.sphx-glr-download a { + border-radius: 10px; + background-color: var(--colorPrimaryDark); + background-image: linear-gradient(to bottom, #d03f3f, var(--colorPrimaryDark)); + color: white; + border: none; + border: 1px solid #fff; + font-weight: normal; + +} + +div.sphx-glr-download a:hover { + background-color: var(--colorPrimaryDark); + box-shadow: inset 0 1px 0 rgba(255,255,255,.1), 0 1px 5px rgba(0,0,0,.25); + text-decoration: none; + background-image: none; +} diff --git a/v0.10.x/_static/vendor/tables.css b/v0.10.x/_static/vendor/tables.css new file mode 100644 index 000000000..9e711c340 --- /dev/null +++ b/v0.10.x/_static/vendor/tables.css @@ -0,0 +1,11 @@ +table td:not(:last-child), table th { + padding-bottom: 0.25rem; +} + +table td:not:first-child, table th:not:first-child { + padding-left: 0.5rem; +} + +table td:not(:last-child), table th:not(:last-child) { + padding-right: 0.5rem; +} diff --git a/v0.10.x/_static/vendor/tabs.css b/v0.10.x/_static/vendor/tabs.css new file mode 100644 index 000000000..ec5355000 --- /dev/null +++ b/v0.10.x/_static/vendor/tabs.css @@ -0,0 +1,220 @@ +.uikit-tab-wrapper-mobile { + display: flex; + flex-direction: row; +} + +.tabs-section { + display: flex; + flex-direction: column; +} + +.tabs-section .container { + display: flex; + flex-direction: column; +} + +.tabs-title { + display: flex; + justify-content: center; + letter-spacing: 1.5px; + font-size: 27px; + margin: 30px 0; +} + +.tabs-info { + font-size: 16px; + color: #4a4a4a; +} + +@media screen and (max-width: 600px) { + .tabs-info { + font-size: 12.8px; + font-weight: bold; + } +} + +.visualization, .data-science, .scientific-domains, .machine-learning, .array-libraries { + max-width: 900px; + margin: 15px auto; +} + +.scientific-domains > table { + margin-left: auto; + margin-right: auto; +} + +.uk-tab > li { + padding: 0 10px; +} + +.uk-nav > li > a { + height: 35px; + font-size: 13px; + text-transform: uppercase; + letter-spacing: 1.5px; + font-weight: 500; + color: rgb(108, 122, 137); +} +.uk-tab > .uk-active > a { + color: var(--colorPrimaryDark) !important; + border-color: var(--colorPrimaryDark) !important; +} + +@media screen and (max-width: 600px) { + + .uk-tab { + margin-left: 0 !important; + } + + .uk-tab > .uk-active > a { + border-color: var(--colorPrimaryDark) !important; + color: var(--colorPrimaryDark) !important; + } + + .uk-tab > li { + width: 50%; + padding: 0 0 0 10px; + } + + .uk-nav > li > a { + height: 47px; + font-size: 12px; + line-height: 15.5px; + margin: 3px; + padding: 5px 7px !important; + text-align: center; + border: 2px solid #e5e5e5; + border-radius: 24px; + } + + .uk-tab::before { + content: none !important; + } + +} + +#tabs-content > li { + width: 90vw; + max-width: 900px; + margin: 50px auto; +} + +@media screen and (max-width: 600px) { + #tabs-content > li { + margin: 10px auto; + } + +} + +@media only screen and (max-width: 1200px) { + .tabs-section { + margin: 30px 10px; + } + + .tabs-title { + margin: 30px; + } +} + +@media screen and (max-width: 600px) { + .tabs-section { + margin: 30px 0px; + } +} + +/* Visualization */ +.visualization-images img, +.visualization-images a { + border-radius: 10px; +} + +.image-grid > div { + background-color: rgb(0, 0, 0); + border-radius: 10px; + + display: flex; + align-items: center; + justify-content: center; + flex-direction: column; + + box-shadow: rgba(0, 0, 0, 0.35) 0px 5px 15px; +} + +@media only screen and (max-width: 600px) { + .image-grid > div { + min-height: 150px; + } +} + +.molecular-band { + padding: 30px; + background-color: white !important; +} + +.image-description { + color: black; +} + +.image-grid > div:hover { + box-shadow: rgba(255, 255, 255, 0.1) 0px 1px 1px 0px inset, rgba(50, 50, 93, 0.25) 0px 50px 100px -20px, rgba(0, 0, 0, 0.3) 0px 30px 60px -30px; +} + +/* Scientific Domains */ +td, th { + font-size: 0.8rem; + padding: 8px; +} + +td > a { + font-size: 0.8rem; +} + +tr.highlight-th { + border-top: 1px solid rgb(238, 238, 238); + font-size: 0.8rem; +} + +td.bold-text { + font-weight: bold; + text-align: center; + line-height: 14px; +} + +img.cell-layout { + border-radius: 10px; + width: 50px; + height: 50px; + display: block; + margin: 12px auto; + filter: invert(11%) sepia(86%) saturate(4861%) hue-rotate(10deg) brightness(84%) contrast(121%); +} + +img.cell-layout:hover { + filter: invert(91%) sepia(73%) saturate(2024%) hue-rotate(313deg) brightness(97%) contrast(109%); +} + +td.center-text { + text-align: center; + line-height: 35%; +} + +td.full-center-text { + text-align: center; + vertical-align: middle; + line-height: 45%; +} + +td.lastrow-center-text { + text-align: center; + line-height: 35%; + border-bottom: 1px solid rgb(255, 255, 255); +} + +/* Array Libraries */ +img.first-column-layout { + height: 30px; +} + +td.left-text { + vertical-align: middle; +} diff --git a/v0.10.x/_static/vendor/teams.css b/v0.10.x/_static/vendor/teams.css new file mode 100644 index 000000000..c6b8310e2 --- /dev/null +++ b/v0.10.x/_static/vendor/teams.css @@ -0,0 +1,29 @@ +.team { + padding-bottom: 2rem; +} + +.team .members { + display: flex; + flex-wrap: wrap; +} + +.team .member { + width: 11rem; + display: flex; + flex-direction: column; + padding-right: 1.25rem; + padding-top: 1.25rem; + padding-bottom: 1.25rem; + text-align: center; + vertical-align: top; +} + +.team .member .photo img { + width: 60px; + border-radius: 50%; + margin-bottom: 0.5rem; +} + +.team .member .name { + font-weight: bold; +} diff --git a/v0.10.x/_static/vendor/vars.css b/v0.10.x/_static/vendor/vars.css new file mode 100644 index 000000000..219b81322 --- /dev/null +++ b/v0.10.x/_static/vendor/vars.css @@ -0,0 +1,15 @@ +:root { + --fontFamily: {{ .Site.Params.font.name }}; + + --colorPrimaryDark: rgb(153, 0, 0); + --colorPrimary: rgb(77, 119, 207); + --colorPrimaryLight: rgb(77, 171, 207); + + --colorSecondaryDark: rgb(108, 122, 137); + --colorSecondary: rgb(238, 238, 238); + --colorSecondaryLight: rgb(255, 255, 255); + + --colorHighlight: rgb(255, 197, 83); + --colorShadow: rgba(0, 0, 0, 0.1); + --colorContentLink: rgb(30, 135, 240); +} diff --git a/v0.10.x/_static/vendor/videos.css b/v0.10.x/_static/vendor/videos.css new file mode 100644 index 000000000..7b0d3fd62 --- /dev/null +++ b/v0.10.x/_static/vendor/videos.css @@ -0,0 +1,61 @@ +.youtube { + width: 100%; + display: flex; + flex-direction: column; +} + +.youtube iframe { + width: 640px; + max-width: 100%; + height: 360px; + margin-top: 1rem; + margin-bottom: 0rem; +} + +.youtube .video-meta { + padding-top: 0.75rem; + padding-bottom: 1.5rem; + font-weight: bold; + padding-bottom: 0.5rem; +} + +.youtube .video-title { +} + +.video-transcript-button { + width: 640px; + max-width: 100%; + background-color: #ddd; + color: #444; + cursor: pointer; + padding: 1rem; + border: none; + text-align: left; + outline: none; + font-size: 1.25rem; +} + +.video-transcript-button:hover { + background-color: #bbb; +} + +/* The little triangle on the transcript button */ +.video-transcript-button-pointer { +} + +.video-transcript-button .video-transcript-button-pointer::before{ + content: "▶"; +} + +.video-transcript-button.active .video-transcript-button-pointer::before{ + content: "▼"; +} + +.video-transcript { + max-width: 640px; + width: 100%; + display: none; + overflow: auto; + background-color: #f1f1f1; + padding: 1rem; +} diff --git a/v0.10.x/_static/versions_switcher.json b/v0.10.x/_static/versions_switcher.json new file mode 100644 index 000000000..1ba7ed4e6 --- /dev/null +++ b/v0.10.x/_static/versions_switcher.json @@ -0,0 +1,52 @@ +[ + { + "name": "dev", + "version": "latest", + "url": "https://fury.gl/dev/index.html" + }, + { + "name": "v0.9.x (stable)", + "version": "stable", + "url": "https://fury.gl/v0.9.x/index.html" + }, + { + "name": "v0.8.x", + "version": "v0.8.x", + "url": "https://fury.gl/v0.8.x/index.html" + }, + { + "name": "v0.7.x", + "version": "v0.7.x", + "url": "https://fury.gl/v0.7.x/index.html" + }, + { + "name": "v0.6.x", + "version": "v0.6.x", + "url": "https://fury.gl/v0.6.x/index.html" + }, + { + "name": "v0.5.x", + "version": "v0.5.x", + "url": "https://fury.gl/v0.5.x/index.html" + }, + { + "name": "v0.4.x", + "version": "v0.4.x", + "url": "https://fury.gl/v0.4.x/index.html" + }, + { + "name": "v0.3.x", + "version": "v0.3.x", + "url": "https://fury.gl/v0.3.x/index.html" + }, + { + "name": "v0.2.x", + "version": "v0.2.x", + "url": "https://fury.gl/v0.2.x/index.html" + }, + { + "name": "v0.1.x", + "version": "v0.1.x", + "url": "https://fury.gl/v0.1.x/index.html" + } +] diff --git a/v0.10.x/_static/webfonts/fa-brands-400.eot b/v0.10.x/_static/webfonts/fa-brands-400.eot new file mode 100644 index 000000000..a1bc094ab Binary files /dev/null and b/v0.10.x/_static/webfonts/fa-brands-400.eot differ diff --git a/v0.10.x/_static/webfonts/fa-brands-400.svg b/v0.10.x/_static/webfonts/fa-brands-400.svg new file mode 100644 index 000000000..304135c66 --- /dev/null +++ b/v0.10.x/_static/webfonts/fa-brands-400.svg @@ -0,0 +1,3570 @@ + + + + + +Created by FontForge 20190801 at Mon Mar 23 10:45:51 2020 + By Robert Madole +Copyright (c) Font Awesome + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/v0.10.x/_static/webfonts/fa-brands-400.ttf b/v0.10.x/_static/webfonts/fa-brands-400.ttf new file mode 100644 index 000000000..948a2a6cc Binary files /dev/null and b/v0.10.x/_static/webfonts/fa-brands-400.ttf differ diff --git a/v0.10.x/_static/webfonts/fa-brands-400.woff b/v0.10.x/_static/webfonts/fa-brands-400.woff new file mode 100644 index 000000000..2a89d521e Binary files /dev/null and b/v0.10.x/_static/webfonts/fa-brands-400.woff differ diff --git a/v0.10.x/_static/webfonts/fa-brands-400.woff2 b/v0.10.x/_static/webfonts/fa-brands-400.woff2 new file mode 100644 index 000000000..141a90a9e Binary files /dev/null and b/v0.10.x/_static/webfonts/fa-brands-400.woff2 differ diff --git a/v0.10.x/_static/webfonts/fa-regular-400.eot b/v0.10.x/_static/webfonts/fa-regular-400.eot new file mode 100644 index 000000000..38cf2517a Binary files /dev/null and b/v0.10.x/_static/webfonts/fa-regular-400.eot differ diff --git a/v0.10.x/_static/webfonts/fa-regular-400.svg b/v0.10.x/_static/webfonts/fa-regular-400.svg new file mode 100644 index 000000000..d77173843 --- /dev/null +++ b/v0.10.x/_static/webfonts/fa-regular-400.svg @@ -0,0 +1,803 @@ + + + + + +Created by FontForge 20190801 at Mon Mar 23 10:45:51 2020 + By Robert Madole +Copyright (c) Font Awesome + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/v0.10.x/_static/webfonts/fa-regular-400.ttf b/v0.10.x/_static/webfonts/fa-regular-400.ttf new file mode 100644 index 000000000..abe99e20c Binary files /dev/null and b/v0.10.x/_static/webfonts/fa-regular-400.ttf differ diff --git a/v0.10.x/_static/webfonts/fa-regular-400.woff b/v0.10.x/_static/webfonts/fa-regular-400.woff new file mode 100644 index 000000000..24de566a5 Binary files /dev/null and b/v0.10.x/_static/webfonts/fa-regular-400.woff differ diff --git a/v0.10.x/_static/webfonts/fa-regular-400.woff2 b/v0.10.x/_static/webfonts/fa-regular-400.woff2 new file mode 100644 index 000000000..7e0118e52 Binary files /dev/null and b/v0.10.x/_static/webfonts/fa-regular-400.woff2 differ diff --git a/v0.10.x/_static/webfonts/fa-solid-900.eot b/v0.10.x/_static/webfonts/fa-solid-900.eot new file mode 100644 index 000000000..d3b77c223 Binary files /dev/null and b/v0.10.x/_static/webfonts/fa-solid-900.eot differ diff --git a/v0.10.x/_static/webfonts/fa-solid-900.svg b/v0.10.x/_static/webfonts/fa-solid-900.svg new file mode 100644 index 000000000..ca508e02d --- /dev/null +++ b/v0.10.x/_static/webfonts/fa-solid-900.svg @@ -0,0 +1,4938 @@ + + + + + +Created by FontForge 20190801 at Mon Mar 23 10:45:51 2020 + By Robert Madole +Copyright (c) Font Awesome + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/v0.10.x/_static/webfonts/fa-solid-900.ttf b/v0.10.x/_static/webfonts/fa-solid-900.ttf new file mode 100644 index 000000000..5b979039a Binary files /dev/null and b/v0.10.x/_static/webfonts/fa-solid-900.ttf differ diff --git a/v0.10.x/_static/webfonts/fa-solid-900.woff b/v0.10.x/_static/webfonts/fa-solid-900.woff new file mode 100644 index 000000000..beec79178 Binary files /dev/null and b/v0.10.x/_static/webfonts/fa-solid-900.woff differ diff --git a/v0.10.x/_static/webfonts/fa-solid-900.woff2 b/v0.10.x/_static/webfonts/fa-solid-900.woff2 new file mode 100644 index 000000000..978a681a1 Binary files /dev/null and b/v0.10.x/_static/webfonts/fa-solid-900.woff2 differ diff --git a/v0.10.x/_static/webpack-macros.html b/v0.10.x/_static/webpack-macros.html new file mode 100644 index 000000000..160ea1d8a --- /dev/null +++ b/v0.10.x/_static/webpack-macros.html @@ -0,0 +1,30 @@ + +{# Load FontAwesome icons #} +{% macro head_pre_icons() %} + + + + +{% endmacro %} + +{% macro head_pre_assets() %} + + + + +{% endmacro %} + +{% macro head_js_preload() %} + + + +{% endmacro %} + +{% macro body_post() %} + + + +{% endmacro %} \ No newline at end of file diff --git a/v0.10.x/auto_examples/01_introductory/index.html b/v0.10.x/auto_examples/01_introductory/index.html new file mode 100644 index 000000000..37d1b9364 --- /dev/null +++ b/v0.10.x/auto_examples/01_introductory/index.html @@ -0,0 +1,558 @@ + + + + + + + + Introductory — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Introductory#

+

These tutorials show:

+
    +
  • How to combine a timer with an actor

  • +
  • How to slice data with the slicer actor

  • +
  • How to use the normals of your data.

  • +
+
+

Sphere Texture

+
Sphere Texture
+
+

Visualizing a glTF file

+
Visualizing a glTF file
+
+

FURY sphere Actor

+
FURY sphere Actor
+
+

Fury Cone Actor

+
Fury Cone Actor
+
+

Fury Arrow Actor

+
Fury Arrow Actor
+
+

Visualizing a glTF file

+
Visualizing a glTF file
+
+

Morphing Animation in a glTF

+
Morphing Animation in a glTF
+
+

Exporting scene as a glTF file

+
Exporting scene as a glTF file
+
+

Skeletal Animation in a glTF file

+
Skeletal Animation in a glTF file
+
+

Using a timer

+
Using a timer
+
+

Spiky Sphere

+
Spiky Sphere
+
+

Visualize surfaces

+
Visualize surfaces
+
+

Selecting multiple objects

+
Selecting multiple objects
+
+

Multithreading Example

+
Multithreading Example
+
+

Simple picking

+
Simple picking
+
+

Texture Sphere Animation

+
Texture Sphere Animation
+
+

Earth Coordinate Conversion

+
Earth Coordinate Conversion
+
+

Simple volume slicing

+
Simple volume slicing
+
+

Solar System Animation

+
Solar System Animation
+
+
+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/auto_examples/01_introductory/sg_execution_times.html b/v0.10.x/auto_examples/01_introductory/sg_execution_times.html new file mode 100644 index 000000000..2b516769a --- /dev/null +++ b/v0.10.x/auto_examples/01_introductory/sg_execution_times.html @@ -0,0 +1,568 @@ + + + + + + + + Computation times — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Computation times#

+

01:59.821 total execution time for 19 files from auto_examples/01_introductory:

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Example

Time

Mem (MB)

Texture Sphere Animation (viz_earth_animation.py)

00:39.436

0.0

Solar System Animation (viz_solar_system.py)

00:31.865

0.0

Earth Coordinate Conversion (viz_earth_coordinates.py)

00:27.806

0.0

Using a timer (viz_timers.py)

00:05.984

0.0

Multithreading Example (viz_multithread.py)

00:05.510

0.0

Spiky Sphere (viz_spiky.py)

00:04.349

0.0

Simple volume slicing (viz_slice.py)

00:02.768

0.0

Selecting multiple objects (viz_selection.py)

00:01.308

0.0

Skeletal Animation in a glTF file (viz_skinning.py)

00:00.644

0.0

Simple picking (viz_picking.py)

00:00.085

0.0

Visualize surfaces (viz_surfaces.py)

00:00.064

0.0

Fury Arrow Actor (viz_arrow.py)

00:00.000

0.0

Fury Cone Actor (viz_cone.py)

00:00.000

0.0

Visualizing a glTF file (viz_gltf.py)

00:00.000

0.0

Visualizing a glTF file (viz_gltf_animated.py)

00:00.000

0.0

Exporting scene as a glTF file (viz_gltf_export.py)

00:00.000

0.0

Morphing Animation in a glTF (viz_morphing.py)

00:00.000

0.0

FURY sphere Actor (viz_sphere.py)

00:00.000

0.0

Sphere Texture (viz_texture.py)

00:00.000

0.0

+
+
+ +
+ + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/auto_examples/01_introductory/viz_arrow.html b/v0.10.x/auto_examples/01_introductory/viz_arrow.html new file mode 100644 index 000000000..2b0cf8e69 --- /dev/null +++ b/v0.10.x/auto_examples/01_introductory/viz_arrow.html @@ -0,0 +1,552 @@ + + + + + + + + Fury Arrow Actor — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +
+

Fury Arrow Actor#

+

This example shows how to use the arrow actor.

+
import numpy as np
+
+from fury import actor, window
+
+
+

First thing, you have to specify centers, directions, and colors of the +arrow(s)

+
centers = np.zeros([3, 3])
+
+
+

np.identity is the same as specifying x, y, and z directions.

+
dirs = np.identity(3)
+colors = np.identity(3)
+scales = np.array([2.1, 2.6, 2.5])
+
+
+

The below arrow actor is generated by repeating the arrow primitive.

+
arrow_actor = actor.arrow(centers, dirs, colors=colors, scales=1.5)
+
+
+

repeating what we did but this time with random centers, directions, and +colors.

+
cen2 = np.random.rand(5, 3)
+dir2 = np.random.rand(5, 3)
+cols2 = np.random.rand(5, 3)
+
+arrow_actor2 = actor.arrow(cen2, dir2, colors=cols2, scales=1.5)
+
+scene = window.Scene()
+
+
+

Adding our Arrow actors to scene.

+
scene.add(arrow_actor)
+scene.add(arrow_actor2)
+
+interactive = False
+
+if interactive:
+    window.show(scene, size=(600, 600))
+
+window.record(scene, out_path='viz_arrow.png', size=(600, 600))
+
+
+viz arrow

Total running time of the script: (0 minutes 0.052 seconds)

+ +

Gallery generated by Sphinx-Gallery

+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/auto_examples/01_introductory/viz_cone.html b/v0.10.x/auto_examples/01_introductory/viz_cone.html new file mode 100644 index 000000000..809a719e5 --- /dev/null +++ b/v0.10.x/auto_examples/01_introductory/viz_cone.html @@ -0,0 +1,547 @@ + + + + + + + + Fury Cone Actor — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +
+

Fury Cone Actor#

+

This example shows how to use the cone actor.

+
import numpy as np
+
+from fury import actor, window
+
+
+

First thing, you have to specify centers, directions, and colors of the cone

+ +

The below cone actor is generated by repeating the cone primitive.

+
cone_actor1 = actor.cone(centers, dirs, colors=colors, heights=1.5)
+
+
+

repeating what we did but this time with random directions, and colors +Here, we’re using vtkConeSource to generate the cone actor

+
cen2 = np.add(centers, np.array([3, 0, 0]))
+dir2 = np.random.rand(5, 3)
+cols2 = np.random.rand(5, 3)
+
+cone_actor2 = actor.cone(cen2, dir2, colors=cols2, heights=1.5, use_primitive=False)
+
+scene = window.Scene()
+
+
+

Adding our cone actors to scene.

+
scene.add(cone_actor1)
+scene.add(cone_actor2)
+
+interactive = False
+
+if interactive:
+    window.show(scene, size=(600, 600))
+
+window.record(scene, out_path='viz_cone.png', size=(600, 600))
+
+
+viz cone

Total running time of the script: (0 minutes 0.055 seconds)

+ +

Gallery generated by Sphinx-Gallery

+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/auto_examples/01_introductory/viz_earth_animation.html b/v0.10.x/auto_examples/01_introductory/viz_earth_animation.html new file mode 100644 index 000000000..bcccba4c1 --- /dev/null +++ b/v0.10.x/auto_examples/01_introductory/viz_earth_animation.html @@ -0,0 +1,667 @@ + + + + + + + + Texture Sphere Animation — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +
+

Texture Sphere Animation#

+

In this tutorial, we will show how to animate a textured sphere.

+
import itertools
+
+import numpy as np
+
+from fury import actor, io, utils, window
+from fury.data import (
+    fetch_viz_models,
+    fetch_viz_textures,
+    read_viz_models,
+    read_viz_textures,
+)
+
+
+

Create a scene to start.

+ +

Next, load in a texture for each of the actors. For this tutorial, we will +be creating one textured sphere for the Earth, and another for the moon. +Collect the Earth texture from the FURY github using fetch_viz_textures +and read_viz_textures, then use io.load_image to load in the +image.

+
fetch_viz_textures()
+earth_filename = read_viz_textures('1_earth_8k.jpg')
+earth_image = io.load_image(earth_filename)
+
+
+
Dataset is already in place. If you want to fetch it again please first remove the folder /Users/skoudoro/.fury/textures
+
+
+

Using actor.texture_on_sphere(), create an earth_actor with your newly +loaded texture.

+ +

Then, do the same for the moon.

+
moon_filename = read_viz_textures('moon-8k.jpg')
+moon_image = io.load_image(moon_filename)
+
+moon_actor = actor.texture_on_sphere(moon_image)
+
+
+

Add both actors to the already existing scene.

+
scene.add(earth_actor)
+scene.add(moon_actor)
+
+
+

Next, alter the position and scale of the moon to correctly size it in +comparison to the Earth using actor.SetPosition() and +actor.SetScale(), and rotate the Earth using utils.rotate to +correctly align the texture.

+
moon_actor.SetPosition(1, 0.1, 0.5)
+moon_actor.SetScale(0.25, 0.25, 0.25)
+utils.rotate(earth_actor, (-90, 1, 0, 0))
+
+
+

The ShowManager class is the interface between the scene, the window and the +interactor.

+
showm = window.ShowManager(
+    scene, size=(900, 768), reset_camera=False, order_transparent=True
+)
+
+
+

Next, let’s focus on creating the animation. +We can determine the duration of animation with using the counter. +Use itertools to avoid global variables.

+ +

Use set_camera to ensure the camera is in the optimal position for the +scene.

+
scene.set_camera(
+    position=(0.24, 0.00, 4.34),
+    focal_point=(0.00, 0.00, 0.00),
+    view_up=(0.00, 1.00, 0.00),
+)
+
+
+

Let’s create a sphere actor to add to the Earth. We will place this sphere +on the Earth’s surface on Bloomington, IN, home of FURY’s headquarters!

+
center = np.array([[-0.39, 0.3175, 0.025]])
+radius = 0.002
+sphere_actor = actor.sphere(center, window.colors.blue_medium, radius)
+
+
+

Also creating a text actor to add below the sphere.

+
text_actor = actor.text_3d(
+    'Bloomington, Indiana', (-0.42, 0.31, 0.03), window.colors.white, 0.004
+)
+utils.rotate(text_actor, (-90, 0, 1, 0))
+
+
+

Let’s also import a model of a satellite to visualize circling the moon.

+
fetch_viz_models()
+satellite_filename = read_viz_models('satellite_obj.obj')
+satellite = io.load_polydata(satellite_filename)
+satellite_actor = utils.get_actor_from_polydata(satellite)
+
+satellite_actor.SetPosition(-0.75, 0.1, 0.4)
+satellite_actor.SetScale(0.005, 0.005, 0.005)
+
+
+
Dataset is already in place. If you want to fetch it again please first remove the folder /Users/skoudoro/.fury/models
+
+
+

In the timer_callback function, use if statements to specify when +certain events will happen in the animation, based on the position that +the counter is at. So, for example, the earth actor will continue to +rotate while the count is less than 450.

+
def timer_callback(_obj, _event):
+    cnt = next(counter)
+    showm.render()
+    if cnt < 450:
+        utils.rotate(earth_actor, (1, 0, 1, 0))
+    if cnt % 5 == 0 and cnt < 450:
+        showm.scene.azimuth(-1)
+    if cnt == 300:
+        scene.set_camera(
+            position=(-3.679, 0.00, 2.314),
+            focal_point=(0.0, 0.35, 0.00),
+            view_up=(0.00, 1.00, 0.00),
+        )
+    if cnt > 300 and cnt < 450:
+        scene.zoom(1.01)
+    if cnt >= 450 and cnt < 1500:
+        scene.add(sphere_actor)
+        scene.add(text_actor)
+    if cnt >= 450 and cnt < 550:
+        scene.zoom(1.01)
+    if cnt == 575:
+        moon_actor.SetPosition(-1, 0.1, 0.5)
+        scene.set_camera(
+            position=(-0.5, 0.1, 0.00),
+            focal_point=(-1, 0.1, 0.5),
+            view_up=(0.00, 1.00, 0.00),
+        )
+        scene.zoom(0.03)
+        scene.add(satellite_actor)
+        utils.rotate(satellite_actor, (180, 0, 1, 0))
+        scene.rm(earth_actor)
+    if cnt > 575 and cnt < 750:
+        showm.scene.azimuth(-2)
+        utils.rotate(moon_actor, (-2, 0, 1, 0))
+        satellite_actor.SetPosition(-0.8, 0.1 - cnt / 10000, 0.4)
+    if cnt >= 750 and cnt < 1100:
+        showm.scene.azimuth(-2)
+        utils.rotate(moon_actor, (-2, 0, 1, 0))
+        satellite_actor.SetPosition(-0.8, -0.07 + cnt / 10000, 0.4)
+    if cnt == 1100:
+        showm.exit()
+
+
+

Watch your new animation take place!

+
showm.add_timer_callback(True, 35, timer_callback)
+showm.start()
+window.record(showm.scene, size=(900, 768), out_path='viz_earth_animation.png')
+
+
+viz earth animation

Total running time of the script: (0 minutes 39.436 seconds)

+ +

Gallery generated by Sphinx-Gallery

+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/auto_examples/01_introductory/viz_earth_coordinates.html b/v0.10.x/auto_examples/01_introductory/viz_earth_coordinates.html new file mode 100644 index 000000000..5b0f1e083 --- /dev/null +++ b/v0.10.x/auto_examples/01_introductory/viz_earth_coordinates.html @@ -0,0 +1,655 @@ + + + + + + + + Earth Coordinate Conversion — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +
+

Earth Coordinate Conversion#

+

In this tutorial, we will show how to place actors on specific locations +on the surface of the Earth using a new function.

+
import itertools
+import math
+
+import numpy as np
+
+from fury import actor, io, utils, window
+from fury.data import fetch_viz_textures, read_viz_textures
+
+
+

Create a new scene, and load in the image of the Earth using +fetch_viz_textures and read_viz_textures. We will use a 16k +resolution texture for maximum detail.

+
scene = window.Scene()
+
+fetch_viz_textures()
+earth_file = read_viz_textures('1_earth_16k.jpg')
+earth_image = io.load_image(earth_file)
+earth_actor = actor.texture_on_sphere(earth_image)
+scene.add(earth_actor)
+
+
+
Dataset is already in place. If you want to fetch it again please first remove the folder /Users/skoudoro/.fury/textures
+/opt/homebrew/Caskroom/miniforge/base/envs/py311-fury/lib/python3.11/site-packages/PIL/Image.py:3186: DecompressionBombWarning: Image size (131220000 pixels) exceeds limit of 89478485 pixels, could be decompression bomb DOS attack.
+  warnings.warn(
+
+
+

Rotate the Earth to make sure the texture is correctly oriented. Change it’s +scale using actor.SetScale().

+
utils.rotate(earth_actor, (-90, 1, 0, 0))
+utils.rotate(earth_actor, (180, 0, 1, 0))
+earth_actor.SetScale(2, 2, 2)
+
+
+

Define the function to convert geographical coordinates of a location in +latitude and longitude degrees to coordinates on the earth_actor surface. +In this function, convert to radians, then to spherical coordinates, and +lastly, to cartesian coordinates.

+
def latlong_coordinates(lat, lon):
+    # Convert latitude and longitude to spherical coordinates
+    degrees_to_radians = math.pi / 180.0
+    # phi = 90 - latitude
+    phi = (90 - lat) * degrees_to_radians
+    # theta = longitude
+    theta = lon * degrees_to_radians * -1
+    # now convert to cartesian
+    x = np.sin(phi) * np.cos(theta)
+    y = np.sin(phi) * np.sin(theta)
+    z = np.cos(phi)
+    # flipping z to y for FURY coordinates
+    return (x, z, y)
+
+
+

Use this new function to place some sphere actors on several big cities +around the Earth.

+
locationone = latlong_coordinates(40.730610, -73.935242)  # new york city, us
+locationtwo = latlong_coordinates(39.916668, 116.383331)  # beijing, china
+locationthree = latlong_coordinates(48.864716, 2.349014)  # paris, france
+
+
+

Set the centers, radii, and colors of these spheres, and create a new +sphere_actor for each location to add to the scene.

+
centers = np.array([[*locationone], [*locationtwo], [*locationthree]])
+colors = np.random.rand(3, 3)
+radii = np.array([0.005, 0.005, 0.005])
+sphere_actor = actor.sphere(centers, colors, radii)
+scene.add(sphere_actor)
+
+
+

Create some text actors to add to the scene indicating each location and its +geographical coordinates.

+
nyc_actor = actor.text_3d(
+    'New York City, New York\n40.7128° N, 74.0060° W',
+    (locationone[0] - 0.04, locationone[1], locationone[2] + 0.07),
+    window.colors.white,
+    0.01,
+)
+paris_actor = actor.text_3d(
+    'Paris, France\n48.8566° N, 2.3522° E',
+    (locationthree[0] - 0.04, locationthree[1], locationthree[2] - 0.07),
+    window.colors.white,
+    0.01,
+)
+beijing_actor = actor.text_3d(
+    'Beijing, China\n39.9042° N, 116.4074° E',
+    (locationtwo[0] - 0.06, locationtwo[1], locationtwo[2] - 0.07),
+    window.colors.white,
+    0.01,
+)
+utils.rotate(paris_actor, (85, 0, 1, 0))
+utils.rotate(beijing_actor, (180, 0, 1, 0))
+utils.rotate(nyc_actor, (5, 1, 0, 0))
+
+
+

Create a ShowManager object, which acts as the interface between the scene, +the window and the interactor.

+
showm = window.ShowManager(
+    scene, size=(900, 768), reset_camera=False, order_transparent=True
+)
+
+
+

Let’s create a timer_callback function to add some animation to the +Earth. Change the camera position and angle to fly over and zoom in on each +new location.

+
counter = itertools.count()
+
+
+def timer_callback(_obj, _event):
+    cnt = next(counter)
+    showm.render()
+    if cnt == 0:
+        scene.set_camera(position=(1.5, 3.5, 7.0))
+    if cnt < 200 and cnt > 25:
+        scene.zoom(1.015)
+        scene.pitch(0.01)
+    if cnt == 200:
+        scene.add(nyc_actor)
+    if cnt > 250 and cnt < 350:
+        scene.zoom(0.985)
+    if cnt > 350 and cnt < 425:
+        scene.azimuth(1)
+    if cnt > 425 and cnt < 525:
+        scene.zoom(1.015)
+        scene.pitch(0.011)
+    if cnt == 525:
+        scene.add(paris_actor)
+    if cnt > 575 and cnt < 700:
+        scene.zoom(0.985)
+    if cnt > 700 and cnt < 820:
+        scene.azimuth(1)
+    if cnt > 820 and cnt < 930:
+        scene.zoom(1.015)
+    if cnt == 930:
+        scene.add(beijing_actor)
+    if cnt == 1000:
+        showm.exit()
+
+
+

Initialize the ShowManager object, add the timer_callback, and watch the +new animation take place!

+
showm.add_timer_callback(True, 25, timer_callback)
+showm.start()
+
+window.record(showm.scene, size=(900, 768), out_path='viz_earth_coordinates.png')
+
+
+viz earth coordinates

Total running time of the script: (0 minutes 27.806 seconds)

+ +

Gallery generated by Sphinx-Gallery

+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/auto_examples/01_introductory/viz_gltf.html b/v0.10.x/auto_examples/01_introductory/viz_gltf.html new file mode 100644 index 000000000..c10b8ce1a --- /dev/null +++ b/v0.10.x/auto_examples/01_introductory/viz_gltf.html @@ -0,0 +1,549 @@ + + + + + + + + Visualizing a glTF file — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +
+

Visualizing a glTF file#

+

In this tutorial, we will show how to display a glTF file in a scene.

+
from fury import window
+from fury.data import fetch_gltf, read_viz_gltf
+from fury.gltf import glTF
+
+
+

Create a scene.

+
scene = window.Scene()
+scene.SetBackground(0.1, 0.1, 0.4)
+
+
+

Retrieving the gltf model.

+
fetch_gltf('Duck', 'glTF')
+filename = read_viz_gltf('Duck')
+
+
+

Initialize the glTF object and get actors using actors method. +Note: You can always manually create actor from polydata, and apply texture +or materials manually afterwards. +Experimental: For smooth mesh/actor you can set apply_normals=True.

+
gltf_obj = glTF(filename, apply_normals=False)
+actors = gltf_obj.actors()
+
+
+

Add all the actor from list of actors to the scene.

+ +

Applying camera

+
cameras = gltf_obj.cameras
+if cameras:
+    scene.SetActiveCamera(cameras[0])
+
+interactive = False
+
+if interactive:
+    window.show(scene, size=(1280, 720))
+
+window.record(scene, out_path='viz_gltf.png', size=(1280, 720))
+
+
+viz gltf

Total running time of the script: (0 minutes 0.135 seconds)

+ +

Gallery generated by Sphinx-Gallery

+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/auto_examples/01_introductory/viz_gltf_animated.html b/v0.10.x/auto_examples/01_introductory/viz_gltf_animated.html new file mode 100644 index 000000000..d20a3135e --- /dev/null +++ b/v0.10.x/auto_examples/01_introductory/viz_gltf_animated.html @@ -0,0 +1,556 @@ + + + + + + + + Visualizing a glTF file — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +
+

Visualizing a glTF file#

+

In this tutorial, we will show how to display a simple animated glTF in a +scene.

+
from fury import window
+from fury.data import fetch_gltf, read_viz_gltf
+from fury.gltf import glTF
+
+
+

Create a scene.

+
scene = window.Scene()
+
+showm = window.ShowManager(
+    scene, size=(900, 768), reset_camera=False, order_transparent=True
+)
+showm.initialize()
+
+
+

Retrieving the gltf model.

+
fetch_gltf('InterpolationTest', 'glTF')
+filename = read_viz_gltf('InterpolationTest')
+
+
+

Initialize the glTF object and get actors using actors method. +Get the main_timeline (which contains multiple Timeline objects).

+ +

Add the timeline to the scene (No need to add actors separately).

+
scene.add(timeline)
+
+
+

define a timer_callback that updates the timeline.

+
interactive = False
+
+
+def timer_callback(_obj, _event):
+    timeline.update_animation()
+    showm.render()
+
+
+showm.add_timer_callback(True, 10, timer_callback)
+
+if interactive:
+    showm.start()
+
+window.record(scene, out_path='viz_gltf_animated.png', size=(900, 768))
+
+
+viz gltf animated

Total running time of the script: (0 minutes 0.156 seconds)

+ +

Gallery generated by Sphinx-Gallery

+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/auto_examples/01_introductory/viz_gltf_export.html b/v0.10.x/auto_examples/01_introductory/viz_gltf_export.html new file mode 100644 index 000000000..c3aae29fe --- /dev/null +++ b/v0.10.x/auto_examples/01_introductory/viz_gltf_export.html @@ -0,0 +1,565 @@ + + + + + + + + Exporting scene as a glTF file — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +
+

Exporting scene as a glTF file#

+

In this tutorial, we will show how to create a glTF file for a scene.

+
import numpy as np
+
+from fury import actor, gltf, window
+from fury.data import fetch_gltf, read_viz_gltf
+
+
+

Specifying centers and colors for actors. We will use these parameters +later.

+
centers = np.zeros((3, 3))
+colors = np.array([1, 1, 1])
+
+
+

Create a scene.

+ +

Creating actors and adding to scene.

+
cube = actor.cube(np.add(centers, np.array([2, 0, 0])), colors=colors / 2)
+scene.add(cube)
+
+sphere = actor.sphere(np.add(centers, np.array([0, 2, 0])), colors=colors)
+scene.add(sphere)
+
+fetch_gltf('BoxTextured', 'glTF')
+filename = read_viz_gltf('BoxTextured')
+gltf_obj = gltf.glTF(filename)
+box_actor = gltf_obj.actors()
+scene.add(box_actor[0])
+
+
+

Setting camera to the scene.

+
scene.set_camera(
+    position=(4.45, -21, 12), focal_point=(4.45, 0.0, 0.0), view_up=(0.0, 0.0, 1.0)
+)
+
+
+

Exporting scene as a glTF file

+
gltf.export_scene(scene, filename='viz_gltf_export.gltf')
+
+
+viz gltf export

Reading the newly created glTF file and get actors.

+
gltf_obj = gltf.glTF('viz_gltf_export.gltf')
+actors = gltf_obj.actors()
+
+
+

Add all the actor from list of actors to the scene.

+
scene.add(*actors)
+
+interactive = False
+
+if interactive:
+    window.show(scene, size=(1280, 720))
+
+window.record(scene, out_path='viz_gltf_export.png', size=(1280, 720))
+
+
+viz gltf export

Total running time of the script: (0 minutes 0.120 seconds)

+ +

Gallery generated by Sphinx-Gallery

+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/auto_examples/01_introductory/viz_morphing.html b/v0.10.x/auto_examples/01_introductory/viz_morphing.html new file mode 100644 index 000000000..959050dcf --- /dev/null +++ b/v0.10.x/auto_examples/01_introductory/viz_morphing.html @@ -0,0 +1,568 @@ + + + + + + + + Morphing Animation in a glTF — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +
+

Morphing Animation in a glTF#

+

In this tutorial, we will show how to use morphing in a glTF model in FURY.

+
from fury import window
+from fury.data import fetch_gltf, read_viz_gltf
+from fury.gltf import glTF
+
+
+

Retrieving the model with morphing in it (look at Khronoos samples). +We’re choosing the MorphStressTest model here.

+
fetch_gltf('MorphStressTest', 'glTF')
+filename = read_viz_gltf('MorphStressTest')
+
+
+

Initializing the glTF object, You can additionally set apply_normals=True. +Note: Normals might not work as intended with morphing.

+
gltf_obj = glTF(filename, apply_normals=True)
+
+
+

Get the morph timeline using morph_timeline method, Choose the animation +name you want to visualize. +Note: If there’s no name for animation, It’s stored as anim_0, anim_1 etc

+
animation = gltf_obj.morph_animation()['TheWave']
+
+
+

Call the update_morph method once, This moves initialise the morphing at +timestamp 0.0 seconds and ensures that camera fits all the actors perfectly.

+
+
+

Create a scene, and show manager. +Initialize the show manager and add timeline to the scene (No need to add +actors to the scene separately).

+
scene = window.Scene()
+showm = window.ShowManager(
+    scene, size=(900, 768), reset_camera=True, order_transparent=True
+)
+
+showm.initialize()
+scene.add(animation)
+
+
+

define a timer_callback. +Use the update_morph method again, It updates the timeline and applies +morphing).

+
def timer_callback(_obj, _event):
+    gltf_obj.update_morph(animation)
+    showm.render()
+
+
+

Optional: timeline.play() auto plays the animations.

+
showm.add_timer_callback(True, 20, timer_callback)
+scene.reset_camera()
+
+interactive = False
+
+if interactive:
+    showm.start()
+
+window.record(scene, out_path='viz_morphing.png', size=(900, 768))
+
+
+viz morphing

Total running time of the script: (0 minutes 0.165 seconds)

+ +

Gallery generated by Sphinx-Gallery

+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/auto_examples/01_introductory/viz_multithread.html b/v0.10.x/auto_examples/01_introductory/viz_multithread.html new file mode 100644 index 000000000..453d3f964 --- /dev/null +++ b/v0.10.x/auto_examples/01_introductory/viz_multithread.html @@ -0,0 +1,721 @@ + + + + + + + + Multithreading Example — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +
+

Multithreading Example#

+

The goal of this demo is to show how to use different threads +to interact with FURY. In particular, the main thread is used +to update interactions and render the scene, while thread A +rotates the camera, thread B prints a counter, and thread C +adds and removes elements from the scene.

+
Counter: 0
+Counter: 1
+Counter: 2
+Counter: 3
+Counter: 4
+Counter: 5
+Counter: 6
+Counter: 7
+Counter: 8
+Counter: 9
+Counter: 10
+Counter: 11
+Counter: 12
+Counter: 13
+Counter: 14
+Counter: 15
+Counter: 16
+Counter: 17
+Counter: 18
+Counter: 19
+Counter: 20
+Counter: 21
+Counter: 22
+Counter: 23
+Counter: 24
+Counter: 25
+Counter: 26
+Counter: 27
+Counter: 28
+Counter: 29
+Counter: 30
+Counter: 31
+Counter: 32
+Counter: 33
+Counter: 34
+Counter: 35
+Counter: 36
+Counter: 37
+Counter: 38
+Counter: 39
+Counter: 40
+Counter: 41
+Counter: 42
+Counter: 43
+Counter: 44
+Counter: 45
+Counter: 46
+Counter: 47
+Counter: 48
+Counter: 49
+Counter: 50
+Counter: 51
+Counter: 52
+Counter: 53
+Counter: 54
+Counter: 55
+Counter: 56
+Counter: 57
+Counter: 58
+Counter: 59
+Counter: 60
+Counter: 61
+Counter: 62
+Counter: 63
+Counter: 64
+Counter: 65
+Counter: 66
+Counter: 67
+Counter: 68
+Counter: 69
+Counter: 70
+Counter: 71
+Counter: 72
+Counter: 73
+Counter: 74
+Counter: 75
+Counter: 76
+Counter: 77
+Counter: 78
+Counter: 79
+Counter: 80
+Counter: 81
+Counter: 82
+Counter: 83
+Counter: 84
+Counter: 85
+Counter: 86
+Counter: 87
+Counter: 88
+Counter: 89
+Counter: 90
+Counter: 91
+Counter: 92
+Counter: 93
+Counter: 94
+Counter: 95
+Counter: 96
+Counter: 97
+Counter: 98
+Counter: 99
+
+
+
+

+
+
import time
+from threading import Thread
+
+import numpy as np
+
+from fury import actor, ui, window
+
+# Preparing to draw some spheres
+xyz = 10 * (np.random.random((100, 3)) - 0.5)
+colors = np.random.random((100, 4))
+radii = np.random.random(100) + 0.5
+
+scene = window.Scene()
+sphere_actor = actor.sphere(
+    centers=xyz, colors=colors, radii=radii, use_primitive=False
+)
+scene.add(sphere_actor)
+
+
+# Preparing the show manager as usual
+showm = window.ShowManager(
+    scene, size=(900, 768), reset_camera=False, order_transparent=True
+)
+
+# showm.initialize()
+
+# Creating a text block to show a message and reset the camera
+tb = ui.TextBlock2D(bold=True)
+scene.add(tb)
+scene.ResetCamera()
+
+
+# Create a function to print a counter to the console
+def print_counter():
+    print('')
+    for i in range(100):
+        print('\rCounter: %d' % i, end='')
+        message = "Let's count up to 100 and exit :" + str(i + 1)
+        tb.message = message
+        time.sleep(0.05)
+        if showm.is_done():
+            break
+    showm.exit()
+    print('')
+
+
+# Create a function to rotate the camera
+
+
+def rotate_camera():
+    for i in range(100):
+        if showm.lock_current():
+            scene.azimuth(0.01 * i)
+            showm.release_current()
+            time.sleep(0.05)
+        else:
+            break
+
+
+# Create a function to add or remove the axes and increase its scale
+
+
+def add_remove_axes():
+    current_axes = None
+    for i in range(100):
+        if showm.lock_current():
+            if current_axes is None:
+                current_axes = actor.axes(scale=(0.20 * i, 0.20 * i, 0.20 * i))
+                scene.add(current_axes)
+                pass
+            else:
+                scene.rm(current_axes)
+                current_axes = None
+                pass
+            showm.release_current()
+            time.sleep(0.1)
+        else:
+            break
+
+
+# Start the threads
+# Multiple threads can be started here
+# First, one to rotate the camera
+thread_a = Thread(target=rotate_camera)
+thread_a.start()
+
+# Now let's start a thread that will print a counter
+thread_b = Thread(target=print_counter)
+thread_b.start()
+
+# Now let's start a thread that will add or remove axes
+thread_c = Thread(target=add_remove_axes)
+thread_c.start()
+
+# Let's start the show manager loop with multithreading option
+showm.start(multithreaded=True)
+
+# Wait for the threads to finish
+thread_a.join()
+thread_b.join()
+thread_c.join()
+
+
+

Total running time of the script: (0 minutes 5.510 seconds)

+ +

Gallery generated by Sphinx-Gallery

+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/auto_examples/01_introductory/viz_picking.html b/v0.10.x/auto_examples/01_introductory/viz_picking.html new file mode 100644 index 000000000..0d38d50c1 --- /dev/null +++ b/v0.10.x/auto_examples/01_introductory/viz_picking.html @@ -0,0 +1,651 @@ + + + + + + + + Simple picking — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +
+

Simple picking#

+

Here we present a tutorial showing how to interact with objects in the +3D world. All objects to be picked are part of a single actor. +FURY likes to bundle objects in a few actors to reduce code and +increase speed.

+

When the objects are picked they will change size and color.

+
import numpy as np
+
+from fury import actor, pick, ui, utils, window
+
+centers = 0.5 * np.array([[0, 0, 0], [100, 0, 0], [200, 0, 0.0]])
+colors = np.array([[0.8, 0, 0], [0, 0.8, 0], [0, 0, 0.8]])
+radii = 0.1 * np.array([50, 100, 150.0])
+
+selected = np.zeros(3, dtype=bool)
+
+
+

Let’s create a panel to show what is picked

+
panel = ui.Panel2D(size=(400, 200), color=(1, 0.5, 0.0), align='right')
+panel.center = (150, 200)
+
+text_block = ui.TextBlock2D(text='Left click on object \n')
+panel.add_element(text_block, (0.3, 0.3))
+
+
+

Build scene and add an actor with many objects.

+
scene = window.Scene()
+
+label_actor = actor.vector_text(text='Test')
+
+
+

This actor is made with 3 cubes of different orientation

+
directions = np.array(
+    [
+        [np.sqrt(2) / 2, 0, np.sqrt(2) / 2],
+        [np.sqrt(2) / 2, np.sqrt(2) / 2, 0],
+        [0, np.sqrt(2) / 2, np.sqrt(2) / 2],
+    ]
+)
+fury_actor = actor.cube(centers, directions, colors, scales=radii)
+
+
+

Access the memory of the vertices of all the cubes

+ +

Access the memory of the colors of all the cubes

+
vcolors = utils.colors_from_actor(fury_actor, 'colors')
+
+
+

Adding an actor showing the axes of the world coordinates

+
ax = actor.axes(scale=(10, 10, 10))
+
+scene.add(fury_actor)
+scene.add(label_actor)
+scene.add(ax)
+scene.reset_camera()
+
+
+

Create the Picking manager

+ +

Time to make the callback which will be called when we pick an object

+
def left_click_callback(obj, event):
+
+    # Get the event position on display and pick
+
+    event_pos = pickm.event_position(showm.iren)
+    picked_info = pickm.pick(event_pos, showm.scene)
+
+    vertex_index = picked_info['vertex']
+
+    # Calculate the objects index
+
+    object_index = int(np.floor((vertex_index / num_vertices) * num_objects))
+
+    # Find how many vertices correspond to each object
+    sec = int(num_vertices / num_objects)
+
+    if not selected[object_index]:
+        scale = 6 / 5
+        color_add = np.array([30, 30, 30], dtype='uint8')
+        selected[object_index] = True
+    else:
+        scale = 5 / 6
+        color_add = np.array([-30, -30, -30], dtype='uint8')
+        selected[object_index] = False
+
+    # Update vertices positions
+    vertices[object_index * sec : object_index * sec + sec] = (
+        scale
+        * (
+            vertices[object_index * sec : object_index * sec + sec]
+            - centers[object_index]
+        )
+        + centers[object_index]
+    )
+
+    # Update colors
+    vcolors[object_index * sec : object_index * sec + sec] += color_add
+
+    # Tell actor that memory is modified
+    utils.update_actor(fury_actor)
+
+    face_index = picked_info['face']
+
+    # Show some info
+    text = 'Object ' + str(object_index) + '\n'
+    text += 'Vertex ID ' + str(vertex_index) + '\n'
+    text += 'Face ID ' + str(face_index) + '\n'
+    text += 'World pos ' + str(np.round(picked_info['xyz'], 2)) + '\n'
+    text += 'Actor ID ' + str(id(picked_info['actor']))
+    text_block.message = text
+    showm.render()
+
+
+

Bind the callback to the actor

+
fury_actor.AddObserver('LeftButtonPressEvent', left_click_callback, 1)
+
+
+
1
+
+
+

Make the window appear

+
showm = window.ShowManager(scene, size=(1024, 768), order_transparent=True)
+
+scene.add(panel)
+
+
+

Change interactive to True to start interacting with the scene

+
interactive = False
+
+if interactive:
+
+    showm.start()
+
+
+

Save the current framebuffer in a PNG file

+
window.record(showm.scene, size=(1024, 768), out_path='viz_picking.png')
+
+
+viz picking

Total running time of the script: (0 minutes 0.085 seconds)

+ +

Gallery generated by Sphinx-Gallery

+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/auto_examples/01_introductory/viz_selection.html b/v0.10.x/auto_examples/01_introductory/viz_selection.html new file mode 100644 index 000000000..4d2b3a4a6 --- /dev/null +++ b/v0.10.x/auto_examples/01_introductory/viz_selection.html @@ -0,0 +1,624 @@ + + + + + + + + Selecting multiple objects — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +
+

Selecting multiple objects#

+

Here we show how to select objects in the +3D world. In this example all objects to be picked are part of +a single actor.

+

FURY likes to bundle objects in a few actors to reduce code and +increase speed. Nonetheless the method works for multiple actors too.

+

The difference with the picking tutorial is that here we will +be able to select more than one object. In addition we can +select interactively many vertices or faces.

+

In summary, we will create an actor with thousands of cubes and +then interactively we will be moving a rectangular box by +hovering the mouse and making transparent everything that is +behind that box.

+
import numpy as np
+
+from fury import actor, pick, utils, window
+
+
+

Adding many cubes of different sizes and colors

+
num_cubes = 50000
+
+centers = 10000 * (np.random.rand(num_cubes, 3) - 0.5)
+colors = np.random.rand(num_cubes, 4)
+colors[:, 3] = 1.0
+radii = 100 * np.random.rand(num_cubes) + 0.1
+
+
+

Keep track of total number of triangle faces +Note that every quad of each cube has 2 triangles +and each cube has 6 quads in total.

+
num_faces = num_cubes * 6 * 2
+
+
+

Build scene and add an actor with many objects.

+ +

Build the actor containing all the cubes

+
cube_actor = actor.cube(centers, directions=(1, 0, 0), colors=colors, scales=radii)
+
+
+

Access the memory of the vertices of all the cubes

+ +

Access the memory of the colors of all the cubes

+
vcolors = utils.colors_from_actor(cube_actor, 'colors')
+
+
+

Create a rectangular 2d box as a texture

+
rgba = 255 * np.ones((100, 200, 4))
+rgba[1:-1, 1:-1] = np.zeros((98, 198, 4)) + 100
+texa = actor.texture_2d(rgba.astype(np.uint8))
+
+scene.add(cube_actor)
+scene.add(texa)
+scene.reset_camera()
+scene.zoom(3.0)
+
+
+

Create the Selection Manager

+
selm = pick.SelectionManager(select='faces')
+
+
+

Tell Selection Manager to avoid selecting specific actors

+ +

Let’s make the callback which will be called +when we hover the mouse

+
def hover_callback(_obj, _event):
+    event_pos = selm.event_position(showm.iren)
+    # updates rectangular box around mouse
+    texa.SetPosition(event_pos[0] - 200 // 2, event_pos[1] - 100 // 2)
+
+    # defines selection region and returns information from selected objects
+    info = selm.select(event_pos, showm.scene, (200 // 2, 100 // 2))
+    for node in info.keys():
+        if info[node]['face'] is not None:
+            if info[node]['actor'] is cube_actor:
+                for face_index in info[node]['face']:
+                    # generates an object_index to help with coloring
+                    # by dividing by the number of faces of each cube (6 * 2)
+                    object_index = face_index // 12
+                    sec = int(num_vertices / num_objects)
+                    color_change = np.array([150, 0, 0, 255], dtype='uint8')
+                    vcolors[
+                        object_index * sec : object_index * sec + sec
+                    ] = color_change
+                utils.update_actor(cube_actor)
+    showm.render()
+
+
+

Make the window appear

+
showm = window.ShowManager(
+    scene, size=(1024, 768), order_transparent=True, reset_camera=False
+)
+
+
+

Bind the callback to the actor

+
showm.add_iren_callback(hover_callback)
+
+
+

Change interactive to True to start interacting with the scene

+
interactive = False
+
+if interactive:
+
+    showm.start()
+
+
+

Save the current framebuffer in a PNG file

+
window.record(showm.scene, size=(1024, 768), out_path='viz_selection.png')
+
+
+viz selection

Total running time of the script: (0 minutes 1.308 seconds)

+ +

Gallery generated by Sphinx-Gallery

+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/auto_examples/01_introductory/viz_skinning.html b/v0.10.x/auto_examples/01_introductory/viz_skinning.html new file mode 100644 index 000000000..b8b2232c1 --- /dev/null +++ b/v0.10.x/auto_examples/01_introductory/viz_skinning.html @@ -0,0 +1,571 @@ + + + + + + + + Skeletal Animation in a glTF file — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +
+

Skeletal Animation in a glTF file#

+

In this tutorial, we will show how to use skeletal animations (skinning) in a +glTF model in FURY.

+
from fury import window
+from fury.data import fetch_gltf, read_viz_gltf
+from fury.gltf import glTF
+
+
+

Retrieving the model with skeletal animations. +We’re choosing the RiggedFigure model here.

+
fetch_gltf('RiggedFigure', 'glTF')
+filename = read_viz_gltf('RiggedFigure')
+
+
+

Initializing the glTF object, You can additionally set apply_normals=True. +Note: Normals might not work well as intended with skinning animations.

+
gltf_obj = glTF(filename, apply_normals=False)
+
+
+

Get the skinning timeline using skin_timeline method, Choose the animation +name you want to visualize. +Note: If there’s no name for animation, It’s stored as anim_0, anim_1 etc

+
animation = gltf_obj.skin_animation()['anim_0']
+
+# After we get the timeline object, We want to initialise the skinning process.
+# You can set `bones=true` to visualize each bone transformation. Additionally,
+# you can set `length` of bones in the `initialise_skin` method.
+# Note: Make sure to call this method before you initialize ShowManager, else
+# bones won't be added to the scene.
+
+gltf_obj.initialize_skin(animation, bones=False)
+
+
+

Create a scene, and show manager. +Initialize the show manager and add timeline to the scene (No need to add +actors to the scene separately).

+
scene = window.Scene()
+showm = window.ShowManager(
+    scene, size=(900, 768), reset_camera=True, order_transparent=True
+)
+showm.initialize()
+scene.add(animation)
+
+
+

define a timer_callback. +Use the update_skin method, It updates the timeline and applies skinning to +actors (and bones).

+
def timer_callback(_obj, _event):
+    gltf_obj.update_skin(animation)
+    showm.render()
+
+
+

Optional: timeline.play() auto plays the animations.

+
showm.add_timer_callback(True, 20, timer_callback)
+scene.reset_camera()
+
+interactive = False
+
+if interactive:
+    showm.start()
+
+window.record(scene, out_path='viz_skinning.png', size=(900, 768))
+
+
+viz skinning

Total running time of the script: (0 minutes 0.644 seconds)

+ +

Gallery generated by Sphinx-Gallery

+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/auto_examples/01_introductory/viz_slice.html b/v0.10.x/auto_examples/01_introductory/viz_slice.html new file mode 100644 index 000000000..89bb8691c --- /dev/null +++ b/v0.10.x/auto_examples/01_introductory/viz_slice.html @@ -0,0 +1,774 @@ + + + + + + + + Simple volume slicing — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +
+

Simple volume slicing#

+

Here we present an example for visualizing slices from 3D images.

+
import os
+
+import nibabel as nib
+from dipy.data import fetch_bundles_2_subjects
+
+from fury import actor, ui, window
+
+
+

Let’s download and load a T1.

+
fetch_bundles_2_subjects()
+
+fname_t1 = os.path.join(
+    os.path.expanduser('~'),
+    '.dipy',
+    'exp_bundles_and_maps',
+    'bundles_2_subjects',
+    'subj_1',
+    't1_warped.nii.gz',
+)
+
+
+img = nib.load(fname_t1)
+data = img.get_fdata()
+affine = img.affine
+
+
+

Create a Scene object which holds all the actors which we want to visualize.

+
scene = window.Scene()
+scene.background((0.5, 0.5, 0.5))
+
+
+
+

Render slices from T1 with a specific value range#

+

The T1 has usually a higher range of values than what can be visualized in an +image. We can set the range that we would like to see.

+
mean, std = data[data > 0].mean(), data[data > 0].std()
+value_range = (mean - 0.5 * std, mean + 1.5 * std)
+
+
+

The slice function will read data and resample the data using an affine +transformation matrix. The default behavior of this function is to show the +middle slice of the last dimension of the resampled data.

+
slice_actor = actor.slicer(data, affine, value_range)
+
+
+

The slice_actor contains an axial slice.

+
scene.add(slice_actor)
+
+
+

The same actor can show any different slice from the given data using its +display function. However, if we want to show multiple slices we need to +copy the actor first.

+
slice_actor2 = slice_actor.copy()
+
+
+

Now we have a new slice_actor which displays the middle slice of sagittal +plane.

+
slice_actor2.display(slice_actor2.shape[0] // 2, None, None)
+
+scene.add(slice_actor2)
+
+scene.reset_camera()
+scene.zoom(1.4)
+
+
+

In order to interact with the data you will need to uncomment the line below.

+
# window.show(scene, size=(600, 600), reset_camera=False)
+
+
+

Otherwise, you can save a screenshot using the following command.

+
window.record(scene, out_path='slices.png', size=(600, 600), reset_camera=False)
+
+
+viz slice
+
+

Render slices from FA with your colormap#

+
# It is also possible to set the colormap of your preference. Here we are
+# loading an FA image and showing it in a non-standard way using an HSV
+# colormap.
+
+fname_fa = os.path.join(
+    os.path.expanduser('~'),
+    '.dipy',
+    'exp_bundles_and_maps',
+    'bundles_2_subjects',
+    'subj_1',
+    'fa_1x1x1.nii.gz',
+)
+
+img = nib.load(fname_fa)
+fa = img.get_fdata()
+
+
+

Notice here how the scale range is. We use FA min and max values to set it up

+
lut = actor.colormap_lookup_table(
+    scale_range=(fa.min(), fa.max()),
+    hue_range=(0.4, 1.0),
+    saturation_range=(1, 1.0),
+    value_range=(0.0, 1.0),
+)
+
+
+

This is because the lookup table is applied in the slice after interpolating +to (0, 255).

+
fa_actor = actor.slicer(fa, affine, lookup_colormap=lut)
+
+scene.clear()
+scene.add(fa_actor)
+
+scene.reset_camera()
+scene.zoom(1.4)
+
+# window.show(scene, size=(600, 600), reset_camera=False)
+
+window.record(scene, out_path='slices_lut.png', size=(600, 600), reset_camera=False)
+
+
+viz slice

Now we would like to add the ability to click on a voxel and show its value +on a panel in the window. The panel is a UI element which requires access to +different areas of the visualization pipeline and therefore we don’t +recommend using it with window.show. The more appropriate way is to use +the ShowManager object, which allows accessing the pipeline in different +areas.

+
show_m = window.ShowManager(scene, size=(1200, 900))
+
+
+

We’ll start by creating the panel and adding it to the ShowManager

+
label_position = ui.TextBlock2D(text='Position:')
+label_value = ui.TextBlock2D(text='Value:')
+
+result_position = ui.TextBlock2D(text='')
+result_value = ui.TextBlock2D(text='')
+
+panel_picking = ui.Panel2D(
+    size=(250, 125), position=(20, 20), color=(0, 0, 0), opacity=0.75, align='left'
+)
+
+panel_picking.add_element(label_position, (0.1, 0.55))
+panel_picking.add_element(label_value, (0.1, 0.25))
+
+panel_picking.add_element(result_position, (0.45, 0.55))
+panel_picking.add_element(result_value, (0.45, 0.25))
+
+show_m.scene.add(panel_picking)
+
+
+

Add a left-click callback to the slicer. Also disable interpolation so you +can see what you are picking.

+
def left_click_callback(obj, _ev):
+    """Get the value of the clicked voxel and show it in the panel."""
+    event_pos = show_m.iren.GetEventPosition()
+
+    obj.picker.Pick(event_pos[0], event_pos[1], 0, show_m.scene)
+
+    i, j, k = obj.picker.GetPointIJK()
+    result_position.message = '({}, {}, {})'.format(str(i), str(j), str(k))
+    result_value.message = '%.8f' % data[i, j, k]
+
+
+fa_actor.SetInterpolate(False)
+fa_actor.AddObserver('LeftButtonPressEvent', left_click_callback, 1.0)
+
+# show_m.start()
+
+
+
1
+
+
+
+
+

Create a mosaic#

+

By using the copy and display method of the slice_actor becomes +easy and efficient to create a mosaic of all the slices.

+

So, let’s clear the scene and change the projection from perspective to +parallel. We’ll also need a new show manager and an associated callback.

+
scene.clear()
+scene.projection('parallel')
+
+result_position.message = ''
+result_value.message = ''
+
+show_m_mosaic = window.ShowManager(scene, size=(1200, 900))
+
+
+def left_click_callback_mosaic(obj, _ev):
+    """Get the value of the clicked voxel and show it in the panel."""
+    event_pos = show_m_mosaic.iren.GetEventPosition()
+
+    obj.picker.Pick(event_pos[0], event_pos[1], 0, show_m_mosaic.scene)
+
+    i, j, k = obj.picker.GetPointIJK()
+    result_position.message = '({}, {}, {})'.format(str(i), str(j), str(k))
+    result_value.message = '%.8f' % data[i, j, k]
+
+
+

Now we need to create two nested for loops which will set the positions of +the grid of the mosaic and add the new actors to the scene. We are going +to use 15 columns and 10 rows but you can adjust those with your datasets.

+
cnt = 0
+
+X, Y, Z = slice_actor.shape[:3]
+
+rows = 10
+cols = 15
+border = 10
+
+for j in range(rows):
+    for i in range(cols):
+        slice_mosaic = slice_actor.copy()
+        slice_mosaic.display(None, None, cnt)
+        slice_mosaic.SetPosition(
+            (X + border) * i, 0.5 * cols * (Y + border) - (Y + border) * j, 0
+        )
+        slice_mosaic.SetInterpolate(False)
+        slice_mosaic.AddObserver(
+            'LeftButtonPressEvent', left_click_callback_mosaic, 1.0
+        )
+        scene.add(slice_mosaic)
+        cnt += 1
+        if cnt > Z:
+            break
+    if cnt > Z:
+        break
+
+scene.reset_camera()
+scene.zoom(1.0)
+
+# show_m_mosaic.scene.add(panel_picking)
+# show_m_mosaic.start()
+
+
+

If you uncomment the two lines above, you will be able to move +the mosaic up/down and left/right using the middle mouse button drag, +zoom in/out using the scroll wheel, and pick voxels with left click.

+
window.record(scene, out_path='mosaic.png', size=(900, 600), reset_camera=False)
+
+
+viz slice

Total running time of the script: (0 minutes 2.768 seconds)

+ +

Gallery generated by Sphinx-Gallery

+
+
+ +
+ + +
+ +
+ + + + + +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/auto_examples/01_introductory/viz_solar_system.html b/v0.10.x/auto_examples/01_introductory/viz_solar_system.html new file mode 100644 index 000000000..c7f8fa31d --- /dev/null +++ b/v0.10.x/auto_examples/01_introductory/viz_solar_system.html @@ -0,0 +1,807 @@ + + + + + + + + Solar System Animation — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +
+

Solar System Animation#

+

In this tutorial, we will create an animation of the solar system +using textured spheres. We will also show how to manipulate the +position of these sphere actors in a timer_callback function +to simulate orbital motion.

+
import itertools
+
+import numpy as np
+
+from fury import actor, io, ui, utils, window
+from fury.data import fetch_viz_textures, read_viz_icons, read_viz_textures
+
+
+

Create a scene to start.

+
scene = window.Scene()
+
+# Create a panel and the start/pause buttons
+
+panel = ui.Panel2D(size=(300, 100), color=(1, 1, 1), align='right')
+panel.center = (400, 50)
+
+pause_button = ui.Button2D(icon_fnames=[('square', read_viz_icons(fname='pause2.png'))])
+start_button = ui.Button2D(icon_fnames=[('square', read_viz_icons(fname='play3.png'))])
+
+# Add the buttons on the panel
+
+panel.add_element(pause_button, (0.25, 0.33))
+panel.add_element(start_button, (0.66, 0.33))
+
+
+

Define information relevant for each planet actor including its +texture name, relative position, and scale.

+
planets_data = [
+    {
+        'filename': '8k_mercury.jpg',
+        'position': 7,
+        'earth_days': 58,
+        'scale': (0.4, 0.4, 0.4),
+    },
+    {
+        'filename': '8k_venus_surface.jpg',
+        'position': 9,
+        'earth_days': 243,
+        'scale': (0.6, 0.6, 0.6),
+    },
+    {
+        'filename': '1_earth_8k.jpg',
+        'position': 11,
+        'earth_days': 1,
+        'scale': (0.4, 0.4, 0.4),
+    },
+    {
+        'filename': '8k_mars.jpg',
+        'position': 13,
+        'earth_days': 1,
+        'scale': (0.8, 0.8, 0.8),
+    },
+    {'filename': 'jupiter.jpg', 'position': 16, 'earth_days': 0.41, 'scale': (2, 2, 2)},
+    {
+        'filename': '8k_saturn.jpg',
+        'position': 19,
+        'earth_days': 0.45,
+        'scale': (2, 2, 2),
+    },
+    {
+        'filename': '8k_saturn_ring_alpha.png',
+        'position': 19,
+        'earth_days': 0.45,
+        'scale': (3, 0.5, 3),
+    },
+    {
+        'filename': '2k_uranus.jpg',
+        'position': 22,
+        'earth_days': 0.70,
+        'scale': (1, 1, 1),
+    },
+    {
+        'filename': '2k_neptune.jpg',
+        'position': 25,
+        'earth_days': 0.70,
+        'scale': (1, 1, 1),
+    },
+    {'filename': '8k_sun.jpg', 'position': 0, 'earth_days': 27, 'scale': (5, 5, 5)},
+]
+fetch_viz_textures()
+
+
+
Dataset is already in place. If you want to fetch it again please first remove the folder /Users/skoudoro/.fury/textures
+
+({'1_earth_8k.jpg': ('https://raw.githubusercontent.com/fury-gl/fury-data/master/textures/1_earth_8k.jpg', '0D66DC62768C43D763D3288CE67128AAED27715B11B0529162DC4117F710E26F'), '2_no_clouds_8k.jpg': ('https://raw.githubusercontent.com/fury-gl/fury-data/master/textures/2_no_clouds_8k.jpg', '5CF740C72287AF7B3ACCF080C3951944ADCB1617083B918537D08CBD9F2C5465'), '5_night_8k.jpg': ('https://raw.githubusercontent.com/fury-gl/fury-data/master/textures/5_night_8k.jpg', 'DF443F3E20C7724803690A350D9F6FDB36AD8EBC011B0345FB519A8B321F680A'), 'earth.ppm': ('https://raw.githubusercontent.com/fury-gl/fury-data/master/textures/earth.ppm', '34CE9AD183D7C7B11E2F682D7EBB84C803E661BE09E01ADB887175AE60C58156'), 'jupiter.jpg': ('https://raw.githubusercontent.com/fury-gl/fury-data/master/textures/jupiter.jpg', '5DF6A384E407BD0D5F18176B7DB96AAE1EEA3CFCFE570DDCE0D34B4F0E493668'), 'masonry.bmp': ('https://raw.githubusercontent.com/fury-gl/fury-data/master/textures/masonry.bmp', '045E30B2ABFEAE6318C2CF955040C4A37E6DE595ACE809CE6766D397C0EE205D'), 'moon-8k.jpg': ('https://raw.githubusercontent.com/fury-gl/fury-data/master/textures/moon_8k.jpg', '7397A6C2CE0348E148C66EBEFE078467DDB9D0370FF5E63434D0451477624839'), '8k_mercury.jpg': ('https://raw.githubusercontent.com/fury-gl/fury-data/master/textures/8k_mercury.jpg', '5C8BD885AE3571C6BA2CD34B3446B9C6D767E314BF0EE8C1D5C147CADD388FC3'), '8k_venus_surface.jpg': ('https://raw.githubusercontent.com/fury-gl/fury-data/master/textures/8k_venus_surface.jpg', '9BC21A50577ED8AC734CDA91058724C7A741C19427AA276224CE349351432C5B'), '8k_mars.jpg': ('https://raw.githubusercontent.com/fury-gl/fury-data/master/textures/8k_mars.jpg', '4CC52149924ABC6AE507D63032F994E1D42A55CB82C09E002D1A567FF66C23EE'), '8k_saturn.jpg': ('https://raw.githubusercontent.com/fury-gl/fury-data/master/textures/8k_saturn.jpg', '0D39A4A490C87C3EDABE00A3881A29BB3418364178C79C534FE0986E97E09853'), '8k_saturn_ring_alpha.png': ('https://raw.githubusercontent.com/fury-gl/fury-data/master/textures/8k_saturn_ring_alpha.png', 'F1F826933C9FF87D64ECF0518D6256B8ED990B003722794F67E96E3D2B876AE4'), '2k_uranus.jpg': ('https://raw.githubusercontent.com/fury-gl/fury-data/master/textures/2k_uranus.jpg', 'D15239D46F82D3EA13D2B260B5B29B2A382F42F2916DAE0694D0387B1204A09D'), '2k_neptune.jpg': ('https://raw.githubusercontent.com/fury-gl/fury-data/master/textures/2k_neptune.jpg', 'CB42EA82709741D28B0AF44D8B283CBC6DBD0C521A7F0E1E1E010ADE00977DF6'), '8k_sun.jpg': ('https://raw.githubusercontent.com/fury-gl/fury-data/master/textures/8k_sun.jpg', 'F22B1CFB306DDCE72A7E3B628668A0175B745038CE6268557CB2F7F1BDF98B9D'), '1_earth_16k.jpg': ('https://raw.githubusercontent.com/fury-gl/fury-data/master/textures/1_earth_16k.jpg', '7DD1DAC926101B5D7B7F2E952E53ACF209421B5CCE57C03168BCE0AAD675998A'), 'clouds.jpg': ('https://raw.githubusercontent.com/fury-gl/fury-data/master/textures/clouds.jpg', '85043336E023C4C9394CFD6D48D257A5564B4F895BFCEC01C70E4898CC77F003')}, '/Users/skoudoro/.fury/textures')
+
+
+

To take advantage of the previously defined data structure we are going to +create an auxiliary function that will load and apply the respective +texture, set its respective properties (relative position and scale), +and add the actor to a previously created scene.

+
def init_planet(planet_data):
+    """Initialize a planet actor.
+
+    Parameters
+    ----------
+    planet_data : dict
+        The planet_data is a dictionary, and the keys are filename(texture),
+        position and scale.
+
+    Returns
+    -------
+    planet_actor: actor
+        The corresponding sphere actor with texture applied.
+    """
+    planet_file = read_viz_textures(planet_data['filename'])
+    planet_image = io.load_image(planet_file)
+    planet_actor = actor.texture_on_sphere(planet_image)
+    planet_actor.SetPosition(planet_data['position'], 0, 0)
+    if planet_data['filename'] != '8k_saturn_ring_alpha.png':
+        utils.rotate(planet_actor, (90, 1, 0, 0))
+    planet_actor.SetScale(planet_data['scale'])
+    scene.add(planet_actor)
+    return planet_actor
+
+
+

Use the map function to create actors for each of the texture files +in the planet_files list. Then, assign each actor to its corresponding +actor in the list.

+
planet_actor_list = list(map(init_planet, planets_data))
+
+mercury_actor = planet_actor_list[0]
+venus_actor = planet_actor_list[1]
+earth_actor = planet_actor_list[2]
+mars_actor = planet_actor_list[3]
+jupiter_actor = planet_actor_list[4]
+saturn_actor = planet_actor_list[5]
+saturn_rings_actor = planet_actor_list[6]
+uranus_actor = planet_actor_list[7]
+neptune_actor = planet_actor_list[8]
+sun_actor = planet_actor_list[9]
+
+
+

Define the gravitational constant G, the orbital radii of each of the +planets, and the central mass of the sun. The gravity and mass will be +used to calculate the orbital position, so multiply these two together to +create a new constant, which we will call miu.

+
g_exponent = np.float_power(10, -11)
+g_constant = 6.673 * g_exponent
+
+m_exponent = 1073741824   # np.power(10, 30)
+m_constant = 1.989 * m_exponent
+
+miu = m_constant * g_constant
+
+
+

Let’s define two functions that will help us calculate the position of each +planet as it orbits around the sun: get_orbit_period and +get_orbital_position, using the constant miu and the orbital radii +of each planet.

+
def get_orbit_period(radius):
+    return 2 * np.pi * np.sqrt(np.power(radius, 3) / miu)
+
+
+def get_orbital_position(radius, time):
+    orbit_period = get_orbit_period(radius)
+    x = radius * np.cos((-2 * np.pi * time) / orbit_period)
+    y = radius * np.sin((-2 * np.pi * time) / orbit_period)
+    return x, y
+
+
+

Let’s define a function to rotate the planet actor axially, we’ll be defining +axis of each planet and angle by which it should be rotated using +rotate_axial funtction

+
def rotate_axial(actor, time, radius):
+    axis = (0, radius, 0)
+    angle = 50 / time
+    utils.rotate(actor, (angle, axis[0], axis[1], axis[2]))
+    return angle
+
+
+

Let’s change the camera position to visualize the planets better.

+
scene.set_camera(position=(-20, 60, 100))
+
+
+

Next, create a ShowManager object. The ShowManager class is the interface +between the scene, the window and the interactor.

+
showm = window.ShowManager(
+    scene, size=(900, 768), reset_camera=False, order_transparent=True
+)
+scene.add(panel)
+
+
+

Next, let’s focus on creating the animation. +We can determine the duration of animation with using the counter. +Use itertools to avoid global variables.

+ +

Define one new function to use in timer_callback to update the planet +positions update_planet_position.

+
def update_planet_position(r_planet, planet_actor, cnt):
+    pos_planet = get_orbital_position(r_planet, cnt)
+    planet_actor.SetPosition(pos_planet[0], 0, pos_planet[1])
+    return pos_planet
+
+
+

calculate_path function is for calculating the path/orbit +of every planet.

+
def calculate_path(r_planet, c):
+    planet_track = [
+        [get_orbital_position(r_planet, i)[0], 0, get_orbital_position(r_planet, i)[1]]
+        for i in range(c)
+    ]
+    return planet_track
+
+
+

First we are making a list that will contain radius from planets_data. +Here we are not taking the radius of orbit/path for sun and saturn ring. +planet_actors will contain all the planet actors. +r_times will contain time taken (in days) by the planets to rotate +around itself.

+
r_planets = [
+    p_data['position']
+    for p_data in planets_data
+    if 'sun' not in p_data['filename']
+    if 'saturn_ring' not in p_data['filename']
+]
+
+planet_actors = [
+    mercury_actor,
+    venus_actor,
+    earth_actor,
+    mars_actor,
+    jupiter_actor,
+    saturn_actor,
+    uranus_actor,
+    neptune_actor,
+]
+
+
+sun_data = {
+    'actor': sun_actor,
+    'position': planets_data[9]['position'],
+    'earth_days': planets_data[9]['earth_days'],
+}
+
+r_times = [p_data['earth_days'] for p_data in planets_data]
+
+
+

Here we are calculating and updating the path/orbit before animation starts.

+
planet_tracks = [calculate_path(rplanet, rplanet * 85) for rplanet in r_planets]
+
+
+

This is for orbit visualization. We are using line actor for orbits. +After creating an actor we add it to the scene.

+
orbit_actor = actor.line(planet_tracks, colors=(1, 1, 1), linewidth=0.1)
+scene.add(orbit_actor)
+
+
+

Define the timer_callback function, which controls what events happen +at certain times, using the counter. Update the position of each planet +actor using update_planet_position, assigning the x and y values of +each planet’s position with the newly calculated ones.

+
def timer_callback(_obj, _event):
+    cnt = next(counter)
+    showm.render()
+
+    # Rotating the sun actor
+    rotate_axial(sun_actor, sun_data['earth_days'], 1)
+
+    for r_planet, p_actor, r_time in zip(r_planets, planet_actors, r_times):
+        # if the planet is saturn then we also need to update the position
+        # of its rings.
+        if p_actor == saturn_actor:
+            pos_saturn = update_planet_position(19, saturn_actor, cnt)
+            saturn_rings_actor.SetPosition(pos_saturn[0], 0, pos_saturn[1])
+        else:
+            update_planet_position(r_planet, p_actor, cnt)
+        rotate_axial(p_actor, r_time, r_planet)
+
+    if cnt == 2000:
+        showm.exit()
+
+
+

We add a callback to each button to perform some action.

+
def start_animation(i_ren, _obj, _button):
+    showm.add_timer_callback(True, 10, timer_callback)
+
+
+def pause_animation(i_ren, _obj, _button):
+    showm.destroy_timers()
+
+
+start_button.on_left_mouse_button_clicked = start_animation
+pause_button.on_left_mouse_button_clicked = pause_animation
+
+
+

Watch the planets orbit the sun in your new animation!

+
showm.add_timer_callback(True, 10, timer_callback)
+showm.start()
+
+window.record(showm.scene, size=(900, 768), out_path='viz_solar_system_animation.png')
+
+
+viz solar system

Total running time of the script: (0 minutes 31.865 seconds)

+ +

Gallery generated by Sphinx-Gallery

+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/auto_examples/01_introductory/viz_sphere.html b/v0.10.x/auto_examples/01_introductory/viz_sphere.html new file mode 100644 index 000000000..8ae188aa7 --- /dev/null +++ b/v0.10.x/auto_examples/01_introductory/viz_sphere.html @@ -0,0 +1,544 @@ + + + + + + + + FURY sphere Actor — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +
+

FURY sphere Actor#

+

This example shows how to use both primitive and vtkSource sphere actor.

+
import numpy as np
+
+from fury import actor, window
+
+
+

First thing, you have to specify centers and colors of the sphere

+
centers = np.zeros([1, 3])
+colors = np.array([0, 0, 1])
+
+
+

The below sphere actor is generated by repeating the sphere primitive.

+
prim_sphere_actor = actor.sphere(centers, colors=colors, radii=5)
+
+
+

This time, we’re using vtkSphereSource to generate the sphere actor

+
cen2 = np.add(centers, np.array([12, 0, 0]))
+cols2 = np.array([1, 0, 0])
+
+vtk_sphere_actor = actor.sphere(cen2, colors=cols2, radii=5, use_primitive=False)
+
+scene = window.Scene()
+
+
+

Adding our sphere actors to scene.

+
scene.add(prim_sphere_actor)
+scene.add(vtk_sphere_actor)
+
+interactive = False
+
+if interactive:
+    window.show(scene, size=(600, 600))
+
+window.record(scene, out_path='viz_sphere.png', size=(600, 600))
+
+
+viz sphere

Total running time of the script: (0 minutes 0.067 seconds)

+ +

Gallery generated by Sphinx-Gallery

+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/auto_examples/01_introductory/viz_spiky.html b/v0.10.x/auto_examples/01_introductory/viz_spiky.html new file mode 100644 index 000000000..fd431d315 --- /dev/null +++ b/v0.10.x/auto_examples/01_introductory/viz_spiky.html @@ -0,0 +1,606 @@ + + + + + + + + Spiky Sphere — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +
+

Spiky Sphere#

+

In this tutorial, we show how to create a sphere with spikes.

+
import itertools
+
+import numpy as np
+
+from fury import actor, primitive, utils, window
+
+
+

Create a sphere actor. Define the center, radius and color of a sphere. +The sphere actor is made of points (vertices) evenly distributed on a +sphere. +Let’s create a scene.

+ +

The vertices are connected with triangles in order to specify the direction +of the surface normal. +prim_sphere provides a sphere with evenly distributed points

+
vertices, triangles = primitive.prim_sphere(name='symmetric362', gen_faces=False)
+
+
+

To be able to visualize the vertices, let’s define a point actor with +green color.

+
point_actor = actor.point(vertices, point_radius=0.01, colors=(0, 1, 0))
+
+
+

Normals are the vectors that are perpendicular to the surface at each +vertex. We specify the normals at the vertices to tell the system +whether triangles represent curved surfaces.

+ +

The normals are usually used to calculate how the light will bounce on +the surface of an object. However, here we will use them to direct the +spikes (represented with arrows). +So, let’s create an arrow actor at the center of each vertex.

+
arrow_actor = actor.arrow(
+    centers=vertices,
+    directions=normals,
+    colors=(1, 0, 0),
+    heights=0.2,
+    resolution=10,
+    vertices=None,
+    faces=None,
+)
+
+
+

To be able to visualize the surface of the primitive sphere, we use +get_actor_from_primitive.

+ +

We add all actors (visual objects) defined above to the scene.

+
scene.add(point_actor)
+scene.add(arrow_actor)
+scene.add(primitive_actor)
+scene.add(actor.axes())
+
+
+

The ShowManager class is the interface between the scene, the window and the +interactor.

+
showm = window.ShowManager(
+    scene, size=(900, 768), reset_camera=False, order_transparent=True
+)
+
+
+

We want to make a small animation for fun! +We can determine the duration of animation with using the counter. +Use itertools to avoid global variables.

+ +

The timer will call this user defined callback every 200 milliseconds. The +application will exit after the callback has been called 20 times.

+
def timer_callback(_obj, _event):
+    cnt = next(counter)
+    showm.scene.azimuth(0.05 * cnt)
+    primitive_actor.GetProperty().SetOpacity(cnt / 10.0)
+    showm.render()
+    if cnt == 20:
+        showm.exit()
+
+
+showm.add_timer_callback(True, 200, timer_callback)
+showm.start()
+window.record(showm.scene, size=(900, 768), out_path='viz_spiky.png')
+
+
+viz spiky

Instead of arrows, you can choose other geometrical objects +such as cones, cubes or spheres.

+

Total running time of the script: (0 minutes 4.349 seconds)

+ +

Gallery generated by Sphinx-Gallery

+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/auto_examples/01_introductory/viz_surfaces.html b/v0.10.x/auto_examples/01_introductory/viz_surfaces.html new file mode 100644 index 000000000..29cd7a41a --- /dev/null +++ b/v0.10.x/auto_examples/01_introductory/viz_surfaces.html @@ -0,0 +1,615 @@ + + + + + + + + Visualize surfaces — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +
+

Visualize surfaces#

+

Here is a simple tutorial that shows how to visualize surfaces using DIPY. It +also shows how to load/save, get/set and update PolyData and show +surfaces.

+

PolyData is a structure used by VTK to represent surfaces and other data +structures. Here we show how to visualize a simple cube but the same idea +should apply for any surface.

+
import numpy as np
+
+from fury import utils, window
+from fury.io import load_polydata, save_polydata
+from fury.lib import PolyData
+
+
+

Import useful functions

+

Create an empty PolyData

+
my_polydata = PolyData()
+
+
+

Create a cube with vertices and triangles as numpy arrays

+
my_vertices = np.array(
+    [
+        [0.0, 0.0, 0.0],
+        [0.0, 0.0, 1.0],
+        [0.0, 1.0, 0.0],
+        [0.0, 1.0, 1.0],
+        [1.0, 0.0, 0.0],
+        [1.0, 0.0, 1.0],
+        [1.0, 1.0, 0.0],
+        [1.0, 1.0, 1.0],
+    ]
+)
+# the data type is needed to mention here, numpy.int64
+my_triangles = np.array(
+    [
+        [0, 6, 4],
+        [0, 2, 6],
+        [0, 3, 2],
+        [0, 1, 3],
+        [2, 7, 6],
+        [2, 3, 7],
+        [4, 6, 7],
+        [4, 7, 5],
+        [0, 4, 5],
+        [0, 5, 1],
+        [1, 5, 7],
+        [1, 7, 3],
+    ],
+    dtype='i8',
+)
+
+
+

Set vertices and triangles in the PolyData

+ +
<vtkmodules.vtkCommonDataModel.vtkPolyData(0x2a2cf7340) at 0x13816ca00>
+
+
+

Save the PolyData

+
file_name = 'my_cube.vtk'
+save_polydata(my_polydata, file_name)
+print('Surface saved in ' + file_name)
+
+
+
Surface saved in my_cube.vtk
+
+
+

Load the PolyData

+
cube_polydata = load_polydata(file_name)
+
+
+

add color based on vertices position

+
cube_vertices = utils.get_polydata_vertices(cube_polydata)
+colors = cube_vertices * 255
+utils.set_polydata_colors(cube_polydata, colors)
+
+print('new surface colors')
+print(utils.get_polydata_colors(cube_polydata))
+
+
+
new surface colors
+[[  0   0   0]
+ [  0   0 255]
+ [  0 255   0]
+ [  0 255 255]
+ [255   0   0]
+ [255   0 255]
+ [255 255   0]
+ [255 255 255]]
+
+
+

Visualize surfaces

+
# get Actor
+cube_actor = utils.get_actor_from_polydata(cube_polydata)
+
+# Create a scene
+scene = window.Scene()
+scene.add(cube_actor)
+scene.set_camera(position=(10, 5, 7), focal_point=(0.5, 0.5, 0.5))
+scene.zoom(3)
+
+# display
+# window.show(scene, size=(600, 600), reset_camera=False)
+window.record(scene, out_path='cube.png', size=(600, 600))
+
+
+viz surfaces

Total running time of the script: (0 minutes 0.064 seconds)

+ +

Gallery generated by Sphinx-Gallery

+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/auto_examples/01_introductory/viz_texture.html b/v0.10.x/auto_examples/01_introductory/viz_texture.html new file mode 100644 index 000000000..e5482059c --- /dev/null +++ b/v0.10.x/auto_examples/01_introductory/viz_texture.html @@ -0,0 +1,544 @@ + + + + + + + + Sphere Texture — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +
+

Sphere Texture#

+

In this tutorial, we will show how to create a sphere with a texture.

+
from fury import actor, io, window
+from fury.data import fetch_viz_textures, read_viz_textures
+
+
+

Create a scene to start.

+ +

Load an image (png, bmp, jpeg or jpg) using io.load_image. In this +example, we will use read_viz_textures to access an image of the +Earth’s surface from the fury Github after using ‘’fetch_viz_textures()’’ +to download the available textures.

+
fetch_viz_textures()
+filename = read_viz_textures('1_earth_8k.jpg')
+image = io.load_image(filename)
+
+
+
Dataset is already in place. If you want to fetch it again please first remove the folder /Users/skoudoro/.fury/textures
+
+
+

Next, use actor.texture_on_sphere to add a sphere with the texture from +your loaded image to the already existing scene. +To add a texture to your scene as visualized on a plane, use +actor.texture instead.

+ +

Lastly, record the scene, or set interactive to True if you would like to +manipulate your new sphere.

+
interactive = False
+if interactive:
+    window.show(scene, size=(600, 600), reset_camera=False)
+window.record(scene, size=(900, 768), out_path='viz_texture.png')
+
+
+viz texture

Total running time of the script: (0 minutes 1.470 seconds)

+ +

Gallery generated by Sphinx-Gallery

+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/auto_examples/01_introductory/viz_timers.html b/v0.10.x/auto_examples/01_introductory/viz_timers.html new file mode 100644 index 000000000..c63695611 --- /dev/null +++ b/v0.10.x/auto_examples/01_introductory/viz_timers.html @@ -0,0 +1,570 @@ + + + + + + + + Using a timer — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +
+

Using a timer#

+

This example shows how to create a simple animation using a timer callback.

+

We will use a sphere actor that generates many spheres of different colors, +radii and opacity. Then we will animate this actor by rotating and changing +global opacity levels from inside a user defined callback.

+

The timer will call this user defined callback every 200 milliseconds. The +application will exit after the callback has been called 100 times.

+viz timers
import itertools
+
+import numpy as np
+
+from fury import actor, ui, window
+
+xyz = 10 * np.random.rand(100, 3)
+colors = np.random.rand(100, 4)
+radii = np.random.rand(100) + 0.5
+
+scene = window.Scene()
+
+sphere_actor = actor.sphere(centers=xyz, colors=colors, radii=radii)
+
+scene.add(sphere_actor)
+
+showm = window.ShowManager(
+    scene, size=(900, 768), reset_camera=False, order_transparent=True
+)
+
+
+tb = ui.TextBlock2D(bold=True)
+
+# use itertools to avoid global variables
+counter = itertools.count()
+
+
+def timer_callback(_obj, _event):
+    global timer_id
+    cnt = next(counter)
+    tb.message = "Let's count up to 300 and exit :" + str(cnt)
+    showm.scene.azimuth(0.05 * cnt)
+    sphere_actor.GetProperty().SetOpacity(cnt / 100.0)
+    showm.render()
+
+    if cnt == 10:
+        # destroy the first timer and replace it with another faster timer
+        showm.destroy_timer(timer_id)
+        timer_id = showm.add_timer_callback(True, 10, timer_callback)
+
+    if cnt == 300:
+        # destroy the second timer and exit
+        showm.destroy_timer(timer_id)
+        showm.exit()
+
+
+scene.add(tb)
+
+# Run every 200 milliseconds
+timer_id = showm.add_timer_callback(True, 200, timer_callback)
+
+showm.start()
+
+window.record(showm.scene, size=(900, 768), out_path='viz_timer.png')
+
+
+

Total running time of the script: (0 minutes 5.984 seconds)

+ +

Gallery generated by Sphinx-Gallery

+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/auto_examples/04_demos/collision-particles.html b/v0.10.x/auto_examples/04_demos/collision-particles.html new file mode 100644 index 000000000..cc4f08744 --- /dev/null +++ b/v0.10.x/auto_examples/04_demos/collision-particles.html @@ -0,0 +1,674 @@ + + + + + + + + Collisions of particles in a box — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +
+

Collisions of particles in a box#

+

This is a simple demonstration of how you can simulate moving +particles in a box using FURY.

+

In this example, the particles collide with each other and with the walls +of the container. When the collision happens between two particles, +the particle with less velocity changes its color and gets the same color +as the particle with higher velocity. For simplicity, in this demo we +do not apply forces.

+
import itertools
+
+import numpy as np
+
+from fury import actor, ui, utils, window
+
+
+

Here, we define the edges of the box.

+
def box_edges(box_lx, box_ly, box_lz):
+
+    edge1 = 0.5 * np.array(
+        [
+            [box_lx, box_ly, box_lz],
+            [box_lx, box_ly, -box_lz],
+            [-box_lx, box_ly, -box_lz],
+            [-box_lx, box_ly, box_lz],
+            [box_lx, box_ly, box_lz],
+        ]
+    )
+    edge2 = 0.5 * np.array([[box_lx, box_ly, box_lz], [box_lx, -box_ly, box_lz]])
+    edge3 = 0.5 * np.array([[box_lx, box_ly, -box_lz], [box_lx, -box_ly, -box_lz]])
+    edge4 = 0.5 * np.array([[-box_lx, box_ly, -box_lz], [-box_lx, -box_ly, -box_lz]])
+    edge5 = 0.5 * np.array([[-box_lx, box_ly, box_lz], [-box_lx, -box_ly, box_lz]])
+    lines = [edge1, -edge1, edge2, edge3, edge4, edge5]
+    return lines
+
+
+

Here we define collision between walls-particles and particle-particle. +When collision happens, the particle with lower velocity gets the +color of the particle with higher velocity

+
def collision():
+    global xyz
+    num_vertices = vertices.shape[0]
+    sec = int(num_vertices / num_particles)
+
+    for i, j in np.ndindex(num_particles, num_particles):
+
+        if i == j:
+            continue
+        distance = np.linalg.norm(xyz[i] - xyz[j])
+        vel_mag_i = np.linalg.norm(vel[i])
+        vel_mag_j = np.linalg.norm(vel[j])
+        # Collision happens if the distance between the centers of two
+        # particles is less or equal to the sum of their radii
+        if distance <= (radii[i] + radii[j]):
+            vel[i] = -vel[i]
+            vel[j] = -vel[j]
+            if vel_mag_j > vel_mag_i:
+                vcolors[i * sec : i * sec + sec] = vcolors[j * sec : j * sec + sec]
+            if vel_mag_i > vel_mag_j:
+                vcolors[j * sec : j * sec + sec] = vcolors[i * sec : i * sec + sec]
+            xyz[i] = xyz[i] + vel[i] * dt
+            xyz[j] = xyz[j] + vel[j] * dt
+    # Collision between particles-walls;
+    vel[:, 0] = np.where(
+        (
+            (xyz[:, 0] <= -0.5 * box_lx + radii[:])
+            | (xyz[:, 0] >= (0.5 * box_lx - radii[:]))
+        ),
+        -vel[:, 0],
+        vel[:, 0],
+    )
+    vel[:, 1] = np.where(
+        (
+            (xyz[:, 1] <= -0.5 * box_ly + radii[:])
+            | (xyz[:, 1] >= (0.5 * box_ly - radii[:]))
+        ),
+        -vel[:, 1],
+        vel[:, 1],
+    )
+    vel[:, 2] = np.where(
+        (
+            (xyz[:, 2] <= -0.5 * box_lz + radii[:])
+            | (xyz[:, 2] >= (0.5 * box_lz - radii[:]))
+        ),
+        -vel[:, 2],
+        vel[:, 2],
+    )
+
+
+

We define position, velocity, color and radius randomly for 50 particles +inside the box.

+
global xyz
+num_particles = 50
+box_lx = 20
+box_ly = 20
+box_lz = 10
+steps = 1000
+dt = 0.05
+xyz = (
+    np.array([box_lx, box_ly, box_lz]) * (np.random.rand(num_particles, 3) - 0.5) * 0.6
+)
+vel = 4 * (np.random.rand(num_particles, 3) - 0.5)
+colors = np.random.rand(num_particles, 3)
+radii = np.random.rand(num_particles) + 0.01
+
+
+

With box, streamtube and sphere actors, we can create the box, the +edges of the box and the spheres respectively.

+
scene = window.Scene()
+box_centers = np.array([[0, 0, 0]])
+box_directions = np.array([[0, 1, 0]])
+box_colors = np.array([[1, 1, 1, 0.2]])
+box_actor = actor.box(
+    box_centers, box_directions, box_colors, scales=(box_lx, box_ly, box_lz)
+)
+scene.add(box_actor)
+
+lines = box_edges(box_lx, box_ly, box_lz)
+line_actor = actor.streamtube(lines, colors=(1, 0.5, 0), linewidth=0.1)
+scene.add(line_actor)
+
+sphere_actor = actor.sphere(centers=xyz, colors=colors, radii=radii)
+scene.add(sphere_actor)
+
+showm = window.ShowManager(
+    scene, size=(900, 768), reset_camera=True, order_transparent=True
+)
+
+tb = ui.TextBlock2D(bold=True)
+scene.zoom(0.8)
+scene.azimuth(30)
+
+# use itertools to avoid global variables
+counter = itertools.count()
+
+vertices = utils.vertices_from_actor(sphere_actor)
+vcolors = utils.colors_from_actor(sphere_actor, 'colors')
+no_vertices_per_sphere = len(vertices) / num_particles
+initial_vertices = vertices.copy() - np.repeat(xyz, no_vertices_per_sphere, axis=0)
+
+
+def timer_callback(_obj, _event):
+    global xyz
+    cnt = next(counter)
+    tb.message = "Let's count up to 1000 and exit :" + str(cnt)
+    xyz = xyz + vel * dt
+    collision()
+
+    vertices[:] = initial_vertices + np.repeat(xyz, no_vertices_per_sphere, axis=0)
+    utils.update_actor(sphere_actor)
+
+    scene.reset_clipping_range()
+    showm.render()
+
+    if cnt == steps:
+        showm.exit()
+
+
+scene.add(tb)
+showm.add_timer_callback(True, 50, timer_callback)
+
+interactive = False
+if interactive:
+    showm.start()
+
+window.record(showm.scene, size=(900, 768), out_path='simple_collisions.png')
+
+
+collision particles

Total running time of the script: (0 minutes 0.128 seconds)

+ +

Gallery generated by Sphinx-Gallery

+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/auto_examples/04_demos/index.html b/v0.10.x/auto_examples/04_demos/index.html new file mode 100644 index 000000000..b2958860b --- /dev/null +++ b/v0.10.x/auto_examples/04_demos/index.html @@ -0,0 +1,550 @@ + + + + + + + + Demos — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Demos#

+

Below is a gallery of Demos. A bunch of apps powered by FURY.

+
+

Fury Markers

+
Fury Markers
+
+

Visualize Interdisciplinary map of the journals network

+
Visualize Interdisciplinary map of the journals network
+
+

Visualization of ROI Surface Rendered with Streamlines

+
Visualization of ROI Surface Rendered with Streamlines
+
+

Motion of a charged particle in a combined magnetic and electric field

+
Motion of a charged particle in a combined magnetic and electric field
+
+

Brownian motion

+
Brownian motion
+
+

Play a video in the 3D world

+
Play a video in the 3D world
+
+

Fine-tuning the OpenGL state using shader callbacks

+
Fine-tuning the OpenGL state using shader callbacks
+
+

Electromagnetic Wave Propagation Animation

+
Electromagnetic Wave Propagation Animation
+
+

Animated 2D functions

+
Animated 2D functions
+
+

Visualize bundles and metrics on bundles

+
Visualize bundles and metrics on bundles
+
+

Tesseract (Hypercube)

+
Tesseract (Hypercube)
+
+

Collisions of particles in a box

+
Collisions of particles in a box
+
+

Advanced interactive visualization

+
Advanced interactive visualization
+
+

Brain Fiber ODF Visualisation

+
Brain Fiber ODF Visualisation
+
+

Fractals

+
Fractals
+
+

Visualize Networks (Animated version)

+
Visualize Networks (Animated version)
+
+

Display Tensor Ellipsoids for DTI using tensor_slicer vs ellipsoid actor

+
Display Tensor Ellipsoids for DTI using tensor_slicer vs ellipsoid actor
+
+

Interactive PBR demo

+
Interactive PBR demo
+
+
+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/auto_examples/04_demos/sg_execution_times.html b/v0.10.x/auto_examples/04_demos/sg_execution_times.html new file mode 100644 index 000000000..13774791f --- /dev/null +++ b/v0.10.x/auto_examples/04_demos/sg_execution_times.html @@ -0,0 +1,564 @@ + + + + + + + + Computation times — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Computation times#

+

00:16.543 total execution time for 18 files from auto_examples/04_demos:

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Example

Time

Mem (MB)

Display Tensor Ellipsoids for DTI using tensor_slicer vs ellipsoid actor (viz_dt_ellipsoids.py)

00:08.555

0.0

Visualize Networks (Animated version) (viz_network_animated.py)

00:07.015

0.0

Interactive PBR demo (viz_pbr_interactive.py)

00:00.974

0.0

Collisions of particles in a box (collision-particles.py)

00:00.000

0.0

Advanced interactive visualization (viz_advanced.py)

00:00.000

0.0

Animated 2D functions (viz_animated_surfaces.py)

00:00.000

0.0

Brownian motion (viz_brownian_motion.py)

00:00.000

0.0

Visualize bundles and metrics on bundles (viz_bundles.py)

00:00.000

0.0

Electromagnetic Wave Propagation Animation (viz_emwave_animation.py)

00:00.000

0.0

Brain Fiber ODF Visualisation (viz_fiber_odf.py)

00:00.000

0.0

Fine-tuning the OpenGL state using shader callbacks (viz_fine_tuning_gl_context.py)

00:00.000

0.0

Fractals (viz_fractals.py)

00:00.000

0.0

Motion of a charged particle in a combined magnetic and electric field (viz_helical_motion.py)

00:00.000

0.0

Fury Markers (viz_markers.py)

00:00.000

0.0

Visualize Interdisciplinary map of the journals network (viz_network.py)

00:00.000

0.0

Play a video in the 3D world (viz_play_video.py)

00:00.000

0.0

Visualization of ROI Surface Rendered with Streamlines (viz_roi_contour.py)

00:00.000

0.0

Tesseract (Hypercube) (viz_tesseract.py)

00:00.000

0.0

+
+
+ +
+ + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/auto_examples/04_demos/viz_advanced.html b/v0.10.x/auto_examples/04_demos/viz_advanced.html new file mode 100644 index 000000000..e95513eae --- /dev/null +++ b/v0.10.x/auto_examples/04_demos/viz_advanced.html @@ -0,0 +1,755 @@ + + + + + + + + Advanced interactive visualization — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +
+

Advanced interactive visualization#

+

In DIPY we created a thin interface to access many of the capabilities +available in the Visualization Toolkit framework (VTK) but tailored to the +needs of structural and diffusion imaging. Initially the 3D visualization +module was named fvtk, meaning functions using vtk. This is still available +for backwards compatibility but now there is a more comprehensive way to access +the main functions using the following modules.

+
import numpy as np
+from dipy.data.fetcher import fetch_bundles_2_subjects, read_bundles_2_subjects
+
+
+

In window we have all the objects that connect what needs to be rendered +to the display or the disk e.g., for saving screenshots. So, there you will +find key objects and functions like the Scene class which holds and +provides access to all the actors and the show function which displays +what is in the scene on a window. Also, this module provides access to +functions for opening/saving dialogs and printing screenshots +(see snapshot).

+

In the actor module we can find all the different primitives e.g., +streamtubes, lines, image slices, etc.

+

In the ui module we have some other objects which allow to add buttons +and sliders and these interact both with windows and actors. Because of this +they need input from the operating system so they can process events.

+

Let’s get started. In this tutorial, we will visualize some bundles +together with FA or T1. We will be able to change the slices using +a LineSlider2D widget.

+

First we need to fetch and load some datasets.

+
from dipy.tracking.streamline import Streamlines
+
+from fury import actor, ui, window
+
+fetch_bundles_2_subjects()
+
+
+
({'bundles_2_subjects.tar.gz': ('https://digital.lib.washington.edu/researchworks/bitstream/handle/1773/38477/bundles_2_subjects.tar.gz', '97756fbef11ce2df31f1bedf1fc7aac7')}, '/Users/skoudoro/.dipy/exp_bundles_and_maps')
+
+
+

The following function outputs a dictionary with the required bundles e.g. +af left (left arcuate fasciculus) and maps, e.g. FA for a specific +subject.

+
res = read_bundles_2_subjects('subj_1', ['t1', 'fa'], ['af.left', 'cst.right', 'cc_1'])
+
+
+

We will use 3 bundles, FA and the affine transformation that brings the voxel +coordinates to world coordinates (RAS 1mm).

+
streamlines = Streamlines(res['af.left'])
+streamlines.extend(res['cst.right'])
+streamlines.extend(res['cc_1'])
+
+data = res['fa']
+shape = data.shape
+affine = res['affine']
+
+
+

With our current design it is easy to decide in which space you want the +streamlines and slices to appear. The default we have here is to appear in +world coordinates (RAS 1mm).

+
world_coords = True
+
+
+

If we want to see the objects in native space we need to make sure that all +objects which are currently in world coordinates are transformed back to +native space using the inverse of the affine.

+
if not world_coords:
+    from dipy.tracking.streamline import transform_streamlines
+
+    streamlines = transform_streamlines(streamlines, np.linalg.inv(affine))
+
+
+

Now we create, a Scene object and add the streamlines using the +line function and an image plane using the slice function.

+
scene = window.Scene()
+stream_actor = actor.line(streamlines)
+
+if not world_coords:
+    image_actor_z = actor.slicer(data, affine=np.eye(4))
+else:
+    image_actor_z = actor.slicer(data, affine)
+
+
+

We can also change also the opacity of the slicer.

+
slicer_opacity = 0.6
+image_actor_z.opacity(slicer_opacity)
+
+
+

We can add additional slicers by copying the original and adjusting the +display_extent.

+
image_actor_x = image_actor_z.copy()
+x_midpoint = int(np.round(shape[0] / 2))
+image_actor_x.display_extent(x_midpoint, x_midpoint, 0, shape[1] - 1, 0, shape[2] - 1)
+
+image_actor_y = image_actor_z.copy()
+y_midpoint = int(np.round(shape[1] / 2))
+image_actor_y.display_extent(0, shape[0] - 1, y_midpoint, y_midpoint, 0, shape[2] - 1)
+
+
+

Connect the actors with the Scene.

+
scene.add(stream_actor)
+scene.add(image_actor_z)
+scene.add(image_actor_x)
+scene.add(image_actor_y)
+
+
+

Now we would like to change the position of each image_actor using a +slider. The sliders are widgets which require access to different areas of +the visualization pipeline and therefore we don’t recommend using them with +show. The more appropriate way is to use them with the ShowManager +object which allows accessing the pipeline in different areas. Here is how:

+
show_m = window.ShowManager(scene, size=(1200, 900))
+
+
+

After we have initialized the ShowManager we can go ahead and create +sliders to move the slices and change their opacity.

+
line_slider_z = ui.LineSlider2D(
+    min_value=0,
+    max_value=shape[2] - 1,
+    initial_value=shape[2] / 2,
+    text_template='{value:.0f}',
+    length=140,
+)
+
+line_slider_x = ui.LineSlider2D(
+    min_value=0,
+    max_value=shape[0] - 1,
+    initial_value=shape[0] / 2,
+    text_template='{value:.0f}',
+    length=140,
+)
+
+line_slider_y = ui.LineSlider2D(
+    min_value=0,
+    max_value=shape[1] - 1,
+    initial_value=shape[1] / 2,
+    text_template='{value:.0f}',
+    length=140,
+)
+
+opacity_slider = ui.LineSlider2D(
+    min_value=0.0, max_value=1.0, initial_value=slicer_opacity, length=140
+)
+
+
+

Now we will write callbacks for the sliders and register them.

+
def change_slice_z(slider):
+    z = int(np.round(slider.value))
+    image_actor_z.display_extent(0, shape[0] - 1, 0, shape[1] - 1, z, z)
+
+
+def change_slice_x(slider):
+    x = int(np.round(slider.value))
+    image_actor_x.display_extent(x, x, 0, shape[1] - 1, 0, shape[2] - 1)
+
+
+def change_slice_y(slider):
+    y = int(np.round(slider.value))
+    image_actor_y.display_extent(0, shape[0] - 1, y, y, 0, shape[2] - 1)
+
+
+def change_opacity(slider):
+    slicer_opacity = slider.value
+    image_actor_z.opacity(slicer_opacity)
+    image_actor_x.opacity(slicer_opacity)
+    image_actor_y.opacity(slicer_opacity)
+
+
+line_slider_z.on_change = change_slice_z
+line_slider_x.on_change = change_slice_x
+line_slider_y.on_change = change_slice_y
+opacity_slider.on_change = change_opacity
+
+
+

We’ll also create text labels to identify the sliders.

+
def build_label(text):
+    label = ui.TextBlock2D()
+    label.message = text
+    label.font_size = 18
+    label.font_family = 'Arial'
+    label.justification = 'left'
+    label.bold = False
+    label.italic = False
+    label.shadow = False
+    label.background_color = (0, 0, 0)
+    label.color = (1, 1, 1)
+
+    return label
+
+
+line_slider_label_z = build_label(text='Z Slice')
+line_slider_label_x = build_label(text='X Slice')
+line_slider_label_y = build_label(text='Y Slice')
+opacity_slider_label = build_label(text='Opacity')
+
+
+

Now we will create a panel to contain the sliders and labels.

+
panel = ui.Panel2D(size=(300, 200), color=(1, 1, 1), opacity=0.1, align='right')
+panel.center = (1030, 120)
+
+panel.add_element(line_slider_label_x, (0.1, 0.75))
+panel.add_element(line_slider_x, (0.38, 0.75))
+panel.add_element(line_slider_label_y, (0.1, 0.55))
+panel.add_element(line_slider_y, (0.38, 0.55))
+panel.add_element(line_slider_label_z, (0.1, 0.35))
+panel.add_element(line_slider_z, (0.38, 0.35))
+panel.add_element(opacity_slider_label, (0.1, 0.15))
+panel.add_element(opacity_slider, (0.38, 0.15))
+
+show_m.scene.add(panel)
+
+
+

Then, we can render all the widgets and everything else in the screen and +start the interaction using show_m.start().

+

However, if you change the window size, the panel will not update its +position properly. The solution to this issue is to update the position of +the panel using its re_align method every time the window size changes.

+
size = scene.GetSize()
+
+
+def win_callback(obj, _event):
+    global size
+    if size != obj.GetSize():
+        size_old = size
+        size = obj.GetSize()
+        size_change = [size[0] - size_old[0], 0]
+        panel.re_align(size_change)
+
+
+

Finally, please set the following variable to True to interact with the +datasets in 3D.

+
interactive = False
+
+scene.zoom(1.5)
+scene.reset_clipping_range()
+
+if interactive:
+
+    show_m.add_window_callback(win_callback)
+    show_m.render()
+    show_m.start()
+
+else:
+
+    window.record(
+        scene, out_path='bundles_and_3_slices.png', size=(1200, 900), reset_camera=False
+    )
+
+del show_m
+
+
+viz advanced

Total running time of the script: (0 minutes 2.302 seconds)

+ +

Gallery generated by Sphinx-Gallery

+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/auto_examples/04_demos/viz_animated_surfaces.html b/v0.10.x/auto_examples/04_demos/viz_animated_surfaces.html new file mode 100644 index 000000000..5a83092f3 --- /dev/null +++ b/v0.10.x/auto_examples/04_demos/viz_animated_surfaces.html @@ -0,0 +1,698 @@ + + + + + + + + Animated 2D functions — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +
+

Animated 2D functions#

+

This is a simple demonstration of how one can +animate 2D functions using FURY.

+

Importing necessary modules

+
import itertools
+
+import numpy as np
+
+from fury import actor, colormap, ui, utils, window
+
+
+

The following function is used to create and update the coordinates of the +points which are being used to plot the surface. It’s also used to create +and update the colormap being used to color the surface. +Kindly note that only the z coordinate is being modified with time as only +the z coordinate is a function of time.

+
def update_surface(x, y, equation, cmap_name='viridis'):
+
+    # z is the function F i.e. F(x, y, t)
+    z = eval(equation)
+    xyz = np.vstack([x, y, z]).T
+
+    # creating the colormap
+    v = np.copy(z)
+    m_v = np.max(np.abs(v), axis=0)
+    v /= m_v if m_v else 1
+    colors = colormap.create_colormap(v, name=cmap_name)
+
+    return xyz, colors
+
+
+

Variables and their usage: +:time - float: initial value of the time variable i.e. value of the time variable at

+
+

the beginning of the program; (default = 0)

+
+
+
dt: float

amount by which time variable is incremented for every iteration +of timer_callback function (default = 0.1)

+
+
lower_xbound: float

lower bound of the x values in which the function is plotted +(default = -1)

+
+
upper_xbound: float

Upper bound of the x values in which the function is plotted +(default = 1)

+
+
lower_ybound: float

lower bound of the y values in which the function is plotted +(default = -1)

+
+
upper_ybound: float

Upper bound of the y values in which the function is plotted +(default = 1)

+
+
npoints: int

For high quality rendering, keep the number high but kindly note +that higher values for npoints slows down the animation +(default = 128)

+
+
+
time = 0
+dt = 0.1
+lower_xbound = -1
+upper_xbound = 1
+lower_ybound = -1
+upper_ybound = 1
+npoints = 128
+
+
+

creating the x, y points which will be used to fit the equation to get +elevation and generate the surface

+ +

Function used to create surface obtained from 2D equation.

+
def create_surface(x, y, equation, colormap_name):
+    xyz, colors = update_surface(x, y, equation=equation, cmap_name=colormap_name)
+    surf = actor.surface(xyz, colors=colors)
+    surf.equation = equation
+    surf.cmap_name = colormap_name
+    surf.vertices = utils.vertices_from_actor(surf)
+    surf.no_vertices_per_point = len(surf.vertices) / npoints**2
+    surf.initial_vertices = surf.vertices.copy() - np.repeat(
+        xyz, surf.no_vertices_per_point, axis=0
+    )
+    return surf
+
+
+

Equations to be plotted

+
eq1 = 'np.abs(np.sin(x*2*np.pi*np.cos(time/2)))**1*np.cos(time/2)*\
+      np.abs(np.cos(y*2*np.pi*np.sin(time/2)))**1*np.sin(time/2)*1.2'
+eq2 = '((x**2 - y**2)/(x**2 + y**2))**(2)*np.cos(6*np.pi*x*y-1.8*time)*0.24'
+eq3 = '(np.sin(np.pi*2*x-np.sin(1.8*time))*np.cos(np.pi*2*y+np.cos(1.8*time)))\
+      *0.48'
+eq4 = 'np.cos(24*np.sqrt(x**2 + y**2) - 2*time)*0.18'
+equations = [eq1, eq2, eq3, eq4]
+
+
+

List of colormaps to be used for the various functions.

+
cmap_names = ['hot', 'plasma', 'viridis', 'ocean']
+
+
+

Creating a list of surfaces.

+
surfaces = []
+for i in range(4):
+    surfaces.append(
+        create_surface(x, y, equation=equations[i], colormap_name=cmap_names[i])
+    )
+
+
+

Creating a scene object and configuring the camera’s position

+
scene = window.Scene()
+scene.set_camera(
+    position=(4.45, -21, 12), focal_point=(4.45, 0.0, 0.0), view_up=(0.0, 0.0, 1.0)
+)
+showm = window.ShowManager(scene, size=(600, 600))
+
+
+

Creating a grid to interact with surfaces individually.

+
# To store the function names
+text = []
+for i in range(4):
+    t_actor = actor.vector_text(
+        'Function ' + str(i + 1), pos=(0, 0, 0), scale=(0.17, 0.2, 0.2)
+    )
+    text.append(t_actor)
+
+grid_ui = ui.GridUI(
+    actors=surfaces,
+    captions=text,
+    caption_offset=(-0.7, -2.5, 0),
+    dim=(1, 4),
+    cell_padding=2,
+    aspect_ratio=1,
+    rotation_axis=(0, 1, 0),
+)
+showm.scene.add(grid_ui)
+
+# Adding an axes actor to the first surface.
+showm.scene.add(actor.axes())
+
+
+

Initializing text box to print the title of the animation

+
tb = ui.TextBlock2D(bold=True, position=(200, 60))
+tb.message = 'Animated 2D functions'
+scene.add(tb)
+
+
+

Initializing showm and counter

+ +

end is used to decide when to end the animation

+
end = 200
+
+
+

The 2D functions are updated and rendered here.

+
def timer_callback(_obj, _event):
+    global xyz, time
+    time += dt
+    cnt = next(counter)
+
+    # updating the colors and vertices of the triangles used to form the
+    # surfaces
+    for surf in surfaces:
+        xyz, colors = update_surface(
+            x, y, equation=surf.equation, cmap_name=surf.cmap_name
+        )
+        utils.update_surface_actor_colors(surf, colors)
+        surf.vertices[:] = surf.initial_vertices + np.repeat(
+            xyz, surf.no_vertices_per_point, axis=0
+        )
+        utils.update_actor(surf)
+
+    showm.render()
+    # to end the animation
+    if cnt == end:
+        showm.exit()
+
+
+

Run every 30 milliseconds

+
showm.add_timer_callback(True, 30, timer_callback)
+
+interactive = False
+if interactive:
+    showm.start()
+
+window.record(showm.scene, size=(600, 600), out_path='viz_animated_surfaces.png')
+
+
+viz animated surfaces

Total running time of the script: (0 minutes 0.450 seconds)

+ +

Gallery generated by Sphinx-Gallery

+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/auto_examples/04_demos/viz_brownian_motion.html b/v0.10.x/auto_examples/04_demos/viz_brownian_motion.html new file mode 100644 index 000000000..48935aa6f --- /dev/null +++ b/v0.10.x/auto_examples/04_demos/viz_brownian_motion.html @@ -0,0 +1,644 @@ + + + + + + + + Brownian motion — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +
+

Brownian motion#

+

Brownian motion, or pedesis, is the random motion of particles +suspended in a medium. In this animation, path followed by 20 particles +exhibiting brownian motion in 3D is plotted.

+

Importing necessary modules

+
import numpy as np
+from scipy.stats import norm
+
+from fury import actor, ui, utils, window
+
+
+

Let’s define some variable and their description:

+
    +
  • total_time: time to be discretized via time_steps (default: 5)

  • +
  • num_total_steps: total number of steps each particle will take +(default: 300)

  • +
  • time_step: By default, it is equal to total_time / num_total_steps

  • +
  • counter_step: to keep track of number of steps taken +(initialised to 0)

  • +
  • delta: delta determines the “speed” of the Brownian motion. +Increase delta to speed up the motion of the particle(s). The random +variable of the position has a normal distribution whose mean is the +position at counter_step = 0 and whose variance is equal to +delta**2*time_step. (default: 1.8)

  • +
  • num_particles: number of particles whose path will be plotted +(default: 20)

  • +
  • path_thickness: thickness of line(s) that will be used to plot the +path(s) of the particle(s) (default: 3)

  • +
  • origin: coordinate from which the the particle(s) begin the motion +(default: [0, 0, 0])

  • +
+
total_time = 5
+num_total_steps = 300
+counter_step = 0
+delta = 1.8
+num_particles = 20
+path_thickness = 3
+origin = [0, 0, 0]
+
+
+

We define a particle function that will return an actor, store and update +coordinates of the particles (the path of the particles).

+
def particle(
+    colors,
+    origin=[0, 0, 0],
+    num_total_steps=300,
+    total_time=5,
+    delta=1.8,
+    path_thickness=3,
+):
+    origin = np.asarray(origin, dtype=float)
+    position = np.tile(origin, (num_total_steps, 1))
+    path_actor = actor.line([position], colors, linewidth=path_thickness)
+    path_actor.position = position
+    path_actor.delta = delta
+    path_actor.num_total_steps = num_total_steps
+    path_actor.time_step = total_time / num_total_steps
+    path_actor.vertices = utils.vertices_from_actor(path_actor)
+    path_actor.no_vertices_per_point = len(path_actor.vertices) / num_total_steps
+    path_actor.initial_vertices = path_actor.vertices.copy() - np.repeat(
+        position, path_actor.no_vertices_per_point, axis=0
+    )
+    return path_actor
+
+
+

The function update_path will simulate the the brownian motion.

+
def update_path(act, counter_step):
+    if counter_step < act.num_total_steps:
+        x, y, z = act.position[counter_step - 1]
+        x += norm.rvs(scale=act.delta**2 * act.time_step)
+        y += norm.rvs(scale=act.delta**2 * act.time_step)
+        z += norm.rvs(scale=act.delta**2 * act.time_step)
+        act.position[counter_step:] = [x, y, z]
+        act.vertices[:] = act.initial_vertices + np.repeat(
+            act.position, act.no_vertices_per_point, axis=0
+        )
+        utils.update_actor(act)
+
+
+

Creating a scene object and configuring the camera’s position

+
scene = window.Scene()
+scene.background((1.0, 1.0, 1.0))
+scene.zoom(1.7)
+scene.set_camera(
+    position=(0, 0, 40), focal_point=(0.0, 0.0, 0.0), view_up=(0.0, 0.0, 0.0)
+)
+showm = window.ShowManager(
+    scene, size=(600, 600), reset_camera=True, order_transparent=True
+)
+
+
+

Creating a list of particle objects

+ +

Creating a container (cube actor) inside which the particle(s) move around

+
container_actor = actor.box(
+    centers=np.array([[0, 0, 0]]), colors=(0.5, 0.9, 0.7, 0.4), scales=6
+)
+scene.add(container_actor)
+
+
+

Initializing text box to display the name of the animation

+
tb = ui.TextBlock2D(bold=True, position=(235, 40), color=(0, 0, 0))
+tb.message = 'Brownian Motion'
+scene.add(tb)
+
+
+

The path of the particles exhibiting Brownian motion is plotted here

+
def timer_callback(_obj, _event):
+    global counter_step, list_particle
+    counter_step += 1
+    for p in l_particle:
+        update_path(p, counter_step=counter_step)
+    showm.render()
+    scene.azimuth(2)
+    if counter_step == num_total_steps:
+        showm.exit()
+
+
+

Run every 30 milliseconds

+
showm.add_timer_callback(True, 30, timer_callback)
+showm.start()
+window.record(showm.scene, size=(600, 600), out_path='viz_brownian_motion.png')
+
+
+viz brownian motion

Total running time of the script: (0 minutes 9.253 seconds)

+ +

Gallery generated by Sphinx-Gallery

+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/auto_examples/04_demos/viz_bundles.html b/v0.10.x/auto_examples/04_demos/viz_bundles.html new file mode 100644 index 000000000..b2ecfaaff --- /dev/null +++ b/v0.10.x/auto_examples/04_demos/viz_bundles.html @@ -0,0 +1,827 @@ + + + + + + + + Visualize bundles and metrics on bundles — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +
+

Visualize bundles and metrics on bundles#

+

First, let’s download some available datasets. Here we are using a dataset +which provides metrics and bundles.

+
import numpy as np
+from dipy.data import fetch_bundles_2_subjects, read_bundles_2_subjects
+from dipy.tracking.streamline import length, transform_streamlines
+
+from fury import actor, window
+
+interactive = False  # set to True to show the interactive display window
+
+fetch_bundles_2_subjects()
+dix = read_bundles_2_subjects(
+    subj_id='subj_1', metrics=['fa'], bundles=['cg.left', 'cst.right']
+)
+
+
+

Store fractional anisotropy.

+
fa = dix['fa']
+
+
+

Store grid to world transformation matrix.

+
affine = dix['affine']
+
+
+

Store the cingulum bundle. A bundle is a list of streamlines.

+
bundle = dix['cg.left']
+
+
+

It happened that this bundle is in world coordinates and therefore we need to +transform it into native image coordinates so that it is in the same +coordinate space as the fa image.

+
bundle_native = transform_streamlines(bundle, np.linalg.inv(affine))
+
+
+
+

Show every streamline with an orientation color#

+

This is the default option when you are using line or streamtube.

+
scene = window.Scene()
+
+stream_actor = actor.line(bundle_native)
+
+scene.set_camera(
+    position=(-176.42, 118.52, 128.20),
+    focal_point=(113.30, 128.31, 76.56),
+    view_up=(0.18, 0.00, 0.98),
+)
+
+scene.add(stream_actor)
+
+if interactive:
+    window.show(scene, size=(600, 600), reset_camera=False)
+
+window.record(scene, out_path='bundle1.png', size=(600, 600))
+
+
+viz bundles

You may wonder how we knew how to set the camera. This is very easy. You just +need to run window.show once see how you want to see the object and then +close the window and call the camera_info method which prints the +position, focal point and view up vectors of the camera.

+ +
# Active Camera
+   Position (-237.76, 115.97, 138.55)
+   Focal Point (112.80, 127.81, 76.06)
+   View Up (0.18, 0.00, 0.98)
+
+
+
+
+

Show every point with a value from a volume with default colormap#

+

Here we will need to input the fa map in streamtube or line.

+
scene.clear()
+stream_actor2 = actor.line(bundle_native, fa, linewidth=0.1)
+
+
+

We can also show the scalar bar.

+
bar = actor.scalar_bar()
+
+scene.add(stream_actor2)
+scene.add(bar)
+
+if interactive:
+    window.show(scene, size=(600, 600), reset_camera=False)
+
+window.record(scene, out_path='bundle2.png', size=(600, 600))
+
+
+viz bundles
+
+

Show every point with a value from a volume with your colormap#

+

Here we will need to input the fa map in streamtube

+
scene.clear()
+
+hue = (0.0, 0.0)  # red only
+saturation = (0.0, 1.0)  # white to red
+
+lut_cmap = actor.colormap_lookup_table(hue_range=hue, saturation_range=saturation)
+
+stream_actor3 = actor.line(bundle_native, fa, linewidth=0.1, lookup_colormap=lut_cmap)
+bar2 = actor.scalar_bar(lut_cmap)
+
+scene.add(stream_actor3)
+scene.add(bar2)
+
+if interactive:
+    window.show(scene, size=(600, 600), reset_camera=False)
+
+window.record(scene, out_path='bundle3.png', size=(600, 600))
+
+
+viz bundles
+
+

Show every bundle with a specific color#

+

You can have a bundle with a specific color. In this example, we are choosing +orange.

+
scene.clear()
+stream_actor4 = actor.line(bundle_native, (1.0, 0.5, 0), linewidth=0.1)
+
+scene.add(stream_actor4)
+
+if interactive:
+    window.show(scene, size=(600, 600), reset_camera=False)
+
+window.record(scene, out_path='bundle4.png', size=(600, 600))
+
+
+viz bundles
+
+

Show every streamline of a bundle with a different color#

+

Let’s make a colormap where every streamline of the bundle is colored by its +length.

+
scene.clear()
+
+lengths = length(bundle_native)
+
+hue = (0.5, 0.5)  # blue only
+saturation = (0.0, 1.0)  # black to white
+
+lut_cmap = actor.colormap_lookup_table(
+    scale_range=(lengths.min(), lengths.max()),
+    hue_range=hue,
+    saturation_range=saturation,
+)
+
+stream_actor5 = actor.line(
+    bundle_native, lengths, linewidth=0.1, lookup_colormap=lut_cmap
+)
+
+scene.add(stream_actor5)
+bar3 = actor.scalar_bar(lut_cmap)
+
+scene.add(bar3)
+
+if interactive:
+    window.show(scene, size=(600, 600), reset_camera=False)
+
+window.record(scene, out_path='bundle5.png', size=(600, 600))
+
+
+viz bundles
+
+

Show every point of every streamline with a different color#

+

In this case in which we want to have a color per point and per streamline, +we can create a list of the colors to correspond to the list of streamlines +(bundles). Here in colors we will insert some random RGB colors.

+
scene.clear()
+
+colors = [np.random.rand(*streamline.shape) for streamline in bundle_native]
+
+stream_actor6 = actor.line(bundle_native, np.vstack(colors), linewidth=0.2)
+
+scene.add(stream_actor6)
+
+if interactive:
+    window.show(scene, size=(600, 600), reset_camera=False)
+
+window.record(scene, out_path='bundle6.png', size=(600, 600))
+
+
+viz bundles
+
+

Add depth cues to streamline rendering#

+

By default, lines are drawn with the same width on the screen, regardless of +their distance from the camera. To increase realism, we can enable +depth_cue to make the lines shrink with distance from the camera. We +will return to the default color scheme from the first example. Note that +depth_cue works best for linewidth <= 1.

+
scene.clear()
+
+stream_actor7 = actor.line(bundle_native, linewidth=0.5, depth_cue=True)
+
+scene.add(stream_actor7)
+
+if interactive:
+    window.show(scene, size=(600, 600), reset_camera=False)
+
+window.record(scene, out_path='bundle7.png', size=(600, 600))
+
+
+viz bundles
+
+

Render streamlines as fake tubes#

+

We can simulate the look of streamtubes by adding shading to streamlines with +fake_tube. Note that fake_tube requires linewidth > 1.

+
scene.clear()
+
+stream_actor8 = actor.line(bundle_native, linewidth=3, fake_tube=True)
+
+scene.add(stream_actor8)
+
+if interactive:
+    window.show(scene, size=(600, 600), reset_camera=False)
+
+window.record(scene, out_path='bundle8.png', size=(600, 600))
+
+
+viz bundles
+
+

Combine depth cues with fake tubes#

+

It is possible to fully simulate streamtubes by enabling both depth_cue +and fake_tube. However, it can be challenging to choose a linewidth +that demonstrates both techniques well.

+
scene.clear()
+
+stream_actor9 = actor.line(bundle_native, linewidth=3, depth_cue=True, fake_tube=True)
+
+scene.add(stream_actor9)
+
+if interactive:
+    window.show(scene, size=(600, 600), reset_camera=False)
+
+window.record(scene, out_path='bundle9.png', size=(600, 600))
+
+
+viz bundles
+
+

Render streamlines as tubes#

+

For yet more realism, we can use streamtube. Note that this actor +generates much more geometry than line, so it is more computationally +expensive. For large datasets, it may be better to approximate tubes using +the methods described above.

+
scene.clear()
+
+stream_actor10 = actor.streamtube(bundle_native, linewidth=0.5)
+
+scene.add(stream_actor10)
+
+if interactive:
+    window.show(scene, size=(600, 600), reset_camera=False)
+
+window.record(scene, out_path='bundle10.png', size=(600, 600))
+
+
+viz bundles

In summary, we showed that there are many useful ways for visualizing maps +on bundles.

+

Total running time of the script: (0 minutes 4.691 seconds)

+ +

Gallery generated by Sphinx-Gallery

+
+
+ +
+ + +
+ +
+ + + + + +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/auto_examples/04_demos/viz_dt_ellipsoids.html b/v0.10.x/auto_examples/04_demos/viz_dt_ellipsoids.html new file mode 100644 index 000000000..8c315ebca --- /dev/null +++ b/v0.10.x/auto_examples/04_demos/viz_dt_ellipsoids.html @@ -0,0 +1,852 @@ + + + + + + + + Display Tensor Ellipsoids for DTI using tensor_slicer vs ellipsoid actor — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +
+

Display Tensor Ellipsoids for DTI using tensor_slicer vs ellipsoid actor#

+

This tutorial is intended to show two ways of displaying diffusion tensor +ellipsoids for DTI visualization. The first is using the usual +tensor_slicer that allows us to slice many tensors as ellipsoids. The +second is the generic ellipsoid actor that can be used to display different +amount of ellipsoids.

+

We start by importing the necessary modules:

+
import itertools
+
+import numpy as np
+
+from dipy.io.image import load_nifti
+
+from fury import window, actor, ui
+from fury.actor import _fa, _color_fa
+from fury.data import fetch_viz_dmri, read_viz_dmri
+from fury.primitive import prim_sphere
+
+
+

Now, we fetch and load the data needed to display the Diffusion Tensor +Images.

+
fetch_viz_dmri()
+
+
+
Dataset is already in place. If you want to fetch it again please first remove the folder /Users/skoudoro/.fury/dmri
+
+({'fodf.nii.gz': ('https://raw.githubusercontent.com/fury-gl/fury-data/master/dmri/fodf.nii.gz', '767ca3e4cd296e78421d83c32201b30be2d859c332210812140caac1b93d492b'), 'slice_evecs.nii.gz': ('https://raw.githubusercontent.com/fury-gl/fury-data/master/dmri/slice_evecs.nii.gz', '8843ECF3224CB8E3315B7251D1E303409A17D7137D3498A8833853C4603C6CC2'), 'slice_evals.nii.gz': ('https://raw.githubusercontent.com/fury-gl/fury-data/master/dmri/slice_evals.nii.gz', '3096B190B1146DD0EADDFECC0B4FBBD901F4933692ADD46A83F637F28B22122D'), 'roi_evecs.nii.gz': ('https://raw.githubusercontent.com/fury-gl/fury-data/master/dmri/roi_evecs.nii.gz', '89E569858A897E72C852A8F05BBCE0B21C1CA726E55508087A2DA5A38C212A17'), 'roi_evals.nii.gz': ('https://raw.githubusercontent.com/fury-gl/fury-data/master/dmri/roi_evals.nii.gz', 'F53C68CCCABF97F1326E93840A8B5CE2E767D66D692FFD955CA747FFF14EC781'), 'whole_brain_evecs.nii.gz': ('https://raw.githubusercontent.com/fury-gl/fury-data/master/dmri/whole_brain_evecs.nii.gz', '8A894F6AB404240E65451FA6D10FB5D74E2D0BDCB2A56AD6BEA38215BF787248'), 'whole_brain_evals.nii.gz': ('https://raw.githubusercontent.com/fury-gl/fury-data/master/dmri/whole_brain_evals.nii.gz', '47A73BBE68196381ED790F80F48E46AC07B699B506973FFA45A95A33023C7A77')}, '/Users/skoudoro/.fury/dmri')
+
+
+

The tensor ellipsoids are expressed as eigenvalues and eigenvectors which are +the decomposition of the diffusion tensor that describes the water diffusion +within a voxel.

+
slice_evecs, _ = load_nifti(read_viz_dmri('slice_evecs.nii.gz'))
+slice_evals, _ = load_nifti(read_viz_dmri('slice_evals.nii.gz'))
+roi_evecs, _ = load_nifti(read_viz_dmri('roi_evecs.nii.gz'))
+roi_evals, _ = load_nifti(read_viz_dmri('roi_evals.nii.gz'))
+whole_brain_evecs, _ = load_nifti(read_viz_dmri('whole_brain_evecs.nii.gz'))
+whole_brain_evals, _ = load_nifti(read_viz_dmri('whole_brain_evals.nii.gz'))
+
+
+
+

Using tensor_slicer actor#

+

First we must define the 3 parameters needed to use the tensor_slicer +actor, which correspond to the eigenvalues, the eigenvectors, and the sphere. +For the sphere we use prim_sphere which provide vertices and triangles of +the spheres. These are labeled as ‘repulsionN’ with N been the number of +vertices that made up the sphere, which have a standard number of 100, 200, +and 724 vertices.

+
vertices, faces = prim_sphere('repulsion100', True)
+
+
+

As we need to provide a sphere object we create a class Sphere to which we +assign the values obtained from vertices and faces.

+
class Sphere:
+    def __init__(self, vertices, faces):
+        self.vertices = vertices
+        self.faces = faces
+
+
+sphere100 = Sphere(vertices, faces)
+
+
+

Now we are ready to create the tensor_slicer actor with the values of a +brain slice. We also define the scale so that the tensors are not so large +and overlap each other.

+
tensor_slice = actor.tensor_slicer(evals=slice_evals, evecs=slice_evecs,
+                                   sphere=sphere100, scale=.3)
+
+
+

Next, we set up a new scene to add and visualize the tensor ellipsoids +created.

+
scene = window.Scene()
+scene.background([255, 255, 255])
+scene.add(tensor_slice)
+
+# Create show manager
+showm = window.ShowManager(scene, size=(600, 600))
+
+# Enables/disables interactive visualization
+interactive = False
+
+if interactive:
+    showm.start()
+
+window.record(showm.scene, size=(600, 600), out_path='tensor_slice_100.png')
+
+
+viz dt ellipsoids

If we zoom in at the scene to see with detail the tensor ellipsoids displayed +with the different spheres, we get the following results.

+
scene.roll(10)
+scene.pitch(90)
+showm = window.ShowManager(scene, size=(600, 600), order_transparent=True)
+showm.scene.zoom(50)
+
+if interactive:
+    showm.render()
+    showm.start()
+
+window.record(showm.scene, out_path='tensor_slice_100_zoom.png',
+              size=(600, 300), reset_camera=False)
+
+
+viz dt ellipsoids

To render the same tensor slice using a different sphere we redefine the +vertices and faces of the sphere using prim_sphere with other sphere +specification, as ‘repulsion200’ or ‘repulsion724’.

+

Now we clear the scene for the next visualization, and revert the scene +rotations.

+ +
+
+

Using ellipsoid actor#

+

In order to use the ellipsoid actor to display the same tensor slice we +need to set additional parameters. For this purpose, we define a helper +function to facilitate the correct setting of the parameters before passing +them to the actor.

+
def get_params(evecs, evals):
+    # We define the centers which corresponds to the ellipsoids positions.
+    valid_mask = np.abs(evecs).max(axis=(-2, -1)) > 0
+    indices = np.nonzero(valid_mask)
+    centers = np.asarray(indices).T
+
+    # We need to pass the data of the axes and lengths of the ellipsoid as a
+    # ndarray, so it is necessary to rearrange the data of the eigenvectors and
+    # eigenvalues.
+    fevecs = evecs[indices]
+    fevals = evals[indices]
+
+    # We need to define the colors of the ellipsoids following the default
+    # coloring in tensor_slicer that is uses _color_fa that is a way to map
+    # colors to each tensor based on the fractional anisotropy (FA) of each
+    # diffusion tensor.
+    colors = _color_fa(_fa(fevals), fevecs)
+
+    return centers, fevecs, fevals, colors
+
+
+

With this we now have the values we need to define the centers, axes, +lengths, and colors of the ellipsoids.

+ +

Now, we can use the ellipsoid actor to create the tensor ellipsoids as +follows.

+
tensors = actor.ellipsoid(centers=centers, colors=colors, axes=evecs,
+                          lengths=evals, scales=.6)
+showm.scene.add(tensors)
+
+if interactive:
+    showm.start()
+
+window.record(scene, size=(600, 600), out_path='tensor_slice_sdf.png')
+
+
+viz dt ellipsoids

Thus, one can see that the same result is obtained, however there is a +difference in the visual quality and this is because the ellipsoid actor +uses raymarching technique, so the objects that are generated are smoother +since they are not made with polygons but defined by an SDF function. Next we +can see in more detail the tensor ellipsoids generated.

+
scene.roll(10)
+scene.pitch(90)
+showm = window.ShowManager(scene, size=(600, 600), order_transparent=True)
+showm.scene.zoom(50)
+
+if interactive:
+    showm.render()
+    showm.start()
+
+window.record(showm.scene, out_path='tensor_slice_sdf_zoom.png',
+              size=(600, 300), reset_camera=False)
+
+showm.scene.clear()
+showm.scene.pitch(-90)
+showm.scene.roll(-10)
+
+
+viz dt ellipsoids
+
+

Visual quality comparison#

+

One can see that there is a different on the visual quality of both ways of +displaying tensors and this is because tensor_slicer uses polygons while +ellipsoid uses raymarching. Let’s display both implementations at the +same time, so we can see this in more detail.

+

We first set up the required data and create the actors.

+
mevals = np.array([1.4, 1.0, 0.35]) * 10 ** (-3)
+mevecs = np.array([[2/3, -2/3, 1/3], [1/3, 2/3, 2/3], [2/3, 1/3, -2/3]])
+
+evals = np.zeros((1, 1, 1, 3))
+evecs = np.zeros((1, 1, 1, 3, 3))
+
+evals[..., :] = mevals
+evecs[..., :, :] = mevecs
+
+vertices, faces = prim_sphere('repulsion200', True)
+sphere200 = Sphere(vertices, faces)
+vertices, faces = prim_sphere('repulsion724', True)
+sphere724 = Sphere(vertices, faces)
+
+tensor_100 = actor.tensor_slicer(evals=evals, evecs=evecs,
+                                 sphere=sphere100, scale=1.0)
+tensor_200 = actor.tensor_slicer(evals=evals, evecs=evecs,
+                                 sphere=sphere200, scale=1.0)
+tensor_724 = actor.tensor_slicer(evals=evals, evecs=evecs,
+                                 sphere=sphere724, scale=1.0)
+
+centers, evecs, evals, colors = get_params(evecs=evecs, evals=evals)
+tensor_sdf = actor.ellipsoid(centers=centers, axes=evecs, lengths=evals,
+                             colors=colors, scales=2.0)
+
+
+

Next, we made use of GridUI which allows us to add the actors in a grid and +interact with them individually.

+
objects = [tensor_100, tensor_200, tensor_724, tensor_sdf]
+text = [actor.vector_text('Tensor 100'), actor.vector_text('Tensor 200'),
+        actor.vector_text('Tensor 724'), actor.vector_text('Tensor SDF')]
+
+grid_ui = ui.GridUI(actors=objects, captions=text, cell_padding=.1,
+                    caption_offset=(-0.7, -2.5, 0), dim=(1, 4))
+
+scene = window.Scene()
+scene.background([255, 255, 255])
+scene.zoom(3.5)
+scene.set_camera(position=(3.2, -20, 12), focal_point=(3.2, 0.0, 0.0))
+showm = window.ShowManager(scene, size=(560, 200))
+showm.scene.add(grid_ui)
+
+if interactive:
+    showm.start()
+
+window.record(showm.scene, size=(560, 200), out_path='tensor_comparison.png',
+              reset_camera=False, magnification=2)
+
+showm.scene.clear()
+
+
+viz dt ellipsoids
+
+

Visualize a larger amount of data#

+

With tensor_slicer is possible to visualize more than one slice using +display_extent(). Here we can see an example of a region of interest +(ROI) using a sphere of 100 vertices.

+
tensor_roi = actor.tensor_slicer(evals=roi_evals, evecs=roi_evecs,
+                                 sphere=sphere100, scale=.3)
+
+data_shape = roi_evals.shape[:3]
+tensor_roi.display_extent(
+    0, data_shape[0], 0, data_shape[1], 0, data_shape[2])
+
+showm.size = (600, 600)
+showm.scene.background([0, 0, 0])
+showm.scene.add(tensor_roi)
+showm.scene.azimuth(87)
+
+if interactive:
+    showm.start()
+
+window.record(showm.scene, size=(600, 600), out_path='tensor_roi_100.png')
+
+showm.scene.clear()
+
+
+viz dt ellipsoids

We can do it also with a sphere of 200 vertices, but if we try to do it with +one of 724 the visualization can no longer be rendered. In contrast, we can +visualize the ROI with the ellipsoid actor without compromising the +quality of the visualization.

+
centers, evecs, evals, colors = get_params(roi_evecs, roi_evals)
+
+tensors = actor.ellipsoid(centers=centers, colors=colors, axes=evecs,
+                          lengths=evals, scales=.6)
+showm.scene.add(tensors)
+
+if interactive:
+    showm.start()
+
+window.record(showm.scene, size=(600, 600), out_path='tensor_roi_sdf.png')
+
+showm.scene.clear()
+
+
+viz dt ellipsoids

In fact, although with a low performance, this actor allows us to visualize +the whole brain, which contains a much larger amount of data, to be exact +184512 tensor ellipsoids are displayed at the same time.

+
centers, evecs, evals, colors = get_params(whole_brain_evecs,
+                                           whole_brain_evals)
+
+# We remove all the noise around the brain to have a better visualization.
+fil = [len(set(elem)) != 1 for elem in evals]
+centers = np.array(list(itertools.compress(centers, fil)))
+colors = np.array(list(itertools.compress(colors, fil)))
+evecs = np.array(list(itertools.compress(evecs, fil)))
+evals = np.array(list(itertools.compress(evals, fil)))
+
+tensors = actor.ellipsoid(centers=centers, colors=colors, axes=evecs,
+                          lengths=evals, scales=.6)
+
+scene = window.Scene()
+scene.add(tensors)
+scene.pitch(180)
+showm = window.ShowManager(scene, size=(600, 600))
+
+if interactive:
+    showm.start()
+
+window.record(showm.scene, size=(600, 600), reset_camera=False,
+              out_path='tensor_whole_brain_sdf.png')
+
+showm.scene.clear()
+
+
+viz dt ellipsoids

Total running time of the script: (0 minutes 8.555 seconds)

+ +

Gallery generated by Sphinx-Gallery

+
+
+ +
+ + +
+ +
+ + + + + +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/auto_examples/04_demos/viz_emwave_animation.html b/v0.10.x/auto_examples/04_demos/viz_emwave_animation.html new file mode 100644 index 000000000..3387bab8a --- /dev/null +++ b/v0.10.x/auto_examples/04_demos/viz_emwave_animation.html @@ -0,0 +1,665 @@ + + + + + + + + Electromagnetic Wave Propagation Animation — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +
+

Electromagnetic Wave Propagation Animation#

+

A linearly polarized sinusoidal electromagnetic wave, propagating in the +direction +x through a homogeneous, isotropic, dissipationless medium, +such as vacuum. The electric field (blue arrows) oscillates in the +±z-direction, and the orthogonal magnetic field (red arrows) oscillates in +phase with the electric field, but in the ±y-direction.

+

Function of the sinusoid used in the animation = sin(k*x - w*t + d) +Where, k:wavenumber, x:abscissa, w:angular frequency, t:time, d:phase angle

+

Importing necessary modules

+
import itertools
+
+import numpy as np
+
+from fury import actor, ui, utils, window
+
+
+

function that updates and returns the coordinates of the waves which are +changing with time

+
def update_coordinates(wavenumber, ang_frq, time, phase_angle):
+    x = np.linspace(-3, 3, npoints)
+    y = np.sin(wavenumber * x - ang_frq * time + phase_angle)
+    z = np.array([0 for i in range(npoints)])
+    return x, y, z
+
+
+

Variable(s) and their description- +npoints: For high quality rendering, keep the number of npoints high

+
+

but kindly note that higher values for npoints will slow down the +rendering process (default = 800)

+
+

wavelength : wavelength of the wave (default = 2) +wavenumber : 2*pi/wavelength +time: time (default time i.e. time at beginning of the animation = 0) +incre_time: value by which time is incremented for each call of

+
+

timer_callback (default = 0.1)

+
+

angular_frq: angular frequency (default = 0.1) +phase_angle: phase angle (default = 0.002)

+
npoints = 800
+wavelength = 2
+wavenumber = 2 * np.pi / wavelength
+time = 0
+incre_time = 0.1
+angular_frq = 0.1
+phase_angle = 0.002
+
+
+

Creating a scene object and configuring the camera’s position

+
scene = window.Scene()
+scene.set_camera(
+    position=(-6, 5, -10), focal_point=(0.0, 0.0, 0.0), view_up=(0.0, 0.0, 0.0)
+)
+showm = window.ShowManager(
+    scene, size=(800, 600), reset_camera=True, order_transparent=True
+)
+
+
+

Creating a yellow colored arrow to show the direction of propagation of +electromagnetic wave

+
centers = np.array([[3, 0, 0]])
+directions = np.array([[-1, 0, 0]])
+heights = np.array([6.4])
+arrow_actor = actor.arrow(
+    centers,
+    directions,
+    window.colors.yellow,
+    heights,
+    resolution=20,
+    tip_length=0.06,
+    tip_radius=0.012,
+    shaft_radius=0.005,
+)
+scene.add(arrow_actor)
+
+
+

Creating point actor that renders the magnetic field

+
x = np.linspace(-3, 3, npoints)
+y = np.sin(wavenumber * x - angular_frq * time + phase_angle)
+z = np.array([0 for i in range(npoints)])
+
+pts = np.array([(a, b, c) for (a, b, c) in zip(x, y, z)])
+pts = [pts]
+colors = window.colors.red
+wave_actor1 = actor.line(pts, colors, linewidth=3)
+scene.add(wave_actor1)
+
+vertices = utils.vertices_from_actor(wave_actor1)
+vcolors = utils.colors_from_actor(wave_actor1, 'colors')
+no_vertices_per_point = len(vertices) / npoints
+initial_vertices = vertices.copy() - np.repeat(pts, no_vertices_per_point, axis=0)
+
+
+

Creating point actor that renders the electric field

+
xx = np.linspace(-3, 3, npoints)
+yy = np.array([0 for i in range(npoints)])
+zz = np.sin(wavenumber * xx - angular_frq * time + phase_angle)
+
+pts2 = np.array([(a, b, c) for (a, b, c) in zip(xx, yy, zz)])
+pts2 = [pts2]
+colors2 = window.colors.blue
+wave_actor2 = actor.line(pts2, colors2, linewidth=3)
+scene.add(wave_actor2)
+
+vertices2 = utils.vertices_from_actor(wave_actor2)
+vcolors2 = utils.colors_from_actor(wave_actor2, 'colors')
+no_vertices_per_point2 = len(vertices2) / npoints
+initial_vertices2 = vertices2.copy() - np.repeat(pts2, no_vertices_per_point2, axis=0)
+
+
+

Initializing text box to display the title of the animation

+
tb = ui.TextBlock2D(bold=True, position=(160, 90))
+tb.message = 'Electromagnetic Wave'
+scene.add(tb)
+
+
+

end is used to decide when to end the animation

+
end = 300
+
+
+

Initializing counter

+ +

Coordinates to be plotted are changed every time timer_callback is called by +using the update_coordinates function. The wave is rendered here.

+
def timer_callback(_obj, _event):
+    global pts, pts2, time, time_incre, angular_frq, phase_angle, wavenumber
+    time += incre_time
+    cnt = next(counter)
+
+    x, y, z = update_coordinates(wavenumber, angular_frq, phase_angle, time)
+    pts = np.array([(a, b, c) for (a, b, c) in zip(x, y, z)])
+    vertices[:] = initial_vertices + np.repeat(pts, no_vertices_per_point, axis=0)
+    utils.update_actor(wave_actor1)
+
+    xx, zz, yy = update_coordinates(wavenumber, angular_frq, phase_angle, time)
+    pts2 = np.array([(a, b, c) for (a, b, c) in zip(xx, yy, zz)])
+    vertices2[:] = initial_vertices2 + np.repeat(pts2, no_vertices_per_point2, axis=0)
+    utils.update_actor(wave_actor2)
+
+    showm.render()
+
+    # to end the animation
+    if cnt == end:
+        showm.exit()
+
+
+

Run every 25 milliseconds

+
showm.add_timer_callback(True, 25, timer_callback)
+
+interactive = False
+if interactive:
+    showm.start()
+window.record(showm.scene, size=(800, 600), out_path='viz_emwave.png')
+
+
+viz emwave animation

Total running time of the script: (0 minutes 0.524 seconds)

+ +

Gallery generated by Sphinx-Gallery

+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/auto_examples/04_demos/viz_fiber_odf.html b/v0.10.x/auto_examples/04_demos/viz_fiber_odf.html new file mode 100644 index 000000000..0de9b58c2 --- /dev/null +++ b/v0.10.x/auto_examples/04_demos/viz_fiber_odf.html @@ -0,0 +1,752 @@ + + + + + + + + Brain Fiber ODF Visualisation — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +
+

Brain Fiber ODF Visualisation#

+

This example demonstrate how to create a simple viewer for fiber +orientation distribution functions (ODF) using fury’s odf_slicer.

+
import nibabel as nib
+
+# First, we import some useful modules and methods.
+import numpy as np
+from dipy.data import get_sphere
+from dipy.reconst.shm import sh_to_sf_matrix
+
+from fury import actor, ui, window
+from fury.data import fetch_viz_dmri, fetch_viz_icons, read_viz_dmri
+from fury.utils import fix_winding_order
+
+
+

Here, we fetch and load the fiber ODF volume to display. The ODF are +expressed as spherical harmonics (SH) coefficients in a 3D grid.

+
fetch_viz_dmri()
+fetch_viz_icons()
+
+fodf_img = nib.load(read_viz_dmri('fodf.nii.gz'))
+sh = fodf_img.get_fdata()
+affine = fodf_img.affine
+grid_shape = sh.shape[:-1]
+
+
+
Dataset is already in place. If you want to fetch it again please first remove the folder /Users/skoudoro/.fury/dmri
+Data size is approximately 12KB
+Dataset is already in place. If you want to fetch it again please first remove the folder /Users/skoudoro/.fury/icons
+
+
+

We then define a low resolution sphere used to visualize SH coefficients +as spherical functions (SF) as well as a matrix B_low to project SH +onto the sphere.

+
sphere_low = get_sphere('repulsion100')
+B_low = sh_to_sf_matrix(sphere_low, 8, return_inv=False)
+
+
+

Now, we create a slicer for each orientation to display a slice in +the middle of the volume and we add them to a scene.

+
# Change these values to test various parameters combinations.
+scale = 0.5
+norm = False
+colormap = None
+radial_scale = True
+opacity = 1.0
+global_cm = False
+
+# ODF slicer for axial slice
+odf_actor_z = actor.odf_slicer(
+    sh,
+    affine=affine,
+    sphere=sphere_low,
+    scale=scale,
+    norm=norm,
+    radial_scale=radial_scale,
+    opacity=opacity,
+    colormap=colormap,
+    global_cm=global_cm,
+    B_matrix=B_low,
+)
+
+# ODF slicer for coronal slice
+odf_actor_y = actor.odf_slicer(
+    sh,
+    affine=affine,
+    sphere=sphere_low,
+    scale=scale,
+    norm=norm,
+    radial_scale=radial_scale,
+    opacity=opacity,
+    colormap=colormap,
+    global_cm=global_cm,
+    B_matrix=B_low,
+)
+odf_actor_y.display_extent(
+    0, grid_shape[0] - 1, grid_shape[1] // 2, grid_shape[1] // 2, 0, grid_shape[2] - 1
+)
+
+# ODF slicer for sagittal slice
+odf_actor_x = actor.odf_slicer(
+    sh,
+    affine=affine,
+    sphere=sphere_low,
+    scale=scale,
+    norm=norm,
+    radial_scale=radial_scale,
+    opacity=opacity,
+    colormap=colormap,
+    global_cm=global_cm,
+    B_matrix=B_low,
+)
+odf_actor_x.display_extent(
+    grid_shape[0] // 2, grid_shape[0] // 2, 0, grid_shape[1] - 1, 0, grid_shape[2] - 1
+)
+
+scene = window.Scene()
+scene.add(odf_actor_z)
+scene.add(odf_actor_y)
+scene.add(odf_actor_x)
+
+show_m = window.ShowManager(scene, reset_camera=True, size=(1200, 900))
+
+
+

Now that we have a ShowManager containing our slicer, we can go on and +configure our UI for changing the slices to visualize.

+
line_slider_z = ui.LineSlider2D(
+    min_value=0,
+    max_value=grid_shape[2] - 1,
+    initial_value=grid_shape[2] / 2,
+    text_template='{value:.0f}',
+    length=140,
+)
+
+line_slider_y = ui.LineSlider2D(
+    min_value=0,
+    max_value=grid_shape[1] - 1,
+    initial_value=grid_shape[1] / 2,
+    text_template='{value:.0f}',
+    length=140,
+)
+
+line_slider_x = ui.LineSlider2D(
+    min_value=0,
+    max_value=grid_shape[0] - 1,
+    initial_value=grid_shape[0] / 2,
+    text_template='{value:.0f}',
+    length=140,
+)
+
+
+

We also define a high resolution sphere to demonstrate the capability to +dynamically change the sphere used for SH to SF projection.

+
sphere_high = get_sphere('symmetric362')
+
+# We fix the order of the faces' three vertices to a clockwise winding. This
+# ensures all faces have a normal going away from the center of the sphere.
+sphere_high.faces = fix_winding_order(sphere_high.vertices, sphere_high.faces, True)
+B_high = sh_to_sf_matrix(sphere_high, 8, return_inv=False)
+
+
+

We add a combobox for choosing the sphere resolution during execution.

+
sphere_dict = {
+    'Low resolution': (sphere_low, B_low),
+    'High resolution': (sphere_high, B_high),
+}
+combobox = ui.ComboBox2D(items=list(sphere_dict))
+scene.add(combobox)
+
+
+

Here we will write callbacks for the sliders and combo box and register them.

+
def change_slice_z(slider):
+    i = int(np.round(slider.value))
+    odf_actor_z.slice_along_axis(i)
+
+
+def change_slice_y(slider):
+    i = int(np.round(slider.value))
+    odf_actor_y.slice_along_axis(i, 'yaxis')
+
+
+def change_slice_x(slider):
+    i = int(np.round(slider.value))
+    odf_actor_x.slice_along_axis(i, 'xaxis')
+
+
+def change_sphere(combobox):
+    sphere, B = sphere_dict[combobox.selected_text]
+    odf_actor_x.update_sphere(sphere.vertices, sphere.faces, B)
+    odf_actor_y.update_sphere(sphere.vertices, sphere.faces, B)
+    odf_actor_z.update_sphere(sphere.vertices, sphere.faces, B)
+
+
+line_slider_z.on_change = change_slice_z
+line_slider_y.on_change = change_slice_y
+line_slider_x.on_change = change_slice_x
+combobox.on_change = change_sphere
+
+
+

We then add labels for the sliders and position them inside a panel.

+
def build_label(text):
+    label = ui.TextBlock2D()
+    label.message = text
+    label.font_size = 18
+    label.font_family = 'Arial'
+    label.justification = 'left'
+    label.bold = False
+    label.italic = False
+    label.shadow = False
+    label.background_color = (0, 0, 0)
+    label.color = (1, 1, 1)
+
+    return label
+
+
+line_slider_label_z = build_label(text='Z Slice')
+line_slider_label_y = build_label(text='Y Slice')
+line_slider_label_x = build_label(text='X Slice')
+
+panel = ui.Panel2D(size=(300, 200), color=(1, 1, 1), opacity=0.1, align='right')
+panel.center = (1030, 120)
+
+panel.add_element(line_slider_label_x, (0.1, 0.75))
+panel.add_element(line_slider_x, (0.38, 0.75))
+panel.add_element(line_slider_label_y, (0.1, 0.55))
+panel.add_element(line_slider_y, (0.38, 0.55))
+panel.add_element(line_slider_label_z, (0.1, 0.35))
+panel.add_element(line_slider_z, (0.38, 0.35))
+
+show_m.scene.add(panel)
+
+
+

Then, we can render all the widgets and everything else in the screen and +start the interaction using show_m.start().

+

However, if you change the window size, the panel will not update its +position properly. The solution to this issue is to update the position of +the panel using its re_align method every time the window size changes.

+
size = scene.GetSize()
+
+
+def win_callback(obj, _event):
+    global size
+    if size != obj.GetSize():
+        size_old = size
+        size = obj.GetSize()
+        size_change = [size[0] - size_old[0], 0]
+        panel.re_align(size_change)
+
+
+

Finally, please set the following variable to True to interact with the +datasets in 3D.

+
interactive = False
+
+if interactive:
+    show_m.add_window_callback(win_callback)
+    show_m.render()
+    show_m.start()
+else:
+    window.record(
+        scene, out_path='odf_slicer_3D.png', size=(1200, 900), reset_camera=False
+    )
+
+del show_m
+
+
+viz fiber odf

Total running time of the script: (0 minutes 1.238 seconds)

+ +

Gallery generated by Sphinx-Gallery

+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/auto_examples/04_demos/viz_fine_tuning_gl_context.html b/v0.10.x/auto_examples/04_demos/viz_fine_tuning_gl_context.html new file mode 100644 index 000000000..c3cf60798 --- /dev/null +++ b/v0.10.x/auto_examples/04_demos/viz_fine_tuning_gl_context.html @@ -0,0 +1,652 @@ + + + + + + + + Fine-tuning the OpenGL state using shader callbacks — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +
+

Fine-tuning the OpenGL state using shader callbacks#

+

Sometimes we need to get more control about how +OpenGL will render the actors. This example shows how to change the OpenGL +state of one or more actors. This can be useful when we need to create +specialized visualization effects.

+

First, let’s import some functions

+
import itertools
+
+import numpy as np
+
+from fury import actor, window
+from fury.shaders import shader_apply_effects
+from fury.utils import remove_observer_from_actor
+
+
+

We just proceed as usual: creating the actors and initializing a scene in +FURY

+
centers = np.array([[0, 0, 0], [-0.1, 0, 0], [0.1, 0, 0]])
+colors = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]])
+
+actor_no_depth_test = actor.markers(
+    centers,
+    marker='s',
+    colors=colors,
+    marker_opacity=0.5,
+    scales=0.2,
+)
+actor_normal_blending = actor.markers(
+    centers - np.array([[0, -0.5, 0]]),
+    marker='s',
+    colors=colors,
+    marker_opacity=0.5,
+    scales=0.2,
+)
+actor_add_blending = actor.markers(
+    centers - np.array([[0, -1, 0]]),
+    marker='s',
+    colors=colors,
+    marker_opacity=0.5,
+    scales=0.2,
+)
+
+actor_sub_blending = actor.markers(
+    centers - np.array([[0, -1.5, 0]]),
+    marker='s',
+    colors=colors,
+    marker_opacity=0.5,
+    scales=0.2,
+)
+actor_mul_blending = actor.markers(
+    centers - np.array([[0, -2, 0]]),
+    marker='s',
+    colors=colors,
+    marker_opacity=0.5,
+    scales=0.2,
+)
+
+
+scene = window.Scene()
+
+
+scene.background((0.5, 0.5, 0.5))
+showm = window.ShowManager(
+    scene, size=(900, 768), reset_camera=False, order_transparent=False
+)
+
+
+

All actors must be added in the scene

+
scene.add(actor_no_depth_test)
+scene.add(actor_normal_blending)
+scene.add(actor_add_blending)
+scene.add(actor_sub_blending)
+scene.add(actor_mul_blending)
+
+
+

Now, we will enter in the topic of this example. First, we need to create +(or use one of the pre-built gl_function of FURY) to +change the OpenGL state of a given fury window instance (showm.window).

+

Here we’re using the pre-build FURY window functions which has already a +set of specific behaviors to be applied in the OpenGL context

+
shader_apply_effects(
+    showm.window, actor_normal_blending, effects=window.gl_set_normal_blending
+)
+
+# ###############################################################################
+#  It's also possible use a list of effects. The final opengl state it'll
+#  be the composition of each effect that each function has in the opengl state
+
+id_observer = shader_apply_effects(
+    showm.window,
+    actor_no_depth_test,
+    effects=[window.gl_reset_blend, window.gl_disable_blend, window.gl_disable_depth],
+)
+
+shader_apply_effects(
+    showm.window,
+    actor_add_blending,
+    effects=[
+        window.gl_reset_blend,
+        window.gl_enable_depth,
+        window.gl_set_additive_blending,
+    ],
+)
+
+shader_apply_effects(
+    showm.window, actor_sub_blending, effects=window.gl_set_subtractive_blending
+)
+
+shader_apply_effects(
+    showm.window, actor_mul_blending, effects=window.gl_set_multiplicative_blending
+)
+
+
+
5
+
+
+

Finally, just render and see the results

+
counter = itertools.count()
+
+# After some steps we will remove the no_depth_test effect
+
+
+def timer_callback(obj, event):
+    cnt = next(counter)
+    showm.render()
+    # we will rotate the visualization just to help you to see
+    # the results of each specific opengl-state
+    showm.scene.azimuth(1)
+    if cnt == 400:
+        remove_observer_from_actor(actor_no_depth_test, id_observer)
+        shader_apply_effects(
+            showm.window, actor_no_depth_test, effects=window.gl_set_additive_blending
+        )
+    if cnt == 1000:
+        showm.exit()
+
+
+interactive = False
+showm.add_timer_callback(interactive, 5, timer_callback)
+if interactive:
+    showm.start()
+
+window.record(scene, out_path='viz_fine_tuning_gl_context.png', size=(600, 600))
+
+
+viz fine tuning gl context

Total running time of the script: (0 minutes 0.086 seconds)

+ +

Gallery generated by Sphinx-Gallery

+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/auto_examples/04_demos/viz_fractals.html b/v0.10.x/auto_examples/04_demos/viz_fractals.html new file mode 100644 index 000000000..5a939d94d --- /dev/null +++ b/v0.10.x/auto_examples/04_demos/viz_fractals.html @@ -0,0 +1,776 @@ + + + + + + + + Fractals — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +
+

Fractals#

+

Fractals are geometric structures that are self-similar at any scale. These +structures are easy to generate using recursion. In this demo, we’ll be +implementing the following fractals:

+
    +
  • Sierpinski Tetrahedron or Tetrix

  • +
  • Menger Sponge

  • +
  • Moseley Snowflake

  • +
+

Let’s begin by importing some necessary modules. We need fury.primitive to +avoid having to hardcode the geometry of a tetrahedron and a cube. +fury.utils also contains a repeat_primitive function which we will use +for this demo.

+
import math
+
+import numpy as np
+
+from fury import primitive, ui, utils, window
+
+
+

Before we create our first fractal, let’s set some ground rules for us to +work with.

+

1. Instead of creating a new actor to represent each primitive of the +fractal, we will compute the centers of each primitive and draw them at once +using repeat_primitive().

+

2. How many primitives do we need? For each fractal, we define a depth which +will prevent infinite recursion. Assuming we have a depth of \(N\), and +at each level the shape is divided into \(k\) smaller parts, we will need +\(k^{N}\) primitives to represent the fractal.

+

3. Ideally, we want to allocate the array of centers upfront. To achieve +this, we can use the method of representing a binary tree in an array, and +extend it to work with k-ary trees (formulas for the same can be found +here). In this scheme of representation, we represent every primitive as a +node, and each sub-primitive as a child node. We can also skip storing the +first \(\frac{k^{N} - 1}{k - 1} + 1\) entries as we only need to render +the leaf nodes. This allows us to create an array of exactly the required +size at the start, without any additional overhead.

+
+

The tetrix is a classic 3d fractal, a natural three-dimensional extension of +the Sierpinski Triangle. At each level, we need to calculate the new centers +for the next level. We can use the vertices of a tetrahedron as the offsets +for the new centers, provided that the tetrahedron is centered at the origin +(which is the case here).

+
def tetrix(N):
+    centers = np.zeros((4**N, 3))
+
+    # skipping non-leaf nodes (see above)
+    offset = (4**N - 1) // 3 + 1
+
+    # just need the vertices
+    U, _ = primitive.prim_tetrahedron()
+
+    def gen_centers(depth, pos, center, dist):
+        if depth == N:
+            centers[pos - offset] = center
+        else:
+            idx = 4 * (pos - 1) + 2
+            for i in range(4):
+                # distance gets halved at each level
+                gen_centers(depth + 1, idx + i, center + dist * U[i], dist / 2)
+
+    # the division by sqrt(6) is to ensure correct scale
+    gen_centers(0, 1, np.zeros(3), 2 / (6**0.5))
+
+    vertices, faces = primitive.prim_tetrahedron()
+
+    # primitive is scaled down depending on level
+    vertices /= 2 ** (N - 1)
+
+    # compute some pretty colors
+    bounds_min, bounds_max = np.min(centers, axis=0), np.max(centers, axis=0)
+    colors = (centers - bounds_min) / (bounds_max - bounds_min)
+
+    vertices, triangles, colors, _ = primitive.repeat_primitive(
+        centers=centers, colors=colors, vertices=vertices, faces=faces
+    )
+    return utils.get_actor_from_primitive(vertices, triangles, colors)
+
+
+

For a Menger Sponge, each cube is divided into 27 smaller cubes, and we skip +some of them (face centers, and the center of the cube). This means that on +every level we get 20 new cubes.

+

Here, to compute the points of each new center, we start at a corner cube’s +center and add the offsets to each smaller cube, scaled according to the +level.

+
def sponge(N):
+    centers = np.zeros((20**N, 3))
+    offset = (20**N - 1) // 19 + 1
+
+    # these are the offsets of the new centers at the next level of recursion
+    # each cube is divided into 20 smaller cubes for a snowflake
+    V = np.array(
+        [
+            [0, 0, 0],
+            [0, 0, 1],
+            [0, 0, 2],
+            [0, 1, 0],
+            [0, 1, 2],
+            [0, 2, 0],
+            [0, 2, 1],
+            [0, 2, 2],
+            [1, 0, 0],
+            [1, 0, 2],
+            [1, 2, 0],
+            [1, 2, 2],
+            [2, 0, 0],
+            [2, 0, 1],
+            [2, 0, 2],
+            [2, 1, 0],
+            [2, 1, 2],
+            [2, 2, 0],
+            [2, 2, 1],
+            [2, 2, 2],
+        ]
+    )
+
+    def gen_centers(depth, pos, center, dist):
+        if depth == N:
+            centers[pos - offset] = center
+        else:
+            # we consider a corner cube as our starting point
+            start = center - np.array([1, 1, 1]) * dist**0.5
+            idx = 20 * (pos - 1) + 2
+
+            # this moves from the corner cube to each new cube's center
+            for i in range(20):
+                # each cube is divided into 27 cubes so side gets divided by 3
+                gen_centers(depth + 1, idx + i, start + V[i] * dist, dist / 3)
+
+    gen_centers(0, 1, np.zeros(3), 1 / 3)
+
+    vertices, faces = primitive.prim_box()
+    vertices /= 3**N
+
+    bounds_min, bounds_max = np.min(centers, axis=0), np.max(centers, axis=0)
+    colors = (centers - bounds_min) / (bounds_max - bounds_min)
+
+    vertices, triangles, colors, _ = primitive.repeat_primitive(
+        centers=centers, colors=colors, vertices=vertices, faces=faces
+    )
+    return utils.get_actor_from_primitive(vertices, triangles, colors)
+
+
+

A snowflake is exactly the same as above, but we skip different cubes +(corners and center). I think this looks quite interesting, and it is +possible to see the Koch snowflake if you position the camera just right.

+
def snowflake(N):
+    centers = np.zeros((18**N, 3))
+    offset = (18**N - 1) // 17 + 1
+    V = np.array(
+        [
+            [0, 0, 1],
+            [0, 1, 0],
+            [0, 1, 1],
+            [0, 1, 2],
+            [0, 2, 1],
+            [1, 0, 0],
+            [1, 0, 1],
+            [1, 0, 2],
+            [1, 1, 0],
+            [1, 1, 2],
+            [1, 2, 0],
+            [1, 2, 1],
+            [1, 2, 2],
+            [2, 0, 1],
+            [2, 1, 0],
+            [2, 1, 1],
+            [2, 1, 2],
+            [2, 2, 1],
+        ]
+    )
+
+    def gen_centers(depth, pos, center, side):
+        if depth == N:
+            centers[pos - offset] = center
+        else:
+            start = center - np.array([1, 1, 1]) * side**0.5
+            idx = 18 * (pos - 1) + 2
+            for i in range(18):
+                gen_centers(depth + 1, idx + i, start + V[i] * side, side / 3)
+
+    gen_centers(0, 1, np.zeros(3), 1 / 3)
+
+    vertices, faces = primitive.prim_box()
+    vertices /= 3**N
+
+    bounds_min, bounds_max = np.min(centers, axis=0), np.max(centers, axis=0)
+    colors = (centers - bounds_min) / (bounds_max - bounds_min)
+
+    vertices, triangles, colors, _ = primitive.repeat_primitive(
+        centers=centers, colors=colors, vertices=vertices, faces=faces
+    )
+    return utils.get_actor_from_primitive(vertices, triangles, colors)
+
+
+

Now that we have the functions to generate fractals, we can start setting up +the Scene and ShowManager.

+
scene = window.Scene()
+showmgr = window.ShowManager(scene, 'Fractals', (800, 800), reset_camera=True)
+
+
+

These values are what work nicely on my machine without lagging. If you have +a powerful machine, you could bump these up by around 2-3.

+
fractals = [tetrix(6), sponge(3), snowflake(3)]
+
+
+

We want to be able to switch between the three fractals. To achieve this +we’ll create a RadioButton and register a callback which will remove existing +fractals and add the selected one. This also resets the camera.

+
options = {
+    'Tetrix': 0,
+    'Sponge': 1,
+    'Snowflake': 2,
+}
+
+shape_chooser = ui.RadioButton(
+    options.keys(),
+    padding=10,
+    font_size=16,
+    checked_labels=['Tetrix'],
+    position=(10, 10),
+)
+
+
+def choose_shape(radio):
+    showmgr.scene.rm(*fractals)
+    showmgr.scene.add(fractals[options[radio.checked_labels[0]]])
+    showmgr.scene.reset_camera()
+
+
+shape_chooser.on_change = choose_shape
+
+# selected at start
+showmgr.scene.add(fractals[0])
+showmgr.scene.add(shape_chooser)
+
+
+

Let’s add some basic camera movement to make it look a little interesting. +We can use a callback here to update a counter and calculate the camera +positions using the counter. sin and cos are used here to make smooth +looping movements.

+
counter = 0
+
+
+def timer_callback(_obj, _event):
+    global counter
+    counter += 1
+    showmgr.scene.azimuth(math.sin(counter * 0.01))
+    showmgr.scene.elevation(math.cos(counter * 0.01) / 4)
+    showmgr.render()
+
+
+showmgr.add_timer_callback(True, 20, timer_callback)
+
+
+
4
+
+
+

Finally, show the window if running in interactive mode or render to an image +otherwise. This is needed for generating the documentation that you are +reading.

+
interactive = False
+if interactive:
+    showmgr.start()
+else:
+    window.record(showmgr.scene, out_path='fractals.png', size=(800, 800))
+
+
+viz fractals

Total running time of the script: (0 minutes 0.193 seconds)

+ +

Gallery generated by Sphinx-Gallery

+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/auto_examples/04_demos/viz_helical_motion.html b/v0.10.x/auto_examples/04_demos/viz_helical_motion.html new file mode 100644 index 000000000..c2661d5d2 --- /dev/null +++ b/v0.10.x/auto_examples/04_demos/viz_helical_motion.html @@ -0,0 +1,652 @@ + + + + + + + + Motion of a charged particle in a combined magnetic and electric field — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +
+

Motion of a charged particle in a combined magnetic and electric field#

+

A charged particle follows a curved path in a magnetic field. +In an electric field, the particle tends to accelerate in a direction +parallel/antiparallel to the electric field depending on the nature of +charge on the particle. In a combined electric and magnetic field, +the particle moves along a helical path.

+

In this animation, there’s a magnetic and an electric field present in +x +direction under whose influence the positively charged particle follows a +helical path.

+

Importing necessary modules

+
import itertools
+
+import numpy as np
+
+from fury import actor, ui, utils, window
+
+
+

Let’s define some variable and their description:

+
    +
  • radius_particle: radius of the point that will represent the particle +(default = 0.08)

  • +
  • initial_velocity: initial velocity of the particle along +x +(default = 0.09)

  • +
  • acc: acceleration of the particle along +x (due to the electric field) +(default = 0.004)

  • +
  • time: time (default time i.e. time at beginning of the animation = 0)

  • +
  • incre_time: value by which time is incremented for each call of +timer_callback (default = 0.09)

  • +
  • angular_frq: angular frequency (default = 0.1)

  • +
  • phase_angle: phase angle (default = 0.002)

  • +
+
radius_particle = 0.08
+initial_velocity = 0.09
+acc = 0.004
+time = 0
+incre_time = 0.09
+angular_frq = 0.1
+phase_angle = 0.002
+
+
+

Creating a scene object and configuring the camera’s position

+
scene = window.Scene()
+scene.zoom(1.2)
+scene.set_camera(
+    position=(10, 12.5, 19), focal_point=(3.0, 0.0, 0.0), view_up=(0.0, 0.0, 0.0)
+)
+showm = window.ShowManager(
+    scene, size=(800, 600), reset_camera=True, order_transparent=True
+)
+
+
+

Creating a blue colored arrow which shows the direction of magnetic field and +electric field.

+
color_arrow = window.colors.blue  # color of the arrow can be manipulated
+centers = np.array([[0, 0, 0]])
+directions = np.array([[1, 0, 0]])
+heights = np.array([8])
+arrow_actor = actor.arrow(
+    centers,
+    directions,
+    color_arrow,
+    heights,
+    resolution=20,
+    tip_length=0.06,
+    tip_radius=0.012,
+    shaft_radius=0.005,
+)
+scene.add(arrow_actor)
+
+
+

Initializing the initial coordinates of the particle

+ +

Initializing point actor which will represent the charged particle

+
color_particle = window.colors.red  # color of particle can be manipulated
+pts = np.array([[x, y, z]])
+charge_actor = actor.point(pts, color_particle, point_radius=radius_particle)
+scene.add(charge_actor)
+
+vertices = utils.vertices_from_actor(charge_actor)
+vcolors = utils.colors_from_actor(charge_actor, 'colors')
+no_vertices_per_point = len(vertices)
+initial_vertices = vertices.copy() - np.repeat(pts, no_vertices_per_point, axis=0)
+
+
+

Initializing text box to display the name of the animation

+
tb = ui.TextBlock2D(bold=True, position=(100, 90))
+m1 = 'Motion of a charged particle in a '
+m2 = 'combined electric and magnetic field'
+tb.message = m1 + m2
+scene.add(tb)
+
+
+

Initializing counter

+ +

end is used to decide when to end the animation

+
end = 200
+
+
+

This will be useful for plotting path of the particle

+
coor_1 = np.array([0, 0, 0])
+
+
+

Coordinates to be plotted are changed every time timer_callback is called by +using the update_coordinates function. The wave is rendered here.

+
def timer_callback(_obj, _event):
+    global pts, time, incre_time, coor_1
+    time += incre_time
+    cnt = next(counter)
+
+    x = initial_velocity * time + 0.5 * acc * (time**2)
+    y = np.sin(10 * angular_frq * time + phase_angle)
+    z = np.cos(10 * angular_frq * time + phase_angle)
+    pts = np.array([[x, y, z]])
+
+    vertices[:] = initial_vertices + np.repeat(pts, no_vertices_per_point, axis=0)
+
+    utils.update_actor(charge_actor)
+
+    # Plotting the path followed by the particle
+    coor_2 = np.array([x, y, z])
+    coors = np.array([coor_1, coor_2])
+    coors = [coors]
+    line_actor = actor.line(coors, window.colors.cyan, linewidth=3)
+    scene.add(line_actor)
+    coor_1 = coor_2
+
+    showm.render()
+
+    # to end the animation
+    if cnt == end:
+        showm.exit()
+
+
+

Run every 15 milliseconds

+
showm.add_timer_callback(True, 15, timer_callback)
+showm.start()
+window.record(showm.scene, size=(800, 600), out_path='viz_helical_motion.png')
+
+
+viz helical motion

Total running time of the script: (0 minutes 4.550 seconds)

+ +

Gallery generated by Sphinx-Gallery

+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/auto_examples/04_demos/viz_markers.html b/v0.10.x/auto_examples/04_demos/viz_markers.html new file mode 100644 index 000000000..98e860b7f --- /dev/null +++ b/v0.10.x/auto_examples/04_demos/viz_markers.html @@ -0,0 +1,558 @@ + + + + + + + + Fury Markers — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +
+

Fury Markers#

+

This example shows how to use the marker actor.

+
import numpy as np
+
+from fury import actor, window
+
+n = 10000
+
+
+

There are nine types 2d markers: circle, square, diamond, triangle, pentagon, +hexagon, heptagon, cross and plus.

+
marker_symbols = ['o', 's', 'd', '^', 'p', 'h', 's6', 'x', '+']
+markers = [np.random.choice(marker_symbols) for i in range(n)]
+
+centers = np.random.normal(size=(n, 3), scale=10)
+
+colors = np.random.uniform(size=(n, 3))
+
+
+

You can control the edge color and edge width for each marker

+
nodes_actor = actor.markers(
+    centers,
+    marker=markers,
+    edge_width=0.1,
+    edge_color=[255, 255, 0],
+    colors=colors,
+    scales=0.5,
+)
+
+
+

In addition, an 3D sphere it’s also a valid type of marker

+
nodes_3d_actor = actor.markers(
+    centers + np.ones_like(centers) * 25,
+    marker='3d',
+    colors=colors,
+    scales=0.5,
+)
+
+scene = window.Scene()
+
+scene.add(nodes_actor)
+scene.add(nodes_3d_actor)
+
+interactive = False
+
+if interactive:
+    window.show(scene, size=(600, 600))
+
+window.record(scene, out_path='viz_markers.png', size=(600, 600))
+
+
+viz markers

Total running time of the script: (0 minutes 0.137 seconds)

+ +

Gallery generated by Sphinx-Gallery

+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/auto_examples/04_demos/viz_network.html b/v0.10.x/auto_examples/04_demos/viz_network.html new file mode 100644 index 000000000..23ba97f8d --- /dev/null +++ b/v0.10.x/auto_examples/04_demos/viz_network.html @@ -0,0 +1,603 @@ + + + + + + + + Visualize Interdisciplinary map of the journals network — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +
+

Visualize Interdisciplinary map of the journals network#

+

The goal of this app is to show an overview of the journals network structure +as a complex network. Each journal is shown as a node and their connections +indicates a citation between two of them.

+

First, let’s import some useful functions

+
from os.path import join as pjoin
+
+import numpy as np
+
+from fury import actor
+from fury import colormap as cmap
+from fury import window
+from fury.data import fetch_viz_wiki_nw
+
+
+

Then let’s download some available datasets.

+
files, folder = fetch_viz_wiki_nw()
+categories_file, edges_file, positions_file = sorted(files.keys())
+
+
+
Dataset is already in place. If you want to fetch it again please first remove the folder /Users/skoudoro/.fury/examples/wiki_nw
+More information about complex networks can be found in this papers: https://arxiv.org/abs/0711.3199
+
+
+

We read our datasets

+ +

We attribute a color to each category of our dataset which correspond to our +nodes colors.

+
category2index = {category: i for i, category in enumerate(np.unique(categories))}
+
+index2category = np.unique(categories)
+
+categoryColors = cmap.distinguishable_colormap(nb_colors=len(index2category))
+
+colors = np.array([categoryColors[category2index[category]] for category in categories])
+
+
+

We define our node size

+ +

Lets create our edges now. They will indicate a citation between two nodes. +OF course, the colors of each edges will be an interpolation between the two +node that it connects.

+ +

Our data preparation is ready, it is time to visualize them all. We start to +build 2 actors that we represent our data : sphere_actor for the nodes and +lines_actor for the edges.

+
sphere_actor = actor.sphere(
+    centers=positions,
+    colors=colors,
+    radii=radii * 0.5,
+    theta=8,
+    phi=8,
+)
+
+lines_actor = actor.line(
+    edgesPositions,
+    colors=edgesColors,
+    opacity=0.1,
+)
+
+
+

All actors need to be added in a scene, so we build one and add our +lines_actor and sphere_actor.

+
scene = window.Scene()
+
+scene.add(lines_actor)
+scene.add(sphere_actor)
+
+
+

The final step ! Visualize and save the result of our creation! Please, +switch interactive variable to True if you want to visualize it.

+
interactive = False
+
+if interactive:
+    window.show(scene, size=(600, 600))
+
+window.record(scene, out_path='journal_networks.png', size=(600, 600))
+
+
+viz network

This example can be improved by adding some interactivy with slider, +picking, etc. Play with it, improve it!

+

Total running time of the script: (0 minutes 0.809 seconds)

+ +

Gallery generated by Sphinx-Gallery

+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/auto_examples/04_demos/viz_network_animated.html b/v0.10.x/auto_examples/04_demos/viz_network_animated.html new file mode 100644 index 000000000..1ac5bf968 --- /dev/null +++ b/v0.10.x/auto_examples/04_demos/viz_network_animated.html @@ -0,0 +1,745 @@ + + + + + + + + Visualize Networks (Animated version) — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +
+

Visualize Networks (Animated version)#

+

The goal of this demo is to show how to visualize a +complex network and use an force directed algorithm to +layout the network. A simpler animation of the network +made by adding some random displacements to nodes +positions is also demoed.

+

First, let’s import some useful functions

+
import math
+from os.path import join as pjoin
+
+import numpy as np
+
+from fury import actor
+from fury import colormap as cmap
+from fury import window
+from fury.utils import compute_bounds, update_actor, vertices_from_actor
+
+
+

This demo has two modes. +Use mode = 0 to visualize a randomly generated geographic network by +iterating it using a force-directed layout heuristic.

+

Use mode = 1 to visualize a large network being animated with random +displacements

+
mode = 0
+
+
+

Then let’s download some available datasets. (mode 1)

+
if mode == 1:
+    from fury.data.fetcher import fetch_viz_wiki_nw
+
+    files, folder = fetch_viz_wiki_nw()
+    categories_file, edges_file, positions_file = sorted(files.keys())
+
+
+

We read our datasets (mode 1)

+
if mode == 1:
+    positions = np.loadtxt(pjoin(folder, positions_file))
+    categories = np.loadtxt(pjoin(folder, categories_file), dtype=str)
+    edges = np.loadtxt(pjoin(folder, edges_file), dtype=int)
+    vertices_count = len(positions)
+
+
+

Generate a geographic random network, requires networkx package (mode 0)

+
if mode == 0:
+    import networkx as nx
+
+    vertices_count = 100
+    view_size = 100
+    network = nx.random_geometric_graph(vertices_count, 0.2)
+    positions = view_size * np.random.random((vertices_count, 3)) - view_size / 2.0
+    categories = np.arange(0, vertices_count)
+    edges = np.array(network.edges())
+    positions = view_size * np.random.random((vertices_count, 3)) - view_size / 2.0
+
+
+

We attribute a color to each category of our dataset which correspond to our +nodes colors.

+
category2index = {category: i for i, category in enumerate(np.unique(categories))}
+
+index2category = np.unique(categories)
+
+category_colors = cmap.distinguishable_colormap(nb_colors=len(index2category))
+
+colors = np.array(
+    [category_colors[category2index[category]] for category in categories]
+)
+
+
+

We define our node size

+ +

Let’s create our edges now. They will indicate a citation between two nodes. +The colors of each edge are interpolated between the two endpoints.

+ +

Our data preparation is ready, it is time to visualize them all. We start to +build 2 actors that we represent our data : sphere_actor for the nodes and +lines_actor for the edges.

+
sphere_actor = actor.sphere(
+    centers=np.zeros(positions.shape), colors=colors, radii=radii * 0.5, theta=8, phi=8
+)
+
+
+lines_actor = actor.line(
+    np.zeros((len(edges), 2, 3)),
+    colors=edges_colors,
+    lod=False,
+    fake_tube=True,
+    linewidth=3,
+)
+
+
+

Defining timer callback and layout iterator

+
def new_layout_timer(
+    showm,
+    edges_list,
+    vertices_count,
+    max_iterations=1000,
+    vertex_initial_positions=None,
+):
+    view_size = 500
+    viscosity = 0.10
+    alpha = 0.5
+    a = 0.0005
+    b = 1.0
+    deltaT = 1.0
+
+    sphere_geometry = np.array(vertices_from_actor(sphere_actor))
+    geometry_length = sphere_geometry.shape[0] / vertices_count
+
+    if vertex_initial_positions is not None:
+        pos = np.array(vertex_initial_positions)
+    else:
+        pos = view_size * np.random.random((vertices_count, 3)) - view_size / 2.0
+
+    velocities = np.zeros((vertices_count, 3))
+
+    def iterate(iterationCount):
+        nonlocal pos, velocities
+        for _ in range(iterationCount):
+            forces = np.zeros((vertices_count, 3))
+            # repulstive forces
+            for vertex1 in range(vertices_count):
+                for vertex2 in range(vertex1):
+                    x1, y1, z1 = pos[vertex1]
+                    x2, y2, z2 = pos[vertex2]
+                    distance = (
+                        math.sqrt(
+                            (x2 - x1) * (x2 - x1)
+                            + (y2 - y1) * (y2 - y1)
+                            + (z2 - z1) * (z2 - z1)
+                        )
+                        + alpha
+                    )
+                    rx = (x2 - x1) / distance
+                    ry = (y2 - y1) / distance
+                    rz = (z2 - z1) / distance
+                    Fx = -b * rx / distance / distance
+                    Fy = -b * ry / distance / distance
+                    Fz = -b * rz / distance / distance
+                    forces[vertex1] += np.array([Fx, Fy, Fz])
+                    forces[vertex2] -= np.array([Fx, Fy, Fz])
+            # attractive forces
+            for vFrom, vTo in edges_list:
+                if vFrom == vTo:
+                    continue
+                x1, y1, z1 = pos[vFrom]
+                x2, y2, z2 = pos[vTo]
+                distance = math.sqrt(
+                    (x2 - x1) * (x2 - x1)
+                    + (y2 - y1) * (y2 - y1)
+                    + (z2 - z1) * (z2 - z1)
+                )
+                Rx = x2 - x1
+                Ry = y2 - y1
+                Rz = z2 - z1
+                Fx = a * Rx * distance
+                Fy = a * Ry * distance
+                Fz = a * Rz * distance
+                forces[vFrom] += np.array([Fx, Fy, Fz])
+                forces[vTo] -= np.array([Fx, Fy, Fz])
+            velocities += forces * deltaT
+            velocities *= 1.0 - viscosity
+            pos += velocities * deltaT
+        pos[:, 0] -= np.mean(pos[:, 0])
+        pos[:, 1] -= np.mean(pos[:, 1])
+        pos[:, 2] -= np.mean(pos[:, 2])
+
+    counter = 0
+
+    def _timer(_obj, _event):
+        nonlocal counter, pos
+        counter += 1
+        if mode == 0:
+            iterate(1)
+        else:
+            pos[:] += (np.random.random(pos.shape) - 0.5) * 1.5
+        spheres_positions = vertices_from_actor(sphere_actor)
+        spheres_positions[:] = sphere_geometry + np.repeat(pos, geometry_length, axis=0)
+
+        edges_positions = vertices_from_actor(lines_actor)
+        edges_positions[::2] = pos[edges_list[:, 0]]
+        edges_positions[1::2] = pos[edges_list[:, 1]]
+
+        update_actor(lines_actor)
+        compute_bounds(lines_actor)
+
+        update_actor(sphere_actor)
+        compute_bounds(lines_actor)
+        showm.scene.reset_clipping_range()
+        showm.render()
+
+        if counter >= max_iterations:
+            showm.exit()
+
+    return _timer
+
+
+

All actors need to be added in a scene, so we build one and add our +lines_actor and sphere_actor.

+
scene = window.Scene()
+
+camera = scene.camera()
+
+scene.add(lines_actor)
+scene.add(sphere_actor)
+
+
+

The final step! Visualize the result of our creation! Also, we need to move +the camera a little bit farther from the network. you can increase the +parameter max_iteractions of the timer callback to let the animation run for +more time.

+
showm = window.ShowManager(
+    scene, reset_camera=False, size=(900, 768), order_transparent=True, multi_samples=8
+)
+
+
+scene.set_camera(position=(0, 0, -300))
+
+timer_callback = new_layout_timer(
+    showm, edges, vertices_count, max_iterations=200, vertex_initial_positions=positions
+)
+
+
+# Run every 16 milliseconds
+showm.add_timer_callback(True, 16, timer_callback)
+
+showm.start()
+
+window.record(showm.scene, size=(900, 768), out_path='viz_animated_networks.png')
+
+
+viz network animated

Total running time of the script: (0 minutes 7.015 seconds)

+ +

Gallery generated by Sphinx-Gallery

+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/auto_examples/04_demos/viz_pbr_interactive.html b/v0.10.x/auto_examples/04_demos/viz_pbr_interactive.html new file mode 100644 index 000000000..a9d8c7002 --- /dev/null +++ b/v0.10.x/auto_examples/04_demos/viz_pbr_interactive.html @@ -0,0 +1,829 @@ + + + + + + + + Interactive PBR demo — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +
+

Interactive PBR demo#

+

This is a demonstration of how Physically-Based Rendering (PBR) can be used to +simulate different materials.

+

Let’s start by importing the necessary modules:

+
from fury import actor, material, ui, window
+from fury.data import fetch_viz_cubemaps, read_viz_cubemap
+from fury.io import load_cubemap_texture
+from fury.utils import (
+    normals_from_actor,
+    tangents_from_direction_of_anisotropy,
+    tangents_to_actor,
+)
+
+
+

The following functions will help us to manage the sliders events.

+
def change_slice_metallic(slider):
+    global pbr_params
+    pbr_params.metallic = slider.value
+
+
+def change_slice_roughness(slider):
+    global pbr_params
+    pbr_params.roughness = slider.value
+
+
+def change_slice_anisotropy(slider):
+    global pbr_params
+    pbr_params.anisotropy = slider.value
+
+
+def change_slice_anisotropy_direction_x(slider):
+    global doa, normals, sphere
+    doa[0] = slider.value
+    tangents = tangents_from_direction_of_anisotropy(normals, doa)
+    tangents_to_actor(sphere, tangents)
+
+
+def change_slice_anisotropy_direction_y(slider):
+    global doa, normals, sphere
+    doa[1] = slider.value
+    tangents = tangents_from_direction_of_anisotropy(normals, doa)
+    tangents_to_actor(sphere, tangents)
+
+
+def change_slice_anisotropy_direction_z(slider):
+    global doa, normals, sphere
+    doa[2] = slider.value
+    tangents = tangents_from_direction_of_anisotropy(normals, doa)
+    tangents_to_actor(sphere, tangents)
+
+
+def change_slice_anisotropy_rotation(slider):
+    global pbr_params
+    pbr_params.anisotropy_rotation = slider.value
+
+
+def change_slice_coat_strength(slider):
+    global pbr_params
+    pbr_params.coat_strength = slider.value
+
+
+def change_slice_coat_roughness(slider):
+    global pbr_params
+    pbr_params.coat_roughness = slider.value
+
+
+def change_slice_base_ior(slider):
+    global pbr_params
+    pbr_params.base_ior = slider.value
+
+
+def change_slice_coat_ior(slider):
+    global pbr_params
+    pbr_params.coat_ior = slider.value
+
+
+

Last, but not least, we define the following function to help us to +reposition the UI elements every time we resize the window.

+
def win_callback(obj, event):
+    global control_panel, size
+    if size != obj.GetSize():
+        size_old = size
+        size = obj.GetSize()
+        size_change = [size[0] - size_old[0], 0]
+        control_panel.re_align(size_change)
+
+
+

Let’s fetch a skybox texture from the FURY data repository.

+
fetch_viz_cubemaps()
+
+
+
Dataset is already in place. If you want to fetch it again please first remove the folder /Users/skoudoro/.fury/cubemaps
+
+({'skybox-nx.jpg': ('https://raw.githubusercontent.com/fury-gl/fury-data/master/cubemaps/skybox-nx.jpg', '12B1CE6C91AA3AAF258A8A5944DF739A6C1CC76E89D4D7119D1F795A30FC1BF2'), 'skybox-ny.jpg': ('https://raw.githubusercontent.com/fury-gl/fury-data/master/cubemaps/skybox-ny.jpg', 'E18FE2206B63D3DF2C879F5E0B9937A61D99734B6C43AC288226C58D2418D23E'), 'skybox-nz.jpg': ('https://raw.githubusercontent.com/fury-gl/fury-data/master/cubemaps/skybox-nz.jpg', '00DDDD1B715D5877AF2A74C014FF6E47891F07435B471D213CD0673A8C47F2B2'), 'skybox-px.jpg': ('https://raw.githubusercontent.com/fury-gl/fury-data/master/cubemaps/skybox-px.jpg', 'BF20ACD6817C9E7073E485BBE2D2CE56DACFF73C021C2B613BA072BA2DF2B754'), 'skybox-py.jpg': ('https://raw.githubusercontent.com/fury-gl/fury-data/master/cubemaps/skybox-py.jpg', '16F0D692AF0B80E46929D8D8A7E596123C76729CC5EB7DFD1C9184B115DD143A'), 'skybox-pz.jpg': ('https://raw.githubusercontent.com/fury-gl/fury-data/master/cubemaps/skybox-pz.jpg', 'B850B5E882889DF26BE9289D7C25BA30524B37E56BC2075B968A83197AD977F3')}, '/Users/skoudoro/.fury/cubemaps')
+
+
+

The following function returns the full path of the 6 images composing the +skybox.

+
textures = read_viz_cubemap('skybox')
+
+
+

Now that we have the location of the textures, let’s load them and create a +Cube Map Texture object.

+ +

The Scene object in FURY can handle cube map textures and extract light +information from them, so it can be used to create more plausible materials +interactions. The skybox parameter takes as input a cube map texture and +performs the previously described process.

+
scene = window.Scene(skybox=cubemap)
+
+
+

With the scene created, we can then populate it. In this demo we will only +add a sphere actor.

+
sphere = actor.sphere([[0, 0, 0]], (0.7, 0.7, 0.7), radii=2, theta=64, phi=64)
+
+
+

The direction of anisotropy (DoA) defines the direction at which all the +tangents of our actor are pointing.

+
doa = [0, 1, 0.5]
+
+
+

The following process gets the normals of the actor and computes the tangents +that are aligned to the provided DoA. Then it registers those tangents to the +actor.

+ +
<vtkmodules.vtkRenderingOpenGL2.vtkOpenGLActor(0x2a1ad4b90) at 0x2a19ccb20>
+
+
+

With the tangents computed and in place, we have all the elements needed to +add some material properties to the actor.

+
pbr_params = material.manifest_pbr(sphere)
+
+
+

Our actor is now ready to be added to the scene.

+
scene.add(sphere)
+
+
+

Let’s setup now the window and the UI.

+
show_m = window.ShowManager(
+    scene=scene, size=(1920, 1080), reset_camera=False, order_transparent=True
+)
+
+
+

We will create one single panel with all of our labels and sliders.

+
control_panel = ui.Panel2D(
+    (400, 500), position=(5, 5), color=(0.25, 0.25, 0.25), opacity=0.75, align='right'
+)
+
+
+

By using our previously defined function, we can easily create all the labels +we need for this demo. And then add them to the panel.

+
slider_label_metallic = ui.TextBlock2D(text='Metallic', font_size=16)
+slider_label_roughness = ui.TextBlock2D(text='Roughness', font_size=16)
+slider_label_anisotropy = ui.TextBlock2D(text='Anisotropy', font_size=16)
+slider_label_anisotropy_rotation = ui.TextBlock2D(
+    text='Anisotropy Rotation', font_size=16
+)
+slider_label_anisotropy_direction_x = ui.TextBlock2D(
+    text='Anisotropy Direction X', font_size=16
+)
+slider_label_anisotropy_direction_y = ui.TextBlock2D(
+    text='Anisotropy Direction Y', font_size=16
+)
+slider_label_anisotropy_direction_z = ui.TextBlock2D(
+    text='Anisotropy Direction Z', font_size=16
+)
+slider_label_coat_strength = ui.TextBlock2D(text='Coat Strength', font_size=16)
+slider_label_coat_roughness = ui.TextBlock2D(text='Coat Roughness', font_size=16)
+slider_label_base_ior = ui.TextBlock2D(text='Base IoR', font_size=16)
+slider_label_coat_ior = ui.TextBlock2D(text='Coat IoR', font_size=16)
+
+control_panel.add_element(slider_label_metallic, (0.01, 0.95))
+control_panel.add_element(slider_label_roughness, (0.01, 0.86))
+control_panel.add_element(slider_label_anisotropy, (0.01, 0.77))
+control_panel.add_element(slider_label_anisotropy_rotation, (0.01, 0.68))
+control_panel.add_element(slider_label_anisotropy_direction_x, (0.01, 0.59))
+control_panel.add_element(slider_label_anisotropy_direction_y, (0.01, 0.5))
+control_panel.add_element(slider_label_anisotropy_direction_z, (0.01, 0.41))
+control_panel.add_element(slider_label_coat_strength, (0.01, 0.32))
+control_panel.add_element(slider_label_coat_roughness, (0.01, 0.23))
+control_panel.add_element(slider_label_base_ior, (0.01, 0.14))
+control_panel.add_element(slider_label_coat_ior, (0.01, 0.05))
+
+
+

Our sliders are created and added to the panel in the following way.

+
slider_slice_metallic = ui.LineSlider2D(
+    initial_value=pbr_params.metallic,
+    max_value=1,
+    length=195,
+    text_template='{value:.1f}',
+)
+slider_slice_roughness = ui.LineSlider2D(
+    initial_value=pbr_params.roughness,
+    max_value=1,
+    length=195,
+    text_template='{value:.1f}',
+)
+slider_slice_anisotropy = ui.LineSlider2D(
+    initial_value=pbr_params.anisotropy,
+    max_value=1,
+    length=195,
+    text_template='{value:.1f}',
+)
+slider_slice_anisotropy_rotation = ui.LineSlider2D(
+    initial_value=pbr_params.anisotropy_rotation,
+    max_value=1,
+    length=195,
+    text_template='{value:.1f}',
+)
+slider_slice_coat_strength = ui.LineSlider2D(
+    initial_value=pbr_params.coat_strength,
+    max_value=1,
+    length=195,
+    text_template='{value:.1f}',
+)
+slider_slice_coat_roughness = ui.LineSlider2D(
+    initial_value=pbr_params.coat_roughness,
+    max_value=1,
+    length=195,
+    text_template='{value:.1f}',
+)
+
+
+

Notice that we are defining a range of [-1, 1] for the DoA. This is because +within that range we cover all the possible 3D directions needed to align the +tangents.

+
slider_slice_anisotropy_direction_x = ui.LineSlider2D(
+    initial_value=doa[0],
+    min_value=-1,
+    max_value=1,
+    length=195,
+    text_template='{value:.1f}',
+)
+slider_slice_anisotropy_direction_y = ui.LineSlider2D(
+    initial_value=doa[1],
+    min_value=-1,
+    max_value=1,
+    length=195,
+    text_template='{value:.1f}',
+)
+slider_slice_anisotropy_direction_z = ui.LineSlider2D(
+    initial_value=doa[2],
+    min_value=-1,
+    max_value=1,
+    length=195,
+    text_template='{value:.1f}',
+)
+
+
+

Another special case are the Index of Refraction (IoR) sliders. In these +cases, the values are defined in the range [1, 2.3] according to the +documentation of the material.

+
slider_slice_base_ior = ui.LineSlider2D(
+    initial_value=pbr_params.base_ior,
+    min_value=1,
+    max_value=2.3,
+    length=195,
+    text_template='{value:.02f}',
+)
+slider_slice_coat_ior = ui.LineSlider2D(
+    initial_value=pbr_params.coat_ior,
+    min_value=1,
+    max_value=2.3,
+    length=195,
+    text_template='{value:.02f}',
+)
+
+
+

Let’s add the event handlers functions to the corresponding sliders.

+
slider_slice_metallic.on_change = change_slice_metallic
+slider_slice_roughness.on_change = change_slice_roughness
+slider_slice_anisotropy.on_change = change_slice_anisotropy
+slider_slice_anisotropy_rotation.on_change = change_slice_anisotropy_rotation
+slider_slice_anisotropy_direction_x.on_change = change_slice_anisotropy_direction_x
+slider_slice_anisotropy_direction_y.on_change = change_slice_anisotropy_direction_y
+slider_slice_anisotropy_direction_z.on_change = change_slice_anisotropy_direction_z
+slider_slice_coat_strength.on_change = change_slice_coat_strength
+slider_slice_coat_roughness.on_change = change_slice_coat_roughness
+slider_slice_base_ior.on_change = change_slice_base_ior
+slider_slice_coat_ior.on_change = change_slice_coat_ior
+
+
+

And then add the sliders to the panel.

+
control_panel.add_element(slider_slice_metallic, (0.44, 0.95))
+control_panel.add_element(slider_slice_roughness, (0.44, 0.86))
+control_panel.add_element(slider_slice_anisotropy, (0.44, 0.77))
+control_panel.add_element(slider_slice_anisotropy_rotation, (0.44, 0.68))
+control_panel.add_element(slider_slice_anisotropy_direction_x, (0.44, 0.59))
+control_panel.add_element(slider_slice_anisotropy_direction_y, (0.44, 0.5))
+control_panel.add_element(slider_slice_anisotropy_direction_z, (0.44, 0.41))
+control_panel.add_element(slider_slice_coat_strength, (0.44, 0.32))
+control_panel.add_element(slider_slice_coat_roughness, (0.44, 0.23))
+control_panel.add_element(slider_slice_base_ior, (0.44, 0.14))
+control_panel.add_element(slider_slice_coat_ior, (0.44, 0.05))
+
+
+

Consequently, we add the panel to the scene.

+
scene.add(control_panel)
+
+
+

Previously we defined a function to help us when we resize the window, so +let’s capture the current size and add our helper function as a +window_callback to the window.

+
size = scene.GetSize()
+
+show_m.add_window_callback(win_callback)
+
+
+

Finally, let’s visualize our demo.

+
interactive = False
+if interactive:
+    show_m.start()
+
+window.record(scene, size=(1920, 1080), out_path='viz_pbr_interactive.png')
+
+
+viz pbr interactive

Total running time of the script: (0 minutes 0.974 seconds)

+ +

Gallery generated by Sphinx-Gallery

+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/auto_examples/04_demos/viz_play_video.html b/v0.10.x/auto_examples/04_demos/viz_play_video.html new file mode 100644 index 000000000..fc7a7b69a --- /dev/null +++ b/v0.10.x/auto_examples/04_demos/viz_play_video.html @@ -0,0 +1,596 @@ + + + + + + + + Play a video in the 3D world — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +
+

Play a video in the 3D world#

+

The goal of this demo is to show how to visualize a video +on a rectangle by updating a texture.

+viz play video
import time
+
+import cv2
+import numpy as np
+
+from fury import actor, window
+
+
+# The VideoCapturer Class
+# This Class wraps OpenCV Videocapture
+class VideoCapturer:
+    def __init__(self, video, time):
+        self.path = video
+        self.video = cv2.VideoCapture(self.path)
+        self.fps = int(self.video.get(cv2.CAP_PROP_FPS))
+        self.frames = int(self.video.get(cv2.CAP_PROP_FRAME_COUNT))
+        self.time = time
+
+    # A generator to yield video frames on every call
+    def get_frame(self):
+        start = time.time()
+        for _ in range(self.frames):
+            isframe, frame = self.video.read()
+            dur = time.time() - start
+            if dur > self.time:
+                break
+            if isframe:
+                yield cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
+        self.video.release()
+        yield None
+
+
+class VideoPlayer:
+    def __init__(self, video, time=10):
+        # Initializes the Video object with the given Video
+        self.video = VideoCapturer(video, time)
+        self.video_generator = self.video.get_frame()
+        self.current_video_frame = next(self.video_generator)
+        # Initialize Scene
+        self.initialize_scene()
+        # Create a Show Manager and Initialize it
+        self.show_manager = window.ShowManager(
+            self.scene, size=(900, 768), reset_camera=False, order_transparent=True
+        )
+
+    # Initialize the Scene with actors
+    def initialize_scene(self):
+        self.scene = window.Scene()
+        # Initialize a Plane actor with the 1st video frame along with
+        # the actor grid which is to be updated in each iteration
+        self.plane_actor = actor.texture(self.current_video_frame)
+        self.scene.add(self.plane_actor)
+
+    # The timer_callback function getting called by the show manager
+    def timer_callback(self, _obj, _event):
+        self.current_video_frame = next(self.video_generator)
+        if isinstance(self.current_video_frame, np.ndarray):
+            # update texture of the actor with the current frame image
+            # by updating the actor grid
+            actor.texture_update(self.plane_actor, self.current_video_frame)
+            self.show_manager.scene.azimuth(1.5)  # to rotate the camera
+        else:
+            self.show_manager.exit()
+
+        self.show_manager.render()
+
+    def run(self):
+        # Add a timer callback to show manager after with
+        # video frame duration as the interval
+        self.frame_duration = int(1000 / self.video.fps)
+        self.show_manager.add_timer_callback(
+            True, self.frame_duration, self.timer_callback
+        )
+        self.show_manager.start()
+
+
+# Create VideoPlayer Object and run it
+video_url = (
+    'http://commondatastorage.googleapis.com/'
+    + 'gtv-videos-bucket/sample/BigBuckBunny.mp4'
+)
+vp = VideoPlayer(video_url)
+vp.run()
+window.record(vp.show_manager.scene, out_path='viz_play_video.png', size=(600, 600))
+
+
+

Total running time of the script: (0 minutes 10.581 seconds)

+ +

Gallery generated by Sphinx-Gallery

+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/auto_examples/04_demos/viz_roi_contour.html b/v0.10.x/auto_examples/04_demos/viz_roi_contour.html new file mode 100644 index 000000000..992a331a4 --- /dev/null +++ b/v0.10.x/auto_examples/04_demos/viz_roi_contour.html @@ -0,0 +1,598 @@ + + + + + + + + Visualization of ROI Surface Rendered with Streamlines — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +
+

Visualization of ROI Surface Rendered with Streamlines#

+

Here is a simple tutorial following the probabilistic CSA Tracking Example in +which we generate a dataset of streamlines from a corpus callosum ROI, and +then display them with the seed ROI rendered in 3D with 50% transparency.

+
from dipy.data import default_sphere, read_stanford_labels
+from dipy.direction import peaks_from_model
+from dipy.reconst.shm import CsaOdfModel
+
+try:
+    from dipy.tracking.local import LocalTracking
+    from dipy.tracking.local import (
+        ThresholdTissueClassifier as ThresholdStoppingCriterion,
+    )
+except ImportError:
+    from dipy.tracking.stopping_criterion import ThresholdStoppingCriterion
+    from dipy.tracking.local_tracking import LocalTracking
+
+from dipy.tracking import utils
+from dipy.tracking.streamline import Streamlines
+
+from fury import actor, window
+from fury.colormap import line_colors
+
+
+

First, we need to generate some streamlines. For a more complete +description of these steps, please refer to the CSA Probabilistic Tracking +Tutorial.

+
hardi_img, gtab, labels_img = read_stanford_labels()
+data = hardi_img.get_fdata()
+labels = labels_img.get_fdata()
+affine = hardi_img.affine
+
+white_matter = (labels == 1) | (labels == 2)
+
+csa_model = CsaOdfModel(gtab, sh_order=6)
+csa_peaks = peaks_from_model(
+    csa_model,
+    data,
+    default_sphere,
+    relative_peak_threshold=0.8,
+    min_separation_angle=45,
+    mask=white_matter,
+)
+
+classifier = ThresholdStoppingCriterion(csa_peaks.gfa, 0.25)
+
+seed_mask = labels == 2
+seeds = utils.seeds_from_mask(seed_mask, density=[1, 1, 1], affine=affine)
+
+# Initialization of LocalTracking. The computation happens in the next step.
+streamlines = LocalTracking(csa_peaks, classifier, seeds, affine, step_size=2)
+
+# Compute streamlines and store as a list.
+streamlines = Streamlines(streamlines)
+
+
+

We will create a streamline actor from the streamlines.

+
streamlines_actor = actor.line(streamlines, line_colors(streamlines))
+
+
+

Next, we create a surface actor from the corpus callosum seed ROI. We +provide the ROI data, the affine, the color in [R,G,B], and the opacity as +a decimal between zero and one. Here, we set the color as blue/green with +50% opacity.

+ +

Next, we initialize a ‘’Scene’’ object and add both actors +to the rendering.

+
scene = window.Scene()
+scene.add(streamlines_actor)
+scene.add(seedroi_actor)
+
+
+

If you uncomment the following line, the rendering will pop up in an +interactive window.

+
interactive = False
+if interactive:
+    window.show(scene)
+
+# scene.zoom(1.5)
+# scene.reset_clipping_range()
+
+window.record(scene, out_path='contour_from_roi_tutorial.png', size=(600, 600))
+
+
+viz roi contour

Total running time of the script: (2 minutes 53.689 seconds)

+ +

Gallery generated by Sphinx-Gallery

+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/auto_examples/04_demos/viz_tesseract.html b/v0.10.x/auto_examples/04_demos/viz_tesseract.html new file mode 100644 index 000000000..6a795386d --- /dev/null +++ b/v0.10.x/auto_examples/04_demos/viz_tesseract.html @@ -0,0 +1,673 @@ + + + + + + + + Tesseract (Hypercube) — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +
+

Tesseract (Hypercube)#

+

A tesseract is a four-dimensional cube. A tesseract can +be unfolded into eight cubes, Just as a cube can be unfolded into eight +squares.

+

First, import some useful functions

+
import itertools
+
+import numpy as np
+
+from fury import actor, utils, window
+from fury.ui import TextBlock2D
+
+
+

Let’s define some variables and their descriptions:

+

Use wireframe = True to show wireframe like representation of the tesseract +wireframe = False will render it with point actor on each vertex.

+
wireframe = False
+
+# p_color: color of the point actor (default: (0, 0.5, 1, 1))
+# e_color: color of the line actor (default: (1, 1, 1, 1))
+# dtheta: change in `angle` on each iteration. It determines the "speed" of the
+#        animation. Increase dtheta to increase speed of rotation, It may
+#        result in less smoother rotation (default: 0.02)
+# angle: defines the angle to be rotated to perform the animation, It changes
+#        as we run the `callback` method later on. (initial value: 0)
+
+p_color = np.array([0, 0.5, 1, 1])
+e_color = np.array([1, 1, 1, 1])
+dtheta = 0.02
+angle = 0
+
+
+

Let’s define vertices for our 4D cube, verts4D contains the coordinates of +our 4D tesseract.

+
verts3D = np.array(
+    [
+        [1, 1, 1],
+        [1, -1, 1],
+        [-1, -1, 1],
+        [-1, 1, 1],
+        [-1, 1, -1],
+        [1, 1, -1],
+        [1, -1, -1],
+        [-1, -1, -1],
+    ]
+)
+
+# We can use primitive.box alternatively to get the cube's 3-D vertices.
+
+u = np.insert(verts3D, 3, 1, axis=1)
+v = np.insert(verts3D, 3, -1, axis=1)
+verts4D = np.append(u, v, axis=0)
+
+
+

We define a rotate4D function that takes 4D matrix as parameter and rotates +it in XY plane (Z axis) and ZW plane (an imaginary axis), projects it to the +3D plane so that we can render it in a scene.

+
def rotate4D(verts4D):
+    cos = np.cos(angle)
+    sin = np.sin(angle)
+    rotation4d_xy = np.array(
+        [[cos, -sin, 0, 0], [sin, cos, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]
+    )
+    rotation4d_zw = np.array(
+        [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, cos, -sin], [0, 0, sin, cos]]
+    )
+    distance = 2
+    projected_marix = np.zeros((16, 3))
+    for i, vert in enumerate(verts4D):
+        rotated_3D = np.dot(rotation4d_xy, vert)
+        rotated_3D = np.dot(rotation4d_zw, rotated_3D)
+        w = 1 / (distance - rotated_3D[3])
+        proj_mat4D = np.array([[w, 0, 0, 0], [0, w, 0, 0], [0, 0, w, 0]])
+
+        projeced_mat3D = np.dot(proj_mat4D, rotated_3D)
+        projected_marix[i] = projeced_mat3D  # vertices to be proj (3D)
+    return projected_marix
+
+
+

Now, We have 4D points projected to 3D. Let’s define a function to connect +lines.

+
def connect_points(verts3D):
+    lines = np.array([])
+    len_vert = len(verts3D)
+
+    for i in range(len_vert - 1):
+        if i < 8:
+            lines = np.append(lines, [verts3D[i], verts3D[i + 8]])
+        if i == 7:
+            pass
+        else:
+            lines = np.append(lines, [verts3D[i], verts3D[i + 1]])
+        if i % 4 == 0:
+            lines = np.append(lines, [verts3D[i], verts3D[i + 3]])
+
+    for i in range(3):
+        lines = np.append(lines, [verts3D[i], verts3D[i + 5]])
+        lines = np.append(lines, [verts3D[i + 8], verts3D[i + 5 + 8]])
+
+    return np.reshape(lines, (-1, 2, 3))
+
+
+

Creating a scene object and configuring the camera’s position

+
scene = window.Scene()
+scene.set_camera(
+    position=(0, 10, -1), focal_point=(0.0, 0.0, 0.0), view_up=(0.0, 0.0, 0.0)
+)
+showm = window.ShowManager(scene, size=(1920, 1080), order_transparent=True)
+
+
+

Creating vertices and points actors

+
verts3D = rotate4D(verts4D)
+if not wireframe:
+    points = actor.point(verts3D, colors=p_color)
+    point_verts = utils.vertices_from_actor(points)
+    no_vertices = len(point_verts) / 16
+    initial_verts = point_verts.copy() - np.repeat(verts3D, no_vertices, axis=0)
+
+    scene.add(points)
+
+
+

Connecting points with lines actor

+
lines = connect_points(verts3D)
+edges = actor.line(lines=lines, colors=e_color, lod=False, fake_tube=True, linewidth=4)
+lines_verts = utils.vertices_from_actor(edges)
+initial_lines = lines_verts.copy() - np.reshape(lines, (-1, 3))
+
+scene.add(edges)
+
+
+

Initializing text box to display the name

+
tb = TextBlock2D(text='Tesseract', position=(900, 950), font_size=20)
+showm.scene.add(tb)
+
+
+

Define a timer_callback in which we’ll update the vertices of point and lines +actor using rotate4D.

+
counter = itertools.count()
+end = 200
+
+
+def timer_callback(_obj, _event):
+    global verts3D, angle
+    cnt = next(counter)
+    verts3D = rotate4D(verts4D)
+    if not wireframe:
+        point_verts[:] = initial_verts + np.repeat(verts3D, no_vertices, axis=0)
+        utils.update_actor(points)
+
+    lines = connect_points(verts3D)
+    lines_verts[:] = initial_lines + np.reshape(lines, (-1, 3))
+    utils.update_actor(edges)
+
+    showm.render()
+    angle += dtheta
+
+    if cnt == end:
+        showm.exit()
+
+
+

Run every 20 milliseconds

+
showm.add_timer_callback(True, 20, timer_callback)
+showm.start()
+window.record(showm.scene, size=(600, 600), out_path='viz_tesseract.png')
+
+
+viz tesseract

Total running time of the script: (0 minutes 4.109 seconds)

+ +

Gallery generated by Sphinx-Gallery

+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/auto_examples/07_ui/index.html b/v0.10.x/auto_examples/07_ui/index.html new file mode 100644 index 000000000..ab5e4a7a3 --- /dev/null +++ b/v0.10.x/auto_examples/07_ui/index.html @@ -0,0 +1,538 @@ + + + + + + + + User Interface Elements — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

User Interface Elements#

+

These tutorials show how to create user interfaces elements.

+
+

Simple Shapes

+
Simple Shapes
+
+

DrawPanel

+
DrawPanel
+
+

Card

+
Card
+
+

SpinBox UI

+
SpinBox UI
+
+

ComboBox

+
ComboBox
+
+

ListBox

+
ListBox
+
+

Using Layouts with different UI elements

+
Using Layouts with different UI elements
+
+

Sphere Color Control using Radio Buttons

+
Sphere Color Control using Radio Buttons
+
+

Buttons & Text

+
Buttons & Text
+
+

Card

+
Card
+
+

Cube & Slider Control

+
Cube & Slider Control
+
+

Figure and Color Control using Check boxes and Radio Buttons

+
Figure and Color Control using Check boxes and Radio Buttons
+
+

Tab UI

+
Tab UI
+
+

User Interfaces

+
User Interfaces
+
+
+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/auto_examples/07_ui/sg_execution_times.html b/v0.10.x/auto_examples/07_ui/sg_execution_times.html new file mode 100644 index 000000000..7ecf208ec --- /dev/null +++ b/v0.10.x/auto_examples/07_ui/sg_execution_times.html @@ -0,0 +1,548 @@ + + + + + + + + Computation times — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Computation times#

+

00:00.931 total execution time for 14 files from auto_examples/07_ui:

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Example

Time

Mem (MB)

Card (viz_card_sprite_sheet.py)

00:00.931

0.0

Buttons & Text (viz_buttons.py)

00:00.000

0.0

Card (viz_card.py)

00:00.000

0.0

Figure and Color Control using Check boxes and Radio Buttons (viz_check_boxes.py)

00:00.000

0.0

ComboBox (viz_combobox.py)

00:00.000

0.0

DrawPanel (viz_drawpanel.py)

00:00.000

0.0

Using Layouts with different UI elements (viz_layout.py)

00:00.000

0.0

Sphere Color Control using Radio Buttons (viz_radio_buttons.py)

00:00.000

0.0

Simple Shapes (viz_shapes.py)

00:00.000

0.0

SpinBox UI (viz_spinbox.py)

00:00.000

0.0

Tab UI (viz_tab.py)

00:00.000

0.0

User Interfaces (viz_ui.py)

00:00.000

0.0

ListBox (viz_ui_listbox.py)

00:00.000

0.0

Cube & Slider Control (viz_ui_slider.py)

00:00.000

0.0

+
+
+ +
+ + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/auto_examples/07_ui/viz_buttons.html b/v0.10.x/auto_examples/07_ui/viz_buttons.html new file mode 100644 index 000000000..45d77b84c --- /dev/null +++ b/v0.10.x/auto_examples/07_ui/viz_buttons.html @@ -0,0 +1,588 @@ + + + + + + + + Buttons & Text — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +
+

Buttons & Text#

+

This example shows how to use the UI API. We will demonstrate how to create +panel having buttons with callbacks.

+

First, some imports.

+
from fury import ui, window
+from fury.data import fetch_viz_icons, read_viz_icons
+
+
+

First we need to fetch some icons that are included in FURY.

+
fetch_viz_icons()
+
+
+
Data size is approximately 12KB
+Dataset is already in place. If you want to fetch it again please first remove the folder /Users/skoudoro/.fury/icons
+
+({'icomoon.tar.gz': ('https://digital.lib.washington.edu/researchworks/bitstream/handle/1773/38478/icomoon.tar.gz', 'BC1FEEA6F58BA3601D6A0B029EB8DFC5F352E21F2A16BA41099A96AA3F5A4735')}, '/Users/skoudoro/.fury/icons')
+
+
+

Let’s create some buttons and text and put them in a panel. +First we’ll make the panel.

+
panel = ui.Panel2D(size=(300, 150), color=(1, 1, 1), align='right')
+panel.center = (500, 400)
+
+
+

Then we’ll make two text labels and place them on the panel. +Note that we specify the position with integer numbers of pixels.

+
text = ui.TextBlock2D(text='Click me')
+text2 = ui.TextBlock2D(text='Me too')
+panel.add_element(text, (50, 100))
+panel.add_element(text2, (180, 100))
+
+
+

Then we’ll create two buttons and add them to the panel.

+

Note that here we specify the positions with floats. In this case, these are +percentages of the panel size.

+
button_example = ui.Button2D(
+    icon_fnames=[('square', read_viz_icons(fname='stop2.png'))]
+)
+
+icon_files = []
+icon_files.append(('down', read_viz_icons(fname='circle-down.png')))
+icon_files.append(('left', read_viz_icons(fname='circle-left.png')))
+icon_files.append(('up', read_viz_icons(fname='circle-up.png')))
+icon_files.append(('right', read_viz_icons(fname='circle-right.png')))
+
+second_button_example = ui.Button2D(icon_fnames=icon_files)
+
+panel.add_element(button_example, (0.25, 0.33))
+panel.add_element(second_button_example, (0.66, 0.33))
+
+
+

We can add a callback to each button to perform some action.

+
def change_text_callback(i_ren, _obj, _button):
+    text.message = 'Clicked!'
+    i_ren.force_render()
+
+
+def change_icon_callback(i_ren, _obj, _button):
+    _button.next_icon()
+    i_ren.force_render()
+
+
+button_example.on_left_mouse_button_clicked = change_text_callback
+second_button_example.on_left_mouse_button_pressed = change_icon_callback
+
+
+

Now that all the elements have been initialised, we add them to the show +manager.

+
current_size = (800, 800)
+show_manager = window.ShowManager(size=current_size, title='FURY Button Example')
+
+show_manager.scene.add(panel)
+
+interactive = False
+
+if interactive:
+    show_manager.start()
+
+window.record(show_manager.scene, size=current_size, out_path='viz_button.png')
+
+
+viz buttons

Total running time of the script: (0 minutes 0.071 seconds)

+ +

Gallery generated by Sphinx-Gallery

+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/auto_examples/07_ui/viz_card.html b/v0.10.x/auto_examples/07_ui/viz_card.html new file mode 100644 index 000000000..95202d6eb --- /dev/null +++ b/v0.10.x/auto_examples/07_ui/viz_card.html @@ -0,0 +1,556 @@ + + + + + + + + Card — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +
+

Card#

+

This example shows how to create a card.

+

First, some imports.

+
from fury import ui, window
+from fury.data import fetch_viz_icons
+
+
+

First we need to fetch some icons that are included in FURY.

+
fetch_viz_icons()
+
+
+
Data size is approximately 12KB
+Dataset is already in place. If you want to fetch it again please first remove the folder /Users/skoudoro/.fury/icons
+
+({'icomoon.tar.gz': ('https://digital.lib.washington.edu/researchworks/bitstream/handle/1773/38478/icomoon.tar.gz', 'BC1FEEA6F58BA3601D6A0B029EB8DFC5F352E21F2A16BA41099A96AA3F5A4735')}, '/Users/skoudoro/.fury/icons')
+
+
+

Let’s create a card and add it to the show manager

+
img_url = "https://raw.githubusercontent.com/fury-gl"\
+          "/fury-communication-assets/main/fury-logo.png"
+
+title = "FURY"
+body = "FURY - Free Unified Rendering in pYthon."\
+       "A software library for scientific visualization in Python."
+
+card = ui.elements.Card2D(image_path=img_url, title_text=title,
+                          body_text=body,
+                          image_scale=0.55, size=(300, 300),
+                          bg_color=(1, 0.294, 0.180),
+                          bg_opacity=0.8, border_width=5,
+                          border_color=(0.1, 0.4, 0.4))
+
+
+

Now that the card has been initialised, we add it to the show +manager.

+
current_size = (1000, 1000)
+show_manager = window.ShowManager(size=current_size,
+                                  title="FURY Card Example")
+
+show_manager.scene.add(card)
+# To interact with the UI, set interactive = True
+interactive = False
+
+if interactive:
+    show_manager.start()
+
+window.record(show_manager.scene, out_path="card_ui.png", size=(1000, 1000))
+
+
+viz card

Total running time of the script: (0 minutes 0.257 seconds)

+ +

Gallery generated by Sphinx-Gallery

+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/auto_examples/07_ui/viz_card_sprite_sheet.html b/v0.10.x/auto_examples/07_ui/viz_card_sprite_sheet.html new file mode 100644 index 000000000..565215f79 --- /dev/null +++ b/v0.10.x/auto_examples/07_ui/viz_card_sprite_sheet.html @@ -0,0 +1,600 @@ + + + + + + + + Card — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +
+

Card#

+

This example shows how to create a card and use a sprite +sheet to update the image in the card.

+

First, some imports.

+
import os
+from fury import ui, window
+from fury.data import fetch_viz_icons
+from fury.io import load_image, load_sprite_sheet, save_image
+from tempfile import TemporaryDirectory as InTemporaryDirectory
+
+
+

First we need to fetch some icons that are included in FURY.

+
TARGET_FPS = 15
+FRAME_TIME = (1.0 / TARGET_FPS) * 1000
+
+fetch_viz_icons()
+
+sprite_sheet = load_sprite_sheet('https://raw.githubusercontent.com/fury-gl/'
+                                 'fury-data/master/unittests/fury_sprite.png',
+                                 5, 5)
+CURRENT_SPRITE_IDX = 0
+
+vtk_sprites = []
+
+
+
Data size is approximately 12KB
+Dataset is already in place. If you want to fetch it again please first remove the folder /Users/skoudoro/.fury/icons
+
+
+

Let’s create a card and add it to the show manager

+
img_url = "https://raw.githubusercontent.com/fury-gl"\
+          "/fury-communication-assets/main/fury-logo.png"
+
+title = "FURY"
+body = "FURY - Free Unified Rendering in pYthon."\
+       "A software library for scientific visualization in Python."
+
+card = ui.elements.Card2D(image_path=img_url, title_text=title,
+                          body_text=body,
+                          image_scale=0.55, size=(300, 300),
+                          bg_color=(1, 0.294, 0.180),
+                          bg_opacity=0.8, border_width=5,
+                          border_color=(0.1, 0.4, 0.8))
+
+
+

Now we define the callback to update the image on card after some delay.

+
def timer_callback(_obj, _evt):
+    global CURRENT_SPRITE_IDX, show_manager
+    CURRENT_SPRITE_IDX += 1
+    sprite = vtk_sprites[CURRENT_SPRITE_IDX % len(vtk_sprites)]
+    card.image.set_img(sprite)
+    i_ren = show_manager.scene.GetRenderWindow()\
+        .GetInteractor().GetInteractorStyle()
+
+    i_ren.force_render()
+
+
+

Lets create a function to convert the sprite to vtkImageData

+
def sprite_to_vtk():
+    with InTemporaryDirectory() as tdir:
+        for idx, sprite in enumerate(list(sprite_sheet.values())):
+            sprite_path = os.path.join(tdir, f'{idx}.png')
+            save_image(sprite, sprite_path, compression_quality=100)
+            vtk_sprite = load_image(sprite_path, as_vtktype=True)
+            vtk_sprites.append(vtk_sprite)
+
+
+

Now that the card has been initialised, we add it to the show +manager.

+ +

Converting numpy array sprites to vtk images

+
sprite_to_vtk()
+
+
+

Adding a timer to update the card image

+
show_manager.add_timer_callback(True, int(FRAME_TIME), timer_callback)
+
+# To interact with the UI, set interactive = True
+interactive = False
+
+if interactive:
+    show_manager.start()
+
+window.record(show_manager.scene, out_path="card_ui.png", size=(1000, 1000))
+
+
+viz card sprite sheet

Total running time of the script: (0 minutes 0.931 seconds)

+ +

Gallery generated by Sphinx-Gallery

+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/auto_examples/07_ui/viz_check_boxes.html b/v0.10.x/auto_examples/07_ui/viz_check_boxes.html new file mode 100644 index 000000000..d96159520 --- /dev/null +++ b/v0.10.x/auto_examples/07_ui/viz_check_boxes.html @@ -0,0 +1,679 @@ + + + + + + + + Figure and Color Control using Check boxes and Radio Buttons — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +
+

Figure and Color Control using Check boxes and Radio Buttons#

+

This example shows how to use the CheckBox UI API. We will demonstrate how to +create a cube, sphere, cone and arrow and control its color and visibility +using checkboxes.

+

First, some imports.

+
import numpy as np
+
+from fury import actor, ui, utils, window
+from fury.data import fetch_viz_icons
+
+
+

First we need to fetch some icons that are included in FURY.

+
fetch_viz_icons()
+
+
+
Data size is approximately 12KB
+Dataset is already in place. If you want to fetch it again please first remove the folder /Users/skoudoro/.fury/icons
+
+({'icomoon.tar.gz': ('https://digital.lib.washington.edu/researchworks/bitstream/handle/1773/38478/icomoon.tar.gz', 'BC1FEEA6F58BA3601D6A0B029EB8DFC5F352E21F2A16BA41099A96AA3F5A4735')}, '/Users/skoudoro/.fury/icons')
+
+
+

We create the corresponding object actors for cube, sphere, cone and arrow.

+
cube = actor.cube(
+    centers=np.array([[15, 0, 0]]),
+    colors=np.array([[0, 0, 1]]),
+    scales=np.array([[20, 20, 20]]),
+    directions=np.array([[0, 0, 1]]),
+)
+
+sphere = actor.sphere(
+    centers=np.array([[50, 0, 0]]),
+    colors=np.array([[0, 0, 1]]),
+    radii=11.0,
+    theta=360,
+    phi=360,
+)
+
+cone = actor.cone(
+    centers=np.array([[-20, -0.5, 0]]),
+    directions=np.array([[0, 1, 0]]),
+    colors=np.array([[0, 0, 1]]),
+    heights=20,
+    resolution=100,
+)
+
+arrow = actor.arrow(
+    centers=np.array([[0, 25, 0]]),
+    colors=np.array([[0, 0, 1]]),
+    directions=np.array([[1, 0, 0]]),
+    heights=40,
+    resolution=100,
+)
+
+
+

We perform symmetric difference to determine the unchecked options. +We also define methods to render visibility and color.

+
# Get difference between two lists.
+def sym_diff(l1, l2):
+    return list(set(l1).symmetric_difference(set(l2)))
+
+
+# Set Visibility of the figures
+def set_figure_visiblity(checkboxes):
+    checked = checkboxes.checked_labels
+    unchecked = sym_diff(list(figure_dict), checked)
+
+    for visible in checked:
+        figure_dict[visible].SetVisibility(True)
+
+    for invisible in unchecked:
+        figure_dict[invisible].SetVisibility(False)
+
+
+def update_colors(color_array):
+    for _, figure in figure_dict.items():
+        vcolors = utils.colors_from_actor(figure)
+        vcolors[:] = color_array
+        utils.update_actor(figure)
+
+
+# Toggle colors of the figures
+def toggle_color(checkboxes):
+    colors = checkboxes.checked_labels
+
+    color_array = np.array([0, 0, 0])
+
+    for col in colors:
+        if col == 'Red':
+            color_array[0] = 255
+        elif col == 'Green':
+            color_array[1] = 255
+        else:
+            color_array[2] = 255
+
+    update_colors(color_array)
+
+
+

We define a dictionary to store the actors with their names as keys. +A checkbox is created with actor names as it’s options.

+
figure_dict = {'cube': cube, 'sphere': sphere, 'cone': cone, 'arrow': arrow}
+check_box = ui.Checkbox(
+    list(figure_dict),
+    list(figure_dict),
+    padding=1,
+    font_size=18,
+    font_family='Arial',
+    position=(400, 85),
+)
+
+
+

A similar checkbox is created for changing colors.

+
options = {'Blue': (0, 0, 1), 'Red': (1, 0, 0), 'Green': (0, 1, 0)}
+color_toggler = ui.Checkbox(
+    list(options),
+    checked_labels=['Blue'],
+    padding=1,
+    font_size=16,
+    font_family='Arial',
+    position=(600, 120),
+)
+
+
+check_box.on_change = set_figure_visiblity
+color_toggler.on_change = toggle_color
+
+
+
+

Show Manager#

+

Now that all the elements have been initialised, we add them to the show +manager.

+
current_size = (1000, 1000)
+show_manager = window.ShowManager(size=current_size, title='FURY Checkbox Example')
+
+show_manager.scene.add(cube)
+show_manager.scene.add(sphere)
+show_manager.scene.add(cone)
+show_manager.scene.add(arrow)
+show_manager.scene.add(check_box)
+show_manager.scene.add(color_toggler)
+
+
+

Set camera for better visualization

+ +viz check boxes

Total running time of the script: (0 minutes 0.140 seconds)

+ +

Gallery generated by Sphinx-Gallery

+
+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ +
+ On this page +
+ +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/auto_examples/07_ui/viz_combobox.html b/v0.10.x/auto_examples/07_ui/viz_combobox.html new file mode 100644 index 000000000..cc8581403 --- /dev/null +++ b/v0.10.x/auto_examples/07_ui/viz_combobox.html @@ -0,0 +1,618 @@ + + + + + + + + ComboBox — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +
+

ComboBox#

+

This example shows how to use the Combobox UI. We will demonstrate how to +create ComboBoxes for selecting colors for a label.

+

First, some imports.

+
from fury import ui, window
+from fury.data import fetch_viz_icons
+
+
+

First we need to fetch some icons that are included in FURY.

+
fetch_viz_icons()
+
+
+
Data size is approximately 12KB
+Dataset is already in place. If you want to fetch it again please first remove the folder /Users/skoudoro/.fury/icons
+
+({'icomoon.tar.gz': ('https://digital.lib.washington.edu/researchworks/bitstream/handle/1773/38478/icomoon.tar.gz', 'BC1FEEA6F58BA3601D6A0B029EB8DFC5F352E21F2A16BA41099A96AA3F5A4735')}, '/Users/skoudoro/.fury/icons')
+
+
+

First, we create a label.

+
label = ui.TextBlock2D(
+    position=(200, 300),
+    font_size=40,
+    color=(1, 0.5, 0),
+    justification='center',
+    vertical_justification='top',
+    text='FURY rocks!!!',
+)
+
+
+

Now we create a dictionary to store colors as its key and their +RGB values as its value.

+
colors = {
+    'Violet': (0.6, 0, 0.8),
+    'Indigo': (0.3, 0, 0.5),
+    'Blue': (0, 0, 1),
+    'Green': (0, 1, 0),
+    'Yellow': (1, 1, 0),
+    'Orange': (1, 0.5, 0),
+    'Red': (1, 0, 0),
+}
+
+
+
+

ComboBox#

+

Now we create a ComboBox UI component for selecting colors.

+
color_combobox = ui.ComboBox2D(
+    items=list(colors.keys()),
+    placeholder='Choose Text Color',
+    position=(75, 50),
+    size=(250, 150),
+)
+
+
+
+
+

Callbacks#

+

Now we create a callback for setting the chosen color.

+
def change_color(combobox):
+    label.color = colors[combobox.selected_text]
+
+
+# `on_change` callback is set to `change_color` method so that
+# it's called whenever a different option is selected.
+color_combobox.on_change = change_color
+
+
+
+
+

Show Manager#

+

Now we add label and combobox to the scene.

+
current_size = (400, 400)
+showm = window.ShowManager(size=current_size, title='ComboBox UI Example')
+showm.scene.add(label, color_combobox)
+
+# To interact with the UI, set interactive = True
+interactive = False
+
+if interactive:
+    showm.start()
+
+window.record(showm.scene, out_path='combobox_ui.png', size=(400, 400))
+
+
+viz combobox

Total running time of the script: (0 minutes 0.050 seconds)

+ +

Gallery generated by Sphinx-Gallery

+
+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ +
+ On this page +
+ +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/auto_examples/07_ui/viz_drawpanel.html b/v0.10.x/auto_examples/07_ui/viz_drawpanel.html new file mode 100644 index 000000000..97fe69a8d --- /dev/null +++ b/v0.10.x/auto_examples/07_ui/viz_drawpanel.html @@ -0,0 +1,567 @@ + + + + + + + + DrawPanel — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +
+

DrawPanel#

+

This example shows how to use the DrawPanel UI. We will demonstrate how to +create Various shapes and transform them.

+

First, some imports.

+
from fury import ui, window
+from fury.data import fetch_viz_new_icons
+
+
+

First we need to fetch some icons that are needed for DrawPanel.

+
fetch_viz_new_icons()
+
+
+
Dataset is already in place. If you want to fetch it again please first remove the folder /Users/skoudoro/.fury/icons/new_icons
+
+({'circle-pressed.png': ('https://raw.githubusercontent.com/fury-gl/fury-data/master/icons/new_icons/circle-pressed.png', 'CD859F244DF1BA719C65C869C3FAF6B8563ABF82F457730ADBFBD7CA72DDB7BC'), 'circle.png': ('https://raw.githubusercontent.com/fury-gl/fury-data/master/icons/new_icons/circle.png', '5896BDC9FF9B3D1054134D7D9A854677CE9FA4E64F494F156BB2E3F0E863F207'), 'delete-pressed.png': ('https://raw.githubusercontent.com/fury-gl/fury-data/master/icons/new_icons/delete-pressed.png', '937C46C25BC38B62021B01C97A4EE3CDE5F7C8C4A6D0DB75BF4E4CACE2AF1226'), 'delete.png': ('https://raw.githubusercontent.com/fury-gl/fury-data/master/icons/new_icons/delete.png', '476E00A0A5373E1CCDA4AF8E7C9158E0AC9B46B540CE410C6EA47D97F364A0CD'), 'drawing-pressed.png': ('https://raw.githubusercontent.com/fury-gl/fury-data/master/icons/new_icons/drawing-pressed.png', '08A914C5DC7997CB944B8C5FBB958951F80B715CFE04FF4F47A73F9D08C4B14B'), 'drawing.png': ('https://raw.githubusercontent.com/fury-gl/fury-data/master/icons/new_icons/drawing.png', 'FB2210B0393ECA8A5DD2B8F034DAE386BBB47EB95BB1CAC2A97DE807EE195ADF'), 'line-pressed.png': ('https://raw.githubusercontent.com/fury-gl/fury-data/master/icons/new_icons/line-pressed.png', '8D1AC2BB7C5BAA34E68578DAAD85F64EF824BE7BCB828CAC18E52833D4CBF4C9'), 'line.png': ('https://raw.githubusercontent.com/fury-gl/fury-data/master/icons/new_icons/line.png', 'E6D833B6D958129E12FF0F6087282CE92CD43C6DAFCE03F185746ECCA89E42A9'), 'polyline-pressed.png': ('https://raw.githubusercontent.com/fury-gl/fury-data/master/icons/new_icons/polyline-pressed.png', 'CFF12B8DE48FC19DA5D5F0EA7FF2D23DD942D05468E19522E7C7BEB72F0FF66E'), 'polyline.png': ('https://raw.githubusercontent.com/fury-gl/fury-data/master/icons/new_icons/polyline.png', '7AFE65EBAE0C0D0556393B979148AE15FC3E037D126CD1DA4A296F4E25F5B4AA'), 'quad-pressed.png': ('https://raw.githubusercontent.com/fury-gl/fury-data/master/icons/new_icons/quad-pressed.png', '5FD43F1C2D37BF9AF05D9FC591172684AC51BA236980CD1B0795B0225B9247E2'), 'quad.png': ('https://raw.githubusercontent.com/fury-gl/fury-data/master/icons/new_icons/quad.png', 'A2DA0CB963401C174919E1D8028AA6F0CB260A736FD26421DB5AB08E9F3C4FDF'), 'resize-pressed.png': ('https://raw.githubusercontent.com/fury-gl/fury-data/master/icons/new_icons/resize-pressed.png', 'FF49DDF9DF24729F4F6345C30C88DE0A11E5B12B2F2FF28375EF9762FE5F8995'), 'resize.png': ('https://raw.githubusercontent.com/fury-gl/fury-data/master/icons/new_icons/resize.png', 'A2D850CDBA8F332DA9CD7B7C9459CBDA587C18AF0D3C12CA68D6E6A864EF54BB'), 'selection-pressed.png': ('https://raw.githubusercontent.com/fury-gl/fury-data/master/icons/new_icons/selection-pressed.png', '54618FDC4589F0A039D531C07A110ED9BC57A256BB15A3B5429CF60E950887C3'), 'selection.png': ('https://raw.githubusercontent.com/fury-gl/fury-data/master/icons/new_icons/selection.png', 'CD573F5E4BF4A91A3B21F6124A95FFB3C036F926F8FEC1FD0180F5D27D8F48C0')}, '/Users/skoudoro/.fury/icons/new_icons')
+
+
+

We then create a DrawPanel Object.

+
drawing_canvas = ui.DrawPanel(size=(560, 560), position=(40, 10))
+
+
+
+

Show Manager#

+

Now we add DrawPanel to the scene.

+
current_size = (650, 650)
+showm = window.ShowManager(size=current_size, title='DrawPanel UI Example')
+
+showm.scene.add(drawing_canvas)
+
+interactive = False
+
+if interactive:
+    showm.start()
+else:
+    # If the UI isn't interactive, then adding a circle to the canvas
+    drawing_canvas.current_mode = 'circle'
+    drawing_canvas.draw_shape(shape_type='circle', current_position=(275, 275))
+    drawing_canvas.shape_list[-1].resize((50, 50))
+
+    window.record(showm.scene, size=current_size, out_path='viz_drawpanel.png')
+
+
+viz drawpanel

Total running time of the script: (0 minutes 0.063 seconds)

+ +

Gallery generated by Sphinx-Gallery

+
+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ +
+ On this page +
+ +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/auto_examples/07_ui/viz_layout.html b/v0.10.x/auto_examples/07_ui/viz_layout.html new file mode 100644 index 000000000..1f603a2ef --- /dev/null +++ b/v0.10.x/auto_examples/07_ui/viz_layout.html @@ -0,0 +1,558 @@ + + + + + + + + Using Layouts with different UI elements — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +
+

Using Layouts with different UI elements#

+

This example shows how to place different UI elements in different Layouts. +The Layouts used here is GridLayout (with different cell shapes).

+

First, some imports.

+
from fury import ui, window
+from fury.layout import GridLayout
+
+
+

We create some panels and then we arrange them in a grid fashion

+

First, we create some panels with different sizes/positions

+
panel_1 = ui.Panel2D(size=(200, 200), color=(0.4, 0.6, 0.3), position=(100, 100))
+
+panel_2 = ui.Panel2D(size=(250, 250), color=(0.8, 0.3, 0.5), position=(150, 150))
+
+
+

Now we create two listboxes

+
listbox_1 = ui.ListBox2D(size=(150, 150), values=['First', 'Second', 'Third'])
+
+listbox_2 = ui.ListBox2D(size=(250, 250), values=['First', 'Second', 'Third'])
+
+
+

Now we create two different UI i.e. a slider and a listbox

+
slider = ui.LineSlider2D(length=150)
+listbox = ui.ListBox2D(size=(150, 150), values=['First', 'Second', 'Third'])
+
+
+

Now, we create grids with different shapes

+
rect_grid = GridLayout(position_offset=(0, 0, 0))
+square_grid = GridLayout(cell_shape='square', position_offset=(0, 300, 0))
+diagonal_grid = GridLayout(cell_shape='diagonal', position_offset=(0, 600, 0))
+
+
+

Applying the grid to the ui elements

+
rect_grid.apply([panel_1, panel_2])
+square_grid.apply([listbox_1, listbox_2])
+diagonal_grid.apply([slider, listbox])
+
+current_size = (1500, 1500)
+show_manager = window.ShowManager(size=current_size, title='FURY UI Layout')
+
+show_manager.scene.add(panel_1, panel_2, listbox_1, listbox_2, slider, listbox)
+
+# To interact with the UI, set interactive = True
+interactive = False
+
+if interactive:
+    show_manager.start()
+
+window.record(show_manager.scene, out_path='ui_layout.png', size=(400, 400))
+
+
+viz layout

Total running time of the script: (0 minutes 0.059 seconds)

+ +

Gallery generated by Sphinx-Gallery

+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/auto_examples/07_ui/viz_radio_buttons.html b/v0.10.x/auto_examples/07_ui/viz_radio_buttons.html new file mode 100644 index 000000000..a268079df --- /dev/null +++ b/v0.10.x/auto_examples/07_ui/viz_radio_buttons.html @@ -0,0 +1,610 @@ + + + + + + + + Sphere Color Control using Radio Buttons — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +
+

Sphere Color Control using Radio Buttons#

+

This example shows how to use the UI API. We will demonstrate how to +create a Sphere and control its color using radio buttons.

+

First, some imports.

+
import numpy as np
+
+from fury import actor, ui, utils, window
+from fury.data import fetch_viz_icons
+
+
+

First we need to fetch some icons that are included in FURY.

+
fetch_viz_icons()
+
+
+
Data size is approximately 12KB
+Dataset is already in place. If you want to fetch it again please first remove the folder /Users/skoudoro/.fury/icons
+
+({'icomoon.tar.gz': ('https://digital.lib.washington.edu/researchworks/bitstream/handle/1773/38478/icomoon.tar.gz', 'BC1FEEA6F58BA3601D6A0B029EB8DFC5F352E21F2A16BA41099A96AA3F5A4735')}, '/Users/skoudoro/.fury/icons')
+
+
+
+

Sphere and Radio Buttons#

+

Add a Sphere to the scene.

+
sphere = actor.sphere(
+    centers=np.array([[50, 0, 0]]),
+    colors=np.array([[0, 0, 1]]),
+    radii=11.0,
+    theta=360,
+    phi=360,
+)
+
+# Creating a dict of possible options and mapping it with their values.
+options = {'Blue': (0, 0, 255), 'Red': (255, 0, 0), 'Green': (0, 255, 0)}
+
+color_toggler = ui.RadioButton(
+    list(options),
+    checked_labels=['Blue'],
+    padding=1,
+    font_size=16,
+    font_family='Arial',
+    position=(200, 200),
+)
+
+
+# A callback which will set the values for the box
+def toggle_color(radio):
+    vcolors = utils.colors_from_actor(sphere)
+    color = options[radio.checked_labels[0]]
+    vcolors[:] = np.array(color)
+    utils.update_actor(sphere)
+
+
+color_toggler.on_change = toggle_color
+
+
+
+
+

Show Manager#

+

Now that all the elements have been initialised, we add them to the show +manager.

+
current_size = (800, 800)
+show_manager = window.ShowManager(size=current_size, title='FURY Sphere Example')
+
+show_manager.scene.add(sphere)
+show_manager.scene.add(color_toggler)
+
+
+

Set camera for better visualization

+ +viz radio buttons

Total running time of the script: (0 minutes 0.121 seconds)

+ +

Gallery generated by Sphinx-Gallery

+
+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ +
+ On this page +
+ +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/auto_examples/07_ui/viz_shapes.html b/v0.10.x/auto_examples/07_ui/viz_shapes.html new file mode 100644 index 000000000..52476e07a --- /dev/null +++ b/v0.10.x/auto_examples/07_ui/viz_shapes.html @@ -0,0 +1,554 @@ + + + + + + + + Simple Shapes — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +
+

Simple Shapes#

+

This example shows how to use the UI API. We will demonstrate how to draw +some geometric shapes from FURY UI elements.

+

First, a bunch of imports.

+
from fury import ui, window
+from fury.data import fetch_viz_icons
+
+
+

First we need to fetch some icons that are included in FURY.

+
fetch_viz_icons()
+
+
+
Data size is approximately 12KB
+Dataset is already in place. If you want to fetch it again please first remove the folder /Users/skoudoro/.fury/icons
+
+({'icomoon.tar.gz': ('https://digital.lib.washington.edu/researchworks/bitstream/handle/1773/38478/icomoon.tar.gz', 'BC1FEEA6F58BA3601D6A0B029EB8DFC5F352E21F2A16BA41099A96AA3F5A4735')}, '/Users/skoudoro/.fury/icons')
+
+
+

Let’s draw some simple shapes. First, a rectangle.

+
rect = ui.Rectangle2D(size=(100, 100), position=(400, 400), color=(1, 0, 1))
+
+
+

Then we can draw a solid circle, or disk.

+
disk = ui.Disk2D(outer_radius=50, center=(400, 200), color=(1, 1, 0))
+
+
+

Add an inner radius to make a ring.

+
ring = ui.Disk2D(outer_radius=50, inner_radius=45, center=(500, 600), color=(0, 1, 1))
+
+
+

Now that all the elements have been initialised, we add them to the show +manager.

+
current_size = (800, 800)
+show_manager = window.ShowManager(size=current_size, title='FURY Shapes Example')
+
+show_manager.scene.add(rect)
+show_manager.scene.add(disk)
+show_manager.scene.add(ring)
+
+interactive = False
+
+if interactive:
+    show_manager.start()
+
+window.record(show_manager.scene, size=current_size, out_path='viz_shapes.png')
+
+
+viz shapes

Total running time of the script: (0 minutes 0.068 seconds)

+ +

Gallery generated by Sphinx-Gallery

+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/auto_examples/07_ui/viz_spinbox.html b/v0.10.x/auto_examples/07_ui/viz_spinbox.html new file mode 100644 index 000000000..94d929f06 --- /dev/null +++ b/v0.10.x/auto_examples/07_ui/viz_spinbox.html @@ -0,0 +1,572 @@ + + + + + + + + SpinBox UI — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +
+

SpinBox UI#

+

This example shows how to use the UI API. We will demonstrate how to create +a SpinBox UI.

+

First, some imports.

+
from fury import actor, ui, utils, window
+from fury.data import fetch_viz_icons
+import numpy as np
+
+
+

First we need to fetch some icons that are included in FURY.

+
fetch_viz_icons()
+
+
+
Data size is approximately 12KB
+Dataset is already in place. If you want to fetch it again please first remove the folder /Users/skoudoro/.fury/icons
+
+({'icomoon.tar.gz': ('https://digital.lib.washington.edu/researchworks/bitstream/handle/1773/38478/icomoon.tar.gz', 'BC1FEEA6F58BA3601D6A0B029EB8DFC5F352E21F2A16BA41099A96AA3F5A4735')}, '/Users/skoudoro/.fury/icons')
+
+
+

Let’s create a Cone.

+
cone = actor.cone(centers=np.random.rand(1, 3),
+                  directions=np.random.rand(1, 3),
+                  colors=(1, 1, 1), heights=np.random.rand(1))
+
+
+

Creating the SpinBox UI.

+
spinbox = ui.SpinBox(position=(200, 100), size=(300, 100), min_val=0,
+                     max_val=360, initial_val=180, step=10)
+
+
+

Now that all the elements have been initialised, we add them to the show +manager.

+
current_size = (800, 800)
+show_manager = window.ShowManager(size=current_size,
+                                  title="FURY SpinBox Example")
+
+show_manager.scene.add(cone)
+show_manager.scene.add(spinbox)
+
+
+

Using the on_change hook to rotate the cone.

+
# Tracking previous value to check in/decrement.
+previous_value = spinbox.value
+
+
+def rotate_cone(spinbox):
+    global previous_value
+    change_in_value = spinbox.value - previous_value
+    utils.rotate(cone, (change_in_value, 1, 0, 0))
+    previous_value = spinbox.value
+
+
+spinbox.on_change = rotate_cone
+
+
+

Starting the ShowManager.

+
interactive = False
+
+if interactive:
+    show_manager.start()
+
+window.record(show_manager.scene, size=current_size,
+              out_path="viz_spinbox.png")
+
+
+viz spinbox

Total running time of the script: (0 minutes 0.083 seconds)

+ +

Gallery generated by Sphinx-Gallery

+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/auto_examples/07_ui/viz_tab.html b/v0.10.x/auto_examples/07_ui/viz_tab.html new file mode 100644 index 000000000..6ab7c0a17 --- /dev/null +++ b/v0.10.x/auto_examples/07_ui/viz_tab.html @@ -0,0 +1,758 @@ + + + + + + + + Tab UI — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +
+

Tab UI#

+

This example shows how to use the Tab UI. We will demonstrate how to +create Tabs for:

+
    +
  1. Slider controls for a Cube

  2. +
  3. Checkboxes for Cylinder and Sphere

  4. +
  5. Color combobox for Fury.

  6. +
+

First, some imports.

+
import numpy as np
+
+from fury import actor, ui, window
+from fury.data import fetch_viz_icons
+
+
+

First we need to fetch some icons that are included in FURY.

+
fetch_viz_icons()
+
+
+
Data size is approximately 12KB
+Dataset is already in place. If you want to fetch it again please first remove the folder /Users/skoudoro/.fury/icons
+
+({'icomoon.tar.gz': ('https://digital.lib.washington.edu/researchworks/bitstream/handle/1773/38478/icomoon.tar.gz', 'BC1FEEA6F58BA3601D6A0B029EB8DFC5F352E21F2A16BA41099A96AA3F5A4735')}, '/Users/skoudoro/.fury/icons')
+
+
+

First, we create the Tab UI.

+
tab_ui = ui.TabUI(position=(49, 94), size=(300, 300), nb_tabs=3, draggable=True)
+
+
+
+

Slider Controls for a Cube for Tab Index 0#

+

Now we prepare content for the first tab.

+
ring_slider = ui.RingSlider2D(initial_value=0, text_template='{angle:5.1f}°')
+
+line_slider_x = ui.LineSlider2D(
+    initial_value=0,
+    min_value=-10,
+    max_value=10,
+    orientation='horizontal',
+    text_alignment='Top',
+)
+
+line_slider_y = ui.LineSlider2D(
+    initial_value=0,
+    min_value=-10,
+    max_value=10,
+    orientation='vertical',
+    text_alignment='Right',
+)
+
+cube = actor.box(
+    centers=np.array([[10, 0, 0]]),
+    directions=np.array([[0, 1, 0]]),
+    colors=np.array([[0, 0, 1]]),
+    scales=np.array([[1, 1, 1]]),
+)
+cube_x = 0
+cube_y = 0
+
+
+def rotate_cube(slider):
+    angle = slider.value
+    previous_angle = slider.previous_value
+    rotation_angle = angle - previous_angle
+    cube.RotateX(rotation_angle)
+
+
+def translate_cube_x(slider):
+    global cube_x, cube_y
+    cube_x = slider.value
+    cube.SetPosition(cube_x, cube_y, 0)
+
+
+def translate_cube_y(slider):
+    global cube_x, cube_y
+    cube_y = slider.value
+    cube.SetPosition(cube_x, cube_y, 0)
+
+
+ring_slider.on_change = rotate_cube
+line_slider_x.on_change = translate_cube_x
+line_slider_y.on_change = translate_cube_y
+
+
+

After defining content, we define properties for the tab.

+
tab_ui.tabs[0].title = 'Sliders'
+tab_ui.add_element(0, ring_slider, (0.3, 0.3))
+tab_ui.add_element(0, line_slider_x, (0.0, 0.0))
+tab_ui.add_element(0, line_slider_y, (0.0, 0.1))
+
+
+
+
+

CheckBoxes For Cylinder and Sphere for Tab Index 1#

+

Now we prepare content for second tab.

+
cylinder = actor.cylinder(
+    centers=np.array([[0, 0, 0]]),
+    directions=np.array([[1, 1, 0]]),
+    colors=np.array([[0, 1, 1]]),
+    radius=1.0,
+)
+
+sphere = actor.sphere(centers=np.array([[5, 0, 0]]), colors=(1, 1, 0))
+
+figure_dict = {'cylinder': cylinder, 'sphere': sphere}
+checkbox = ui.Checkbox(labels=['cylinder', 'sphere'])
+
+
+# Get difference between two lists.
+def sym_diff(l1, l2):
+    return list(set(l1).symmetric_difference(set(l2)))
+
+
+# Set Visibility of the figures
+def set_figure_visiblity(checkboxes):
+    checked = checkboxes.checked_labels
+    unchecked = sym_diff(list(figure_dict), checked)
+
+    for visible in checked:
+        figure_dict[visible].SetVisibility(True)
+
+    for invisible in unchecked:
+        figure_dict[invisible].SetVisibility(False)
+
+
+checkbox.on_change = set_figure_visiblity
+
+
+

After defining content, we define properties for the tab.

+
tab_ui.tabs[1].title = 'Checkbox'
+tab_ui.add_element(1, checkbox, (0.2, 0.2))
+
+
+
+
+

Color Combobox for Fury for Tab Index 2#

+

Now we prepare content for third tab.

+
label = ui.TextBlock2D(
+    position=(600, 300),
+    font_size=40,
+    color=(1, 0.5, 0),
+    justification='center',
+    vertical_justification='top',
+    text='FURY rocks!!!',
+)
+
+colors = {
+    'Violet': (0.6, 0, 0.8),
+    'Indigo': (0.3, 0, 0.5),
+    'Blue': (0, 0, 1),
+    'Green': (0, 1, 0),
+    'Yellow': (1, 1, 0),
+    'Orange': (1, 0.5, 0),
+    'Red': (1, 0, 0),
+}
+
+color_combobox = ui.ComboBox2D(
+    items=list(colors.keys()),
+    placeholder='Choose Text Color',
+    size=(250, 150),
+    draggable=True,
+)
+
+
+def change_color(combobox):
+    label.color = colors[combobox.selected_text]
+
+
+color_combobox.on_change = change_color
+
+
+

After defining content, we define properties for the tab.

+
tab_ui.tabs[2].title = 'Colors'
+tab_ui.add_element(2, color_combobox, (0.1, 0.3))
+
+
+

Define on_change & on_collapsed methods for tab ui to perform certain tasks +while active tab is changed or when the tab is collapsed. +Note: Tab UI can be collapsed by right clicking on it.

+
def hide_actors(tab_ui):
+    if tab_ui.tabs[tab_ui.active_tab_idx].title == 'Sliders':
+        cube.SetVisibility(True)
+        cylinder.SetVisibility(False)
+        sphere.SetVisibility(False)
+        label.set_visibility(False)
+
+    elif tab_ui.tabs[tab_ui.active_tab_idx].title == 'Checkbox':
+        cube.SetVisibility(False)
+        set_figure_visiblity(checkbox)
+        label.set_visibility(False)
+
+    else:
+        cube.SetVisibility(False)
+        cylinder.SetVisibility(False)
+        sphere.SetVisibility(False)
+        label.set_visibility(True)
+
+
+def collapse(tab_ui):
+    if tab_ui.collapsed:
+        cube.SetVisibility(False)
+        cylinder.SetVisibility(False)
+        sphere.SetVisibility(False)
+        label.set_visibility(False)
+
+
+tab_ui.on_change = hide_actors
+tab_ui.on_collapse = collapse
+
+
+

Next we prepare the scene and render it with the help of show manager.

+
sm = window.ShowManager(size=(800, 500), title='Viz Tab')
+sm.scene.add(tab_ui, cube, cylinder, sphere, label)
+
+# To interact with the ui set interactive = True
+interactive = False
+
+if interactive:
+    sm.start()
+
+window.record(sm.scene, size=(500, 500), out_path='viz_tab.png')
+
+
+viz tab

Total running time of the script: (0 minutes 0.071 seconds)

+ +

Gallery generated by Sphinx-Gallery

+
+
+ +
+ + +
+ +
+ + + + + +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/auto_examples/07_ui/viz_ui.html b/v0.10.x/auto_examples/07_ui/viz_ui.html new file mode 100644 index 000000000..1de1068ce --- /dev/null +++ b/v0.10.x/auto_examples/07_ui/viz_ui.html @@ -0,0 +1,839 @@ + + + + + + + + User Interfaces — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +
+

User Interfaces#

+

This example shows how to use the UI API. We will demonstrate how to create +several FURY UI elements, then use a list box to toggle which element is shown.

+

First, a bunch of imports.

+
import numpy as np
+
+from fury import actor, ui, window
+from fury.data import fetch_viz_icons, read_viz_icons
+
+
+
+

Shapes#

+

Let’s start by drawing some simple shapes. First, a rectangle.

+
rect = ui.Rectangle2D(size=(200, 200), position=(400, 300), color=(1, 0, 1))
+
+
+

Then we can draw a solid circle, or disk.

+
disk = ui.Disk2D(outer_radius=50, center=(500, 500), color=(1, 1, 0))
+
+
+

Add an inner radius to make a ring.

+
ring = ui.Disk2D(outer_radius=50, inner_radius=45, center=(500, 300), color=(0, 1, 1))
+
+
+
+
+

Image#

+

Now let’s display an image. First we need to fetch some icons that are +included in FURY.

+
fetch_viz_icons()
+
+
+
Data size is approximately 12KB
+Dataset is already in place. If you want to fetch it again please first remove the folder /Users/skoudoro/.fury/icons
+
+({'icomoon.tar.gz': ('https://digital.lib.washington.edu/researchworks/bitstream/handle/1773/38478/icomoon.tar.gz', 'BC1FEEA6F58BA3601D6A0B029EB8DFC5F352E21F2A16BA41099A96AA3F5A4735')}, '/Users/skoudoro/.fury/icons')
+
+
+

Now we can create an image container.

+
img = ui.ImageContainer2D(
+    img_path=read_viz_icons(fname='home3.png'), position=(450, 350)
+)
+
+
+
+
+

Panel with buttons and text#

+

Let’s create some buttons and text and put them in a panel. First we’ll +make the panel.

+
panel = ui.Panel2D(size=(300, 150), color=(1, 1, 1), align='right')
+panel.center = (500, 400)
+
+
+

Then we’ll make two text labels and place them on the panel. +Note that we specify the position with integer numbers of pixels.

+
text = ui.TextBlock2D(text='Click me')
+text2 = ui.TextBlock2D(text='Me too')
+panel.add_element(text, (50, 100))
+panel.add_element(text2, (180, 100))
+
+
+

Then we’ll create two buttons and add them to the panel.

+

Note that here we specify the positions with floats. In this case, these are +percentages of the panel size.

+
button_example = ui.Button2D(
+    icon_fnames=[('square', read_viz_icons(fname='stop2.png'))]
+)
+
+icon_files = []
+icon_files.append(('down', read_viz_icons(fname='circle-down.png')))
+icon_files.append(('left', read_viz_icons(fname='circle-left.png')))
+icon_files.append(('up', read_viz_icons(fname='circle-up.png')))
+icon_files.append(('right', read_viz_icons(fname='circle-right.png')))
+
+second_button_example = ui.Button2D(icon_fnames=icon_files)
+
+panel.add_element(button_example, (0.25, 0.33))
+panel.add_element(second_button_example, (0.66, 0.33))
+
+
+

We can add a callback to each button to perform some action.

+
def change_text_callback(i_ren, _obj, _button):
+    text.message = 'Clicked!'
+    i_ren.force_render()
+
+
+def change_icon_callback(i_ren, _obj, _button):
+    _button.next_icon()
+    i_ren.force_render()
+
+
+button_example.on_left_mouse_button_clicked = change_text_callback
+second_button_example.on_left_mouse_button_pressed = change_icon_callback
+
+
+
+
+

Cube and sliders#

+

Let’s add a cube to the scene and control it with sliders.

+
cube = actor.cube(
+    centers=np.array([[15, 0, 0]]),
+    colors=np.array([[0, 0, 1]]),
+    scales=np.array([[20, 20, 20]]),
+    directions=np.array([[0, 0, 1]]),
+)
+
+
+

Now we’ll add three sliders: one circular and two linear.

+
ring_slider = ui.RingSlider2D(
+    center=(740, 400), initial_value=0, text_template='{angle:5.1f}°'
+)
+
+line_slider_x = ui.LineSlider2D(
+    center=(500, 250),
+    initial_value=0,
+    min_value=-10,
+    max_value=10,
+    orientation='horizontal',
+)
+
+line_slider_y = ui.LineSlider2D(
+    center=(650, 350),
+    initial_value=0,
+    min_value=-10,
+    max_value=10,
+    orientation='vertical',
+)
+
+
+

We can use a callback to rotate the cube with the ring slider.

+
def rotate_cube(slider):
+    angle = slider.value
+    previous_angle = slider.previous_value
+    rotation_angle = angle - previous_angle
+    cube.RotateX(rotation_angle)
+
+
+ring_slider.on_change = rotate_cube
+
+
+

Similarly, we can translate the cube with line sliders. +We use global variables to keep track of the position of the cube.

+
cube_x = 0
+cube_y = 0
+
+
+def translate_cube_x(slider):
+    global cube_x, cube_y
+    cube_x = slider.value
+    cube.SetPosition(cube_x, cube_y, 0)
+
+
+def translate_cube_y(slider):
+    global cube_x, cube_y
+    cube_y = slider.value
+    cube.SetPosition(cube_x, cube_y, 0)
+
+
+line_slider_x.on_change = translate_cube_x
+line_slider_y.on_change = translate_cube_y
+
+
+
+
+

Range Slider#

+

Finally, we can add a range slider. This element is composed of two sliders. +The first slider has two handles which let you set the range of the second.

+
range_slider_x = ui.RangeSlider(
+    line_width=8,
+    handle_side=25,
+    range_slider_center=(450, 450),
+    value_slider_center=(450, 350),
+    length=150,
+    min_value=0,
+    max_value=10,
+    font_size=18,
+    range_precision=2,
+    value_precision=4,
+    shape='square',
+)
+
+range_slider_y = ui.RangeSlider(
+    line_width=8,
+    handle_side=25,
+    range_slider_center=(750, 400),
+    value_slider_center=(650, 400),
+    length=150,
+    min_value=0,
+    max_value=10,
+    font_size=18,
+    range_precision=2,
+    value_precision=4,
+    orientation='vertical',
+    shape='square',
+)
+
+
+
+
+

Select menu#

+

We just added many examples. If we showed them all at once, they would fill +the screen. Let’s make a simple menu to choose which example is shown.

+

We’ll first make a list of the examples.

+
examples = [
+    [rect],
+    [disk, ring],
+    [img],
+    [panel],
+    [ring_slider, line_slider_x, line_slider_y],
+    [range_slider_x, range_slider_y],
+]
+
+
+

Now we’ll make a function to hide all the examples. Then we’ll call it so +that none are shown initially.

+
def hide_all_examples():
+    for example in examples:
+        for element in example:
+            element.set_visibility(False)
+    cube.SetVisibility(False)
+
+
+hide_all_examples()
+
+
+

To make the menu, we’ll first need to create a list of labels which +correspond with the examples.

+
values = [
+    'Rectangle',
+    'Disks',
+    'Image',
+    'Button Panel',
+    'Line & Ring Slider',
+    'Range Slider',
+]
+
+
+

Now we can create the menu.

+
listbox = ui.ListBox2D(
+    values=values, position=(10, 300), size=(300, 200), multiselection=False
+)
+
+
+

Then we will use a callback to show the correct example when a label is +clicked.

+
def display_element():
+    hide_all_examples()
+    example = examples[values.index(listbox.selected[0])]
+    for element in example:
+        element.set_visibility(True)
+    if values.index(listbox.selected[0]) == 4:
+        cube.SetVisibility(True)
+
+
+listbox.on_change = display_element
+
+
+
+
+

Show Manager#

+

Now that all the elements have been initialised, we add them to the show +manager.

+
current_size = (800, 800)
+show_manager = window.ShowManager(size=current_size, title='FURY UI Example')
+
+show_manager.scene.add(listbox)
+for example in examples:
+    for element in example:
+        show_manager.scene.add(element)
+show_manager.scene.add(cube)
+show_manager.scene.reset_camera()
+show_manager.scene.set_camera(position=(0, 0, 200))
+show_manager.scene.reset_clipping_range()
+show_manager.scene.azimuth(30)
+
+# To interact with the UI, set interactive = True
+interactive = False
+
+if interactive:
+    show_manager.start()
+
+window.record(show_manager.scene, size=current_size, out_path='viz_ui.png')
+
+
+viz ui

Total running time of the script: (0 minutes 0.090 seconds)

+ +

Gallery generated by Sphinx-Gallery

+
+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/auto_examples/07_ui/viz_ui_listbox.html b/v0.10.x/auto_examples/07_ui/viz_ui_listbox.html new file mode 100644 index 000000000..ec6600a1b --- /dev/null +++ b/v0.10.x/auto_examples/07_ui/viz_ui_listbox.html @@ -0,0 +1,577 @@ + + + + + + + + ListBox — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +
+

ListBox#

+

This example shows how to use the UI API. We will create a list +some geometric shapes from FURY UI elements.

+

First, a bunch of imports.

+
from fury import ui, window
+from fury.data import fetch_viz_icons
+
+
+

First we need to fetch some icons that are included in FURY.

+
fetch_viz_icons()
+
+
+
Data size is approximately 12KB
+Dataset is already in place. If you want to fetch it again please first remove the folder /Users/skoudoro/.fury/icons
+
+({'icomoon.tar.gz': ('https://digital.lib.washington.edu/researchworks/bitstream/handle/1773/38478/icomoon.tar.gz', 'BC1FEEA6F58BA3601D6A0B029EB8DFC5F352E21F2A16BA41099A96AA3F5A4735')}, '/Users/skoudoro/.fury/icons')
+
+
+

Create some text blocks that will be shown when +list elements will be selected

+
welcome_text = ui.TextBlock2D(text='Welcome', font_size=30, position=(500, 400))
+bye_text = ui.TextBlock2D(text='Bye', font_size=30, position=(500, 400))
+fury_text = ui.TextBlock2D(text='Fury', font_size=30, position=(500, 400))
+
+example = [welcome_text, bye_text, fury_text]
+
+
+

Hide these text blocks for now

+
def hide_all_examples():
+    for element in example:
+        element.set_visibility(False)
+
+
+hide_all_examples()
+
+
+

Create ListBox with the values as parameter.

+
values = ['Welcome', 'Bye', 'Fury']
+listbox = ui.ListBox2D(
+    values=values, position=(10, 300), size=(200, 200), multiselection=False
+)
+
+
+

Function to show selected element.

+
def display_element():
+    hide_all_examples()
+    element = example[values.index(listbox.selected[0])]
+    element.set_visibility(True)
+
+
+listbox.on_change = display_element
+
+
+

Now that all the elements have been initialised, we add them to the show +manager.

+
current_size = (800, 800)
+show_manager = window.ShowManager(size=current_size, title='FURY UI ListBox_Example')
+
+show_manager.scene.add(listbox)
+show_manager.scene.add(welcome_text)
+show_manager.scene.add(bye_text)
+show_manager.scene.add(fury_text)
+interactive = False
+
+if interactive:
+    show_manager.start()
+
+window.record(show_manager.scene, size=current_size, out_path='viz_listbox.png')
+
+
+viz ui listbox

Total running time of the script: (0 minutes 0.077 seconds)

+ +

Gallery generated by Sphinx-Gallery

+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/auto_examples/07_ui/viz_ui_slider.html b/v0.10.x/auto_examples/07_ui/viz_ui_slider.html new file mode 100644 index 000000000..fb810fbdf --- /dev/null +++ b/v0.10.x/auto_examples/07_ui/viz_ui_slider.html @@ -0,0 +1,670 @@ + + + + + + + + Cube & Slider Control — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +
+

Cube & Slider Control#

+

This example shows how to use the UI API. We will demonstrate how to +create a cube and control with sliders.

+

First, some imports.

+
import numpy as np
+
+from fury import actor, ui, window
+from fury.data import fetch_viz_icons
+
+
+

First we need to fetch some icons that are included in FURY.

+
fetch_viz_icons()
+
+
+
Data size is approximately 12KB
+Dataset is already in place. If you want to fetch it again please first remove the folder /Users/skoudoro/.fury/icons
+
+({'icomoon.tar.gz': ('https://digital.lib.washington.edu/researchworks/bitstream/handle/1773/38478/icomoon.tar.gz', 'BC1FEEA6F58BA3601D6A0B029EB8DFC5F352E21F2A16BA41099A96AA3F5A4735')}, '/Users/skoudoro/.fury/icons')
+
+
+
+

Cube and sliders#

+

Add a cube to the scene .

+
cube = actor.cube(
+    centers=np.array([[15, 0, 0]]),
+    colors=np.array([[0, 0, 1]]),
+    scales=np.array([[20, 20, 20]]),
+    directions=np.array([[0, 0, 1]]),
+)
+
+
+

Now we’ll add five sliders: 1 circular and 4 linear sliders. +By default the alignments are ‘bottom’ for horizontal and ‘top’ for vertical.

+
ring_slider = ui.RingSlider2D(
+    center=(630, 400), initial_value=0, text_template='{angle:5.1f}°'
+)
+
+hor_line_slider_text_top = ui.LineSlider2D(
+    center=(400, 230),
+    initial_value=0,
+    orientation='horizontal',
+    min_value=-10,
+    max_value=10,
+    text_alignment='top',
+)
+
+hor_line_slider_text_bottom = ui.LineSlider2D(
+    center=(400, 200),
+    initial_value=0,
+    orientation='horizontal',
+    min_value=-10,
+    max_value=10,
+    text_alignment='bottom',
+)
+
+ver_line_slider_text_left = ui.LineSlider2D(
+    center=(100, 400),
+    initial_value=0,
+    orientation='vertical',
+    min_value=-10,
+    max_value=10,
+    text_alignment='left',
+)
+
+ver_line_slider_text_right = ui.LineSlider2D(
+    center=(150, 400),
+    initial_value=0,
+    orientation='vertical',
+    min_value=-10,
+    max_value=10,
+    text_alignment='right',
+)
+
+
+

We can use a callback to rotate the cube with the ring slider.

+
def rotate_cube(slider):
+    angle = slider.value
+    previous_angle = slider.previous_value
+    rotation_angle = angle - previous_angle
+    cube.RotateX(rotation_angle)
+
+
+ring_slider.on_change = rotate_cube
+
+
+

Similarly, we can translate the cube with the line slider.

+
def translate_cube_ver(slider):
+    value = slider.value
+    cube.SetPosition(0, value, 0)
+
+
+def translate_cube_hor(slider):
+    value = slider.value
+    cube.SetPosition(value, 0, 0)
+
+
+hor_line_slider_text_top.on_change = translate_cube_hor
+hor_line_slider_text_bottom.on_change = translate_cube_hor
+ver_line_slider_text_left.on_change = translate_cube_ver
+ver_line_slider_text_right.on_change = translate_cube_ver
+
+
+
+
+

Show Manager#

+

Now that all the elements have been initialised, we add them to the show +manager.

+
current_size = (800, 800)
+show_manager = window.ShowManager(size=current_size, title='FURY Cube Example')
+
+show_manager.scene.add(cube)
+show_manager.scene.add(ring_slider)
+show_manager.scene.add(hor_line_slider_text_top)
+show_manager.scene.add(hor_line_slider_text_bottom)
+show_manager.scene.add(ver_line_slider_text_left)
+show_manager.scene.add(ver_line_slider_text_right)
+
+
+

Visibility by default is True

+ +

Set camera for better visualization

+ +viz ui slider

Total running time of the script: (0 minutes 0.079 seconds)

+ +

Gallery generated by Sphinx-Gallery

+
+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ +
+ On this page +
+ +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/auto_examples/10_animation/index.html b/v0.10.x/auto_examples/10_animation/index.html new file mode 100644 index 000000000..2e92667d4 --- /dev/null +++ b/v0.10.x/auto_examples/10_animation/index.html @@ -0,0 +1,533 @@ + + + + + + + + Animation — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Animation#

+

These tutorials show:

+
    +
  • How to animate FURY actors.

  • +
  • How to use different interpolation methods in animations.

  • +
+
+

Keyframe animation introduction

+
Keyframe animation introduction
+
+

Timeline and setting keyframes

+
Timeline and setting keyframes
+
+

Keyframes Spline Interpolator

+
Keyframes Spline Interpolator
+
+

Keyframe animation

+
Keyframe animation
+
+

Keyframe animation

+
Keyframe animation
+
+

Keyframe Color Interpolators

+
Keyframe Color Interpolators
+
+

Arm Robot Animation

+
Arm Robot Animation
+
+

Keyframe hierarchical Animation

+
Keyframe hierarchical Animation
+
+

Bezier Interpolator

+
Bezier Interpolator
+
+

Keyframe animation: Camera and opacity

+
Keyframe animation: Camera and opacity
+
+

Making a custom interpolator

+
Making a custom interpolator
+
+
+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/auto_examples/10_animation/sg_execution_times.html b/v0.10.x/auto_examples/10_animation/sg_execution_times.html new file mode 100644 index 000000000..a10aa8297 --- /dev/null +++ b/v0.10.x/auto_examples/10_animation/sg_execution_times.html @@ -0,0 +1,536 @@ + + + + + + + + Computation times — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Computation times#

+

00:00.700 total execution time for 11 files from auto_examples/10_animation:

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Example

Time

Mem (MB)

Keyframe animation: Camera and opacity (viz_camera.py)

00:00.585

0.0

Making a custom interpolator (viz_custom_interpolator.py)

00:00.115

0.0

Bezier Interpolator (viz_bezier_interpolator.py)

00:00.000

0.0

Keyframe Color Interpolators (viz_color_interpolators.py)

00:00.000

0.0

Keyframe hierarchical Animation (viz_hierarchical_animation.py)

00:00.000

0.0

Keyframe animation (viz_interpolators.py)

00:00.000

0.0

Keyframe animation introduction (viz_introduction.py)

00:00.000

0.0

Arm Robot Animation (viz_robot_arm_animation.py)

00:00.000

0.0

Keyframes Spline Interpolator (viz_spline_interpolator.py)

00:00.000

0.0

Timeline and setting keyframes (viz_timeline.py)

00:00.000

0.0

Keyframe animation (viz_using_time_equations.py)

00:00.000

0.0

+
+
+ +
+ + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/auto_examples/10_animation/viz_bezier_interpolator.html b/v0.10.x/auto_examples/10_animation/viz_bezier_interpolator.html new file mode 100644 index 000000000..d076ef7df --- /dev/null +++ b/v0.10.x/auto_examples/10_animation/viz_bezier_interpolator.html @@ -0,0 +1,726 @@ + + + + + + + + Bezier Interpolator — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +
+

Bezier Interpolator#

+

Keyframe animation using cubic Bezier interpolator.

+
import numpy as np
+
+from fury import actor, window
+from fury.animation import Animation, Timeline
+from fury.animation.interpolator import cubic_bezier_interpolator
+
+
+
+

Position interpolation using cubic Bezier curve#

+

Cubic bezier curve is a widely used method for interpolating motion paths. +This can be achieved using positions and control points between those +positions.

+
scene = window.Scene()
+showm = window.ShowManager(
+    scene, size=(900, 768), reset_camera=False, order_transparent=True
+)
+
+
+
+
+

Cubic Bezier curve parameters#

+

In order to make a cubic bezier curve based animation, you need four values +for every keyframe: +1- Timestamp: The time that the keyframe is assigned to. +2- value: The value of the keyframe. This might be position, quaternion, or

+
+

scale value.

+
+
+
3- In control point: The control point used when the value is the destination

value.

+
+
4- Out control point: The control point used when the value is the departure
+

value:

+
+

keyframe 0 —————–> keyframe 1

+
+
+

(time-0) (value-0) (out-cp-0) —————–> (time-1) (value-1) (in-cp-1)

+
+

keyframe 1 —————–> keyframe 2

+
+

(time-1) (value-1) (out-cp-1) —————–> (time-2) (value-2) (in-cp-2)

+
keyframe_1 = {'value': [-2, 0, 0], 'out_cp': [-15, 6, 0]}
+keyframe_2 = {'value': [18, 0, 0], 'in_cp': [27, 18, 0]}
+
+
+

Visualizing points

+
pts_actor = actor.sphere(
+    np.array([keyframe_1.get('value'), keyframe_2.get('value')]), (1, 0, 0), radii=0.3
+)
+
+
+

Visualizing the control points

+
cps_actor = actor.sphere(
+    np.array([keyframe_2.get('in_cp'), keyframe_1.get('out_cp')]), (0, 0, 1), radii=0.6
+)
+
+
+

Visualizing the connection between the control points and the points

+
cline_actor = actor.line(
+    np.array([list(keyframe_1.values()), list(keyframe_2.values())]),
+    colors=np.array([0, 1, 0]),
+)
+
+
+

Initializing an Animation and adding sphere actor to it.

+
animation = Animation()
+sphere = actor.sphere(np.array([[0, 0, 0]]), (1, 0, 1))
+animation.add_actor(sphere)
+
+
+
+
+

Setting Cubic Bezier keyframes#

+

Cubic Bezier keyframes consists of 4 data per keyframe +Timestamp, position, in control point, and out control point. +- In control point is the cubic bezier control point for the associated

+
+

position when this position is the destination position.

+
+
    +
  • Out control point is the cubic bezier control point for the associated +position when this position is the origin position or departing position.

  • +
+

Note: If a control point is not provided or set None, this control point +will be the same as the position itself.

+
animation.set_position(
+    0.0, np.array(keyframe_1.get('value')), out_cp=np.array(keyframe_1.get('out_cp'))
+)
+animation.set_position(
+    5.0, np.array(keyframe_2.get('value')), in_cp=np.array(keyframe_2.get('in_cp'))
+)
+
+
+

Changing position interpolation into cubic bezier interpolation

+
animation.set_position_interpolator(cubic_bezier_interpolator)
+
+
+

Adding the visualization actors to the scene.

+
scene.add(pts_actor, cps_actor, cline_actor)
+
+
+

Adding the animation to the ShowManager

+
showm.add_animation(animation)
+
+interactive = False
+
+if interactive:
+    showm.start()
+
+window.record(scene, out_path='viz_keyframe_animation_bezier_1.png', size=(900, 768))
+
+
+viz bezier interpolator
+
+

A more complex scene scene#

+
scene = window.Scene()
+show_manager = window.ShowManager(
+    scene, size=(900, 768), reset_camera=False, order_transparent=True
+)
+
+
+

Note: If a control point is set to None, it gets the value of the +point it controls.

+
keyframes = {
+    # time - position - in control point  - out control point
+    0.0: {'value': [-2, 0, 0], 'out_cp': [-15, 6, 0]},
+    5.0: {'value': [18, 0, 0], 'in_cp': [27, 18, 0], 'out_cp': [27, -18, 0]},
+    9.0: {'value': [-5, -10, -10]},
+}
+
+
+

Create the sphere actor.

+
sphere = actor.sphere(np.array([[0, 0, 0]]), (1, 0, 1))
+
+
+

Create an Animation and adding the sphere actor to it.

+
animation = Animation(sphere)
+
+
+

Setting Cubic Bezier keyframes

+
animation.set_position_keyframes(keyframes)
+
+
+

changing position interpolation into cubic bezier interpolation

+
animation.set_position_interpolator(cubic_bezier_interpolator)
+
+
+

visualizing the points and control points (only for demonstration)

+
for t, keyframe in keyframes.items():
+    pos = keyframe.get('value')
+    in_control_point = keyframe.get('in_cp')
+    out_control_point = keyframe.get('out_cp')
+
+    ###########################################################################
+    # visualizing position keyframe
+    vis_point = actor.sphere(np.array([pos]), (1, 0, 0), radii=0.3)
+    scene.add(vis_point)
+
+    ###########################################################################
+    # Visualizing the control points and their length (if exist)
+    for cp in [in_control_point, out_control_point]:
+        if cp is not None:
+            vis_cps = actor.sphere(np.array([cp]), (0, 0, 1), radii=0.6)
+            cline_actor = actor.line(np.array([[pos, cp]]), colors=np.array([0, 1, 0]))
+            scene.add(vis_cps, cline_actor)
+
+
+

Initializing the timeline to be able to control the playback of the +animation.

+
timeline = Timeline(animation, playback_panel=True)
+
+
+

We only need to add the Timeline to the ShowManager

+ +

Start the animation

+
if interactive:
+    show_manager.start()
+
+window.record(scene, out_path='viz_keyframe_animation_bezier_2.png', size=(900, 768))
+
+
+viz bezier interpolator

Total running time of the script: (0 minutes 0.212 seconds)

+ +

Gallery generated by Sphinx-Gallery

+
+
+ +
+ + +
+ +
+ + + + + +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/auto_examples/10_animation/viz_camera.html b/v0.10.x/auto_examples/10_animation/viz_camera.html new file mode 100644 index 000000000..b4081b014 --- /dev/null +++ b/v0.10.x/auto_examples/10_animation/viz_camera.html @@ -0,0 +1,717 @@ + + + + + + + + Keyframe animation: Camera and opacity — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +
+

Keyframe animation: Camera and opacity#

+

Camera and opacity keyframe animation explained in this tutorial.

+
import numpy as np
+
+from fury import actor, window
+from fury.animation import Animation, CameraAnimation, Timeline
+from fury.animation.interpolator import cubic_spline_interpolator
+
+
+
+

The Plan#

+

The plan here is to animate (scale and translate) 50 spheres randomly, and +show FURY text that appears at the end!

+
scene = window.Scene()
+
+showm = window.ShowManager(
+    scene, size=(900, 768), reset_camera=False, order_transparent=True
+)
+
+
+
+
+

Creating the main Timeline and adding static actors to it#

+

Here we create a Timeline. so that we can use it as a controller for the +50 animations we will create. +So, Instead of updating and adding 50 Animations to the ShowManager, +we only need to update the main Timeline. Also, a playback panel can be +assigned to this main Timeline.

+

But, why we need 50 Animations, you may ask. +-> A single Animation can handle each property once at a time. So we need +50 Animations to translate and scale our 50 spheres.

+

playback_panel=True assigns a playback panel that can control the +playback of its Animations

+
timeline = Timeline(playback_panel=True)
+
+
+

Creating two actors for visualization, and to detect camera’s animations.

+
arrow = actor.arrow(
+    np.array([[0, 0, 0]]), np.array([[0, 1, 0]]), np.array([[1, 1, 0]]), scales=5
+)
+plan = actor.box(
+    np.array([[0, 0, 0]]),
+    colors=np.array([[1, 1, 1]]),
+    scales=np.array([[20, 0.2, 20]]),
+)
+
+
+
+
+

Creating “FURY” text#

+
fury_text = actor.vector_text('FURY', pos=(-4.3, 15, 0), scale=(2, 2, 2))
+
+
+

Creating an Animation to animate the opacity of fury_text

+
text_anim = Animation(fury_text, loop=False)
+
+
+

opacity is set to 0 at time 29 and set to one at time 35. +Linear interpolator is always used by default.

+
text_anim.set_opacity(29, 0)
+text_anim.set_opacity(35, 1)
+
+
+

text_anim contains the text actor is added to the Timeline.

+
timeline.add_animation(text_anim)
+
+
+
+
+

Creating and animating 50 Spheres#

+
for i in range(50):
+    ###########################################################################
+    # create a sphere actor that's centered at the origin and has random color
+    # and radius.
+    actors = [
+        actor.sphere(
+            np.array([[0, 0, 0]]), np.random.random([1, 3]), np.random.random([1, 3])
+        )
+    ]
+
+    ###########################################################################
+    # create a timeline to animate this actor (single actor or list of actors)
+    # Actors can be added later using `Timeline.add_actor(actor)`
+    animation = Animation(actors)
+
+    # We generate random position and scale values from time=0 to time=49 each
+    # two seconds.
+    for t in range(0, 50, 2):
+        #######################################################################
+        # Position and scale are set to a random value at the timestamps
+        # mentioned above.
+        animation.set_position(t, np.random.random(3) * 30 - np.array([15, 0, 15]))
+        animation.set_scale(t, np.repeat(np.random.random(1), 3))
+
+    ###########################################################################
+    # change the position interpolator to cubic spline interpolator.
+    animation.set_position_interpolator(cubic_spline_interpolator)
+
+    ###########################################################################
+    # Finally, the ``Animation`` is added to the ``Timeline``.
+    timeline.add_animation(animation)
+
+
+
+
+

Animating the camera#

+

Since, only one camera is needed, camera animations are preferably done using +a separate Animation. +Three properties can control the camera’s animation: +Position, focal position (referred to by focal), and up-view.

+
camera_anim = CameraAnimation(loop=False)
+timeline.add_animation(camera_anim)
+
+
+

Multiple keyframes can be set at once as follows. +camera focal positions

+
camera_positions = {
+    # time: camera position
+    0: np.array([3, 3, 3]),
+    4: np.array([50, 25, -40]),
+    7: np.array([-50, 50, -40]),
+    10: np.array([-25, 25, 20]),
+    14: np.array([0, 16, 25]),
+    20: np.array([0, 14.5, 20]),
+}
+
+# camera focal positions
+camera_focal_positions = {
+    # time: focal position
+    15: np.array([0, 0, 0]),
+    20: np.array([3, 9, 5]),
+    23: np.array([7, 5, 3]),
+    25: np.array([-2, 9, -6]),
+    27: np.array([0, 16, 0]),
+    31: np.array([0, 14.5, 0]),
+}
+
+
+

set_camera_focal can only set one keyframe, but +set_camera_focal_keyframes can set a dictionary of keyframes.

+
camera_anim.set_focal_keyframes(camera_focal_positions)
+camera_anim.set_position_keyframes(camera_positions)
+
+
+

Change camera position and focal interpolators

+
camera_anim.set_position_interpolator(cubic_spline_interpolator)
+camera_anim.set_focal_interpolator(cubic_spline_interpolator)
+
+
+

Adding non-animatable actors to the scene.

+
scene.add(arrow, plan)
+
+
+

Adding the timeline to the ShowManager.

+
+
+

The ShowManager must go on!

+
interactive = False
+
+if interactive:
+    showm.start()
+
+window.record(scene, out_path='viz_keyframe_animation_camera.png', size=(900, 768))
+
+
+viz camera

Total running time of the script: (0 minutes 0.585 seconds)

+ +

Gallery generated by Sphinx-Gallery

+
+
+ +
+ + +
+ +
+ + + + + +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/auto_examples/10_animation/viz_color_interpolators.html b/v0.10.x/auto_examples/10_animation/viz_color_interpolators.html new file mode 100644 index 000000000..4ec6b7ef8 --- /dev/null +++ b/v0.10.x/auto_examples/10_animation/viz_color_interpolators.html @@ -0,0 +1,627 @@ + + + + + + + + Keyframe Color Interpolators — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +
+

Keyframe Color Interpolators#

+

Color animation explained in this tutorial and how to use different color +space interpolators.

+
import numpy as np
+
+from fury import actor, window
+from fury.animation import Animation
+from fury.animation.interpolator import (
+    hsv_color_interpolator,
+    lab_color_interpolator,
+    step_interpolator,
+    xyz_color_interpolator,
+)
+from fury.animation.timeline import Timeline
+from fury.colormap import distinguishable_colormap
+
+scene = window.Scene()
+
+showm = window.ShowManager(
+    scene, size=(900, 768), reset_camera=False, order_transparent=True
+)
+
+
+

Initializing positions of the cubes that will be color-animated.

+
cubes_pos = np.array(
+    [
+        [[-2, 0, 0]],
+        [[0, 0, 0]],
+        [[2, 0, 0]],
+        [[4, 0, 0]],
+        [[6, 0, 0]],
+    ]
+)
+
+
+

Static labels for different interpolators (for show)

+
linear_text = actor.vector_text('Linear', (-2.64, -1, 0))
+lab_text = actor.vector_text('LAB', (-0.37, -1, 0))
+hsv_text = actor.vector_text('HSV', (1.68, -1, 0))
+xyz_text = actor.vector_text('XYZ', (3.6, -1, 0))
+step_text = actor.vector_text('Step', (5.7, -1, 0))
+scene.add(step_text, lab_text, linear_text, hsv_text, xyz_text)
+
+
+

Creating an animation to animate the actor. +Also cube actor is provided for each timeline to handle as follows: +Animation(actor), Animation(list_of_actors), or actors can be added +later using animation.add() or animation.add_actor()

+
anim_linear_color = Animation(actor.cube(cubes_pos[0]))
+anim_LAB_color = Animation(actor.cube(cubes_pos[1]))
+anim_HSV_color = Animation(actor.cube(cubes_pos[2]))
+anim_XYZ_color = Animation(actor.cube(cubes_pos[3]))
+anim_step_color = Animation(actor.cube(cubes_pos[4]))
+
+
+

Creating a timeline to control all the animations (one for each color +interpolation method)

+
timeline = Timeline(playback_panel=True)
+
+
+

Adding animations to a Timeline.

+
timeline.add_animation(
+    [anim_linear_color, anim_LAB_color, anim_HSV_color, anim_XYZ_color, anim_step_color]
+)
+
+
+
+

Setting color keyframes#

+

Setting the same color keyframes to all the animations

+

First, we generate some distinguishable colors

+
+
+

Then, we set them as keyframes for the animations

+
for t in range(0, 20, 5):
+    col = colors.pop()
+    anim_linear_color.set_color(t, col)
+    anim_LAB_color.set_color(t, col)
+    anim_HSV_color.set_color(t, col)
+    anim_XYZ_color.set_color(t, col)
+    anim_step_color.set_color(t, col)
+
+
+

Changing the default scale interpolator to be a step interpolator +The default is linear interpolator for color keyframes

+
anim_HSV_color.set_color_interpolator(hsv_color_interpolator)
+anim_LAB_color.set_color_interpolator(lab_color_interpolator)
+anim_step_color.set_color_interpolator(step_interpolator)
+anim_XYZ_color.set_color_interpolator(xyz_color_interpolator)
+
+
+

Adding the main timeline to the show manager

+
showm.add_animation(timeline)
+
+interactive = False
+
+if interactive:
+    showm.start()
+
+window.record(scene, out_path='viz_keyframe_animation_colors.png', size=(900, 768))
+
+
+viz color interpolators

Total running time of the script: (0 minutes 0.109 seconds)

+ +

Gallery generated by Sphinx-Gallery

+
+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ +
+ On this page +
+ +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/auto_examples/10_animation/viz_custom_interpolator.html b/v0.10.x/auto_examples/10_animation/viz_custom_interpolator.html new file mode 100644 index 000000000..343c50b95 --- /dev/null +++ b/v0.10.x/auto_examples/10_animation/viz_custom_interpolator.html @@ -0,0 +1,692 @@ + + + + + + + + Making a custom interpolator — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +
+

Making a custom interpolator#

+

Keyframe animation using custom interpolator.

+
import numpy as np
+
+from fury import actor, window
+from fury.animation import Animation, helpers
+
+
+
+

Implementing a custom interpolator#

+

A keyframe interpolator function must return a function which take the time +as an argument and returns a value. +It’s recommended to import fury.animation.helpers, which has some useful +functions that would help to implement the interpolator.

+

In glTF, animations using cubic spline interpolator needs at least two +points, and each point has two tangent vectors. +The interpolation equation for such data is in the glTF tutorials below: +https://github.khronos.org/glTF-Tutorials/gltfTutorial/gltfTutorial_007_Animations.html#cubic-spline-interpolation

+

Tangent based cubic spline interpolation function:

+
>>> def cubicSpline(previousPoint, previousTangent, nextPoint, nextTangent,
+>>>                   interpolationValue):
+>>>     t = interpolationValue
+>>>     t2 = t * t
+>>>     t3 = t2 * t
+>>>     return (2 * t3 - 3 * t2 + 1) * previousPoint +
+>>>            (t3 - 2 * t2 + t) * previousTangent +
+>>>            (-2 * t3 + 3 * t2) * nextPoint +
+>>>            (t3 - t2) * nextTangent
+
+
+

First we create a function that must take a dict object that contains the +animation keyframes when initialized as follows:

+
>>> def tan_cubic_spline_interpolator(keyframes):
+>>>     ...
+>>>     def interpolate(t):
+>>>           return interpolated_value
+>>>     return interpolator
+
+
+

Note: Also any other additional arguments are ok, see spline_interpolator +Second step is to implement the interpolate closure that only takes the +current time as input.

+
def tan_cubic_spline_interpolator(keyframes):
+    # First we must get ordered timestamps array:
+    timestamps = helpers.get_timestamps_from_keyframes(keyframes)
+
+    # keyframes should be on the following form:
+    # {
+    # 1: {'value': ndarray, 'in_tangent': ndarray, 'out_tangent': ndarray},
+    # 2: {'value': np.array([1, 2, 3], 'in_tangent': ndarray},
+    # }
+    # See here, we might get incomplete data (out_tangent) in the second
+    # keyframe. In this case we need to have a default behaviour dealing
+    # with these missing data.
+    # Setting the tangent to a zero vector in this case is the best choice
+    for time in keyframes:
+        data = keyframes.get(time)
+        value = data.get('value')
+        if data.get('in_tangent') is None:
+            data['in_tangent'] = np.zeros_like(value)
+        if data.get('in_tangent') is None:
+            data['in_tangent'] = np.zeros_like(value)
+
+    def interpolate(t):
+        # `get_previous_timestamp`and `get_next_timestamp` functions take
+        # timestamps array and current time as inputs and returns the
+        # surrounding timestamps.
+        t0 = helpers.get_previous_timestamp(timestamps, t)
+        t1 = helpers.get_next_timestamp(timestamps, t)
+
+        # `get_time_tau` function takes current time and surrounding
+        # timestamps and returns a value from 0 to 1
+        dt = helpers.get_time_tau(t, t0, t1)
+
+        time_delta = t1 - t0
+
+        # to get a keyframe data at a specific timestamp, use
+        # `keyframes.get(t0)`. This keyframe data contains `value` and any
+        # other data set as a custom argument using keyframe setters.
+        # for example:
+        # >>> animation = Animation()
+        # >>> animation.set_position(0, np.array([1, 1, 1]),
+        # >>>                       custom_field=np.array([2, 3, 1]))
+        # In this case `keyframes.get(0)` would return:
+        # {'value': array(1, 1, 1), 'custom_field': array(2, 3, 1)}
+        #
+        # now we continue with the cubic spline equation.
+        p0 = keyframes.get(t0).get('value')
+        tan_0 = keyframes.get(t0).get('out_tangent') * time_delta
+        p1 = keyframes.get(t1).get('value')
+        tan_1 = keyframes.get(t1).get('in_tangent') * time_delta
+        # cubic spline equation using tangents
+        t2 = dt * dt
+        t3 = t2 * dt
+        return (
+            (2 * t3 - 3 * t2 + 1) * p0
+            + (t3 - 2 * t2 + dt) * tan_0
+            + (-2 * t3 + 3 * t2) * p1
+            + (t3 - t2) * tan_1
+        )
+
+    return interpolate
+
+
+scene = window.Scene()
+showm = window.ShowManager(
+    scene, size=(900, 768), reset_camera=False, order_transparent=True
+)
+
+
+
+
+

Cubic spline keyframes data same as the one you get from glTF file.#

+
#               t    in tangent     position                   out tangent
+translation = [
+    [0.0, [0.0, 0.0, 0.0], [3.3051798, 6.640117, 0.0], [1.0, 0.0, 0.0]],
+    [1.0, [0.0, 0.0, 0.0], [3.3051798, 8.0, 0.0], [-1.0, 0.0, 0.0]],
+    [2.0, [-1.0, 0.0, 0.0], [3.3051798, 6.0, 0.0], [1.0, 0.0, 0.0]],
+    [3.0, [0.0, 0.0, 0.0], [3.3051798, 8.0, 0.0], [-1.0, 0.0, 0.0]],
+    [4.0, [0, -1.0, 0.0], [3.3051798, 6.0, 0.0], [0.0, 0.0, 0.0]],
+]
+
+
+

Initializing an Animation and adding sphere actor to it.

+
animation = Animation(motion_path_res=100)
+
+sphere = actor.sphere(np.array([[0, 0, 0]]), (1, 0, 1), radii=0.1)
+
+animation.add_actor(sphere)
+
+
+
+
+

Setting position keyframes#

+
for keyframe_data in translation:
+    t, in_tan, pos, out_tan = keyframe_data
+    # Since we used the name 'in_tangent' and 'out_tangent' in the interpolator
+    # We must use the same name as an argument to set it in the keyframe data.
+    animation.set_position(t, pos, in_tangent=in_tan, out_tangent=out_tan)
+
+
+

Set the new interpolator to interpolate position keyframes

+
animation.set_position_interpolator(tan_cubic_spline_interpolator)
+
+
+

adding the animation to the show manager.

+
showm.add_animation(animation)
+
+
+interactive = False
+
+if interactive:
+    showm.start()
+
+window.record(scene, out_path='viz_keyframe_custom_interpolator.png', size=(900, 768))
+
+
+viz custom interpolator

Total running time of the script: (0 minutes 0.115 seconds)

+ +

Gallery generated by Sphinx-Gallery

+
+
+ +
+ + +
+ +
+ + + + + +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/auto_examples/10_animation/viz_hierarchical_animation.html b/v0.10.x/auto_examples/10_animation/viz_hierarchical_animation.html new file mode 100644 index 000000000..44e3b3107 --- /dev/null +++ b/v0.10.x/auto_examples/10_animation/viz_hierarchical_animation.html @@ -0,0 +1,644 @@ + + + + + + + + Keyframe hierarchical Animation — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +
+

Keyframe hierarchical Animation#

+

Creating hierarchical keyframes animation in fury

+
import numpy as np
+
+from fury import actor, window
+from fury.animation import Animation
+
+scene = window.Scene()
+
+showm = window.ShowManager(
+    scene, size=(900, 768), reset_camera=False, order_transparent=True
+)
+showm.initialize()
+
+
+

Creating the road

+
road = actor.box(
+    np.array([[0, 0, 0]]), colors=np.array([[1, 1, 1]]), scales=np.array([[22, 0.1, 5]])
+)
+
+
+

Constructing the car geometry

+
body_actor = actor.box(
+    np.array([[0, 0.5, 0], [-0.2, 1, 0]]),
+    scales=((4, 1, 2), (2.5, 1.5, 1.8)),
+    colors=(0.6, 0.3, 0.1),
+)
+
+
+

Adding the the car’s body to an Animation to be able to animate it later.

+
car_anim = Animation(body_actor)
+
+
+

Creating the wheels of the car

+
wheel_center = np.array([[0, 0, 0]])
+
+wheel_direction = np.array([[0, 0, 1]])
+wheel_positions = [
+    [1.2, 0, 1.1],
+    [-1.2, 0, 1.1],
+    [1.2, 0, -1.1],
+    [-1.2, 0, -1.1],
+]
+
+wheels = [
+    actor.cylinder(
+        wheel_center,
+        wheel_direction,
+        (0.1, 0.7, 0.3),
+        radius=1.7,
+        heights=0.3,
+        resolution=10,
+        capped=True,
+    )
+    for _ in range(4)
+]
+
+
+

Animating each wheel and setting its position to the right position using a +single keyframe that will not change.

+
wheels_animations = [Animation(wheel) for wheel in wheels]
+
+for wheel_anim in wheels_animations:
+    wheel_anim.set_position(0.0, wheel_positions.pop())
+    wheel_anim.set_rotation(0.0, [0, 0, 1, 1])
+    wheel_anim.set_rotation(1.0, [0, 0, 1, -1])
+
+
+

Creating a radar on top of the car

+

First we create the shaft holding and rotating the radar

+
radar_shaft = actor.cylinder(
+    np.array([[0, 0, 0]]), np.array([[0, 1, 0]]), (0, 1, 0), heights=1
+)
+
+
+

In order to animate the shaft actor we have to add it to an Animation

+
radar_shaft_anim = Animation(radar_shaft)
+
+
+

Setting a single position keyframe will make sure the actor will be placed at +that position

+
radar_shaft_anim.set_position(0.0, [0, 2, 0])
+
+
+

Rotating the shaft around Y axis

+
radar_shaft_anim.set_rotation(0.0, [0, -250, 0])
+radar_shaft_anim.set_rotation(1.0, [0, 250, 0])
+radar_shaft_anim.set_rotation(2.0, [0, -250, 0])
+
+
+

Now we create the radar itself

+
radar = actor.cone(np.array([[0, 0, 0]]), directions=(0, 0, 0), colors=(0.2, 0.2, 0.9))
+
+
+

Then add it to an animation in order to rotate it

+
radar_animation = Animation(radar)
+
+
+

Set position and rotation as done above with the shaft.

+
radar_animation.set_position(0, [-0.4, 0.5, 0])
+radar_animation.set_rotation(0.0, [0, 0, 0])
+radar_animation.set_rotation(1.0, [180, 0, 0])
+radar_animation.set_rotation(2.0, [0, 0, 0])
+
+
+

Now, we want the radar to rotate when the shaft rotates in hierarchical way. +To do that we must add the radar animation as a child animation of the shaft +animation as below:

+
radar_shaft_anim.add_child_animation(radar_animation)
+
+
+

After that we want everything to animate related to the car. +The wheels should always be attached to the car no matter where it moves. +we do that by adding them as child animations of the car’s body animation

+
car_anim.add_child_animation([wheels_animations, radar_shaft_anim])
+
+
+

Moving the car

+
car_anim.set_position(0.0, [-10, 0.5, 0])
+car_anim.set_position(6.0, [10, 0.5, 0])
+
+
+

Adding the car Animation to the show manager

+
showm.add_animation(car_anim)
+scene.add(road)
+scene.camera().SetPosition(0, 20, 30)
+
+interactive = False
+
+if interactive:
+    showm.start()
+
+window.record(
+    scene, out_path='viz_keyframe_hierarchical_animation.png', size=(900, 768)
+)
+
+
+viz hierarchical animation

Total running time of the script: (0 minutes 0.102 seconds)

+ +

Gallery generated by Sphinx-Gallery

+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/auto_examples/10_animation/viz_interpolators.html b/v0.10.x/auto_examples/10_animation/viz_interpolators.html new file mode 100644 index 000000000..3acafdb35 --- /dev/null +++ b/v0.10.x/auto_examples/10_animation/viz_interpolators.html @@ -0,0 +1,678 @@ + + + + + + + + Keyframe animation — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +
+

Keyframe animation#

+

Minimal tutorial of making keyframe-based animation in FURY.

+
+

What is an Animation#

+

Animation is responsible for animating FURY actors using a set of +keyframes by interpolating values between timestamps of these keyframes.

+
import numpy as np
+
+from fury import actor, window
+from fury.animation import Animation
+from fury.animation.interpolator import cubic_spline_interpolator
+
+keyframes = {
+    1.0: {'value': np.array([0, 0, 0])},
+    2.0: {'value': np.array([-4, 1, 0])},
+    5.0: {'value': np.array([0, 0, 12])},
+    6.0: {'value': np.array([25, 0, 12])},
+}
+
+
+

Why keyframes data are also a dictionary {'value': np.array([0, 0, 0])})? +-> Since some keyframes data can only be defined by a set of data i.e. a +single position keyframe could consist of a position, in control point, and +out control point or any other data that helps to define this keyframe.

+
+
+

What are the interpolators#

+

The keyframes interpolators are functions that takes a set of keyframes and +returns a function that calculates an interpolated value between these +keyframes. +Below there is an example on how to use interpolators manually to interpolate +the above defined keyframes.

+
interpolation_function = cubic_spline_interpolator(keyframes)
+
+
+

Now, if we feed any time to this function it would return the cubic +interpolated position at that time.

+
position = interpolation_function(1.44434)
+
+
+

position would contain an interpolated position at time equals 1.44434

+
+
+

Creating the environment#

+

In order to make any animations in FURY, a ShowManager is needed to handle +updating the animation and rendering the scene.

+
scene = window.Scene()
+
+showm = window.ShowManager(
+    scene, size=(900, 768), reset_camera=False, order_transparent=True
+)
+showm.initialize()
+
+arrow = actor.arrow(np.array([[0, 0, 0]]), (0, 0, 0), (1, 0, 1), scales=6)
+
+
+
+
+

Creating an Animation#

+

First step is creating the Animation.

+
animation = Animation()
+
+
+

Adding the sphere actor to the timeline +This could’ve been done during initialization.

+
animation.add_actor(arrow)
+
+
+
+
+

Setting position keyframes#

+

Adding some position keyframes

+
animation.set_position(0.0, np.array([0, 0, 0]))
+animation.set_position(2.0, np.array([10, 10, 10]))
+animation.set_position(5.0, np.array([-10, -3, -6]))
+animation.set_position(9.0, np.array([10, 6, 20]))
+
+
+
+
+

Changing the default interpolator for a single property#

+

For all properties except rotation, linear interpolator is used by +default. In order to change the default interpolator and set another +interpolator, call animation.set_<property>_interpolator(interpolator) +FURY already has some interpolators located at: +fury.animation.interpolator.

+

Below we set the interpolator for position keyframes to be +cubic spline interpolator.

+
animation.set_position_interpolator(cubic_spline_interpolator)
+
+
+

Adding some rotation keyframes.

+
animation.set_rotation(0.0, np.array([160, 50, 0]))
+animation.set_rotation(8.0, np.array([60, 160, 0]))
+
+
+

For Rotation keyframes, Slerp is used as the default interpolator. +What is Slerp? +Slerp (spherical linear interpolation) of quaternions results in a constant +speed rotation in keyframe animation. +Reed more about Slerp: https://en.wikipedia.org/wiki/Slerp

+

Setting camera position to see the animation better.

+
+
+

Adding main animation to the ShowManager.

+
showm.add_animation(animation)
+
+
+

Start the ShowManager to start playing the animation

+
interactive = False
+
+if interactive:
+    showm.start()
+
+window.record(scene, out_path='viz_keyframe_interpolator.png', size=(900, 768))
+
+
+viz interpolators

Total running time of the script: (0 minutes 0.101 seconds)

+ +

Gallery generated by Sphinx-Gallery

+
+
+ +
+ + +
+ +
+ + + + + +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/auto_examples/10_animation/viz_introduction.html b/v0.10.x/auto_examples/10_animation/viz_introduction.html new file mode 100644 index 000000000..ca4d90025 --- /dev/null +++ b/v0.10.x/auto_examples/10_animation/viz_introduction.html @@ -0,0 +1,634 @@ + + + + + + + + Keyframe animation introduction — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +
+

Keyframe animation introduction#

+

This tutorial explains keyframe animation in FURY.

+
+

Animations in FURY#

+

FURY provides an easy-to-use animation system that enables users creating +complex animations based on keyframes. +The user only need to provide the attributes of actors at certain +times (keyframes), and the system will take care of animating everything +through interpolating between those keyframes.

+
+
+

What exactly is a keyframe#

+

A Keyframe is simply a marker of time which stores the value of a property.

+

A keyframe consists of a timestamp and some data. These data can be anything +such as temperature, position, or scale.

+
+
+

What is Keyframe Animation#

+

Keyframe animations is a technique to simplify the process of animating a +scene. +Instead of providing the actor attributes for each frame, only a small amount +of keyframes are needed to create a smooth animation. Each keyframe encodes +the state of an actor at a certain timestamp. For instance a keyframe might +define that an actor should be positioned at the origin (0,0,0) at the start +of the animation. Another keyframe may define that the actor should move to +position (1,0,0) after 10 seconds. The system will take care of interpolating +the position of that actor between these two keyframes.

+

Almost any parameter that you can set for FURY actors can be animated +using keyframes.

+

For example, a Keyframe might define that the position of a FURY actor is +(0, 0, 0) at time equals 1 second.

+

The goal of a Keyframe is to allow for interpolated animation, meaning, +for example, that the user could then add another key at time equals 3 +seconds, specifying the actor’s position is (1, 1, 0),

+

Then the correct position of the actor for all the times between 3 and 10 +will be interpolated.

+

For this tutorial, we are going to use the FURY animation module to translate +FURY sphere actor.

+
import numpy as np
+
+from fury import actor, window
+from fury.animation import Animation
+
+scene = window.Scene()
+
+showm = window.ShowManager(scene, size=(900, 768))
+showm.initialize()
+
+
+
+
+

Translating a sphere#

+

This is a quick demo showing how to translate a sphere from (0, 0, 0) to +(1, 1, 1). +First, we create an Animation. See viz_interpolators.py tutorial

+
animation = Animation()
+
+
+

We also create the FURY sphere actor that will be animated.

+
sphere = actor.sphere(np.zeros([1, 3]), np.ones([1, 3]))
+
+
+

Then lets add the sphere actor to the Animation

+
animation.add_actor(sphere)
+
+
+

Then, we set our position keyframes at different timestamps +Here we want the sphere’s position at the beginning to be [0, 0, 0]. And then +at time equals 3 seconds to be at [1, 1, 0] then finally at the end +(time equals 6) to return to the initial position which is [0, 0, 0] again.

+
animation.set_position(0.0, [-1, -1, 0])
+animation.set_position(3.0, [1, 1, 0])
+animation.set_position(6.0, [-1, -1, 0])
+
+
+

The Animation must be added to the ShowManager as follows:

+
showm.add_animation(animation)
+scene.camera().SetPosition(0, 0, 10)
+
+
+

Animation can be added to the scene instead of the ShowManager but, the +animation will need to be updated and then render the scene manually.

+

No need to add the sphere actor to scene, since it’s now a part of the +Animation.

+
interactive = False
+
+if interactive:
+    showm.start()
+
+window.record(
+    scene, out_path='viz_keyframe_animation_introduction.png', size=(900, 768)
+)
+
+
+viz introduction

Total running time of the script: (0 minutes 0.120 seconds)

+ +

Gallery generated by Sphinx-Gallery

+
+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/auto_examples/10_animation/viz_robot_arm_animation.html b/v0.10.x/auto_examples/10_animation/viz_robot_arm_animation.html new file mode 100644 index 000000000..c82efd015 --- /dev/null +++ b/v0.10.x/auto_examples/10_animation/viz_robot_arm_animation.html @@ -0,0 +1,618 @@ + + + + + + + + Arm Robot Animation — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +
+

Arm Robot Animation#

+

Tutorial on making a robot arm animation in FURY.

+
import numpy as np
+
+from fury import actor, window
+from fury.animation import Animation, Timeline
+from fury.utils import set_actor_origin
+
+scene = window.Scene()
+
+showm = window.ShowManager(
+    scene, size=(900, 768), reset_camera=False, order_transparent=True
+)
+showm.initialize()
+
+
+

Creating robot arm components

+
base = actor.cylinder(
+    np.array([[0, 0, 0]]), np.array([[0, 1, 0]]), colors=(0, 1, 0), radius=1
+)
+main_arm = actor.box(np.array([[0, 0, 0]]), colors=(1, 0.5, 0), scales=(12, 1, 1))
+
+sub_arm = actor.box(np.array([[0, 0, 0]]), colors=(0, 0.5, 0.8), scales=(8, 0.7, 0.7))
+joint_1 = actor.sphere(np.array([[0, 0, 0]]), colors=np.array([1, 0, 1]), radii=1.2)
+joint_2 = actor.sphere(np.array([[0, 0, 0]]), colors=np.array([1, 0, 1]))
+
+end = actor.cone(
+    np.array([[0, 0, 0]]),
+    np.array([[1, 0, 0]]),
+    np.array([[1, 0, 0]]),
+    heights=2.2,
+    resolution=6,
+)
+
+
+

Setting the center of both shafts to the beginning.

+
set_actor_origin(main_arm, np.array([-6, 0, 0]))
+set_actor_origin(sub_arm, np.array([-4, 0, 0]))
+
+
+

Creating a timeline

+
timeline = Timeline(playback_panel=True)
+
+
+

Creating animations

+
main_arm_animation = Animation([main_arm, joint_1], length=2 * np.pi)
+child_arm_animation = Animation([sub_arm, joint_2])
+drill_animation = Animation(end)
+
+
+

Adding other Animations in hierarchical order

+
main_arm_animation.add_child_animation(child_arm_animation)
+child_arm_animation.add_child_animation(drill_animation)
+
+
+

Creating Arm joints time dependent animation functions.

+
def rot_main_arm(t):
+    return np.array([np.sin(t / 2) * 180, np.cos(t / 2) * 180, 0])
+
+
+def rot_sub_arm(t):
+    return np.array([np.sin(t) * 180, np.cos(t) * 70, np.cos(t) * 40])
+
+
+def rot_drill(t):
+    return np.array([t * 1000, 0, 0])
+
+
+

Setting timelines (joints) relative position +1- Placing the main arm on the cube static base.

+
main_arm_animation.set_position(0, np.array([0, 1.3, 0]))
+
+
+

2- Translating the timeline containing the sub arm to the end of the first +arm.

+
child_arm_animation.set_position(0, np.array([12, 0, 0]))
+
+
+

3- Translating the timeline containing the drill to the end of the sub arm.

+
drill_animation.set_position(0, np.array([8, 0, 0]))
+
+
+

Setting rotation time-based evaluators

+
main_arm_animation.set_rotation_interpolator(rot_main_arm, is_evaluator=True)
+child_arm_animation.set_rotation_interpolator(rot_sub_arm, is_evaluator=True)
+drill_animation.set_rotation_interpolator(rot_drill, is_evaluator=True)
+
+
+

Setting camera position to observe the robot arm.

+
scene.camera().SetPosition(0, 0, 90)
+
+
+

Adding the base actor to the scene

+
scene.add(base)
+
+
+

Adding the main parent animation to the Timeline.

+
timeline.add_animation(main_arm_animation)
+
+
+

Now we add the timeline to the ShowManager

+
showm.add_animation(timeline)
+
+interactive = False
+
+if interactive:
+    showm.start()
+
+window.record(scene, out_path='viz_robot_arm.png', size=(900, 768))
+
+
+viz robot arm animation

Total running time of the script: (0 minutes 0.107 seconds)

+ +

Gallery generated by Sphinx-Gallery

+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/auto_examples/10_animation/viz_spline_interpolator.html b/v0.10.x/auto_examples/10_animation/viz_spline_interpolator.html new file mode 100644 index 000000000..e919e7633 --- /dev/null +++ b/v0.10.x/auto_examples/10_animation/viz_spline_interpolator.html @@ -0,0 +1,608 @@ + + + + + + + + Keyframes Spline Interpolator — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +
+

Keyframes Spline Interpolator#

+

Tutorial on making keyframe-based animation in FURY using Spline interpolators.

+
import numpy as np
+
+from fury import actor, window
+from fury.animation import Animation, Timeline
+from fury.animation.interpolator import spline_interpolator
+
+scene = window.Scene()
+
+showm = window.ShowManager(
+    scene, size=(900, 768), reset_camera=False, order_transparent=True
+)
+
+
+

Position keyframes as a dict object containing timestamps as keys and +positions as values.

+
position_keyframes = {
+    0.0: np.array([0, 0, 0]),
+    2.0: np.array([10, 3, 5]),
+    4.0: np.array([20, 14, 13]),
+    6.0: np.array([-20, 20, 0]),
+    8.0: np.array([17, -10, 15]),
+    10.0: np.array([0, -6, 0]),
+}
+
+
+

creating FURY dots to visualize the position values.

+
pos_dots = actor.dot(np.array(list(position_keyframes.values())))
+
+
+

creating two timelines (one uses linear and the other uses’ spline +interpolator), each timeline controls a sphere actor

+
sphere_linear = actor.sphere(np.array([[0, 0, 0]]), (1, 0.5, 0.2), 0.5)
+
+linear_anim = Animation()
+linear_anim.add_actor(sphere_linear)
+
+linear_anim.set_position_keyframes(position_keyframes)
+
+
+

Note: linear_interpolator is used by default. So, no need to set it for this +first animation that we need to linearly interpolate positional animation.

+

creating a second timeline that translates another larger sphere actor using +spline interpolator.

+
sphere_spline = actor.sphere(np.array([[0, 0, 0]]), (0.3, 0.9, 0.6), 1)
+spline_anim = Animation(sphere_spline)
+spline_anim.set_position_keyframes(position_keyframes)
+
+
+

Setting 5th degree spline interpolator for position keyframes.

+
spline_anim.set_position_interpolator(spline_interpolator, degree=5)
+
+
+
+

Wrapping animations up!#

+

Adding everything to a Timeline to control the two timelines.

+

First we create a timeline with a playback panel:

+
timeline = Timeline(playback_panel=True)
+
+
+

Add visualization dots actor to the scene.

+
scene.add(pos_dots)
+
+
+

Adding the animations to the timeline (so that it controls their playback).

+
timeline.add_animation([linear_anim, spline_anim])
+
+
+

Adding the timeline to the show manager.

+
+
+

Now that these two animations are added to timeline, if the timeline +is played, paused, …, all these changes will reflect on the animations.

+
interactive = False
+
+if interactive:
+    showm.start()
+
+window.record(scene, out_path='viz_keyframe_animation_spline.png', size=(900, 768))
+
+
+viz spline interpolator

Total running time of the script: (0 minutes 0.216 seconds)

+ +

Gallery generated by Sphinx-Gallery

+
+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ +
+ On this page +
+ +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/auto_examples/10_animation/viz_timeline.html b/v0.10.x/auto_examples/10_animation/viz_timeline.html new file mode 100644 index 000000000..c2da44457 --- /dev/null +++ b/v0.10.x/auto_examples/10_animation/viz_timeline.html @@ -0,0 +1,622 @@ + + + + + + + + Timeline and setting keyframes — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +
+

Timeline and setting keyframes#

+

In his tutorial, you will learn how to use Fury Timeline for playing the +animations.

+
+

What is Timeline?#

+

Timeline is responsible for handling the playback of Fury Animations.

+

Timeline has playback methods such as play, pause, stop, … +which can be used to control the animation.

+
import numpy as np
+
+from fury import actor, window
+from fury.animation import Animation, Timeline
+
+
+

We create our Scene and ShowManager as usual.

+ +
+
+

Creating a Timeline#

+

FURY Timeline has the option to attaches a very useful panel for +controlling the animation by setting playback_panel=True.

+

Creating a Timeline with a PlaybackPanel.

+
timeline = Timeline(playback_panel=True)
+
+
+

Creating a Fury Animation as usual

+
anim = Animation()
+sphere = actor.sphere(np.zeros([1, 3]), np.ones([1, 3]))
+anim.add_actor(sphere)
+# Now that the actor is add to the ``Animation``, setting keyframes to the
+# Animation will animate the actor accordingly.
+
+
+
+
+

Setting Keyframes#

+

There are multiple ways to set keyframes:

+

1- To set a single keyframe, you may use animation.set_<property>(t, k), +where <property> is the name of the property to be set. I.e. setting position +to (1, 2, 3) at time 0.0 would be as following:

+
anim.set_position(0.0, np.array([1, 2, 3]))
+
+
+

Supported properties are: position, rotation, scale, color, and opacity.

+

2- To set multiple keyframes at once, you may use +animation.set_<property>_keyframes(keyframes).

+
keyframes = {1.0: np.array([0, 0, 0]), 3.0: np.array([-2, 0, 0])}
+
+anim.set_position_keyframes(keyframes)
+
+
+

That’s it! Now we are done setting keyframes.

+

In order to control this animation by the timeline we created earlier, this +animation must be added to the timeline.

+
timeline.add_animation(anim)
+
+
+

Now we add only the Timeline to the ShowManager the same way we add +Animation to the ShowManager.

+
showm.add_animation(timeline)
+
+scene.set_camera(position=(0, 0, -10))
+
+interactive = False
+
+if interactive:
+    showm.start()
+
+window.record(scene, out_path='viz_keyframe_animation_timeline.png', size=(900, 768))
+
+
+viz timeline

Total running time of the script: (0 minutes 0.120 seconds)

+ +

Gallery generated by Sphinx-Gallery

+
+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/auto_examples/10_animation/viz_using_time_equations.html b/v0.10.x/auto_examples/10_animation/viz_using_time_equations.html new file mode 100644 index 000000000..20f69d4e9 --- /dev/null +++ b/v0.10.x/auto_examples/10_animation/viz_using_time_equations.html @@ -0,0 +1,581 @@ + + + + + + + + Keyframe animation — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +
+

Keyframe animation#

+

Tutorial on making keyframe-based animation in FURY using custom functions.

+
import numpy as np
+
+from fury import actor, window
+from fury.animation import Animation
+
+scene = window.Scene()
+
+showm = window.ShowManager(
+    scene, size=(900, 768), reset_camera=False, order_transparent=True
+)
+
+
+cube = actor.cube(np.array([[0, 0, 0]]), (0, 0, 0), (1, 0, 1), scales=6)
+
+
+

Creating an Animation to animate the actor and show its motion path.

+
anim = Animation(length=2 * np.pi, loop=True, motion_path_res=200)
+
+
+

Adding the sphere actor to the timeline +This could’ve been done during initialization.

+
anim.add_actor(cube)
+
+
+

Creating time dependent functions.

+
def pos_eval(t):
+    return np.array([np.sin(t), np.cos(t) * np.sin(t), 0]) * 15
+
+
+def color_eval(t):
+    return (
+        np.array([np.sin(t), np.sin(t - 2 * np.pi / 3), np.sin(t + np.pi / 3)])
+        + np.ones(3)
+    ) / 2
+
+
+def rotation_eval(t):
+    return np.array([np.sin(t) * 360, np.cos(t) * 360, 0])
+
+
+def scale_eval(t):
+    return (
+        np.array([np.sin(t), np.sin(t - 2 * np.pi / 3), np.sin(t + np.pi / 3)])
+        + np.ones(3) * 2
+    ) / 5
+
+
+

Setting evaluator functions is the same as setting interpolators, but with +one extra argument: is_evaluator=True since these functions does not need +keyframes as input.

+
anim.set_position_interpolator(pos_eval, is_evaluator=True)
+anim.set_rotation_interpolator(rotation_eval, is_evaluator=True)
+anim.set_color_interpolator(color_eval, is_evaluator=True)
+anim.set_interpolator('scale', scale_eval, is_evaluator=True)
+
+
+

changing camera position to observe the animation better.

+
scene.set_camera(position=(0, 0, 90))
+
+
+

Adding the animation to the show manager.

+
showm.add_animation(anim)
+
+
+interactive = False
+
+if interactive:
+    showm.start()
+
+window.record(scene, out_path='viz_keyframe_animation_evaluators.png', size=(900, 768))
+
+
+viz using time equations

Total running time of the script: (0 minutes 0.120 seconds)

+ +

Gallery generated by Sphinx-Gallery

+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/auto_examples/13_shaders/index.html b/v0.10.x/auto_examples/13_shaders/index.html new file mode 100644 index 000000000..ea1dbe954 --- /dev/null +++ b/v0.10.x/auto_examples/13_shaders/index.html @@ -0,0 +1,518 @@ + + + + + + + + Shaders — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Shaders#

+

These tutorials show:

+
    +
  • How to use shaders in FURY actors.

  • +
  • How to create new user shaders and internal conventions.

  • +
+
+

Visualize SDF Actor

+
Visualize SDF Actor
+
+

Principled BRDF shader on spheres

+
Principled BRDF shader on spheres
+
+

Varying Color

+
Varying Color
+
+

Physically-Based Rendering (PBR) on spheres

+
Physically-Based Rendering (PBR) on spheres
+
+

SDF Impostors on Billboards

+
SDF Impostors on Billboards
+
+

Make a Cylinder using polygons vs SDF

+
Make a Cylinder using polygons vs SDF
+
+
+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/auto_examples/13_shaders/sg_execution_times.html b/v0.10.x/auto_examples/13_shaders/sg_execution_times.html new file mode 100644 index 000000000..7d2e63a1b --- /dev/null +++ b/v0.10.x/auto_examples/13_shaders/sg_execution_times.html @@ -0,0 +1,516 @@ + + + + + + + + Computation times — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Computation times#

+

00:01.540 total execution time for 6 files from auto_examples/13_shaders:

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Example

Time

Mem (MB)

Principled BRDF shader on spheres (viz_principled_spheres.py)

00:00.608

0.0

SDF Impostors on Billboards (viz_billboard_sdf_spheres.py)

00:00.333

0.0

Varying Color (viz_shader.py)

00:00.216

0.0

Make a Cylinder using polygons vs SDF (viz_sdf_cylinder.py)

00:00.208

0.0

Physically-Based Rendering (PBR) on spheres (viz_pbr_spheres.py)

00:00.176

0.0

Visualize SDF Actor (viz_sdfactor.py)

00:00.000

0.0

+
+
+ +
+ + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/auto_examples/13_shaders/viz_billboard_sdf_spheres.html b/v0.10.x/auto_examples/13_shaders/viz_billboard_sdf_spheres.html new file mode 100644 index 000000000..cf171de1c --- /dev/null +++ b/v0.10.x/auto_examples/13_shaders/viz_billboard_sdf_spheres.html @@ -0,0 +1,807 @@ + + + + + + + + SDF Impostors on Billboards — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +
+

SDF Impostors on Billboards#

+

Traditional rendering engines discretize surfaces using triangles or +quadrilateral polygons. The visual quality of these elements depends on the +number of polygons used to build the 3D mesh, i.e., a smoother surface will +require more polygons. However, increasing the amount of rendered polygons +comes at the cost of performance as it decreases the number of frames per +second (FPS), which might compromise the real-time interactivity of a +visualization.

+

Billboarding is a technique that changes an object’s orientation to always face +a specific direction, in most cases, the camera. This technique became popular +in games and applications with a high polygonal quota requirement.

+

Signed Distance Functions (SDFs) are mathematical functions that take as input +a point in a metric space and return the distance from that point to the +boundary of the function. Depending on whether the point is contained within +this boundary or outside it, the function will return negative or positive +values [Hart1996]. For visualization purposes, the task is to display only the +points within the boundary or, in other words, those whose distance to the +border is either negative or positive, depending on the definition of the SDF.

+

This tutorial exemplifies why FURY’s billboard actor is a suitable rendering +option when thinking about performance and how it can be used to create +impostors using SDFs.

+

Let’s start by importing the necessary modules:

+
import os
+
+import numpy as np
+
+from fury import actor, window
+from fury.shaders import compose_shader, import_fury_shader
+from fury.utils import represent_actor_as_wireframe
+
+
+

Now set up a new scene to place our actors in.

+ +

This tutorial is divided into two parts. First, we will render spheres in the +traditional way and then render them using SDFs on billboards.

+
+

Traditional sphere rendering#

+

FURY provides an easy way to create sphere glyphs from numpy arrays as +follows:

+
centers = np.array([
+    [0, 0, 0], [-6, -6, -6], [8, 8, 8], [8.5, 9.5, 9.5], [10, -10, 10],
+    [-13, 13, -13], [-17, -17, 17]])
+colors = np.array([
+    [1, 1, 0], [1, 0, 1], [0, 0, 1], [1, 1, 1], [1, 0, 0], [0, 1, 0],
+    [0, 1, 1]])
+scales = np.array([6, 1.2, 1, .2, .7, 3, 2])
+spheres_actor = actor.sphere(
+    centers, colors, radii=scales, phi=8, theta=8, use_primitive=False)
+
+
+

To interactively visualize the recently created actors, we only need to add +them to the previously created scene and set the following variable to +True, otherwise, we will screenshot the scene.

+
scene.add(spheres_actor)
+
+interactive = False
+
+if interactive:
+    window.show(scene)
+else:
+    window.record(scene, size=(600, 600), out_path='viz_regular_spheres.png')
+
+
+viz billboard sdf spheres

Now, let’s explore our scene to understand what we have created. Traditional +FURY spheres are designed using a set of interconnected triangles. To +visualize them, we want to transform our representation from Surface to +Wireframe using the following command.

+
represent_actor_as_wireframe(spheres_actor)
+
+if interactive:
+    window.show(scene)
+else:
+    window.record(scene, size=(600, 600), out_path='viz_low_res_wireframe.png')
+
+
+viz billboard sdf spheres

Let’s clean the scene and play with the parameters phi and theta.

+
scene.clear()
+spheres_actor = actor.sphere(
+    centers, colors, radii=scales, phi=16, theta=16, use_primitive=False)
+represent_actor_as_wireframe(spheres_actor)
+scene.add(spheres_actor)
+
+if interactive:
+    window.show(scene)
+else:
+    window.record(scene, size=(600, 600), out_path='viz_hi_res_wireframe.png')
+
+
+viz billboard sdf spheres

As you might have noticed, these parameters control the resolution of the +spheres. Evidently, these parameters directly impact the quality of the +visualization, but increasing such resolution comes at the cost of +performance, i.e., more computing power will be needed and drawn to interact +with these actors.

+

Luckily for us, a technique delivers high-resolution glyphs at a much lower +cost. This technique is known as Signed Distance Functions (SDFs), and they +work as follows:

+
+
+

SDF sphere rendering#

+

It is possible to render SDFs in FURY by using the following configuration, +but first, let’s clear the scene.

+ +

The billboard actor is suited and continuously improved to render SDFs. To +create and visualize it, we can use the following instructions:

+
billboards_actor = actor.billboard(centers, colors=colors, scales=scales)
+represent_actor_as_wireframe(billboards_actor)
+scene.add(billboards_actor)
+
+if interactive:
+    window.show(scene)
+else:
+    window.record(
+        scene, size=(600, 600), out_path='viz_billboards_wireframe.png')
+
+
+viz billboard sdf spheres

If you interacted with this actor, you might have noticed how it always +aligned itself to the camera or, in other words, your FURY window. Now that +we know how billboards work, we can start working on our Signed Distance +Spheres. Let’s clear our scene first.

+ +

FURY already includes a shader function with the definition of a Signed +Distance Sphere. So we can load it and use it like this:

+
sd_sphere = import_fury_shader(os.path.join('sdf', 'sd_sphere.frag'))
+
+
+

Additionally, we need to define the radii of our spheres. Since we prefer +these to be determined by the billboards’ size, we will use the maximum +radius distance allowed by our billboards.

+
sphere_radius = 'const float RADIUS = 1.;'
+
+
+

Let’s calculate the distance to the sphere by combining the previously +defined variables.

+
sphere_dist = 'float dist = sdSphere(point, RADIUS);'
+
+
+

Now, evaluate the signed distance function.

+
sdf_eval = \
+    """
+    if (dist < 0)
+        fragOutput0 = vec4(color, opacity);
+    else
+        discard;
+    """
+
+
+

Putting all of our declarations (constants and function) and implementations +(distance calculation and evaluation) together.

+
fs_dec = compose_shader([sphere_radius, sd_sphere])
+fs_impl = compose_shader([sphere_dist, sdf_eval])
+
+
+

We are ready to create and visualize our SDF-billboard actors.

+
spheres_actor = actor.billboard(
+    centers, colors=colors, scales=scales, fs_dec=fs_dec, fs_impl=fs_impl)
+scene.add(spheres_actor)
+
+if interactive:
+    window.show(scene)
+else:
+    window.record(
+        scene, size=(600, 600), out_path='viz_billboards_circles.png')
+
+
+viz billboard sdf spheres

Hold on, those actors don’t look exactly like the ones we created using +traditional techniques; they don’t even look 3D but 2D. Well, that’s because +we still need an essential component: shading. So let’s clear our scene and +add shading to our SDF billboard actors.

+ +

The first thing necessary to add shading to our SDF-billboard actors is to +calculate the normals of the SDFs. In this tutorial we are not going to get +into detail in the gradient and derivatives of SDFs, so we will use the +central differences technique implemented in the following FURY shader +function:

+
central_diffs_normal = import_fury_shader(
+    os.path.join('sdf', 'central_diffs.frag'))
+
+
+

To use the central differences technique, we need to define a map function +that wraps our SDF and evaluates only a point.

+
sd_sphere_normal = \
+    """
+    float map(vec3 p)
+    {
+        return sdSphere(p, RADIUS);
+    }
+    """
+
+
+

Then we can load the Blinn-Phong illumination model.

+
blinn_phong_model = import_fury_shader(
+    os.path.join('lighting', 'blinn_phong_model.frag'))
+
+
+

Again, let’s bring all of our declarations (constants and functions) +together.

+ +

Now, we can start our fragment shader implementation with the signed distance +function evaluation. You might notice that in this case, we are not using an +if statement but a step function, which is a more efficient way to perform +this evaluation. You can also replace the step function with a smoothstep +operation and, in that way, add a very efficient form of antialiasing.

+
sdf_eval = 'opacity *= 1 - step(0, dist);'
+
+
+

In this case, we also need the absolute value of the distance to compensate +for the depth of the SDF sphere.

+
abs_dist = 'float absDist = abs(dist);'
+
+
+

We are ready to calculate the normals.

+
normal = 'vec3 normal = centralDiffsNormals(vec3(point.xy, absDist), .0001);'
+
+
+

With the normals we can calculate a light attenuation factor.

+
light_attenuation = 'float lightAttenuation = normal.z;'
+
+
+

Now, we are ready to calculate the color and output it.

+
color = \
+    """
+    color = blinnPhongIllumModel(
+        lightAttenuation, lightColor0, diffuseColor, specularPower,
+        specularColor, ambientColor);
+    """
+
+frag_output = 'fragOutput0 = vec4(color, opacity);'
+
+
+

As before, we can bring our implementation code together.

+ +

Finally, recreate the SDF billboard actors and visualize them.

+
spheres_actor = actor.billboard(
+    centers, colors=colors, scales=scales, fs_dec=fs_dec, fs_impl=fs_impl)
+scene.add(spheres_actor)
+
+if interactive:
+    window.show(scene)
+else:
+    window.record(
+        scene, size=(600, 600), out_path='viz_billboards_spheres.png')
+
+
+viz billboard sdf spheres
+

References#

+
+
+[Hart1996] +

Hart, John C. “Sphere tracing: A geometric method for the +antialiased ray tracing of implicit surfaces.” The Visual +Computer 12.10 (1996): 527-545.

+
+
+

Total running time of the script: (0 minutes 0.333 seconds)

+ +

Gallery generated by Sphinx-Gallery

+
+
+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ +
+ On this page +
+ +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/auto_examples/13_shaders/viz_pbr_spheres.html b/v0.10.x/auto_examples/13_shaders/viz_pbr_spheres.html new file mode 100644 index 000000000..0e91cfb78 --- /dev/null +++ b/v0.10.x/auto_examples/13_shaders/viz_pbr_spheres.html @@ -0,0 +1,650 @@ + + + + + + + + Physically-Based Rendering (PBR) on spheres — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +
+

Physically-Based Rendering (PBR) on spheres#

+

PBR engines aim to simulate properties of light when it interacts with objects +in the scene in a physically plausible way. The interaction of light with an +object depends on the material the object is made of. In computer graphics, +materials are usually divided in 2 main categories based on their conductive +properties: dielectrics and metals.

+

This tutorial, illustrates how to model some material properties in FURY by +using the PBR material.

+

Let’s start by importing the necessary modules:

+
import numpy as np
+
+from fury import actor, material, window
+from fury.utils import (
+    normals_from_actor,
+    tangents_from_direction_of_anisotropy,
+    tangents_to_actor,
+)
+
+
+

Now set up a new scene.

+
scene = window.Scene()
+scene.background((0.9, 0.9, 0.9))
+
+
+

Let’s define the parameters we are going to showcase in this tutorial. +These subset of parameters have their values constrained in the 0 to 1 range.

+
material_params = [
+    [[1, 1, 0], {'metallic': 0, 'roughness': 0}],
+    [(0, 0, 1), {'roughness': 0}],
+    [(1, 0, 1), {'anisotropy': 0, 'metallic': 0.25, 'roughness': 0.5}],
+    [
+        (1, 0, 1),
+        {'anisotropy_rotation': 0, 'anisotropy': 1, 'metallic': 0.25, 'roughness': 0.5},
+    ],
+    [(0, 1, 1), {'coat_strength': 0, 'roughness': 0}],
+    [(0, 1, 1), {'coat_roughness': 0, 'coat_strength': 1, 'roughness': 0}],
+]
+
+
+

Now we can start to add our actors to the scene and see how different values +of the parameters produce interesting effects. For the purpose of this +tutorial, we will see the effect of 11 different values of each parameter.

+
num_values = 11
+
+for i, mp in enumerate(material_params):
+    color = mp[0]
+    params = mp[1]
+    center = [[0, -5 * i, 0]]
+    for j in range(num_values):
+        center[0][0] = -25 + 5 * j
+        sphere = actor.sphere(center, color, radii=2, theta=32, phi=32)
+        normals = normals_from_actor(sphere)
+        tangents = tangents_from_direction_of_anisotropy(normals, (0, 1, 0.5))
+        tangents_to_actor(sphere, tangents)
+        keys = list(params)
+        params[keys[0]] = np.round(0.1 * j, decimals=1)
+        material.manifest_pbr(sphere, **params)
+        scene.add(sphere)
+
+
+

For interpretability purposes we will add some labels to guide us through our +visualization.

+
labels = [
+    'Metallic',
+    'Roughness',
+    'Anisotropy',
+    'Anisotropy Rotation',
+    'Coat Strength',
+    'Coat Roughness',
+]
+
+for i, l in enumerate(labels):
+    pos = [-40, -5 * i, 0]
+    label = actor.vector_text(l, pos=pos, scale=(0.8, 0.8, 0.8), color=(0, 0, 0))
+    scene.add(label)
+
+for j in range(num_values):
+    pos = [-26 + 5 * j, 3, 0]
+    label = actor.vector_text(
+        str(np.round(j * 0.1, decimals=1)),
+        pos=pos,
+        scale=(0.8, 0.8, 0.8),
+        color=(0, 0, 0),
+    )
+    scene.add(label)
+
+
+

Some parameters of this material have their values constrained to be between +1 and 2.3. These parameters are the Base Index of Refraction (IOR) and the +Clear coat Index of Refraction (IOR). Therefore, we will interpolate some +values within this range and see how they affect the rendering.

+
iors = np.round(np.linspace(1, 2.3, num=num_values), decimals=2)
+
+ior_params = [
+    [(0, 1, 1), {'base_ior': iors[0], 'roughness': 0}],
+    [
+        (0, 1, 1),
+        {
+            'coat_ior': iors[0],
+            'coat_roughness': 0.1,
+            'coat_strength': 1,
+            'roughness': 0,
+        },
+    ],
+]
+
+for i, iorp in enumerate(ior_params):
+    color = iorp[0]
+    params = iorp[1]
+    center = [[0, -35 - (5 * i), 0]]
+    for j in range(num_values):
+        center[0][0] = -25 + 5 * j
+        sphere = actor.sphere(center, color, radii=2, theta=32, phi=32)
+        keys = list(params)
+        params[keys[0]] = iors[j]
+        material.manifest_pbr(sphere, **params)
+        scene.add(sphere)
+
+
+

Let’s add the respective labels to the scene.

+
labels = ['Base IoR', 'Coat IoR']
+
+for i, l in enumerate(labels):
+    pos = [-40, -35 - (5 * i), 0]
+    label = actor.vector_text(l, pos=pos, scale=(0.8, 0.8, 0.8), color=(0, 0, 0))
+    scene.add(label)
+
+for j in range(num_values):
+    pos = [-26 + 5 * j, -32, 0]
+    label = actor.vector_text(
+        '{:.02f}'.format(iors[j]), pos=pos, scale=(0.8, 0.8, 0.8), color=(0, 0, 0)
+    )
+    scene.add(label)
+
+
+

Finally, let’s visualize our tutorial.

+
interactive = False
+if interactive:
+    window.show(scene)
+
+window.record(scene, size=(600, 600), out_path='viz_pbr_spheres.png')
+
+
+viz pbr spheres

Total running time of the script: (0 minutes 0.176 seconds)

+ +

Gallery generated by Sphinx-Gallery

+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/auto_examples/13_shaders/viz_principled_spheres.html b/v0.10.x/auto_examples/13_shaders/viz_principled_spheres.html new file mode 100644 index 000000000..28bd8dd59 --- /dev/null +++ b/v0.10.x/auto_examples/13_shaders/viz_principled_spheres.html @@ -0,0 +1,603 @@ + + + + + + + + Principled BRDF shader on spheres — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +
+

Principled BRDF shader on spheres#

+

The Principled Bidirectional Reflectance Distribution Function ([BRDF] +(https://en.wikipedia.org/wiki/Bidirectional_reflectance_distribution_function) +) was introduced by Brent Burley as part of the [SIGGRAPH 2012 Physically Based +Shading course] +(https://blog.selfshadow.com/publications/s2012-shading-course/). Although it +is not strictly physically based, it was designed so the parameters included +could model materials in the [MERL 100](https://www.merl.com/brdf/) (Material +Exchange and Research Library) database. Moreover, each parameter was +carefully chosen and limited to be easy to use and understand, so that +blending multiple layers together would give intuitive results.

+

In this demo, we showcase our implementation of the Principled BRDF in FURY.

+

Let’s start by importing the necessary modules:

+
import numpy as np
+
+from fury import actor, material, window
+
+
+

Now set up a new scene.

+
scene = window.Scene()
+scene.background((0.9, 0.9, 0.9))
+
+
+

Let’s define the parameters needed for our demo. In this demo we will see the +effect of each one of the 10 parameters defined by the Principled shader. +For interpretability and usability purposes, each parameter is limited to +values between the range 0 to 1.

+
material_params = [
+    [(1, 1, 1), {'subsurface': 0}],
+    [[1, 1, 0], {'metallic': 0}],
+    [(1, 0, 0), {'specular': 0}],
+    [(1, 0, 0), {'specular_tint': 0, 'specular': 1}],
+    [(0, 0, 1), {'roughness': 0}],
+    [(1, 0, 1), {'anisotropic': 0, 'metallic': 0.25, 'roughness': 0.5}],
+    [[0, 1, 0.5], {'sheen': 0}],
+    [(0, 1, 0.5), {'sheen_tint': 0, 'sheen': 1}],
+    [(0, 1, 1), {'clearcoat': 0}],
+    [(0, 1, 1), {'clearcoat_gloss': 0, 'clearcoat': 1}],
+]
+
+
+

We can start to add our actors to the scene and see how different values of +the parameters produce interesting effects.

+
for i in range(10):
+    center = np.array([[0, -5 * i, 0]])
+    for j in range(11):
+        center[0][0] = -25 + 5 * j
+        sphere = actor.sphere(
+            center, colors=material_params[i][0], radii=2, theta=32, phi=32
+        )
+        keys = list(material_params[i][1])
+        material_params[i][1][keys[0]] = np.round(0.1 * j, decimals=1)
+        material.manifest_principled(sphere, **material_params[i][1])
+        scene.add(sphere)
+
+
+

Finally, let’s add some labels to guide us through our visualization.

+
labels = [
+    'Subsurface',
+    'Metallic',
+    'Specular',
+    'Specular Tint',
+    'Roughness',
+    'Anisotropic',
+    'Sheen',
+    'Sheen Tint',
+    'Clearcoat',
+    'Clearcoat Gloss',
+]
+
+for i in range(10):
+    pos = [-40, -5 * i, 0]
+    label = actor.vector_text(
+        labels[i], pos=pos, scale=(0.8, 0.8, 0.8), color=(0, 0, 0)
+    )
+    scene.add(label)
+
+for j in range(11):
+    pos = [-26 + 5 * j, 5, 0]
+    label = actor.vector_text(
+        str(np.round(j * 0.1, decimals=1)),
+        pos=pos,
+        scale=(0.8, 0.8, 0.8),
+        color=(0, 0, 0),
+    )
+    scene.add(label)
+
+
+

And visualize our demo.

+
interactive = False
+if interactive:
+    window.show(scene)
+
+window.record(scene, size=(600, 600), out_path='viz_principled_spheres.png')
+
+
+viz principled spheres

Total running time of the script: (0 minutes 0.608 seconds)

+ +

Gallery generated by Sphinx-Gallery

+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/auto_examples/13_shaders/viz_sdf_cylinder.html b/v0.10.x/auto_examples/13_shaders/viz_sdf_cylinder.html new file mode 100644 index 000000000..84658fdd1 --- /dev/null +++ b/v0.10.x/auto_examples/13_shaders/viz_sdf_cylinder.html @@ -0,0 +1,881 @@ + + + + + + + + Make a Cylinder using polygons vs SDF — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +
+

Make a Cylinder using polygons vs SDF#

+

This tutorial is intended to show two ways of primitives creation with the use +of polygons, and Signed Distance Functions (SDFs). We will use cylinders as an +example since they have a simpler polygonal representation. Hence, it allows us +to see better the difference between using one or the other method.

+

For the cylinder representation with polygons, we will use cylinder actor +implementation on FURY, and for the visualization using SDFs, we will +implement shader code to create the cylinder and use a box actor to put our +implementation inside.

+

We start by importing the necessary modules:

+
import os
+
+import numpy as np
+
+from fury import actor, window
+from fury.shaders import (
+    attribute_to_actor,
+    compose_shader,
+    import_fury_shader,
+    shader_to_actor,
+)
+
+
+
+

Cylinder using polygons#

+

Polygons-based modeling, use smaller components namely triangles or polygons +to represent 3D objects. Each polygon is defined by the position of its +vertices and its connecting edges. In order to get a better representation +of an object, it may be necessary to increase the number of polygons in the +model, which is translated into the use of more space to store data and more +rendering time to display the object.

+

Now we define some properties of our actors, use them to create a set of +cylinders, and add them to the scene.

+
centers = np.array(
+    [
+        [-3.2, 0.9, 0.4],
+        [-3.5, -0.5, 1],
+        [-2.1, 0, 0.4],
+        [-0.2, 0.9, 0.4],
+        [-0.5, -0.5, 1],
+        [0.9, 0, 0.4],
+        [2.8, 0.9, 1.4],
+        [2.5, -0.5, 2],
+        [3.9, 0, 1.4],
+    ]
+)
+dirs = np.array(
+    [
+        [-0.2, 0.9, 0.4],
+        [-0.5, -0.5, 1],
+        [0.9, 0, 0.4],
+        [-0.2, 0.9, 0.4],
+        [-0.5, -0.5, 1],
+        [0.9, 0, 0.4],
+        [-0.2, 0.9, 0.4],
+        [-0.5, -0.5, 1],
+        [0.9, 0, 0.4],
+    ]
+)
+colors = np.array(
+    [
+        [1, 0, 0],
+        [1, 0, 0],
+        [1, 0, 0],
+        [0, 1, 0],
+        [0, 1, 0],
+        [0, 1, 0],
+        [0, 0, 1],
+        [0, 0, 1],
+        [0, 0, 1],
+    ]
+)
+radius = 0.5
+height = 1
+
+
+

In order to see how cylinders are made, we set different resolutions (number +of sides used to define the bases of the cylinder) to see how it changes the +surface of the primitive.

+
cylinders_8 = actor.cylinder(
+    centers[:3],
+    dirs[:3],
+    colors[:3],
+    radius=radius,
+    heights=height,
+    capped=True,
+    resolution=8,
+)
+cylinders_16 = actor.cylinder(
+    centers[3:6],
+    dirs[3:6],
+    colors[3:6],
+    radius=radius,
+    heights=height,
+    capped=True,
+    resolution=16,
+)
+cylinders_32 = actor.cylinder(
+    centers[6:9],
+    dirs[6:9],
+    colors[6:9],
+    radius=radius,
+    heights=height,
+    capped=True,
+    resolution=32,
+)
+
+
+

Next, we set up a new scene to add and visualize the actors created.

+
scene = window.Scene()
+
+scene.add(cylinders_8)
+scene.add(cylinders_16)
+scene.add(cylinders_32)
+
+interactive = False
+
+if interactive:
+    window.show(scene)
+
+window.record(scene, size=(600, 600), out_path='viz_poly_cylinder.png')
+
+
+viz sdf cylinder

Visualize the surface geometry representation for the object.

+
cylinders_8.GetProperty().SetRepresentationToWireframe()
+cylinders_16.GetProperty().SetRepresentationToWireframe()
+cylinders_32.GetProperty().SetRepresentationToWireframe()
+
+if interactive:
+    window.show(scene)
+
+window.record(scene, size=(600, 600), out_path='viz_poly_cylinder_geom.png')
+
+
+viz sdf cylinder

Then we clean the scene to render the boxes we will use to render our +SDF-based actors.

+ +
+
+

Cylinder using SDF#

+

Signed Distance Functions are mathematical functions that take as input a +point in a metric space and return the distance from that point to the +boundary of an object.

+

We will use the ray marching algorithm to render the SDF primitive using +shaders. Ray marching is a technique where you step along a ray in order to +find intersections with solid geometry. Objects in the scene are defined by +SDF, and because we don’t use polygonal meshes it is possible to define +perfectly smooth surfaces and allows a faster rendering in comparison to +polygon-based modeling (more details in [Hart1996]).

+

Now we create cylinders using box actor and SDF implementation on shaders. +For this, we first create a box actor.

+
box_actor = actor.box(
+    centers=centers,
+    directions=dirs,
+    colors=colors,
+    scales=(height, radius * 2, radius * 2),
+)
+
+
+

Now we use attribute_to_actor to link a NumPy array, with the centers and +directions data, with a vertex attribute. We do this to pass the data to +the vertex shader, with the corresponding attribute name.

+

We need to associate the data to each of the 8 vertices that make up the box +since we handle the processing of individual vertices in the vertex shader.

+
rep_directions = np.repeat(dirs, 8, axis=0)
+rep_centers = np.repeat(centers, 8, axis=0)
+rep_radii = np.repeat(np.repeat(radius, 9), 8, axis=0)
+rep_heights = np.repeat(np.repeat(height, 9), 8, axis=0)
+
+attribute_to_actor(box_actor, rep_centers, 'center')
+attribute_to_actor(box_actor, rep_directions, 'direction')
+attribute_to_actor(box_actor, rep_radii, 'radius')
+attribute_to_actor(box_actor, rep_heights, 'height')
+
+
+

Then we have the shader code implementation corresponding to vertex and +fragment shader. Here we are passing data to the fragment shader through +the vertex shader.

+

Vertex shaders perform basic processing of each individual vertex.

+
vs_dec = """
+    in vec3 center;
+    in vec3 direction;
+    in float height;
+    in float radius;
+
+    out vec4 vertexMCVSOutput;
+    out vec3 centerMCVSOutput;
+    out vec3 directionVSOutput;
+    out float heightVSOutput;
+    out float radiusVSOutput;
+    """
+
+vs_impl = """
+    vertexMCVSOutput = vertexMC;
+    centerMCVSOutput = center;
+    directionVSOutput = direction;
+    heightVSOutput = height;
+    radiusVSOutput = radius;
+    """
+
+
+

Then we add the vertex shader code to the box_actor. We use shader_to_actor +to apply our implementation to the shader creation process, this function +joins our code to the shader template that FURY has by default.

+
shader_to_actor(box_actor, 'vertex', decl_code=vs_dec, impl_code=vs_impl)
+
+
+

Fragment shaders are used to define the colors of each pixel being processed, +the program runs on each of the pixels that the object occupies on the +screen.

+

Fragment shaders also allow us to have control over details of movement, +lighting, and color in a scene. In this case, we are using vertex shader not +just to define the colors of the cylinders but to manipulate its position in +world space, rotation with respect to the box, and lighting of the scene.

+
fs_vars_dec = """
+    in vec4 vertexMCVSOutput;
+    in vec3 centerMCVSOutput;
+    in vec3 directionVSOutput;
+    in float heightVSOutput;
+    in float radiusVSOutput;
+
+    uniform mat4 MCVCMatrix;
+    """
+
+
+

We use this function to generate an appropriate rotation matrix which help us +to transform our position vectors in order to align the direction of +cylinder with respect to the box.

+
vec_to_vec_rot_mat = import_fury_shader(
+    os.path.join('utils', 'vec_to_vec_rot_mat.glsl')
+)
+
+
+

We calculate the distance using the SDF function for the cylinder.

+
sd_cylinder = import_fury_shader(os.path.join('sdf', 'sd_cylinder.frag'))
+
+
+

This is used on calculations for surface normals of the cylinder.

+
sdf_map = """
+    float map(in vec3 position)
+    {
+        // the sdCylinder function creates vertical cylinders by default, that
+        // is the cylinder is created pointing in the up direction (0, 1, 0).
+        // We want to rotate that vector to be aligned with the box's direction
+        mat4 rot = vec2VecRotMat(normalize(directionVSOutput),
+                                 normalize(vec3(0, 1, 0)));
+
+        vec3 pos = (rot * vec4(position - centerMCVSOutput, 0.0)).xyz;
+
+        // distance to the cylinder's boundary
+        return sdCylinder(pos, radiusVSOutput, heightVSOutput / 2);
+    }
+    """
+
+
+

We use central differences technique for computing surface normals.

+
central_diffs_normal = import_fury_shader(os.path.join('sdf', 'central_diffs.frag'))
+
+
+

We use cast_ray for the implementation of Ray Marching.

+
cast_ray = import_fury_shader(os.path.join('ray_marching', 'cast_ray.frag'))
+
+
+

For the illumination of the scene we use the Blinn-Phong model.

+
blinn_phong_model = import_fury_shader(
+    os.path.join('lighting', 'blinn_phong_model.frag')
+)
+
+
+

Now we use compose_shader to join our pieces of GLSL shader code.

+
fs_dec = compose_shader(
+    [
+        fs_vars_dec,
+        vec_to_vec_rot_mat,
+        sd_cylinder,
+        sdf_map,
+        central_diffs_normal,
+        cast_ray,
+        blinn_phong_model,
+    ]
+)
+
+shader_to_actor(box_actor, 'fragment', decl_code=fs_dec)
+
+
+

Here we have the implementation of all the previous code with all the +necessary variables and functions to build the cylinders.

+
sdf_cylinder_frag_impl = """
+    vec3 point = vertexMCVSOutput.xyz;
+
+    // ray origin
+    vec4 ro = -MCVCMatrix[3] * MCVCMatrix;  // camera position in world space
+
+    // ray direction
+    vec3 rd = normalize(point - ro.xyz);
+
+    // light direction
+    vec3 ld = normalize(ro.xyz - point);
+
+    ro += vec4((point - ro.xyz), 0);
+
+    float t = castRay(ro.xyz, rd);
+
+    if(t < 20.0)
+    {
+        vec3 position = ro.xyz + t * rd;
+        vec3 normal = centralDiffsNormals(position, .0001);
+        float lightAttenuation = dot(ld, normal);
+        vec3 color = blinnPhongIllumModel(
+                        lightAttenuation, lightColor0, diffuseColor,
+                        specularPower, specularColor, ambientColor);
+        fragOutput0 = vec4(color, opacity);
+    }
+    else
+    {
+        discard;
+    }
+    """
+
+shader_to_actor(box_actor, 'fragment', impl_code=sdf_cylinder_frag_impl, block='light')
+
+
+

Finally, we visualize the cylinders made using ray marching and SDFs.

+
scene.add(box_actor)
+
+if interactive:
+    window.show(scene)
+
+window.record(scene, size=(600, 600), out_path='viz_sdf_cylinder.png')
+
+
+viz sdf cylinder
+

References#

+
+
+[Hart1996] +

Hart, John C. “Sphere tracing: A geometric method for the +antialiased ray tracing of implicit surfaces.” The Visual +Computer 12.10 (1996): 527-545.

+
+
+

Total running time of the script: (0 minutes 0.208 seconds)

+ +

Gallery generated by Sphinx-Gallery

+
+
+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ +
+ On this page +
+ +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/auto_examples/13_shaders/viz_sdfactor.html b/v0.10.x/auto_examples/13_shaders/viz_sdfactor.html new file mode 100644 index 000000000..ccea29bd8 --- /dev/null +++ b/v0.10.x/auto_examples/13_shaders/viz_sdfactor.html @@ -0,0 +1,558 @@ + + + + + + + + Visualize SDF Actor — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +
+

Visualize SDF Actor#

+

Here is a simple tutorial that shows how to visualize SDF primitives using +FURY.

+

SDFs or Signed-distance functions when passed the coordinates of a point in +space, return the shortest distance between that point and some surface. +This property of SDFs can be used to model 3D geometry at a faster rate +compared to traditional polygons based modeling.

+

In this example we use the raymarching algorithm to render the SDF primitives +shapes using shaders

+
import numpy as np
+
+from fury import actor, window
+
+
+

Lets define variables for the SDF Actor

+
dirs = np.random.rand(4, 3)
+colors = np.random.rand(4, 3) * 255
+centers = np.array([[1, 0, 0], [0, 0, 0], [-1, 0, 0], [0, 1, 0]])
+scales = np.random.rand(4, 1)
+
+
+

Create SDF Actor

+
sdfactor = actor.sdf(
+    centers=centers,
+    directions=dirs,
+    colors=colors,
+    primitives=['sphere', 'torus', 'ellipsoid', 'capsule'],
+    scales=scales,
+)
+
+
+

Create a scene

+
scene = window.Scene()
+scene.background((1.0, 0.8, 0.8))
+scene.add(sdfactor)
+
+
+

Show Manager

+

Since all the elements have been initialised ,we add them to the show +manager.

+
current_size = (1024, 720)
+showm = window.ShowManager(scene, size=current_size, title='Visualize SDF Actor')
+
+interactive = False
+
+if interactive:
+    showm.start()
+
+window.record(scene, out_path='viz_sdfactor.png', size=current_size)
+
+
+viz sdfactor

Total running time of the script: (0 minutes 0.074 seconds)

+ +

Gallery generated by Sphinx-Gallery

+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/auto_examples/13_shaders/viz_shader.html b/v0.10.x/auto_examples/13_shaders/viz_shader.html new file mode 100644 index 000000000..cd6717676 --- /dev/null +++ b/v0.10.x/auto_examples/13_shaders/viz_shader.html @@ -0,0 +1,621 @@ + + + + + + + + Varying Color — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +
+

Varying Color#

+

This example shows how to use shaders to generate a shaded output. We will +demonstrate how to load polydata then use a custom shader calls to render +a custom shaded model. +First, a bunch of imports.

+
from fury import io, ui, utils, window
+from fury.data.fetcher import fetch_viz_models, read_viz_models
+from fury.shaders import add_shader_callback, shader_to_actor
+
+
+

Let’s download and load the model

+
fetch_viz_models()
+model = read_viz_models('utah.obj')
+
+
+
Dataset is already in place. If you want to fetch it again please first remove the folder /Users/skoudoro/.fury/models
+
+
+

Let’s start by loading the polydata of choice. +For this example we use the standard utah teapot model. +currently supported formats include OBJ, VTK, FIB, PLY, STL and XML

+
utah = io.load_polydata(model)
+utah = utils.get_polymapper_from_polydata(utah)
+utah = utils.get_actor_from_polymapper(utah)
+mapper = utah.GetMapper()
+
+
+

To change the default shader we add a shader replacement. +Specify vertex shader using vtkShader.Vertex +Specify fragment shader using vtkShader.Fragment

+
vertex_shader_code_decl = """
+    out vec4 myVertexVC;
+    """
+
+vertex_shader_code_impl = """
+    myVertexVC = vertexMC;
+    """
+
+fragment_shader_code_decl = """
+    uniform float time;
+    varying vec4 myVertexVC;
+    """
+
+fragment_shader_code_impl = """
+    vec2 iResolution = vec2(1024,720);
+    vec2 uv = myVertexVC.xy/iResolution;
+    vec3 col = 0.5 + 0.5 * cos((time/30) + uv.xyx + vec3(0, 2, 4));
+    fragOutput0 = vec4(col, fragOutput0.a);
+    """
+
+shader_to_actor(
+    utah, 'vertex', impl_code=vertex_shader_code_impl, decl_code=vertex_shader_code_decl
+)
+shader_to_actor(utah, 'fragment', decl_code=fragment_shader_code_decl)
+shader_to_actor(utah, 'fragment', impl_code=fragment_shader_code_impl, block='light')
+
+
+

Let’s create a scene.

+
scene = window.Scene()
+
+global timer
+timer = 0
+
+
+

The timer will call this user defined callback every 30 milliseconds.

+
def timer_callback(obj, event):
+    global timer
+    timer += 1.0
+    showm.render()
+    scene.azimuth(5)
+
+
+

The shader callback will update the color of our utah pot via the update of +the timer variable.

+
def shader_callback(_caller, _event, calldata=None):
+    program = calldata
+    global timer
+    if program is not None:
+        try:
+            program.SetUniformf('time', timer)
+        except ValueError:
+            pass
+
+
+add_shader_callback(utah, shader_callback)
+
+
+
1
+
+
+

Let’s add a textblock to the scene with a custom message

+
tb = ui.TextBlock2D()
+tb.message = 'Hello Shaders'
+
+
+

Show Manager

+

Now that all the elements have been initialised, we add them to the show +manager.

+
current_size = (1024, 720)
+showm = window.ShowManager(scene, size=current_size, reset_camera=False)
+
+
+showm.add_timer_callback(True, 30, timer_callback)
+
+scene.add(utah)
+scene.add(tb)
+
+interactive = False
+if interactive:
+    showm.start()
+
+window.record(showm.scene, size=current_size, out_path='viz_shader.png')
+
+
+viz shader

Total running time of the script: (0 minutes 0.216 seconds)

+ +

Gallery generated by Sphinx-Gallery

+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/auto_examples/17_pybullet/index.html b/v0.10.x/auto_examples/17_pybullet/index.html new file mode 100644 index 000000000..aeef52adb --- /dev/null +++ b/v0.10.x/auto_examples/17_pybullet/index.html @@ -0,0 +1,511 @@ + + + + + + + + Integrate Physics using pybullet — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + + + + + + + +
+ + + +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/auto_examples/17_pybullet/sg_execution_times.html b/v0.10.x/auto_examples/17_pybullet/sg_execution_times.html new file mode 100644 index 000000000..70b55e575 --- /dev/null +++ b/v0.10.x/auto_examples/17_pybullet/sg_execution_times.html @@ -0,0 +1,512 @@ + + + + + + + + Computation times — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Computation times#

+

00:00.591 total execution time for 5 files from auto_examples/17_pybullet:

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Example

Time

Mem (MB)

Chain Simulation (viz_chain.py)

00:00.591

0.0

Ball Collision Simulation (viz_ball_collide.py)

00:00.000

0.0

Brick Wall Simulation (viz_brick_wall.py)

00:00.000

0.0

Domino Physics Simulation (viz_domino.py)

00:00.000

0.0

Wrecking Ball Simulation (viz_wrecking_ball.py)

00:00.000

0.0

+
+
+ +
+ + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/auto_examples/17_pybullet/viz_ball_collide.html b/v0.10.x/auto_examples/17_pybullet/viz_ball_collide.html new file mode 100644 index 000000000..3293607f6 --- /dev/null +++ b/v0.10.x/auto_examples/17_pybullet/viz_ball_collide.html @@ -0,0 +1,635 @@ + + + + + + + + Ball Collision Simulation — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +
+

Ball Collision Simulation#

+

This example simulation shows how to use pybullet to render physics simulations +in fury. In this example we render the collision between a blue ball and red +ball and also display a message by confirming the collision.

+

First some imports.

+
import itertools
+
+import numpy as np
+import pybullet as p
+
+from fury import actor, ui, window
+
+client = p.connect(p.DIRECT)
+
+
+

Parameters and definition of red and blue balls.

+
red_radius = 0.5
+blue_radius = 0.5
+duration = 50
+
+# Red Ball
+red_ball_actor = actor.sphere(
+    centers=np.array([[0, 0, 0]]), colors=np.array([[1, 0, 0]]), radii=red_radius
+)
+
+red_ball_coll = p.createCollisionShape(p.GEOM_SPHERE, radius=red_radius)
+
+red_ball = p.createMultiBody(
+    baseMass=0.5,
+    baseCollisionShapeIndex=red_ball_coll,
+    basePosition=[10, 0, 0],
+    baseOrientation=[0, 0, 0, 1],
+)
+
+# Blue ball
+blue_ball_actor = actor.sphere(
+    centers=np.array([[0, 0, 0]]), colors=np.array([[0, 0, 1]]), radii=blue_radius
+)
+
+blue_ball_coll = p.createCollisionShape(p.GEOM_SPHERE, radius=blue_radius)
+
+blue_ball = p.createMultiBody(
+    baseMass=0.5,
+    baseCollisionShapeIndex=blue_ball_coll,
+    basePosition=[-10, 0, 0],
+    baseOrientation=[0, 0, 0, 1],
+)
+
+
+

We set the coefficient of restitution of both the balls to 0.6.

+
p.changeDynamics(red_ball, -1, restitution=0.6)
+p.changeDynamics(blue_ball, -1, restitution=0.6)
+
+
+

We add all the actors to the scene.

+
scene = window.Scene()
+scene.add(actor.axes())
+scene.add(red_ball_actor)
+scene.add(blue_ball_actor)
+
+showm = window.ShowManager(
+    scene, size=(900, 700), reset_camera=False, order_transparent=True
+)
+
+
+counter = itertools.count()
+
+
+

Method to sync objects.

+
def sync_actor(actor, multibody):
+    pos, orn = p.getBasePositionAndOrientation(multibody)
+    actor.SetPosition(*pos)
+    orn_deg = np.degrees(p.getEulerFromQuaternion(orn))
+    actor.SetOrientation(*orn_deg)
+
+
+apply_force = True
+tb = ui.TextBlock2D(position=(0, 600), font_size=30, color=(1, 0.5, 0), text='')
+scene.add(tb)
+scene.set_camera(
+    position=(0.30, -18.78, 0.89), focal_point=(0.15, 0.25, 0.40), view_up=(0, 0, 1.00)
+)
+
+
+

Timer callback to sync and step simulation every second.

+
def timer_callback(_obj, _event):
+    global apply_force
+    cnt = next(counter)
+    showm.render()
+    red_pos, red_orn = p.getBasePositionAndOrientation(red_ball)
+    blue_pos, blue_orn = p.getBasePositionAndOrientation(blue_ball)
+
+    # Apply force for the first step of the simulation.
+    if apply_force:
+        p.applyExternalForce(
+            red_ball, -1, forceObj=[-40000, 0, 0], posObj=red_pos, flags=p.WORLD_FRAME
+        )
+
+        p.applyExternalForce(
+            blue_ball, -1, forceObj=[40000, 0, 0], posObj=blue_pos, flags=p.WORLD_FRAME
+        )
+
+        apply_force = 0
+
+    sync_actor(blue_ball_actor, blue_ball)
+    sync_actor(red_ball_actor, red_ball)
+
+    # Get various collision information using `p.getContactPoints`.
+    contact = p.getContactPoints(red_ball, blue_ball, -1, -1)
+    if len(contact) != 0:
+        tb.message = 'Collision!!'
+
+    p.stepSimulation()
+
+    if cnt == 50:
+        showm.exit()
+
+
+showm.add_timer_callback(True, duration, timer_callback)
+
+interactive = False
+
+if interactive:
+    showm.start()
+
+window.record(scene, size=(900, 700), out_path='viz_ball_collide.png')
+
+
+viz ball collide

Total running time of the script: (0 minutes 0.558 seconds)

+ +

Gallery generated by Sphinx-Gallery

+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/auto_examples/17_pybullet/viz_brick_wall.html b/v0.10.x/auto_examples/17_pybullet/viz_brick_wall.html new file mode 100644 index 000000000..c815db51d --- /dev/null +++ b/v0.10.x/auto_examples/17_pybullet/viz_brick_wall.html @@ -0,0 +1,814 @@ + + + + + + + + Brick Wall Simulation — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +
+

Brick Wall Simulation#

+

This example simulation shows how to use pybullet to render physics simulations +in fury. In this example we specifically render a ball beign thrown at a brick +wall.

+

First some imports.

+
import itertools
+
+import numpy as np
+import pybullet as p
+
+from fury import actor, ui, utils, window
+
+
+

Next, we initialize a pybullet client to render the physics. We use DIRECT +mode to initialize pybullet without a GUI.

+
p.connect(p.DIRECT)
+
+
+
1
+
+
+

Apply gravity to the scene. In pybullet all values are in SI units.

+
p.setGravity(0, 0, -10)
+
+
+

We define some global parameters so that its easier for us to tweak the +tweak the simulation.

+
# Ball Parameters
+ball_radius = 0.3
+ball_color = np.array([1, 0, 0])
+ball_mass = 3
+ball_position = np.array([2, 0, 1.5])
+ball_orientation = np.array([0, 0, 0, 1])
+
+# Base Plane Parameters
+base_size = np.array([5, 5, 0.2])
+base_color = np.array([1, 1, 1])
+base_position = np.array([0, 0, -0.1])
+base_orientation = np.array([0, 0, 0, 1])
+
+# Wall Parameters
+wall_height = 10
+wall_width = 10
+brick_mass = 0.5
+brick_size = np.array([0.2, 0.4, 0.2])
+
+
+

Now we define the required parameters to render the Ball.

+
# Ball actor
+ball_actor = actor.sphere(
+    centers=np.array([[0, 0, 0]]), colors=ball_color, radii=ball_radius
+)
+
+# Collision shape for the ball.
+ball_coll = p.createCollisionShape(p.GEOM_SPHERE, radius=ball_radius)
+
+# Creating a multi-body which will be tracked by pybullet.
+ball = p.createMultiBody(
+    baseMass=3,
+    baseCollisionShapeIndex=ball_coll,
+    basePosition=ball_position,
+    baseOrientation=ball_orientation,
+)
+
+# Change the dynamics of the ball by adding friction and restitution.
+p.changeDynamics(ball, -1, lateralFriction=0.3, restitution=0.5)
+
+
+

Render a base plane to support the bricks.

+
base_actor = actor.box(
+    centers=np.array([[0, 0, 0]]),
+    directions=[0, 0, 0],
+    scales=base_size,
+    colors=base_color,
+)
+
+base_coll = p.createCollisionShape(p.GEOM_BOX, halfExtents=base_size / 2)
+# half of the actual size.
+
+base = p.createMultiBody(
+    baseCollisionShapeIndex=base_coll,
+    basePosition=base_position,
+    baseOrientation=base_orientation,
+)
+
+p.changeDynamics(base, -1, lateralFriction=0.3, restitution=0.5)
+
+
+

Now we render the bricks. All the bricks are rendered by a single actor for +better performance.

+
nb_bricks = wall_height * wall_width
+
+brick_centers = np.zeros((nb_bricks, 3))
+
+brick_directions = np.zeros((nb_bricks, 3))
+brick_directions[:] = np.array([1.57, 0, 0])
+
+brick_orns = np.zeros((nb_bricks, 4))
+
+brick_sizes = np.zeros((nb_bricks, 3))
+brick_sizes[:] = brick_size
+
+brick_colors = np.random.rand(nb_bricks, 3)
+
+brick_coll = p.createCollisionShape(p.GEOM_BOX, halfExtents=brick_size / 2)
+
+# We use this array to store the reference of brick objects in pybullet world.
+bricks = np.zeros(nb_bricks, dtype=np.int8)
+
+# Logic to position the bricks appropriately to form a wall.
+i = 0
+for k in range(wall_height):
+    for j in range(wall_width):
+        center_pos = np.array([-1, (j * 0.4) - 1.8, (0.2 * k) + 0.1])
+        brick_centers[i] = center_pos
+        brick_orns[i] = np.array([0, 0, 0, 1])
+        bricks[i] = p.createMultiBody(
+            baseMass=brick_mass,
+            baseCollisionShapeIndex=brick_coll,
+            basePosition=center_pos,
+            baseOrientation=brick_orns[i],
+        )
+        p.changeDynamics(bricks[i], -1, lateralFriction=0.1, restitution=0.1)
+        i += 1
+
+brick_actor = actor.box(
+    centers=brick_centers,
+    directions=brick_directions,
+    scales=brick_sizes,
+    colors=brick_colors,
+)
+
+
+

Now, we define a scene and add actors to it.

+
scene = window.Scene()
+scene.add(actor.axes())
+scene.add(ball_actor)
+scene.add(base_actor)
+scene.add(brick_actor)
+
+# Create show manager.
+showm = window.ShowManager(
+    scene, size=(900, 768), reset_camera=False, order_transparent=True
+)
+
+
+# Counter iterator for tracking simulation steps.
+counter = itertools.count()
+
+# Variable for tracking applied force.
+apply_force = True
+
+
+

Now, we define methods to sync objects between fury and Pybullet.

+
# Get the position of base and set it.
+base_pos, _ = p.getBasePositionAndOrientation(base)
+base_actor.SetPosition(*base_pos)
+
+# Do the same for ball.
+ball_pos, _ = p.getBasePositionAndOrientation(ball)
+ball_actor.SetPosition(*ball_pos)
+
+# Calculate the vertices of the bricks.
+vertices = utils.vertices_from_actor(brick_actor)
+num_vertices = vertices.shape[0]
+num_objects = brick_centers.shape[0]
+sec = int(num_vertices / num_objects)
+
+
+
+
+

Syncing Bricks#

+

Here, we perform three major steps to sync bricks accurately. +* Get the position and orientation of the bricks from pybullet. +* Calculate the Rotation Matrix.

+
+
    +
  • Get the difference in orientations (Quaternion).

  • +
  • Generate the corresponding rotation matrix according to that difference.

  • +
  • Reshape it in a 3x3 matrix.

  • +
+
+
    +
  • Perform calculations to get the required position and orientation.

  • +
  • Update the position and orientation.

  • +
+
def sync_brick(object_index, multibody):
+    pos, orn = p.getBasePositionAndOrientation(multibody)
+
+    rot_mat = np.reshape(
+        p.getMatrixFromQuaternion(
+            p.getDifferenceQuaternion(orn, brick_orns[object_index])
+        ),
+        (3, 3),
+    )
+
+    vertices[object_index * sec : object_index * sec + sec] = (
+        vertices[object_index * sec : object_index * sec + sec]
+        - brick_centers[object_index]
+    ) @ rot_mat + pos
+
+    brick_centers[object_index] = pos
+    brick_orns[object_index] = orn
+
+
+

A simpler but inaccurate approach is used here to update the position and +orientation.

+
def sync_actor(actor, multibody):
+    pos, orn = p.getBasePositionAndOrientation(multibody)
+    actor.SetPosition(*pos)
+    orn_deg = np.degrees(p.getEulerFromQuaternion(orn))
+    actor.SetOrientation(*orn_deg)
+
+
+

Here, we define a textblock to display the Avg. FPS and simulation steps.

+
fpss = np.array([])
+tb = ui.TextBlock2D(
+    text='Avg. FPS: \nSim Steps: ', position=(0, 680), font_size=30, color=(1, 0.5, 0)
+)
+scene.add(tb)
+
+
+

Set the camera for better visualization.

+
scene.set_camera(
+    position=(10.46, -8.13, 6.18),
+    focal_point=(0.0, 0.0, 0.79),
+    view_up=(-0.27, 0.26, 0.90),
+)
+
+
+

Timer callback is created which is responsible for calling the sync and +simulation methods.

+
# Create timer callback which will execute at each step of simulation.
+def timer_callback(_obj, _event):
+    global apply_force, fpss
+    cnt = next(counter)
+    showm.render()
+
+    if cnt % 1 == 0:
+        fps = showm.frame_rate
+        fpss = np.append(fpss, fps)
+        tb.message = (
+            'Avg. FPS: ' + str(np.round(np.mean(fpss), 0)) + '\nSim Steps: ' + str(cnt)
+        )
+
+    # Get the position and orientation of the ball.
+    ball_pos, ball_orn = p.getBasePositionAndOrientation(ball)
+
+    # Apply force for 5 times for the first step of simulation.
+    if apply_force:
+        # Apply the force.
+        p.applyExternalForce(
+            ball, -1, forceObj=[-10000, 0, 0], posObj=ball_pos, flags=p.WORLD_FRAME
+        )
+        apply_force = False
+
+    # Set position and orientation of the ball.
+    sync_actor(ball_actor, ball)
+
+    # Updating the position and orientation of each individual brick.
+    for idx, brick in enumerate(bricks):
+        sync_brick(idx, brick)
+    utils.update_actor(brick_actor)
+
+    # Simulate a step.
+    p.stepSimulation()
+
+    # Exit after 2000 steps of simulation.
+    if cnt == 130:
+        showm.exit()
+
+
+# Add the timer callback to showmanager.
+# Increasing the duration value will slow down the simulation.
+showm.add_timer_callback(True, 1, timer_callback)
+
+interactive = False
+
+# start simulation
+if interactive:
+    showm.start()
+
+window.record(scene, out_path='viz_brick_wall.png', size=(900, 768))
+
+
+viz brick wall

Total running time of the script: (0 minutes 0.258 seconds)

+ +

Gallery generated by Sphinx-Gallery

+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ +
+ On this page +
+ +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/auto_examples/17_pybullet/viz_chain.html b/v0.10.x/auto_examples/17_pybullet/viz_chain.html new file mode 100644 index 000000000..1c0886c4c --- /dev/null +++ b/v0.10.x/auto_examples/17_pybullet/viz_chain.html @@ -0,0 +1,756 @@ + + + + + + + + Chain Simulation — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +
+

Chain Simulation#

+

This example simulation shows how to use pybullet to render physics simulations +in fury. In this example we specifically render a Chain oscillating to and from.

+

First some imports.

+
import itertools
+
+import numpy as np
+import pybullet as p
+
+from fury import actor, ui, utils, window
+
+
+

Setup pybullet and add gravity.

+
p.connect(p.DIRECT)
+
+# Apply gravity to the scene.
+p.setGravity(0, 0, -10)
+
+
+

Now we render the Chain using the following parameters and definitions.

+
# Parameters
+n_links = 20
+dx_link = 0.1  # Size of segments
+link_mass = 0.5
+base_mass = 0.1
+radii = 0.5
+
+joint_friction = 0.0005  # rotational joint friction [N/(rad/s)]
+
+link_shape = p.createCollisionShape(
+    p.GEOM_CYLINDER,
+    radius=radii,
+    height=dx_link,
+    collisionFramePosition=[0, 0, -dx_link / 2],
+)
+
+base_shape = p.createCollisionShape(p.GEOM_BOX, halfExtents=[0.01, 0.01, 0.01])
+
+visualShapeId = -1
+
+link_Masses = np.zeros(n_links)
+link_Masses[:] = link_mass
+
+linkCollisionShapeIndices = np.zeros(n_links)
+linkCollisionShapeIndices[:] = np.array(link_shape)
+linkVisualShapeIndices = -1 * np.ones(n_links)
+linkPositions = np.zeros((n_links, 3))
+linkPositions[:] = np.array([0, 0, -dx_link])
+linkOrientations = np.zeros((n_links, 4))
+linkOrientations[:] = np.array([0, 0, 0, 1])
+linkInertialFramePositions = np.zeros((n_links, 3))
+linkInertialFrameOrns = np.zeros((n_links, 4))
+linkInertialFrameOrns[:] = np.array([0, 0, 0, 1])
+indices = np.arange(n_links)
+jointTypes = np.zeros(n_links)
+jointTypes[:] = np.array(p.JOINT_SPHERICAL)
+axis = np.zeros((n_links, 3))
+axis[:] = np.array([1, 0, 0])
+
+linkDirections = np.zeros((n_links, 3))
+linkDirections[:] = np.array([1, 1, 1])
+
+link_radii = np.zeros(n_links)
+link_radii[:] = radii
+
+link_heights = np.zeros(n_links)
+link_heights[:] = dx_link
+
+rope_actor = actor.cylinder(
+    centers=linkPositions,
+    directions=linkDirections,
+    colors=np.random.rand(n_links, 3),
+    radius=radii,
+    heights=link_heights,
+    capped=True,
+)
+
+basePosition = [0, 0, 2]
+baseOrientation = [0, 0, 0, 1]
+rope = p.createMultiBody(
+    base_mass,
+    base_shape,
+    visualShapeId,
+    basePosition,
+    baseOrientation,
+    linkMasses=link_Masses,
+    linkCollisionShapeIndices=linkCollisionShapeIndices.astype(int),
+    linkVisualShapeIndices=linkVisualShapeIndices.astype(int),
+    linkPositions=linkPositions,
+    linkOrientations=linkOrientations,
+    linkInertialFramePositions=linkInertialFramePositions,
+    linkInertialFrameOrientations=linkInertialFrameOrns,
+    linkParentIndices=indices.astype(int),
+    linkJointTypes=jointTypes.astype(int),
+    linkJointAxis=axis.astype(int),
+)
+
+
+

We remove stiffness among the joints by adding friction to them.

+
friction_vec = [joint_friction] * 3  # same all axis
+control_mode = p.POSITION_CONTROL  # set pos control mode
+for j in range(p.getNumJoints(rope)):
+    p.setJointMotorControlMultiDof(
+        rope,
+        j,
+        control_mode,
+        targetPosition=[0, 0, 0, 1],
+        targetVelocity=[0, 0, 0],
+        positionGain=0,
+        velocityGain=1,
+        force=friction_vec,
+    )
+
+
+

Next, we define a constraint base that will help us in the oscillation of the +chain.

+
root_robe_c = p.createConstraint(
+    rope, -1, -1, -1, p.JOINT_FIXED, [0, 0, 0], [0, 0, 0], [0, 0, 2]
+)
+
+# some traj to inject motion
+amplitude_x = 0.3
+amplitude_y = 0.0
+freq = 0.6
+
+base_actor = actor.box(
+    centers=np.array([[0, 0, 0]]),
+    directions=np.array([[0, 0, 0]]),
+    scales=(0.02, 0.02, 0.02),
+    colors=np.array([[1, 0, 0]]),
+)
+
+
+

We add the necessary actors to the scene.

+
scene = window.Scene()
+scene.background((1, 1, 1))
+scene.set_camera((2.2, -3.0, 3.0), (-0.3, 0.6, 0.7), (-0.2, 0.2, 1.0))
+scene.add(actor.axes(scale=(0.1, 0.1, 0.1)))
+scene.add(rope_actor)
+scene.add(base_actor)
+
+# Create show manager.
+showm = window.ShowManager(
+    scene, size=(900, 768), reset_camera=False, order_transparent=True
+)
+
+
+# Counter iterator for tracking simulation steps.
+counter = itertools.count()
+
+
+

We define a couple of syncing methods for the base and chain.

+
# Function for syncing actors with multi-bodies.
+def sync_actor(actor, multibody):
+    pos, orn = p.getBasePositionAndOrientation(multibody)
+    actor.SetPosition(*pos)
+    orn_deg = np.degrees(p.getEulerFromQuaternion(orn))
+    actor.SetOrientation(*orn_deg)
+
+
+vertices = utils.vertices_from_actor(rope_actor)
+num_vertices = vertices.shape[0]
+num_objects = linkPositions.shape[0]
+sec = int(num_vertices / num_objects)
+
+
+def sync_joints(actor_list, multibody):
+    for joint in range(p.getNumJoints(multibody)):
+        # `p.getLinkState` offers various information about the joints
+        # as a list and the values in 4th and 5th index refer to the joint's
+        # position and orientation respectively.
+        pos, orn = p.getLinkState(multibody, joint)[4:6]
+
+        rot_mat = np.reshape(
+            p.getMatrixFromQuaternion(
+                p.getDifferenceQuaternion(orn, linkOrientations[joint])
+            ),
+            (3, 3),
+        )
+
+        vertices[joint * sec : joint * sec + sec] = (
+            vertices[joint * sec : joint * sec + sec] - linkPositions[joint]
+        ) @ rot_mat + pos
+
+        linkPositions[joint] = pos
+        linkOrientations[joint] = orn
+
+
+

We define a TextBlock to display the Avg. FPS and Simulation steps.

+
fpss = np.array([])
+tb = ui.TextBlock2D(
+    position=(0, 680), font_size=30, color=(1, 0.5, 0), text='Avg. FPS: \nSim Steps: '
+)
+scene.add(tb)
+
+t = 0.0
+freq_sim = 240
+
+
+

Timer callback to sync objects, simulate steps and oscillate the base.

+
def timer_callback(_obj, _event):
+    cnt = next(counter)
+    global t, fpss
+    showm.render()
+
+    t += 1.0 / freq_sim
+
+    if cnt % 1 == 0:
+        fps = showm.frame_rate
+        fpss = np.append(fpss, fps)
+        tb.message = (
+            'Avg. FPS: ' + str(np.round(np.mean(fpss), 0)) + '\nSim Steps: ' + str(cnt)
+        )
+
+    # some trajectory
+    ux = amplitude_x * np.sin(2 * np.pi * freq * t)
+    uy = amplitude_y * np.cos(2 * np.pi * freq * t)
+
+    # move base around
+    pivot = [3 * ux, uy, 2]
+    orn = p.getQuaternionFromEuler([0, 0, 0])
+    p.changeConstraint(root_robe_c, pivot, jointChildFrameOrientation=orn, maxForce=500)
+
+    # Sync base and chain.
+    sync_actor(base_actor, rope)
+    sync_joints(rope_actor, rope)
+    utils.update_actor(rope_actor)
+
+    # Simulate a step.
+    p.stepSimulation()
+
+    # Exit after 2000 steps of simulation.
+    if cnt == 130:
+        showm.exit()
+
+
+# Add the timer callback to showmanager.
+# Increasing the duration value will slow down the simulation.
+showm.add_timer_callback(True, 1, timer_callback)
+
+interactive = False
+
+# start simulation
+if interactive:
+    showm.start()
+
+window.record(scene, size=(900, 768), out_path='viz_chain.png')
+
+
+viz chain

Total running time of the script: (0 minutes 0.591 seconds)

+ +

Gallery generated by Sphinx-Gallery

+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/auto_examples/17_pybullet/viz_domino.html b/v0.10.x/auto_examples/17_pybullet/viz_domino.html new file mode 100644 index 000000000..75a998616 --- /dev/null +++ b/v0.10.x/auto_examples/17_pybullet/viz_domino.html @@ -0,0 +1,765 @@ + + + + + + + + Domino Physics Simulation — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +
+

Domino Physics Simulation#

+

This example simulation shows how to use pybullet to render physics simulations +in fury. In this example we specifically render a series of Dominoes which are +under Domino Effect.

+

First some imports.

+
import itertools
+
+import numpy as np
+import pybullet as p
+
+from fury import actor, ui, utils, window
+
+# Next, we initialize a pybullet client to render the physics.
+# We use `DIRECT` mode to initialize pybullet without a GUI.
+client = p.connect(p.DIRECT)
+
+# Apply gravity to the scene.
+p.setGravity(0, 0, -10, physicsClientId=client)
+
+
+

Set the Number of Dominoes for Simulation.

+
number_of_dominoes = 10
+
+# Base Plane Parameters
+base_size = np.array([number_of_dominoes * 2, number_of_dominoes * 2, 0.2])
+base_color = np.array([1, 1, 1])
+base_position = np.array([0, 0, -0.1])
+base_orientation = np.array([0, 0, 0, 1])
+
+# Render a BASE plane to support the Dominoes.
+base_actor = actor.box(
+    centers=np.array([[0, 0, 0]]),
+    directions=[0, 0, 0],
+    scales=base_size,
+    colors=base_color,
+)
+
+# half of the actual size.
+base_coll = p.createCollisionShape(p.GEOM_BOX, halfExtents=base_size / 2)
+
+base = p.createMultiBody(
+    baseCollisionShapeIndex=base_coll,
+    basePosition=base_position,
+    baseOrientation=base_orientation,
+)
+
+p.changeDynamics(base, -1, lateralFriction=1, restitution=0.5)
+
+
+

We define some global parameters of the Dominoes so that its easier for +us to tweak the simulation.

+
domino_mass = 0.5
+domino_size = np.array([0.1, 1, 2])
+
+domino_centers = np.zeros((number_of_dominoes, 3))
+
+# Keeping all the dominos Parallel
+domino_directions = np.zeros((number_of_dominoes, 3))
+domino_directions[:] = np.array([1.57, 0, 0])
+
+domino_orns = np.zeros((number_of_dominoes, 4))
+
+domino_sizes = np.zeros((number_of_dominoes, 3))
+domino_sizes[:] = domino_size
+
+domino_colors = np.random.rand(number_of_dominoes, 3)
+
+domino_coll = p.createCollisionShape(p.GEOM_BOX, halfExtents=domino_size / 2)
+
+# We use this array to store the reference of domino objects in pybullet world.
+dominos = np.zeros(number_of_dominoes, dtype=np.int8)
+
+centers_list = np.zeros((number_of_dominoes, 3))
+
+# Adding the dominoes
+for i in range(number_of_dominoes):
+    center_pos = np.array([(i * 0.99) - 5.5, 0.4, 1])
+    domino_centers[i] = center_pos
+    domino_orns[i] = np.array([0, 0, 0, 1])
+    dominos[i] = p.createMultiBody(
+        baseMass=domino_mass,
+        baseCollisionShapeIndex=domino_coll,
+        basePosition=center_pos,
+        baseOrientation=domino_orns[i],
+    )
+    p.changeDynamics(dominos[i], -1, lateralFriction=0.2, restitution=0.1)
+
+
+domino_actor = actor.box(
+    centers=domino_centers,
+    directions=domino_directions,
+    scales=domino_sizes,
+    colors=domino_colors,
+)
+
+
+

Now, we define a scene and add actors to it.

+
scene = window.Scene()
+scene.add(actor.axes())
+scene.add(base_actor)
+scene.add(domino_actor)
+
+# Create show manager.
+showm = window.ShowManager(
+    scene, size=(900, 768), reset_camera=False, order_transparent=True
+)
+
+
+# Counter iterator for tracking simulation steps.
+counter = itertools.count()
+
+# Variable for tracking applied force.
+apply_force = True
+
+
+

Now, we define methods to sync objects between fury and Pybullet.

+
# Get the position of base and set it.
+base_pos, _ = p.getBasePositionAndOrientation(base)
+base_actor.SetPosition(*base_pos)
+
+
+# Calculate the vertices of the dominos.
+vertices = utils.vertices_from_actor(domino_actor)
+num_vertices = vertices.shape[0]
+num_objects = domino_centers.shape[0]
+sec = int(num_vertices / num_objects)
+
+
+
+
+

Syncing Dominoes#

+

Here, we perform three major steps to sync Dominoes accurately. +* Get the position and orientation of the Dominoes from pybullet. +* Calculate the Rotation Matrix.

+
+
    +
  • Get the difference in orientations (Quaternion).

  • +
  • Generate the corresponding rotation matrix according to that difference.

  • +
  • Reshape it in a 3x3 matrix.

  • +
+
+
    +
  • Perform calculations to get the required position and orientation.

  • +
  • Update the position and orientation.

  • +
+
def sync_domino(object_index, multibody):
+    pos, orn = p.getBasePositionAndOrientation(multibody)
+
+    rot_mat = np.reshape(
+        p.getMatrixFromQuaternion(
+            p.getDifferenceQuaternion(orn, domino_orns[object_index])
+        ),
+        (3, 3),
+    )
+
+    vertices[object_index * sec : object_index * sec + sec] = (
+        vertices[object_index * sec : object_index * sec + sec]
+        - domino_centers[object_index]
+    ) @ rot_mat + pos
+
+    domino_centers[object_index] = pos
+    domino_orns[object_index] = orn
+
+
+

Here, we define a textblock to display the Avg. FPS and simulation steps.

+
fpss = np.array([])
+tb = ui.TextBlock2D(
+    text='Avg. FPS: \nSim Steps: ', position=(0, 680), font_size=30, color=(1, 0.5, 0)
+)
+scene.add(tb)
+
+
+

Set the camera for better visualization.

+
scene.set_camera(
+    position=(10.46, -8.13, 6.18),
+    focal_point=(0.0, 0.0, 0.79),
+    view_up=(-0.27, 0.26, 0.90),
+)
+
+
+

Timer callback is created which is responsible for calling the sync and +simulation methods.

+
# Create timer callback which will execute at each step of simulation.
+def timer_callback(_obj, _event):
+    global apply_force, fpss
+    cnt = next(counter)
+    showm.render()
+
+    if cnt % 1 == 0:
+        fps = showm.frame_rate
+        fpss = np.append(fpss, fps)
+        tb.message = (
+            'Avg. FPS: ' + str(np.round(np.mean(fpss), 0)) + '\nSim Steps: ' + str(cnt)
+        )
+
+    # Get the position and orientation of the first domino.
+    domino1_pos, domino1_orn = p.getBasePositionAndOrientation(dominos[0])
+
+    # Apply force on the First Domino (domino) above the Center of Mass.
+    if apply_force:
+        # Apply the force.
+        p.applyExternalForce(
+            dominos[0],
+            -1,
+            forceObj=[100, 0, 0],
+            posObj=domino1_pos + np.array([0, 0, 1.7]),
+            flags=p.WORLD_FRAME,
+        )
+        apply_force = False
+
+    # Updating the position and orientation of individual dominos.
+    for idx, domino in enumerate(dominos):
+        sync_domino(idx, domino)
+    utils.update_actor(domino_actor)
+
+    # Simulate a step.
+    p.stepSimulation()
+
+    # Exit after 300 steps of simulation.
+    if cnt == 300:
+        showm.exit()
+
+
+# Add the timer callback to showmanager.
+# Increasing the duration value will slow down the simulation.
+showm.add_timer_callback(True, 1, timer_callback)
+
+interactive = False
+
+# start simulation
+if interactive:
+    showm.start()
+
+window.record(scene, out_path='viz_domino.png', size=(900, 768))
+
+
+viz domino

Total running time of the script: (0 minutes 0.110 seconds)

+ +

Gallery generated by Sphinx-Gallery

+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ +
+ On this page +
+ +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/auto_examples/17_pybullet/viz_wrecking_ball.html b/v0.10.x/auto_examples/17_pybullet/viz_wrecking_ball.html new file mode 100644 index 000000000..0b726e0dc --- /dev/null +++ b/v0.10.x/auto_examples/17_pybullet/viz_wrecking_ball.html @@ -0,0 +1,861 @@ + + + + + + + + Wrecking Ball Simulation — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +
+

Wrecking Ball Simulation#

+

This example simulation shows how to use pybullet to render physics simulations +in fury. In this example we specifically render a brick wall being destroyed by +a wrecking ball.

+

First some imports.

+
import itertools
+
+import numpy as np
+import pybullet as p
+
+from fury import actor, ui, utils, window
+
+
+

Initiate pybullet and enable gravity.

+
p.connect(p.DIRECT)
+p.setGravity(0, 0, -10)
+
+
+

Define some handy parameters to customize simulation.

+
# Parameters
+wall_length = 5
+wall_breadth = 5
+wall_height = 5
+
+brick_size = np.array([0.2, 0.4, 0.2])
+
+n_links = 15
+# Size of segments
+dx_link = 0.1
+link_mass = 0.5
+base_mass = 0.1
+# radius of the cylindrical links or the rope
+radii = 0.1
+
+ball_mass = 10
+# radius of the wrecking ball
+ball_radius = 0.5
+ball_color = np.array([[1, 0, 0]])
+
+joint_friction = 0.0005
+
+
+

Creating the base plane actor.

+
# Base
+base_actor = actor.box(
+    centers=np.array([[0, 0, 0]]),
+    directions=[0, 0, 0],
+    scales=(5, 5, 0.2),
+    colors=(1, 1, 1),
+)
+base_coll = p.createCollisionShape(p.GEOM_BOX, halfExtents=[2.5, 2.5, 0.1])
+base = p.createMultiBody(
+    baseCollisionShapeIndex=base_coll,
+    basePosition=[0, 0, -0.1],
+    baseOrientation=[0, 0, 0, 1],
+)
+p.changeDynamics(base, -1, lateralFriction=0.3, restitution=0.5)
+
+
+

The following definitions are made to render a NxNxN brick wall.

+ +

The following is the logic to position the bricks in our desired location and +generate the actor.

+
idx = 0
+# Setting up wall
+for i in range(wall_length):
+    for k in range(wall_height):
+        for j in range(wall_breadth):
+            center_pos = np.array([(i * 0.2) - 1.8, (j * 0.4) - 0.9, (0.2 * k) + 0.1])
+            brick_centers[idx] = center_pos
+            brick_orns[idx] = np.array([0, 0, 0, 1])
+            bricks[idx] = p.createMultiBody(
+                baseMass=0.5,
+                baseCollisionShapeIndex=brick_coll,
+                basePosition=center_pos,
+                baseOrientation=brick_orns[i],
+            )
+            p.changeDynamics(bricks[idx], -1, lateralFriction=0.1, restitution=0.1)
+            idx += 1
+
+brick_actor = actor.box(
+    centers=brick_centers,
+    directions=brick_directions,
+    scales=brick_sizes,
+    colors=brick_colors,
+)
+
+
+

Now we render the wrecking ball consisting of a fixed hinge, a ball and rope.

+
# Generate wrecking ball
+link_shape = p.createCollisionShape(
+    p.GEOM_CYLINDER,
+    radius=radii,
+    height=dx_link,
+    collisionFramePosition=[0, 0, -dx_link / 2],
+)
+
+base_shape = p.createCollisionShape(p.GEOM_BOX, halfExtents=[0.01, 0.01, 0.01])
+ball_shape = p.createCollisionShape(p.GEOM_SPHERE, radius=ball_radius)
+
+visualShapeId = -1
+
+link_Masses = np.zeros(n_links)
+link_Masses[:] = link_mass
+link_Masses[-1] = 5
+linkCollisionShapeIndices = np.zeros(n_links)
+linkCollisionShapeIndices[:] = np.array(link_shape)
+linkCollisionShapeIndices[-1] = ball_shape
+linkVisualShapeIndices = -1 * np.ones(n_links)
+linkPositions = np.zeros((n_links, 3))
+linkPositions[:] = np.array([0, 0, -dx_link])
+linkOrientations = np.zeros((n_links, 4))
+linkOrientations[:] = np.array([0, 0, 0, 1])
+linkInertialFramePositions = np.zeros((n_links, 3))
+linkInertialFrameOrns = np.zeros((n_links, 4))
+linkInertialFrameOrns[:] = np.array([0, 0, 0, 1])
+indices = np.arange(n_links)
+jointTypes = np.zeros(n_links)
+jointTypes[:] = np.array(p.JOINT_SPHERICAL)
+axis = np.zeros((n_links, 3))
+axis[:] = np.array([1, 0, 0])
+
+linkDirections = np.zeros((n_links, 3))
+linkDirections[:] = np.array([1, 1, 1])
+
+link_radii = np.zeros(n_links)
+link_radii[:] = radii
+
+link_heights = np.zeros(n_links)
+link_heights[:] = dx_link
+
+rope_actor = actor.cylinder(
+    centers=linkPositions,
+    directions=linkDirections,
+    colors=np.random.rand(n_links, 3),
+    radius=radii,
+    heights=link_heights,
+    capped=True,
+)
+
+basePosition = [0, 0, 2]
+baseOrientation = [0, 0, 0, 1]
+rope = p.createMultiBody(
+    base_mass,
+    base_shape,
+    visualShapeId,
+    basePosition,
+    baseOrientation,
+    linkMasses=link_Masses,
+    linkCollisionShapeIndices=linkCollisionShapeIndices.astype(int),
+    linkVisualShapeIndices=linkVisualShapeIndices.astype(int),
+    linkPositions=linkPositions.astype(int),
+    linkOrientations=linkOrientations.astype(int),
+    linkInertialFramePositions=linkInertialFramePositions.astype(int),
+    linkInertialFrameOrientations=linkInertialFrameOrns.astype(int),
+    linkParentIndices=indices.astype(int),
+    linkJointTypes=jointTypes.astype(int),
+    linkJointAxis=axis.astype(int),
+)
+
+
+

Next we define the frictional force between the joints of wrecking ball.

+
friction_vec = [joint_friction] * 3  # same all axis
+control_mode = p.POSITION_CONTROL  # set pos control mode
+for j in range(p.getNumJoints(rope)):
+    p.setJointMotorControlMultiDof(
+        rope,
+        j,
+        control_mode,
+        targetPosition=[0, 0, 0, 1],
+        targetVelocity=[0, 0, 0],
+        positionGain=0,
+        velocityGain=1,
+        force=friction_vec,
+    )
+
+
+

We add the following constraint to keep the cubical hinge fixed.

+
root_robe_c = p.createConstraint(
+    rope, -1, -1, -1, p.JOINT_FIXED, [0, 0, 0], [0, 0, 0], [0, 0, 2]
+)
+
+box_actor = actor.box(
+    centers=np.array([[0, 0, 0]]),
+    directions=np.array([[0, 0, 0]]),
+    scales=(0.02, 0.02, 0.02),
+    colors=np.array([[1, 0, 0]]),
+)
+
+ball_actor = actor.sphere(
+    centers=np.array([[0, 0, 0]]), radii=ball_radius, colors=np.array([1, 0, 1])
+)
+
+
+

Now we add the necessary actors to the scene and set the camera for better +visualization.

+
scene = window.Scene()
+scene.set_camera((10.28, -7.10, 6.39), (0.0, 0.0, 0.4), (-0.35, 0.26, 1.0))
+scene.add(actor.axes(scale=(0.5, 0.5, 0.5)), base_actor, brick_actor)
+scene.add(rope_actor, box_actor, ball_actor)
+
+showm = window.ShowManager(
+    scene, size=(900, 768), reset_camera=False, order_transparent=True
+)
+
+
+

Position the base correctly.

+
base_pos, base_orn = p.getBasePositionAndOrientation(base)
+base_actor.SetPosition(*base_pos)
+
+
+

Calculate the vertices of the bricks.

+ +

Calculate the vertices of the wrecking ball.

+ +

We define methods to sync bricks and wrecking ball.

+
# Function for syncing actors with multibodies.
+def sync_brick(object_index, multibody):
+    pos, orn = p.getBasePositionAndOrientation(multibody)
+
+    rot_mat = np.reshape(
+        p.getMatrixFromQuaternion(
+            p.getDifferenceQuaternion(orn, brick_orns[object_index])
+        ),
+        (3, 3),
+    )
+
+    sec = brick_sec
+
+    brick_vertices[object_index * sec : object_index * sec + sec] = (
+        brick_vertices[object_index * sec : object_index * sec + sec]
+        - brick_centers[object_index]
+    ) @ rot_mat + pos
+
+    brick_centers[object_index] = pos
+    brick_orns[object_index] = orn
+
+
+def sync_chain(actor_list, multibody):
+    for joint in range(p.getNumJoints(multibody)):
+        # `p.getLinkState` offers various information about the joints
+        # as a list and the values in 4th and 5th index refer to the joint's
+        # position and orientation respectively.
+        pos, orn = p.getLinkState(multibody, joint)[4:6]
+
+        rot_mat = np.reshape(
+            p.getMatrixFromQuaternion(
+                p.getDifferenceQuaternion(orn, linkOrientations[joint])
+            ),
+            (3, 3),
+        )
+
+        sec = chain_sec
+
+        chain_vertices[joint * sec : joint * sec + sec] = (
+            chain_vertices[joint * sec : joint * sec + sec] - linkPositions[joint]
+        ) @ rot_mat + pos
+
+        linkPositions[joint] = pos
+        linkOrientations[joint] = orn
+
+
+

Some helper tools to keep track of avg. FPS and simulation steps.

+
counter = itertools.count()
+fpss = np.array([])
+tb = ui.TextBlock2D(
+    position=(0, 680), font_size=30, color=(1, 0.5, 0), text='Avg. FPS: \nSim Steps: '
+)
+scene.add(tb)
+
+
+

Timer callback to sync objects, simulate steps and apply force.

+
apply_force = True
+
+
+# Create timer callback which will execute at each step of simulation.
+def timer_callback(_obj, _event):
+    global apply_force, fpss
+    cnt = next(counter)
+    showm.render()
+
+    if cnt % 1 == 0:
+        fps = showm.frame_rate
+        fpss = np.append(fpss, fps)
+        tb.message = (
+            'Avg. FPS: ' + str(np.round(np.mean(fpss), 0)) + '\nSim Steps: ' + str(cnt)
+        )
+
+    # Updating the position and orientation of each individual brick.
+    for idx, brick in enumerate(bricks):
+        sync_brick(idx, brick)
+
+    pos, _ = p.getBasePositionAndOrientation(rope)
+
+    if apply_force:
+        p.applyExternalForce(
+            rope, -1, forceObj=[-500, 0, 0], posObj=pos, flags=p.WORLD_FRAME
+        )
+        apply_force = False
+
+    pos = p.getLinkState(rope, p.getNumJoints(rope) - 1)[4]
+    ball_actor.SetPosition(*pos)
+    sync_chain(rope_actor, rope)
+    utils.update_actor(brick_actor)
+    utils.update_actor(rope_actor)
+
+    # Simulate a step.
+    p.stepSimulation()
+
+    if cnt == 130:
+        showm.exit()
+
+
+# Add the timer callback to showmanager.
+# Increasing the duration value will slow down the simulation.
+showm.add_timer_callback(True, 1, timer_callback)
+
+interactive = True #False
+
+# start simulation
+if interactive:
+    showm.start()
+
+window.record(scene, size=(900, 768), out_path='viz_wrecking_ball.png')
+
+
+viz wrecking ball

Total running time of the script: (0 minutes 3.473 seconds)

+ +

Gallery generated by Sphinx-Gallery

+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/auto_examples/20_stream/index.html b/v0.10.x/auto_examples/20_stream/index.html new file mode 100644 index 000000000..dee6687f0 --- /dev/null +++ b/v0.10.x/auto_examples/20_stream/index.html @@ -0,0 +1,510 @@ + + + + + + + + Streaming — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Streaming#

+

These tutorials show:

+
    +
  • How to create a simple streaming server and turn that available.

  • +
  • How to create a streaming server with user interaction.

  • +
  • How to create a streaming server using the Widget Object.

  • +
+
+

Streaming FURY with WebRTC/MJPEG using the Widget Object

+
Streaming FURY with WebRTC/MJPEG using the Widget Object
+
+

Streaming FURY with WebRTC/MJPEG

+
Streaming FURY with WebRTC/MJPEG
+
+

Streaming FURY with user interaction

+
Streaming FURY with user interaction
+
+
+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/auto_examples/20_stream/sg_execution_times.html b/v0.10.x/auto_examples/20_stream/sg_execution_times.html new file mode 100644 index 000000000..fe7669fba --- /dev/null +++ b/v0.10.x/auto_examples/20_stream/sg_execution_times.html @@ -0,0 +1,504 @@ + + + + + + + + Computation times — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Computation times#

+

00:03.155 total execution time for 3 files from auto_examples/20_stream:

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +

Example

Time

Mem (MB)

Streaming FURY with WebRTC/MJPEG using the Widget Object (viz_widget.py)

00:01.648

0.0

Streaming FURY with WebRTC/MJPEG (viz_no_interaction.py)

00:01.397

0.0

Streaming FURY with user interaction (viz_interaction.py)

00:00.109

0.0

+
+
+ +
+ + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/auto_examples/20_stream/viz_interaction.html b/v0.10.x/auto_examples/20_stream/viz_interaction.html new file mode 100644 index 000000000..38f7264df --- /dev/null +++ b/v0.10.x/auto_examples/20_stream/viz_interaction.html @@ -0,0 +1,657 @@ + + + + + + + + Streaming FURY with user interaction — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +
+

Streaming FURY with user interaction#

+

In this tutorial, we show how to use the FURY Streaming system to +serve an interactive visualization through a web browser.

+

You can choose between two different encodings: WebRTC or MJPEG. +WebRTC is a more robust option and can be used to perform +a live streaming with a low-latency connection for example using +ngrok. However, to use webRTC you need to install the aiortc library.

+
pip install aiortc
+
+
+
+

Notes#

+

If you don’t have ffmpeg installed, you need to install it to use WebRTC

+

Linux

+

apt install libavdevice-dev libavfilter-dev libopus-dev libvpx-dev pkg-config

+

OS X

+

brew install ffmpeg opus libvpx pkg-config

+viz interaction
import multiprocessing
+import sys
+
+import numpy as np
+
+from fury import actor, window
+from fury.stream.client import FuryStreamClient, FuryStreamInteraction
+
+# if this example it's not working for you and you're using MacOs
+# uncomment the following line
+# multiprocessing.set_start_method('spawn')
+from fury.stream.server.main import WEBRTC_AVAILABLE, web_server, web_server_raw_array
+
+if __name__ == '__main__':
+    interactive = False
+    # `use_raw_array` is a flag to tell the server to use python RawArray
+    # instead of SharedMemory which is a new feature in python 3.8
+    # https://docs.python.org/3/library/multiprocessing.html#multiprocessing.Array
+    # https://docs.python.org/3/library/multiprocessing.html#shared-memory-objects
+
+    use_raw_array = sys.version_info < (3, 8)
+    window_size = (300, 300)
+    # `max_window_size` are the maximum size of the window that will be
+    # allowed to be sent to the browser. For example, if you set
+    # `max_window_size=(800, 800)` then the browser will be limited to
+    # a window of size (800, 800).
+
+    max_window_size = (400, 400)
+    # 0 ms_stream means that the frame will be sent to the server
+    # right after the rendering
+
+    # `ms_interaction` is the time in milliseconds that the user will have
+    # to interact with the visualization
+
+    ms_interaction = 1
+    # `ms_stream` is the number of milliseconds that the server will
+    # wait before sending a new frame to the browser. If `ms_stream=0`
+    # then the server will send the frame right after the rendering.
+
+    ms_stream = 0
+    # max number of interactions to be stored inside the queue
+    max_queue_size = 17
+    ######################################################################
+    centers = np.array([[0, 0, 0], [-1, 0, 0], [1, 0, 0]])
+    colors = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]])
+
+    actors = actor.sphere(centers, opacity=0.5, radii=0.4, colors=colors)
+    scene = window.Scene()
+
+    scene.add(actors)
+
+    showm = window.ShowManager(scene, size=(window_size[0], window_size[1]))
+
+    stream = FuryStreamClient(
+        showm, max_window_size=max_window_size, use_raw_array=use_raw_array
+    )
+    stream_interaction = FuryStreamInteraction(
+        showm, max_queue_size=max_queue_size, use_raw_array=use_raw_array
+    )
+
+    if use_raw_array:
+        p = multiprocessing.Process(
+            target=web_server_raw_array,
+            args=(
+                stream.img_manager.image_buffers,
+                stream.img_manager.info_buffer,
+                stream_interaction.circular_queue.head_tail_buffer,
+                stream_interaction.circular_queue.buffer._buffer,
+                8000,
+                'localhost',
+                True,
+                WEBRTC_AVAILABLE,
+            ),
+        )
+
+    else:
+        p = multiprocessing.Process(
+            target=web_server,
+            args=(
+                stream.img_manager.image_buffer_names,
+                stream.img_manager.info_buffer_name,
+                stream_interaction.circular_queue.head_tail_buffer_name,
+                stream_interaction.circular_queue.buffer.buffer_name,
+                8000,
+                'localhost',
+                True,
+                WEBRTC_AVAILABLE,
+            ),
+        )
+    p.start()
+    stream_interaction.start(ms=ms_interaction)
+    stream.start(
+        ms_stream,
+    )
+    ###########################################################################
+    # If you have aiortc in your system, you can see your live streaming
+    # through the following url: htttp://localhost:8000/?encoding=webrtc
+    # Other wise, you can use the following url:
+    # http://localhost:8000/?encoding=mjpeg
+
+    if interactive:
+        showm.start()
+
+    # We need to close the server after the show is over
+    p.kill()
+    ###########################################################################
+    # We release the resources and stop the interactive mode
+    stream.stop()
+    stream_interaction.stop()
+    stream.cleanup()
+    stream_interaction.cleanup()
+
+    window.record(showm.scene, size=window_size, out_path='viz_interaction.png')
+
+
+

Total running time of the script: (0 minutes 0.109 seconds)

+ +

Gallery generated by Sphinx-Gallery

+
+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ +
+ On this page +
+ +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/auto_examples/20_stream/viz_no_interaction.html b/v0.10.x/auto_examples/20_stream/viz_no_interaction.html new file mode 100644 index 000000000..472fcd26d --- /dev/null +++ b/v0.10.x/auto_examples/20_stream/viz_no_interaction.html @@ -0,0 +1,618 @@ + + + + + + + + Streaming FURY with WebRTC/MJPEG — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +
+

Streaming FURY with WebRTC/MJPEG#

+viz no interaction
webrtc not available
+Dataset is already in place. If you want to fetch it again please first remove the folder /Users/skoudoro/.fury/examples/wiki_nw
+More information about complex networks can be found in this papers: https://arxiv.org/abs/0711.3199
+
+
+
+

+
+
import multiprocessing
+from os.path import join as pjoin
+
+# if this example it's not working for you and you're using MacOs
+# uncomment the following line
+# multiprocessing.set_start_method('spawn')
+import numpy as np
+
+from fury import actor
+from fury import colormap as cmap
+from fury import window
+from fury.data.fetcher import fetch_viz_wiki_nw
+from fury.stream.client import FuryStreamClient
+from fury.stream.server.main import web_server_raw_array
+
+if __name__ == '__main__':
+
+    interactive = False
+    ###########################################################################
+    # First we will set the resolution which it'll be used by the streamer
+
+    window_size = (400, 400)
+
+    files, folder = fetch_viz_wiki_nw()
+    categories_file, edges_file, positions_file = sorted(files.keys())
+    positions = np.loadtxt(pjoin(folder, positions_file))
+    categories = np.loadtxt(pjoin(folder, categories_file), dtype=str)
+    edges = np.loadtxt(pjoin(folder, edges_file), dtype=int)
+    category2index = {category: i for i, category in enumerate(np.unique(categories))}
+
+    index2category = np.unique(categories)
+
+    categoryColors = cmap.distinguishable_colormap(nb_colors=len(index2category))
+
+    colors = np.array(
+        [categoryColors[category2index[category]] for category in categories]
+    )
+    radii = 1 + np.random.rand(len(positions))
+
+    edgesPositions = []
+    edgesColors = []
+    for source, target in edges:
+        edgesPositions.append(np.array([positions[source], positions[target]]))
+        edgesColors.append(np.array([colors[source], colors[target]]))
+
+    edgesPositions = np.array(edgesPositions)
+    edgesColors = np.average(np.array(edgesColors), axis=1)
+
+    sphere_actor = actor.sdf(
+        centers=positions,
+        colors=colors,
+        primitives='sphere',
+        scales=radii * 0.5,
+    )
+
+    lines_actor = actor.line(
+        edgesPositions,
+        colors=edgesColors,
+        opacity=0.1,
+    )
+    scene = window.Scene()
+
+    scene.add(lines_actor)
+    scene.add(sphere_actor)
+
+    scene.set_camera(
+        position=(0, 0, 1000), focal_point=(0.0, 0.0, 0.0), view_up=(0.0, 0.0, 0.0)
+    )
+
+    showm = window.ShowManager(
+        scene,
+        reset_camera=False,
+        size=(window_size[0], window_size[1]),
+        order_transparent=False,
+    )
+
+    ###########################################################################
+    # ms define the amount of mileseconds that will be used in the timer event.
+
+    ms = 0
+
+    stream = FuryStreamClient(showm, use_raw_array=True)
+    p = multiprocessing.Process(
+        target=web_server_raw_array,
+        args=(
+            stream.img_manager.image_buffers,
+            stream.img_manager.info_buffer,
+        ),
+    )
+    p.start()
+
+    stream.start(
+        ms,
+    )
+    if interactive:
+        showm.start()
+    stream.stop()
+    stream.cleanup()
+
+    window.record(showm.scene, size=window_size, out_path='viz_no_interaction.png')
+
+
+

Total running time of the script: (0 minutes 1.397 seconds)

+ +

Gallery generated by Sphinx-Gallery

+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/auto_examples/20_stream/viz_widget.html b/v0.10.x/auto_examples/20_stream/viz_widget.html new file mode 100644 index 000000000..757d708b2 --- /dev/null +++ b/v0.10.x/auto_examples/20_stream/viz_widget.html @@ -0,0 +1,601 @@ + + + + + + + + Streaming FURY with WebRTC/MJPEG using the Widget Object — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +
+

Streaming FURY with WebRTC/MJPEG using the Widget Object#

+

The Widget Object simplifies the process of streaming +your data visualization with WebRTC or MJPEG. Encoding. +Other users can view and interact with your data visualization +in real-time using a web-browser.

+

By default, the widget will open a local server on port 8000. +With the encoding parameter you can choose between mjpeg or +webrtc. WebRTC is a more robust option and can be used to perform +a live streaming with a low-latency connection. However, to use +webRTC you need to install the aiortc library.

+
pip install aiortc
+
+
+

In addition, if you don’t have ffmpeg installed, you need +to install it.

+

Linux

+

apt install libavdevice-dev libavfilter-dev libopus-dev libvpx-dev pkg-config

+

OS X

+

brew install ffmpeg opus libvpx pkg-config

+
+

Notes#

+

For this example your python version should be 3.8 or greater

+
import asyncio
+import platform
+import time
+
+import numpy as np
+
+from fury import actor, window
+from fury.stream.widget import Widget
+
+interactive = False
+window_size = (720, 500)
+N = 4
+centers = np.random.normal(size=(N, 3))
+colors = np.random.uniform(0.1, 1.0, size=(N, 3))
+actors = actor.sphere(centers, opacity=0.5, radii=0.4, colors=colors)
+scene = window.Scene()
+scene.add(actors)
+showm = window.ShowManager(scene, size=(window_size[0], window_size[1]))
+
+
+

Create a stream widget

+
widget = Widget(showm, port=8000)
+
+# if you want to use webRTC, you can pass the argument to choose this encoding
+# which is a more robust option.
+# `widget = Widget(showm, port=8000, encoding='webrtc')`
+
+time_sleep = 1000 if interactive else 1
+
+
+

If you want to use the widget in a Windows environment without the WSL +you need to use the asyncio version of the widget.

+
if platform.system() == 'Windows':
+
+    async def main():
+        widget.start()
+        await asyncio.sleep(time_sleep)
+        widget.stop()
+
+    loop = asyncio.get_event_loop()
+    loop.run_until_complete(main())
+else:
+    # Running the widget in a normal Python environment in Linux or MacOS
+    # we can use the normal version of the widget.
+    widget.start()
+    time.sleep(time_sleep)
+    widget.stop()
+
+window.record(showm.scene, size=window_size, out_path='viz_widget.png')
+
+
+viz widget
url: http://localhost:8000?iframe=1&encoding=mjpeg
+
+
+

Total running time of the script: (0 minutes 1.648 seconds)

+ +

Gallery generated by Sphinx-Gallery

+
+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ +
+ On this page +
+ +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/auto_examples/index.html b/v0.10.x/auto_examples/index.html new file mode 100644 index 000000000..13ec3c5ca --- /dev/null +++ b/v0.10.x/auto_examples/index.html @@ -0,0 +1,826 @@ + + + + + + + + Tutorials — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Tutorials#

+

How to use widgets, ui, actor and windows module. Below some examples and apps to go in details.

+
+

Introductory#

+

These tutorials show:

+
    +
  • How to combine a timer with an actor

  • +
  • How to slice data with the slicer actor

  • +
  • How to use the normals of your data.

  • +
+
+

Sphere Texture

+
Sphere Texture
+
+

Visualizing a glTF file

+
Visualizing a glTF file
+
+

FURY sphere Actor

+
FURY sphere Actor
+
+

Fury Cone Actor

+
Fury Cone Actor
+
+

Fury Arrow Actor

+
Fury Arrow Actor
+
+

Visualizing a glTF file

+
Visualizing a glTF file
+
+

Morphing Animation in a glTF

+
Morphing Animation in a glTF
+
+

Exporting scene as a glTF file

+
Exporting scene as a glTF file
+
+

Skeletal Animation in a glTF file

+
Skeletal Animation in a glTF file
+
+

Using a timer

+
Using a timer
+
+

Spiky Sphere

+
Spiky Sphere
+
+

Visualize surfaces

+
Visualize surfaces
+
+

Selecting multiple objects

+
Selecting multiple objects
+
+

Multithreading Example

+
Multithreading Example
+
+

Simple picking

+
Simple picking
+
+

Texture Sphere Animation

+
Texture Sphere Animation
+
+

Earth Coordinate Conversion

+
Earth Coordinate Conversion
+
+

Simple volume slicing

+
Simple volume slicing
+
+

Solar System Animation

+
Solar System Animation
+
+
+

Demos#

+

Below is a gallery of Demos. A bunch of apps powered by FURY.

+
+

Fury Markers

+
Fury Markers
+
+

Visualize Interdisciplinary map of the journals network

+
Visualize Interdisciplinary map of the journals network
+
+

Visualization of ROI Surface Rendered with Streamlines

+
Visualization of ROI Surface Rendered with Streamlines
+
+

Motion of a charged particle in a combined magnetic and electric field

+
Motion of a charged particle in a combined magnetic and electric field
+
+

Brownian motion

+
Brownian motion
+
+

Play a video in the 3D world

+
Play a video in the 3D world
+
+

Fine-tuning the OpenGL state using shader callbacks

+
Fine-tuning the OpenGL state using shader callbacks
+
+

Electromagnetic Wave Propagation Animation

+
Electromagnetic Wave Propagation Animation
+
+

Animated 2D functions

+
Animated 2D functions
+
+

Visualize bundles and metrics on bundles

+
Visualize bundles and metrics on bundles
+
+

Tesseract (Hypercube)

+
Tesseract (Hypercube)
+
+

Collisions of particles in a box

+
Collisions of particles in a box
+
+

Advanced interactive visualization

+
Advanced interactive visualization
+
+

Brain Fiber ODF Visualisation

+
Brain Fiber ODF Visualisation
+
+

Fractals

+
Fractals
+
+

Visualize Networks (Animated version)

+
Visualize Networks (Animated version)
+
+

Display Tensor Ellipsoids for DTI using tensor_slicer vs ellipsoid actor

+
Display Tensor Ellipsoids for DTI using tensor_slicer vs ellipsoid actor
+
+

Interactive PBR demo

+
Interactive PBR demo
+
+
+

User Interface Elements#

+

These tutorials show how to create user interfaces elements.

+
+

Simple Shapes

+
Simple Shapes
+
+

DrawPanel

+
DrawPanel
+
+

Card

+
Card
+
+

SpinBox UI

+
SpinBox UI
+
+

ComboBox

+
ComboBox
+
+

ListBox

+
ListBox
+
+

Using Layouts with different UI elements

+
Using Layouts with different UI elements
+
+

Sphere Color Control using Radio Buttons

+
Sphere Color Control using Radio Buttons
+
+

Buttons & Text

+
Buttons & Text
+
+

Card

+
Card
+
+

Cube & Slider Control

+
Cube & Slider Control
+
+

Figure and Color Control using Check boxes and Radio Buttons

+
Figure and Color Control using Check boxes and Radio Buttons
+
+

Tab UI

+
Tab UI
+
+

User Interfaces

+
User Interfaces
+
+
+

Animation#

+

These tutorials show:

+
    +
  • How to animate FURY actors.

  • +
  • How to use different interpolation methods in animations.

  • +
+
+

Keyframe animation introduction

+
Keyframe animation introduction
+
+

Timeline and setting keyframes

+
Timeline and setting keyframes
+
+

Keyframes Spline Interpolator

+
Keyframes Spline Interpolator
+
+

Keyframe animation

+
Keyframe animation
+
+

Keyframe animation

+
Keyframe animation
+
+

Keyframe Color Interpolators

+
Keyframe Color Interpolators
+
+

Arm Robot Animation

+
Arm Robot Animation
+
+

Keyframe hierarchical Animation

+
Keyframe hierarchical Animation
+
+

Bezier Interpolator

+
Bezier Interpolator
+
+

Keyframe animation: Camera and opacity

+
Keyframe animation: Camera and opacity
+
+

Making a custom interpolator

+
Making a custom interpolator
+
+
+

Shaders#

+

These tutorials show:

+
    +
  • How to use shaders in FURY actors.

  • +
  • How to create new user shaders and internal conventions.

  • +
+
+

Visualize SDF Actor

+
Visualize SDF Actor
+
+

Principled BRDF shader on spheres

+
Principled BRDF shader on spheres
+
+

Varying Color

+
Varying Color
+
+

Physically-Based Rendering (PBR) on spheres

+
Physically-Based Rendering (PBR) on spheres
+
+

SDF Impostors on Billboards

+
SDF Impostors on Billboards
+
+

Make a Cylinder using polygons vs SDF

+
Make a Cylinder using polygons vs SDF
+
+
+

Integrate Physics using pybullet#

+

These demos show how to use connect FURY with a physics engine library.

+
+

Ball Collision Simulation

+
Ball Collision Simulation
+
+

Domino Physics Simulation

+
Domino Physics Simulation
+
+

Chain Simulation

+
Chain Simulation
+
+

Brick Wall Simulation

+
Brick Wall Simulation
+
+

Wrecking Ball Simulation

+
Wrecking Ball Simulation
+
+
+

Streaming#

+

These tutorials show:

+
    +
  • How to create a simple streaming server and turn that available.

  • +
  • How to create a streaming server with user interaction.

  • +
  • How to create a streaming server using the Widget Object.

  • +
+
+

Streaming FURY with WebRTC/MJPEG using the Widget Object

+
Streaming FURY with WebRTC/MJPEG using the Widget Object
+
+

Streaming FURY with WebRTC/MJPEG

+
Streaming FURY with WebRTC/MJPEG
+
+

Streaming FURY with user interaction

+
Streaming FURY with user interaction
+
+
+ +

Gallery generated by Sphinx-Gallery

+
+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/auto_examples/sg_execution_times.html b/v0.10.x/auto_examples/sg_execution_times.html new file mode 100644 index 000000000..ab5ff43f5 --- /dev/null +++ b/v0.10.x/auto_examples/sg_execution_times.html @@ -0,0 +1,496 @@ + + + + + + + + Computation times — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Computation times#

+

00:00.000 total execution time for 0 files from auto_examples:

+
+ + + + + + + + + + + + + + + + + +

Example

Time

Mem (MB)

N/A

N/A

N/A

+
+
+ +
+ + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/blog.html b/v0.10.x/blog.html new file mode 100644 index 000000000..42cab3600 --- /dev/null +++ b/v0.10.x/blog.html @@ -0,0 +1,12898 @@ + + + + + + + All Posts — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +
+

+ + All + + Posts + +

+ + +
+

+ Google Summer of Code Final Work Product +

+
    +
  • + + + 25 August 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Name: Praneeth Shetty

+

+ +

Read more ...

+
+
+ +
+

+ Week 12 : Experimenting with ODFs implementation +

+
    +
  • + + + 24 August 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Tania Castillo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

There were different issues I needed to address for the ODF implementation. Even though I could not solve any of them completely, I did check each of the issues and made some progress. All the work in progress is being recorded in the following branch SH-for-ODF-impl, which when ready will be associated with a well-structured PR.

+

+ +

Read more ...

+
+
+ +
+

+ Google Summer of Code Final Work Product +

+
    +
  • + + + 24 August 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Tania Castillo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Name: Tania Castillo

+

+ +

Read more ...

+
+
+ +
+

+ Week 12: Now That is (almost) a Wrap! +

+ +

Hello everyone, it’s time for another GSoC blogpost! Today, I am going to talk about some minor details I worked on last week on my +project.

+

+ +

Read more ...

+
+
+ +
+

+ Google Summer of Code Final Work Product +

+ +

Name: João Victor Dell Agli Floriano

+

+ +

Read more ...

+
+
+ +
+

+ Week 12: FileDialog Quest Begins! +

+
    +
  • + + + 19 August 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

During this week, I initiated my work on the FileDialog PR, which had been started by Soham. The initial version of the FileDialog can be found at #294. To start, I focused on rebasing the PR. Since this PR was based on an older version, there were some updates to the overall UI structure that needed to be addressed for compatibility. While handling this, I identified a set of issues that I documented in the current PR #832. These mainly revolved around:

+

+ +

Read more ...

+
+
+ +
+

+ Week 11 : Adjusting ODF implementation and looking for solutions on issues found +

+
    +
  • + + + 16 August 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Tania Castillo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

I continued to experiment with the ODF glyph implementation. Thanks to one of my mentors I figured out how to get the missing data corresponding to the SH coefficients \(a^l_m\) part of the function \(f(\theta, \phi)\) described here. I also was told to make sure to implement the correct SH basis since there are different definitions from the literature, I have to focus now in the one proposed by Descoteaux, described in this paper, which is labeled in dipy as descoteaux07. To do this I had to make a small adjustment to the base implementation that I took as a reference, from which I obtained a first result using SH of order 4.

+

+ +

Read more ...

+
+
+ +
+

+ Week 11: A Refactor is Sometimes Needed +

+ +

Hello everyone, it’s time for another weekly blogpost! Today I am going to share some updates on the API refactoring +I was working on with my mentors.

+

+ +

Read more ...

+
+
+ +
+

+ Week 11: Bye Bye SpinBox +

+
    +
  • + + + 12 August 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Building upon the progress of the previous week, a major milestone was reached with the merging of PR #830. This PR added essential “getters” and “setters” for the new features of TextBlock, making it easier to handle changes. This, in turn, facilitated the integration of SpinBoxUI with the updated TextBlock.

+

+ +

Read more ...

+
+
+ +
+

+ Week 10 : Start of SH implementation experiments +

+
    +
  • + + + 08 August 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Tania Castillo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

I started formally working on SH implementation. I was told to start first doing a simple program where I can modify in real-time the order \(l\) and degree \(m\), parameters corresponding to the Spherical Harmonics function \(Y^m_l(\theta,\phi)=\), based on previous work. That is just one part of the final ODF calculation, but here is what a first experimental script looks like.

+

+ +

Read more ...

+
+
+ +
+

+ Week 10: Ready for Review! +

+ +

Hello everyone, it’s time for another weekly blogpost!

+

+ +

Read more ...

+
+
+ +
+

+ Week 10: Its time for a Spin-Box! +

+
    +
  • + + + 05 August 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week, my focus shifted to the SpinBoxUI after wrapping up work on TextBlock2D. SpinBoxUI is a component that allows users to select a value by spinning through a range. To ensure a smooth transition, I made adjustments in SpinBoxUI to align it with the recent updates in TextBlock2D. To make things even clearer and more user-friendly, I initiated a continuous code improvement process. I introduced setters and getters that enable easier customization of TextBlock2D’s new features, such as auto_font_scale and dynamic_bbox. These tools simplify the process of adjusting these settings, and you can see the ongoing changes in pull request #830.

+

+ +

Read more ...

+
+
+ +
+

+ Week 9: Tutorial done and polishing DTI uncertainty +

+
    +
  • + + + 31 July 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Tania Castillo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

I addressed the comments from the tutorial of PR #818 related to how to display specific visualizations I wanted to make. I was suggested to use ShowManager to handle the zoom of the scene and also to use GridUI to display several actors at the same time for a visual quality comparison of the tensors. Below are some images generated for the tutorial that is almost done.

+

+ +

Read more ...

+
+
+ +
+

+ Week 9: It is Polishing Time! +

+ +

Hello everyone, it’s time for another weekly blogpost! Today, I am going to update you on my project’s latest changes.

+

+ +

Read more ...

+
+
+ +
+

+ Week 9: TextBlock2D is Finally Merged! +

+
    +
  • + + + 29 July 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Continuing from the previous week, it seemed like we were almost done with the TextBlock2D, but there remained a final task of addressing conflicting issues. Being a core part of the UI, TextBlock2D had a few compatibility problems with certain other UI elements.

+

+ +

Read more ...

+
+
+ +
+

+ Week 8: Working on Ellipsoid Tutorial and exploring SH +

+
    +
  • + + + 25 July 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Tania Castillo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

I mainly worked on the ellipsoid actor tutorial, as PR #791 is finally merged, so I was able to complete the tutorial by adding my implementation. In addition, during the weekly meeting, I received a good overview of the next issue I will be working on, which is using raymarching SDFs to display spherical harmonics (SH) for visualizing ODF glyphs for DTI. I got several ideas and resources which I can start experimenting with, such as Shadertoy and some base implementations from other FURY contributors. The main drawback when creating these objects is the amount of data required to create them, because depending on the SH order, the number of parameters that the function receives may vary, also unlike the tensors, which are represented only with a 3x3 matrix, here we could have more than 9 values associated with a single glyph, so passing the information from python to the shaders is not so trivial, besides requiring more resources as there is more information that needs to be processed. Some ideas I received were using matrixes instead of vectors, using templating, or even using texture to pass the data. I started to explore these options further, as well as to review in more detail the existing implementations of SH with raymarching, in order to understand them better.

+

+ +

Read more ...

+
+
+ +
+

+ Week 8: The Birth of a Versatile API +

+ +

Hello everyone, it’s time for another weekly blogpost! Today, I am going to tell you all about how is the KDE API development going, and +to show you the potential this holds for the future!

+

+ +

Read more ...

+
+
+ +
+

+ Week 8: Another week with TextBlockUI +

+
    +
  • + + + 22 July 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week, I delved deeper into the TextBlock2D Bounding Box PR to address the challenges with tests and offsetting issues. In a pair programming session with my mentor, we discovered that the offsetting background problem stemmed from the dynamic nature of the bounding box. The issue arose when the RingSlider2D component began with an initial text size larger than the current text, which changed as the value was adjusted between 0-100%. This resulted in problems with offsetting and shrinking the bounding box. To resolve this, we decided to make the dynamic bounding box an optional feature.

+

+ +

Read more ...

+
+
+ +
+

+ Week 7: Experimentation Done +

+ +

Hello everyone, welcome to another weekly blogpost! Let’s talk about the current status of my project (spoiler: it is beautiful).

+

+ +

Read more ...

+
+
+ +
+

+ Week 7: Adjustments on the Uncertainty Cones visualization +

+
    +
  • + + + 17 July 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Tania Castillo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

I was told to refactor some parts of the uncertainty PR, since I was relying too much on dipy functions which is not good because it makes maintenance more difficult as dipy requires FURY for some functionalities. So I did some adjustments on the uncertainty function parameters and the corresponding tests, hopefully I managed to get with the most appropriate definition but I need to receive a first feedback to see how much I have to adjust the implementation. As I had to delete some relevant code lines inside the uncertainty calculation which consisted of preprocessing the data in order to define the necessary variables for the uncertainty formula, I was also suggested to make a tutorial of this new feature, so I can explain in detail how to obtain and adjust the necessary information, before passing it to the actor, and in general how and what is the purpose of this new function.

+

+ +

Read more ...

+
+
+ +
+

+ Week 7: Sowing the seeds for TreeUI +

+
    +
  • + + + 15 July 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week, I focused on completing the TextBlock2D Bounding Box feature. However, the tests were failing due to automatic background resizing based on content and improper text actor alignment during setup. I encountered difficulties while positioning the text, which caused the text to appear offset and led to test failures.

+

+ +

Read more ...

+
+
+ +
+

+ Week 6: Things are Starting to Build Up +

+ +

Hello everyone, time for a other weekly blogpost! Today, I will show you my current progress on my project and latest activities.

+

+ +

Read more ...

+
+
+ +
+

+ Week 6: First draft of the Ellipsoid tutorial +

+
    +
  • + + + 10 July 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Tania Castillo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

#PR 818: Tutorial on using ellipsoid actor to visualize tensor ellipsoids for DTI

+

+ +

Read more ...

+
+
+ +
+

+ Week 6: BoundingBox for TextBlock2D! +

+
    +
  • + + + 08 July 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week, I worked on improving the TextBlock2D component in the UI system. I started from scratch to address alignment and scaling issues. When resizing the TextBlock2D, the text alignment and justification with the background rectangle were inconsistent. To resolve this, I introduced a new “boundingbox” property that calculates the text bounding box based on its content. Additionally, I separated the scaling mode from the resizing action with the new “auto_font_scale” property, enabling automatic font scaling according to the bounding box. This will provide better alignment, justified text, and smoother font scaling for the TextBlock2D component. Try it out at PR #803.

+

+ +

Read more ...

+
+
+ +
+

+ Week 5: Preparing the data for the Ellipsoid tutorial +

+
    +
  • + + + 03 July 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Tania Castillo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

During the weekly meeting with my mentors, there was a small discussion over the naming of the actor and its usage. On the one hand, although the purpose of the actor is to visualize diffusion tensor ellipsoids, the idea is that it can also be used for any other type of visualization that requires the use of ellipsoids, so in the end, we decided to keep the name ellipsoid as it is more generic. On the other hand, as there is already an actor made for the purpose of tensor visualization, namely tensor_slicer, it might not be obvious how and why one would use this new ellipsoid actor for this purpose, thus it was proposed to make a tutorial that can clarify this. The main difference between both actors relies on the quality and the amount of data that can be displayed, so the idea is to show the difference between both alternatives so the user can choose which one to use depending on their needs. To prepare the tutorial the first step was to add the data I will use on fury-data so I can then fetch and load the datasets I need to work on the tutorial.

+

+ +

Read more ...

+
+
+ +
+

+ Week 5: All Roads Lead to Rome +

+ +

Hello everyone, time for another weekly blogpost! Today, we will talk about taking different paths to reach your objective.

+

+ +

Read more ...

+
+
+ +
+

+ Week 5: Trying out PRs and Planning Ahead +

+
    +
  • + + + 01 July 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Due to ongoing exams, my productivity was limited this week. However, I managed to find some time to explore and review a few PRs submitted by contributors:

+

+ +

Read more ...

+
+
+ +
+

+ Week 4: First draft of the DTI uncertainty visualization +

+
    +
  • + + + 27 June 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Tania Castillo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

#PR 810: DTI uncertainty visualization

+

+ +

Read more ...

+
+
+ +
+

+ Week 4: Nothing is Ever Lost +

+ +

Welcome again to another weekly blogpost! Today, let’s talk about the importance of guidance throughout a project.

+

+ +

Read more ...

+
+
+ +
+

+ Week 4: Exam Preparations and Reviewing +

+
    +
  • + + + 24 June 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week, amidst end-semester exams, I managed to accomplish a few notable tasks. Let’s dive into the highlights:

+

+ +

Read more ...

+
+
+ +
+

+ Week 3: Working on uncertainty and details of the first PR +

+
    +
  • + + + 19 June 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Tania Castillo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

I made some adjustments to the ellipsoid actor definition, now called tensor. This was something discussed in the weekly meeting as the coming changes are related to this actor, the idea now is to have a tensor actor that allows choosing between displaying the tensor ellipsoids or the uncertainty cones (later on). I also worked on the uncertainty calculation, and the cone SDF for the visualization, so I plan to do a WIP PR next to start getting feedback on this new addition.

+

+ +

Read more ...

+
+
+ +
+

+ Week 3: Watch Your Expectations +

+ +

Hello everyone, it’s time for another weekly blogpost! This week, +I will talk about how you should watch your expectations when working with any project.

+

+ +

Read more ...

+
+
+ +
+

+ Week 3: Resolving Combobox Icon Flaw and TextBox Justification +

+
    +
  • + + + 17 June 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week, I tackled the ComboBox2D icon flaw, which was addressed using Pull Request (PR) #576. The problem arose when we added a ComboBox2D to the TabUI. The TabUI would propagate the set_visibility = true for all its child elements, causing the combobox to appear on the screen without the icon change. To fix this issue, PR #768 updated the set_visibility method of the UI class, ensuring that the icon change was applied correctly.

+

+ +

Read more ...

+
+
+ +
+

+ Week 2: The Importance of (good) Documentation +

+ +

Hello everybody, welcome to the week 2 of this project! I must admit I thought this would be simpler than it is currently being, but I forgot that when it comes to dealing with computer graphics’ applications, things never are. Below, some updates on what I have been up to for this past week.

+

+ +

Read more ...

+
+
+ +
+

+ Week 2: Making adjustments to the Ellipsoid Actor +

+
    +
  • + + + 12 June 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Tania Castillo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

I made some minor adjustments to the last PR I submitted. Last time it was a draft since I was waiting for the weekly meeting to know how to proceed, but now it is ready. I am waiting for the review so I can make the necessary corrections and adjustments to merge this first PR soon.

+

+ +

Read more ...

+
+
+ +
+

+ Week 2: Tackling Text Justification and Icon Flaw Issues +

+
    +
  • + + + 11 June 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week, I continued tweaking the text justification PR #790 and encountered a new issue when combining both justification and vertical_justification. The problem arose because the vertical_justification did not take into account the applied justification, resulting in unexpected behavior. I focused on resolving this issue by ensuring that both justifications work together correctly. Additionally, during the weekly meeting, we discussed the problem and decided to introduce new properties such as boundaries and padding to enhance the functionality of the text justification feature.

+

+ +

Read more ...

+
+
+ +
+

+ Week 1: Ellipsoid actor implemented with SDF +

+
    +
  • + + + 05 June 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Tania Castillo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

PR #791: Ellipsoid actor implemented with SDF

+

+ +

Read more ...

+
+
+ +
+

+ The FBO Saga - Week 1 +

+ +

As mentioned in the last week’s blogpost, the goal for that week was to investigate VTK’s Framebuffer Object framework. +An update on that is that indeed, VTK has one more low-level working FBO class that can be used inside FURY, however, +they come with some issues that I will explain further below.

+

+ +

Read more ...

+
+
+ +
+

+ Week 1: Working with SpinBox and TextBox Enhancements +

+
    +
  • + + + 03 June 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week, my focus was on reviewing pull requests (PRs) and issues related to the user interface (UI) of the project. I meticulously went through each PR and issue, identifying those specifically associated with UI improvements. To streamline the process, I categorized them accordingly under the UI category. One of the key tasks was PR #499, which involved the implementation of SpinBoxUI. After rebasing the PR, I identified an alignment issue with the textbox component.

+

+ +

Read more ...

+
+
+ +
+

+ Week 0: Community Bounding Period +

+
    +
  • + + + 02 June 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hello All!

+

+ +

Read more ...

+
+
+ +
+

+ Week 0: Community Bounding Period +

+
    +
  • + + + 02 June 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Tania Castillo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hello everyone, my name is Tania Castillo, I am close to finishing my degree in Computer Science and I think this is a great opportunity to put my learning and skills into practice. I will be working with FURY on improving the visualization of DTI tensors and HARDI ODFs glyphs by using well-known techniques in computer graphics.

+

+ +

Read more ...

+
+
+ +
+

+ The Beginning of Everything - Week 0 +

+ +

Hello everyone, welcome to the beginning of my journey through GSoC 2023! I would like to thank everyone involved for the opportunity provided, it is an honour to be working side by side with professionals and so many experienced people from around the world.

+

+ +

Read more ...

+
+
+ +
+

+ FURY 0.9.0 Released +

+
    +
  • + + + 15 April 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Serge Koudoro + + + +
  • + + + + +
  • + + + Category: + + + + + release + + + +
  • + + +
  • + + + + Tag: + + + + + fury + + + +
  • + + +
    +
+

The FURY project is happy to announce the release of FURY 0.9.0! +FURY is a free and open source software library for scientific visualization and 3D animations.

+

+ +

Read more ...

+
+
+ +
+

+ Contribute to FURY via Google Summer of Code 2023 +

+
    +
  • + + + 01 February 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Serge Koudoro + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

FURY is participating in the Google Summer of Code 2023 under the umbrella of the Python Software Foundation.

+

+ +

Read more ...

+
+
+ +
+

+ Google Summer of Code Final Work Product +

+
    +
  • + + + 29 January 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Mohamed Abouagour + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Name: Mohamed Abouagour

+

+ +

Read more ...

+
+
+ +
+

+ Google Summer of Code Final Work Product +

+
    +
  • + + + 29 January 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Shivam Anand + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Name: Shivam Anand

+

+ +

Read more ...

+
+
+ +
+

+ Google Summer of Code Final Work Product +

+
    +
  • + + + 24 January 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Name: Praneeth Shetty

+

+ +

Read more ...

+
+
+ +
+

+ Week 14: Keyframes animation is now a bit easier in FURY +

+
    +
  • + + + 28 September 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Mohamed Abouagour + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Separated the Timeline into a Timeline and an Animation. So, instead of having the Timeline do everything. It’s now more like doing animations in Blender and other 3D editing software where the timeline handles the playback of several animations #694.

+

+ +

Read more ...

+
+
+ +
+

+ Week 14 - Morphing is here! +

+
    +
  • + + + 28 September 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Shivam Anand + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week, I started with multiple actor support in skinning and managed to do it +successfully. Here’s the preview using the BrainStem model.

+

+ +

Read more ...

+
+
+ +
+

+ Week 16 - Working with Rotations! +

+
    +
  • + + + 21 September 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Last week my mentors noticed that each DrawShape has its individual rotation_slider which increases redundancy and complexity in setting its visibility on and off. Instead, they suggested moving the rotation_slider to DrawPanel and keeping a common slider for all the shapes.

+

+ +

Read more ...

+
+
+ +
+

+ Week 13: Keyframes animation is now a bit easier in FURY +

+
    +
  • + + + 20 September 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Mohamed Abouagour + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Added the ability to have the ShowManager stored inside the Timeline. That way the user does not have to update and render the animations because it will be done internally.

+

+ +

Read more ...

+
+
+ +
+

+ Week 13 - Multi-bone skeletal animation support +

+
    +
  • + + + 15 September 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Shivam Anand + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week I fixed all the issues with skeletal animations, and we got to see our first render of skeletal animation :).

+

+ +

Read more ...

+
+
+ +
+

+ Week 15 - Highlighting DrawShapes +

+
    +
  • + + + 14 September 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week I started with highlighting the shapes. As discussed earlier, I had two ways, but while implementing them, I found out both ways aren’t that good to continue with. +The first way in which we thought of creating the scaled shapes in the background had an issue with the stacking. The border(blue rectangle) and the shape(grey rectangle) both seem to look like different shapes just grouped together as shown below.

+

+ +

Read more ...

+
+
+ +
+

+ Week 12 - Adding skeleton as actors and fix global transformation +

+
    +
  • + + + 08 September 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Shivam Anand + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

I started this week by fixing the segmentation fault for the skinning test. I could not fix this as of now.

+

+ +

Read more ...

+
+
+ +
+

+ Week 14 - Updating DrawPanel architecture +

+
    +
  • + + + 07 September 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week I continued updating the DrawShape and DrawPanel.

+

+ +

Read more ...

+
+
+ +
+

+ Week 12: Adding new tutorials +

+
    +
  • + + + 07 September 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Mohamed Abouagour + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Restructured tutorials to be more readable and more focused on a specific topic.

+

+ +

Read more ...

+
+
+ +
+

+ Week 13 - Separating tests and fixing bugs +

+
    +
  • + + + 31 August 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week I managed to fix the translation issue in PR #653. This was happening because of the calculation error while repositioning the shapes. Now it works as intended.

+

+ +

Read more ...

+
+
+ +
+

+ Week 11 - Multiple transformations support and adding tests +

+
    +
  • + + + 31 August 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Shivam Anand + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

As decided last week, I added support for multiple animations at the same timestamp. But this didn’t solve the animation problems of RiggedSimple model.

+

+ +

Read more ...

+
+
+ +
+

+ Week 11: Improving tutorials a little +

+
    +
  • + + + 30 August 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Mohamed Abouagour + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Fixed some issues in the hierarchical order animation support PR that we discussed during last week’s meeting (mostly naming issues).

+

+ +

Read more ...

+
+
+ +
+

+ Week 10 - Multi-node skinning support +

+
    +
  • + + + 25 August 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Shivam Anand + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

As we figured out that the SimpleSkin model is not animated as intended. This week I started working with that model; +I figured out that we need to apply the InverseBindMatrix to each timer callback. I had a hard time figuring out what inverse bind matrix actually does. +Here’s a good blog that answers that.

+

+ +

Read more ...

+
+
+ +
+

+ Week 12 - Fixing translating issues and updating tests +

+
    +
  • + + + 24 August 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

I started with updating the tests for PR #623 as some of the tests weren’t covering all the aspects in the code. +Previously I was just creating the DrawShape and adding it to the scene but now I had to analyze the scene to see whether they were properly added or not.

+

+ +

Read more ...

+
+
+ +
+

+ Week 10: Supporting hierarchical animating +

+
    +
  • + + + 23 August 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Mohamed Abouagour + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Implemented hierarchical order support for animations using matrices in this PR.

+

+ +

Read more ...

+
+
+ +
+

+ Week 9 - First working skeletal animation prototype +

+
    +
  • + + + 17 August 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Shivam Anand + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week I had the first working example of skeletal animation ready. I was able to render the SimpleSkin model. Here’s a quick preview:

+

+ +

Read more ...

+
+
+ +
+

+ Week 11 - Creating a base for Freehand Drawing +

+
    +
  • + + + 17 August 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week I tried to imitate the working of vtkImageTracer. Previously, I had created a small prototype for freehand drawing by adding points at the mouse position (which you can check out here). As mentioned, there were some drawback of this method. +So to overcome these issues, I tried combining both methods. Considering points using the previous method and instead of adding points I tried creating lines between them which looks promising. Below you can see a demo.

+

+ +

Read more ...

+
+
+ +
+

+ Week 9: Animating primitives of the same actor +

+
    +
  • + + + 16 August 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Mohamed Abouagour + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Made two tutorials in this PR that show two approaches on how to animate primitives of the same FURY actor using the Timeline.

+

+ +

Read more ...

+
+
+ +
+

+ Week 8 - Fixing animation bugs +

+
    +
  • + + + 10 August 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Shivam Anand + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week I had to fix the transformation issue in glTF animation. As discussed in the last meeting, I disabled vertex transformation and applied the transformation after the actor was formed.

+

+ +

Read more ...

+
+
+ +
+

+ Week 10 - Understanding Codes and Playing with Animation +

+
    +
  • + + + 10 August 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

I started working on the PR #645 created last week and tested a few more corner cases such as What happens if the maximum value is exceeded?? What if we give a value less than the minimum value range?? +Most of these worked as intended.

+

+ +

Read more ...

+
+
+ +
+

+ Week 8: Back to the shader-based version of the Timeline +

+
    +
  • + + + 09 August 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Mohamed Abouagour + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

First, I made some modifications to the main animation PR. Then as Filipi requested, I integrated the vertex shader that I was implementing a few weeks ago to work with the new improved version of the Timeline.

+

+ +

Read more ...

+
+
+ +
+

+ Week 9 - Grouping and Transforming Shapes +

+
    +
  • + + + 03 August 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

I started this week by creating a quick PR #645 for the UI sliders. The sliders raised ZeroDivsionError when the min and max values were the same. To solve this, I handled the case where the value_range becomes zero and then manually set the handle position to zero.

+

+ +

Read more ...

+
+
+ +
+

+ Week 7: Billboard spheres and implementing interpolators using closures +

+
    +
  • + + + 01 August 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Mohamed Abouagour + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Restructured the keyframe animation interpolators using closures to be functions instead of classes #647. Now it is easier to implement new interpolators with the help of the functions existing in fury/animation/helpers.py. Also, now unit tests can be added for the latter functions.

+

+ +

Read more ...

+
+
+ +
+

+ Week 7 - Fixing bugs in animations +

+
    +
  • + + + 01 August 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Shivam Anand + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week I started with implementing scaling to the animation example.

+

+ +

Read more ...

+
+
+ +
+

+ Week 8 - Working on the polyline feature +

+
    +
  • + + + 27 July 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week I started working on the polyline feature. After a lot of investigating and trying out different things, I found a way to call the dragging event manually without any prior click event. VTK actually captures the mouse movement using the MouseMoveEvent. This event is then modified by FURY to only be called after the click event. So I added a new callback to track the mouse movement and set the current canvas as an active prop because it is required to capture the drag event happening on it.

+

+ +

Read more ...

+
+
+ +
+

+ Week 6: Fixing the Timeline issues and equipping it with more features +

+
    +
  • + + + 25 July 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Mohamed Abouagour + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Improved the PlaybackPanel by adding speed control and the ability to loop the animation. Also, fixed the lagging issue of play and pause buttons and composed them into a single play/pause button.

+

+ +

Read more ...

+
+
+ +
+

+ Week 6 - Extracting the animation data +

+
    +
  • + + + 25 July 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Shivam Anand + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week, it was all about reading docs and extracting the animation data from buffers.

+

+ +

Read more ...

+
+
+ +
+

+ Week 7 - Working on Rotation PR and Trying Freehand Drawing +

+
    +
  • + + + 20 July 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

I continued PR #623 and fixed the displacement of the shape from its original position when applying rotation. This was happening because most of the calculations resulted in float values, but as the pixel position were integers we had to explicitly convert these values into int. This conversion rounded off the values and as we call this function continuously, each time the round-off would happen, the shape would get displaced.

+

+ +

Read more ...

+
+
+ +
+

+ Week 5: Slerp implementation, documenting the Timeline, and adding unit tests +

+
    +
  • + + + 19 July 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Mohamed Abouagour + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Implemented Slerp (spherical linear interpolation) for rotation keyframes.

+

+ +

Read more ...

+
+
+ +
+

+ Week 5 - Creating PR for glTF exporter and fixing the loader +

+
    +
  • + + + 19 July 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Shivam Anand + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Finalised the glTF export PR #630., adding tutorial, docs, and tests for all functions.

+

+ +

Read more ...

+
+
+ +
+

+ Week 6 - Supporting Rotation of the Shapes from the Center +

+
    +
  • + + + 13 July 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week I started implementing a new feature to rotate the shapes from the center using RingSlider2D. I already had a rotate function that rotates the shape around its pivot vertex, so I updated it to support rotation from the center.

+

+ +

Read more ...

+
+
+ +
+

+ Week 4 - Finalizing glTF loader +

+
    +
  • + + + 12 July 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Shivam Anand + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week I had to travel back to my college since the summer vacations have ended. +I had a coding session with Serge this week, we modified the exporter function and looked at some bugs I faced.

+

+ +

Read more ...

+
+
+ +
+

+ Week 4: Camera animation, interpolation in GLSL, and a single Timeline! +

+
    +
  • + + + 11 July 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Mohamed Abouagour + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Managed to implement a single Timeline using the Container class. So, instead of having two classes: Timeline and CompositeTimeline, now the Timeline can have multiple Timeline objects and controls them as in the code below.

+

+ +

Read more ...

+
+
+ +
+

+ Week 5 - Working on new features +

+
    +
  • + + + 06 July 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week I tried to create a base for some upcoming new features. +The first thing I updated was the Properties panel which I prototyped in Week 3. +So previously, it was just displaying the properties but now after the update, it is able to modify the properties(such as color, position, and rotation) too. This was a quick change to test the callbacks.

+

+ +

Read more ...

+
+
+ +
+

+ Week 3: Redesigning the API, Implementing cubic Bezier Interpolator, and making progress on the GPU side! +

+
    +
  • + + + 04 July 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Mohamed Abouagour + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Redesigned the keyframe animations API to optimize having a lot of timelines by composing them into a parent Timeline called CompositeTimeline while maintaining playing individual timelines separately.

+

+ +

Read more ...

+
+
+ +
+

+ Week 3 - Fixing fetcher, adding tests and docs +

+
    +
  • + + + 04 July 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Shivam Anand + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

The first task for this week was to fix the glTF fetcher. We noticed that while running tests it reaches the API limit. So we decided to use a JSON file that contains the download URLs for all models.

+

+ +

Read more ...

+
+
+ +
+

+ Week 4 - Fixing the Clamping Issue +

+
    +
  • + + + 29 June 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Phew!! This week was a tedious week for me as parallelly my End-Sem exams also started. So as usual I started from where I left off last week, The Clamping Issue. As per the discussion with the mentors, we decided to use the AABB bounding box method to calculate the bounding box around the shape and then reposition or transform respectively, as now we had a fixed reference point. So after doing some calculations with the mouse positions and the bounding box points at last, I was able to clamp all the shapes successfully.

+

+ +

Read more ...

+
+
+ +
+

+ Week 2 - Improving Fetcher and Exporting glTF +

+
    +
  • + + + 29 June 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Shivam Anand + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week I worked primarily on the glTF fetcher and exporting scenes to a glTF file. I added tests and docstrings for all functions. I modified the fetch_gltf function to return the downloaded files. As we planned, the PR for the glTF fetcher was merged this week.

+

+ +

Read more ...

+
+
+ +
+

+ Week 2: Implementing non-linear and color interpolators +

+
    +
  • + + + 28 June 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Mohamed Abouagour + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Implemented some other general interpolators such as n-th degree spline and cubic spline interpolators. Also implemented HSV and LAB color interpolators.

+

+ +

Read more ...

+
+
+ +
+

+ Week 3 - Dealing with Problems +

+
    +
  • + + + 22 June 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week was full of researching, playing around with things, prototyping ideas, etc. +I started with last week’s clamping issue and managed to solve this issue while drawing shapes by clipping the mouse position according to canvas size, but it didn’t solve the problem with translating these shapes. I tried solving this using various approaches, but if one thing would get fixed, other things would raise a new error.

+

+ +

Read more ...

+
+
+ +
+

+ Week 1 - A Basic glTF Importer +

+
    +
  • + + + 20 June 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Shivam Anand + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

In the community bonding period I met with my mentor Serge Koudoro, along with other mentors in FURY and gsoc contributors. +We discussed about my project and set up project timeline on github projects section. As my project (glTF Integration) +and Keyframe animations were related so we discussed on that too.

+

+ +

Read more ...

+
+
+ +
+

+ Week 1: Implementing a basic Keyframe animation API +

+
    +
  • + + + 19 June 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Mohamed Abouagour + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

During the community bonding period, we had weekly meetings in which I got to know the mentors better and bonded with Shivam and Praneeth, my fellow contributors. +We talked about the importance of open-source contribution and discussed scientific visualization, how important it is and how it differs from game engines despite having some similarities. +We also discussed how important the code review is and how to do a proper code review.

+

+ +

Read more ...

+
+
+ +
+

+ Week 2 - Improving DrawPanel UI +

+
    +
  • + + + 15 June 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week I had to refactor and make my code cleaner along with some bug fixing, I started by adding tests and tutorials so that my changes could be tested by everyone. Then I separated the mode for selection so that it would be easy to select an individual element and work along with it. Once the selection mode was complete I started with the deletion of the elements.

+

+ +

Read more ...

+
+
+ +
+

+ Week 1 - Laying the Foundation of DrawPanel UI +

+
    +
  • + + + 08 June 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week we started with our first technical meeting in which the weekly tasks were assigned. So I had to start with some background or canvas and draw a line using mouse clicks.

+

+ +

Read more ...

+
+
+ +
+

+ Pre-GSoC Journey +

+
    +
  • + + + 25 May 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hello Guys!! I am Praneeth Shetty, currently pursuing Bachelor of Engineering in Computer Engineering, and here is my journey from where I started to the selection into GSoC22.

+

+ +

Read more ...

+
+
+ +
+

+ My Journey to GSoC 2022 +

+
    +
  • + + + 24 May 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Shivam Sahu + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hi! I’m Shivam, currently pursuing my bachelor’s (expected 2024) in Production and Industrial engineering from the Indian Institute of Technology (IIT) Roorkee.

+

+ +

Read more ...

+
+
+ +
+

+ My journey till getting accepted into GSoC22 +

+
    +
  • + + + 23 May 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Mohamed Abouagour + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

My name is Mohamed and I’m from Egypt. I am pursuing a Bachelor of Engineering in Computer Engineering and Automatic Control (expected: 2023), Tanta University, Egypt.

+

+ +

Read more ...

+
+
+ +
+

+ Contribute to FURY via Google Summer of Code 2022 +

+
    +
  • + + + 01 February 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Serge Koudoro + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

FURY is participating in the Google Summer of Code 2022 under the umbrella of the Python Software Foundation.

+

+ +

Read more ...

+
+
+ +
+

+ FURY 0.8.0 Released +

+
    +
  • + + + 31 January 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Serge Koudoro + + + +
  • + + + + +
  • + + + Category: + + + + + release + + + +
  • + + +
  • + + + + Tag: + + + + + fury + + + +
  • + + +
    +
+

The FURY project is happy to announce the release of FURY 0.8.0! +FURY is a free and open source software library for scientific visualization and 3D animations.

+

+ +

Read more ...

+
+
+ +
+

+ Google Summer of Code Final Work Product +

+
    +
  • + + + 23 August 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Antriksh Misri + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Name: Antriksh Misri

+

+ +

Read more ...

+
+
+ +
+

+ Google Summer of Code Final Work Product +

+
    +
  • + + + 23 August 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Sajag Swami + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Name: Sajag Swami

+

+ +

Read more ...

+
+
+ +
+

+ Google Summer of Code 2021 - Final Report - Bruno Messias +

+
    +
  • + + + 23 August 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Bruno Messias + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

We have changed some points of my project in the first meeting. +Specifically, we focused the efforts into developing a streaming system +using the WebRTC protocol that could be used in more generic scenarios +than just the network visualization. In addition to that, we have opted +to develop the network visualization for fury as a separated repository +and package available here. The +name Helios was selected for this new network visualization system based +on the Fury rendering pipeline.

+

+ +

Read more ...

+
+
+ +
+

+ Week #11: Removing the flickering effect +

+
    +
  • + + + 16 August 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Bruno Messias + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

PR fury-gl/fury#489:

+

+ +

Read more ...

+
+
+ +
+

+ Week #11: Finalizing open Pull Requests +

+
    +
  • + + + 16 August 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Antriksh Misri + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Below are the tasks that I worked on:

+

+ +

Read more ...

+
+
+ +
+

+ Tenth coding week! +

+
    +
  • + + + 16 August 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Sajag Swami + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Welcome to the eleventh weekly check-in. I’ll be sharing my progress for the tenth week of coding.

+

+ +

Read more ...

+
+
+ +
+

+ Week#10: Accordion UI, Support for sprite sheet animations +

+
    +
  • + + + 09 August 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Antriksh Misri + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Below are the tasks that I worked on:

+

+ +

Read more ...

+
+
+ +
+

+ Week #10: SDF Fonts +

+
    +
  • + + + 09 August 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Bruno Messias + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

PR fury-gl/helios#22 +: Helios Documentation +Improvements.

+

+ +

Read more ...

+
+
+ +
+

+ Ninth coding week! +

+
    +
  • + + + 09 August 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Sajag Swami + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Welcome to the tenth weekly check-in. I’ll be sharing my progress for the ninth week of coding.

+

+ +

Read more ...

+
+
+ +
+

+ FURY 0.7.0 Released +

+
    +
  • + + + 03 August 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Serge Koudoro + + + +
  • + + + + +
  • + + + Category: + + + + + release + + + +
  • + + +
  • + + + + Tag: + + + + + fury + + + +
  • + + +
    +
+

The FURY project is happy to announce the release of FURY 0.7.1! +FURY is a free and open source software library for scientific visualization and 3D animations.

+

+ +

Read more ...

+
+
+ +
+

+ Week #9: More Layouts! +

+
    +
  • + + + 02 August 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Antriksh Misri + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Below are the tasks that I worked on:

+

+ +

Read more ...

+
+
+ +
+

+ Week #09: Sphinx custom summary +

+
    +
  • + + + 02 August 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Bruno Messias + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

PR fury-gl/helios#22 +: Helios Documentation +Improvements. +I’ve spent some time studying sphinx in order to discover how I could create a +custom summary inside of a template module.

+

+ +

Read more ...

+
+
+ +
+

+ Eighth coding week! +

+
    +
  • + + + 02 August 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Sajag Swami + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Welcome to the ninth weekly check-in. I’ll be sharing my progress for the eighth week of coding.

+

+ +

Read more ...

+
+
+ +
+

+ Weekly Check-In #8 +

+
    +
  • + + + 26 July 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Bruno Messias + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

PR fury-gl/helios#18 (merged): Helios Documentation/ +I’ve been working on Helios documentation. Now it’s available +online at https://fury-gl.github.io/helios-website image1

+

+ +

Read more ...

+
+
+ +
+

+ Week #8: Code Cleanup, Finishing up open PRs, Continuing work on Tree2D +

+
    +
  • + + + 26 July 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Antriksh Misri + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week I had to work on the open PRs specifically work on the bugs that were pointed out in last week’s meeting. Along side the bugs I had to continue the work on Tree2D UI element. Below is the detailed description of what I worked on this week:

+

+ +

Read more ...

+
+
+ +
+

+ Seventh week of coding! +

+
    +
  • + + + 26 July 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Sajag Swami + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Welcome to the eighth weekly check-in. I’ll be sharing my progress for the seventh week of coding.

+

+ +

Read more ...

+
+
+ +
+

+ Weekly Check-In #7 +

+
    +
  • + + + 19 July 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Bruno Messias + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

PR fury-gl/helios#16 +(merged): Helios IPC +network layout support for MacOs

+

+ +

Read more ...

+
+
+ +
+

+ Week #7: Finalizing the stalling PRs, finishing up Tree2D UI. +

+
    +
  • + + + 19 July 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Antriksh Misri + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week I had limited tasks to do, mostly tasks related to existing PRs. Other than some minor fixes I had to implement some more things in Tree2D which included some minor UI fixes, some changes in tutorial, adding tests. Below is the detailed description of what I worked on this week:

+

+ +

Read more ...

+
+
+ +
+

+ Sixth week of coding! +

+
    +
  • + + + 19 July 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Sajag Swami + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Welcome to the seventh weekly check-in. I’ll be sharing my progress for the sixth week of coding.

+

+ +

Read more ...

+
+
+ +
+

+ Week #6: Bug fixes, Working on Tree2D UI +

+
    +
  • + + + 12 July 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Antriksh Misri + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week I had relatively few tasks and most of them were to fix some bugs/design flaws that were discussed in last week’s meeting. Other than that, I had to implement a few things in the Tree2D UI element that will be discussed in detail below. I also had to update some existing PRs in order to make things work well. Below are the list of things I worked on this week:

+

+ +

Read more ...

+
+
+ +
+

+ Network layout algorithms using IPC +

+
    +
  • + + + 12 July 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Bruno Messias + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hi all. In the past weeks, I’ve been focusing on developing Helios; the +network visualization library for FURY. I improved the visual aspects of +the network rendering as well as implemented the most relevant network +layout methods.

+

+ +

Read more ...

+
+
+ +
+

+ Fifth week of coding! +

+
    +
  • + + + 12 July 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Sajag Swami + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Welcome to the sixth weekly check-in. I’ll be sharing my progress for the fifth week of coding.

+

+ +

Read more ...

+
+
+ +
+

+ Weekly Check-In #5 +

+
    +
  • + + + 05 July 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Bruno Messias + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Before the 8c670c2 commit, for some versions of MacOs the +streaming system was falling in a silent bug. I’ve spent a lot of +time researching to found a cause for this. Fortunately, I could found +the cause and the solution. This troublesome MacOs was falling in a +silent bug because the SharedMemory Object was creating a memory +resource with at least 4086 bytes independent if I’ve requested less +than that. If we look into the MultiDimensionalBuffer Object +(stream/tools.py) before the 8c670c2 commit we can see that Object +has max_size parameter which needs to be updated if the SharedMemory +was created with a “wrong” size.

+

+ +

Read more ...

+
+
+ +
+

+ Week #5: Rebasing all PRs w.r.t the UI restructuring, Tree2D, Bug Fixes +

+
    +
  • + + + 05 July 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Antriksh Misri + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

The UI restructuring was finally merged this week. This means UI is now a submodule in itself and provides different UI elements based on their types which are, core, elements, containers and some helper methods/classes. So, this week my main tasks were to rebase and fix merge conflicts of my open PR’s. Other than that, I had to continue my work on Tree2D UI element and finish the remaining aspects of it. Also, I had to create an example demonstrating how to use the newly added UI element. Many use cases were discussed in the open meeting like, an image gallery which displays preview image on the title and when expanded reveals the full scale image. I am thinking of adding multiple examples for the Tree2D to brainstorm on its certain features. Also, I had this annoying bug in Panel2D which didn’t allow it to be resized from the bottom right corner. It was resizing from the top right corner. I had to address this bug as well. Below are the tasks in detail:

+

+ +

Read more ...

+
+
+ +
+

+ SOLID, monkey patching a python issue and network visualization through WebRTC +

+
    +
  • + + + 05 July 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Bruno Messias + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

These past two weeks I’ve spent most of my time in the Streaming System +PR and the Network Layout +PR . In this post I’ll +focus on the most relevant things I’ve made for those PRs.

+

+ +

Read more ...

+
+
+ +
+

+ Fourth week of coding! +

+
    +
  • + + + 05 July 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Sajag Swami + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Welcome to the fifth weekly check-in. I’ll be sharing my progress for the fourth week of coding.

+

+ +

Read more ...

+
+
+ +
+

+ Week #4: Adding Tree UI to the UI module +

+
    +
  • + + + 28 June 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Antriksh Misri + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week I had very few tasks to do, almost all of them revolved around UI elements and adding stuff to the UI module. Earlier, it was pointed out that due to some design issues, importing certain modules into others caused circular imports which led to importing the specific modules inside a class/method which is not the best approach. This will be resolved as soon as the PR that fixes this issue is reviewed/merged in the codebase. In the meantime, all the PR’s related to UI will be on hold, which is why this I had few tasks this week. The tasks are described below in detail:

+

+ +

Read more ...

+
+
+ +
+

+ Third week of coding! +

+
    +
  • + + + 28 June 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Sajag Swami + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Welcome to the fourth weekly check-in. I’ll be sharing my progress for the third week of coding.

+

+ +

Read more ...

+
+
+ +
+

+ Weekly Check-In #3 +

+
    +
  • + + + 21 June 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Bruno Messias + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

PR fury-gl/fury#422 +(merged): +Integrated the 3d impostor spheres with the marker actor.

+

+ +

Read more ...

+
+
+ +
+

+ Week #3: Adapting GridLayout to work with UI +

+
    +
  • + + + 21 June 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Antriksh Misri + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week my tasks revolved around layout and UI elements. The primary goal for this week was to adapt the GridLayout to work with different UI elements. Currently, GridLayout just supports vtk actors and not UI elements, my task was to modify the class to support UI elements. The other tasks for this week are described below in detail:

+

+ +

Read more ...

+
+
+ +
+

+ Second week of coding! +

+
    +
  • + + + 21 June 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Sajag Swami + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Welcome to the third weekly check-in. I’ll be sharing my progress for the second week of coding.

+

+ +

Read more ...

+
+
+ +
+

+ First week of coding! +

+
    +
  • + + + 14 June 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Sajag Swami + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Welcome to the second weekly check-in. I’ll be sharing my progress for the first week of coding.

+

+ +

Read more ...

+
+
+ +
+

+ Week #2: Feature additions in UI and IO modules +

+
    +
  • + + + 13 June 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Antriksh Misri + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week I had to work on 3 PRs as well as some documentation. I really enjoyed this week’s work as the tasks were really interesting. The aim for these PRs were to actually add a couple of features in the UI as well as the IO module, which includes, adding support for border in Panel2D, adding support for network/URL images in load_image method in IO module, adding resizing Panel2D from bottom right corner, completing the document with layout solutions provided by Unity/Unreal engine. Below are the PRs that I worked on:

+

+ +

Read more ...

+
+
+ +
+

+ A Stadia-like system for data visualization +

+
    +
  • + + + 13 June 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Bruno Messias + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hi all! In this post I’ll talk about the PR +#437.

+

+ +

Read more ...

+
+
+ +
+

+ Welcome to my GSoC Blog! +

+
    +
  • + + + 08 June 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Sajag Swami + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hi all! +I’m Sajag Swami, a sophomore at Indian Institute of Technology, Roorkee. This summer, I will be working on adding a new functionality to FURY which shall enable users to +visualise various types of proteins via different representations like Richardson aka Ribbon diagrams and molecular surface diagrams. +As a part of my stretch goals, I’ll try to expand protein diagrams via other representations including:

+

+ +

Read more ...

+
+
+ +
+

+ Weekly Check-In #1 +

+
    +
  • + + + 08 June 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Bruno Messias + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hi everyone! My name is Bruno Messias currently I’m a Ph.D student at +USP/Brazil. In this summer I’ll develop new tools and features for +FURY-GL. Specifically, I’ll focus into developing a system for +collaborative visualization of large network layouts using FURY and VTK.

+

+ +

Read more ...

+
+
+ +
+

+ Week #1: Welcome to my weekly Blogs! +

+
    +
  • + + + 08 June 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Antriksh Misri + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hi everyone! I am Antriksh Misri. I am a Pre-Final year student at MIT Pune. This summer, I will be working on Layout Management under FURY’s UI module as my primary goal. This includes addition of different classes under Layout Management to provide different layouts/arrangements in which the UI elements can be arranged. As my stretch goals, I will be working on a couple of UI components for FURY’s UI module. These 2D and 3D components will be sci-fi like as seen in the movie “Guardians of The Galaxy”. My objective for the stretch goals would be to develop these UI components with their respective test and tutorials such that it adds on to the UI module of FURY and doesn’t hinder existing functionalities/performance.

+

+ +

Read more ...

+
+
+ +
+

+ FURY 0.7.0 Released +

+
    +
  • + + + 13 March 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Serge Koudoro + + + +
  • + + + + +
  • + + + Category: + + + + + release + + + +
  • + + +
  • + + + + Tag: + + + + + fury + + + +
  • + + +
    +
+

The FURY project is happy to announce the release of FURY 0.7.0! +FURY is a free and open source software library for scientific visualization and 3D animations.

+

+ +

Read more ...

+
+
+ +
+

+ Google Summer of Code +

+
    +
  • + + + 09 March 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Serge Koudoro + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

FURY is participating in the Google Summer of Code 2021 under the umbrella of the Python Software Foundation.

+

+ +

Read more ...

+
+
+ +
+

+ Shader Showcase +

+
    +
  • + + + 24 August 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Lenix Lobo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Make sure to check out Project FURY

+

+ +

Read more ...

+
+
+ +
+

+ Google Summer of Code Final Work Product +

+
    +
  • + + + 24 August 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Soham Biswas + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Name: Soham Biswas

+

+ +

Read more ...

+
+
+ +
+

+ Google Summer of Code 2020 Final Work Product +

+
    +
  • + + + 24 August 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Lenix Lobo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Name: Lenix Lobo

+

+ +

Read more ...

+
+
+ +
+

+ Part of the Journey is the end unless its Open Source! +

+
    +
  • + + + 23 August 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Soham Biswas + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hello and welcome to my final weekly check-in. Today officially marks the end of the coding period for GSoC 2020. I enjoyed every bit of it. This was a life-changing experience for me and now I observe and interpret everything from a different perspective altogether. I have grown into a better developer and a person since GSoC. I would like to thank all my mentors and especially Serge for his immense support and mentorship. I would love to contribute to fury even after GSoC is over but unfortunately my semester break is over so I won’t be as active as I was during the summer.

+

+ +

Read more ...

+
+
+ +
+

+ FURY 0.6.1 Released +

+
    +
  • + + + 18 August 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Serge Koudoro + + + +
  • + + + + +
  • + + + Category: + + + + + release + + + +
  • + + +
  • + + + + Tag: + + + + + fury + + + +
  • + + +
    +
+

The FURY project is happy to announce the release of FURY 0.6.1! +FURY is a free and open source software library for scientific visualization and 3D animations.

+

+ +

Read more ...

+
+
+ +
+

+ Outline Picker +

+
    +
  • + + + 17 August 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Lenix Lobo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Make sure to check out Project FURY

+

+ +

Read more ...

+
+
+ +
+

+ Wrecking Ball Simulation, Scrollbars Update, Physics Tutorials. +

+
    +
  • + + + 16 August 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Soham Biswas + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hello and welcome to my 12th weekly check-in. In this blog I will be discussing my progress with the wrecking ball simulation and my scrollbar separation work. Apart from this I have also finalized the physics simulation tutorials and have created a Pull Request to finally get it merged with the official repository. The official repository of my sub-org can be found here.

+

+ +

Read more ...

+
+
+ +
+

+ More Shaders!! +

+
    +
  • + + + 09 August 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Lenix Lobo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Make sure to check out Project FURY

+

+ +

Read more ...

+
+
+ +
+

+ Chain Simulation, Scrollbar Refactor, Tutorial Update. +

+
    +
  • + + + 09 August 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Soham Biswas + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hello and welcome to my 11th weekly check-in. In this blog I will be discussing my progress with multiple topics related to physics and ui components. I was actively working on a couple of things, specifically Joint simulations in pyBullet and scrollbar UI component. I also took up the responsibility to complete an incomplete Pull Request which was pending for quite a while. The official repository of my sub-org can be found here.

+

+ +

Read more ...

+
+
+ +
+

+ Single Actor, Physics, Scrollbars. +

+
    +
  • + + + 02 August 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Soham Biswas + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hello and welcome to my 10th weekly check-in. Second evaluation ended this week and now we move on to our 3rd and final coding period. In today’s check-in I will be sharing my progress with the single actor physics simulation that I facing some issues with and I will also be discussing my future plans regarding UI components. The official repository of my sub-org, FURY can always be found here.

+

+ +

Read more ...

+
+
+ +
+

+ More Shaders!! +

+
    +
  • + + + 02 August 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Lenix Lobo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Make sure to check out Project FURY

+

+ +

Read more ...

+
+
+ +
+

+ Merging SDF primitives. +

+
    +
  • + + + 27 July 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Lenix Lobo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Make sure to check out Project FURY

+

+ +

Read more ...

+
+
+ +
+

+ Tab UI, TabPanel2D, Tab UI Tutorial. +

+
    +
  • + + + 26 July 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Soham Biswas + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hello and welcome to my 9th weekly check-in. I will be sharing my progress with TabUI and its corresponding tutorial. The official repository of my sub-org, FURY can always be found here.

+

+ +

Read more ...

+
+
+ +
+

+ Improvements in SDF primitives. +

+
    +
  • + + + 20 July 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Lenix Lobo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Make sure to check out Project FURY

+

+ +

Read more ...

+
+
+ +
+

+ FURY 0.6.0 Released +

+
    +
  • + + + 20 July 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Serge Koudoro + + + +
  • + + + + +
  • + + + Category: + + + + + release + + + +
  • + + +
  • + + + + Tag: + + + + + fury + + + +
  • + + +
    +
+

The FURY project is happy to announce the release of FURY 0.6.0! +FURY is a free and open source software library for scientific visualization and 3D animations.

+

+ +

Read more ...

+
+
+ +
+

+ ComboBox2D, TextBlock2D, Clipping Overflow. +

+
    +
  • + + + 19 July 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Soham Biswas + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hello and welcome to my 8th weekly check-in. I will be sharing my progress with ComboBox2D and TextBlock2D UI components. After solving TextBlock2D sizing issue, I was finally able to complete the implementation of combo box. I also faced some problems while refactoring TextBlock2D. The official repository of my sub-org, FURY can always be found here.

+

+ +

Read more ...

+
+
+ +
+

+ Multiple SDF primitives. +

+
    +
  • + + + 13 July 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Lenix Lobo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Make sure to check out Project FURY

+

+ +

Read more ...

+
+
+ +
+

+ Orientation, Sizing, Tab UI. +

+
    +
  • + + + 12 July 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Soham Biswas + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hello and welcome to my 7th weekly check-in. I will be sharing my progress with single actor physics simulation and TextBlock2D sizing issue which was pending for quite a while now. I will also be sharing my thoughts regarding the TAB UI component. The official repository of my sub-org, FURY can always be found here.

+

+ +

Read more ...

+
+
+ +
+

+ Translation, Reposition, Rotation. +

+
    +
  • + + + 05 July 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Soham Biswas + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hello and welcome to my 6th weekly check-in. The first evaluation period officially ends and I am very excited to move on to the second coding period. I will be sharing my progress with handling specific object’s properties among various multiple objects rendered by a single actor. I am mainly focusing on making it easier to translate, rotate and reposition a particular object, so that I can use them to render physics simulations more efficiently. The official repository of my sub-org, FURY can always be found here.

+

+ +

Read more ...

+
+
+ +
+

+ Spherical harmonics, Continued. +

+
    +
  • + + + 05 July 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Lenix Lobo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Make sure to check out Project FURY

+

+ +

Read more ...

+
+
+ +
+

+ Spherical harmonics +

+
    +
  • + + + 28 June 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Lenix Lobo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Make sure to check out Project FURY

+

+ +

Read more ...

+
+
+ +
+

+ May the Force be with you!! +

+
    +
  • + + + 28 June 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Soham Biswas + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hello and welcome to my 5th weekly check-in, I will be sharing my progress of pyBullet Physics Engine Integration with FURY. The official repository of my sub-org, FURY can always be found here.

+

+ +

Read more ...

+
+
+ +
+

+ TextBlock2D Progress!! +

+
    +
  • + + + 21 June 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Soham Biswas + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hello and welcome to my 4th weekly check-in, I will be sharing my progress with TextBlock2D UI component. The official repository of my sub-org, FURY can always be found here.

+

+ +

Read more ...

+
+
+ +
+

+ Raymarching continued +

+
    +
  • + + + 21 June 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Lenix Lobo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Make sure to check out Project FURY

+

+ +

Read more ...

+
+
+ +
+

+ Raymarching!! +

+
    +
  • + + + 14 June 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Lenix Lobo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Make sure to check out Project FURY

+

+ +

Read more ...

+
+
+ +
+

+ ComboBox2D Progress!! +

+
    +
  • + + + 14 June 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Soham Biswas + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hello and welcome to my third weekly check-in, I will be sharing my progress with the project so far. In case you wondered, the sub-org that I am affiliated to is FURY. Make sure to check out the official repository here.

+

+ +

Read more ...

+
+
+ +
+

+ First week of coding!! +

+
    +
  • + + + 07 June 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Lenix Lobo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hey everyone! +This week : Geometry Shaders!

+

+ +

Read more ...

+
+
+ +
+

+ First week of coding!! +

+
    +
  • + + + 07 June 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Soham Biswas + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hello and welcome to my second weekly check-in, I will be sharing my progress for the first week of coding.

+

+ +

Read more ...

+
+
+ +
+

+ Welcome to my GSoC Blog!!! +

+
    +
  • + + + 30 May 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Soham Biswas + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hello Everyone, this is Soham Biswas currently in 2nd year pursuing my Bachelor’s(B.Tech) degree in Computer Science & Engineering from Institute of Engineering & Management, Kolkata. I have been selected for GSoC’ 20 at sub-org FURY under the umbrella organization of Python Software Foundation. I will be working on building sci-fi-like 2D and 3D interfaces and provide physics engine integration under project titled “Create new UI widgets & Physics Engine Integration”.

+

+ +

Read more ...

+
+
+ +
+

+ Weekly Check-in #1 +

+
    +
  • + + + 30 May 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Lenix Lobo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hey everyone! +This is my blog for this summer’s GSoC @ PSF +I am Lenix Lobo, an undergraduate student from India, and this summer I will be working with project Fury under the umbrella of the Python Software foundation. I will be working on improving the current shader framework.

+

+ +

Read more ...

+
+
+ +
+

+ FURY 0.5.1 Released +

+
    +
  • + + + 09 April 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Serge Koudoro + + + +
  • + + + + +
  • + + + Category: + + + + + release + + + +
  • + + +
  • + + + + Tag: + + + + + fury + + + +
  • + + +
    +
+

The FURY project is happy to announce the release of FURY 0.5.1! +FURY is a free and open source software library for scientific visualization and 3D animations.

+

+ +

Read more ...

+
+
+ +
+

+ Google Summer of Code +

+
    +
  • + + + 05 January 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Serge Koudoro + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

FURY is participating in the Google Summer of Code 2020 under the umbrella of the Python Software Foundation.

+

+ +

Read more ...

+
+
+ +
+

+ FURY 0.4.0 Released +

+
    +
  • + + + 29 October 2019 + +
  • +
    + + +
  • + + + Author: + + + + + Serge Koudoro + + + +
  • + + + + +
  • + + + Category: + + + + + release + + + +
  • + + +
  • + + + + Tag: + + + + + fury + + + +
  • + + +
    +
+

The FURY project is happy to announce the release of FURY 0.4.0! +FURY is a free and open source software library for scientific visualization and 3D animations.

+

+ +

Read more ...

+
+
+ +
+

+ FURY 0.3.0 Released +

+
    +
  • + + + 02 August 2019 + +
  • +
    + + +
  • + + + Author: + + + + + Serge Koudoro + + + +
  • + + + + +
  • + + + Category: + + + + + release + + + +
  • + + +
  • + + + + Tag: + + + + + fury + + + +
  • + + +
    +
+

The FURY project is happy to announce the release of FURY 0.3.0! +FURY is a free and open source software library for scientific visualization and 3D animations.

+

+ +

Read more ...

+
+
+ +
+

+ Success on Brain Art Competition using FURY +

+
    +
  • + + + 19 June 2019 + +
  • +
    + + +
  • + + + Author: + + + + + Serge Koudoro + + + +
  • + + + + +
  • + + + Category: + + + + + news + + + +
  • + + +
  • + + + + Tag: + + + + + shader + + + +
  • + + +
    +
+

Congratulations to David who won the OHBM BrainArt (MELPOMENE category) by using DIPY and FURY!!!

+

+ +

Read more ...

+
+
+ +
+

+ FURY 0.2.0 Released +

+
    +
  • + + + 08 March 2019 + +
  • +
    + + +
  • + + + Author: + + + + + Serge Koudoro + + + +
  • + + + + +
  • + + + Category: + + + + + release + + + +
  • + + +
  • + + + + Tag: + + + + + fury + + + +
  • + + +
    +
+

The FURY project is happy to announce the release of FURY 0.2.0! +FURY is a free and open source software library for scientific visualization and 3D animations.

+

+ +

Read more ...

+
+
+ +
+

+ FURY 0.1.4 Released +

+
    +
  • + + + 26 November 2018 + +
  • +
    + + +
  • + + + Author: + + + + + Serge Koudoro + + + +
  • + + + + +
  • + + + Category: + + + + + release + + + +
  • + + +
  • + + + + Tag: + + + + + fury + + + +
  • + + +
    +
+

The FURY project is happy to announce the release of FURY 0.1.4! +FURY is a free and open source software library for scientific visualization and 3D animations.

+

+ +

Read more ...

+
+
+ +
+

+ FURY 0.1.3 Released +

+
    +
  • + + + 31 October 2018 + +
  • +
    + + +
  • + + + Author: + + + + + Serge Koudoro + + + +
  • + + + + +
  • + + + Category: + + + + + release + + + +
  • + + +
  • + + + + Tag: + + + + + fury + + + +
  • + + +
    +
+

The FURY project is happy to announce the release of FURY 0.1.3! +FURY is a free and open source software library for scientific visualization and 3D animations.

+

+ +

Read more ...

+
+
+ +
+

+ FURY 0.1.0 Released +

+
    +
  • + + + 21 September 2018 + +
  • +
    + + +
  • + + + Author: + + + + + Serge Koudoro + + + +
  • + + + + +
  • + + + Category: + + + + + release + + + +
  • + + +
  • + + + + Tag: + + + + + fury + + + +
  • + + +
    +
+

The FURY project is happy to announce the release of FURY 0.1.0! +FURY is a free and open source software library for scientific visualization and 3D animations.

+

+ +

Read more ...

+
+
+ + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/blog/2018.html b/v0.10.x/blog/2018.html new file mode 100644 index 000000000..7718754d8 --- /dev/null +++ b/v0.10.x/blog/2018.html @@ -0,0 +1,682 @@ + + + + + + + Posted in 2018 — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +
+

+ + Posted in + + 2018 + +

+ + +
+

+ FURY 0.1.4 Released +

+
    +
  • + + + 26 November 2018 + +
  • +
    + + +
  • + + + Author: + + + + + Serge Koudoro + + + +
  • + + + + +
  • + + + Category: + + + + + release + + + +
  • + + +
  • + + + + Tag: + + + + + fury + + + +
  • + + +
    +
+

The FURY project is happy to announce the release of FURY 0.1.4! +FURY is a free and open source software library for scientific visualization and 3D animations.

+

+ +

Read more ...

+
+
+ +
+

+ FURY 0.1.3 Released +

+
    +
  • + + + 31 October 2018 + +
  • +
    + + +
  • + + + Author: + + + + + Serge Koudoro + + + +
  • + + + + +
  • + + + Category: + + + + + release + + + +
  • + + +
  • + + + + Tag: + + + + + fury + + + +
  • + + +
    +
+

The FURY project is happy to announce the release of FURY 0.1.3! +FURY is a free and open source software library for scientific visualization and 3D animations.

+

+ +

Read more ...

+
+
+ +
+

+ FURY 0.1.0 Released +

+
    +
  • + + + 21 September 2018 + +
  • +
    + + +
  • + + + Author: + + + + + Serge Koudoro + + + +
  • + + + + +
  • + + + Category: + + + + + release + + + +
  • + + +
  • + + + + Tag: + + + + + fury + + + +
  • + + +
    +
+

The FURY project is happy to announce the release of FURY 0.1.0! +FURY is a free and open source software library for scientific visualization and 3D animations.

+

+ +

Read more ...

+
+
+ + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/blog/2018/atom.xml b/v0.10.x/blog/2018/atom.xml new file mode 100644 index 000000000..4b1beffa1 --- /dev/null +++ b/v0.10.x/blog/2018/atom.xml @@ -0,0 +1,146 @@ + + + https://fury.gl/ + Blog - Posted in 2018 + 2024-02-29T15:43:57.766747+00:00 + + + ABlog + + https://fury.gl/posts/2018/2018-11-26-release-announcement.html + FURY 0.1.4 Released + 2018-11-26T00:00:00-05:00 + + Serge Koudoro + + <section id="fury-0-1-4-released"> + +<p>The FURY project is happy to announce the release of FURY 0.1.4! +FURY is a free and open source software library for scientific visualization and 3D animations.</p> +<p>You can show your support by <a class="reference external" href="https://github.com/fury-gl/fury/stargazers">adding a star</a> on FURY github project.</p> +<p>The <strong>major highlights</strong> of this release are:</p> +<p>This is a maintenance release</p> +<ul class="simple"> +<li><p>Add vtk.utils.color on window package</p></li> +<li><p>Update Readme, codecov, travis…</p></li> +</ul> +<div class="admonition note"> +<p class="admonition-title">Note</p> +<p>The complete release notes are <a class="reference internal" href="../release_notes/releasev0.1.4.html#releasev0-1-4"><span class="std std-ref">available here</span></a></p> +</div> +<p><strong>To upgrade or install FURY</strong></p> +<p>Run the following command in your terminal:</p> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">pip</span> <span class="n">install</span> <span class="o">--</span><span class="n">upgrade</span> <span class="n">fury</span> +</pre></div> +</div> +<p>or:</p> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">conda</span> <span class="n">install</span> <span class="o">-</span><span class="n">c</span> <span class="n">conda</span><span class="o">-</span><span class="n">forge</span> <span class="n">fury</span> +</pre></div> +</div> +<p><strong>Questions or suggestions?</strong></p> +<p>For any questions go to <a class="reference external" href="http://fury.gl">http://fury.gl</a>, or send an e-mail to <a class="reference external" href="mailto:fury&#37;&#52;&#48;python&#46;org">fury<span>&#64;</span>python<span>&#46;</span>org</a> +We can also join our <a class="reference external" href="https://discord.gg/6btFPPj">discord community</a></p> +<p>On behalf of the <a class="reference internal" href="../community.html#community"><span class="std std-ref">FURY developers</span></a>,</p> +<p>Serge K.</p> +</section> + + + The FURY project is happy to announce the release of FURY 0.1.4! +FURY is a free and open source software library for scientific visualization and 3D animations. + + 2018-11-26T00:00:00-05:00 + + + https://fury.gl/posts/2018/2018-10-31-release-announcement.html + FURY 0.1.3 Released + 2018-10-31T00:00:00-04:00 + + Serge Koudoro + + <section id="fury-0-1-3-released"> + +<p>The FURY project is happy to announce the release of FURY 0.1.3! +FURY is a free and open source software library for scientific visualization and 3D animations.</p> +<p>You can show your support by <a class="reference external" href="https://github.com/fury-gl/fury/stargazers">adding a star</a> on FURY github project.</p> +<p>The <strong>major highlights</strong> of this release are:</p> +<p>This is a maintenance release</p> +<ul class="simple"> +<li><p>Update setup.py</p></li> +<li><p>Remove dependence on requirements.txt</p></li> +</ul> +<div class="admonition note"> +<p class="admonition-title">Note</p> +<p>The complete release notes are <a class="reference internal" href="../release_notes/releasev0.1.3.html#releasev0-1-3"><span class="std std-ref">available here</span></a></p> +</div> +<p><strong>To upgrade or install FURY</strong></p> +<p>Run the following command in your terminal:</p> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">pip</span> <span class="n">install</span> <span class="o">--</span><span class="n">upgrade</span> <span class="n">fury</span> +</pre></div> +</div> +<p>or:</p> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">conda</span> <span class="n">install</span> <span class="o">-</span><span class="n">c</span> <span class="n">conda</span><span class="o">-</span><span class="n">forge</span> <span class="n">fury</span> +</pre></div> +</div> +<p><strong>Questions or suggestions?</strong></p> +<p>For any questions go to <a class="reference external" href="http://fury.gl">http://fury.gl</a>, or send an e-mail to <a class="reference external" href="mailto:fury&#37;&#52;&#48;python&#46;org">fury<span>&#64;</span>python<span>&#46;</span>org</a> +We can also join our <a class="reference external" href="https://discord.gg/6btFPPj">discord community</a></p> +<p>On behalf of the <a class="reference internal" href="../community.html#community"><span class="std std-ref">FURY developers</span></a>,</p> +<p>Serge K.</p> +</section> + + + The FURY project is happy to announce the release of FURY 0.1.3! +FURY is a free and open source software library for scientific visualization and 3D animations. + + 2018-10-31T00:00:00-04:00 + + + https://fury.gl/posts/2018/2018-09-21-release-announcement.html + FURY 0.1.0 Released + 2018-09-21T00:00:00-04:00 + + Serge Koudoro + + <section id="fury-0-1-0-released"> + +<p>The FURY project is happy to announce the release of FURY 0.1.0! +FURY is a free and open source software library for scientific visualization and 3D animations.</p> +<p>You can show your support by <a class="reference external" href="https://github.com/fury-gl/fury/stargazers">adding a star</a> on FURY github project.</p> +<p>The <strong>major highlights</strong> of this release are:</p> +<p>This initial release is a split from DIPY. It contains:</p> +<ul class="simple"> +<li><p>from <code class="docutils literal notranslate"><span class="pre">dipy.viz.actors</span></code> to <code class="docutils literal notranslate"><span class="pre">fury.actors</span></code></p></li> +<li><p>from <code class="docutils literal notranslate"><span class="pre">dipy.viz.window</span></code> to <code class="docutils literal notranslate"><span class="pre">fury.window</span></code></p></li> +<li><p>from <code class="docutils literal notranslate"><span class="pre">dipy.viz.ui</span></code> to <code class="docutils literal notranslate"><span class="pre">fury.ui</span></code></p></li> +<li><p>from <code class="docutils literal notranslate"><span class="pre">dipy.viz.widget</span></code> to <code class="docutils literal notranslate"><span class="pre">fury.widget</span></code></p></li> +<li><p>from <code class="docutils literal notranslate"><span class="pre">dipy.viz.interactor</span></code> to <code class="docutils literal notranslate"><span class="pre">fury.interactor</span></code></p></li> +<li><p>from <code class="docutils literal notranslate"><span class="pre">dipy.viz.colormap</span></code> to <code class="docutils literal notranslate"><span class="pre">fury.colormap</span></code></p></li> +<li><p>from <code class="docutils literal notranslate"><span class="pre">dipy.viz.utils</span></code> to <code class="docutils literal notranslate"><span class="pre">fury.utils</span></code></p></li> +</ul> +<div class="admonition note"> +<p class="admonition-title">Note</p> +<p>The complete release notes are <a class="reference internal" href="../release_notes/releasev0.1.0.html#releasev0-1-0"><span class="std std-ref">available here</span></a></p> +</div> +<p><strong>To upgrade or install FURY</strong></p> +<p>Run the following command in your terminal:</p> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">pip</span> <span class="n">install</span> <span class="o">--</span><span class="n">upgrade</span> <span class="n">fury</span> +</pre></div> +</div> +<p>or:</p> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">conda</span> <span class="n">install</span> <span class="o">-</span><span class="n">c</span> <span class="n">conda</span><span class="o">-</span><span class="n">forge</span> <span class="n">fury</span> +</pre></div> +</div> +<p><strong>Questions or suggestions?</strong></p> +<p>For any questions go to <a class="reference external" href="http://fury.gl">http://fury.gl</a>, or send an e-mail to <a class="reference external" href="mailto:fury&#37;&#52;&#48;python&#46;org">fury<span>&#64;</span>python<span>&#46;</span>org</a> +We can also join our <a class="reference external" href="https://discord.gg/6btFPPj">discord community</a></p> +<p>On behalf of the <a class="reference internal" href="../community.html#community"><span class="std std-ref">FURY developers</span></a>,</p> +<p>Serge K.</p> +</section> + + + The FURY project is happy to announce the release of FURY 0.1.0! +FURY is a free and open source software library for scientific visualization and 3D animations. + + 2018-09-21T00:00:00-04:00 + + diff --git a/v0.10.x/blog/2019.html b/v0.10.x/blog/2019.html new file mode 100644 index 000000000..98287ce26 --- /dev/null +++ b/v0.10.x/blog/2019.html @@ -0,0 +1,753 @@ + + + + + + + Posted in 2019 — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +
+

+ + Posted in + + 2019 + +

+ + +
+

+ FURY 0.4.0 Released +

+
    +
  • + + + 29 October 2019 + +
  • +
    + + +
  • + + + Author: + + + + + Serge Koudoro + + + +
  • + + + + +
  • + + + Category: + + + + + release + + + +
  • + + +
  • + + + + Tag: + + + + + fury + + + +
  • + + +
    +
+

The FURY project is happy to announce the release of FURY 0.4.0! +FURY is a free and open source software library for scientific visualization and 3D animations.

+

+ +

Read more ...

+
+
+ +
+

+ FURY 0.3.0 Released +

+
    +
  • + + + 02 August 2019 + +
  • +
    + + +
  • + + + Author: + + + + + Serge Koudoro + + + +
  • + + + + +
  • + + + Category: + + + + + release + + + +
  • + + +
  • + + + + Tag: + + + + + fury + + + +
  • + + +
    +
+

The FURY project is happy to announce the release of FURY 0.3.0! +FURY is a free and open source software library for scientific visualization and 3D animations.

+

+ +

Read more ...

+
+
+ +
+

+ Success on Brain Art Competition using FURY +

+
    +
  • + + + 19 June 2019 + +
  • +
    + + +
  • + + + Author: + + + + + Serge Koudoro + + + +
  • + + + + +
  • + + + Category: + + + + + news + + + +
  • + + +
  • + + + + Tag: + + + + + shader + + + +
  • + + +
    +
+

Congratulations to David who won the OHBM BrainArt (MELPOMENE category) by using DIPY and FURY!!!

+

+ +

Read more ...

+
+
+ +
+

+ FURY 0.2.0 Released +

+
    +
  • + + + 08 March 2019 + +
  • +
    + + +
  • + + + Author: + + + + + Serge Koudoro + + + +
  • + + + + +
  • + + + Category: + + + + + release + + + +
  • + + +
  • + + + + Tag: + + + + + fury + + + +
  • + + +
    +
+

The FURY project is happy to announce the release of FURY 0.2.0! +FURY is a free and open source software library for scientific visualization and 3D animations.

+

+ +

Read more ...

+
+
+ + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/blog/2019/atom.xml b/v0.10.x/blog/2019/atom.xml new file mode 100644 index 000000000..c060f01e6 --- /dev/null +++ b/v0.10.x/blog/2019/atom.xml @@ -0,0 +1,191 @@ + + + https://fury.gl/ + Blog - Posted in 2019 + 2024-02-29T15:43:57.759897+00:00 + + + ABlog + + https://fury.gl/posts/2019/2019-10-29-release-announcement.html + FURY 0.4.0 Released + 2019-10-29T00:00:00-04:00 + + Serge Koudoro + + <section id="fury-0-4-0-released"> + +<p>The FURY project is happy to announce the release of FURY 0.4.0! +FURY is a free and open source software library for scientific visualization and 3D animations.</p> +<p>You can show your support by <a class="reference external" href="https://github.com/fury-gl/fury/stargazers">adding a star</a> on FURY github project.</p> +<p>The <strong>major highlights</strong> of this release are:</p> +<ul class="simple"> +<li><p>Enable Anti aliasing and frame rate features</p></li> +<li><p>Add multiples actors (arrow, box, …)</p></li> +<li><p>Glyph extensions</p></li> +<li><p>Remove Nose dependency</p></li> +<li><p>Replace Appveyor by Azure pipeline for Windows</p></li> +<li><p>Update Documentation, examples and tutorials</p></li> +<li><p>Increase tests coverage and code quality</p></li> +</ul> +<div class="admonition note"> +<p class="admonition-title">Note</p> +<p>The complete release notes are <a class="reference internal" href="../release_notes/releasev0.4.0.html#releasev0-4-0"><span class="std std-ref">available here</span></a></p> +</div> +<p><strong>To upgrade or install FURY</strong></p> +<p>Run the following command in your terminal:</p> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">pip</span> <span class="n">install</span> <span class="o">--</span><span class="n">upgrade</span> <span class="n">fury</span> +</pre></div> +</div> +<p>or:</p> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">conda</span> <span class="n">install</span> <span class="o">-</span><span class="n">c</span> <span class="n">conda</span><span class="o">-</span><span class="n">forge</span> <span class="n">fury</span> +</pre></div> +</div> +<p><strong>Questions or suggestions?</strong></p> +<p>For any questions go to <a class="reference external" href="http://fury.gl">http://fury.gl</a>, or send an e-mail to <a class="reference external" href="mailto:fury&#37;&#52;&#48;python&#46;org">fury<span>&#64;</span>python<span>&#46;</span>org</a> +We can also join our <a class="reference external" href="https://discord.gg/6btFPPj">discord community</a></p> +<p>We would like to thanks to <a class="reference internal" href="../community.html#community"><span class="std std-ref">all contributors</span></a> for this release:</p> +<ul class="simple"> +<li><p>Eleftherios Garyfallidis</p></li> +<li><p>Etienne St-Onge</p></li> +<li><p>Javier Guaje</p></li> +<li><p>Serge Koudoro</p></li> +</ul> +<p>On behalf of the <a class="reference internal" href="../community.html#community"><span class="std std-ref">FURY developers</span></a>,</p> +<p>Serge K.</p> +</section> + + + The FURY project is happy to announce the release of FURY 0.4.0! +FURY is a free and open source software library for scientific visualization and 3D animations. + + 2019-10-29T00:00:00-04:00 + + + https://fury.gl/posts/2019/2019-08-02-release-announcement.html + FURY 0.3.0 Released + 2019-08-02T00:00:00-04:00 + + Serge Koudoro + + <section id="fury-0-3-0-released"> + +<p>The FURY project is happy to announce the release of FURY 0.3.0! +FURY is a free and open source software library for scientific visualization and 3D animations.</p> +<p>You can show your support by <a class="reference external" href="https://github.com/fury-gl/fury/stargazers">adding a star</a> on FURY github project.</p> +<p>The <strong>major highlights</strong> of this release are:</p> +<ul class="simple"> +<li><p>Add cone actor and update odf actor</p></li> +<li><p>Add Appveyor CI and update MacOS CI</p></li> +<li><p>Update Documentation, examples and tutorials</p></li> +<li><p>Increase tests coverage and code quality</p></li> +</ul> +<div class="admonition note"> +<p class="admonition-title">Note</p> +<p>The complete release notes are <a class="reference internal" href="../release_notes/releasev0.3.0.html#releasev0-3-0"><span class="std std-ref">available here</span></a></p> +</div> +<p><strong>To upgrade or install FURY</strong></p> +<p>Run the following command in your terminal:</p> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">pip</span> <span class="n">install</span> <span class="o">--</span><span class="n">upgrade</span> <span class="n">fury</span> +</pre></div> +</div> +<p>or:</p> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">conda</span> <span class="n">install</span> <span class="o">-</span><span class="n">c</span> <span class="n">conda</span><span class="o">-</span><span class="n">forge</span> <span class="n">fury</span> +</pre></div> +</div> +<p><strong>Questions or suggestions?</strong></p> +<p>For any questions go to <a class="reference external" href="http://fury.gl">http://fury.gl</a>, or send an e-mail to <a class="reference external" href="mailto:fury&#37;&#52;&#48;python&#46;org">fury<span>&#64;</span>python<span>&#46;</span>org</a> +We can also join our <a class="reference external" href="https://discord.gg/6btFPPj">discord community</a></p> +<p>We would like to thanks to <a class="reference internal" href="../community.html#community"><span class="std std-ref">all contributors</span></a> for this release:</p> +<ul class="simple"> +<li><p>Ariel Rokem</p></li> +<li><p>Eleftherios Garyfallidis</p></li> +<li><p>Guillaume Favelier</p></li> +<li><p>Kevin Sitek</p></li> +<li><p>Prashil</p></li> +<li><p>Scott Trinkle</p></li> +<li><p>Serge Koudoro</p></li> +</ul> +<p>On behalf of the <a class="reference internal" href="../community.html#community"><span class="std std-ref">FURY developers</span></a>,</p> +<p>Serge K.</p> +</section> + + + The FURY project is happy to announce the release of FURY 0.3.0! +FURY is a free and open source software library for scientific visualization and 3D animations. + + 2019-08-02T00:00:00-04:00 + + + https://fury.gl/posts/2019/2019-06-19-brain-art.html + Success on Brain Art Competition using FURY + 2019-06-19T00:00:00-04:00 + + Serge Koudoro + + <section id="success-on-brain-art-competition-using-fury"> + +<p>Congratulations to <a class="reference external" href="https://github.com/dmreagan">David</a> who won the <a class="reference external" href="https://www.neurobureau.org/galleries/brain-art-competition-2019-2/">OHBM BrainArt (MELPOMENE category)</a> by using DIPY and FURY!!!</p> +<p>As you can see below, really beautiful streamlines effect created during shader experiment/fail!</p> +<img alt="Brain Streamlines Shader Experiment" class="align-center" src="https://fury.gl/_images/Melpomene_Brain-Streamlines-shader-experiment_by_David-Reagan.jpg" /> +</section> + + + Congratulations to David who won the OHBM BrainArt (MELPOMENE category) by using DIPY and FURY!!! + + 2019-06-19T00:00:00-04:00 + + + https://fury.gl/posts/2019/2019-03-08-release-announcement.html + FURY 0.2.0 Released + 2019-03-08T00:00:00-05:00 + + Serge Koudoro + + <section id="fury-0-2-0-released"> + +<p>The FURY project is happy to announce the release of FURY 0.2.0! +FURY is a free and open source software library for scientific visualization and 3D animations.</p> +<p>You can show your support by <a class="reference external" href="https://github.com/fury-gl/fury/stargazers">adding a star</a> on FURY github project.</p> +<p>The <strong>major highlights</strong> of this release are:</p> +<ul class="simple"> +<li><p>Replace <code class="docutils literal notranslate"><span class="pre">fury.window.Renderer</span></code> by <code class="docutils literal notranslate"><span class="pre">fury.window.Scene</span></code></p></li> +<li><p>Add stereo support</p></li> +<li><p>Add GridUI object</p></li> +<li><p>Increase tests coverage and code quality</p></li> +</ul> +<div class="admonition note"> +<p class="admonition-title">Note</p> +<p>The complete release notes are <a class="reference internal" href="../release_notes/releasev0.2.0.html#releasev0-2-0"><span class="std std-ref">available here</span></a></p> +</div> +<p><strong>To upgrade or install FURY</strong></p> +<p>Run the following command in your terminal:</p> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">pip</span> <span class="n">install</span> <span class="o">--</span><span class="n">upgrade</span> <span class="n">fury</span> +</pre></div> +</div> +<p>or:</p> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">conda</span> <span class="n">install</span> <span class="o">-</span><span class="n">c</span> <span class="n">conda</span><span class="o">-</span><span class="n">forge</span> <span class="n">fury</span> +</pre></div> +</div> +<p><strong>Questions or suggestions?</strong></p> +<p>For any questions go to <a class="reference external" href="http://fury.gl">http://fury.gl</a>, or send an e-mail to <a class="reference external" href="mailto:fury&#37;&#52;&#48;python&#46;org">fury<span>&#64;</span>python<span>&#46;</span>org</a> +We can also join our <a class="reference external" href="https://discord.gg/6btFPPj">discord community</a></p> +<p>We would like to thanks to <a class="reference internal" href="../community.html#community"><span class="std std-ref">all contributors</span></a> for this release:</p> +<ul class="simple"> +<li><p>David Reagan</p></li> +<li><p>Eleftherios Garyfallidis</p></li> +<li><p>Jon Haitz Legarreta Gorroño</p></li> +<li><p>Marc-Alexandre Côté</p></li> +<li><p>Serge Koudoro</p></li> +</ul> +<p>On behalf of the <a class="reference internal" href="../community.html#community"><span class="std std-ref">FURY developers</span></a>,</p> +<p>Serge K.</p> +</section> + + + The FURY project is happy to announce the release of FURY 0.2.0! +FURY is a free and open source software library for scientific visualization and 3D animations. + + 2019-03-08T00:00:00-05:00 + + diff --git a/v0.10.x/blog/2020.html b/v0.10.x/blog/2020.html new file mode 100644 index 000000000..f9f3bcebc --- /dev/null +++ b/v0.10.x/blog/2020.html @@ -0,0 +1,2744 @@ + + + + + + + Posted in 2020 — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +
+

+ + Posted in + + 2020 + +

+ + +
+

+ Shader Showcase +

+
    +
  • + + + 24 August 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Lenix Lobo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Make sure to check out Project FURY

+

+ +

Read more ...

+
+
+ +
+

+ Google Summer of Code Final Work Product +

+
    +
  • + + + 24 August 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Soham Biswas + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Name: Soham Biswas

+

+ +

Read more ...

+
+
+ +
+

+ Google Summer of Code 2020 Final Work Product +

+
    +
  • + + + 24 August 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Lenix Lobo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Name: Lenix Lobo

+

+ +

Read more ...

+
+
+ +
+

+ Part of the Journey is the end unless its Open Source! +

+
    +
  • + + + 23 August 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Soham Biswas + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hello and welcome to my final weekly check-in. Today officially marks the end of the coding period for GSoC 2020. I enjoyed every bit of it. This was a life-changing experience for me and now I observe and interpret everything from a different perspective altogether. I have grown into a better developer and a person since GSoC. I would like to thank all my mentors and especially Serge for his immense support and mentorship. I would love to contribute to fury even after GSoC is over but unfortunately my semester break is over so I won’t be as active as I was during the summer.

+

+ +

Read more ...

+
+
+ +
+

+ FURY 0.6.1 Released +

+
    +
  • + + + 18 August 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Serge Koudoro + + + +
  • + + + + +
  • + + + Category: + + + + + release + + + +
  • + + +
  • + + + + Tag: + + + + + fury + + + +
  • + + +
    +
+

The FURY project is happy to announce the release of FURY 0.6.1! +FURY is a free and open source software library for scientific visualization and 3D animations.

+

+ +

Read more ...

+
+
+ +
+

+ Outline Picker +

+
    +
  • + + + 17 August 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Lenix Lobo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Make sure to check out Project FURY

+

+ +

Read more ...

+
+
+ +
+

+ Wrecking Ball Simulation, Scrollbars Update, Physics Tutorials. +

+
    +
  • + + + 16 August 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Soham Biswas + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hello and welcome to my 12th weekly check-in. In this blog I will be discussing my progress with the wrecking ball simulation and my scrollbar separation work. Apart from this I have also finalized the physics simulation tutorials and have created a Pull Request to finally get it merged with the official repository. The official repository of my sub-org can be found here.

+

+ +

Read more ...

+
+
+ +
+

+ More Shaders!! +

+
    +
  • + + + 09 August 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Lenix Lobo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Make sure to check out Project FURY

+

+ +

Read more ...

+
+
+ +
+

+ Chain Simulation, Scrollbar Refactor, Tutorial Update. +

+
    +
  • + + + 09 August 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Soham Biswas + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hello and welcome to my 11th weekly check-in. In this blog I will be discussing my progress with multiple topics related to physics and ui components. I was actively working on a couple of things, specifically Joint simulations in pyBullet and scrollbar UI component. I also took up the responsibility to complete an incomplete Pull Request which was pending for quite a while. The official repository of my sub-org can be found here.

+

+ +

Read more ...

+
+
+ +
+

+ Single Actor, Physics, Scrollbars. +

+
    +
  • + + + 02 August 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Soham Biswas + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hello and welcome to my 10th weekly check-in. Second evaluation ended this week and now we move on to our 3rd and final coding period. In today’s check-in I will be sharing my progress with the single actor physics simulation that I facing some issues with and I will also be discussing my future plans regarding UI components. The official repository of my sub-org, FURY can always be found here.

+

+ +

Read more ...

+
+
+ +
+

+ More Shaders!! +

+
    +
  • + + + 02 August 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Lenix Lobo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Make sure to check out Project FURY

+

+ +

Read more ...

+
+
+ +
+

+ Merging SDF primitives. +

+
    +
  • + + + 27 July 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Lenix Lobo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Make sure to check out Project FURY

+

+ +

Read more ...

+
+
+ +
+

+ Tab UI, TabPanel2D, Tab UI Tutorial. +

+
    +
  • + + + 26 July 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Soham Biswas + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hello and welcome to my 9th weekly check-in. I will be sharing my progress with TabUI and its corresponding tutorial. The official repository of my sub-org, FURY can always be found here.

+

+ +

Read more ...

+
+
+ +
+

+ Improvements in SDF primitives. +

+
    +
  • + + + 20 July 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Lenix Lobo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Make sure to check out Project FURY

+

+ +

Read more ...

+
+
+ +
+

+ FURY 0.6.0 Released +

+
    +
  • + + + 20 July 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Serge Koudoro + + + +
  • + + + + +
  • + + + Category: + + + + + release + + + +
  • + + +
  • + + + + Tag: + + + + + fury + + + +
  • + + +
    +
+

The FURY project is happy to announce the release of FURY 0.6.0! +FURY is a free and open source software library for scientific visualization and 3D animations.

+

+ +

Read more ...

+
+
+ +
+

+ ComboBox2D, TextBlock2D, Clipping Overflow. +

+
    +
  • + + + 19 July 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Soham Biswas + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hello and welcome to my 8th weekly check-in. I will be sharing my progress with ComboBox2D and TextBlock2D UI components. After solving TextBlock2D sizing issue, I was finally able to complete the implementation of combo box. I also faced some problems while refactoring TextBlock2D. The official repository of my sub-org, FURY can always be found here.

+

+ +

Read more ...

+
+
+ +
+

+ Multiple SDF primitives. +

+
    +
  • + + + 13 July 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Lenix Lobo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Make sure to check out Project FURY

+

+ +

Read more ...

+
+
+ +
+

+ Orientation, Sizing, Tab UI. +

+
    +
  • + + + 12 July 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Soham Biswas + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hello and welcome to my 7th weekly check-in. I will be sharing my progress with single actor physics simulation and TextBlock2D sizing issue which was pending for quite a while now. I will also be sharing my thoughts regarding the TAB UI component. The official repository of my sub-org, FURY can always be found here.

+

+ +

Read more ...

+
+
+ +
+

+ Translation, Reposition, Rotation. +

+
    +
  • + + + 05 July 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Soham Biswas + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hello and welcome to my 6th weekly check-in. The first evaluation period officially ends and I am very excited to move on to the second coding period. I will be sharing my progress with handling specific object’s properties among various multiple objects rendered by a single actor. I am mainly focusing on making it easier to translate, rotate and reposition a particular object, so that I can use them to render physics simulations more efficiently. The official repository of my sub-org, FURY can always be found here.

+

+ +

Read more ...

+
+
+ +
+

+ Spherical harmonics, Continued. +

+
    +
  • + + + 05 July 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Lenix Lobo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Make sure to check out Project FURY

+

+ +

Read more ...

+
+
+ +
+

+ Spherical harmonics +

+
    +
  • + + + 28 June 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Lenix Lobo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Make sure to check out Project FURY

+

+ +

Read more ...

+
+
+ +
+

+ May the Force be with you!! +

+
    +
  • + + + 28 June 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Soham Biswas + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hello and welcome to my 5th weekly check-in, I will be sharing my progress of pyBullet Physics Engine Integration with FURY. The official repository of my sub-org, FURY can always be found here.

+

+ +

Read more ...

+
+
+ +
+

+ TextBlock2D Progress!! +

+
    +
  • + + + 21 June 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Soham Biswas + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hello and welcome to my 4th weekly check-in, I will be sharing my progress with TextBlock2D UI component. The official repository of my sub-org, FURY can always be found here.

+

+ +

Read more ...

+
+
+ +
+

+ Raymarching continued +

+
    +
  • + + + 21 June 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Lenix Lobo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Make sure to check out Project FURY

+

+ +

Read more ...

+
+
+ +
+

+ Raymarching!! +

+
    +
  • + + + 14 June 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Lenix Lobo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Make sure to check out Project FURY

+

+ +

Read more ...

+
+
+ +
+

+ ComboBox2D Progress!! +

+
    +
  • + + + 14 June 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Soham Biswas + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hello and welcome to my third weekly check-in, I will be sharing my progress with the project so far. In case you wondered, the sub-org that I am affiliated to is FURY. Make sure to check out the official repository here.

+

+ +

Read more ...

+
+
+ +
+

+ First week of coding!! +

+
    +
  • + + + 07 June 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Lenix Lobo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hey everyone! +This week : Geometry Shaders!

+

+ +

Read more ...

+
+
+ +
+

+ First week of coding!! +

+
    +
  • + + + 07 June 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Soham Biswas + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hello and welcome to my second weekly check-in, I will be sharing my progress for the first week of coding.

+

+ +

Read more ...

+
+
+ +
+

+ Welcome to my GSoC Blog!!! +

+
    +
  • + + + 30 May 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Soham Biswas + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hello Everyone, this is Soham Biswas currently in 2nd year pursuing my Bachelor’s(B.Tech) degree in Computer Science & Engineering from Institute of Engineering & Management, Kolkata. I have been selected for GSoC’ 20 at sub-org FURY under the umbrella organization of Python Software Foundation. I will be working on building sci-fi-like 2D and 3D interfaces and provide physics engine integration under project titled “Create new UI widgets & Physics Engine Integration”.

+

+ +

Read more ...

+
+
+ +
+

+ Weekly Check-in #1 +

+
    +
  • + + + 30 May 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Lenix Lobo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hey everyone! +This is my blog for this summer’s GSoC @ PSF +I am Lenix Lobo, an undergraduate student from India, and this summer I will be working with project Fury under the umbrella of the Python Software foundation. I will be working on improving the current shader framework.

+

+ +

Read more ...

+
+
+ +
+

+ FURY 0.5.1 Released +

+
    +
  • + + + 09 April 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Serge Koudoro + + + +
  • + + + + +
  • + + + Category: + + + + + release + + + +
  • + + +
  • + + + + Tag: + + + + + fury + + + +
  • + + +
    +
+

The FURY project is happy to announce the release of FURY 0.5.1! +FURY is a free and open source software library for scientific visualization and 3D animations.

+

+ +

Read more ...

+
+
+ +
+

+ Google Summer of Code +

+
    +
  • + + + 05 January 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Serge Koudoro + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

FURY is participating in the Google Summer of Code 2020 under the umbrella of the Python Software Foundation.

+

+ +

Read more ...

+
+
+ + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/blog/2020/atom.xml b/v0.10.x/blog/2020/atom.xml new file mode 100644 index 000000000..e6debbb87 --- /dev/null +++ b/v0.10.x/blog/2020/atom.xml @@ -0,0 +1,772 @@ + + + https://fury.gl/ + Blog - Posted in 2020 + 2024-02-29T15:43:57.738767+00:00 + + + ABlog + + https://fury.gl/posts/2020/2020-08-24-week-13-lenix.html + Shader Showcase + 2020-08-24T00:00:00-04:00 + + Lenix Lobo + + <section id="shader-showcase"> + +<p>Make sure to check out Project <a class="reference external" href="https://github.com/fury-gl/fury">FURY</a></p> +<p>Hey Everyone! +Today marked the official end of the coding period for Google Summer of Code 2020. On this day I would like to take the opportunity to thank all my mentors and Soham who have shown immense support during this time and helped me grow not only to be a better programmer but also to be a better team member. While the GSoC period ends, I will try my best to be active and contribute to the project and help it grow. +Cheers!</p> +<section id="what-did-you-do-this-week"> +<h2>What did you do this week?</h2> +<p>This being the final week of GSoC , my task was to create a PR which showcases not only the shader capabilities of the project but also to create a example which integrates both the UI and shader system of project FURY. This example can help new users to get familiar with both the UI and shaders. +Apart from this i also worked on a Toon Shader.</p> +<p>The output for the above task is given below :</p> +<img alt="https://raw.githubusercontent.com/lenixlobo/fury-outputs/master/blog-week-13.gif" src="https://raw.githubusercontent.com/lenixlobo/fury-outputs/master/blog-week-13.gif" /> +<p>The shader demos are available <a class="reference external" href="https://github.com/lenixlobo/fury/tree/shader-demos">here</a></p> +</section> +<section id="what-is-coming-up-next-week"> +<h2>What is coming up next week?</h2> +<p>The next week I will work on the final GSoC documentation which explains what I worked on throughout the GSoC period. In case of any changes are requested by the mentors I will also try to implement them.</p> +</section> +<section id="did-you-get-stuck-anywhere"> +<h2>Did you get stuck anywhere?</h2> +<p>With the help of Soham and the mentors this week went smoothly.</p> +</section> +</section> + + + Make sure to check out Project FURY + + 2020-08-24T00:00:00-04:00 + + + https://fury.gl/posts/2020/2020-08-24-final-work-soham.html + Google Summer of Code Final Work Product + 2020-08-24T00:00:00-04:00 + + Soham Biswas + + <a class="reference external image-reference" href="https://summerofcode.withgoogle.com/projects/#6653942668197888"><img alt="https://developers.google.com/open-source/gsoc/resources/downloads/GSoC-logo-horizontal.svg" class="align-center" height="50" src="https://developers.google.com/open-source/gsoc/resources/downloads/GSoC-logo-horizontal.svg" /></a> +<a class="reference external image-reference" href="https://blogs.python-gsoc.org/en/nibba2018s-blog/"><img alt="https://www.python.org/static/community_logos/python-logo.png" src="https://www.python.org/static/community_logos/python-logo.png" style="width: 40%;" /></a> +<a class="reference external image-reference" href="https://fury.gl/latest/community.html"><img alt="https://python-gsoc.org/logos/FURY.png" src="https://python-gsoc.org/logos/FURY.png" style="width: 25%;" /></a> +<section id="google-summer-of-code-final-work-product"> + +<ul class="simple"> +<li><p><strong>Name:</strong> Soham Biswas</p></li> +<li><p><strong>Organisation:</strong> Python Software Foundation</p></li> +<li><p><strong>Sub-Organisation:</strong> FURY</p></li> +<li><p><strong>Project:</strong> <a class="reference external" href="https://github.com/fury-gl/fury/wiki/Google-Summer-of-Code-2020">FURY - Create new UI Widgets &amp; Physics Engine +Integration</a></p></li> +</ul> +<section id="proposed-objectives"> +<h2>Proposed Objectives</h2> +<ul class="simple"> +<li><p>ComboBox</p></li> +<li><p>Tab UI</p></li> +<li><p>File Dialog Improvements</p></li> +</ul> +</section> +<section id="modified-objectives"> +<h2>Modified Objectives</h2> +<ul class="simple"> +<li><p>Combobox</p></li> +<li><p>Tab UI</p></li> +<li><p>File Dialog Improvements</p></li> +<li><p>Double Click Callback</p></li> +<li><p>TextBlock2D Improvements</p></li> +<li><p>Scrollbars as a Standalone Component</p></li> +<li><p>Physics Engine Integration</p></li> +</ul> +</section> +<section id="objectives-completed"> +<h2>Objectives Completed</h2> +<ul> +<li><p><strong>ComboBox2D UI Component</strong></p> +<p>A combobox is a commonly used graphical user interface widget. +Traditionally, it is a combination of a drop-down list or list box and a +single-line textbox, allowing the user to select a value from the list. +The term “combo box” is sometimes used to mean “drop-down list”. +Respective components, tests and tutorials were created.</p> +<p><em>Pull Requests:</em></p> +<ul class="simple"> +<li><p><strong>Combobox UI component:</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/240">fury-gl/fury#240</a></p></li> +<li><p><strong>Combobox UI Tutorial:</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/246">fury-gl/fury#246</a></p></li> +</ul> +</li> +<li><p><strong>Tab UI Component</strong></p> +<p>In interface design, a tabbed document interface or Tab is a graphical +control element that allows multiple documents or panels to be contained +within a single window, using tabs as a navigational widget for +switching between sets of documents. Respective components, tests and +tutorials were created.</p> +<p><em>Pull Requests:</em></p> +<ul class="simple"> +<li><p><strong>Tab UI component:</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/252">fury-gl/fury#252</a></p></li> +<li><p><strong>Tab UI tutorial:</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/275">fury-gl/fury#275</a></p></li> +</ul> +</li> +<li><p><strong>Double Click Callback</strong></p> +<p>Double click callbacks aren’t implemented in VTK by default so they need +to be implemented manually. With my mentor’s help I was able to +implement double click callbacks for all the three mouse buttons +successfully.</p> +<p><em>Pull Requests:</em></p> +<ul class="simple"> +<li><p><strong>Adding Double Click Callback:</strong> +<a class="github reference external" href="https://github.com/fury-gl/fury/pull/231">fury-gl/fury#231</a></p></li> +</ul> +</li> +<li><p><strong>TextBlock2D Improvements</strong></p> +<p>The previous implementation of <code class="docutils literal notranslate"><span class="pre">TextBlock2D</span></code> was lacking a few +features such as size arguments and text overflow. There was no specific +way to create Texts occupying a said height or width area. Apart from +that UI components like <code class="docutils literal notranslate"><span class="pre">ListBoxItem2D</span></code>, <code class="docutils literal notranslate"><span class="pre">FileMenu2D</span></code> etc had an +issue where text would overflow from their specified width. In order to +tackle these problems, a modification was done to <code class="docutils literal notranslate"><span class="pre">TextBlock2D</span></code> to +accept size as an argument and a new method was added to clip +overflowing text based on a specified width and to replace the +overflowing characters with <code class="docutils literal notranslate"><span class="pre">...</span></code>.</p> +<p><em>Pull Requests:</em></p> +<ul class="simple"> +<li><p><strong>Setting Bounding Box for TextBlock2D:</strong> +<a class="github reference external" href="https://github.com/fury-gl/fury/pull/248">fury-gl/fury#248</a></p></li> +<li><p><strong>Clip Text Overflow:</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/268">fury-gl/fury#268</a></p></li> +</ul> +</li> +<li><p><strong>Physics Engine Integration</strong></p> +<p>Optional support for Physics engine integration of Pybullet was added to +Fury. Pybullet’s engine was used for the simulations and FURY was used +for rendering the said simulations. Exhaustive examples were added to +demonstrate various types of physics simulations possible using pybullet +and fury. The said examples are as follows:</p> +<ul class="simple"> +<li><p>Brick Wall Simulation</p> +<ul> +<li><p>Explains how to render and simulate external forces, objects and +gravity.</p></li> +</ul> +</li> +<li><p>Ball Collision Simulation</p> +<ul> +<li><p>Explains how collisions work and how to detect said collisions.</p></li> +</ul> +</li> +<li><p>Chain Simulation</p> +<ul> +<li><p>Explains how to render and simulate joints.</p></li> +</ul> +</li> +<li><p>Wrecking Ball Simulation</p> +<ul> +<li><p>A more complicated simulation that combines concepts explained by +the other examples.</p></li> +</ul> +</li> +</ul> +<p>Apart from that, a document was created to explain the integration +process between pybullet and fury in detail.</p> +<p><em>Pull Requests:</em></p> +<ul class="simple"> +<li><p><strong>Physics Simulation Examples:</strong> +<a class="github reference external" href="https://github.com/fury-gl/fury/pull/287">fury-gl/fury#287</a></p></li> +<li><p><strong>Fury-Pybullet Integration Docs:</strong> +<a class="reference external" href="https://docs.google.com/document/d/1XJcG1TL5ZRJZDyi8V76leYZt_maxGp0kOB7OZIxKsTA/edit?usp=sharing">https://docs.google.com/document/d/1XJcG1TL5ZRJZDyi8V76leYZt_maxGp0kOB7OZIxKsTA/edit?usp=sharing</a></p></li> +</ul> +</li> +</ul> +</section> +<section id="objectives-in-progress"> +<h2>Objectives in Progress</h2> +<ul> +<li><p><strong>Scrollbars as a standalone component</strong></p> +<p>The previous implementation of scrollbars were hard coded into +<code class="docutils literal notranslate"><span class="pre">ListBox2D</span></code>. Therefore, it was not possible to use scrollbars with any +other UI component. Apart from that, scrollbars in terms of design were +limited. Creating a horizontal scrollbar was not possible. The objective +of this PR is to make scrollbars separate so that other UI elements can +also make use of it.</p> +<p>Currently, the skeletal and design aspects of the scrollbars are +implemented but the combination of scrollbars with other UI components +are still in progress.</p> +<p><em>Pull Requests:</em></p> +<ul class="simple"> +<li><p><strong>Scrollbars as a Standalone API:</strong> +<a class="github reference external" href="https://github.com/fury-gl/fury/pull/285">fury-gl/fury#285</a></p></li> +</ul> +</li> +<li><p><strong>File Dialog Improvements</strong></p> +<p>Currently, we have access to <code class="docutils literal notranslate"><span class="pre">FileMenu2D</span></code> which allows us to navigate +through the filesystem but it does not provide a user friendly Dialog to +read and write files in Fury. Hence the idea is to create a file dialog +which can easily open or save file at runtime. As of now, <code class="docutils literal notranslate"><span class="pre">Open</span></code> and +<code class="docutils literal notranslate"><span class="pre">Save</span></code> operations are implemented. Corresponding tests and tutorials +are in progress.</p> +<p><em>Pull Requests:</em></p> +<ul class="simple"> +<li><p><strong>File Dialog UI component:</strong> +<a class="github reference external" href="https://github.com/fury-gl/fury/pull/294">fury-gl/fury#294</a></p></li> +</ul> +</li> +</ul> +</section> +<section id="other-objectives"> +<h2>Other Objectives</h2> +<ul> +<li><p><strong>Radio Checkbox Tutorial using FURY API</strong></p> +<p>The objects for Radio button and Checkbox tutorial were rendered using +VTK’s method by a fellow contributor so I decided to replace them with +native FURY API. The methods were rewritten keeping the previous commits +intact.</p> +<p><em>Pull Requests:</em></p> +<ul class="simple"> +<li><p><strong>Radio Checkbox tutorial using FURY API:</strong> +<a class="github reference external" href="https://github.com/fury-gl/fury/pull/281">fury-gl/fury#281</a></p></li> +</ul> +</li> +<li><p><strong>GSoC weekly Blogs</strong></p> +<p>Weekly blogs were added for FURY’s Website.</p> +<p><em>Pull Requests:</em></p> +<ul class="simple"> +<li><p><strong>First &amp; Second Evaluation:</strong> +<a class="github reference external" href="https://github.com/fury-gl/fury/pull/272">fury-gl/fury#272</a></p></li> +<li><p><strong>Third Evaluation:</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/286">fury-gl/fury#286</a></p></li> +</ul> +</li> +</ul> +</section> +<section id="timeline"> +<h2>Timeline</h2> +<table class="table"> +<thead> +<tr class="row-odd"><th class="head"><p>Date</p></th> +<th class="head"><p>Description</p></th> +<th class="head"><p>Blog Link</p></th> +</tr> +</thead> +<tbody> +<tr class="row-even"><td><p>Week 1(30-05-2020)</p></td> +<td><p>Welcome to my GSoC Blog!!</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/nibba2018s-blog/weekly-check-in-1-5/">Weekly Check-in #1</a></p></td> +</tr> +<tr class="row-odd"><td><p>Week 2(07-06-2020)</p></td> +<td><p>First Week of Coding!!</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/nibba2018s-blog/weekly-check-in-2-3/">Weekly Check-in #2</a></p></td> +</tr> +<tr class="row-even"><td><p>Week 3(14-06-2020)</p></td> +<td><p>ComboBox2D Progress!!</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/nibba2018s-blog/weekly-check-in-3-4/">Weekly Check-in #3</a></p></td> +</tr> +<tr class="row-odd"><td><p>Week 4(21-06-2020)</p></td> +<td><p>TextBlock2D Progress!!</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/nibba2018s-blog/weekly-check-in-4-4/">Weekly Check-in #4</a></p></td> +</tr> +<tr class="row-even"><td><p>Week 5(28-06-2020)</p></td> +<td><p>May the Force be with you!!</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/nibba2018s-blog/weekly-check-in-5-4/">Weekly Check-in #5</a></p></td> +</tr> +<tr class="row-odd"><td><p>Week 6(05-07-2020)</p></td> +<td><p>Translation, Reposition, Rotation.</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/nibba2018s-blog/weekly-check-in-6-7/">Weekly Check-in #6</a></p></td> +</tr> +<tr class="row-even"><td><p>Week 7(12-07-2020)</p></td> +<td><p>Orientation, Sizing, Tab UI.</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/nibba2018s-blog/weekly-check-in-7-4/">Weekly Check-in #7</a></p></td> +</tr> +<tr class="row-odd"><td><p>Week 8(19-07-2020)</p></td> +<td><p>ComboBox2D, TextBlock2D, ClippingOverflow.</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/nibba2018s-blog/weekly-check-in-8-2/">Weekly Check-in #8</a></p></td> +</tr> +<tr class="row-even"><td><p>Week 9(26-07-2020)</p></td> +<td><p>Tab UI, TabPanel2D, Tab UI Tutorial.</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/nibba2018s-blog/weekly-check-in-9-4/">Weekly Check-in #9</a></p></td> +</tr> +<tr class="row-odd"><td><p>Week 10(02-08-2020)</p></td> +<td><p>Single Actor, Physics, Scrollbars.</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/nibba2018s-blog/weekly-check-in-10-2/">Weekly Check-in #10</a></p></td> +</tr> +<tr class="row-even"><td><p>Week 11(09-08-2020)</p></td> +<td><p>Chain Simulation, Scrollbar Refactor,Tutorial Update.</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/nibba2018s-blog/weekly-check-in-11-1/">Weekly Check-in #11</a></p></td> +</tr> +<tr class="row-odd"><td><p>Week 12(16-08-2020)</p></td> +<td><p>Wrecking Ball Simulation, ScrollbarsUpdate, Physics Tutorials.</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/nibba2018s-blog/weekly-check-in-12/">Weekly Check-in #12</a></p></td> +</tr> +<tr class="row-even"><td><p>Week 13(23-08-2020)</p></td> +<td><p>Part of the Journey is the end unless itsOpen Source!</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/nibba2018s-blog/weekly-check-in-13/">Weekly Check-in #13</a></p></td> +</tr> +</tbody> +</table> +<p>Detailed weekly tasks and work done can be found +<a class="reference external" href="https://blogs.python-gsoc.org/en/nibba2018s-blog/">here</a>.</p> +</section> +</section> + + + Name: Soham Biswas + + 2020-08-24T00:00:00-04:00 + + + https://fury.gl/posts/2020/2020-08-24-final-work-lenix.html + Google Summer of Code 2020 Final Work Product + 2020-08-24T00:00:00-04:00 + + Lenix Lobo + + <img alt="https://developers.google.com/open-source/gsoc/resources/downloads/GSoC-logo-horizontal.svg" class="align-center" height="50" src="https://developers.google.com/open-source/gsoc/resources/downloads/GSoC-logo-horizontal.svg" /><img alt="https://www.python.org/static/community_logos/python-logo.png" src="https://www.python.org/static/community_logos/python-logo.png" style="width: 40%;" /> +<img alt="https://python-gsoc.org/logos/FURY.png" src="https://python-gsoc.org/logos/FURY.png" style="height: 30px;" /> +<section id="google-summer-of-code-2020-final-work-product"> + +<ul class="simple"> +<li><p><strong>Name:</strong> Lenix Lobo</p></li> +<li><p><strong>Organisation:</strong> Python Software Foundation</p></li> +<li><p><strong>Sub-Organisation:</strong> FURY</p></li> +<li><p><strong>Project:</strong> <a class="reference external" href="https://github.com/fury-gl/fury/wiki/Google-Summer-of-Code-2020">FURY - Improve Shader Framework</a></p></li> +</ul> +<section id="introduction"> +<h2>Introduction</h2> +<p>The current shader framework for FURY is based on VTK and lacks documentation to get started which can be overwhelming for new users. The objective of this project is to enable users to be easily able to understand and use the shader framework to render stunning visual representations of data. The project involves programming vertex and fragment shaders to generate effects for more immersive visualization.</p> +</section> +<section id="proposed-objectives"> +<h2>Proposed Objectives</h2> +<p><strong>Adding SDF actor to the API</strong></p> +<p>This actor uses raymarching to model actors using SDF. The method provides several actors including <cite>ellipsoid</cite>, <cite>sphere</cite> and <cite>torus</cite>. +<strong>Shader demos</strong></p> +<blockquote> +<div><p>Use the FURY shader system to create and visualize different shading algorithms. Implementations include <cite>SphereMap</cite>, <cite>Toon</cite>, <cite>Gooch</cite> and <cite>Vertex Noise</cite></p> +</div></blockquote> +</section> +<section id="unsubmitted-functionalities"> +<h2>Unsubmitted Functionalities</h2> +<p><strong>Spherical Harmonics using Shaders.</strong></p> +<p>The spherical harmonics algorithm is used to generate spherical surfaces using biases and coefficients computed. The general approach to achieve this is computationally expensive. The idea proposed was to leverage the GPU hardware using shaders to provide a faster more efficient alternative to the current implementations. The second month of the coding period was devoted to the same task but unfortunately, the observed performance was quite unsatisfactory than the expected performance. Moreover, the output shape of the geometry was distorted. It was then decided to continue the work after the GSoC period and prioritize the task at hand.</p> +<p>The Work in Progress can be accessed here. <a class="github reference external" href="https://github.com/lenixlobo/fury/tree/Spherical-Harmonics">lenixlobo/fury</a></p> +<p><strong>Dynamic Texture using Geometry Shader</strong></p> +<p>Geometry Shaders provide a lot of flexibility to users to create custom geometry behaviors such as instancing. The idea was to create a dynamic Fur/Hair effect on top of a FURY actor. Unfortunately due to missing documentation on VTK geometry shaders and lack of resources, the project was not completed during the GSoC period. However, I will continue to try to solve the issue.</p> +<p>The source code for the current progress can be accessed here. <a class="github reference external" href="https://github.com/lenixlobo/fury/tree/Dynamic-Texture">lenixlobo/fury</a></p> +</section> +<section id="objectives-completed"> +<h2>Objectives Completed</h2> +<p><strong>SDF based Actor</strong></p> +<blockquote> +<div><p>The objective here was to provide an alternative approach to users to use SDF modeled actors in the scene. This actor is modeled using the raymarching algorithm which provides much better performance than conventional polygon-based actors. Currently, the shapes supported include ellipsoid, sphere and torus</p> +<p><em>Pull Requests:</em> +<strong>SDF Actor method:</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/250">fury-gl/fury#250</a></p> +</div></blockquote> +<p><strong>Multiple SDF Actor</strong></p> +<blockquote> +<div><p>The objective was to create a method through which multiple SDF primitives are rendered within a single cube. This task helped us explore the limitations of the shader system and also benchmarking the performance.</p> +<p><em>Pull Requests:</em> +<strong>MultiSDF Shader:</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/blob/master/docs/experimental/viz_multisdf.py">fury-gl/fury</a></p> +</div></blockquote> +<p><strong>Shader Demos</strong></p> +<blockquote> +<div><p>The task here was to create a pull request showcasing the capabilities of the FURY shader system and to also provide examples or new users to get started with integrating custom shaders into the scenes.</p> +<p><em>Pull Requests:</em> +<strong>Shader Demos:</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/296">fury-gl/fury#296</a></p> +</div></blockquote> +</section> +<section id="other-objectives"> +<h2>Other Objectives</h2> +<ul> +<li><p><strong>Tutorials</strong></p> +<blockquote> +<div><p>Create Tutorials for new users to get familiar with the Shader System</p> +<p><em>Pull Requests:</em> +- <strong>Shader UI Tutorial</strong></p> +<p><a class="github reference external" href="https://github.com/fury-gl/fury/pull/296">fury-gl/fury#296</a></p> +<p>-<strong>SDF Actor Tutorial</strong></p> +<p><a class="github reference external" href="https://github.com/fury-gl/fury/pull/267">fury-gl/fury#267</a></p> +</div></blockquote> +</li> +<li><p><strong>GSoC weekly Blogs</strong></p> +<p>Weekly blogs were added for FURY’s Website.</p> +<p><em>Pull Requests:</em> +- <strong>First &amp; Second Evaluation:</strong></p> +<p><a class="github reference external" href="https://github.com/fury-gl/fury/pull/250">fury-gl/fury#250</a> +<a class="github reference external" href="https://github.com/fury-gl/fury/pull/267">fury-gl/fury#267</a></p> +<ul class="simple"> +<li><p><strong>Third Evaluation:</strong></p></li> +</ul> +<p><a class="github reference external" href="https://github.com/fury-gl/fury/pull/296">fury-gl/fury#296</a></p> +</li> +</ul> +</section> +<section id="timeline"> +<h2>Timeline</h2> +<table class="table"> +<thead> +<tr class="row-odd"><th class="head"><p>Date</p></th> +<th class="head"><p>Description</p></th> +<th class="head"><p>Blog Link</p></th> +</tr> +</thead> +<tbody> +<tr class="row-even"><td><p>Week 1(30-05-2020)</p></td> +<td><p>Welcome to my GSoC Blog!</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/lenixlobos-blog/gsoc-blog-week-1/">Weekly Check-in #1</a></p></td> +</tr> +<tr class="row-odd"><td><p>Week 2(07-06-2020)</p></td> +<td><p>Geometry Shaders!</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/lenixlobos-blog/weekly-check-in-week-2/">Weekly Check-in #2</a></p></td> +</tr> +<tr class="row-even"><td><p>Week 3(14-06-2020)</p></td> +<td><p>Ray Marching!</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/lenixlobos-blog/weekly-check-in-week-3/">Weekly Check-in #3</a></p></td> +</tr> +<tr class="row-odd"><td><p>Week 4(21-06-2020)</p></td> +<td><p>RayMarching Continued</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/lenixlobos-blog/weekly-check-in-week-4/">Weekly Check-in #4</a></p></td> +</tr> +<tr class="row-even"><td><p>Week 5(28-06-2020)</p></td> +<td><p>Spherical Harmonics</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/lenixlobos-blog/weekly-check-in-week-5/">Weekly Check-in #5</a></p></td> +</tr> +<tr class="row-odd"><td><p>Week 6(05-07-2020)</p></td> +<td><p>Spherical Harmonics Continued</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/lenixlobos-blog/weekly-check-in-week-6/">Weekly Check-in #6</a></p></td> +</tr> +<tr class="row-even"><td><p>Week 7(12-07-2020)</p></td> +<td><p>Multiple SDF Primitives</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/lenixlobos-blog/weekly-check-in-week-7/">Weekly Check-in #7</a></p></td> +</tr> +<tr class="row-odd"><td><p>Week 8(19-07-2020)</p></td> +<td><p>Improvements in SDF primitives</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/lenixlobos-blog/weekly-check-in-week-8/">Weekly Check-in #8</a></p></td> +</tr> +<tr class="row-even"><td><p>Week 9(26-07-2020)</p></td> +<td><p>Merging SDF Actor and Benchmarks!</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/lenixlobos-blog/weekly-check-in-week-9/">Weekly Check-in #9</a></p></td> +</tr> +<tr class="row-odd"><td><p>Week 10(02-08-2020)</p></td> +<td><p>More Shaders</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/lenixlobos-blog/weekly-check-in-week-10/">Weekly Check-in #10</a></p></td> +</tr> +<tr class="row-even"><td><p>Week 11(08-08-2020)</p></td> +<td><p>Even More Shaders</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/lenixlobos-blog/weekly-check-in-week-11/">Weekly Check-in #11</a></p></td> +</tr> +<tr class="row-odd"><td><p>Week 12(16-08-2020)</p></td> +<td><p>Picking Outline</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/lenixlobos-blog/weekly-check-in-week-12/">Weekly Check-in #12</a></p></td> +</tr> +<tr class="row-even"><td><p>Week 13(23-08-2020)</p></td> +<td><p>Final Week</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/lenixlobos-blog/weekly-check-in-week-13/">Weekly Check-in #13</a></p></td> +</tr> +</tbody> +</table> +<p>Detailed weekly tasks and work done can be found +<a class="reference external" href="https://blogs.python-gsoc.org/en/lenixlobos-blog/">here</a>.</p> +</section> +</section> + + + Name: Lenix Lobo + + 2020-08-24T00:00:00-04:00 + + + https://fury.gl/posts/2020/2020-08-23-week-13-soham.html + Part of the Journey is the end unless its Open Source! + 2020-08-23T00:00:00-04:00 + + Soham Biswas + + <section id="part-of-the-journey-is-the-end-unless-its-open-source"> + +<p>Hello and welcome to my final weekly check-in. Today officially marks the end of the coding period for GSoC 2020. I enjoyed every bit of it. This was a life-changing experience for me and now I observe and interpret everything from a different perspective altogether. I have grown into a better developer and a person since GSoC. I would like to thank all my mentors and especially Serge for his immense support and mentorship. I would love to contribute to fury even after GSoC is over but unfortunately my semester break is over so I won’t be as active as I was during the summer.</p> +<p>Now, regarding work I will be sharing my progress with the File Dialog UI component. The official repository of my sub-org can be found <a class="reference external" href="https://github.com/fury-gl/fury/">here</a>.</p> +<section id="what-did-you-do-this-week"> +<h2>What did you do this week?</h2> +<p>This week I worked on the File Dialog UI component. Fury previously had a FileMenu component which could browse through the file system but we needed a dialog like implementation for it so that its easier for the users to read and write files during runtime. I tried implementing a simple design for it. It specifically has two modes, one for saving files and the other for writing files. The implementation can be demonstrated as follows:</p> +<section id="open-dialog"> +<h3>Open Dialog:</h3> +<img alt="https://user-images.githubusercontent.com/29832615/90978632-df12c780-e56c-11ea-8517-6243ea06bdd2.gif" src="https://user-images.githubusercontent.com/29832615/90978632-df12c780-e56c-11ea-8517-6243ea06bdd2.gif" /> +</section> +<section id="save-dialog"> +<h3>Save Dialog:</h3> +<img alt="https://user-images.githubusercontent.com/29832615/90978638-eafe8980-e56c-11ea-835a-3a82ccee2973.gif" src="https://user-images.githubusercontent.com/29832615/90978638-eafe8980-e56c-11ea-835a-3a82ccee2973.gif" /> +</section> +</section> +<section id="what-is-coming-up-next-week"> +<h2>What is coming up next week?</h2> +<p>Next week I will start with my final GSoC documentation and code submission. I will also try to implement the tests and tutorials for File Dialog or any further changes requested by my mentors. If I am not able to finish it within the next week, I will get it done after GSoC.</p> +</section> +<section id="did-you-get-stuck-anywhere"> +<h2>Did you get stuck anywhere?</h2> +<p>I did not face any major issues this week.</p> +<p><code class="docutils literal notranslate"><span class="pre">Thank</span> <span class="pre">you</span> <span class="pre">all</span> <span class="pre">for</span> <span class="pre">your</span> <span class="pre">love</span> <span class="pre">and</span> <span class="pre">support.</span> <span class="pre">❤️😄</span></code></p> +</section> +</section> + + + Hello and welcome to my final weekly check-in. Today officially marks the end of the coding period for GSoC 2020. I enjoyed every bit of it. This was a life-changing experience for me and now I observe and interpret everything from a different perspective altogether. I have grown into a better developer and a person since GSoC. I would like to thank all my mentors and especially Serge for his immense support and mentorship. I would love to contribute to fury even after GSoC is over but unfortunately my semester break is over so I won’t be as active as I was during the summer. + + 2020-08-23T00:00:00-04:00 + + + https://fury.gl/posts/2020/2020-08-18-release-announcement.html + FURY 0.6.1 Released + 2020-08-18T00:00:00-04:00 + + Serge Koudoro + + <section id="fury-0-6-1-released"> + +<p>The FURY project is happy to announce the release of FURY 0.6.1! +FURY is a free and open source software library for scientific visualization and 3D animations.</p> +<p>You can show your support by <a class="reference external" href="https://github.com/fury-gl/fury/stargazers">adding a star</a> on FURY github project.</p> +<p>This Release is mainly a maintenance release. The <strong>major highlights</strong> of this release are:</p> +<ul class="simple"> +<li><p>Added Shaders Manager.</p></li> +<li><p>Standardized colors across API.</p></li> +<li><p>Added a new UI Tab.</p></li> +<li><p>Added Physics Engine Tutorial.</p></li> +<li><p>Large documentation update, examples and tutorials (4 new).</p></li> +<li><p>Increased tests coverage and code quality.</p></li> +</ul> +<div class="admonition note"> +<p class="admonition-title">Note</p> +<p>The complete release notes are available <a class="reference internal" href="../release_notes/releasev0.6.1.html#releasev0-6-1"><span class="std std-ref">here</span></a></p> +</div> +<p><strong>To upgrade or install FURY</strong></p> +<p>Run the following command in your terminal:</p> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">pip</span> <span class="n">install</span> <span class="o">--</span><span class="n">upgrade</span> <span class="n">fury</span> +</pre></div> +</div> +<p>or:</p> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">conda</span> <span class="n">install</span> <span class="o">-</span><span class="n">c</span> <span class="n">conda</span><span class="o">-</span><span class="n">forge</span> <span class="n">fury</span> +</pre></div> +</div> +<p><strong>Questions or suggestions?</strong></p> +<p>For any questions go to <a class="reference external" href="http://fury.gl">http://fury.gl</a>, or send an e-mail to <a class="reference external" href="mailto:fury&#37;&#52;&#48;python&#46;org">fury<span>&#64;</span>python<span>&#46;</span>org</a> +We can also join our <a class="reference external" href="https://discord.gg/6btFPPj">discord community</a></p> +<p>We would like to thanks to <a class="reference internal" href="../community.html#community"><span class="std std-ref">all contributors</span></a> for this release:</p> +<ul class="simple"> +<li><p>Eleftherios Garyfallidis</p></li> +<li><p>Javier Guaje</p></li> +<li><p>Lenix Lobo</p></li> +<li><p>Melina Raglin</p></li> +<li><p>Nasim Anousheh</p></li> +<li><p>Serge Koudoro</p></li> +<li><p>Soham Biswas</p></li> +<li><p>Vivek Choudhary</p></li> +</ul> +<p>On behalf of the <a class="reference internal" href="../community.html#community"><span class="std std-ref">FURY developers</span></a>,</p> +<p>Serge K.</p> +</section> + + + The FURY project is happy to announce the release of FURY 0.6.1! +FURY is a free and open source software library for scientific visualization and 3D animations. + + 2020-08-18T00:00:00-04:00 + + + https://fury.gl/posts/2020/2020-08-17-week-12-lenix.html + Outline Picker + 2020-08-17T00:00:00-04:00 + + Lenix Lobo + + <section id="outline-picker"> + +<p>Make sure to check out Project <a class="reference external" href="https://github.com/fury-gl/fury">FURY</a></p> +<p>Hey ! +This week, Picking Outline!</p> +<section id="what-did-you-do-this-week"> +<h2>What did you do this week?</h2> +<p>We needed a Outline feature in FURY to indicate which model we choose in the scene. So the task assigned was to find options to achieve this. There were two ways to do this, 1. Using shader and 2. Using Vtk PolyData Silhouette. Despite trying multiple implementation methods the shader approach was not working . I also tried using VTKs inbuilt function , but there is a bug when i use some models. When i choose a model, it renders outline for every polygon , which is not what we want to achieve. The bug is shown below:</p> +<p>Below are the outputs of the techniques i worked on :</p> +<img alt="https://raw.githubusercontent.com/lenixlobo/fury-outputs/master/blog-week-12.gif" src="https://raw.githubusercontent.com/lenixlobo/fury-outputs/master/blog-week-12.gif" /> +<p>The shader demos are available <a class="reference external" href="https://github.com/lenixlobo/fury/tree/shader-demos">here</a></p> +</section> +<section id="what-is-coming-up-next-week"> +<h2>What is coming up next week?</h2> +<p>With the end of GSoC approaching soon, the next task is to create a PR which can help new users to test different shaders using UI to get started.</p> +</section> +<section id="did-you-get-stuck-anywhere"> +<h2>Did you get stuck anywhere?</h2> +<p>I still was not able to figure out how we can achieve the outline effect. Am currently looking into other approaches we could use</p> +</section> +</section> + + + Make sure to check out Project FURY + + 2020-08-17T00:00:00-04:00 + + + https://fury.gl/posts/2020/2020-08-16-week-12-soham.html + Wrecking Ball Simulation, Scrollbars Update, Physics Tutorials. + 2020-08-16T00:00:00-04:00 + + Soham Biswas + + <section id="wrecking-ball-simulation-scrollbars-update-physics-tutorials"> + +<p>Hello and welcome to my 12th weekly check-in. In this blog I will be discussing my progress with the wrecking ball simulation and my scrollbar separation work. Apart from this I have also finalized the physics simulation tutorials and have created a Pull Request to finally get it merged with the official repository. The official repository of my sub-org can be found <a class="reference external" href="https://github.com/fury-gl/fury/">here</a>.</p> +<section id="what-did-you-do-this-week"> +<h2>What did you do this week?</h2> +<p>This week I was mainly focusing on the wrecking ball simulation. This simulation is basically the combination of chain simulation and brick wall simulation. A sphere attached to a chain smashes a “NxNxN” brick wall. The simulation is as follows:</p> +<img alt="https://user-images.githubusercontent.com/29832615/90336291-84232280-dff8-11ea-869b-21a99b203c31.gif" src="https://user-images.githubusercontent.com/29832615/90336291-84232280-dff8-11ea-869b-21a99b203c31.gif" /> +<p>There’s a rendering bug with the cylinders because of which the chain segments look weird. My mentors confirmed that this bug originated from VTK’s <cite>cylinder source</cite> method and they are currently working on it to fix it. The simulation will render correctly once that bug is fixed.</p> +<p>Regarding the scrollbar separation task, I was able to fix those callback issues that I was facing. The mouse callbacks on the scrollbar now work correctly:</p> +<img alt="https://user-images.githubusercontent.com/29832615/90337280-1af2dd80-dfff-11ea-94c4-508121307583.gif" src="https://user-images.githubusercontent.com/29832615/90337280-1af2dd80-dfff-11ea-94c4-508121307583.gif" /> +<p>I have also created a pull request to add the following physics simulations with proper documentation to the main repository:</p> +<ul class="simple"> +<li><p>Brick Wall Simulation</p></li> +<li><p>Ball Collision Simulation</p></li> +<li><p>Chain Simulation</p></li> +<li><p>Wrecking Ball Simulation</p></li> +</ul> +</section> +<section id="what-is-coming-up-next-week"> +<h2>What is coming up next week?</h2> +<p>Currently I am a bit confused with the implementation of scrollbars with UI components. I had a meeting with my mentor and he decided to help me out with this. So most probably I will be working with the scrollbar component and its implementation. Next week will also be the final week for GSoC 2020 before the evaluations start so I would work on getting the final documentation and formalities ready.</p> +</section> +<section id="did-you-get-stuck-anywhere"> +<h2>Did you get stuck anywhere?</h2> +<p>Apart from the scrollbar implementation idea, I did not face any major issues.</p> +<p><code class="docutils literal notranslate"><span class="pre">Thank</span> <span class="pre">you</span> <span class="pre">for</span> <span class="pre">reading,</span> <span class="pre">see</span> <span class="pre">you</span> <span class="pre">next</span> <span class="pre">week!!</span></code></p> +</section> +</section> + + + Hello and welcome to my 12th weekly check-in. In this blog I will be discussing my progress with the wrecking ball simulation and my scrollbar separation work. Apart from this I have also finalized the physics simulation tutorials and have created a Pull Request to finally get it merged with the official repository. The official repository of my sub-org can be found here. + + 2020-08-16T00:00:00-04:00 + + + https://fury.gl/posts/2020/2020-08-09-week-11-lenix.html + More Shaders!! + 2020-08-09T00:00:00-04:00 + + Lenix Lobo + + <section id="more-shaders"> + +<p>Make sure to check out Project <a class="reference external" href="https://github.com/fury-gl/fury">FURY</a></p> +<p>Hey ! +This week, More Shaders!</p> +<section id="what-did-you-do-this-week"> +<h2>What did you do this week?</h2> +<p>The task assigned for this week was to explore more shader techniques which could be implemented using FURY and which would demonstrate the capability of FURY shader system. So i decided to work on implementing shading examples such as Gooch shading and reflection shader using textures.</p> +<p>Below are the outputs of the techniques i worked on :</p> +<img alt="https://raw.githubusercontent.com/lenixlobo/fury-outputs/master/blog-week-11a.gif" src="https://raw.githubusercontent.com/lenixlobo/fury-outputs/master/blog-week-11a.gif" /> +<img alt="https://raw.githubusercontent.com/lenixlobo/fury-outputs/master/blog-week-11b.gif" src="https://raw.githubusercontent.com/lenixlobo/fury-outputs/master/blog-week-11b.gif" /> +<img alt="https://raw.githubusercontent.com/lenixlobo/fury-outputs/master/blog-week-11c.gif" src="https://raw.githubusercontent.com/lenixlobo/fury-outputs/master/blog-week-11c.gif" /> +<p>The shader demos are available <a class="reference external" href="https://github.com/lenixlobo/fury/tree/shader-demos">here</a></p> +</section> +<section id="what-is-coming-up-next-week"> +<h2>What is coming up next week?</h2> +<p>The next week will involve working on more such demos which can demonstrate the capabilities of FURY</p> +</section> +<section id="did-you-get-stuck-anywhere"> +<h2>Did you get stuck anywhere?</h2> +<p>No issues were faced this week</p> +</section> +</section> + + + Make sure to check out Project FURY + + 2020-08-09T00:00:00-04:00 + + + https://fury.gl/posts/2020/2020-08-09-week-11-soham.html + Chain Simulation, Scrollbar Refactor, Tutorial Update. + 2020-08-09T00:00:00-04:00 + + Soham Biswas + + <section id="chain-simulation-scrollbar-refactor-tutorial-update"> + +<p>Hello and welcome to my 11th weekly check-in. In this blog I will be discussing my progress with multiple topics related to physics and ui components. I was actively working on a couple of things, specifically Joint simulations in pyBullet and scrollbar UI component. I also took up the responsibility to complete an incomplete Pull Request which was pending for quite a while. The official repository of my sub-org can be found <a class="reference external" href="https://github.com/fury-gl/fury/">here</a>.</p> +<section id="what-did-you-do-this-week"> +<h2>What did you do this week?</h2> +<p>The first thing that I did this week was to figure out joint simulations in pybullet. Due to lack of proper documentation I was not aware that Joints are kept stiff by default, hence I had no idea what was wrong with my simulations. Thankfully, while I was browsing pybullet forums, I found this <a class="reference external" href="https://pybullet.org/Bullet/phpBB3/viewtopic.php?f=24&amp;t=13035">post</a> regarding rope simulations when I realized that I had to explicitly set the friction force to prevent stiffness among the Joints. Keeping this point in mind I was able to simulate the following Chain of hexagonal prisms:</p> +<img alt="https://user-images.githubusercontent.com/29832615/89737601-b7613100-da8f-11ea-947f-a96c66caefae.gif" src="https://user-images.githubusercontent.com/29832615/89737601-b7613100-da8f-11ea-947f-a96c66caefae.gif" /> +<p>This week I was mainly supposed to work on refactoring scrollbars as a standalone component. I have made some progress for now. I am able to render the scrollbars properly, with proper size, orientation and color but I am having some issues regarding its scrolling callbacks. I need to look further into it. Here’s a brief glimpse:</p> +<img alt="https://user-images.githubusercontent.com/29832615/89738159-28a2e300-da94-11ea-9167-e825f82edf98.png" src="https://user-images.githubusercontent.com/29832615/89738159-28a2e300-da94-11ea-9167-e825f82edf98.png" /> +<p>This particular <a class="reference external" href="https://github.com/fury-gl/fury/pull/208">PR</a> by a fellow contributor was pending for quite a while, so I decided to look into it and complete it. The objective of the PR was to add examples for the <code class="docutils literal notranslate"><span class="pre">CheckBox</span></code> and <code class="docutils literal notranslate"><span class="pre">RadioButton</span></code> UI components, but the problem was that the objects were not rendered using FURY API in the tutorial, so I decided to complete that. It was already a well made tutorial. I only had to replace the appropriate functions with FURY’s API calls.</p> +<p>The <code class="docutils literal notranslate"><span class="pre">CheckBox</span></code> tutorial:</p> +<img alt="https://user-images.githubusercontent.com/29832615/89438967-20326b80-d767-11ea-8f47-e7711e900c9f.gif" src="https://user-images.githubusercontent.com/29832615/89438967-20326b80-d767-11ea-8f47-e7711e900c9f.gif" /> +<p>There’s still some internal issues while updating the colors of the cube which is currently being worked on by my mentors.</p> +<p>The <code class="docutils literal notranslate"><span class="pre">RadioButton</span></code> tutorial:</p> +<img alt="https://user-images.githubusercontent.com/29832615/89438999-2e808780-d767-11ea-8b08-2a36a05294bc.gif" src="https://user-images.githubusercontent.com/29832615/89438999-2e808780-d767-11ea-8b08-2a36a05294bc.gif" /> +</section> +<section id="what-is-coming-up-next-week"> +<h2>What is coming up next week?</h2> +<p>Next week I will continue working on the scrollbar component and try to fix the issues that I am having with its callbacks. I will also try to work on the wrecking ball simulation.</p> +</section> +<section id="did-you-get-stuck-anywhere"> +<h2>Did you get stuck anywhere?</h2> +<p>Apart from the scrollbar callbacks and stiff joints, I did not face any major issues.</p> +<p><code class="docutils literal notranslate"><span class="pre">Thank</span> <span class="pre">you</span> <span class="pre">for</span> <span class="pre">reading,</span> <span class="pre">see</span> <span class="pre">you</span> <span class="pre">next</span> <span class="pre">week!!</span></code></p> +</section> +</section> + + + Hello and welcome to my 11th weekly check-in. In this blog I will be discussing my progress with multiple topics related to physics and ui components. I was actively working on a couple of things, specifically Joint simulations in pyBullet and scrollbar UI component. I also took up the responsibility to complete an incomplete Pull Request which was pending for quite a while. The official repository of my sub-org can be found here. + + 2020-08-09T00:00:00-04:00 + + + https://fury.gl/posts/2020/2020-08-02-week-10-soham.html + Single Actor, Physics, Scrollbars. + 2020-08-02T00:00:00-04:00 + + Soham Biswas + + <section id="single-actor-physics-scrollbars"> + +<p>Hello and welcome to my 10th weekly check-in. Second evaluation ended this week and now we move on to our 3rd and final coding period. In today’s check-in I will be sharing my progress with the single actor physics simulation that I facing some issues with and I will also be discussing my future plans regarding UI components. The official repository of my sub-org, FURY can always be found <a class="reference external" href="https://github.com/fury-gl/fury/">here</a>.</p> +<section id="what-did-you-do-this-week"> +<h2>What did you do this week?</h2> +<p>This week I was able to figure out the uncontrollable spinning problem that I was facing while rendering physics simulations. Specifically the simulation where a brick wall was rendered by a single actor. The spinning problem was as follows:</p> +<img alt="https://user-images.githubusercontent.com/29832615/88485303-87476780-cf92-11ea-850c-cc63e1376ef8.gif" src="https://user-images.githubusercontent.com/29832615/88485303-87476780-cf92-11ea-850c-cc63e1376ef8.gif" /> +<p>Here’s how the fixed simulation looks like:</p> +<img alt="https://user-images.githubusercontent.com/29832615/89126963-946ed400-d507-11ea-93cd-aad3a9f59ab0.gif" src="https://user-images.githubusercontent.com/29832615/89126963-946ed400-d507-11ea-93cd-aad3a9f59ab0.gif" /> +<p>I was facing this particular issue because I was directly syncing the orientation of the objects in pyBullet world to the objects in the Fury world. So I decided to apply the change in orientation instead and it worked. In order to achieve this I had to keep track of the bricks’ orientation at each step of the simulation, sync the change and then update the tracked orientation. Thankfully, pybullet had convenient tools to achieve this. Here’s a snippet on how to update individual objects rendered by a single actor:</p> +<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">sync_brick</span><span class="p">(</span><span class="n">object_index</span><span class="p">,</span> <span class="n">multibody</span><span class="p">):</span> + <span class="n">pos</span><span class="p">,</span> <span class="n">orn</span> <span class="o">=</span> <span class="n">p</span><span class="o">.</span><span class="n">getBasePositionAndOrientation</span><span class="p">(</span><span class="n">multibody</span><span class="p">)</span> + + <span class="n">rot_mat</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">reshape</span><span class="p">(</span> + <span class="n">p</span><span class="o">.</span><span class="n">getMatrixFromQuaternion</span><span class="p">(</span> + <span class="n">p</span><span class="o">.</span><span class="n">getDifferenceQuaternion</span><span class="p">(</span><span class="n">orn</span><span class="p">,</span> <span class="n">brick_orns</span><span class="p">[</span><span class="n">object_index</span><span class="p">])),</span> + <span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="mi">3</span><span class="p">))</span> + + <span class="n">vertices</span><span class="p">[</span><span class="n">object_index</span> <span class="o">*</span> <span class="n">sec</span><span class="p">:</span> <span class="n">object_index</span> <span class="o">*</span> <span class="n">sec</span> <span class="o">+</span> <span class="n">sec</span><span class="p">]</span> <span class="o">=</span> \ + <span class="p">(</span><span class="n">vertices</span><span class="p">[</span><span class="n">object_index</span> <span class="o">*</span> <span class="n">sec</span><span class="p">:</span> <span class="n">object_index</span> <span class="o">*</span> <span class="n">sec</span> <span class="o">+</span> <span class="n">sec</span><span class="p">]</span> <span class="o">-</span> + <span class="n">brick_centers</span><span class="p">[</span><span class="n">object_index</span><span class="p">])</span><span class="nd">@rot_mat</span> <span class="o">+</span> <span class="n">pos</span> + + <span class="n">brick_centers</span><span class="p">[</span><span class="n">object_index</span><span class="p">]</span> <span class="o">=</span> <span class="n">pos</span> + <span class="n">brick_orns</span><span class="p">[</span><span class="n">object_index</span><span class="p">]</span> <span class="o">=</span> <span class="n">orn</span> +</pre></div> +</div> +<p>All the necessary information is updated <a class="reference external" href="https://docs.google.com/document/d/1XJcG1TL5ZRJZDyi8V76leYZt_maxGp0kOB7OZIxKsTA/edit?usp=sharing">here</a>.</p> +</section> +<section id="what-is-coming-up-next-week"> +<h2>What is coming up next week?</h2> +<p>Currently, the scrollbars are native to <code class="docutils literal notranslate"><span class="pre">ListBox2D</span></code> only. We are planning to separate scrollbars from <code class="docutils literal notranslate"><span class="pre">ListBox2D</span></code> to create a standalone UI component. This was in progress previously but was later discontinued, so I was given the responsibility to complete it. After this we plan to improve File Dialog capabilities later on.</p> +</section> +<section id="did-you-get-stuck-anywhere"> +<h2>Did you get stuck anywhere?</h2> +<p>I did not face any major issues but it took me some time to understand and evaluate the existing discontinued <a class="reference external" href="https://github.com/fury-gl/fury/pull/222">PR</a> regarding scrollbar separation.</p> +<p><code class="docutils literal notranslate"><span class="pre">Thank</span> <span class="pre">you</span> <span class="pre">for</span> <span class="pre">reading,</span> <span class="pre">see</span> <span class="pre">you</span> <span class="pre">next</span> <span class="pre">week!!</span></code></p> +</section> +</section> + + + Hello and welcome to my 10th weekly check-in. Second evaluation ended this week and now we move on to our 3rd and final coding period. In today’s check-in I will be sharing my progress with the single actor physics simulation that I facing some issues with and I will also be discussing my future plans regarding UI components. The official repository of my sub-org, FURY can always be found here. + + 2020-08-02T00:00:00-04:00 + + diff --git a/v0.10.x/blog/2021.html b/v0.10.x/blog/2021.html new file mode 100644 index 000000000..b43ba617c --- /dev/null +++ b/v0.10.x/blog/2021.html @@ -0,0 +1,3278 @@ + + + + + + + Posted in 2021 — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +
+

+ + Posted in + + 2021 + +

+ + +
+

+ Google Summer of Code Final Work Product +

+
    +
  • + + + 23 August 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Antriksh Misri + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Name: Antriksh Misri

+

+ +

Read more ...

+
+
+ +
+

+ Google Summer of Code Final Work Product +

+
    +
  • + + + 23 August 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Sajag Swami + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Name: Sajag Swami

+

+ +

Read more ...

+
+
+ +
+

+ Google Summer of Code 2021 - Final Report - Bruno Messias +

+
    +
  • + + + 23 August 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Bruno Messias + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

We have changed some points of my project in the first meeting. +Specifically, we focused the efforts into developing a streaming system +using the WebRTC protocol that could be used in more generic scenarios +than just the network visualization. In addition to that, we have opted +to develop the network visualization for fury as a separated repository +and package available here. The +name Helios was selected for this new network visualization system based +on the Fury rendering pipeline.

+

+ +

Read more ...

+
+
+ +
+

+ Week #11: Removing the flickering effect +

+
    +
  • + + + 16 August 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Bruno Messias + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

PR fury-gl/fury#489:

+

+ +

Read more ...

+
+
+ +
+

+ Week #11: Finalizing open Pull Requests +

+
    +
  • + + + 16 August 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Antriksh Misri + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Below are the tasks that I worked on:

+

+ +

Read more ...

+
+
+ +
+

+ Tenth coding week! +

+
    +
  • + + + 16 August 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Sajag Swami + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Welcome to the eleventh weekly check-in. I’ll be sharing my progress for the tenth week of coding.

+

+ +

Read more ...

+
+
+ +
+

+ Week#10: Accordion UI, Support for sprite sheet animations +

+
    +
  • + + + 09 August 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Antriksh Misri + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Below are the tasks that I worked on:

+

+ +

Read more ...

+
+
+ +
+

+ Week #10: SDF Fonts +

+
    +
  • + + + 09 August 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Bruno Messias + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

PR fury-gl/helios#22 +: Helios Documentation +Improvements.

+

+ +

Read more ...

+
+
+ +
+

+ Ninth coding week! +

+
    +
  • + + + 09 August 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Sajag Swami + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Welcome to the tenth weekly check-in. I’ll be sharing my progress for the ninth week of coding.

+

+ +

Read more ...

+
+
+ +
+

+ FURY 0.7.0 Released +

+
    +
  • + + + 03 August 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Serge Koudoro + + + +
  • + + + + +
  • + + + Category: + + + + + release + + + +
  • + + +
  • + + + + Tag: + + + + + fury + + + +
  • + + +
    +
+

The FURY project is happy to announce the release of FURY 0.7.1! +FURY is a free and open source software library for scientific visualization and 3D animations.

+

+ +

Read more ...

+
+
+ +
+

+ Week #9: More Layouts! +

+
    +
  • + + + 02 August 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Antriksh Misri + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Below are the tasks that I worked on:

+

+ +

Read more ...

+
+
+ +
+

+ Week #09: Sphinx custom summary +

+
    +
  • + + + 02 August 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Bruno Messias + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

PR fury-gl/helios#22 +: Helios Documentation +Improvements. +I’ve spent some time studying sphinx in order to discover how I could create a +custom summary inside of a template module.

+

+ +

Read more ...

+
+
+ +
+

+ Eighth coding week! +

+
    +
  • + + + 02 August 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Sajag Swami + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Welcome to the ninth weekly check-in. I’ll be sharing my progress for the eighth week of coding.

+

+ +

Read more ...

+
+
+ +
+

+ Weekly Check-In #8 +

+
    +
  • + + + 26 July 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Bruno Messias + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

PR fury-gl/helios#18 (merged): Helios Documentation/ +I’ve been working on Helios documentation. Now it’s available +online at https://fury-gl.github.io/helios-website image1

+

+ +

Read more ...

+
+
+ +
+

+ Week #8: Code Cleanup, Finishing up open PRs, Continuing work on Tree2D +

+
    +
  • + + + 26 July 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Antriksh Misri + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week I had to work on the open PRs specifically work on the bugs that were pointed out in last week’s meeting. Along side the bugs I had to continue the work on Tree2D UI element. Below is the detailed description of what I worked on this week:

+

+ +

Read more ...

+
+
+ +
+

+ Seventh week of coding! +

+
    +
  • + + + 26 July 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Sajag Swami + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Welcome to the eighth weekly check-in. I’ll be sharing my progress for the seventh week of coding.

+

+ +

Read more ...

+
+
+ +
+

+ Weekly Check-In #7 +

+
    +
  • + + + 19 July 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Bruno Messias + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

PR fury-gl/helios#16 +(merged): Helios IPC +network layout support for MacOs

+

+ +

Read more ...

+
+
+ +
+

+ Week #7: Finalizing the stalling PRs, finishing up Tree2D UI. +

+
    +
  • + + + 19 July 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Antriksh Misri + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week I had limited tasks to do, mostly tasks related to existing PRs. Other than some minor fixes I had to implement some more things in Tree2D which included some minor UI fixes, some changes in tutorial, adding tests. Below is the detailed description of what I worked on this week:

+

+ +

Read more ...

+
+
+ +
+

+ Sixth week of coding! +

+
    +
  • + + + 19 July 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Sajag Swami + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Welcome to the seventh weekly check-in. I’ll be sharing my progress for the sixth week of coding.

+

+ +

Read more ...

+
+
+ +
+

+ Week #6: Bug fixes, Working on Tree2D UI +

+
    +
  • + + + 12 July 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Antriksh Misri + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week I had relatively few tasks and most of them were to fix some bugs/design flaws that were discussed in last week’s meeting. Other than that, I had to implement a few things in the Tree2D UI element that will be discussed in detail below. I also had to update some existing PRs in order to make things work well. Below are the list of things I worked on this week:

+

+ +

Read more ...

+
+
+ +
+

+ Network layout algorithms using IPC +

+
    +
  • + + + 12 July 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Bruno Messias + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hi all. In the past weeks, I’ve been focusing on developing Helios; the +network visualization library for FURY. I improved the visual aspects of +the network rendering as well as implemented the most relevant network +layout methods.

+

+ +

Read more ...

+
+
+ +
+

+ Fifth week of coding! +

+
    +
  • + + + 12 July 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Sajag Swami + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Welcome to the sixth weekly check-in. I’ll be sharing my progress for the fifth week of coding.

+

+ +

Read more ...

+
+
+ +
+

+ Weekly Check-In #5 +

+
    +
  • + + + 05 July 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Bruno Messias + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Before the 8c670c2 commit, for some versions of MacOs the +streaming system was falling in a silent bug. I’ve spent a lot of +time researching to found a cause for this. Fortunately, I could found +the cause and the solution. This troublesome MacOs was falling in a +silent bug because the SharedMemory Object was creating a memory +resource with at least 4086 bytes independent if I’ve requested less +than that. If we look into the MultiDimensionalBuffer Object +(stream/tools.py) before the 8c670c2 commit we can see that Object +has max_size parameter which needs to be updated if the SharedMemory +was created with a “wrong” size.

+

+ +

Read more ...

+
+
+ +
+

+ Week #5: Rebasing all PRs w.r.t the UI restructuring, Tree2D, Bug Fixes +

+
    +
  • + + + 05 July 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Antriksh Misri + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

The UI restructuring was finally merged this week. This means UI is now a submodule in itself and provides different UI elements based on their types which are, core, elements, containers and some helper methods/classes. So, this week my main tasks were to rebase and fix merge conflicts of my open PR’s. Other than that, I had to continue my work on Tree2D UI element and finish the remaining aspects of it. Also, I had to create an example demonstrating how to use the newly added UI element. Many use cases were discussed in the open meeting like, an image gallery which displays preview image on the title and when expanded reveals the full scale image. I am thinking of adding multiple examples for the Tree2D to brainstorm on its certain features. Also, I had this annoying bug in Panel2D which didn’t allow it to be resized from the bottom right corner. It was resizing from the top right corner. I had to address this bug as well. Below are the tasks in detail:

+

+ +

Read more ...

+
+
+ +
+

+ SOLID, monkey patching a python issue and network visualization through WebRTC +

+
    +
  • + + + 05 July 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Bruno Messias + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

These past two weeks I’ve spent most of my time in the Streaming System +PR and the Network Layout +PR . In this post I’ll +focus on the most relevant things I’ve made for those PRs.

+

+ +

Read more ...

+
+
+ +
+

+ Fourth week of coding! +

+
    +
  • + + + 05 July 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Sajag Swami + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Welcome to the fifth weekly check-in. I’ll be sharing my progress for the fourth week of coding.

+

+ +

Read more ...

+
+
+ +
+

+ Week #4: Adding Tree UI to the UI module +

+
    +
  • + + + 28 June 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Antriksh Misri + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week I had very few tasks to do, almost all of them revolved around UI elements and adding stuff to the UI module. Earlier, it was pointed out that due to some design issues, importing certain modules into others caused circular imports which led to importing the specific modules inside a class/method which is not the best approach. This will be resolved as soon as the PR that fixes this issue is reviewed/merged in the codebase. In the meantime, all the PR’s related to UI will be on hold, which is why this I had few tasks this week. The tasks are described below in detail:

+

+ +

Read more ...

+
+
+ +
+

+ Third week of coding! +

+
    +
  • + + + 28 June 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Sajag Swami + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Welcome to the fourth weekly check-in. I’ll be sharing my progress for the third week of coding.

+

+ +

Read more ...

+
+
+ +
+

+ Weekly Check-In #3 +

+
    +
  • + + + 21 June 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Bruno Messias + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

PR fury-gl/fury#422 +(merged): +Integrated the 3d impostor spheres with the marker actor.

+

+ +

Read more ...

+
+
+ +
+

+ Week #3: Adapting GridLayout to work with UI +

+
    +
  • + + + 21 June 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Antriksh Misri + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week my tasks revolved around layout and UI elements. The primary goal for this week was to adapt the GridLayout to work with different UI elements. Currently, GridLayout just supports vtk actors and not UI elements, my task was to modify the class to support UI elements. The other tasks for this week are described below in detail:

+

+ +

Read more ...

+
+
+ +
+

+ Second week of coding! +

+
    +
  • + + + 21 June 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Sajag Swami + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Welcome to the third weekly check-in. I’ll be sharing my progress for the second week of coding.

+

+ +

Read more ...

+
+
+ +
+

+ First week of coding! +

+
    +
  • + + + 14 June 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Sajag Swami + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Welcome to the second weekly check-in. I’ll be sharing my progress for the first week of coding.

+

+ +

Read more ...

+
+
+ +
+

+ Week #2: Feature additions in UI and IO modules +

+
    +
  • + + + 13 June 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Antriksh Misri + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week I had to work on 3 PRs as well as some documentation. I really enjoyed this week’s work as the tasks were really interesting. The aim for these PRs were to actually add a couple of features in the UI as well as the IO module, which includes, adding support for border in Panel2D, adding support for network/URL images in load_image method in IO module, adding resizing Panel2D from bottom right corner, completing the document with layout solutions provided by Unity/Unreal engine. Below are the PRs that I worked on:

+

+ +

Read more ...

+
+
+ +
+

+ A Stadia-like system for data visualization +

+
    +
  • + + + 13 June 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Bruno Messias + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hi all! In this post I’ll talk about the PR +#437.

+

+ +

Read more ...

+
+
+ +
+

+ Welcome to my GSoC Blog! +

+
    +
  • + + + 08 June 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Sajag Swami + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hi all! +I’m Sajag Swami, a sophomore at Indian Institute of Technology, Roorkee. This summer, I will be working on adding a new functionality to FURY which shall enable users to +visualise various types of proteins via different representations like Richardson aka Ribbon diagrams and molecular surface diagrams. +As a part of my stretch goals, I’ll try to expand protein diagrams via other representations including:

+

+ +

Read more ...

+
+
+ +
+

+ Weekly Check-In #1 +

+
    +
  • + + + 08 June 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Bruno Messias + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hi everyone! My name is Bruno Messias currently I’m a Ph.D student at +USP/Brazil. In this summer I’ll develop new tools and features for +FURY-GL. Specifically, I’ll focus into developing a system for +collaborative visualization of large network layouts using FURY and VTK.

+

+ +

Read more ...

+
+
+ +
+

+ Week #1: Welcome to my weekly Blogs! +

+
    +
  • + + + 08 June 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Antriksh Misri + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hi everyone! I am Antriksh Misri. I am a Pre-Final year student at MIT Pune. This summer, I will be working on Layout Management under FURY’s UI module as my primary goal. This includes addition of different classes under Layout Management to provide different layouts/arrangements in which the UI elements can be arranged. As my stretch goals, I will be working on a couple of UI components for FURY’s UI module. These 2D and 3D components will be sci-fi like as seen in the movie “Guardians of The Galaxy”. My objective for the stretch goals would be to develop these UI components with their respective test and tutorials such that it adds on to the UI module of FURY and doesn’t hinder existing functionalities/performance.

+

+ +

Read more ...

+
+
+ +
+

+ FURY 0.7.0 Released +

+
    +
  • + + + 13 March 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Serge Koudoro + + + +
  • + + + + +
  • + + + Category: + + + + + release + + + +
  • + + +
  • + + + + Tag: + + + + + fury + + + +
  • + + +
    +
+

The FURY project is happy to announce the release of FURY 0.7.0! +FURY is a free and open source software library for scientific visualization and 3D animations.

+

+ +

Read more ...

+
+
+ +
+

+ Google Summer of Code +

+
    +
  • + + + 09 March 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Serge Koudoro + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

FURY is participating in the Google Summer of Code 2021 under the umbrella of the Python Software Foundation.

+

+ +

Read more ...

+
+
+ + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/blog/2021/atom.xml b/v0.10.x/blog/2021/atom.xml new file mode 100644 index 000000000..2dd518ea0 --- /dev/null +++ b/v0.10.x/blog/2021/atom.xml @@ -0,0 +1,1240 @@ + + + https://fury.gl/ + Blog - Posted in 2021 + 2024-02-29T15:43:57.710854+00:00 + + + ABlog + + https://fury.gl/posts/2021/2021-08-23-final-work-antriksh.html + Google Summer of Code Final Work Product + 2021-08-23T00:00:00-04:00 + + Antriksh Misri + + <a class="reference external image-reference" href="https://summerofcode.withgoogle.com/projects/#6653942668197888"><img alt="https://developers.google.com/open-source/gsoc/resources/downloads/GSoC-logo-horizontal.svg" class="align-center" height="50" src="https://developers.google.com/open-source/gsoc/resources/downloads/GSoC-logo-horizontal.svg" /></a> +<a class="reference external image-reference" href="https://blogs.python-gsoc.org/en/nibba2018s-blog/"><img alt="https://www.python.org/static/community_logos/python-logo.png" src="https://www.python.org/static/community_logos/python-logo.png" style="width: 40%;" /></a> +<a class="reference external image-reference" href="https://fury.gl/latest/community.html"><img alt="https://python-gsoc.org/logos/FURY.png" src="https://python-gsoc.org/logos/FURY.png" style="width: 25%;" /></a> +<section id="google-summer-of-code-final-work-product"> + +<ul class="simple"> +<li><p><strong>Name:</strong> Antriksh Misri</p></li> +<li><p><strong>Organisation:</strong> Python Software Foundation</p></li> +<li><p><strong>Sub-Organisation:</strong> FURY</p></li> +<li><p><strong>Project:</strong> <a class="reference external" href="https://github.com/fury-gl/fury/wiki/Google-Summer-of-Code-2021#project-3-create-new-user-interface-widget">FURY: Create new user interface widget</a></p></li> +</ul> +<section id="proposed-objectives"> +<h2>Proposed Objectives</h2> +<ul class="simple"> +<li><p>Add support for Layouts in UI elements</p></li> +<li><p>Add support for Horizontal Layout</p></li> +<li><p>Add support for Vertical Layout</p></li> +<li><p>Add support for Layout along X, Y, Z axes.</p></li> +<li><p>Stretch Goals:</p> +<ul> +<li><p>Add Tree2D UI element to the UI sub-module</p></li> +<li><p>Add Accordion2D UI element to the UI sub-module</p></li> +<li><p>Add SpinBox2D UI element to the UI sub-module</p></li> +</ul> +</li> +</ul> +</section> +<section id="objectives-completed"> +<h2>Objectives Completed</h2> +<ul> +<li><p><strong>Add support for Horizontal Layout</strong></p> +<p>Added support for Horizontal Layout in the layout module. This layout allows the user to stack actors in a horizontal fashion. Primarily, should be used for laying out UI elements as there is no meaning of horizontal/vertical in 3D space.</p> +<p><em>Pull Requests:</em></p> +<ul class="simple"> +<li><p><strong>Horizontal Layout:</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/480">fury-gl/fury#480</a></p></li> +<li><p><strong>Ribbon Representation demo:</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/480">fury-gl/fury#480</a></p></li> +</ul> +</li> +<li><p><strong>Add support for Vertical Layout</strong></p> +<p>Added support for Vertical Layout in the layout module. This layout allows the user to stack actors in a vertical fashion. Primarily, should be used for laying out UI elements as there is no meaning of horizontal/vertical in 3D space.</p> +<p><em>Pull Requests:</em></p> +<ul class="simple"> +<li><p><strong>Vertical Layout:</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/479">fury-gl/fury#479</a></p></li> +<li><p><strong>Vertical Layout demo:</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/479">fury-gl/fury#479</a></p></li> +</ul> +</li> +<li><p><strong>Add support for Layout along X, Y, Z axes</strong></p> +<p>Added support for Layout along x, y, z axes. Allows user to layout different actors along any given axes. Also it allows users to switch the stacking order by passing a axis+ or axis- to the constructor.</p> +<p><em>Pull Requests:</em></p> +<ul class="simple"> +<li><p><strong>X, Y, Z axes Layout:</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/486">fury-gl/fury#486</a></p></li> +<li><p><strong>X, Y, Z axes Layout demo:</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/486">fury-gl/fury#486</a></p></li> +</ul> +</li> +<li><p><strong>Add Tree2D UI element to the UI sub-module</strong></p> +<p>Added Tree2D UI element to the UI sub-module. This allows user to visualize some data in a hierarchical fashion. Each node inside the tree can have N child nodes and the depth can be infinite. Each node can be clicked to trigger a user defined callback to perform some action. Tests and two demos were added for this UI element. Below is a screenshot for reference:</p> +<img alt="https://camo.githubusercontent.com/dd23b7c8503e4d01c80f2d9e84ee173e06c61eeb7c348c35aeadc75f722647ca/68747470733a2f2f692e696d6775722e636f6d2f4e49334873746c2e706e67" src="https://camo.githubusercontent.com/dd23b7c8503e4d01c80f2d9e84ee173e06c61eeb7c348c35aeadc75f722647ca/68747470733a2f2f692e696d6775722e636f6d2f4e49334873746c2e706e67" style="width: 200px; height: 200px;" /> +<p><em>Pull Requests:</em></p> +<ul class="simple"> +<li><p><strong>Tree2D UI element:</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/460">fury-gl/fury#460</a></p></li> +<li><p><strong>Tree2D UI element demo:</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/460">fury-gl/fury#460</a></p></li> +</ul> +</li> +<li><p><strong>Add Accordion2D UI element to the UI sub-module</strong></p> +<p>Added Accordion2D to the UI sub-module. This Ui element allows users to visualize data in a tree with depth of one. Each node has a title and a content panel. The children for each node can be N if and only if the children are not nodes themselves. The child UIs can be placed inside the content panel by passing some coordinates, which can be absolute or normalized w.r.t the node content panel size. Tests and two demos were added for this UI element. Below is a screenshot for reference</p> +<img alt="https://camo.githubusercontent.com/9395d0ea572d7f253a051823f02496450c9f79d19ff0baf32841ec648b6f2860/68747470733a2f2f692e696d6775722e636f6d2f7854754f645a742e706e67" src="https://camo.githubusercontent.com/9395d0ea572d7f253a051823f02496450c9f79d19ff0baf32841ec648b6f2860/68747470733a2f2f692e696d6775722e636f6d2f7854754f645a742e706e67" style="width: 200px; height: 200px;" /> +<p><em>Pull Requests:</em></p> +<ul class="simple"> +<li><p><strong>Accordion2D UI element:</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/487">fury-gl/fury#487</a></p></li> +<li><p><strong>Accordion2D UI element demo:</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/487">fury-gl/fury#487</a></p></li> +</ul> +</li> +</ul> +</section> +<section id="objectives-in-progress"> +<h2>Objectives in Progress</h2> +<ul> +<li><p><strong>Add support for Layout in UI elements</strong></p> +<p>Currently all the available layouts are only available for actors i.e. of type vtkActor2D. In order to add support for the layouts in UI elements there needs to be some tweaking in the base Layout class. Currently, the PR that adds these functionalities in stalling because of some circular imports. These will hopefully be fixed soon and as soon as the circular imports are fixed, the PR will be merged.</p> +<p><em>Pull Requests:</em></p> +<ul class="simple"> +<li><p><strong>Add support for Layout in UI elements:</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/443">fury-gl/fury#443</a></p></li> +</ul> +</li> +<li><p><strong>Method to process and load sprite sheets</strong></p> +<p>This method adds support for loading and processing a sprite sheet. This will be very useful in playing animations from a n*m sprite sheet. This also has a flag to convert the processed chunks into vtkimageData which can be directly used to update the texture in some UI elements. The primary use of this method will in a tutorial for Card2D, wherein, the image panel of the card will play the animation directly from the sprite sheet.</p> +<p><em>Pull Requests:</em></p> +<ul class="simple"> +<li><p><strong>Method to process and load sprite sheets:</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/491">fury-gl/fury#491</a></p></li> +</ul> +</li> +</ul> +</section> +<section id="other-objectives"> +<h2>Other Objectives</h2> +<ul> +<li><p><strong>Add Card2D UI element to UI sub-module</strong></p> +<p>Added Card2D UI element to the UI sub-module. A Card2D is generally divided into two parts i.e. the image content and the text content. This version of card has an image which can be fetched from a URL and the text content which is yet again divided into two parts i.e. the title and the body. The space distribution between the image and the text content is decided by a float between 0 and 1. A value of 0 means the image takes up no space and a value of 1 means the image consumes the whole space. Below is a demonstration:</p> +<img alt="https://camo.githubusercontent.com/a2e461352799b6490088de15ac041162d7bf8adf9c07485ea921b525fecd0a8e/68747470733a2f2f692e696d6775722e636f6d2f446c69537066302e676966" src="https://camo.githubusercontent.com/a2e461352799b6490088de15ac041162d7bf8adf9c07485ea921b525fecd0a8e/68747470733a2f2f692e696d6775722e636f6d2f446c69537066302e676966" style="width: 200px; height: 200px;" /> +<p><em>Pull Requests:</em></p> +<ul class="simple"> +<li><p><strong>Add Card2D UI element to UI sub-module:</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/398">fury-gl/fury#398</a></p></li> +</ul> +</li> +<li><p><strong>Resize Panel2D with WindowResizeEvent or from corner placeholder</strong></p> +<p>Currently, the size of the Panel2D is static and cannot be changed dynamically. The size is passed in during the initialization and cannot be changed easily at runtime. This PR adds support for resizing the Panel2D dynamically by adding a placeholder icon at the bottom right corner of the panel. This icon can be click and dragged on to change the size accordingly. Other than this, the panel also retains a specific size ratio when the window is resized. This means if the window is resized in any direction the panel adapts itself w.r.t the updated size. This is done by adding relevant observers for the WindowResizeEvent and binding the relevant callback to it. Below is a quick demonstration:</p> +<blockquote> +<div><img alt="https://camo.githubusercontent.com/3b1bf6a1b6522a6079055ff196551362fcf89a41b35ac4b32315ce02333e496d/68747470733a2f2f692e696d6775722e636f6d2f3837504e3754512e676966" src="https://camo.githubusercontent.com/3b1bf6a1b6522a6079055ff196551362fcf89a41b35ac4b32315ce02333e496d/68747470733a2f2f692e696d6775722e636f6d2f3837504e3754512e676966" style="width: 200px; height: 200px;" /> +</div></blockquote> +<p><em>Pull Requests:</em></p> +<ul class="simple"> +<li><p><strong>Resize Panel2D with WindowResizeEvent or from corner placeholder:</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/446">fury-gl/fury#446</a></p></li> +</ul> +</li> +<li><p><strong>Added the watcher class to UI</strong></p> +<p>This PR adds support for a watcher class in the UI elements. The purpose of this class is to monitor a particular attribute from the UI element after it has been added to the scene. If the attribute changes in the real time, a user defined callback is triggered and the scene is force rendered.</p> +<p><em>Pull Requests:</em></p> +<ul class="simple"> +<li><p><strong>Added wathcer class to the UI sub-module:</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/448">fury-gl/fury#448</a></p></li> +</ul> +</li> +<li><p><strong>Added support for borders in Panel2D</strong></p> +<p>The Panel2D previously, didn’t support any sort of effect, the main reason behind this is that, all UI elements are individual entities that are comprised of different actors. These are not the widgets provided by vtk and in order to have some effects provided by vtk shaders must be involved. This obviously makes the whole system very complicated. The border on the other hand uses 4 Rectangle2Ds to draw the 4 borders. This makes the whole process easier but makes the Panel2D very performance heavy as we are adding 5 actors to the scene. Future iterations will replace these rectangles by textures, that way we don’t compromise performance and we can have different patterns in the border. Below is a demonstration:</p> +<img alt="https://user-images.githubusercontent.com/54466356/121709989-bd340280-caf6-11eb-9b8a-81c65260d277.png" src="https://user-images.githubusercontent.com/54466356/121709989-bd340280-caf6-11eb-9b8a-81c65260d277.png" style="width: 200px; height: 200px;" /> +<p><em>Pull Requests:</em></p> +<ul class="simple"> +<li><p><strong>Added support for borders in Panel2D:</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/441">fury-gl/fury#441</a></p></li> +</ul> +</li> +<li><p><strong>GSoC weekly Blogs</strong></p> +<blockquote> +<div><p>Weekly blogs were added for FURY’s Website.</p> +<p><em>Pull Requests:</em></p> +<ul class="simple"> +<li><p><strong>First Evaluation:</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/477">fury-gl/fury#477</a></p></li> +<li><p><strong>Second Evaluation:</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/494">fury-gl/fury#494</a></p></li> +</ul> +</div></blockquote> +</li> +</ul> +</section> +<section id="timeline"> +<h2>Timeline</h2> +<table class="table"> +<thead> +<tr class="row-odd"><th class="head"><p>Date</p></th> +<th class="head"><p>Description</p></th> +<th class="head"><p>Blog Link</p></th> +</tr> +</thead> +<tbody> +<tr class="row-even"><td><p>Week 1(08-06-2021)</p></td> +<td><p>Welcome to my weekly Blogs!</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/antrikshmisris-blog/week-1-welcome-to-my-weekly-blogs/">Weekly Check-in #1</a></p></td> +</tr> +<tr class="row-odd"><td><p>Week 2(14-06-2021)</p></td> +<td><p>Feature additions in UI and IO modules</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/antrikshmisris-blog/week-2-feature-additions-in-ui-and-io-modules/">Weekly Check-in #2</a></p></td> +</tr> +<tr class="row-even"><td><p>Week 3(21-06-2021)</p></td> +<td><p>Adapting GridLayout to work with UI</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/antrikshmisris-blog/week-3-adapting-gridlayout-to-work-with-ui/">Weekly Check-in #3</a></p></td> +</tr> +<tr class="row-odd"><td><p>Week 4(28-06-2021)</p></td> +<td><p>Adding Tree UI to the UI module</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/antrikshmisris-blog/week-4-adding-tree-ui-to-the-ui-module/">Weekly Check-in #4</a></p></td> +</tr> +<tr class="row-even"><td><p>Week 5(05-07-2021)</p></td> +<td><p>Rebasing all PR’s w.r.t the UI restructuring, Tree2D, Bug Fixes</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/antrikshmisris-blog/week-5-rebasing-all-pr-s-w-r-t-the-ui-restructuring-tree2d-bug-fixes/">Weekly Check-in #5</a></p></td> +</tr> +<tr class="row-odd"><td><p>Week 6(12-07-2021)</p></td> +<td><p>Bug fixes, Working on Tree2D UI</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/antrikshmisris-blog/week-6-bug-fixes-working-on-tree2d-ui/">Weekly Check-in #6</a></p></td> +</tr> +<tr class="row-even"><td><p>Week 7(19-07-2021)</p></td> +<td><p>Finalizing the stalling PR’s, finishing up Tree2D UI.</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/antrikshmisris-blog/week-7-finalizing-the-stalling-pr-s-finishing-up-tree2d-ui/">Weekly Check-in #7</a></p></td> +</tr> +<tr class="row-odd"><td><p>Week 8(26-07-2020)</p></td> +<td><p>Code Cleanup, Finishing up open PR’s, Continuing work on Tree2D.</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/antrikshmisris-blog/week-8-code-cleanup-finishing-up-open-pr-s-continuing-work-on-tree2d/">Weekly Check-in #8</a></p></td> +</tr> +<tr class="row-even"><td><p>Week 9(02-08-2021)</p></td> +<td><p>More Layouts!</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/antrikshmisris-blog/week-9-more-layouts/">Weekly Check-in #9</a></p></td> +</tr> +<tr class="row-odd"><td><p>Week 10(09-08-2021)</p></td> +<td><p>Accordion UI, Support for sprite sheet animations.</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/antrikshmisris-blog/week-10-accordion-ui-support-for-sprite-sheet-animations/">Weekly Check-in #10</a></p></td> +</tr> +<tr class="row-even"><td><p>Week 11(16-08-2021)</p></td> +<td><p>More tutorials for Accordion2D, Finalizing remaining PRs.</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/antrikshmisris-blog/week-11-2/">Weekly Check-in #11</a></p></td> +</tr> +</tbody> +</table> +<p>Detailed weekly tasks and work done can be found +<a class="reference external" href="https://blogs.python-gsoc.org/en/antrikshmisris-blog/">here</a>.</p> +</section> +</section> + + + Name: Antriksh Misri + + 2021-08-23T00:00:00-04:00 + + + https://fury.gl/posts/2021/2021-08-23-final-work-sajag.html + Google Summer of Code Final Work Product + 2021-08-23T00:00:00-04:00 + + Sajag Swami + + <a class="reference external image-reference" href="https://summerofcode.withgoogle.com/projects/#6653942668197888"><img alt="https://developers.google.com/open-source/gsoc/resources/downloads/GSoC-logo-horizontal.svg" class="align-center" height="50" src="https://developers.google.com/open-source/gsoc/resources/downloads/GSoC-logo-horizontal.svg" /></a> +<a class="reference external image-reference" href="https://blogs.python-gsoc.org/en/nibba2018s-blog/"><img alt="https://www.python.org/static/community_logos/python-logo.png" src="https://www.python.org/static/community_logos/python-logo.png" style="width: 40%;" /></a> +<a class="reference external image-reference" href="https://fury.gl/latest/community.html"><img alt="https://python-gsoc.org/logos/FURY.png" src="https://python-gsoc.org/logos/FURY.png" style="width: 25%;" /></a> +<section id="google-summer-of-code-final-work-product"> + +<ul class="simple"> +<li><p><strong>Name:</strong> Sajag Swami</p></li> +<li><p><strong>Organisation:</strong> Python Software Foundation</p></li> +<li><p><strong>Sub-Organisation:</strong> FURY</p></li> +<li><p><strong>Project:</strong> <a class="reference external" href="https://github.com/fury-gl/fury/wiki/Google-Summer-of-Code-2021">FURY: Ribbon and Molecular Surface Representations for +Proteins</a></p></li> +</ul> +<section id="proposed-objectives"> +<h2>Proposed Objectives</h2> +<ul class="simple"> +<li><p>Ribbon Representation</p></li> +<li><p>Molecular Surface Representation</p></li> +<li><p>Stretch Goals:</p> +<ul> +<li><p>Stick Representation</p></li> +<li><p>Ball and stick Representation</p></li> +<li><p>Wire Representation</p></li> +<li><p>Pipes and Planks Representation</p></li> +<li><p>Sphere Representation</p></li> +</ul> +</li> +</ul> +</section> +<section id="objectives-completed"> +<h2>Objectives Completed</h2> +<ul> +<li><p><strong>Ribbon Representation</strong></p> +<p>Ribbon diagrams, also known as Richardson diagrams, +are 3D schematic representations of protein structure. Ribbon diagrams are +generated by interpolating a smooth curve through the polypeptide backbone. +α-helices are shown as coiled ribbons. β-strands as sheets, and non-repetitive +coils or loops as lines or thin strips. It was implemented by using +<cite>vtkProteinRibbonFilter</cite>. Generating a <cite>vtkPolyData</cite> of appropriate format +required by <cite>vtkProteinRibbonFilter</cite> was initially unclear due to lack of +examples. I was able to understand what kind of output the filter required +after a meeting with mentors. Tests were added and a demo was created.</p> +<p><em>Pull Requests:</em></p> +<ul class="simple"> +<li><p><strong>Ribbon representation:</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/452">fury-gl/fury#452</a></p></li> +<li><p><strong>Ribbon Representation demo:</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/452">fury-gl/fury#452</a></p></li> +</ul> +</li> +<li><p><strong>Ball and Stick Representation</strong></p> +<p>The ball-and-stick model is a molecular model of a chemical substance which +displays both the three-dimensional position of the atoms and the bonds between +them. The atoms are typically represented by spheres, connected by tubes which +represent the bonds. It was created by using <cite>vtkOpenGLMoleculeMapper</cite>. +Added <cite>vtkSimpleBondPerceiver</cite> for detection of bonds. Tests were added and a +demo was created.</p> +<p><em>Pull Requests:</em></p> +<ul class="simple"> +<li><p><strong>Ball and Stick Representation:</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/452">fury-gl/fury#452</a></p></li> +<li><p><strong>Ball and Stick Representation demo:</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/452">fury-gl/fury#452</a></p></li> +</ul> +</li> +<li><p><strong>Stick Representation</strong></p> +<p>Stick model is a special case of Ball and Stick model where atomic radius of all +molecules is set equal to the radius of tubes used to create bonds. It was created +by using <cite>vtkOpenGLMoleculeMapper</cite>. Tests were added and a demo was created.</p> +<p><em>Pull Requests:</em></p> +<ul class="simple"> +<li><p><strong>Stick Representation:</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/452">fury-gl/fury#452</a></p></li> +<li><p><strong>Stick Representation demo:</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/452">fury-gl/fury#452</a></p></li> +</ul> +</li> +<li><p><strong>Sphere Representation</strong></p> +<p>In chemistry, a space-filling model, also known as a calotte or sphere model, is a +type of three-dimensional (3D) molecular model where the atoms are represented by +spheres whose radii are proportional to the radii of the atoms. It was created by +using <cite>vtkOpenGLMoleculeMapper</cite>. Tests were added and a demo was created.</p> +<p><em>Pull Requests:</em></p> +<ul class="simple"> +<li><p><strong>Sphere Representation:</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/452">fury-gl/fury#452</a></p></li> +<li><p><strong>Sphere Representation demo:</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/452">fury-gl/fury#452</a></p></li> +</ul> +</li> +</ul> +</section> +<section id="objectives-in-progress"> +<h2>Objectives in Progress</h2> +<ul> +<li><p><strong>Molecular Surfaces</strong></p> +<p>There are three types of molecular surfaces:</p> +<ul class="simple"> +<li><p>Van der Waals</p></li> +<li><p>Solvent Accessible</p></li> +<li><p>Solvent Excluded</p></li> +</ul> +<p>Currently the first two molecular surfaces i.e. Van der Waals and Solvent +Accessible are implemented. The code is based on the paper “Generating +Triangulated Macromolecular Surfaces by Euclidean Distance Transform” by +Dong Xu and Yang Zhang.</p> +<p><em>Pull Requests:</em></p> +<ul class="simple"> +<li><p><strong>Molecular Surfaces Implementation:</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/492">fury-gl/fury#492</a></p></li> +</ul> +</li> +</ul> +</section> +<section id="other-objectives"> +<h2>Other Objectives</h2> +<ul> +<li><p><strong>2D Animated Surfaces</strong></p> +<p>This was a simple demonstration that animated Two-Dimensional (2D) functions using FURY. +Created a grid of x-y coordinates and mapped the heights (z-values) to the corresponding x, y +coordinates to generate the surfaces. Used colormaps to color the surfaces.</p> +<p><em>Pull Requests:</em></p> +<ul class="simple"> +<li><p><strong>Animated Surfaces:</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/362">fury-gl/fury#362</a></p></li> +</ul> +</li> +<li><p><strong>Updated miscellaneous animations</strong></p> +<ul class="simple"> +<li><p>Updated the demo of helical motion to stop using multiple line actors as discussed in the meeting.</p></li> +<li><p>Updated the demo of brownian motion to make it more scientifically useful (removed unnecessary rotation of camera +during animation and box actor).</p></li> +<li><p>Display simulation data for brownian motion and helical motion animations (number of simulated steps for brownian +motion and velocity of the particle for helical motion).</p></li> +<li><p>Created utility functions to make the code understandable and used these in emwave, helical and brownian +animations.</p></li> +</ul> +<p><em>Pull Requests:</em></p> +<ul class="simple"> +<li><p><strong>Updated helical, brownian, emwave animations:</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/462">fury-gl/fury#462</a></p></li> +</ul> +</li> +<li><p><strong>GSoC weekly Blogs</strong></p> +<blockquote> +<div><p>Weekly blogs were added for FURY’s Website.</p> +<p><em>Pull Requests:</em></p> +<ul class="simple"> +<li><p><strong>First Evaluation:</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/475">fury-gl/fury#475</a></p></li> +<li><p><strong>Second Evaluation:</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/493">fury-gl/fury#493</a></p></li> +</ul> +</div></blockquote> +</li> +</ul> +</section> +<section id="timeline"> +<h2>Timeline</h2> +<table class="table"> +<thead> +<tr class="row-odd"><th class="head"><p>Date</p></th> +<th class="head"><p>Description</p></th> +<th class="head"><p>Blog Link</p></th> +</tr> +</thead> +<tbody> +<tr class="row-even"><td><p>Week 1(08-06-2021)</p></td> +<td><p>Welcome to my GSoC Blog!</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/suntzunamis-blog/weekly-check-in-1-11/">Weekly Check-in #1</a></p></td> +</tr> +<tr class="row-odd"><td><p>Week 2(14-06-2021)</p></td> +<td><p>First Week of coding: sphere model.</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/suntzunamis-blog/weekly-check-in-2-11/">Weekly Check-in #2</a></p></td> +</tr> +<tr class="row-even"><td><p>Week 3(21-06-2021)</p></td> +<td><p>Bonding algorithms, Ball and Stick model progress.</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/suntzunamis-blog/weekly-check-in-3-13/">Weekly Check-in #3</a></p></td> +</tr> +<tr class="row-odd"><td><p>Week 4(28-06-2021)</p></td> +<td><p>VTK molecular visualization classes.</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/suntzunamis-blog/weekly-check-in-4-14/">Weekly Check-in #4</a></p></td> +</tr> +<tr class="row-even"><td><p>Week 5(05-07-2021)</p></td> +<td><p>Genesis of <cite>molecular</cite> module.</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/suntzunamis-blog/weekly-check-in-5-13/">Weekly Check-in #5</a></p></td> +</tr> +<tr class="row-odd"><td><p>Week 6(12-07-2021)</p></td> +<td><p>Ribbon representation, updated <cite>molecular</cite> module (more pythonic)</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/suntzunamis-blog/weekly-check-in-6-18/">Weekly Check-in #6</a></p></td> +</tr> +<tr class="row-even"><td><p>Week 7(19-07-2021)</p></td> +<td><p>More features to <cite>molecular</cite>, updated misc. animations.</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/suntzunamis-blog/weekly-check-in-7-16/">Weekly Check-in #7</a></p></td> +</tr> +<tr class="row-odd"><td><p>Week 8(26-07-2020)</p></td> +<td><p>Ribbon to <cite>molecular</cite>, tests for <cite>molecular</cite>, animated surfaces.</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/suntzunamis-blog/weekly-check-in-8-11/">Weekly Check-in #8</a></p></td> +</tr> +<tr class="row-even"><td><p>Week 9(02-08-2021)</p></td> +<td><p>Optimized <cite>molecular</cite> with mentors, GSoC blogs to FURY docs.</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/suntzunamis-blog/weekly-check-in-9-11/">Weekly Check-in #9</a></p></td> +</tr> +<tr class="row-odd"><td><p>Week 10(09-08-2021)</p></td> +<td><p>Bounding box, <cite>molecular</cite> tutorial, molecular surfaces progress.</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/suntzunamis-blog/weekly-check-in-10-11/">Weekly Check-in #10</a></p></td> +</tr> +<tr class="row-even"><td><p>Week 11(16-08-2021)</p></td> +<td><p>Molecular Surfaces (VDW, SAS) implementation.</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/suntzunamis-blog/weekly-check-in-11-9/">Weekly Check-in #11</a></p></td> +</tr> +</tbody> +</table> +<p>Detailed weekly tasks and work done can be found +<a class="reference external" href="https://blogs.python-gsoc.org/en/suntzunamis-blog/">here</a>.</p> +</section> +</section> + + + Name: Sajag Swami + + 2021-08-23T00:00:00-04:00 + + + https://fury.gl/posts/2021/2021-08-23-gsoc-devmessias-final-report.html + Google Summer of Code 2021 - Final Report - Bruno Messias + 2021-08-23T00:00:00-04:00 + + Bruno Messias + + <section id="google-summer-of-code-2021-final-report-bruno-messias"> + +<section id="abstract"> +<h2>Abstract</h2> +<p>We have changed some points of my project in the first meeting. +Specifically, we focused the efforts into developing a streaming system +using the WebRTC protocol that could be used in more generic scenarios +than just the network visualization. In addition to that, we have opted +to develop the network visualization for fury as a separated repository +and package available <a class="reference external" href="https://github.com/fury-gl/helios">here</a>. The +name Helios was selected for this new network visualization system based +on the Fury rendering pipeline.</p> +</section> +<section id="proposed-objectives"> +<h2>Proposed Objectives</h2> +<ul class="simple"> +<li><p>Create a streaming system (stadia-like) for FURY</p> +<ul> +<li><p>Should work in a low-bandwidth scenario</p></li> +<li><p>Should allow user interactions and collaboration across the +Internet using a web-browser</p></li> +</ul> +</li> +<li><p>Helios Network System objectives:</p> +<ul> +<li><p>Implement the Force-Directed Algorithm with examples</p></li> +<li><p>Implement the ForceAtlas2 algorithm using cugraph with examples</p></li> +<li><p>Implement Minimum-Distortion Embeddings algorithm (PyMDE) and +examples</p></li> +<li><p>Non-blocking network algorithms computation avoiding the GIL using +the Shared Memory approach</p></li> +<li><p>Create the documentation and the actions for the CI</p></li> +</ul> +</li> +<li><p>Stretch Goals:</p> +<ul> +<li><p>Create an actor in FURY to draw text efficiently using shaders</p></li> +<li><p>Add support to draw millions of nodes using FURY</p></li> +<li><p>Add support to control the opengl state on FURY</p></li> +</ul> +</li> +</ul> +</section> +<section id="objectives-completed"> +<h2>Objectives Completed</h2> +<ul> +<li><p class="rubric" id="create-a-streaming-system-stadia-like-for-fury">Create a streaming system (stadia-like) for FURY</p> +<p>To construct the streaming system for my project we have opted to +follow three main properties and behaviors:</p> +<ol class="arabic simple"> +<li><p>avoid blocking the code execution in the main thread (where the +vtk/fury instance resides)</p></li> +<li><p>work inside of a low bandwidth environment</p></li> +<li><p>make it easy and cheap to share the rendering result. For example, +using the free version of <code class="docutils literal notranslate"><span class="pre">ngrok</span></code></p></li> +</ol> +<p>To achieve the first property we need to circumvent the GIL and allow +python code to execute in parallel. Using the threading module alone +is not good enough to reach real parallelism as Python calls in the +same process can not execute concurrently. In addition to that, to +achieve better organization it is desirable to define the server +system as an uncoupled module from the rendering pipeline. Therefore, +I have chosen to employ the multiprocessing approach for that. The +second and third property can be only achieved choosing a suitable +protocol for transferring the rendered results to the client. We have +opted to implement two streaming protocols: the MJPEG and the WebRTC. +The latter is more suitable for low-bandwidth scenarios [1].</p> +<p>The image below shows a simple representation of the streaming +system.</p> +</li> +</ul> + <center> + <img alt="..." height="400" + src="https://user-images.githubusercontent.com/6979335/121934889-33ff1480-cd1e-11eb-89a4-562fbb953ba4.png"/> + </center> + +The video below shows how our streaming system works smothly and can +be easily integrated inside of a Jupyter notebook.<p><a class="reference external" href="https://user-images.githubusercontent.com/6979335/130284952-2ffbf117-7119-4048-b7aa-428e0162fb7a.mp4">Video: WebRTC Streaming + +Ngrok</a></p> +<p><a class="reference external" href="https://user-images.githubusercontent.com/6979335/130284261-20e84622-427e-4a59-a46f-6a33f5473025.mp4">Video: WebRTC Streaming + +Jupyter</a></p> +<p><em>Pull Requests:</em> * <a class="github reference external" href="https://github.com/fury-gl/fury/pull/480">fury-gl/fury#480</a></p> +<ul> +<li><p class="rubric" id="d-and-3d-marker-actor">2D and 3D marker actor</p> +<p>This feature gave FURY the ability to efficiently draw millions of +markers and impostor 3D spheres. This feature was essential for the +development of Helios. This feature work with signed distance fields +(SDFs) you can get more information about how SDFs works here [4] .</p> +<p>The image below shows 1 million of markers rendered using an Intel +HD graphics 3000.</p> +</li> +</ul> +<center> + <img src="https://user-images.githubusercontent.com/6979335/116004971-70927780-a5db-11eb-8363-8c0757574eb4.png"/> +</center><ul> +<li><p class="rubric" id="fine-tunning-the-opengl-state">Fine-Tunning the OpenGl State</p> +<p>Sometimes users may need to have finer control on how OpenGL will +render the actors. This can be useful when they need to create +specialized visualization effects or to improve the performance.</p> +<p>In this PR I have worked in a feature that allows FURY to control the +OpenGL context created by VTK</p> +<p><em>Pull Request:</em></p> +<ul class="simple"> +<li><p><a class="github reference external" href="https://github.com/fury-gl/fury/pull/432">fury-gl/fury#432</a></p></li> +</ul> +</li> +<li><p class="rubric" id="helios-network-visualization-lib-network-layout-algorithms">Helios Network Visualization Lib: Network Layout +Algorithms</p> +<p><strong>Case 1:</strong> Suppose that you need to monitor a hashtag and build a +social graph. You want to interact with the graph and at the same +time get insights about the structure of the user interactions. To +get those insights you can perform a node embedding using any kind of +network layout algorithm, such as force-directed or minimum +distortion embeddings.</p> +<p><strong>Case 2:</strong> Suppose that you are modelling a network dynamic such as +an epidemic spreading or a Kuramoto model. In some of those network +dynamics a node can change the state and the edges related to the +node must be deleted. For example, in an epidemic model a node can +represent a person who died due to a disease. Consequently, the +layout of the network must be recomputed to give better insights.</p> +<p>In the described cases, if we want a better (UX) and at the same time +a more practical and insightful application of Helios, the employed +layout algorithms should not block any kind of computation in the +main thread.</p> +<p>In Helios we already have a lib written in C (with a python wrapper) +which performs the force-directed layout algorithm using separated +threads avoiding the GIL problem and consequently avoiding blocking +the main thread. But what about the other open-source network layout +libs available on the internet? Unfortunately, most of those libs +have not been implemented like Helios force-directed methods and +consequently, if we want to update the network layout the Python +interpreter will block the computation and user interaction in your +network visualization.</p> +<p>My solution for having PyMDE and CuGraph-ForceAtlas not blocking the +main thread was to break the network layout method into two different +types of processes: A and B and communicate both process using the +Shared Memory approach. You can more information about this PR +through my following posts [2], [3].</p> +</li> +</ul> +<p>The image below show an example that I made and is available at +<a class="github reference external" href="https://github.com/fury-gl/helios/blob/main/docs/examples/viz_mde.py">fury-gl/helios</a></p> +<p><img alt="image2" src="https://user-images.githubusercontent.com/6979335/125310065-a3a9f480-e308-11eb-98d9-0ff5406a0e96.gif" /> <em>Pull Requests:</em></p> +<ul> +<li><p><strong>MDE Layout:</strong> <a class="github reference external" href="https://github.com/fury-gl/helios/pull/6">fury-gl/helios#6</a></p></li> +<li><p><strong>CuGraph ForceAtlas2</strong> <a class="github reference external" href="https://github.com/fury-gl/helios/pull/13">fury-gl/helios#13</a></p></li> +<li><p><strong>Force-Directed and MDE improvements</strong> +<a class="github reference external" href="https://github.com/fury-gl/helios/pull/14">fury-gl/helios#14</a></p></li> +<li><p class="rubric" id="helios-network-visualization-lib-visual-aspects">Helios Network Visualization Lib: Visual Aspects</p> +</li> +</ul> +<p>I’ve made several stuffs to give Helios a better visual aspects. One of +them was to give a smooth real-time network layout animations. Because +the layout computations happens into a different process that the +process responsible to render the network was necessary to record the +positions and communicate the state of layout between both process.</p> +<p>The GIF below shows how the network layout through IPC behaved before +these modification</p> +<center> +<img src="https://user-images.githubusercontent.com/6979335/125310065-a3a9f480-e308-11eb-98d9-0ff5406a0e96.gif"/> +</center><p>below, you can see how after those modifications the visual aspect is +better.</p> +<center> +<img alt="..." height="300" +src="https://user-images.githubusercontent.com/6979335/126175583-c7d85f0a-3d0c-400e-bbdd-4cbcd2a36fed.gif"/> +</center><p><em>Pull Requests:</em></p> +<ul> +<li><p><strong>OpenGL SuperActors:</strong> <a class="github reference external" href="https://github.com/fury-gl/helios/pull/1">fury-gl/helios#1</a></p></li> +<li><p><strong>Fixed the flickering effect</strong> +<a class="github reference external" href="https://github.com/fury-gl/helios/pull/10">fury-gl/helios#10</a></p></li> +<li><p><strong>Improvements in the network node visual aspects</strong> +<a class="github reference external" href="https://github.com/fury-gl/helios/pull/15">fury-gl/helios#15</a></p></li> +<li><p><strong>Smooth animations when using IPC layouts</strong> +<a class="github reference external" href="https://github.com/fury-gl/helios/pull/17">fury-gl/helios#17</a></p></li> +<li><p class="rubric" id="helios-network-visualization-lib-ci-and-documentation">Helios Network Visualization Lib: CI and Documentation</p> +</li> +</ul> +<p>Because Helios was an project that begins in my GSoC project It was +necessary to create the documentation, hosting and more. Now we have a +online documentation available at <a class="reference external" href="https://heliosnetwork.io/">https://heliosnetwork.io/</a> although the +documentation still need some improvements.</p> +<p>The Helios Logo which was developed by +Filipi Nascimento.</p> +<img alt="Helios Network Logo" height="100" src="https://fury-gl.github.io/helios-website/_images/logo.png"/><p><em>Pull Requests:</em></p> +<ul> +<li><p><strong>CI and pytests:</strong> <a class="github reference external" href="https://github.com/fury-gl/helios/pull/5">fury-gl/helios#5</a>, +<a class="github reference external" href="https://github.com/fury-gl/helios/pull/20">fury-gl/helios#20</a></p></li> +<li><p><strong>Helios Logo, Sphinx Gallery and API documentation</strong> +<a class="github reference external" href="https://github.com/fury-gl/helios/pull/18">fury-gl/helios#18</a></p></li> +<li><p><strong>Documentation improvements:</strong> +<a class="github reference external" href="https://github.com/fury-gl/helios/pull/8">fury-gl/helios#8</a></p></li> +<li><p class="rubric" id="objectives-in-progress">Objectives in Progress</p> +</li> +<li><p class="rubric" id="draw-texts-on-fury-and-helios">Draw texts on FURY and Helios</p> +<p>This two PRs allows FURY and Helios to draw millions of characters in +VTK windows instance with low computational resources consumptions. I +still working on that, finishing the SDF font rendering which the +theory behinds was developed here [5].</p> +<p><em>Pull Requests:</em></p> +<ul> +<li><p><a class="github reference external" href="https://github.com/fury-gl/helios/pull/24">fury-gl/helios#24</a></p></li> +<li><p><a class="github reference external" href="https://github.com/fury-gl/fury/pull/489">fury-gl/fury#489</a></p> +<center> +<img alt="..." height="400" src="https://user-images.githubusercontent.com/6979335/129643743-6cb12c06-3415-4a02-ba43-ccc97003b02d.png"/> +</center></li> +</ul> +</li> +<li><p class="rubric" id="gsoc-weekly-blogs">GSoC weekly Blogs</p> +<p>Weekly blogs were added to the FURY Website.</p> +<p><em>Pull Requests:</em></p> +<ul class="simple"> +<li><p><strong>First Evaluation:</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/476">fury-gl/fury#476</a></p></li> +<li><p><strong>Second Evaluation:</strong> TBD</p></li> +</ul> +</li> +</ul> +</section> +<section id="timeline"> +<h2>Timeline</h2> +<table class="table"> +<thead> +<tr class="row-odd"><th class="head"><p>Date</p></th> +<th class="head"><p>Description</p></th> +<th class="head"><p>Blog Link</p></th> +</tr> +</thead> +<tbody> +<tr class="row-even"><td><p>Week 1 +(08-06-2021)</p></td> +<td><p>Welcome to my weekly Blogs!</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/demvessiass-blog/weekly-check-in-1-21/">Weekly Check-in +#1</a></p></td> +</tr> +<tr class="row-odd"><td><p>Week 2 +(14-06-2021)</p></td> +<td><p>Post #1: A Stadia-like +system for data +visualization</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/demvessiass-blog/post-1-a-stadia-like-system-for-data-visualization/">Weekly Check-in +# +2</a></p></td> +</tr> +<tr class="row-even"><td><p>Week 3 +(21-06-2021)</p></td> +<td><p>2d and 3d fake impostors +marker; fine-tunning +open-gl state; Shared +Memory support for the +streaming system; +first-version of helios: +the network visualization +lib for helios</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/demvessiass-blog/weekly-check-in-3-15/">Weekly Check-in +#3</a></p></td> +</tr> +<tr class="row-odd"><td><p>Week 4 +(28-06-2020)</p></td> +<td><p>Post #2: SOLID, monkey +patching a python issue and +network layouts through +WebRTC</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/demvessiass-blog/post-2-solid-monkey-patching-a-python-issue-and-network-layouts-through-webrtc/">Weekly Check-in +#4</a></p></td> +</tr> +<tr class="row-even"><td><p>Week 5 +(05-07-2021)</p></td> +<td><p>Code refactoring; 2d +network layouts for Helios; +Implemented the Minimum +distortion embedding +algorithm using the IPC +approach</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/demvessiass-blog/weekly-check-in-5-14/">Weekly Check-in +#5</a></p></td> +</tr> +<tr class="row-odd"><td><p>Week 6 +(12-07-2020)</p></td> +<td><p>Post #3: Network layout +algorithms using IPC</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/demvessiass-blog/post-3-network-layout-algorithms-using-ipc/">Weekly Check-in +#6</a></p></td> +</tr> +<tr class="row-even"><td><p>Week 7 +(19-07-2020)</p></td> +<td><p>Helios IPC network layout +algorithms support for +MacOs; Smooth animations +for IPC layouts; +ForceAtlas2 network layout +using cugraph/cuda</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/demvessiass-blog/weekly-check-in-7-14/">Weekly Check-in +#7</a></p></td> +</tr> +<tr class="row-odd"><td><p>Week 8 +(26-07-2020)</p></td> +<td><p>Helios CI, Helios +documentation</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/demvessiass-blog/weekly-check-in-8-9/">Weekly Check-in +#8</a></p></td> +</tr> +<tr class="row-even"><td><p>Week 9 +(02-08-2020)</p></td> +<td><p>Helios documentation; +improved the examples and +documentation of the WebRTC +streaming system and made +some improvements in the +compatibility removing some +dependencies</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/demvessiass-blog/weekly-check-in-9-16/">Weekly Check-in +#9</a></p></td> +</tr> +<tr class="row-odd"><td><p>Week 10 +(09-08-2020)</p></td> +<td><p>Helios documentation +improvements; found and +fixed a bug in fury w.r.t. +the time management system; +improved the memory +management system for the +network layout algorithms +using IPC</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/demvessiass-blog/weekly-check-in-10-12/">Weekly Check-in +#10</a></p></td> +</tr> +<tr class="row-even"><td><p>Week 11 +(16-08-2020)</p></td> +<td><p>Created a PR that allows +FURY to draw hundred of +thousands of characters +without any expensive GPU; +fixed the flickering effect +on the streaming system; +helios node labels feature; +finalizing remaining PRs</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/demvessiass-blog/weekly-check-in-11-13/">Weekly Check-in +#11</a></p></td> +</tr> +</tbody> +</table> +<p>Detailed weekly tasks, progress and work done can be found +<a class="reference external" href="https://blogs.python-gsoc.org/en/demvessiass-blog/">here</a>.</p> +<section id="references"> +<h3>References</h3> +<p>[1] ( Python GSoC - Post #1 - A Stadia-like system for data +visualization - demvessias s Blog, n.d.; +<a class="reference external" href="https://blogs.python-gsoc.org/en/demvessiass-blog/post-1-a-stadia-like-system-for-data-visualization/">https://blogs.python-gsoc.org/en/demvessiass-blog/post-1-a-stadia-like-system-for-data-visualization/</a></p> +<p>[2] Python GSoC - Post #2: SOLID, monkey patching a python issue and +network layouts through WebRTC - demvessias s Blog, n.d.; +<a class="reference external" href="https://blogs.python-gsoc.org/en/demvessiass-blog/post-2-solid-monkey-patching-a-python-issue-and-network-layouts-through-webrtc/">https://blogs.python-gsoc.org/en/demvessiass-blog/post-2-solid-monkey-patching-a-python-issue-and-network-layouts-through-webrtc/</a></p> +<p>[3] Python GSoC - Post #3: Network layout algorithms using IPC - +demvessias s Blog, +n.d.)https://blogs.python-gsoc.org/en/demvessiass-blog/post-3-network-layout-algorithms-using-ipc/</p> +<p>[4] Rougier, N.P., 2018. An open access book on Python, OpenGL and +Scientific Visualization [WWW Document]. An open access book on Python, +OpenGL and Scientific Visualization. URL +<a class="github reference external" href="https://github.com/rougier/python-opengl">rougier/python-opengl</a> (accessed 8.21.21).</p> +<p>[5] Green, C., 2007. Improved alpha-tested magnification for vector +textures and special effects, in: ACM SIGGRAPH 2007 Courses on - +SIGGRAPH ’07. Presented at the ACM SIGGRAPH 2007 courses, ACM Press, San +Diego, California, p. 9. <a class="reference external" href="https://doi.org/10.1145/1281500.1281665">https://doi.org/10.1145/1281500.1281665</a></p> +</section> +</section> +</section> + + + We have changed some points of my project in the first meeting. +Specifically, we focused the efforts into developing a streaming system +using the WebRTC protocol that could be used in more generic scenarios +than just the network visualization. In addition to that, we have opted +to develop the network visualization for fury as a separated repository +and package available here. The +name Helios was selected for this new network visualization system based +on the Fury rendering pipeline. + + 2021-08-23T00:00:00-04:00 + + + https://fury.gl/posts/2021/2021-16-08-gsoc-devmessias-11.html + Week #11: Removing the flickering effect + 2021-08-16T00:00:00-04:00 + + Bruno Messias + + <section id="week-11-removing-the-flickering-effect"> + +<section id="what-did-i-do-this-week"> +<h2>What did I do this week?</h2> +<section id="fury"> +<h3>FURY</h3> +<ul class="simple"> +<li><p><a class="reference external" href="https://github.com/fury-gl/fury/pull/489">PR fury-gl/fury#489:</a></p></li> +</ul> +<blockquote> +<div><p>This PR give to FURY three +pre-built texture maps using different fonts. However, is quite easy +to create new fonts to be used in a visualization.</p> +</div></blockquote> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2021/2021-16-08-gsoc-devmessias-11.rst</span>, line 20)</p> +<p>Block quote ends without a blank line; unexpected unindent.</p> +</aside> +<div class="line-block"> +<div class="line">It’s was quite hard to develop the shader code and find the correct +positions of the texture maps to be used in the shader. Because we +used the freetype-py to generate the texture and packing the glyps. +However, the lib has some examples with bugs. But fortunelly, now +everything is woking on FURY. I’ve also created two different examples +to show how this PR works.</div> +</div> +<blockquote> +<div><p>The first example, viz_huge_amount_of_labels.py, shows that the user can +draw hundreds of thousands of characters.</p> +<p><img alt="image2" src="https://user-images.githubusercontent.com/6979335/129643743-6cb12c06-3415-4a02-ba43-ccc97003b02d.png" /></p> +<p>The second example, viz_billboad_labels.py, shows the different behaviors of the label actor. In addition, presents +to the user how to create a new texture atlas font to be used across different visualizations.</p> +</div></blockquote> +<ul> +<li><p><a class="reference external" href="https://github.com/fury-gl/fury/pull/437">PR fury-gl/fury#437:</a></p> +<ul> +<li><dl class="simple"> +<dt>Fix: avoid multiple OpenGl context on windows using asyncio</dt><dd><p>The streaming system must be generic, but opengl and vtk behaves in uniques ways in each Operating System. Thus, can be tricky +to have the same behavior acrros different OS. One hard stuff that we founded is that was not possible to use my +TimeIntervals objects (implemented with threading module) with vtk. The reason for this impossibility is because we can’t use +vtk in windows in different threads. But fortunely, moving from the threading (multithreading) to the asyncio approcach (concurrency) +have fixed this issue and now the streaming system is ready to be used anywhere.</p> +</dd> +</dl> +</li> +<li><p>Flickering:</p> +<blockquote> +<div><p>Finally, I could found the cause of the flickering effect on the streaming system. +This flickering was appearing only when the streaming was created using the Widget object. +The cause seems to be a bug or a strange behavior from vtk. +Calling iren.MouseWheelForwardEvent() or iren.MouseWheelBackwardEvent() +inside of a thread without invoking the +Start method from a vtk instance produces a memory corruption. +Fortunately, I could fix this behavior and now the streaming system is +working without this glitch effect.</p> +</div></blockquote> +</li> +</ul> +</li> +</ul> +</section> +<section id="fury-helios"> +<h3>FURY/Helios</h3> +<ul class="simple"> +<li><p><a class="reference external" href="https://github.com/fury-gl/helios/pull/24">PR fury-gl/helios#24 +:</a></p></li> +</ul> +<p>This uses the +<a class="reference external" href="https://github.com/fury-gl/fury/pull/489">PRfury-gl/fury#489:</a> to +give the network label feature to helios. Is possible to draw node +labels, update the colors, change the positions at runtime. In addition, +when a network layout algorithm is running this will automatically +update the node labels positions to follow the nodes across the screen.</p> +<p><img alt="image1" src="https://user-images.githubusercontent.com/6979335/129642582-fc6785d8-0e4f-4fdd-81f4-b2552e1ff7c7.png" /></p> +<ul class="simple"> +<li><p><a class="reference external" href="https://github.com/fury-gl/helios/pull/23">PR fury-gl/helios#23: +Merged.</a></p></li> +</ul> +<p>This PR granted compatibility between IPC Layouts and Windows. Besides +that , now is quite easier to create new network layouts using inter +process communication</p> +</section> +</section> +<section id="did-i-get-stuck-anywhere"> +<h2>Did I get stuck anywhere?</h2> +<p>I did not get stuck this week.</p> +</section> +</section> + + + PR fury-gl/fury#489: + + 2021-08-16T00:00:00-04:00 + + + https://fury.gl/posts/2021/2021-08-16-week-11-antriksh.html + Week #11: Finalizing open Pull Requests + 2021-08-16T00:00:00-04:00 + + Antriksh Misri + + <section id="week-11-finalizing-open-pull-requests"> + +<section id="what-did-i-do-this-week"> +<h2>What did I do this week?</h2> +<p>Below are the tasks that I worked on:</p> +<ul class="simple"> +<li><p><a class="reference external" href="https://github.com/fury-gl/fury/pull/491">Created PR for sprite sheet animation</a> : This PR adds support for playing animations from a sprite sheet. This feature will be used in Card2D to create a tutorial in which the card will show the animation in the image box. Previously, the utility functions for this were added directly inside the tutorial but now they are refactored to go in their respective modules.</p></li> +<li><p><a class="reference external" href="https://github.com/fury-gl/fury/pull/486">Finalized the x, y, z layouts</a> : The PR that adds these layouts needed some updates for it to work as intended. These changes were added and this PR is ready to go.</p></li> +<li><p><a class="reference external" href="https://github.com/fury-gl/fury/pull/443">Resolved all conflicts in the GridLayout PR</a> : As the Horizontal and Vertical layouts were merged this week the GridLayout PR had got some conflicts. These conflicts were resolved and the PR is almost ready.</p></li> +<li><p><strong>Continuing the work on custom font rendering</strong> : In the last meeting, a few points were brought up. Firstly, to position each glyph to their respective location in the atlas a separate module is used which is freetype-gl. The python bindings for this module are not available which means either we have to write the bindings ourselves or the freetype team will be emailed about this and they will add bindings for that. On the other hand, I looked how latex is rendered in matplotlib. <a class="reference external" href="https://github.com/matplotlib/matplotlib/blob/3a4fdea8d23207d67431973fe5df1811605c4132/lib/matplotlib/text.py#L106">This</a> is the Text class that is used to represent the string that is to be drawn and <a href="#id1"><span class="problematic" id="id2">`This is the class that it inherits from.&lt;https://github.com/matplotlib/matplotlib/blob/3a4fdea8d23207d67431973fe5df1811605c4132/lib/matplotlib/artist.py#L94&gt;`_</span></a> Everything is handled internally in matplotlib, to draw the rasterized text <a class="reference external" href="https://github.com/matplotlib/matplotlib/blob/3a4fdea8d23207d67431973fe5df1811605c4132/lib/matplotlib/text.py#L672">this function is used.</a> The text can be rendered in two ways, the first one is by using the default renderer and the second way is by using PathEffectRenderer that is used to add effects like outlines, anti-aliasing etc. It is a very rigid way of rendering text and is designed to be used internally.</p></li> +</ul> +</section> +<section id="did-i-get-stuck-anywhere"> +<h2>Did I get stuck anywhere?</h2> +<p>No, I did not get stuck anywhere.</p> +</section> +<section id="what-is-coming-up-next-week"> +<h2>What is coming up next week?</h2> +<p>Hopefully everything is resolved by the end of this week and next week I will hopefully submit my final code in a gist format.</p> +<p><strong>See you guys next week!</strong></p> +</section> +</section> + + + Below are the tasks that I worked on: + + 2021-08-16T00:00:00-04:00 + + + https://fury.gl/posts/2021/2021-08-16-week-11-sajag.html + Tenth coding week! + 2021-08-16T00:00:00-04:00 + + Sajag Swami + + <section id="tenth-coding-week"> + +<p>Welcome to the eleventh weekly check-in. I’ll be sharing my progress for the tenth week of coding.</p> +<section id="what-did-you-do-this-week"> +<h2>What did you do this week?</h2> +<ol class="arabic"> +<li><p>Implemented <a class="reference external" href="https://journals.plos.org/plosone/article?id=10.1371/journal.pone.0008140">this paper</a> to generate Van der Waals surface and solvent-accessible surface (PR created: <a class="reference external" href="https://github.com/fury-gl/fury/pull/492">PR #492</a>). It was a good learning experience because the first time I read the paper, I didn’t understand the underlying math, it all seemed alien to me. I had to read it many times, read about the algorithms used and understand the terminologies. I had a meeting with the mentors to understand a bit of the theory which proved to be quite fruitful as I understood how to go about making the space-filling model. <a class="reference external" href="ttps://pyscience.wordpress.com/2014/09/11/surface-extraction-creating-a-mesh-from-pixel-data-using-python-and-vtk/">This</a> blog was helpful in understanding how to use vtkMarchingCubes with numpy arrays. One of the earliest SAS rendering looked like this (this implementation was not strictly according to the paper):</p> +<blockquote> +<div><figure class="align-default" id="id1"> +<img alt="https://user-images.githubusercontent.com/65067354/129559593-baf201bf-720c-45f7-9269-3b31954efd5e.png" src="https://user-images.githubusercontent.com/65067354/129559593-baf201bf-720c-45f7-9269-3b31954efd5e.png" style="width: 300px; height: 300px;" /> +<figcaption> +<p><span class="caption-text">Notice that it’s rather rough</span></p> +</figcaption> +</figure> +</div></blockquote> +<p>Current implementation (this implementation was according to the paper):</p> +<blockquote> +<div><figure class="align-default" id="id2"> +<img alt="https://user-images.githubusercontent.com/65067354/129560374-14180b22-14b2-449b-88a6-b3140226418d.png" src="https://user-images.githubusercontent.com/65067354/129560374-14180b22-14b2-449b-88a6-b3140226418d.png" style="width: 300px; height: 300px;" /> +<figcaption> +<p><span class="caption-text">grid dimensions = 256 × 256 × 256, used smoothing algorithms recommended by vtk</span></p> +</figcaption> +</figure> +</div></blockquote> +</li> +</ol> +<p>I also understood how to go about rendering volumes. I think that the ability to render volumes with FURY will be a cool capability and I’ll discuss my implementation and request the mentors for feedback and ideas in the weekly meeting. Example of volume rendering:</p> +<blockquote> +<div><figure class="align-default" id="id3"> +<img alt="https://user-images.githubusercontent.com/65067354/129562606-50a9f0cf-e16d-4501-b0fa-a0038fda406b.png" src="https://user-images.githubusercontent.com/65067354/129562606-50a9f0cf-e16d-4501-b0fa-a0038fda406b.png" style="width: 300px; height: 300px;" /> +<figcaption> +<p><span class="caption-text">grid dimensions = 256 × 256 × 256</span></p> +</figcaption> +</figure> +</div></blockquote> +</section> +<section id="what-is-coming-up-next-week"> +<h2>What is coming up next week?</h2> +<p>I’ll try to get <a class="reference external" href="https://github.com/fury-gl/fury/pull/452">PR #452</a> merged. Documentation work to be done as GSoC coding period has come to an end.</p> +</section> +<section id="did-you-get-stuck-anywhere"> +<h2>Did you get stuck anywhere?</h2> +<p>No.</p> +<p><code class="docutils literal notranslate"><span class="pre">Au</span> <span class="pre">Revoir!</span></code></p> +</section> +</section> + + + Welcome to the eleventh weekly check-in. I’ll be sharing my progress for the tenth week of coding. + + 2021-08-16T00:00:00-04:00 + + + https://fury.gl/posts/2021/2021-08-09-week-10-antriksh.html + Week#10: Accordion UI, Support for sprite sheet animations + 2021-08-09T00:00:00-04:00 + + Antriksh Misri + + <section id="week-10-accordion-ui-support-for-sprite-sheet-animations"> + +<section id="what-did-i-do-this-week"> +<h2>What did I do this week?</h2> +<p>Below are the tasks that I worked on:</p> +<ul> +<li><p><a class="reference external" href="https://github.com/fury-gl/fury/pull/487">Added Accordion2D to UI sub-module</a> : This PR adds the Accordion UI to the UI sub-module. This UI inherits from the Tree2D UI and can only be merged once the Tree2D UI is in. Here’s a screenshot for reference:</p> +<blockquote> +<div><img alt="https://i.imgur.com/klI4Tb5.png" src="https://i.imgur.com/klI4Tb5.png" style="width: 200px; height: 200px;" /> +</div></blockquote> +</li> +<li><p><a class="reference external" href="https://github.com/fury-gl/fury/pull/486">Adding X, Y, Z Layouts</a> : It was pointed out in last week’s meeting that in 3D space horizontal/vertical means nothing. Instead X, Y, Z are used, so, these three layouts were added on top of horizontal/vertical layouts. They also have functionality of changing the direction i.e. reverse the stacking order.</p></li> +<li><p><a class="reference external" href="https://github.com/fury-gl/fury/pull/398">Added support of sprite sheet animation in Card2D</a> : The image in Card2D was static in nature and wasn’t very interesting. So, to make things a bit interesting support for animated images were added. These animations are played from a sprite sheet or a texture atlas. A buffer of processed sprite chunks is maintained and with the help of a timer callback the image in the card is updated after a certain delay which is dependent of the frame rate. Below is the demonstration:</p> +<blockquote> +<div><img alt="https://i.imgur.com/DliSpf0.gif" src="https://i.imgur.com/DliSpf0.gif" style="width: 200px; height: 200px;" /> +</div></blockquote> +</li> +<li><p><strong>Researching more about Freetype/Freetype-GL</strong>: Apart from coding stuff, i did some more research on custom font using freetype and freetype-gl. I found some examples that used the python bindings of the c++ library and displayed custom fonts that were transformable i.e. can be rotated by some angle. Hopefully I can create a working example by this weeks meeting.</p></li> +</ul> +</section> +<section id="did-i-get-stuck-anywhere"> +<h2>Did I get stuck anywhere?</h2> +<p>No, I did not get stuck anywhere.</p> +</section> +<section id="what-is-coming-up-next-week"> +<h2>What is coming up next week?</h2> +<p>Next week I will finish up my remaining work. Which includes addressing all PR reviews and adding some more features.</p> +<p><strong>See you guys next week!</strong></p> +</section> +</section> + + + Below are the tasks that I worked on: + + 2021-08-09T00:00:00-04:00 + + + https://fury.gl/posts/2021/2021-09-08-gsoc-devmessias-10.html + Week #10: SDF Fonts + 2021-08-09T00:00:00-04:00 + + Bruno Messias + + <section id="week-10-sdf-fonts"> + +<section id="what-did-i-do-this-week"> +<h2>What did I do this week?</h2> +<section id="fury-helios"> +<h3>FURY/Helios</h3> +<ul class="simple"> +<li><p><a class="reference external" href="https://github.com/fury-gl/helios/pull/22">PR fury-gl/helios#22 +:</a> Helios Documentation +Improvements.</p></li> +<li><p><a class="reference external" href="https://github.com/fury-gl/helios/pull/23">PR fury-gl/helios#23:</a> +A PR that makes helios IPCLayout system compatible with Windows.</p></li> +</ul> +</section> +<section id="fury"> +<h3>FURY</h3> +<ul class="simple"> +<li><p><a class="reference external" href="https://github.com/fury-gl/fury/pull/484">PR fury-gl/fury#484: I’ve found and fixed a bug in FURY time +management system</a></p></li> +<li><p><a class="reference external" href="https://github.com/fury-gl/fury/pull/437">PR fury-gl/fury#437:</a></p> +<ul> +<li><p>Fixed the tests on Windows</p></li> +<li><p>Improve the streaming memory management system for IPC +communication</p></li> +</ul> +</li> +<li><p>I’ve developing a feature that will allows FURY to draw hundreds +thousands of labels using texture maps and signed distance functions. +Until now I’ve a sketch that at least is able to draw the labels +using the markers billboards and bitmap fonts <img alt="image1" src="https://user-images.githubusercontent.com/6979335/128761833-53f53e2c-5bc0-4ff3-93c4-0ad01dc7d8eb.png" /></p></li> +<li><p><a class="reference external" href="https://github.com/fury-gl/fury/pull/432">PR fury-gl/fury#432:</a> +minor improvements</p></li> +<li><p><a class="reference external" href="https://github.com/fury-gl/fury/pull/474">PR #474</a> Helped to +review this PR</p></li> +</ul> +</section> +</section> +<section id="did-i-get-stuck-anywhere"> +<h2>Did I get stuck anywhere?</h2> +<p>I did not get stuck this week.</p> +</section> +<section id="what-is-coming-up-next"> +<h2>What is coming up next?</h2> +<p>I’ll discuss that with my mentors tomorrow.</p> +</section> +</section> + + + PR fury-gl/helios#22 +: Helios Documentation +Improvements. + + 2021-08-09T00:00:00-04:00 + + + https://fury.gl/posts/2021/2021-08-09-week-10-sajag.html + Ninth coding week! + 2021-08-09T00:00:00-04:00 + + Sajag Swami + + <section id="ninth-coding-week"> + +<p>Welcome to the tenth weekly check-in. I’ll be sharing my progress for the ninth week of coding.</p> +<section id="what-did-you-do-this-week"> +<h2>What did you do this week?</h2> +<ol class="arabic"> +<li><p>Updated <a class="reference external" href="https://github.com/fury-gl/fury/pull/452">PR #452</a> :</p> +<blockquote> +<div><ul class="simple"> +<li><p>Made ribbon representation faster.</p></li> +<li><p>Added an actor to display bounding box around the molecule.</p></li> +</ul> +<blockquote> +<div><figure class="align-default" id="id1"> +<img alt="https://user-images.githubusercontent.com/65067354/128624529-03c026be-7f80-4792-b57e-eceeb1767ec2.png" src="https://user-images.githubusercontent.com/65067354/128624529-03c026be-7f80-4792-b57e-eceeb1767ec2.png" style="width: 300px; height: 300px;" /> +<figcaption> +<p><span class="caption-text">Bounding Box</span></p> +</figcaption> +</figure> +</div></blockquote> +</div></blockquote> +</li> +<li><p>Made a tutorial which showcases the abilities of molecular module (will create a PR after molecular module is merged).</p></li> +<li><p>I’m trying to implement a native implementation of molecular surfaces in FURY. Currently searching for recent research papers to find good algorithms to generate the molecular surfaces (the ones I’d collected in the research period were archaic and rather time consuming). The papers that I’ve read so far seem a tad bit intimidating as I’ve never done math related to this domain yet. Implementing them will be a good learning experience I reckon.</p></li> +</ol> +</section> +<section id="what-is-coming-up-next-week"> +<h2>What is coming up next week?</h2> +<ol class="arabic simple"> +<li><p>Try to create a native implementation of molecular surface.</p></li> +<li><p>Small fixes to <a class="reference external" href="https://github.com/fury-gl/fury/pull/362">PR #362</a>, <a class="reference external" href="https://github.com/fury-gl/fury/pull/462">PR #462</a>.</p></li> +</ol> +</section> +<section id="did-you-get-stuck-anywhere"> +<h2>Did you get stuck anywhere?</h2> +<p>No.</p> +<p><code class="docutils literal notranslate"><span class="pre">Au</span> <span class="pre">Revoir!</span></code></p> +</section> +</section> + + + Welcome to the tenth weekly check-in. I’ll be sharing my progress for the ninth week of coding. + + 2021-08-09T00:00:00-04:00 + + + https://fury.gl/posts/2021/2021-08-03-release-announcement.html + FURY 0.7.0 Released + 2021-08-03T00:00:00-04:00 + + Serge Koudoro + + <section id="fury-0-7-0-released"> + +<p>The FURY project is happy to announce the release of FURY 0.7.1! +FURY is a free and open source software library for scientific visualization and 3D animations.</p> +<p>You can show your support by <a class="reference external" href="https://github.com/fury-gl/fury/stargazers">adding a star</a> on FURY github project.</p> +<p>This Release is mainly a maintenance release. The <strong>major highlights</strong> of this release are:</p> +<ul class="simple"> +<li><p>FURY paper added.</p></li> +<li><p>Fast selection of multiple objects added.</p></li> +<li><p>UI refactored.</p></li> +<li><p>Tests coverage increased.</p></li> +<li><p>New actor (Marker) added.</p></li> +<li><p>New primitive (Triangular Prism) added.</p></li> +<li><p>Demos added and updated.</p></li> +<li><p>Large Documentation Update.</p></li> +</ul> +<div class="admonition note"> +<p class="admonition-title">Note</p> +<p>The complete release notes are available <a class="reference internal" href="../release_notes/releasev0.7.1.html#releasev0-7-1"><span class="std std-ref">here</span></a></p> +</div> +<p><strong>To upgrade or install FURY</strong></p> +<p>Run the following command in your terminal:</p> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">pip</span> <span class="n">install</span> <span class="o">--</span><span class="n">upgrade</span> <span class="n">fury</span> +</pre></div> +</div> +<p>or:</p> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">conda</span> <span class="n">install</span> <span class="o">-</span><span class="n">c</span> <span class="n">conda</span><span class="o">-</span><span class="n">forge</span> <span class="n">fury</span> +</pre></div> +</div> +<p><strong>Questions or suggestions?</strong></p> +<p>For any questions go to <a class="reference external" href="http://fury.gl">http://fury.gl</a>, or send an e-mail to <a class="reference external" href="mailto:fury&#37;&#52;&#48;python&#46;org">fury<span>&#64;</span>python<span>&#46;</span>org</a> +We can also join our <a class="reference external" href="https://discord.gg/6btFPPj">discord community</a></p> +<p>We would like to thanks to <a class="reference internal" href="../community.html#community"><span class="std std-ref">all contributors</span></a> for this release:</p> +<ul class="simple"> +<li><p>Amit Chaudhari</p></li> +<li><p>Antriksh Misri</p></li> +<li><p>Bruno Messias</p></li> +<li><p>Daniel S. Katz</p></li> +<li><p>Eleftherios Garyfallidis</p></li> +<li><p>Gurdit Siyan</p></li> +<li><p>Javier Guaje</p></li> +<li><p>Jhalak Gupta</p></li> +<li><p>LoopThrough-i-j</p></li> +<li><p>MIHIR</p></li> +<li><p>Praneeth Shetty</p></li> +<li><p>Sajag Swami</p></li> +<li><p>Serge Koudoro</p></li> +<li><p>Hariharan Ayappane</p></li> +</ul> +<p>On behalf of the <a class="reference internal" href="../community.html#community"><span class="std std-ref">FURY developers</span></a>,</p> +<p>Serge K.</p> +</section> + + + The FURY project is happy to announce the release of FURY 0.7.1! +FURY is a free and open source software library for scientific visualization and 3D animations. + + 2021-08-03T00:00:00-04:00 + + diff --git a/v0.10.x/blog/2022.html b/v0.10.x/blog/2022.html new file mode 100644 index 000000000..8911b8c10 --- /dev/null +++ b/v0.10.x/blog/2022.html @@ -0,0 +1,3961 @@ + + + + + + + Posted in 2022 — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +
+

+ + Posted in + + 2022 + +

+ + +
+

+ Week 14: Keyframes animation is now a bit easier in FURY +

+
    +
  • + + + 28 September 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Mohamed Abouagour + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Separated the Timeline into a Timeline and an Animation. So, instead of having the Timeline do everything. It’s now more like doing animations in Blender and other 3D editing software where the timeline handles the playback of several animations #694.

+

+ +

Read more ...

+
+
+ +
+

+ Week 14 - Morphing is here! +

+
    +
  • + + + 28 September 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Shivam Anand + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week, I started with multiple actor support in skinning and managed to do it +successfully. Here’s the preview using the BrainStem model.

+

+ +

Read more ...

+
+
+ +
+

+ Week 16 - Working with Rotations! +

+
    +
  • + + + 21 September 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Last week my mentors noticed that each DrawShape has its individual rotation_slider which increases redundancy and complexity in setting its visibility on and off. Instead, they suggested moving the rotation_slider to DrawPanel and keeping a common slider for all the shapes.

+

+ +

Read more ...

+
+
+ +
+

+ Week 13: Keyframes animation is now a bit easier in FURY +

+
    +
  • + + + 20 September 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Mohamed Abouagour + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Added the ability to have the ShowManager stored inside the Timeline. That way the user does not have to update and render the animations because it will be done internally.

+

+ +

Read more ...

+
+
+ +
+

+ Week 13 - Multi-bone skeletal animation support +

+
    +
  • + + + 15 September 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Shivam Anand + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week I fixed all the issues with skeletal animations, and we got to see our first render of skeletal animation :).

+

+ +

Read more ...

+
+
+ +
+

+ Week 15 - Highlighting DrawShapes +

+
    +
  • + + + 14 September 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week I started with highlighting the shapes. As discussed earlier, I had two ways, but while implementing them, I found out both ways aren’t that good to continue with. +The first way in which we thought of creating the scaled shapes in the background had an issue with the stacking. The border(blue rectangle) and the shape(grey rectangle) both seem to look like different shapes just grouped together as shown below.

+

+ +

Read more ...

+
+
+ +
+

+ Week 12 - Adding skeleton as actors and fix global transformation +

+
    +
  • + + + 08 September 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Shivam Anand + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

I started this week by fixing the segmentation fault for the skinning test. I could not fix this as of now.

+

+ +

Read more ...

+
+
+ +
+

+ Week 14 - Updating DrawPanel architecture +

+
    +
  • + + + 07 September 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week I continued updating the DrawShape and DrawPanel.

+

+ +

Read more ...

+
+
+ +
+

+ Week 12: Adding new tutorials +

+
    +
  • + + + 07 September 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Mohamed Abouagour + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Restructured tutorials to be more readable and more focused on a specific topic.

+

+ +

Read more ...

+
+
+ +
+

+ Week 13 - Separating tests and fixing bugs +

+
    +
  • + + + 31 August 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week I managed to fix the translation issue in PR #653. This was happening because of the calculation error while repositioning the shapes. Now it works as intended.

+

+ +

Read more ...

+
+
+ +
+

+ Week 11 - Multiple transformations support and adding tests +

+
    +
  • + + + 31 August 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Shivam Anand + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

As decided last week, I added support for multiple animations at the same timestamp. But this didn’t solve the animation problems of RiggedSimple model.

+

+ +

Read more ...

+
+
+ +
+

+ Week 11: Improving tutorials a little +

+
    +
  • + + + 30 August 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Mohamed Abouagour + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Fixed some issues in the hierarchical order animation support PR that we discussed during last week’s meeting (mostly naming issues).

+

+ +

Read more ...

+
+
+ +
+

+ Week 10 - Multi-node skinning support +

+
    +
  • + + + 25 August 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Shivam Anand + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

As we figured out that the SimpleSkin model is not animated as intended. This week I started working with that model; +I figured out that we need to apply the InverseBindMatrix to each timer callback. I had a hard time figuring out what inverse bind matrix actually does. +Here’s a good blog that answers that.

+

+ +

Read more ...

+
+
+ +
+

+ Week 12 - Fixing translating issues and updating tests +

+
    +
  • + + + 24 August 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

I started with updating the tests for PR #623 as some of the tests weren’t covering all the aspects in the code. +Previously I was just creating the DrawShape and adding it to the scene but now I had to analyze the scene to see whether they were properly added or not.

+

+ +

Read more ...

+
+
+ +
+

+ Week 10: Supporting hierarchical animating +

+
    +
  • + + + 23 August 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Mohamed Abouagour + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Implemented hierarchical order support for animations using matrices in this PR.

+

+ +

Read more ...

+
+
+ +
+

+ Week 9 - First working skeletal animation prototype +

+
    +
  • + + + 17 August 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Shivam Anand + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week I had the first working example of skeletal animation ready. I was able to render the SimpleSkin model. Here’s a quick preview:

+

+ +

Read more ...

+
+
+ +
+

+ Week 11 - Creating a base for Freehand Drawing +

+
    +
  • + + + 17 August 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week I tried to imitate the working of vtkImageTracer. Previously, I had created a small prototype for freehand drawing by adding points at the mouse position (which you can check out here). As mentioned, there were some drawback of this method. +So to overcome these issues, I tried combining both methods. Considering points using the previous method and instead of adding points I tried creating lines between them which looks promising. Below you can see a demo.

+

+ +

Read more ...

+
+
+ +
+

+ Week 9: Animating primitives of the same actor +

+
    +
  • + + + 16 August 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Mohamed Abouagour + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Made two tutorials in this PR that show two approaches on how to animate primitives of the same FURY actor using the Timeline.

+

+ +

Read more ...

+
+
+ +
+

+ Week 8 - Fixing animation bugs +

+
    +
  • + + + 10 August 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Shivam Anand + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week I had to fix the transformation issue in glTF animation. As discussed in the last meeting, I disabled vertex transformation and applied the transformation after the actor was formed.

+

+ +

Read more ...

+
+
+ +
+

+ Week 10 - Understanding Codes and Playing with Animation +

+
    +
  • + + + 10 August 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

I started working on the PR #645 created last week and tested a few more corner cases such as What happens if the maximum value is exceeded?? What if we give a value less than the minimum value range?? +Most of these worked as intended.

+

+ +

Read more ...

+
+
+ +
+

+ Week 8: Back to the shader-based version of the Timeline +

+
    +
  • + + + 09 August 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Mohamed Abouagour + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

First, I made some modifications to the main animation PR. Then as Filipi requested, I integrated the vertex shader that I was implementing a few weeks ago to work with the new improved version of the Timeline.

+

+ +

Read more ...

+
+
+ +
+

+ Week 9 - Grouping and Transforming Shapes +

+
    +
  • + + + 03 August 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

I started this week by creating a quick PR #645 for the UI sliders. The sliders raised ZeroDivsionError when the min and max values were the same. To solve this, I handled the case where the value_range becomes zero and then manually set the handle position to zero.

+

+ +

Read more ...

+
+
+ +
+

+ Week 7: Billboard spheres and implementing interpolators using closures +

+
    +
  • + + + 01 August 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Mohamed Abouagour + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Restructured the keyframe animation interpolators using closures to be functions instead of classes #647. Now it is easier to implement new interpolators with the help of the functions existing in fury/animation/helpers.py. Also, now unit tests can be added for the latter functions.

+

+ +

Read more ...

+
+
+ +
+

+ Week 7 - Fixing bugs in animations +

+
    +
  • + + + 01 August 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Shivam Anand + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week I started with implementing scaling to the animation example.

+

+ +

Read more ...

+
+
+ +
+

+ Week 8 - Working on the polyline feature +

+
    +
  • + + + 27 July 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week I started working on the polyline feature. After a lot of investigating and trying out different things, I found a way to call the dragging event manually without any prior click event. VTK actually captures the mouse movement using the MouseMoveEvent. This event is then modified by FURY to only be called after the click event. So I added a new callback to track the mouse movement and set the current canvas as an active prop because it is required to capture the drag event happening on it.

+

+ +

Read more ...

+
+
+ +
+

+ Week 6: Fixing the Timeline issues and equipping it with more features +

+
    +
  • + + + 25 July 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Mohamed Abouagour + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Improved the PlaybackPanel by adding speed control and the ability to loop the animation. Also, fixed the lagging issue of play and pause buttons and composed them into a single play/pause button.

+

+ +

Read more ...

+
+
+ +
+

+ Week 6 - Extracting the animation data +

+
    +
  • + + + 25 July 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Shivam Anand + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week, it was all about reading docs and extracting the animation data from buffers.

+

+ +

Read more ...

+
+
+ +
+

+ Week 7 - Working on Rotation PR and Trying Freehand Drawing +

+
    +
  • + + + 20 July 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

I continued PR #623 and fixed the displacement of the shape from its original position when applying rotation. This was happening because most of the calculations resulted in float values, but as the pixel position were integers we had to explicitly convert these values into int. This conversion rounded off the values and as we call this function continuously, each time the round-off would happen, the shape would get displaced.

+

+ +

Read more ...

+
+
+ +
+

+ Week 5: Slerp implementation, documenting the Timeline, and adding unit tests +

+
    +
  • + + + 19 July 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Mohamed Abouagour + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Implemented Slerp (spherical linear interpolation) for rotation keyframes.

+

+ +

Read more ...

+
+
+ +
+

+ Week 5 - Creating PR for glTF exporter and fixing the loader +

+
    +
  • + + + 19 July 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Shivam Anand + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Finalised the glTF export PR #630., adding tutorial, docs, and tests for all functions.

+

+ +

Read more ...

+
+
+ +
+

+ Week 6 - Supporting Rotation of the Shapes from the Center +

+
    +
  • + + + 13 July 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week I started implementing a new feature to rotate the shapes from the center using RingSlider2D. I already had a rotate function that rotates the shape around its pivot vertex, so I updated it to support rotation from the center.

+

+ +

Read more ...

+
+
+ +
+

+ Week 4 - Finalizing glTF loader +

+
    +
  • + + + 12 July 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Shivam Anand + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week I had to travel back to my college since the summer vacations have ended. +I had a coding session with Serge this week, we modified the exporter function and looked at some bugs I faced.

+

+ +

Read more ...

+
+
+ +
+

+ Week 4: Camera animation, interpolation in GLSL, and a single Timeline! +

+
    +
  • + + + 11 July 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Mohamed Abouagour + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Managed to implement a single Timeline using the Container class. So, instead of having two classes: Timeline and CompositeTimeline, now the Timeline can have multiple Timeline objects and controls them as in the code below.

+

+ +

Read more ...

+
+
+ +
+

+ Week 5 - Working on new features +

+
    +
  • + + + 06 July 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week I tried to create a base for some upcoming new features. +The first thing I updated was the Properties panel which I prototyped in Week 3. +So previously, it was just displaying the properties but now after the update, it is able to modify the properties(such as color, position, and rotation) too. This was a quick change to test the callbacks.

+

+ +

Read more ...

+
+
+ +
+

+ Week 3: Redesigning the API, Implementing cubic Bezier Interpolator, and making progress on the GPU side! +

+
    +
  • + + + 04 July 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Mohamed Abouagour + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Redesigned the keyframe animations API to optimize having a lot of timelines by composing them into a parent Timeline called CompositeTimeline while maintaining playing individual timelines separately.

+

+ +

Read more ...

+
+
+ +
+

+ Week 3 - Fixing fetcher, adding tests and docs +

+
    +
  • + + + 04 July 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Shivam Anand + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

The first task for this week was to fix the glTF fetcher. We noticed that while running tests it reaches the API limit. So we decided to use a JSON file that contains the download URLs for all models.

+

+ +

Read more ...

+
+
+ +
+

+ Week 4 - Fixing the Clamping Issue +

+
    +
  • + + + 29 June 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Phew!! This week was a tedious week for me as parallelly my End-Sem exams also started. So as usual I started from where I left off last week, The Clamping Issue. As per the discussion with the mentors, we decided to use the AABB bounding box method to calculate the bounding box around the shape and then reposition or transform respectively, as now we had a fixed reference point. So after doing some calculations with the mouse positions and the bounding box points at last, I was able to clamp all the shapes successfully.

+

+ +

Read more ...

+
+
+ +
+

+ Week 2 - Improving Fetcher and Exporting glTF +

+
    +
  • + + + 29 June 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Shivam Anand + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week I worked primarily on the glTF fetcher and exporting scenes to a glTF file. I added tests and docstrings for all functions. I modified the fetch_gltf function to return the downloaded files. As we planned, the PR for the glTF fetcher was merged this week.

+

+ +

Read more ...

+
+
+ +
+

+ Week 2: Implementing non-linear and color interpolators +

+
    +
  • + + + 28 June 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Mohamed Abouagour + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Implemented some other general interpolators such as n-th degree spline and cubic spline interpolators. Also implemented HSV and LAB color interpolators.

+

+ +

Read more ...

+
+
+ +
+

+ Week 3 - Dealing with Problems +

+
    +
  • + + + 22 June 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week was full of researching, playing around with things, prototyping ideas, etc. +I started with last week’s clamping issue and managed to solve this issue while drawing shapes by clipping the mouse position according to canvas size, but it didn’t solve the problem with translating these shapes. I tried solving this using various approaches, but if one thing would get fixed, other things would raise a new error.

+

+ +

Read more ...

+
+
+ +
+

+ Week 1 - A Basic glTF Importer +

+
    +
  • + + + 20 June 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Shivam Anand + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

In the community bonding period I met with my mentor Serge Koudoro, along with other mentors in FURY and gsoc contributors. +We discussed about my project and set up project timeline on github projects section. As my project (glTF Integration) +and Keyframe animations were related so we discussed on that too.

+

+ +

Read more ...

+
+
+ +
+

+ Week 1: Implementing a basic Keyframe animation API +

+
    +
  • + + + 19 June 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Mohamed Abouagour + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

During the community bonding period, we had weekly meetings in which I got to know the mentors better and bonded with Shivam and Praneeth, my fellow contributors. +We talked about the importance of open-source contribution and discussed scientific visualization, how important it is and how it differs from game engines despite having some similarities. +We also discussed how important the code review is and how to do a proper code review.

+

+ +

Read more ...

+
+
+ +
+

+ Week 2 - Improving DrawPanel UI +

+
    +
  • + + + 15 June 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week I had to refactor and make my code cleaner along with some bug fixing, I started by adding tests and tutorials so that my changes could be tested by everyone. Then I separated the mode for selection so that it would be easy to select an individual element and work along with it. Once the selection mode was complete I started with the deletion of the elements.

+

+ +

Read more ...

+
+
+ +
+

+ Week 1 - Laying the Foundation of DrawPanel UI +

+
    +
  • + + + 08 June 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week we started with our first technical meeting in which the weekly tasks were assigned. So I had to start with some background or canvas and draw a line using mouse clicks.

+

+ +

Read more ...

+
+
+ +
+

+ Pre-GSoC Journey +

+
    +
  • + + + 25 May 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hello Guys!! I am Praneeth Shetty, currently pursuing Bachelor of Engineering in Computer Engineering, and here is my journey from where I started to the selection into GSoC22.

+

+ +

Read more ...

+
+
+ +
+

+ My Journey to GSoC 2022 +

+
    +
  • + + + 24 May 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Shivam Sahu + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hi! I’m Shivam, currently pursuing my bachelor’s (expected 2024) in Production and Industrial engineering from the Indian Institute of Technology (IIT) Roorkee.

+

+ +

Read more ...

+
+
+ +
+

+ My journey till getting accepted into GSoC22 +

+
    +
  • + + + 23 May 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Mohamed Abouagour + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

My name is Mohamed and I’m from Egypt. I am pursuing a Bachelor of Engineering in Computer Engineering and Automatic Control (expected: 2023), Tanta University, Egypt.

+

+ +

Read more ...

+
+
+ +
+

+ Contribute to FURY via Google Summer of Code 2022 +

+
    +
  • + + + 01 February 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Serge Koudoro + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

FURY is participating in the Google Summer of Code 2022 under the umbrella of the Python Software Foundation.

+

+ +

Read more ...

+
+
+ +
+

+ FURY 0.8.0 Released +

+
    +
  • + + + 31 January 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Serge Koudoro + + + +
  • + + + + +
  • + + + Category: + + + + + release + + + +
  • + + +
  • + + + + Tag: + + + + + fury + + + +
  • + + +
    +
+

The FURY project is happy to announce the release of FURY 0.8.0! +FURY is a free and open source software library for scientific visualization and 3D animations.

+

+ +

Read more ...

+
+
+ + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/blog/2022/atom.xml b/v0.10.x/blog/2022/atom.xml new file mode 100644 index 000000000..15cb61ca2 --- /dev/null +++ b/v0.10.x/blog/2022/atom.xml @@ -0,0 +1,401 @@ + + + https://fury.gl/ + Blog - Posted in 2022 + 2024-02-29T15:43:57.699363+00:00 + + + ABlog + + https://fury.gl/posts/2022/2022-09-28-week-14-mohamed.html + Week 14: Keyframes animation is now a bit easier in FURY + 2022-09-28T00:00:00-04:00 + + Mohamed Abouagour + + <section id="week-14-keyframes-animation-is-now-a-bit-easier-in-fury"> + +<section id="what-did-you-do-this-week"> +<h2>What did you do this week?</h2> +<ul class="simple"> +<li><p>Separated the <code class="docutils literal notranslate"><span class="pre">Timeline</span></code> into a <code class="docutils literal notranslate"><span class="pre">Timeline</span></code> and an <code class="docutils literal notranslate"><span class="pre">Animation</span></code>. So, instead of having the <code class="docutils literal notranslate"><span class="pre">Timeline</span></code> do everything. It’s now more like doing animations in Blender and other 3D editing software where the timeline handles the playback of several animations <a class="reference external" href="https://github.com/fury-gl/fury/pull/694">#694</a>.</p></li> +<li><p>Added unit tests for the billboards based on geometry shader.</p></li> +<li><p>Tried to solve the issue with actors not being rendered when their positions are changed in the vertex shader. For now, I just found a way to force invoke the shader callbacks, but force rendering the actor itself still needs more investigation.</p></li> +</ul> +</section> +<section id="what-is-coming-up-next-week"> +<h2>What is coming up next week?</h2> +<ul class="simple"> +<li><p>Add unit testing for the <code class="docutils literal notranslate"><span class="pre">Animation</span></code>, document it well, and implement more properties suggested by Shivam (&#64;xtanion).</p></li> +<li><p>Modify <a class="reference external" href="https://github.com/fury-gl/fury/pull/690">Add Timelines to ShowManager directly</a> PR to allow adding <code class="docutils literal notranslate"><span class="pre">Animation</span></code> to the <code class="docutils literal notranslate"><span class="pre">ShowManager</span></code> as well.</p></li> +<li><p>Update tutorials to adapt to all the new changes in the <code class="docutils literal notranslate"><span class="pre">animation</span></code> module.</p></li> +</ul> +</section> +<section id="did-you-get-stuck-anywhere"> +<h2>Did you get stuck anywhere?</h2> +<ul class="simple"> +<li><p>I got stuck trying to solve the issue mentioned above with actors not being rendered.</p></li> +</ul> +</section> +</section> + + + Separated the Timeline into a Timeline and an Animation. So, instead of having the Timeline do everything. It’s now more like doing animations in Blender and other 3D editing software where the timeline handles the playback of several animations #694. + + 2022-09-28T00:00:00-04:00 + + + https://fury.gl/posts/2022/2022-09-28-week-14-shivam.html + Week 14 - Morphing is here! + 2022-09-28T00:00:00-04:00 + + Shivam Anand + + <section id="week-14-morphing-is-here"> + +<section id="what-did-you-do-this-week"> +<h2>What did you do this week?</h2> +<ul class="simple"> +<li><p>This week, I started with multiple actor support in skinning and managed to do it +successfully. Here’s the preview using the BrainStem model.</p></li> +</ul> +<iframe id="player" type="text/html" width="600" height="340" src="https://user-images.githubusercontent.com/74976752/195650455-927a0238-5db1-4349-99d4-c021db356b66.mp4" frameborder="0"></iframe><ul class="simple"> +<li><p>Implementing multiple animation channels support (as seen in the <code class="docutils literal notranslate"><span class="pre">Fox</span></code> model). The <code class="docutils literal notranslate"><span class="pre">get_skin_timelines()</span></code> method now returns a dictionary of all animation channels with Timeline as their value.</p></li> +<li><p>We merged two PRs, <a class="reference external" href="https://github.com/fury-gl/fury/pull/689/">#689</a> (colors from Material) and <a class="reference external" href="https://github.com/fury-gl/fury/pull/643/">#643</a> (simple animations).</p></li> +<li><p>Added ability to load morphing information and create timelines from it. Here’s a preview of the <code class="docutils literal notranslate"><span class="pre">AnimatedMorphCube</span></code> and <code class="docutils literal notranslate"><span class="pre">AnimatedMorphSphere</span></code> models:</p></li> +</ul> +<iframe id="player" type="text/html" width="600" height="340" src="https://user-images.githubusercontent.com/74976752/195654414-b290900c-b80f-40c7-a49d-5ea8413e906a.mp4" frameborder="0"></iframe></section> +<section id="what-is-coming-up-next-week"> +<h2>What is coming up next week?</h2> +<ul class="simple"> +<li><p>Cleaning and Rebasing Skinning animation PR <a class="reference external" href="https://github.com/fury-gl/fury/pull/685/">#685</a>.</p></li> +<li><p>Creating a PR for morphing code.</p></li> +<li><p>Multi primitive (actor) support in morphing.</p></li> +</ul> +</section> +<section id="did-you-get-stuck-anywhere"> +<h2>Did you get stuck anywhere?</h2> +<ul class="simple"> +<li><p>No, I didn’t get stuck this week.</p></li> +</ul> +</section> +</section> + + + This week, I started with multiple actor support in skinning and managed to do it +successfully. Here’s the preview using the BrainStem model. + + 2022-09-28T00:00:00-04:00 + + + https://fury.gl/posts/2022/2022-09-21-week-16-praneeth.html + Week 16 - Working with Rotations! + 2022-09-21T00:00:00-04:00 + + Praneeth Shetty + + <section id="week-16-working-with-rotations"> + +<section id="what-did-you-do-this-week"> +<h2>What did you do this week?</h2> +<p>Last week my mentors noticed that each <cite>DrawShape</cite> has its individual <cite>rotation_slider</cite> which increases redundancy and complexity in setting its visibility on and off. Instead, they suggested moving the <cite>rotation_slider</cite> to <cite>DrawPanel</cite> and keeping a common slider for all the shapes.</p> +<p>PR <a class="reference external" href="https://github.com/fury-gl/fury/pull/688">#688</a> does the above mentioned thing. +There isn’t any visual difference as everything is as it was earlier, just the code was modified a bit to make it work properly.</p> +<p>After this, I started working with the rotation for the <cite>Polyline</cite> feature. For rotating the <cite>Polyline</cite>, I implemented something similar to what I had did while rotating the individual shapes. Firstly I calculate the bounding box and the center of the shape, then apply the rotation to the points through which the polyline was generated.</p> +<p><a class="reference external" href="https://github.com/ganimtron-10/fury/tree/polyline-with-grouping">Polyline:</a></p> +<img alt="https://user-images.githubusercontent.com/64432063/193308748-6bc14acb-b687-4d88-9c41-12991186a104.gif" class="align-center" src="https://user-images.githubusercontent.com/64432063/193308748-6bc14acb-b687-4d88-9c41-12991186a104.gif" style="width: 400px;" /> +<p>As we can see above the rotation seems correct but as earlier the shape is translating from its original center. This should be easy to fix.</p> +</section> +<section id="did-you-get-stuck-anywhere"> +<h2>Did you get stuck anywhere?</h2> +<p>Instead of implementing the approaches for creating and managing the <cite>Polyline</cite>, I kept on thinking of various ideas on how I could do so, which wasted my time. I should have thought about some approaches and tried to implement them so that I would get an idea of whether things would work or not.</p> +</section> +<section id="what-is-coming-up-next"> +<h2>What is coming up next?</h2> +<p>Working on <cite>Polyline</cite> to make sure everything works fine.</p> +</section> +</section> + + + Last week my mentors noticed that each DrawShape has its individual rotation_slider which increases redundancy and complexity in setting its visibility on and off. Instead, they suggested moving the rotation_slider to DrawPanel and keeping a common slider for all the shapes. + + 2022-09-21T00:00:00-04:00 + + + https://fury.gl/posts/2022/2022-09-20-week-13-mohamed.html + Week 13: Keyframes animation is now a bit easier in FURY + 2022-09-20T00:00:00-04:00 + + Mohamed Abouagour + + <section id="week-13-keyframes-animation-is-now-a-bit-easier-in-fury"> + +<section id="what-did-you-do-this-week"> +<h2>What did you do this week?</h2> +<ul> +<li><p>Added the ability to have the ShowManager stored inside the Timeline. That way the user does not have to update and render the animations because it will be done internally.</p></li> +<li><p>Added a record method to the Timeline that records the animation and saves it as either GIF or MP4 (requires OpenCV). This record functionality has the option to show/hide the PlaybackPanel which makes it better than recording the animation using a third-party software.</p> +<blockquote> +<div><img alt="https://user-images.githubusercontent.com/63170874/190892795-f47ceaf1-8dd0-4235-99be-2cf0aec323bb.gif" class="align-center" src="https://user-images.githubusercontent.com/63170874/190892795-f47ceaf1-8dd0-4235-99be-2cf0aec323bb.gif" style="width: 600px;" /> +</div></blockquote> +</li> +<li><p>Fixed some issues that Serge mentioned while reviewing PR <a class="reference external" href="https://github.com/fury-gl/fury/pull/665">#665</a>.</p></li> +</ul> +</section> +<section id="what-is-coming-up-next-week"> +<h2>What is coming up next week?</h2> +<ul class="simple"> +<li><p>Instead of adding the ShowManager to the Timeline, doing it the other way around is a better choice and makes the code more readable.</p></li> +<li><p>Add tests for the Timeline’s record method.</p></li> +<li><p>Add tests for the billboard actor to test consistency among different approaches..</p></li> +</ul> +</section> +<section id="did-you-get-stuck-anywhere"> +<h2>Did you get stuck anywhere?</h2> +<p>I didn’t get stuck this week.</p> +</section> +</section> + + + Added the ability to have the ShowManager stored inside the Timeline. That way the user does not have to update and render the animations because it will be done internally. + + 2022-09-20T00:00:00-04:00 + + + https://fury.gl/posts/2022/2022-09-15-week-13-blog.html + Week 13 - Multi-bone skeletal animation support + 2022-09-15T00:00:00-04:00 + + Shivam Anand + + <section id="week-13-multi-bone-skeletal-animation-support"> + +<section id="what-did-you-do-this-week"> +<h2>What did you do this week?</h2> +<p>This week I fixed all the issues with skeletal animations, and we got to see our first render of skeletal animation :).</p> +<ul class="simple"> +<li><p>Implemented a hierarchical timeline system (i.e., one timeline for each bone, and the timeline will contain its parent timeline in a hierarchy).</p></li> +<li><p>I figured out that we don’t need to apply the parent transform as we’re applying it to the vertex data while forming the actor. So the skin matrix becomes</p></li> +</ul> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2022/2022-09-15-week-13-blog.rst</span>, line 18)</p> +<p>Bullet list ends without a blank line; unexpected unindent.</p> +</aside> +<p><code class="docutils literal notranslate"><span class="pre">SkinMatrix</span> <span class="pre">=</span> <span class="pre">InverseBindPose</span> <span class="pre">*</span> <span class="pre">BoneDeform</span></code> where <code class="docutils literal notranslate"><span class="pre">BoneDeform</span> <span class="pre">=</span> <span class="pre">CurrentBoneTransform</span> <span class="pre">*</span> <span class="pre">ParentBonetransform</span></code>.</p> +<p>Here’s a preview using the <code class="docutils literal notranslate"><span class="pre">CesiumMan</span></code> model:</p> +<blockquote> +<div><iframe id="player" type="text/html" width="1280" height="600" src="https://user-images.githubusercontent.com/74976752/190474528-9d66651b-032f-4c7d-9bb6-5ad140017d0c.mp4" frameborder="0"></iframe></div></blockquote> +</section> +<section id="what-is-coming-up-next-week"> +<h2>What is coming up next week?</h2> +<ul class="simple"> +<li><p>Add tests for simple animation PR <a class="reference external" href="https://github.com/fury-gl/fury/pull/643/">#643</a>.</p></li> +<li><p>Multiple actor support for skeletal animation.</p></li> +<li><p>Take a look at Morphing.</p></li> +</ul> +</section> +<section id="did-you-get-stuck-anywhere"> +<h2>Did you get stuck anywhere?</h2> +<ul class="simple"> +<li><p>No, I didn’t get stuck this week.</p></li> +</ul> +</section> +</section> + + + This week I fixed all the issues with skeletal animations, and we got to see our first render of skeletal animation :). + + 2022-09-15T00:00:00-04:00 + + + https://fury.gl/posts/2022/2022-09-14-week-15-praneeth.html + Week 15 - Highlighting DrawShapes + 2022-09-14T00:00:00-04:00 + + Praneeth Shetty + + <section id="week-15-highlighting-drawshapes"> + +<section id="what-did-you-do-this-week"> +<h2>What did you do this week?</h2> +<p>This week I started with highlighting the shapes. As discussed earlier, I had two ways, but while implementing them, I found out both ways aren’t that good to continue with. +The first way in which we thought of creating the scaled shapes in the background had an issue with the stacking. The border(blue rectangle) and the shape(grey rectangle) both seem to look like different shapes just grouped together as shown below.</p> +<img alt="https://user-images.githubusercontent.com/64432063/192321622-964cef6e-f965-4a24-8dcf-0b899fe5e387.gif" class="align-center" src="https://user-images.githubusercontent.com/64432063/192321622-964cef6e-f965-4a24-8dcf-0b899fe5e387.gif" style="width: 400px;" /> +<p>While playing around with the second way, which was to add yellow color to the shape to make it brighter, it was difficult to identify which shape was selected. Also sometimes instead of making it brighter the addition of color created a new color which again confused the user. +After discussing these issues my mentors suggested having a user-defined highlight color that will be shown whenever the shape is selected.</p> +<img alt="https://user-images.githubusercontent.com/64432063/192326416-4454718d-1dda-4a13-9f97-07387a50a580.gif" class="align-center" src="https://user-images.githubusercontent.com/64432063/192326416-4454718d-1dda-4a13-9f97-07387a50a580.gif" style="width: 400px;" /> +<p>Along this, we were also trying to integrate shaders to the Actor2D (i.e. the UI elements) but there were some issues with it. I used <a class="reference external" href="https://fury.gl/latest/auto_tutorials/03_shaders/viz_shader.html#sphx-glr-auto-tutorials-03-shaders-viz-shader-py">this</a> shaders example as a starting point and just replaced the <cite>utah</cite> actor by Rectangle2D actor. This program executed successfully without any errors, but it didn’t give the required output.</p> +<p>So instead of wasting time searching for how it is done, we thought it would be great if we directly ask in the VTK discourse forum. For this, I had to create a minimalistic pure VTK code. You can check out my code as well as the post <a class="reference external" href="https://discourse.vtk.org/t/how-to-connect-shaders-to-actor2d/9384">here</a>.</p> +</section> +<section id="did-you-get-stuck-anywhere"> +<h2>Did you get stuck anywhere?</h2> +<p>No, I didn’t get stuck this week.</p> +</section> +<section id="what-is-coming-up-next"> +<h2>What is coming up next?</h2> +<p>Working on the rotation slider and the polyline.</p> +</section> +</section> + + + This week I started with highlighting the shapes. As discussed earlier, I had two ways, but while implementing them, I found out both ways aren’t that good to continue with. +The first way in which we thought of creating the scaled shapes in the background had an issue with the stacking. The border(blue rectangle) and the shape(grey rectangle) both seem to look like different shapes just grouped together as shown below. + + 2022-09-14T00:00:00-04:00 + + + https://fury.gl/posts/2022/2022-09-08-week-12-shivam.html + Week 12 - Adding skeleton as actors and fix global transformation + 2022-09-08T00:00:00-04:00 + + Shivam Anand + + <section id="week-12-adding-skeleton-as-actors-and-fix-global-transformation"> + +<section id="what-did-you-do-this-week"> +<h2>What did you do this week?</h2> +<ul class="simple"> +<li><p>I started this week by fixing the segmentation fault for the skinning test. I could not fix this as of now.</p></li> +<li><p>I imported the <code class="docutils literal notranslate"><span class="pre">RiggedFigure</span></code> model into the Blender and I was quite impressed with how it visualizes each bone. So, I created a function that creates an arrow actor in place of a bone, and by applying the correct transformation, we get the bones of a model in place. Here’s a quick preview of bones in Blender vs bones in FURY:</p></li> +</ul> +<img alt="https://user-images.githubusercontent.com/74976752/189194609-e55f6285-b5ed-4eb3-9e78-5fb462fb2dee.png" class="align-center" src="https://user-images.githubusercontent.com/74976752/189194609-e55f6285-b5ed-4eb3-9e78-5fb462fb2dee.png" style="width: 500px;" /> +<img alt="https://user-images.githubusercontent.com/74976752/189195853-5b1f8945-9822-48f5-8d55-f13e822a43a7.png" class="align-center" src="https://user-images.githubusercontent.com/74976752/189195853-5b1f8945-9822-48f5-8d55-f13e822a43a7.png" style="width: 500px;" /> +<ul class="simple"> +<li><p>After having the bones actor, I noticed that some bones are not aligned correctly. It was happening due to multiplication of the same transformation matrix twice.</p></li> +<li><p>I also created a function that calculates the total transformation of a node, it eliminates the need to use <code class="docutils literal notranslate"><span class="pre">timeline.get_value</span></code> in <code class="docutils literal notranslate"><span class="pre">get_skin_timeline</span></code> function.</p></li> +</ul> +</section> +<section id="what-is-coming-up-next-week"> +<h2>What is coming up next week?</h2> +<ul class="simple"> +<li><p>It seems like I fixed everything, but we are not getting the correct model at timestamp 0. We need to find the cause and fix it!</p></li> +<li><p>Cleaning the Simple Animation PR <a class="reference external" href="https://github.com/fury-gl/fury/pull/643/">#643</a>, and merging it.</p></li> +</ul> +</section> +<section id="did-you-get-stuck-anywhere"> +<h2>Did you get stuck anywhere?</h2> +<ul class="simple"> +<li><p>While applying the timeline, we were getting the identity matrix for timestamp 0.0s, it was set to a new value before. We figured this in our meeting that it’s happening due to some model’s animation not starting from 0.0s.</p></li> +</ul> +<img alt="https://user-images.githubusercontent.com/74976752/189196234-b28f86f7-223b-40e4-94bf-2ec18d914487.png" class="align-center" src="https://user-images.githubusercontent.com/74976752/189196234-b28f86f7-223b-40e4-94bf-2ec18d914487.png" style="width: 400px;" /> +</section> +</section> + + + I started this week by fixing the segmentation fault for the skinning test. I could not fix this as of now. + + 2022-09-08T00:00:00-04:00 + + + https://fury.gl/posts/2022/2022-09-07-week-14-praneeth.html + Week 14 - Updating DrawPanel architecture + 2022-09-07T00:00:00-04:00 + + Praneeth Shetty + + <section id="week-14-updating-drawpanel-architecture"> + +<section id="what-did-you-do-this-week"> +<h2>What did you do this week?</h2> +<p>This week I continued updating the DrawShape and DrawPanel.</p> +<p>So as we can see below, whenever we create, translate, or rotate the shapes on the panel, it sometimes overlaps the <cite>mode_panel</cite> or <cite>mode_text</cite> which are used to select and show the current mode respectively.</p> +<img alt="https://user-images.githubusercontent.com/64432063/188268649-65ea24f0-3f46-4545-8e52-e07513a94b9f.gif" class="align-center" src="https://user-images.githubusercontent.com/64432063/188268649-65ea24f0-3f46-4545-8e52-e07513a94b9f.gif" style="width: 400px;" /> +<p>To resolve this, I created a PR <a class="reference external" href="https://github.com/fury-gl/fury/pull/678">#678</a> which moves the <cite>mode_panel</cite> and the <cite>mode_text</cite> to be on the borders of the panel.</p> +<img alt="https://user-images.githubusercontent.com/64432063/188268804-949ec656-7da3-4310-ba8b-7e4f0281faa1.gif" class="align-center" src="https://user-images.githubusercontent.com/64432063/188268804-949ec656-7da3-4310-ba8b-7e4f0281faa1.gif" style="width: 400px;" /> +<p>Along this, there were some similar functionalities in the <a class="reference external" href="https://github.com/fury-gl/fury/pull/653">Grouping Shapes PR</a> and the <cite>DrawShape</cite> due to which some lines of code were repeating. To remove this duplicacy I created a PR <a class="reference external" href="https://github.com/fury-gl/fury/pull/679">#679</a> to move these functions to the <cite>helper.py</cite> file.</p> +<p>Then I tried different ways of highlighting the shapes,</p> +<ol class="arabic simple"> +<li><p>To create a copy of the shape and scale it in the background so that it looks like a border or highlighted edges.</p></li> +<li><p>Add yellow color to the shape so that it looks brighter.</p></li> +</ol> +</section> +<section id="did-you-get-stuck-anywhere"> +<h2>Did you get stuck anywhere?</h2> +<p>No, I didn’t get stuck this week.</p> +</section> +<section id="what-is-coming-up-next"> +<h2>What is coming up next?</h2> +<p>Working on these new PRs to get them merged. Implement a highlighting feature.</p> +</section> +</section> + + + This week I continued updating the DrawShape and DrawPanel. + + 2022-09-07T00:00:00-04:00 + + + https://fury.gl/posts/2022/2022-09-7-week-12-mohamed.html + Week 12: Adding new tutorials + 2022-09-07T00:00:00-04:00 + + Mohamed Abouagour + + <section id="week-12-adding-new-tutorials"> + +<section id="what-did-you-do-this-week"> +<h2>What did you do this week?</h2> +<ul class="simple"> +<li><p>Restructured tutorials to be more readable and more focused on a specific topic.</p></li> +<li><p>Replaced the old animation introductory tutorial with a lot simpler one, and added tutorial to explain keyframes and interpolators.</p></li> +<li><p>Simplified setting lighting uniforms for the geometry-based-billboard actor by getting the <code class="docutils literal notranslate"><span class="pre">Scene</span></code> from the actor using <code class="docutils literal notranslate"><span class="pre">actor.GetConsumer(scene_idx)</span></code>.</p></li> +</ul> +</section> +<section id="what-is-coming-up-next-week"> +<h2>What is coming up next week?</h2> +<ul class="simple"> +<li><p>Allow the <code class="docutils literal notranslate"><span class="pre">Timeline</span></code> to take the <code class="docutils literal notranslate"><span class="pre">ShowManager</span></code> as an argument to reduce the amount of code the user has to write every time using FURY animations.</p></li> +<li><p>Fix some typos in the tutorials and write some info about <code class="docutils literal notranslate"><span class="pre">Slerp</span></code>.</p></li> +<li><p>Find a way to fix the shader-callback problem of not being executed when the actor is out of the camera’s frustum.</p></li> +</ul> +</section> +<section id="did-you-get-stuck-anywhere"> +<h2>Did you get stuck anywhere?</h2> +<p>I didn’t get stuck this week.</p> +</section> +</section> + + + Restructured tutorials to be more readable and more focused on a specific topic. + + 2022-09-07T00:00:00-04:00 + + + https://fury.gl/posts/2022/2022-08-31-week-13-praneeth.html + Week 13 - Separating tests and fixing bugs + 2022-08-31T00:00:00-04:00 + + Praneeth Shetty + + <section id="week-13-separating-tests-and-fixing-bugs"> + +<section id="what-did-you-do-this-week"> +<h2>What did you do this week?</h2> +<p>This week I managed to fix the translation issue in PR <a class="reference external" href="https://github.com/fury-gl/fury/pull/653">#653</a>. This was happening because of the calculation error while repositioning the shapes. Now it works as intended.</p> +<img alt="https://user-images.githubusercontent.com/64432063/187058183-840df649-163e-44dd-8104-27d6c2db87a9.gif" class="align-center" src="https://user-images.githubusercontent.com/64432063/187058183-840df649-163e-44dd-8104-27d6c2db87a9.gif" style="width: 400px;" /> +<p>Also, the PR <a class="reference external" href="https://github.com/fury-gl/fury/pull/623">#623</a> got merged as now the tests were passing after the update.</p> +<p>As we are now adding new features to the DrawPanel, the current tests are becoming bigger and bigger. +Due to this creating, debugging, and managing tests are becoming harder. +So to keep things simple, separating the tests to validate individual parts and features of the DrawPanel. This was done in PR <a class="reference external" href="https://github.com/fury-gl/fury/pull/674">#674</a>.</p> +<p>Along this, there was a redundant parameter called <cite>in_progress</cite>, which was used to keep a check whether the shapes are added to the panel or not, but it was confusing, and discarding it didn’t affect the codebase. So PR <a class="reference external" href="https://github.com/fury-gl/fury/pull/673">#673</a> removed that parameter and separated the two functions.</p> +</section> +<section id="did-you-get-stuck-anywhere"> +<h2>Did you get stuck anywhere?</h2> +<aside class="system-message"> +<p class="system-message-title">System Message: INFO/1 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2022/2022-08-31-week-13-praneeth.rst</span>, line 3); <em><a href="#id5">backlink</a></em></p> +<p>Duplicate explicit target name: “#653”.</p> +</aside> +<p>Debugging the issue in PR <a class="reference external" href="https://github.com/fury-gl/fury/pull/653">#653</a> took most of the time this week. I had to manually calculate and check whether the calculations were correct or not.</p> +</section> +<section id="what-is-coming-up-next"> +<h2>What is coming up next?</h2> +<p>Currently, the borders around the shapes are not actually the borders, they are the bounding box of that shape. So I have to find out some ways to highlight the shapes when selected by the user.</p> +</section> +</section> + + + This week I managed to fix the translation issue in PR #653. This was happening because of the calculation error while repositioning the shapes. Now it works as intended. + + 2022-08-31T00:00:00-04:00 + + diff --git a/v0.10.x/blog/2023.html b/v0.10.x/blog/2023.html new file mode 100644 index 000000000..f38aa40a6 --- /dev/null +++ b/v0.10.x/blog/2023.html @@ -0,0 +1,3810 @@ + + + + + + + Posted in 2023 — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +
+

+ + Posted in + + 2023 + +

+ + +
+

+ Google Summer of Code Final Work Product +

+
    +
  • + + + 25 August 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Name: Praneeth Shetty

+

+ +

Read more ...

+
+
+ +
+

+ Week 12 : Experimenting with ODFs implementation +

+
    +
  • + + + 24 August 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Tania Castillo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

There were different issues I needed to address for the ODF implementation. Even though I could not solve any of them completely, I did check each of the issues and made some progress. All the work in progress is being recorded in the following branch SH-for-ODF-impl, which when ready will be associated with a well-structured PR.

+

+ +

Read more ...

+
+
+ +
+

+ Google Summer of Code Final Work Product +

+
    +
  • + + + 24 August 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Tania Castillo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Name: Tania Castillo

+

+ +

Read more ...

+
+
+ +
+

+ Week 12: Now That is (almost) a Wrap! +

+ +

Hello everyone, it’s time for another GSoC blogpost! Today, I am going to talk about some minor details I worked on last week on my +project.

+

+ +

Read more ...

+
+
+ +
+

+ Google Summer of Code Final Work Product +

+ +

Name: João Victor Dell Agli Floriano

+

+ +

Read more ...

+
+
+ +
+

+ Week 12: FileDialog Quest Begins! +

+
    +
  • + + + 19 August 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

During this week, I initiated my work on the FileDialog PR, which had been started by Soham. The initial version of the FileDialog can be found at #294. To start, I focused on rebasing the PR. Since this PR was based on an older version, there were some updates to the overall UI structure that needed to be addressed for compatibility. While handling this, I identified a set of issues that I documented in the current PR #832. These mainly revolved around:

+

+ +

Read more ...

+
+
+ +
+

+ Week 11 : Adjusting ODF implementation and looking for solutions on issues found +

+
    +
  • + + + 16 August 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Tania Castillo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

I continued to experiment with the ODF glyph implementation. Thanks to one of my mentors I figured out how to get the missing data corresponding to the SH coefficients \(a^l_m\) part of the function \(f(\theta, \phi)\) described here. I also was told to make sure to implement the correct SH basis since there are different definitions from the literature, I have to focus now in the one proposed by Descoteaux, described in this paper, which is labeled in dipy as descoteaux07. To do this I had to make a small adjustment to the base implementation that I took as a reference, from which I obtained a first result using SH of order 4.

+

+ +

Read more ...

+
+
+ +
+

+ Week 11: A Refactor is Sometimes Needed +

+ +

Hello everyone, it’s time for another weekly blogpost! Today I am going to share some updates on the API refactoring +I was working on with my mentors.

+

+ +

Read more ...

+
+
+ +
+

+ Week 11: Bye Bye SpinBox +

+
    +
  • + + + 12 August 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Building upon the progress of the previous week, a major milestone was reached with the merging of PR #830. This PR added essential “getters” and “setters” for the new features of TextBlock, making it easier to handle changes. This, in turn, facilitated the integration of SpinBoxUI with the updated TextBlock.

+

+ +

Read more ...

+
+
+ +
+

+ Week 10 : Start of SH implementation experiments +

+
    +
  • + + + 08 August 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Tania Castillo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

I started formally working on SH implementation. I was told to start first doing a simple program where I can modify in real-time the order \(l\) and degree \(m\), parameters corresponding to the Spherical Harmonics function \(Y^m_l(\theta,\phi)=\), based on previous work. That is just one part of the final ODF calculation, but here is what a first experimental script looks like.

+

+ +

Read more ...

+
+
+ +
+

+ Week 10: Ready for Review! +

+ +

Hello everyone, it’s time for another weekly blogpost!

+

+ +

Read more ...

+
+
+ +
+

+ Week 10: Its time for a Spin-Box! +

+
    +
  • + + + 05 August 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week, my focus shifted to the SpinBoxUI after wrapping up work on TextBlock2D. SpinBoxUI is a component that allows users to select a value by spinning through a range. To ensure a smooth transition, I made adjustments in SpinBoxUI to align it with the recent updates in TextBlock2D. To make things even clearer and more user-friendly, I initiated a continuous code improvement process. I introduced setters and getters that enable easier customization of TextBlock2D’s new features, such as auto_font_scale and dynamic_bbox. These tools simplify the process of adjusting these settings, and you can see the ongoing changes in pull request #830.

+

+ +

Read more ...

+
+
+ +
+

+ Week 9: Tutorial done and polishing DTI uncertainty +

+
    +
  • + + + 31 July 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Tania Castillo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

I addressed the comments from the tutorial of PR #818 related to how to display specific visualizations I wanted to make. I was suggested to use ShowManager to handle the zoom of the scene and also to use GridUI to display several actors at the same time for a visual quality comparison of the tensors. Below are some images generated for the tutorial that is almost done.

+

+ +

Read more ...

+
+
+ +
+

+ Week 9: It is Polishing Time! +

+ +

Hello everyone, it’s time for another weekly blogpost! Today, I am going to update you on my project’s latest changes.

+

+ +

Read more ...

+
+
+ +
+

+ Week 9: TextBlock2D is Finally Merged! +

+
    +
  • + + + 29 July 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Continuing from the previous week, it seemed like we were almost done with the TextBlock2D, but there remained a final task of addressing conflicting issues. Being a core part of the UI, TextBlock2D had a few compatibility problems with certain other UI elements.

+

+ +

Read more ...

+
+
+ +
+

+ Week 8: Working on Ellipsoid Tutorial and exploring SH +

+
    +
  • + + + 25 July 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Tania Castillo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

I mainly worked on the ellipsoid actor tutorial, as PR #791 is finally merged, so I was able to complete the tutorial by adding my implementation. In addition, during the weekly meeting, I received a good overview of the next issue I will be working on, which is using raymarching SDFs to display spherical harmonics (SH) for visualizing ODF glyphs for DTI. I got several ideas and resources which I can start experimenting with, such as Shadertoy and some base implementations from other FURY contributors. The main drawback when creating these objects is the amount of data required to create them, because depending on the SH order, the number of parameters that the function receives may vary, also unlike the tensors, which are represented only with a 3x3 matrix, here we could have more than 9 values associated with a single glyph, so passing the information from python to the shaders is not so trivial, besides requiring more resources as there is more information that needs to be processed. Some ideas I received were using matrixes instead of vectors, using templating, or even using texture to pass the data. I started to explore these options further, as well as to review in more detail the existing implementations of SH with raymarching, in order to understand them better.

+

+ +

Read more ...

+
+
+ +
+

+ Week 8: The Birth of a Versatile API +

+ +

Hello everyone, it’s time for another weekly blogpost! Today, I am going to tell you all about how is the KDE API development going, and +to show you the potential this holds for the future!

+

+ +

Read more ...

+
+
+ +
+

+ Week 8: Another week with TextBlockUI +

+
    +
  • + + + 22 July 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week, I delved deeper into the TextBlock2D Bounding Box PR to address the challenges with tests and offsetting issues. In a pair programming session with my mentor, we discovered that the offsetting background problem stemmed from the dynamic nature of the bounding box. The issue arose when the RingSlider2D component began with an initial text size larger than the current text, which changed as the value was adjusted between 0-100%. This resulted in problems with offsetting and shrinking the bounding box. To resolve this, we decided to make the dynamic bounding box an optional feature.

+

+ +

Read more ...

+
+
+ +
+

+ Week 7: Experimentation Done +

+ +

Hello everyone, welcome to another weekly blogpost! Let’s talk about the current status of my project (spoiler: it is beautiful).

+

+ +

Read more ...

+
+
+ +
+

+ Week 7: Adjustments on the Uncertainty Cones visualization +

+
    +
  • + + + 17 July 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Tania Castillo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

I was told to refactor some parts of the uncertainty PR, since I was relying too much on dipy functions which is not good because it makes maintenance more difficult as dipy requires FURY for some functionalities. So I did some adjustments on the uncertainty function parameters and the corresponding tests, hopefully I managed to get with the most appropriate definition but I need to receive a first feedback to see how much I have to adjust the implementation. As I had to delete some relevant code lines inside the uncertainty calculation which consisted of preprocessing the data in order to define the necessary variables for the uncertainty formula, I was also suggested to make a tutorial of this new feature, so I can explain in detail how to obtain and adjust the necessary information, before passing it to the actor, and in general how and what is the purpose of this new function.

+

+ +

Read more ...

+
+
+ +
+

+ Week 7: Sowing the seeds for TreeUI +

+
    +
  • + + + 15 July 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week, I focused on completing the TextBlock2D Bounding Box feature. However, the tests were failing due to automatic background resizing based on content and improper text actor alignment during setup. I encountered difficulties while positioning the text, which caused the text to appear offset and led to test failures.

+

+ +

Read more ...

+
+
+ +
+

+ Week 6: Things are Starting to Build Up +

+ +

Hello everyone, time for a other weekly blogpost! Today, I will show you my current progress on my project and latest activities.

+

+ +

Read more ...

+
+
+ +
+

+ Week 6: First draft of the Ellipsoid tutorial +

+
    +
  • + + + 10 July 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Tania Castillo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

#PR 818: Tutorial on using ellipsoid actor to visualize tensor ellipsoids for DTI

+

+ +

Read more ...

+
+
+ +
+

+ Week 6: BoundingBox for TextBlock2D! +

+
    +
  • + + + 08 July 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week, I worked on improving the TextBlock2D component in the UI system. I started from scratch to address alignment and scaling issues. When resizing the TextBlock2D, the text alignment and justification with the background rectangle were inconsistent. To resolve this, I introduced a new “boundingbox” property that calculates the text bounding box based on its content. Additionally, I separated the scaling mode from the resizing action with the new “auto_font_scale” property, enabling automatic font scaling according to the bounding box. This will provide better alignment, justified text, and smoother font scaling for the TextBlock2D component. Try it out at PR #803.

+

+ +

Read more ...

+
+
+ +
+

+ Week 5: Preparing the data for the Ellipsoid tutorial +

+
    +
  • + + + 03 July 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Tania Castillo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

During the weekly meeting with my mentors, there was a small discussion over the naming of the actor and its usage. On the one hand, although the purpose of the actor is to visualize diffusion tensor ellipsoids, the idea is that it can also be used for any other type of visualization that requires the use of ellipsoids, so in the end, we decided to keep the name ellipsoid as it is more generic. On the other hand, as there is already an actor made for the purpose of tensor visualization, namely tensor_slicer, it might not be obvious how and why one would use this new ellipsoid actor for this purpose, thus it was proposed to make a tutorial that can clarify this. The main difference between both actors relies on the quality and the amount of data that can be displayed, so the idea is to show the difference between both alternatives so the user can choose which one to use depending on their needs. To prepare the tutorial the first step was to add the data I will use on fury-data so I can then fetch and load the datasets I need to work on the tutorial.

+

+ +

Read more ...

+
+
+ +
+

+ Week 5: All Roads Lead to Rome +

+ +

Hello everyone, time for another weekly blogpost! Today, we will talk about taking different paths to reach your objective.

+

+ +

Read more ...

+
+
+ +
+

+ Week 5: Trying out PRs and Planning Ahead +

+
    +
  • + + + 01 July 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Due to ongoing exams, my productivity was limited this week. However, I managed to find some time to explore and review a few PRs submitted by contributors:

+

+ +

Read more ...

+
+
+ +
+

+ Week 4: First draft of the DTI uncertainty visualization +

+
    +
  • + + + 27 June 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Tania Castillo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

#PR 810: DTI uncertainty visualization

+

+ +

Read more ...

+
+
+ +
+

+ Week 4: Nothing is Ever Lost +

+ +

Welcome again to another weekly blogpost! Today, let’s talk about the importance of guidance throughout a project.

+

+ +

Read more ...

+
+
+ +
+

+ Week 4: Exam Preparations and Reviewing +

+
    +
  • + + + 24 June 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week, amidst end-semester exams, I managed to accomplish a few notable tasks. Let’s dive into the highlights:

+

+ +

Read more ...

+
+
+ +
+

+ Week 3: Working on uncertainty and details of the first PR +

+
    +
  • + + + 19 June 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Tania Castillo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

I made some adjustments to the ellipsoid actor definition, now called tensor. This was something discussed in the weekly meeting as the coming changes are related to this actor, the idea now is to have a tensor actor that allows choosing between displaying the tensor ellipsoids or the uncertainty cones (later on). I also worked on the uncertainty calculation, and the cone SDF for the visualization, so I plan to do a WIP PR next to start getting feedback on this new addition.

+

+ +

Read more ...

+
+
+ +
+

+ Week 3: Watch Your Expectations +

+ +

Hello everyone, it’s time for another weekly blogpost! This week, +I will talk about how you should watch your expectations when working with any project.

+

+ +

Read more ...

+
+
+ +
+

+ Week 3: Resolving Combobox Icon Flaw and TextBox Justification +

+
    +
  • + + + 17 June 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week, I tackled the ComboBox2D icon flaw, which was addressed using Pull Request (PR) #576. The problem arose when we added a ComboBox2D to the TabUI. The TabUI would propagate the set_visibility = true for all its child elements, causing the combobox to appear on the screen without the icon change. To fix this issue, PR #768 updated the set_visibility method of the UI class, ensuring that the icon change was applied correctly.

+

+ +

Read more ...

+
+
+ +
+

+ Week 2: The Importance of (good) Documentation +

+ +

Hello everybody, welcome to the week 2 of this project! I must admit I thought this would be simpler than it is currently being, but I forgot that when it comes to dealing with computer graphics’ applications, things never are. Below, some updates on what I have been up to for this past week.

+

+ +

Read more ...

+
+
+ +
+

+ Week 2: Making adjustments to the Ellipsoid Actor +

+
    +
  • + + + 12 June 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Tania Castillo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

I made some minor adjustments to the last PR I submitted. Last time it was a draft since I was waiting for the weekly meeting to know how to proceed, but now it is ready. I am waiting for the review so I can make the necessary corrections and adjustments to merge this first PR soon.

+

+ +

Read more ...

+
+
+ +
+

+ Week 2: Tackling Text Justification and Icon Flaw Issues +

+
    +
  • + + + 11 June 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week, I continued tweaking the text justification PR #790 and encountered a new issue when combining both justification and vertical_justification. The problem arose because the vertical_justification did not take into account the applied justification, resulting in unexpected behavior. I focused on resolving this issue by ensuring that both justifications work together correctly. Additionally, during the weekly meeting, we discussed the problem and decided to introduce new properties such as boundaries and padding to enhance the functionality of the text justification feature.

+

+ +

Read more ...

+
+
+ +
+

+ Week 1: Ellipsoid actor implemented with SDF +

+
    +
  • + + + 05 June 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Tania Castillo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

PR #791: Ellipsoid actor implemented with SDF

+

+ +

Read more ...

+
+
+ +
+

+ The FBO Saga - Week 1 +

+ +

As mentioned in the last week’s blogpost, the goal for that week was to investigate VTK’s Framebuffer Object framework. +An update on that is that indeed, VTK has one more low-level working FBO class that can be used inside FURY, however, +they come with some issues that I will explain further below.

+

+ +

Read more ...

+
+
+ +
+

+ Week 1: Working with SpinBox and TextBox Enhancements +

+
    +
  • + + + 03 June 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week, my focus was on reviewing pull requests (PRs) and issues related to the user interface (UI) of the project. I meticulously went through each PR and issue, identifying those specifically associated with UI improvements. To streamline the process, I categorized them accordingly under the UI category. One of the key tasks was PR #499, which involved the implementation of SpinBoxUI. After rebasing the PR, I identified an alignment issue with the textbox component.

+

+ +

Read more ...

+
+
+ +
+

+ Week 0: Community Bounding Period +

+
    +
  • + + + 02 June 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hello All!

+

+ +

Read more ...

+
+
+ +
+

+ Week 0: Community Bounding Period +

+
    +
  • + + + 02 June 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Tania Castillo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hello everyone, my name is Tania Castillo, I am close to finishing my degree in Computer Science and I think this is a great opportunity to put my learning and skills into practice. I will be working with FURY on improving the visualization of DTI tensors and HARDI ODFs glyphs by using well-known techniques in computer graphics.

+

+ +

Read more ...

+
+
+ +
+

+ The Beginning of Everything - Week 0 +

+ +

Hello everyone, welcome to the beginning of my journey through GSoC 2023! I would like to thank everyone involved for the opportunity provided, it is an honour to be working side by side with professionals and so many experienced people from around the world.

+

+ +

Read more ...

+
+
+ +
+

+ FURY 0.9.0 Released +

+
    +
  • + + + 15 April 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Serge Koudoro + + + +
  • + + + + +
  • + + + Category: + + + + + release + + + +
  • + + +
  • + + + + Tag: + + + + + fury + + + +
  • + + +
    +
+

The FURY project is happy to announce the release of FURY 0.9.0! +FURY is a free and open source software library for scientific visualization and 3D animations.

+

+ +

Read more ...

+
+
+ +
+

+ Contribute to FURY via Google Summer of Code 2023 +

+
    +
  • + + + 01 February 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Serge Koudoro + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

FURY is participating in the Google Summer of Code 2023 under the umbrella of the Python Software Foundation.

+

+ +

Read more ...

+
+
+ +
+

+ Google Summer of Code Final Work Product +

+
    +
  • + + + 29 January 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Mohamed Abouagour + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Name: Mohamed Abouagour

+

+ +

Read more ...

+
+
+ +
+

+ Google Summer of Code Final Work Product +

+
    +
  • + + + 29 January 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Shivam Anand + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Name: Shivam Anand

+

+ +

Read more ...

+
+
+ +
+

+ Google Summer of Code Final Work Product +

+
    +
  • + + + 24 January 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Name: Praneeth Shetty

+

+ +

Read more ...

+
+
+ + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/blog/2023/atom.xml b/v0.10.x/blog/2023/atom.xml new file mode 100644 index 000000000..9ca57d688 --- /dev/null +++ b/v0.10.x/blog/2023/atom.xml @@ -0,0 +1,1229 @@ + + + https://fury.gl/ + Blog - Posted in 2023 + 2024-02-29T15:43:57.660940+00:00 + + + ABlog + + https://fury.gl/posts/2023/2023-08-25-final-report-praneeth.html + Google Summer of Code Final Work Product + 2023-08-25T00:00:00-04:00 + + Praneeth Shetty + + <a class="reference external image-reference" href="https://summerofcode.withgoogle.com/programs/2023/projects/BqfBWfwS"><img alt="https://developers.google.com/open-source/gsoc/resources/downloads/GSoC-logo-horizontal.svg" class="align-center" height="50" src="https://developers.google.com/open-source/gsoc/resources/downloads/GSoC-logo-horizontal.svg" /></a> +<a class="reference external image-reference" href="https://summerofcode.withgoogle.com/programs/2023/organizations/python-software-foundation"><img alt="https://www.python.org/static/community_logos/python-logo.png" src="https://www.python.org/static/community_logos/python-logo.png" style="width: 40%;" /></a> +<a class="reference external image-reference" href="https://fury.gl/latest/index.html"><img alt="https://python-gsoc.org/logos/FURY.png" src="https://python-gsoc.org/logos/FURY.png" style="width: 25%;" /></a> +<section id="google-summer-of-code-final-work-product"> + +<ul class="simple"> +<li><p><strong>Name:</strong> Praneeth Shetty</p></li> +<li><p><strong>Organisation:</strong> Python Software Foundation</p></li> +<li><p><strong>Sub-Organisation:</strong> FURY</p></li> +<li><p><strong>Project:</strong> <a class="reference external" href="https://github.com/fury-gl/fury/wiki/Google-Summer-of-Code-2023-(GSOC2023)#project-5-update-user-interface-widget--explore-new-ui-framework">FURY - Update user interface widget + Explore new UI Framework</a></p></li> +</ul> +<section id="proposed-objectives"> +<h2>Proposed Objectives</h2> +<ul class="simple"> +<li><p>SpinBoxUI</p></li> +<li><p>Scrollbar as Independent Element</p></li> +<li><p>FileDialog</p></li> +<li><p>TreeUI</p></li> +<li><p>AccordionUI</p></li> +<li><p>ColorPickerUI</p></li> +<li><dl class="simple"> +<dt>Stretch Goals:</dt><dd><ul> +<li><p>Exploring new UI Framework</p></li> +<li><p>Implementing Borders for UI elements</p></li> +</ul> +</dd> +</dl> +</li> +</ul> +</section> +<section id="objectives-completed"> +<h2>Objectives Completed</h2> +<ul> +<li><dl> +<dt><strong>SpinBoxUI:</strong></dt><dd><p>The <code class="docutils literal notranslate"><span class="pre">SpinBoxUI</span></code> element is essential for user interfaces as it allows users to pick a numeric value from a set range. While we had an active pull request (PR) to add this element, updates in the main code caused conflicts and required further changes for added features. At one point, we noticed that text alignment wasn’t centered properly within the box due to a flaw. To fix this, we began a PR to adjust the alignment, but it turned into a larger refactoring of the <code class="docutils literal notranslate"><span class="pre">TextBlock2D</span></code>, a core component connected to various parts. This was a complex task that needed careful handling. After sorting out the <code class="docutils literal notranslate"><span class="pre">TextBlock2D</span></code>, we returned to the <code class="docutils literal notranslate"><span class="pre">SpinBoxUI</span></code> and made a few tweaks. Once we were confident with the changes, the PR was successfully merged after thorough review and testing.</p> +<p><strong>Pull Requests:</strong></p> +</dd> +</dl> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 50)</p> +<p>Definition list ends without a blank line; unexpected unindent.</p> +</aside> +<ul> +<li><p><strong>SpinBoxUI (Merged)</strong> - <a class="github reference external" href="https://github.com/fury-gl/fury/pull/499">fury-gl/fury#499</a></p> +<blockquote> +<div><img alt="SpinBoxUI" class="align-center" src="https://user-images.githubusercontent.com/64432063/263165327-c0b19cdc-9ebd-433a-8ff1-99e706a76508.gif" style="height: 500px;" /> +</div></blockquote> +</li> +</ul> +</li> +<li><dl> +<dt><strong>`TextBlock2D` Refactoring:</strong></dt><dd><p>This was a significant aspect of the GSoC period and occupied a substantial portion of the timeline. The process began when we observed misaligned text in the <code class="docutils literal notranslate"><span class="pre">SpinBoxUI</span></code>, as previously discussed. The root cause of the alignment issue was the mispositioning of the text actor concerning the background actor. The text actor’s independent repositioning based on justification conflicted with the static position of the background actor, leading to the alignment problem.</p> +<p>To address this, the initial focus was on resolving the justification issue. However, as the work progressed, we recognized that solely adjusting justification would not suffice. The alignment was inherently linked to the UI’s size, which was currently retrieved only when a valid scene was present. This approach lacked scalability and efficiency, as it constrained size retrieval to scene availability.</p> +<p>To overcome these challenges, we devised a solution involving the creation of a bounding box around the <code class="docutils literal notranslate"><span class="pre">TextBlock2D</span></code>. This bounding box would encapsulate the size information, enabling proper text alignment. This endeavor spanned several weeks of development, culminating in a finalized solution that underwent rigorous testing before being merged.</p> +<p>As a result of this refactoring effort, the <code class="docutils literal notranslate"><span class="pre">TextBlock2D</span></code> now offers three distinct modes:</p> +<ol class="arabic simple"> +<li><p><strong>Fully Static Background:</strong> This mode requires background setup during initialization.</p></li> +<li><p><strong>Dynamic Background:</strong> The background dynamically scales based on the text content.</p></li> +<li><p><strong>Auto Font Scale Mode:</strong> The font within the background box automatically scales to fill the available space.</p></li> +</ol> +<p>An issue has been identified with <code class="docutils literal notranslate"><span class="pre">TextBlock2D</span></code> where its text actor aligns with the top boundary of the background actor, especially noticeable with letters like “g,” “y,” and “j”. These letters extend beyond the baseline of standard alphabets, causing the text box to shift upwards.</p> +<p>However, resolving this matter is complex. Adjusting the text’s position might lead to it touching the bottom boundary, especially in font scale mode, resulting in unexpected positioning and transformations. To address this, the plan is to defer discussions about this matter until after GSoC, allowing for thorough consideration and solutions.</p> +<p>For more detailed insights into the individual steps and nuances of this process, you can refer to the comprehensive weekly blog post provided below. It delves into the entire journey of this <code class="docutils literal notranslate"><span class="pre">TextBlock2D</span></code> refactoring effort.</p> +<p><strong>Pull Requests:</strong></p> +</dd> +</dl> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 79)</p> +<p>Definition list ends without a blank line; unexpected unindent.</p> +</aside> +<ul> +<li><p><strong>Fixing Justification Issue - 1st Draft (Closed)</strong> - <a class="github reference external" href="https://github.com/fury-gl/fury/pull/790">fury-gl/fury#790</a></p></li> +<li><p><strong>Adding BoundingBox and fixing Justificaiton (Merged)</strong> - <a class="github reference external" href="https://github.com/fury-gl/fury/pull/803">fury-gl/fury#803</a></p></li> +<li><p><strong>Adding getters and setter for properties (Merged)</strong> - <a class="github reference external" href="https://github.com/fury-gl/fury/pull/830">fury-gl/fury#830</a></p></li> +<li><p><strong>Text Offset PR (Closed)</strong> - <a class="github reference external" href="https://github.com/fury-gl/fury/pull/837">fury-gl/fury#837</a></p> +<img alt="TextBlock2D Feature Demo" class="align-center" src="https://user-images.githubusercontent.com/64432063/258603191-d540105a-0612-450e-8ae3-ca8aa87916e6.gif" style="height: 500px;" /> +<img alt="TextBlock2D All Justification" class="align-center" src="https://github-production-user-asset-6210df.s3.amazonaws.com/64432063/254652569-94212105-7259-48da-8fdc-41ee987bda84.png" style="height: 500px;" /> +</li> +</ul> +</li> +<li><dl> +<dt><strong>ScrollbarUI as Independent Element:</strong></dt><dd><p>We initially planned to make the scrollbar independent based on PR <a class="reference external" href="https://github.com/fury-gl/fury/pull/16">#16</a>. The main goal was to avoid redundancy by not rewriting the scrollbar code for each element that requires it, such as the <code class="docutils literal notranslate"><span class="pre">FileMenu2D</span></code>. However, upon further analysis, we realized that elements like the <code class="docutils literal notranslate"><span class="pre">FileMenu2D</span></code> and others utilize the <code class="docutils literal notranslate"><span class="pre">Listbox2D</span></code>, which already includes an integrated scrollbar. We also examined other UI libraries and found that they also have independent scrollbars but lack a proper use case. Typically, display containers like <code class="docutils literal notranslate"><span class="pre">Listbox2D</span></code> are directly used instead of utilizing an independent scrollbar.</p> +<p>Based on these findings, we have decided to close all related issues and pull requests for now. If the need arises in the future, we can revisit this topic.</p> +<p><strong>Topic:</strong> - <a class="github reference external" href="https://github.com/fury-gl/fury/discussions/816">fury-gl/fury#816</a></p> +</dd> +</dl> +</li> +</ul> +</section> +<section id="other-objectives"> +<h2>Other Objectives</h2> +<ul> +<li><dl> +<dt><strong>Reviewing &amp; Merging:</strong></dt><dd><p>In this phase, my focus was not on specific coding but rather on facilitating the completion of ongoing PRs. Here are two instances where I played a role:</p> +<ol class="arabic simple"> +<li><p><strong>CardUI PR:</strong> +I assisted with the <code class="docutils literal notranslate"><span class="pre">CardUI</span></code> PR by aiding in the rebase process and reviewing the changes. The CardUI is a simple UI element consisting of an image and a description, designed to function like a flash card. I worked closely with my mentor to ensure a smooth rebase and review process.</p></li> +<li><p><strong>ComboBox Issue:</strong> +There was an issue with the <code class="docutils literal notranslate"><span class="pre">ComboBox2D</span></code> functionality, where adding it to a <code class="docutils literal notranslate"><span class="pre">TabUI</span></code> caused all elements to open simultaneously, which shouldn’t be the case. I tested various PRs addressing this problem and identified a suitable solution. I then helped the lead in reviewing the PR that fixed the issue, which was successfully merged.</p></li> +</ol> +<p><strong>Pull Requests:</strong></p> +</dd> +</dl> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 116)</p> +<p>Definition list ends without a blank line; unexpected unindent.</p> +</aside> +<ul> +<li><p><strong>CardUI (Merged)</strong> - <a class="github reference external" href="https://github.com/fury-gl/fury/pull/398">fury-gl/fury#398</a></p></li> +<li><p><strong>ComboBox Flaw (Merged)</strong> - <a class="github reference external" href="https://github.com/fury-gl/fury/pull/768">fury-gl/fury#768</a></p> +<img alt="CardUI" class="align-center" src="https://user-images.githubusercontent.com/54466356/112532305-b090ef80-8dce-11eb-90a0-8d06eed55993.png" style="height: 500px;" /> +</li> +</ul> +</li> +<li><dl> +<dt><strong>Updating Broken Website Links:</strong></dt><dd><p>I addressed an issue with malfunctioning links in the Scientific Section of the website. The problem emerged from alterations introduced in PR <a class="reference external" href="https://github.com/fury-gl/fury/pull/769">#769</a>. These changes consolidated demos and examples into a unified “auto_examples” folder, and a toml file was utilized to retrieve this data and construct examples. However, this led to challenges with the paths employed in website generation. My responsibility was to rectify these links, ensuring they accurately direct users to the intended content.</p> +<p><strong>Pull Requests:</strong></p> +</dd> +</dl> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 130)</p> +<p>Definition list ends without a blank line; unexpected unindent.</p> +</aside> +<ul class="simple"> +<li><p><strong>Updating Broken Links (Merged)</strong> - <a class="github reference external" href="https://github.com/fury-gl/fury/pull/820">fury-gl/fury#820</a></p></li> +</ul> +</li> +</ul> +</section> +<section id="objectives-in-progress"> +<h2>Objectives in Progress</h2> +<ul> +<li><dl> +<dt><strong>FileDialogUI:</strong></dt><dd><p>An existing <code class="docutils literal notranslate"><span class="pre">FileDialog</span></code> PR by Soham (<a class="reference external" href="https://github.com/fury-gl/fury/pull/294">#294</a>) was worked upon. The primary task was to rebase the PR to match the current UI structure, resolving compatibility concerns with the older base. In PR <a class="reference external" href="https://github.com/fury-gl/fury/pull/832">#832</a>, we detailed issues encompassing resizing <code class="docutils literal notranslate"><span class="pre">FileDialog</span></code> and components, addressing text overflow, fixing <code class="docutils literal notranslate"><span class="pre">ZeroDivisionError</span></code>, and correcting <code class="docutils literal notranslate"><span class="pre">ListBox2D</span></code> item positioning. The PR is complete with comprehensive testing and documentation. Presently, it’s undergoing review, and upon approval, it will be prepared for integration.</p> +<p><strong>Pull Requests:</strong></p> +</dd> +</dl> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 140)</p> +<p>Definition list ends without a blank line; unexpected unindent.</p> +</aside> +<ul> +<li><p><strong>Soham’s FileDialog (Closed)</strong> - <a class="github reference external" href="https://github.com/fury-gl/fury/pull/294">fury-gl/fury#294</a></p></li> +<li><p><strong>FileDialogUI (Under Review)</strong> - <a class="github reference external" href="https://github.com/fury-gl/fury/pull/832">fury-gl/fury#832</a></p> +<img alt="FileDialogUI" class="align-center" src="https://user-images.githubusercontent.com/64432063/263189092-6b0891d5-f0ef-4185-8b17-c7104f1a7d60.gif" style="height: 500px;" /> +</li> +</ul> +</li> +<li><dl> +<dt><strong>TreeUI:</strong></dt><dd><p>Continuing Antriksh’s initial PR for <code class="docutils literal notranslate"><span class="pre">TreeUI</span></code> posed some challenges. Antriksh had set the foundation, and I picked up from there. The main issue was with the visibility of TreeUI due to updates in the <code class="docutils literal notranslate"><span class="pre">set_visibility</span></code> method of <code class="docutils literal notranslate"><span class="pre">Panel2D</span></code>. These updates affected how <code class="docutils literal notranslate"><span class="pre">TreeUI</span></code> was displayed, and after investigating the actors involved, it was clear that the visibility features had changed. This took some time to figure out, and I had a helpful pair programming session with my mentor, Serge, to narrow down the problem. Now, I’ve updated the code to address this issue. However, I’m still a bit cautious about potential future problems. The PR is now ready for review.</p> +<p><strong>Pull Requests:</strong></p> +</dd> +</dl> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 154)</p> +<p>Definition list ends without a blank line; unexpected unindent.</p> +</aside> +<ul> +<li><p><strong>TreeUI (In Progress)</strong> - <a class="github reference external" href="https://github.com/fury-gl/fury/pull/821">fury-gl/fury#821</a></p> +<img alt="TreeUI" class="align-center" src="https://user-images.githubusercontent.com/64432063/263237308-70e77ba0-1ce8-449e-a79c-d5e0fbb58b45.gif" style="height: 500px;" /> +</li> +</ul> +</li> +</ul> +</section> +<section id="gsoc-weekly-blogs"> +<h2>GSoC Weekly Blogs</h2> +<ul class="simple"> +<li><p>My blog posts can be found at <a class="reference external" href="https://fury.gl/latest/blog/author/praneeth-shetty.html">FURY website</a> +and <a class="reference external" href="https://blogs.python-gsoc.org/en/ganimtron_10s-blog-copy-2/">Python GSoC blog</a>.</p></li> +</ul> +</section> +<section id="timeline"> +<h2>Timeline</h2> +<table class="table"> +<colgroup> +<col style="width: 40.0%" /> +<col style="width: 40.0%" /> +<col style="width: 20.0%" /> +</colgroup> +<thead> +<tr class="row-odd"><th class="head"><p>Date</p></th> +<th class="head"><p>Description</p></th> +<th class="head"><p>Blog Post Link</p></th> +</tr> +</thead> +<tbody> +<tr class="row-even"><td><p>Week 0 (27-05-2023)</p></td> +<td><p>Community Bounding Period</p></td> +<td><p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-06-02-week-0-praneeth.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/ganimtron_10s-blog-copy-2/gsoc-2023-community-bonding-period/">Python</a></p></td> +</tr> +<tr class="row-odd"><td><p>Week 1 (03-06-2023)</p></td> +<td><p>Working with SpinBox and TextBox Enhancements</p></td> +<td><aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id5">backlink</a></em></p> +<p>Duplicate explicit target name: “fury”.</p> +</aside> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id6">backlink</a></em></p> +<p>Duplicate explicit target name: “python”.</p> +</aside> +<p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-06-03-week-1-praneeth.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/ganimtron_10s-blog-copy-2/week-1-working-with-spinbox-and-textbox-enhancements/">Python</a></p> +</td> +</tr> +<tr class="row-even"><td><p>Week 2 (10-06-2023)</p></td> +<td><p>Tackling Text Justification and Icon Flaw Issues</p></td> +<td><aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id7">backlink</a></em></p> +<p>Duplicate explicit target name: “fury”.</p> +</aside> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id8">backlink</a></em></p> +<p>Duplicate explicit target name: “python”.</p> +</aside> +<p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-06-11-week-2-praneeth.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/ganimtron_10s-blog-copy-2/week-2-tackling-text-justification-and-icon-flaw-issues/">Python</a></p> +</td> +</tr> +<tr class="row-odd"><td><p>Week 3 (17-06-2023)</p></td> +<td><p>Resolving Combobox Icon Flaw and TextBox Justification</p></td> +<td><aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id9">backlink</a></em></p> +<p>Duplicate explicit target name: “fury”.</p> +</aside> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id10">backlink</a></em></p> +<p>Duplicate explicit target name: “python”.</p> +</aside> +<p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-06-17-week-3-praneeth.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/ganimtron_10s-blog-copy-2/week-3-resolving-combobox-icon-flaw-and-textbox-justification/">Python</a></p> +</td> +</tr> +<tr class="row-even"><td><p>Week 4 (24-06-2023)</p></td> +<td><p>Exam Preparations and Reviewing</p></td> +<td><aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id11">backlink</a></em></p> +<p>Duplicate explicit target name: “fury”.</p> +</aside> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id12">backlink</a></em></p> +<p>Duplicate explicit target name: “python”.</p> +</aside> +<p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-06-24-week-4-praneeth.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/ganimtron_10s-blog-copy-2/week-4-exam-preparations-and-reviewing/">Python</a></p> +</td> +</tr> +<tr class="row-odd"><td><p>Week 5 (01-07-2023)</p></td> +<td><p>Trying out PRs and Planning Ahead</p></td> +<td><aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id13">backlink</a></em></p> +<p>Duplicate explicit target name: “fury”.</p> +</aside> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id14">backlink</a></em></p> +<p>Duplicate explicit target name: “python”.</p> +</aside> +<p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-07-01-week-5-praneeth.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/ganimtron_10s-blog-copy-2/week-5-testing-out-prs-and-planning-ahead/">Python</a></p> +</td> +</tr> +<tr class="row-even"><td><p>Week 6 (08-07-2023)</p></td> +<td><p>BoundingBox for TextBlock2D!</p></td> +<td><aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id15">backlink</a></em></p> +<p>Duplicate explicit target name: “fury”.</p> +</aside> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id16">backlink</a></em></p> +<p>Duplicate explicit target name: “python”.</p> +</aside> +<p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-07-08-week-6-praneeth.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/ganimtron_10s-blog-copy-2/week-6-boundingbox-for-textblock2d/">Python</a></p> +</td> +</tr> +<tr class="row-odd"><td><p>Week 7 (15-07-2023)</p></td> +<td><p>Sowing the seeds for TreeUI</p></td> +<td><aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id17">backlink</a></em></p> +<p>Duplicate explicit target name: “fury”.</p> +</aside> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id18">backlink</a></em></p> +<p>Duplicate explicit target name: “python”.</p> +</aside> +<p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-07-15-week-7-praneeth.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/ganimtron_10s-blog-copy-2/week-7-sowing-the-seeds-for-treeui/">Python</a></p> +</td> +</tr> +<tr class="row-even"><td><p>Week 8 (22-07-2023)</p></td> +<td><p>Another week with TextBlockUI</p></td> +<td><aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id19">backlink</a></em></p> +<p>Duplicate explicit target name: “fury”.</p> +</aside> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id20">backlink</a></em></p> +<p>Duplicate explicit target name: “python”.</p> +</aside> +<p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-07-22-week-8-praneeth.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/ganimtron_10s-blog-copy-2/week-8-another-week-with-textblockui/">Python</a></p> +</td> +</tr> +<tr class="row-odd"><td><p>Week 9 (29-07-2023)</p></td> +<td><p>TextBlock2D is Finally Merged!</p></td> +<td><aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id21">backlink</a></em></p> +<p>Duplicate explicit target name: “fury”.</p> +</aside> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id22">backlink</a></em></p> +<p>Duplicate explicit target name: “python”.</p> +</aside> +<p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-07-29-week-9-praneeth.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/ganimtron_10s-blog-copy-2/week-9-textblock2d-is-finally-merged/">Python</a></p> +</td> +</tr> +<tr class="row-even"><td><p>Week 10 (05-08-2023)</p></td> +<td><p>Its time for a Spin-Box!</p></td> +<td><aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id23">backlink</a></em></p> +<p>Duplicate explicit target name: “fury”.</p> +</aside> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id24">backlink</a></em></p> +<p>Duplicate explicit target name: “python”.</p> +</aside> +<p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-08-05-week-10-praneeth.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/ganimtron_10s-blog-copy-2/week-10-its-time-for-a-spin-box/">Python</a></p> +</td> +</tr> +<tr class="row-odd"><td><p>Week 11 (12-08-2023)</p></td> +<td><p>Bye Bye SpinBox</p></td> +<td><aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id25">backlink</a></em></p> +<p>Duplicate explicit target name: “fury”.</p> +</aside> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id26">backlink</a></em></p> +<p>Duplicate explicit target name: “python”.</p> +</aside> +<p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-08-12-week-11-praneeth.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/ganimtron_10s-blog-copy-2/week-11-bye-bye-spinbox/">Python</a></p> +</td> +</tr> +<tr class="row-even"><td><p>Week 12 (19-08-2023)</p></td> +<td><p>FileDialog Quest Begins!</p></td> +<td><aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id27">backlink</a></em></p> +<p>Duplicate explicit target name: “fury”.</p> +</aside> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id28">backlink</a></em></p> +<p>Duplicate explicit target name: “python”.</p> +</aside> +<p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-08-19-week-12-praneeth.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/ganimtron_10s-blog-copy-2/week-12-filedialog-quest-begins/">Python</a></p> +</td> +</tr> +</tbody> +</table> +</section> +</section> + + + Name: Praneeth Shetty + + 2023-08-25T00:00:00-04:00 + + + https://fury.gl/posts/2023/2023-08-24-week-12-tvcastillod.html + Week 12 : Experimenting with ODFs implementation + 2023-08-24T00:00:00-04:00 + + Tania Castillo + + <section id="week-12-experimenting-with-odfs-implementation"> + +<section id="what-did-i-do-this-week"> +<h2>What did I do this week?</h2> +<p>There were different issues I needed to address for the ODF implementation. Even though I could not solve any of them completely, I did check each of the issues and made some progress. All the work in progress is being recorded in the following branch <a class="reference external" href="https://github.com/tvcastillod/fury/tree/SH-for-ODF-impl">SH-for-ODF-impl</a>, which when ready will be associated with a well-structured PR.</p> +<p>First, about the scaling, I was suggested to check Generalized Fractional Anisotropy <strong>gfa</strong> metric to adjust the scaling depending on the shape of the ODF glyph, i.e., the less the <strong>gfa</strong> the more sphere-shaped and smaller, so I had to associate a greater scaling for those. However, this did not work very well as I was unable to define an appropriate scale relation that would give an equitable result for each glyph. For this reason, I opted to use peak values which are extracted from the ODFs, setting the scales as 1/peak_value*0.4 and I got a more uniformly sized glyph without the need of setting it manually. That is a temporal solution as I would like to see better why this happens and if possible do the adjustment inside the shader instead of a precalculation.</p> +<p>Second, for the direction, I made a small adjustment to the spherical coordinates which affected the direction of the ODF glyph. As you can see below,</p> +<img alt="https://user-images.githubusercontent.com/31288525/263122770-b9ee19d2-d82b-4d7f-a5bb-1cbbf5907049.png" class="align-center" src="https://user-images.githubusercontent.com/31288525/263122770-b9ee19d2-d82b-4d7f-a5bb-1cbbf5907049.png" style="width: 400px;" /> +<p>All the glyphs are aligned over the y-axis but not over the z-axis, to correct this I precalculated the main direction of each glyph using peaks and passed it to the shader as a <em>vec3</em>, then used <em>vec2vecrotmat</em> to align the main axis vector of the ODF to the required direction vector, the only problem with this is that not all the glyps are equally aligned to the axis, i.e., the first 3 glyphs are aligned with the x-axis but the last one is aligned with the y-axis, so the final rotation gives a different result for that one.</p> +<img alt="https://user-images.githubusercontent.com/31288525/263122752-b2aa696f-62a5-4b09-b8dd-0cb1ec49431c.png" class="align-center" src="https://user-images.githubusercontent.com/31288525/263122752-b2aa696f-62a5-4b09-b8dd-0cb1ec49431c.png" style="width: 400px;" /> +<p>As with the first small adjustment of the coordinates the direction was partially correct, I need to double check the theta, phi and r definitions to see if I can get the right direction without the need of the additional data of direction. Also, there might be a way to get the specific rotation angles associated to each individual glyph from the data associated with the ODFs.</p> +<p>Third, about passing the coefficients data through textures, I understand better now how to pass textures to the shaders but I still have problems understanding how to retrieve the data inside the shader. I used <a class="reference external" href="https://github.com/fury-gl/fury/blob/master/docs/experimental/viz_shader_texture.py">this base implementation</a>, suggested by one of my mentors, to store the data as a <a class="reference external" href="http://www.khronos.org/opengl/wiki/Cubemap_Texture#:~:text=A%20Cubemap%20Texture%20is%20a,the%20value%20to%20be%20accessed.">texture cubemap</a>, “a texture, where each mipmap level consists of six 2D images which must be square. The 6 images represent the faces of a cube”. I had 4x15 coefficients and inside the function, a grid of RGB colors is made so then it can be mapped as a texture. To check if was passing the data correctly, I used the same value, .5, for all the textures, so then I could pick a random texel get a specific color (gray), and pass it as <em>fragOutput0</em> to see if the value was correct. However, it didn’t appear to work correctly as I couldn’t get the expected color. To get the specific color I used <a class="reference external" href="https://registry.khronos.org/OpenGL-Refpages/gl4/html/texture.xhtml">texture(sampler, P)</a> which samples texels from the texture bound to sampler at texture coordinate P. Now, what I still need to figure out is which should be the corresponding texture coordinate. I have tried with random coordinates, as they are supposed to correspond to a point on the cube and since the information I have encoded in the texture is all the same, I assumed that I would get the expected result for any set of values. It might be a problem with the data normalization, or maybe there is something failing on the texture definition, but I need to review it in more detail to see where is the problem.</p> +<p>Lastly, about the colormapping, I created the texture based on a generic colormap from <a class="reference external" href="https://matplotlib.org/stable/tutorials/colors/colormaps.html">matplotlib</a>. I was able to give some color to the glyph but it does not match correctly its shape. Some adjustment must be done regarding the texels, as the colormap is mapped on a cube, but I need it to fit the shape of the glyph correctly.</p> +<img alt="https://user-images.githubusercontent.com/31288525/263122760-7d1fff5e-7787-473c-8053-ea69f3009fb4.png" class="align-center" src="https://user-images.githubusercontent.com/31288525/263122760-7d1fff5e-7787-473c-8053-ea69f3009fb4.png" style="width: 250px;" /> +</section> +<section id="what-is-coming-up-next"> +<h2>What is coming up next?</h2> +<p>I will continue to explore more on how to handle textures so I can solve the issues related to the coefficient data and colormapping. Also, take a deeper look at the SH implementation and check what is the information needed to adjust the main direction of the ODF correctly.</p> +</section> +<section id="did-i-get-stuck-anywhere"> +<h2>Did I get stuck anywhere?</h2> +<p>As I mentioned I had some drawbacks in understanding the use of textures and how to retrieve the data inside the shaders. This is a topic that might take some time to manage properly but if I can master it and understand it better, it is a tool that can be useful later. Additionally, there are details of the SH implementation that I still need to understand and explore better in order to make sure I get exactly the same result as the current <em>odf_slicer</em> implementation.</p> +</section> +</section> + + + There were different issues I needed to address for the ODF implementation. Even though I could not solve any of them completely, I did check each of the issues and made some progress. All the work in progress is being recorded in the following branch SH-for-ODF-impl, which when ready will be associated with a well-structured PR. + + 2023-08-24T00:00:00-04:00 + + + https://fury.gl/posts/2023/2023-08-24-final-report-tvcastillod.html + Google Summer of Code Final Work Product + 2023-08-24T00:00:00-04:00 + + Tania Castillo + + <a class="reference external image-reference" href="https://summerofcode.withgoogle.com/programs/2023/projects/ymwnLwtT"><img alt="https://developers.google.com/open-source/gsoc/resources/downloads/GSoC-logo-horizontal.svg" class="align-center" height="50" src="https://developers.google.com/open-source/gsoc/resources/downloads/GSoC-logo-horizontal.svg" /></a> +<a class="reference external image-reference" href="https://summerofcode.withgoogle.com/programs/2023/organizations/python-software-foundation"><img alt="https://www.python.org/static/community_logos/python-logo.png" src="https://www.python.org/static/community_logos/python-logo.png" style="width: 40%;" /></a> +<a class="reference external image-reference" href="https://fury.gl/latest/index.html"><img alt="https://python-gsoc.org/logos/FURY.png" src="https://python-gsoc.org/logos/FURY.png" style="width: 25%;" /></a> +<section id="google-summer-of-code-final-work-product"> + +<ul class="simple"> +<li><p><strong>Name:</strong> Tania Castillo</p></li> +<li><p><strong>Organisation:</strong> Python Software Foundation</p></li> +<li><p><strong>Sub-Organisation:</strong> FURY</p></li> +<li><p><strong>Project:</strong> <a class="reference external" href="https://github.com/fury-gl/fury/wiki/Google-Summer-of-Code-2023-(GSOC2023)#project-3-sdf-based-uncertainty-representation-for-dmri-glyphs">SDF-based uncertainty representation for dMRI glyphs</a></p></li> +</ul> +<section id="abstract"> +<h2>Abstract</h2> +<p>Diffusion Magnetic Resonance Imaging (dMRI) is a non-invasive imaging technique used by neuroscientists to measure the diffusion of water molecules in biological tissue. The directional information is reconstructed using either a Diffusion Tensor Imaging (DTI) or High Angular Resolution Diffusion Imaging (HARDI) based model, which is graphically represented as tensors and Orientation Distribution Functions (ODF). Traditional rendering engines discretize Tensor and ODF surfaces using triangles or quadrilateral polygons, making their visual quality depending on the number of polygons used to build the 3D mesh, which might compromise real-time display performance. This project proposes a methodological approach to further improve the visualization of DTI tensors and HARDI ODFs glyphs by using well-established techniques in the field of computer graphics, such as geometry amplification, billboarding, signed distance functions (SDFs), and ray marching.</p> +</section> +<section id="proposed-objectives"> +<h2>Proposed Objectives</h2> +<ul class="simple"> +<li><p>Implement a parallelized version of computer-generated billboards using geometry shaders for amplification.</p></li> +<li><p>Model the mathematical functions that express the geometry of ellipsoid glyphs and implement them using Ray Marching techniques.</p></li> +<li><p>Model the mathematical functions that express the geometry of ODF glyphs and implement them using Ray Marching techniques.</p></li> +<li><p>Use SDF properties and techniques to represent the uncertainty of dMRI reconstruction models.</p></li> +</ul> +</section> +<section id="objectives-completed"> +<h2>Objectives Completed</h2> +<section id="ellipsoid-actor-implemented-with-sdf"> +<h3>Ellipsoid actor implemented with SDF</h3> +<p>A first approach for tensor glyph generation has been made, using ray marching and SDF applied to a box. The current implementation (<code class="docutils literal notranslate"><span class="pre">tensor_slicer</span></code>) requires a sphere with a specific number of vertices to be deformed. Based on this model, a sphere with more vertices is needed to get a higher resolution. Because the ray marching technique does not use polygonal meshes, it is possible to define perfectly smooth surfaces and still obtain a fast rendering.</p> +<p>Details of the implementation:</p> +<ul class="simple"> +<li><p><em>Vertex shader pre-calculations</em>: Some minor calculations are done in the vertex shader. One, corresponding to the eigenvalues constraining and min-max normalization, are to avoid incorrect visualizations when the difference between the eigenvalues is too large. And the other is related to the tensor matrix calculation given by the diffusion tensor definition <span class="math notranslate nohighlight">\(T = R^{−1}\Lambda R\)</span>, where <span class="math notranslate nohighlight">\(R\)</span> is a rotation matrix that transforms the standard basis onto the eigenvector basis, and <span class="math notranslate nohighlight">\(\Lambda\)</span> is the diagonal matrix of eigenvalues <a class="footnote-reference brackets" href="#id10" id="id1" role="doc-noteref"><span class="fn-bracket">[</span>4<span class="fn-bracket">]</span></a>.</p></li> +<li><p><em>Ellipsoid SDF definition</em>: The definition of the SDF is done in the fragment shader inside the <code class="docutils literal notranslate"><span class="pre">map</span></code> function, which is used later for the ray marching algorithm and the normals calculation. We define the SDF more simply by transforming a sphere into an ellipsoid, considering that the SDF of a sphere is easily computed and the definition of a tensor gives us a linear transformation of a given geometry. Also, as scaling is not a rigid body transformation, we multiply the final result by a factor to compensate for the difference, which gave us the SDF of the ellipsoid defined as <code class="docutils literal notranslate"><span class="pre">sdSphere(tensorMatrix</span> <span class="pre">*</span> <span class="pre">(position</span> <span class="pre">-</span> <span class="pre">centerMCVSOutput),</span> <span class="pre">scaleVSOutput*0.48)</span> <span class="pre">*</span> <span class="pre">scFactor</span></code>.</p></li> +<li><p><em>Ray marching algorithm and lighting</em>: For the ray marching algorithm, a small value of 20 was taken as the maximum distance since we apply the technique to each individual object and not all at the same time. Additionally, we set the convergence precision to 0.001. We use the central differences method to compute the normals necessary for the scene’s illumination, besides the Blinn-Phong lighting technique, which is high-quality and computationally cheap.</p></li> +<li><p><em>Visualization example</em>: Below is a detailed visualization of the ellipsoids created from this new implementation.</p></li> +</ul> +<img alt="https://user-images.githubusercontent.com/31288525/244503195-a626718f-4a13-4275-a2b7-6773823e553c.png" class="align-center" src="https://user-images.githubusercontent.com/31288525/244503195-a626718f-4a13-4275-a2b7-6773823e553c.png" style="width: 376px;" /> +<p>This implementation does show a better quality in the displayed glyphs, and supports the display of a large amount of data, as seen in the image below. For this reason, a tutorial was made to justify in more detail the value of this new implementation. Below are some images generated for the tutorial.</p> +<img alt="https://user-images.githubusercontent.com/31288525/260906510-d422e7b4-3ba3-4de6-bfd0-09c04bec8876.png" class="align-center" src="https://user-images.githubusercontent.com/31288525/260906510-d422e7b4-3ba3-4de6-bfd0-09c04bec8876.png" style="width: 600px;" /> +<p><em>Pull Requests:</em></p> +<ul class="simple"> +<li><p><strong>Ellipsoid actor implemented with SDF (Merged)</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/791">fury-gl/fury#791</a></p></li> +<li><p><strong>Tutorial on using ellipsoid actor to visualize tensor ellipsoids for DTI (Merged)</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/818">fury-gl/fury#818</a></p></li> +</ul> +<p><strong>Future work:</strong> In line with one of the initial objectives, it is expected to implement billboards later on to improve the performance, i.e., higher frame rate and less memory usage for the tensor ellipsoid creation. In addition to looking for ways to optimize the naive ray marching algorithm and the definition of SDFs.</p> +</section> +</section> +<section id="objectives-in-progress"> +<h2>Objectives in Progress</h2> +<section id="dti-uncertainty-visualization"> +<h3>DTI uncertainty visualization</h3> +<p>The DTI visualization pipeline is fairly complex, as a level of uncertainty arises, which, if visualized, helps to assess the model’s accuracy. This measure is not currently implemented, and even though there are several methods to calculate and visualize the uncertainty in the DTI model, because of its simplicity and visual representation, we considered Matrix Perturbation Analysis (MPA) proposed by Basser <a class="footnote-reference brackets" href="#id7" id="id2" role="doc-noteref"><span class="fn-bracket">[</span>1<span class="fn-bracket">]</span></a>. This measurement is visualized as double cones representing the variance of the main direction of diffusion, for which the ray marching technique was also used to create these objects.</p> +<p>Details of the implementation:</p> +<ul class="simple"> +<li><p><em>Source of uncertainty</em>: The method of MPA arises from the susceptibility of DTI to dMRI noise present in diffusion-weighted images (DWIs), and also because the model is inherently statistical, making the tensor estimation and other derived quantities to be random variables <a class="footnote-reference brackets" href="#id7" id="id3" role="doc-noteref"><span class="fn-bracket">[</span>1<span class="fn-bracket">]</span></a>. For this reason, this method focus on the premise that image noise produces a random perturbation in the diffusion tensor estimation, and therefore in the calculation of eigenvalues and eigenvectors, particularly in the first eigenvector associated with the main diffusion direction.</p></li> +<li><p><em>Mathematical equation</em>: The description of the perturbation of the principal eigenvector is given by math formula where <span class="math notranslate nohighlight">\(\Delta D\)</span> corresponds to the estimated perturbation matrix of <span class="math notranslate nohighlight">\(D\)</span> given by the diagonal elements of the covariance matrix <span class="math notranslate nohighlight">\(\Sigma_{\alpha} \approx (B^T\Sigma^{−1}_{e}B)^{−1}\)</span>, where <span class="math notranslate nohighlight">\(\Sigma_{e}\)</span> is the covariance matrix of the error e, defined as a diagonal matrix made with the diagonal elements of <span class="math notranslate nohighlight">\((\Sigma^{−1}_{e}) = ⟨S(b)⟩^2 / \sigma^{2}_{\eta}\)</span>. Then, to get the angle <span class="math notranslate nohighlight">\(\theta\)</span> between the perturbed principal eigenvector of <span class="math notranslate nohighlight">\(D\)</span>, <span class="math notranslate nohighlight">\(\varepsilon_1 + \Delta\varepsilon_1\)</span>, and the estimated eigenvector <span class="math notranslate nohighlight">\(\varepsilon_1\)</span>, it can be approximated by <span class="math notranslate nohighlight">\(\theta = \tan^{−1}( \| \Delta\varepsilon_1 \|)\)</span> <a class="footnote-reference brackets" href="#id8" id="id4" role="doc-noteref"><span class="fn-bracket">[</span>2<span class="fn-bracket">]</span></a>. Taking into account the above, we define the function <code class="docutils literal notranslate"><span class="pre">main_dir_uncertainty(evals,</span> <span class="pre">evecs,</span> <span class="pre">signal,</span> <span class="pre">sigma,</span> <span class="pre">b_matrix)</span></code> that calculates the uncertainty of the eigenvector associated to the main direction of diffusion.</p></li> +<li><p><em>Double cone SDF definition</em>: The final SDF is composed by the union of 2 separately cones using the definition taken from this list of <a class="reference external" href="https://iquilezles.org/articles/distfunctions/#:~:text=Cone%20%2D%20exact,sign(s)%3B%0A%7D">distance functions</a>, in this way we have the SDF for the double cone defined as <code class="docutils literal notranslate"><span class="pre">opUnion(sdCone(p,a,h),</span> <span class="pre">sdCone(-p,a,h))</span> <span class="pre">*</span> <span class="pre">scaleVSOutput</span></code></p></li> +<li><p><em>Visualization example</em>: Below is a demo of how this new feature is intended to be used, an image of diffusion tensor ellipsoids and their associated uncertainty cones.</p></li> +</ul> +<img alt="https://user-images.githubusercontent.com/31288525/254747296-09a8674e-bfc0-4b3f-820f-8a1b1ad8c5c9.png" class="align-center" src="https://user-images.githubusercontent.com/31288525/254747296-09a8674e-bfc0-4b3f-820f-8a1b1ad8c5c9.png" style="width: 610px;" /> +<p>The implementation is almost complete, but as it is a new addition that includes mathematical calculations and for which there is no direct reference for comparison, it requires a more detail review before it can be incorporated.</p> +<p><em>Pull Request:</em></p> +<ul class="simple"> +<li><p><strong>DTI uncertainty visualization (Under Review)</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/810">fury-gl/fury#810</a></p></li> +</ul> +<p><strong>Future work:</strong> A tutorial will be made explaining in more detail how to calculate the parameters needed for the uncertainty cones using <strong>dipy</strong> functions, specifically: <a class="reference external" href="https://github.com/dipy/dipy/blob/321e06722ef42b5add3a7f570f6422845177eafa/dipy/denoise/noise_estimate.py#L272">estimate_sigma</a> for the noise variance calculation, <a class="reference external" href="https://github.com/dipy/dipy/blob/321e06722ef42b5add3a7f570f6422845177eafa/dipy/reconst/dti.py#L2112">design_matrix</a> to get the b-matrix, and <a class="reference external" href="https://github.com/dipy/dipy/blob/321e06722ef42b5add3a7f570f6422845177eafa/dipy/reconst/dti.py#L639">tensor_prediction</a> for the signal estimation. Additionally, when the ODF implementation is complete, uncertainty for this other reconstruction model is expected to be added, using semitransparent glyphs representing the mean directional information proposed by Tournier <a class="footnote-reference brackets" href="#id9" id="id5" role="doc-noteref"><span class="fn-bracket">[</span>3<span class="fn-bracket">]</span></a>.</p> +</section> +<section id="odf-actor-implemented-with-sdf"> +<h3>ODF actor implemented with SDF</h3> +<p>HARDI-based techniques require more images than DTI, however, they model the diffusion directions as probability distribution functions (PDFs), and the fitted values are returned as orientation distribution functions (ODFs). ODFs are more diffusion sensitive than the diffusion tensor and, therefore, can determine the structure of multi-directional voxels very common in the white matter regions of the brain <a class="footnote-reference brackets" href="#id9" id="id6" role="doc-noteref"><span class="fn-bracket">[</span>3<span class="fn-bracket">]</span></a>. The current actor to display this kind of glyphs is the <code class="docutils literal notranslate"><span class="pre">odf_slicer</span></code> which, given an array of spherical harmonics (SH) coefficients renders a grid of ODFs, which are created from a sphere with a specific number of vertices that fit the data.</p> +<p>For the application of this model using the same SDF ray marching techniques, we need the data of the SH coefficients, which are used to calculate the orientation distribution function (ODF) described <a class="reference external" href="https://dipy.org/documentation/1.7.0/theory/sh_basis/">here</a>. Different SH bases can be used, but for this first approach we focus on <code class="docutils literal notranslate"><span class="pre">descoteaux07</span></code> (as labeled in dipy). After performing the necessary calculations, we obtain an approximate result of the current implementation of FURY, as seen below.</p> +<img alt="https://user-images.githubusercontent.com/31288525/260909561-fd90033c-018a-465b-bd16-3586bb31ca36.png" class="align-center" src="https://user-images.githubusercontent.com/31288525/260909561-fd90033c-018a-465b-bd16-3586bb31ca36.png" style="width: 580px;" /> +<p>With a first implementation we start to solve some issues related to direction, color, and data handling, to obtain exactly the same results as the current implementation.</p> +<p>Details on the issues:</p> +<ul class="simple"> +<li><p><em>The direction and the scaling</em>: When the shape of the ODF is more sphere-like, the size of the glyph is smaller, so for the moment it needs to be adjusted manually, but the idea is to find a relationship between the coefficients and the final object size so it can be automatically scaled. Additionally, as seen in the image, the direction does not match. To fix this, an adjustment in the calculation of the spherical coordinates can be made, or pass the direction information directly.</p></li> +<li><p><em>Pass the coefficients data efficiently</em>: I’m currently creating one actor per glyph since I’m using a <em>uniform</em> array to pass the coefficients, but the idea is to pass all the data simultaneously. The first idea is to encode the coefficients data through a texture and retrieve them in the fragment shader.</p></li> +<li><p><em>The colormapping and the lighting</em>: As these objects present curvatures with quite a bit of detail in some cases, this requires more specific lighting work, in addition to having now not only one color but a color map. This can also be done with texture, but it is necessary to see in more detail how to adjust the texture to the glyph’s shape.</p></li> +</ul> +<p>More details on current progress can be seen in blogpost of <a class="reference external" href="https://fury.gl/latest/posts/2023/2023-08-16-week-11-tvcastillod.html">week 11</a> and <a class="reference external" href="https://fury.gl/latest/posts/2023/2023-08-24-week-12-tvcastillod.html">week 12</a>.</p> +<p><em>Working branch:</em></p> +<ul class="simple"> +<li><p><strong>ODF implementation (Under Development)</strong> +<a class="github reference external" href="https://github.com/tvcastillod/fury/tree/SH-for-ODF-impl">tvcastillod/fury</a></p></li> +</ul> +</section> +</section> +<section id="gsoc-weekly-blogs"> +<h2>GSoC Weekly Blogs</h2> +<ul class="simple"> +<li><p>My blog posts can be found on the <a class="reference external" href="https://fury.gl/latest/blog/author/tania-castillo.html">FURY website</a> and the <a class="reference external" href="https://blogs.python-gsoc.org/en/tvcastillods-blog/">Python GSoC blog</a>.</p></li> +</ul> +</section> +<section id="timeline"> +<h2>Timeline</h2> +<table class="table"> +<thead> +<tr class="row-odd"><th class="head"><p>Date</p></th> +<th class="head"><p>Description</p></th> +<th class="head"><p>Blog Post Link</p></th> +</tr> +</thead> +<tbody> +<tr class="row-even"><td><p>Week 0(02-06-2022)</p></td> +<td><p>Community Bounding Period</p></td> +<td><p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-06-02-week-0-tvcastillod.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/tvcastillods-blog/weekly-check-in-0-2">Python</a></p></td> +</tr> +<tr class="row-odd"><td><p>Week 1(05-06-2022)</p></td> +<td><p>Ellipsoid actor implemented with SDF</p></td> +<td><p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-06-05-week-1-tvcastillod.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/tvcastillods-blog/weekly-check-in-1-23">Python</a></p></td> +</tr> +<tr class="row-even"><td><p>Week 2(12-06-2022)</p></td> +<td><p>Making adjustments to the Ellipsoid Actor</p></td> +<td><p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-06-12-week-2-tvcastillod.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/tvcastillods-blog/weekly-check-in-2-18">Python</a></p></td> +</tr> +<tr class="row-odd"><td><p>Week 3(19-06-2022)</p></td> +<td><p>Working on uncertainty and details of the first PR</p></td> +<td><p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-06-19-week-3-tvcastillod.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/tvcastillods-blog/weekly-check-in-3-27">Python</a></p></td> +</tr> +<tr class="row-even"><td><p>Week 4(27-06-2022)</p></td> +<td><p>First draft of the DTI uncertainty visualization</p></td> +<td><p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-06-27-week-4-tvcastillod.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/tvcastillods-blog/weekly-check-in-4-24">Python</a></p></td> +</tr> +<tr class="row-odd"><td><p>Week 5(03-07-2022)</p></td> +<td><p>Preparing the data for the Ellipsoid tutorial</p></td> +<td><p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-07-03-week-5-tvcastillod.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/tvcastillods-blog/weekly-check-in-5-27">Python</a></p></td> +</tr> +<tr class="row-even"><td><p>Week 6(10-07-2022)</p></td> +<td><p>First draft of the Ellipsoid tutorial</p></td> +<td><p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-07-10-week-6-tvcastillod.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/tvcastillods-blog/weekly-check-in-6-26">Python</a></p></td> +</tr> +<tr class="row-odd"><td><p>Week 7(17-07-2022)</p></td> +<td><p>Adjustments on the Uncertainty Cones visualization</p></td> +<td><p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-07-17-week-7-tvcastillod.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/tvcastillods-blog/weekly-check-in-7-26">Python</a></p></td> +</tr> +<tr class="row-even"><td><p>Week 8(25-07-2022)</p></td> +<td><p>Working on Ellipsoid Tutorial and exploring SH</p></td> +<td><p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-07-25-week-8-tvcastillod.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/tvcastillods-blog/weekly-check-in-8-17">Python</a></p></td> +</tr> +<tr class="row-odd"><td><p>Week 9(31-07-2022)</p></td> +<td><p>Tutorial done and polishing DTI uncertainty</p></td> +<td><p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-07-31-week-9-tvcastillod.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/tvcastillods-blog/weekly-check-in-9-22">Python</a></p></td> +</tr> +<tr class="row-even"><td><p>Week 10(08-08-2022)</p></td> +<td><p>Start of SH implementation experiments</p></td> +<td><p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-08-08-week-10-tvcastillod.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/tvcastillods-blog/weekly-check-in-10-16">Python</a></p></td> +</tr> +<tr class="row-odd"><td><p>Week 11(16-08-2022)</p></td> +<td><p>Adjusting ODF implementation and looking for solutions on issues found</p></td> +<td><p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-08-16-week-11-tvcastillod.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/tvcastillods-blog/weekly-check-in-11-17">Python</a></p></td> +</tr> +<tr class="row-even"><td><p>Week 12(24-08-2022)</p></td> +<td><p>Experimenting with ODFs implementation</p></td> +<td><p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-08-24-week-12-tvcastillod.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/tvcastillods-blog/weekly-check-in-12-9">Python</a></p></td> +</tr> +</tbody> +</table> +</section> +<section id="references"> +<h2>References</h2> +<aside class="footnote-list brackets"> +<aside class="footnote brackets" id="id7" role="doc-footnote"> +<span class="label"><span class="fn-bracket">[</span>1<span class="fn-bracket">]</span></span> +<span class="backrefs">(<a role="doc-backlink" href="#id2">1</a>,<a role="doc-backlink" href="#id3">2</a>)</span> +<p>Basser, P. J. (1997). Quantifying errors in fiber direction and diffusion tensor field maps resulting from MR noise. In 5th Scientific Meeting of the ISMRM (Vol. 1740).</p> +</aside> +<aside class="footnote brackets" id="id8" role="doc-footnote"> +<span class="label"><span class="fn-bracket">[</span><a role="doc-backlink" href="#id4">2</a><span class="fn-bracket">]</span></span> +<p>Chang, L. C., Koay, C. G., Pierpaoli, C., &amp; Basser, P. J. (2007). Variance of estimated DTI‐derived parameters via first‐order perturbation methods. Magnetic Resonance in Medicine: An Official Journal of the International Society for Magnetic Resonance in Medicine, 57(1), 141-149.</p> +</aside> +<aside class="footnote brackets" id="id9" role="doc-footnote"> +<span class="label"><span class="fn-bracket">[</span>3<span class="fn-bracket">]</span></span> +<span class="backrefs">(<a role="doc-backlink" href="#id5">1</a>,<a role="doc-backlink" href="#id6">2</a>)</span> +<p>J-Donald Tournier, Fernando Calamante, David G Gadian, and Alan Connelly. Direct estimation of the fiber orientation density function from diffusion-weighted mri data using spherical deconvolution. Neuroimage, 23(3):1176–1185, 2004.</p> +</aside> +<aside class="footnote brackets" id="id10" role="doc-footnote"> +<span class="label"><span class="fn-bracket">[</span><a role="doc-backlink" href="#id1">4</a><span class="fn-bracket">]</span></span> +<p>Gordon Kindlmann. Superquadric tensor glyphs. In Proceedings of the Sixth Joint Eurographics-IEEE TCVG conference on Visualization, pages 147–154, 2004.</p> +</aside> +</aside> +</section> +</section> + + + Name: Tania Castillo + + 2023-08-24T00:00:00-04:00 + + + https://fury.gl/posts/2023/2023-08-21-week-12-joaodellagli.html + Week 12: Now That is (almost) a Wrap! + 2023-08-21T00:00:00-04:00 + + João Victor Dell Agli Floriano + + <section id="week-12-now-that-is-almost-a-wrap"> + +<p>Hello everyone, it’s time for another GSoC blogpost! Today, I am going to talk about some minor details I worked on last week on my +project.</p> +<section id="last-week-s-effort"> +<h2>Last Week’s Effort</h2> +<p>After the API refactoring was done last week, I focused on addressing the reviews I would get from it. The first issues I addressed was related to +style, as there were some minor details my GSoC contributors pointed out that needed change. Also, I have addressed an issue I was having +with the <cite>typed hint</cite> of one of my functions. Filipi, my mentor, showed me there is a way to have more than one typed hint in the same parameter, +all I needed to do was to use the <cite>Union</cite> class from the <cite>typing</cite> module, as shown below:</p> +<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">Union</span> <span class="k">as</span> <span class="n">tUnion</span> +<span class="kn">from</span> <span class="nn">numpy</span> <span class="kn">import</span> <span class="n">ndarray</span> + +<span class="k">def</span> <span class="nf">function</span><span class="p">(</span><span class="n">variable</span> <span class="p">:</span> <span class="n">tUnion</span><span class="p">(</span><span class="nb">float</span><span class="p">,</span> <span class="n">np</span><span class="o">.</span><span class="n">ndarray</span><span class="p">)):</span> + <span class="k">pass</span> +</pre></div> +</div> +<p>Using that, I could set the typedhint of the <cite>bandwidth</cite> variable to <cite>float</cite> and <cite>np.ndarray</cite>.</p> +</section> +<section id="so-how-did-it-go"> +<h2>So how did it go?</h2> +<p>All went fine with no difficult at all, thankfully.</p> +</section> +<section id="the-next-steps"> +<h2>The Next Steps</h2> +<p>My next plans are, after having PR <a class="reference external" href="https://github.com/fury-gl/fury/pull/826">#826</a> merged, to work on the float encoding issue described in +<span class="xref std std-doc">this blogpost</span>. Also, I plan to tackle the UI idea once again, to see if I can finally give the user +a way to control the intensities of the distributions.</p> +<p>Wish me luck!</p> +</section> +</section> + + + Hello everyone, it’s time for another GSoC blogpost! Today, I am going to talk about some minor details I worked on last week on my +project. + + 2023-08-21T00:00:00-04:00 + + + https://fury.gl/posts/2023/2023-08-21-joaodellagli-final-report.html + Google Summer of Code Final Work Product + 2023-08-21T00:00:00-04:00 + + João Victor Dell Agli Floriano + + <a class="reference external image-reference" href="https://summerofcode.withgoogle.com/programs/2023/projects/ED0203De"><img alt="https://developers.google.com/open-source/gsoc/resources/downloads/GSoC-logo-horizontal.svg" height="40" src="https://developers.google.com/open-source/gsoc/resources/downloads/GSoC-logo-horizontal.svg" /></a> +<a class="reference external image-reference" href="https://summerofcode.withgoogle.com/programs/2023/organizations/python-software-foundation"><img alt="https://www.python.org/static/img/python-logo&#64;2x.png" src="https://www.python.org/static/img/python-logo&#64;2x.png" style="height: 40px;" /></a> +<a class="reference external image-reference" href="https://fury.gl/latest/index.html"><img alt="https://python-gsoc.org/logos/fury_logo.png" src="https://python-gsoc.org/logos/fury_logo.png" style="width: 40px;" /></a> +<section id="google-summer-of-code-final-work-product"> + +<ul class="simple"> +<li><p><strong>Name:</strong> João Victor Dell Agli Floriano</p></li> +<li><p><strong>Organisation:</strong> Python Software Foundation</p></li> +<li><p><strong>Sub-Organisation:</strong> FURY</p></li> +<li><p><strong>Project:</strong> <a class="reference external" href="https://github.com/fury-gl/fury/wiki/Google-Summer-of-Code-2023-(GSOC2023)#project-2-fast-3d-kernel-based-density-rendering-using-billboards">FURY - Project 2. Fast 3D kernel-based density rendering using billboards.</a></p></li> +</ul> +<section id="abstract"> +<h2>Abstract</h2> +<p>This project had the goal to implement 3D Kernel Density Estimation rendering to FURY. Kernel Density Estimation, or KDE, is a +statistical method that uses kernel smoothing for modeling and estimating the density distribution of a set of points defined +inside a given region. For its graphical implementation, it was used post-processing techniques such as offscreen rendering to +framebuffers and colormap post-processing as tools to achieve the desired results. This was completed with a functional basic KDE +rendering result, that relies on a solid and easy-to-use API, as well as some additional features.</p> +</section> +<section id="proposed-objectives"> +<h2>Proposed Objectives</h2> +<ul class="simple"> +<li><dl class="simple"> +<dt><strong>First Phase</strong><span class="classifier">Implement framebuffer usage in FURY</span></dt><dd><ul> +<li><p>Investigate the usage of float framebuffers inside FURY’s environment.</p></li> +<li><p>Implement a float framebuffer API.</p></li> +</ul> +</dd> +</dl> +</li> +<li><dl class="simple"> +<dt><strong>Second Phase</strong><span class="classifier">Shader-framebuffer integration</span></dt><dd><ul> +<li><p>Implement a shader that uses a colormap to render framebuffers.</p></li> +<li><p>Escalate this rendering for composing multiple framebuffers.</p></li> +</ul> +</dd> +</dl> +</li> +<li><dl class="simple"> +<dt><strong>Third Phase</strong><span class="classifier">KDE Calculations</span></dt><dd><ul> +<li><p>Investigate KDE calculation for point-cloud datasets.</p></li> +<li><p>Implement KDE calculation inside the framebuffer rendering shaders.</p></li> +<li><p>Test KDE for multiple datasets.</p></li> +</ul> +</dd> +</dl> +</li> +</ul> +</section> +<section id="objectives-completed"> +<h2>Objectives Completed</h2> +<ul> +<li><dl> +<dt><strong>Implement framebuffer usage in FURY</strong></dt><dd><p>The first phase, addressed from <em>May/29</em> to <em>July/07</em>, started with the investigation of +<a class="reference external" href="https://vtk.org/doc/nightly/html/classvtkOpenGLFramebufferObject.html#details">VTK’s Framebuffer Object</a>, a vital part of this project, to understand +how to use it properly.</p> +<p>Framebuffer Objects, abbreviated as FBOs, are the key to post-processing effects in OpenGL, as they are used to render things offscreen and save the resulting image to a texture +that will be later used to apply the desired post-processing effects within the object’s <a class="reference external" href="https://www.khronos.org/opengl/wiki/Fragment_Shader">fragment shader</a> +rendered to screen, in this case, a <a class="reference external" href="http://www.opengl-tutorial.org/intermediate-tutorials/billboards-particles/billboards/">billboard</a>. In the case of the +<a class="reference external" href="https://en.wikipedia.org/wiki/Kernel_density_estimation">Kernel Density Estimation</a> post-processing effect, we need a special kind of FBO, one that stores textures’ +values as floats, different from the standard 8-bit unsigned int storage. This is necessary because the KDE rendering involves rendering every KDE point calculation +to separate billboards, rendered to the same scene, which will have their intensities, divided by the number of points rendered, blended with +<a class="reference external" href="https://www.khronos.org/opengl/wiki/Blending">OpenGL Additive Blending</a>, and if a relative big number of points are rendered at the +same time, 32-bit float precision is needed to guarantee that small-intensity values will not be capped to zero, and disappear.</p> +<p>After a month going through VTK’s FBO documentation and weeks spent trying different approaches to this method, it would not work +properly, as some details seemed to be missing from the documentation, and asking the community haven’t solved the problem as well. +Reporting that to my mentors, which unsuccessfully tried themselves to make it work, they decided it was better if another path was taken, using +<a class="reference external" href="https://vtk.org/doc/nightly/html/classvtkWindowToImageFilter.html">VTK’s WindowToImageFilter</a> method as a workaround, described +in this <a class="reference external" href="https://fury.gl/latest/posts/2023/2023-07-03-week-5-joaodellagli.html">blogpost</a>. This method helped the development of +three new functions to FURY, <em>window_to_texture()</em>, <em>texture_to_actor()</em> and <em>colormap_to_texture()</em>, that allow the passing of +different kinds of textures to FURY’s actor’s shaders, the first one to capture a window and pass it as a texture to an actor, +the second one to pass an external texture to an actor, and the third one to specifically pass a colormap as a texture to an +actor. It is important to say that <em>WindowToImageFilter()</em> is not the ideal way to make it work, as this method does not seem to +support float textures. However, a workaround to that is currently being worked on, as I will describe later on.</p> +<p><em>Pull Requests:</em></p> +<ul class="simple"> +<li><p><strong>KDE Rendering Experimental Program (Needs major revision):</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/804">fury-gl/fury#804</a></p></li> +</ul> +<p>The result of this whole FBO and WindowToImageFilter experimentation is well documented in PR +<a class="reference external" href="https://github.com/fury-gl/fury/pull/804">#804</a> that implements an experimental version of a KDE rendering program. +The future of this PR, as discussed with my mentors, is to be better documented to be used as an example for developers on +how to develop features in FURY with the tools used, and it shall be done soon.</p> +</dd> +</dl> +</li> +<li><dl> +<dt><strong>Shader-framebuffer integration</strong></dt><dd><aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-21-joaodellagli-final-report.rst</span>, line 16); <em><a href="#id2">backlink</a></em></p> +<p>Duplicate explicit target name: “blogpost”.</p> +</aside> +<p>The second phase, which initially was thought of as “Implement a shader that uses a colormap to render framebuffers” and “Escalate this +rendering for composing multiple framebuffers” was actually a pretty simple phase that could be addressed in one week, <em>July/10</em> +to <em>July/17</em>, done at the same time as the third phase goal, documented in this +<a class="reference external" href="https://fury.gl/latest/posts/2023/2023-07-17-week-7-joaodellagli.html">blogpost</a>. As FURY already had a tool for generating and +using colormaps, they were simply connected to the shader part of the program as textures, with the functions explained above. +Below, is the result of the <em>matplotlib viridis</em> colormap passed to a simple gaussian KDE render:</p> +<img alt="Final 2D plot" class="align-center" src="https://raw.githubusercontent.com/JoaoDell/gsoc_assets/main/images/final_2d_plot.png" /> +<aside class="system-message"> +<p class="system-message-title">System Message: INFO/1 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-21-joaodellagli-final-report.rst</span>, line 16); <em><a href="#id3">backlink</a></em></p> +<p>Duplicate explicit target name: “#804”.</p> +</aside> +<p>That is also included in PR <a class="reference external" href="https://github.com/fury-gl/fury/pull/804">#804</a>. Having the 2D plot ready, some time was taken to +figure out how to enable a 3D render, that includes rotation and other movement around the set rendered, which was solved by +learning about the callback properties that exist inside <em>VTK</em>. Callbacks are ways to enable code execution inside the VTK rendering +loop, enclosed inside <em>vtkRenderWindowInteractor.start()</em>. If it is desired to add a piece of code that, for example, passes a time +variable to the fragment shader over time, a callback function can be declared:</p> +<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">fury</span> <span class="kn">import</span> <span class="n">window</span> +<span class="n">t</span> <span class="o">=</span> <span class="mi">0</span> +<span class="n">showm</span> <span class="o">=</span> <span class="n">window</span><span class="o">.</span><span class="n">ShowManager</span><span class="p">(</span><span class="o">...</span><span class="p">)</span> + +<span class="k">def</span> <span class="nf">callback_function</span><span class="p">:</span> + <span class="n">t</span> <span class="o">+=</span> <span class="mf">0.01</span> + <span class="n">pass_shader_uniforms_to_fs</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="s2">&quot;t&quot;</span><span class="p">)</span> + +<span class="n">showm</span><span class="o">.</span><span class="n">add_iren_callback</span><span class="p">(</span><span class="n">callback_function</span><span class="p">,</span> <span class="s2">&quot;RenderEvent&quot;</span><span class="p">)</span> +</pre></div> +</div> +<p>The piece of code above created a function that updates the time variable <em>t</em> in every <em>“RenderEvent”</em>, and passes it to the +fragment shader. With that property, the camera and some other parameters could be updated, which enabled 3D visualization, that +then, outputted the following result, using <em>matplotlib inferno</em> colormap:</p> +<img alt="3D Render gif" class="align-center" src="https://raw.githubusercontent.com/JoaoDell/gsoc_assets/main/images/3d_kde_gif.gif" /> +</dd> +</dl> +</li> +<li><dl> +<dt><strong>KDE Calculations</strong> (ongoing)</dt><dd><p>As said before, the second and third phases were done simultaneously, so after having a way to capture the window and use it as a +texture ready, the colormap ready, and an initial KDE render ready, all it was needed to do was to improve the KDE calculations. +As this <a class="reference external" href="https://en.wikipedia.org/wiki/Kernel_density_estimation">Wikipedia page</a> explains, a KDE calculation is to estimate an +abstract density around a set of points defined inside a given region with a kernel, that is a function that models the density +around a point based on its associated distribution <span class="math notranslate nohighlight">\(\sigma\)</span>.</p> +<p>A well-known kernel is, for example, the <strong>Gaussian Kernel</strong>, that says that the density around a point <span class="math notranslate nohighlight">\(p\)</span> with distribution +<span class="math notranslate nohighlight">\(\sigma\)</span> is defined as:</p> +<div class="math notranslate nohighlight"> +\[GK_{\textbf{p}, \sigma} (\textbf{x}) = e^{-\frac{1}{2}\frac{||\textbf{x} - \textbf{p}||^2}{\sigma^2}}\]</div> +<p>Using that kernel, we can calculate the KDE of a set of points <span class="math notranslate nohighlight">\(P\)</span> with associated distributions <span class="math notranslate nohighlight">\(S\)</span> calculating their individual +Gaussian distributions, summing them up and dividing them by the total number of points <span class="math notranslate nohighlight">\(n\)</span>:</p> +<div class="math notranslate nohighlight"> +\[KDE(A, S)=\frac{1}{n}\sum_{i = 0}^{n}GK(x, p_{i}, \sigma_{i})\]</div> +<p>So I dove into implementing all of that into the offscreen rendering part, and that is when the lack of a float framebuffer would +charge its cost. As it can be seen above, just calculating each point’s density isn’t the whole part, as I also need to divide +everyone by the total number of points <span class="math notranslate nohighlight">\(n\)</span>, and then sum them all. The problem is that, if the number of points its big enough, +the individual densities will be really low, and that would not be a problem for a 32-bit precision float framebuffer, but that is +<em>definitely</em> a problem for a 8-bit integer framebuffer, as small enough values will simply underflow and disappear. That issue is +currently under investigation, and some solutions have already being presented, as I will show in the <strong>Objectives in Progress</strong> +section.</p> +<p>Apart from that, after having the experimental program ready, I focused on modularizing it into a functional and simple API +(without the <span class="math notranslate nohighlight">\(n\)</span> division for now), and I could get a good set of results from that. The API I first developed implemented the +<em>EffectManager</em> class, responsible for managing all of the behind-the-scenes steps necessary for the kde render to work, +encapsulated inside the <em>ÈffectManager.kde()</em> method. It had the following look:</p> +<aside class="system-message"> +<p class="system-message-title">System Message: ERROR/3 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-21-joaodellagli-final-report.rst</span>, line 162)</p> +<p>Error in “code-block” directive: +maximum 1 argument(s) allowed, 9 supplied.</p> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="o">..</span> <span class="n">code</span><span class="o">-</span><span class="n">block</span><span class="p">::</span> <span class="n">python</span> + <span class="kn">from</span> <span class="nn">fury.effect_manager</span> <span class="kn">import</span> <span class="n">EffectManager</span> + <span class="kn">from</span> <span class="nn">fury</span> <span class="kn">import</span> <span class="n">window</span> + + <span class="n">showm</span> <span class="o">=</span> <span class="n">window</span><span class="o">.</span><span class="n">ShowManager</span><span class="p">(</span><span class="o">...</span><span class="p">)</span> + + <span class="c1"># KDE rendering setup</span> + <span class="n">em</span> <span class="o">=</span> <span class="n">EffectManager</span><span class="p">(</span><span class="n">showm</span><span class="p">)</span> + <span class="n">kde_actor</span> <span class="o">=</span> <span class="n">em</span><span class="o">.</span><span class="n">kde</span><span class="p">(</span><span class="o">...</span><span class="p">)</span> + <span class="c1"># End of KDE rendering setup</span> + + <span class="n">showmn</span><span class="o">.</span><span class="n">scene</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">kde_actor</span><span class="p">)</span> + + <span class="n">showm</span><span class="o">.</span><span class="n">start</span><span class="p">()</span> +</pre></div> +</div> +</aside> +<p>Those straightforward instructions, that hid several lines of code and setup, could manage to output the following result:</p> +<img alt="API 3D KDE plot" class="align-center" src="https://raw.githubusercontent.com/JoaoDell/gsoc_assets/main/images/fianl_3d_plot.png" /> +<p>And this was not the only feature I had implemented for this API, as the use of <em>WindowToImageFilter</em> method opened doors for a +whole new world for FURY: The world of post-processing effects. With this features setup, I managed to implement a <em>gaussian blur</em> +effect, a <em>grayscale</em> effect and a <em>Laplacian</em> effect for calculating “borders”:</p> +<img alt="Gaussian Blur effect" class="align-center" src="https://raw.githubusercontent.com/JoaoDell/gsoc_assets/main/images/gaussian_blur.png" /> +<img alt="Grayscale effect" class="align-center" src="https://raw.githubusercontent.com/JoaoDell/gsoc_assets/main/images/grayscale.png" /> +<img alt="Laplacian effect" class="align-center" src="https://raw.githubusercontent.com/JoaoDell/gsoc_assets/main/images/laplacian1.gif" /> +<p>As this wasn’t the initial goal of the project and I still had several issues to deal with, I have decided to leave these features as a +future addition.</p> +<p>Talking with my mentors, we realized that the first KDE API, even though simple, could lead to bad usage from users, as the +<em>em.kde()</em> method, that outputted a <em>FURY actor</em>, had dependencies different from any other object of its kind, making it a new +class of actors, which could lead to confusion and bad handling. After some pair programming sessions, they instructed me to take +a similar, but different road from what I was doing, turning the kde actor into a new class, the <em>KDE</em> class. This class would +have almost the same set of instructions present in the prior method, but it would break them in a way it would only be completely +set up after being passed to the <em>EffectManager</em> via its add function. Below, how the refactoring handles it:</p> +<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">fury.effects</span> <span class="kn">import</span> <span class="n">EffectManager</span><span class="p">,</span> <span class="n">KDE</span> +<span class="kn">from</span> <span class="nn">fury</span> <span class="kn">import</span> <span class="n">window</span> + +<span class="n">showm</span> <span class="o">=</span> <span class="n">window</span><span class="o">.</span><span class="n">ShowManager</span><span class="p">(</span><span class="o">...</span><span class="p">)</span> + +<span class="c1"># KDE rendering setup</span> +<span class="n">em</span> <span class="o">=</span> <span class="n">EffectManager</span><span class="p">(</span><span class="n">showm</span><span class="p">)</span> +<span class="n">kde_effect</span> <span class="o">=</span> <span class="n">KDE</span><span class="p">(</span><span class="o">...</span><span class="p">)</span> +<span class="n">em</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">kde_effect</span><span class="p">)</span> +<span class="c1"># End of KDE rendering setup</span> + +<span class="n">showm</span><span class="o">.</span><span class="n">start</span><span class="p">()</span> +</pre></div> +</div> +<p>Which outputted the same results as shown above. It may have cost some simplicity as we are now one line farther from having it +working, but it is more explicit in telling the user this is not just a normal actor.</p> +<p>Another detail I worked on was the kernel variety. The Gaussian Kernel isn’t the only one available to model density distributions, +there are several others that can do that job, as it can be seen in this <a class="reference external" href="https://scikit-learn.org/stable/modules/density.html">scikit-learn piece of documentation</a> +and this <a class="reference external" href="https://en.wikipedia.org/wiki/Kernel_(statistics)">Wikipedia page on kernels</a>. Based on the scikit-learn KDE +implementation, I worked on implementing the following kernels inside our API, that can be chosen as a parameter when calling the +<em>KDE</em> class:</p> +<ul class="simple"> +<li><p>Cosine</p></li> +<li><p>Epanechnikov</p></li> +<li><p>Exponential</p></li> +<li><p>Gaussian</p></li> +<li><p>Linear</p></li> +<li><p>Tophat</p></li> +</ul> +<p>Below, the comparison between them using the same set of points and bandwidths:</p> +<img alt="Comparison between the six implemented kernels" class="align-center" src="https://raw.githubusercontent.com/JoaoDell/gsoc_assets/main/images/kernels.png" /> +<p><em>Pull Requests</em>:</p> +<ul class="simple"> +<li><p><strong>First Stage of the KDE Rendering API (will be merged soon)</strong>: <a class="github reference external" href="https://github.com/fury-gl/fury/pull/826">fury-gl/fury#826</a></p></li> +</ul> +<p>All of this work culminated in PR <a class="reference external" href="https://github.com/fury-gl/fury/pull/826/">#826</a>, that proposes to add the first stage of +this API (there are some details yet to be completed, like the <span class="math notranslate nohighlight">\(n\)</span> division) to FURY. This PR added the described API, and also +proposed some minor changes to some already existing FURY functions related to callbacks, changes necessary for this and other +future applications that would use it to work. It also added the six kernels described, and a simple documented example on how +to use this feature.</p> +</dd> +</dl> +</li> +</ul> +</section> +<section id="other-objectives"> +<h2>Other Objectives</h2> +<ul class="simple"> +<li><dl class="simple"> +<dt><strong>Stretch Goals</strong><span class="classifier">SDE Implementation, Network/Graph visualization using SDE/KDE, Tutorials</span></dt><dd><ul> +<li><p>Investigate SDE calculation for surface datasets.</p></li> +<li><p>Implement SDE calculation inside the framebuffer rendering shaders.</p></li> +<li><p>Test SDE for multiple datasets.</p></li> +<li><p>Develop comprehensive tutorials that explain SDE concepts and FURY API usage.</p></li> +<li><p>Create practical, scenario-based tutorials using real datasets and/or simulations.</p></li> +</ul> +</dd> +</dl> +</li> +</ul> +</section> +<section id="objectives-in-progress"> +<h2>Objectives in Progress</h2> +<ul> +<li><dl> +<dt><strong>KDE Calculations</strong> (ongoing)</dt><dd><p>The KDE rendering, even though almost complete, have the $n$ division, an important step, missing, as this normalization allows colormaps +to cover the whole range o values rendered. The lack of a float FBO made a big difference in the project, as the search for a functional implementation of it not only delayed the project, but it is vital for +the correct calculations to work.</p> +<p>For the last part, a workaround thought was to try an approach I later figured out is an old one, as it can be check in +<a class="reference external" href="https://developer.nvidia.com/gpugems/gpugems/part-ii-lighting-and-shadows/chapter-12-omnidirectional-shadow-mapping">GPU Gems 12.3.3 section</a>: +If I need 32-bit float precision and I got 4 8-bit integer precision available, why not trying to pack this float into this RGBA +texture? I have first tried to do one myself, but it didn’t work for some reason, so I tried <a class="reference external" href="https://aras-p.info/blog/2009/07/30/encoding-floats-to-rgba-the-final/">Aras Pranckevičius</a> +implementation, that does the following:</p> +<div class="highlight-GLSL notranslate"><div class="highlight"><pre><span></span><span class="kt">vec4</span><span class="w"> </span><span class="n">float_to_rgba</span><span class="p">(</span><span class="kt">float</span><span class="w"> </span><span class="n">value</span><span class="p">)</span><span class="w"> </span><span class="p">{</span> +<span class="w"> </span><span class="kt">vec4</span><span class="w"> </span><span class="n">bitEnc</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="kt">vec4</span><span class="p">(</span><span class="mf">1.</span><span class="p">,</span><span class="mf">256.</span><span class="p">,</span><span class="mf">65536.0</span><span class="p">,</span><span class="mf">16777216.0</span><span class="p">);</span> +<span class="w"> </span><span class="kt">vec4</span><span class="w"> </span><span class="n">enc</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">bitEnc</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">value</span><span class="p">;</span> +<span class="w"> </span><span class="n">enc</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">fract</span><span class="p">(</span><span class="n">enc</span><span class="p">);</span> +<span class="w"> </span><span class="n">enc</span><span class="w"> </span><span class="o">-=</span><span class="w"> </span><span class="n">enc</span><span class="p">.</span><span class="n">yzww</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="kt">vec2</span><span class="p">(</span><span class="mf">1.</span><span class="o">/</span><span class="mf">255.</span><span class="p">,</span><span class="w"> </span><span class="mf">0.</span><span class="p">).</span><span class="n">xxxy</span><span class="p">;</span> +<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="n">enc</span><span class="p">;</span> +<span class="p">}</span> +</pre></div> +</div> +<p>That initially worked, but for some reason I am still trying to understand, it is resulting in a really noisy texture:</p> +<img alt="Noisy KDE render" class="align-center" src="https://raw.githubusercontent.com/JoaoDell/gsoc_assets/main/images/noisy%20kde.png" /> +<p>One way to try to mitigate that while is to pass this by a gaussian blur filter, to try to smooth out the result:</p> +<img alt="Blurred result" class="align-center" src="https://raw.githubusercontent.com/JoaoDell/gsoc_assets/main/images/blurred_kde.png" /> +<p>But it is not an ideal solution as well, as it may lead to distortions in the actual density values, depending on the application of +the KDE. Now, my goal is to first find the root of the noise problem, and then, if that does not work, try to make the gaussian filter +work.</p> +<p>Another detail that would be a good addition to the API is UI controls. Filipi, one of my mentors, told me it would be a good feature +if the user could control the intensities of the bandwidths for a better structural visualization of the render, and knowing FURY already +have a good set of <a class="reference external" href="https://fury.gl/latest/auto_examples/index.html#user-interface-elements">UI elements</a>, I just needed to integrate +that into my program via callbacks. I tried implementing an intensity slider. However, for some reason, it is making the program crash +randomly, for reasons I still don’t know, so that is another issue under investigation. Below, we show a first version of that feature, +which was working before the crashes:</p> +<img alt="Slider for bandwidths" class="align-center" src="https://raw.githubusercontent.com/JoaoDell/gsoc_assets/main/images/slider.gif" /> +<p><em>Pull Requests</em></p> +<ul class="simple"> +<li><p><strong>UI intensity slider for the KDE rendering API (draft)</strong>: <a class="github reference external" href="https://github.com/fury-gl/fury/pull/849">fury-gl/fury#849</a></p></li> +<li><p><strong>Post-processing effects for FURY Effects API (draft)</strong>: <a class="github reference external" href="https://github.com/fury-gl/fury/pull/850">fury-gl/fury#850</a></p></li> +</ul> +</dd> +</dl> +</li> +</ul> +</section> +<section id="gsoc-weekly-blogs"> +<h2>GSoC Weekly Blogs</h2> +<ul class="simple"> +<li><p>My blog posts can be found at <a class="reference external" href="https://fury.gl/latest/blog/author/joao-victor-dell-agli-floriano.html">FURY website</a> and <a class="reference external" href="https://blogs.python-gsoc.org/en/joaodellaglis-blog/">Python GSoC blog</a>.</p></li> +</ul> +</section> +<section id="timeline"> +<h2>Timeline</h2> +<aside class="system-message"> +<p class="system-message-title">System Message: ERROR/3 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-21-joaodellagli-final-report.rst</span>, line 332)</p> +<p>Malformed table.</p> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>+---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Date | Description | Blog Post Link | ++=====================+====================================================+===========================================================================================================================================================================================================+ +| Week 0 (29-05-2023) | The Beginning of Everything | `FURY &lt;https://fury.gl/latest/posts/2023/2023-05-29-week-0-joaodellagli.html&gt;`__ - `Python &lt;https://blogs.python-gsoc.org/en/joaodellaglis-blog/the-beggining-of-everything-week-0/&gt;`__ | ++---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 1 (05-06-2022) | The FBO Saga | `FURY &lt;https://fury.gl/latest/posts/2023/2023-06-05-week-1-joaodellagli.html&gt;`__ - `Python &lt;https://blogs.python-gsoc.org/en/joaodellaglis-blog/the-fbo-saga-week-1/&gt;`__ | ++---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 2 (12-06-2022) | The Importance of (good) Documentation | `FURY &lt;https://fury.gl/latest/posts/2023/2023-06-12-week-2-joaodellagli.html&gt;`__ - `Python &lt;https://blogs.python-gsoc.org/en/joaodellaglis-blog/the-importance-of-good-documentation-week-2/&gt;`__ | ++---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 3 (19-06-2022) | Watch Your Expectations | `FURY &lt;https://fury.gl/latest/posts/2023/2023-06-19-week-3-joaodellagli.html&gt;`__ - `Python &lt;https://blogs.python-gsoc.org/en/joaodellaglis-blog/week-3-watch-your-expectations/&gt;`__ | ++---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 4 (26-06-2022) | Nothing is Ever Lost | `FURY &lt;https://fury.gl/latest/posts/2023/2023-06-26-week-4-joaodellagli.html&gt;`__ - `Python &lt;https://blogs.python-gsoc.org/en/joaodellaglis-blog/week-4-nothing-is-ever-lost/&gt;`__ | ++---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 5 (03-07-2022) | All Roads Lead to Rome | `FURY &lt;https://fury.gl/latest/posts/2023/2023-07-03-week-5-joaodellagli.html&gt;`__ - `Python &lt;https://blogs.python-gsoc.org/en/joaodellaglis-blog/week-5-all-roads-lead-to-rome/&gt;`__ | ++---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 6 (10-07-2022) | Things are Starting to Build Up | `FURY &lt;https://fury.gl/latest/posts/2023/2023-07-10-week-6-joaodellagli.html&gt;`__ - `Python &lt;https://blogs.python-gsoc.org/en/joaodellaglis-blog/week-6-things-are-starting-to-build-up/&gt;`__ | ++---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 7 (17-07-2022) | Experimentation Done | `FURY &lt;https://fury.gl/latest/posts/2023/2023-07-17-week-7-joaodellagli.html&gt;`__ - `Python &lt;https://blogs.python-gsoc.org/en/joaodellaglis-blog/week-7-experimentation-done/&gt;`__ | ++---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 8 (24-07-2022) | The Birth of a Versatile API | `FURY &lt;https://fury.gl/latest/posts/2023/2023-07-24-week-8-joaodellagli.html&gt;`__ - `Python &lt;https://blogs.python-gsoc.org/en/joaodellaglis-blog/week-8-the-birth-of-a-versatile-api/&gt;`__ | ++---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 9 (31-07-2022) | It is Polishing Time! | `FURY &lt;https://fury.gl/latest/posts/2023/2023-07-31-week-9-joaodellagli.html&gt;`__ - `Python &lt;https://blogs.python-gsoc.org/en/joaodellaglis-blog/week-9-it-is-polishing-time/&gt;`__ | ++---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 10 (07-08-2022)| Ready for Review! | `FURY &lt;https://fury.gl/latest/posts/2023/2023-08-07-week-10-joaodellagli.html&gt;`__ - `Python &lt;https://blogs.python-gsoc.org/en/joaodellaglis-blog/ready-for-review/&gt;`__ | ++---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 11 (14-08-2022)| A Refactor is Sometimes Needed | `FURY &lt;https://fury.gl/latest/posts/2023/2023-08-14-week-11-joaodellagli.html&gt;`__ - `Python &lt;https://blogs.python-gsoc.org/en/joaodellaglis-blog/a-refactor-is-sometimes-needed/&gt;`__ | ++---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 12 (21-08-2022)| Now That is (almost) a Wrap! | `FURY &lt;https://fury.gl/latest/posts/2023/2023-08-21-week-12-joaodellagli.html&gt;`__ - `Python &lt;https://blogs.python-gsoc.org/en/joaodellaglis-blog/week-12-now-that-is-almost-a-wrap/&gt;`__ | ++---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +</pre></div> +</div> +</aside> +</section> +</section> + + + Name: João Victor Dell Agli Floriano + + 2023-08-21T00:00:00-04:00 + + + https://fury.gl/posts/2023/2023-08-19-week-12-praneeth.html + Week 12: FileDialog Quest Begins! + 2023-08-19T00:00:00-04:00 + + Praneeth Shetty + + <section id="week-12-filedialog-quest-begins"> + +<section id="what-did-you-do-this-week"> +<h2>What did you do this week?</h2> +<p>During this week, I initiated my work on the <code class="docutils literal notranslate"><span class="pre">FileDialog</span></code> PR, which had been started by Soham. The initial version of the <code class="docutils literal notranslate"><span class="pre">FileDialog</span></code> can be found at <a class="reference external" href="https://github.com/fury-gl/fury/pull/294">#294</a>. To start, I focused on rebasing the PR. Since this PR was based on an older version, there were some updates to the overall UI structure that needed to be addressed for compatibility. While handling this, I identified a set of issues that I documented in the current PR <a class="reference external" href="https://github.com/fury-gl/fury/pull/832">#832</a>. These mainly revolved around:</p> +<ol class="arabic simple"> +<li><p>Resizing <code class="docutils literal notranslate"><span class="pre">FileDialog</span></code> and related components.</p></li> +<li><p>Rectifying the text overflow problem.</p></li> +<li><p>Dealing with a <code class="docutils literal notranslate"><span class="pre">ZeroDivisionError</span></code>.</p></li> +<li><p>Fixing the positioning of items in the <code class="docutils literal notranslate"><span class="pre">ListBox2D</span></code>.</p></li> +</ol> +<p>I systematically approached each of these challenges:</p> +<p><strong>Resizing FileMenu and Related Components:</strong> This was a fairly complex task since it involved intricate dependencies, such as the <code class="docutils literal notranslate"><span class="pre">FileDialog</span></code> relying on the <code class="docutils literal notranslate"><span class="pre">FileMenu</span></code>, which, in turn, was dependent on <code class="docutils literal notranslate"><span class="pre">ListBox2D</span></code> and <code class="docutils literal notranslate"><span class="pre">Panel2D</span></code> resizing. To make the process manageable, I decided to progress incrementally in a separate PR a bit later.</p> +<p><strong>Text Overflow Issue:</strong> The problem with text overflow was rooted in our previous approach, which involved executing these actions only when the <code class="docutils literal notranslate"><span class="pre">TextBlock2D</span></code> had a scene property. Although this approach suited the previous version of <code class="docutils literal notranslate"><span class="pre">TextBlock2D</span></code>, the recent refactoring led to the removal of this property. The scene was previously utilized to determine the text actor’s size. However, we had new methodologies to calculate these sizes, which are detailed in <a class="reference external" href="https://github.com/fury-gl/fury/pull/803">#803</a>.</p> +<img alt="Text Overflow Before" class="align-center" src="https://github.com/fury-gl/fury/assets/64432063/b001f9d3-a5e8-45ad-8605-85df595b5654" /> +<img alt="Text Overflow After" class="align-center" src="https://github.com/fury-gl/fury/assets/64432063/d3c9c3a3-e601-45ab-8975-2b1e98acf1d3" /> +<p><strong>Addressing ZeroDivisionError:</strong> The <code class="docutils literal notranslate"><span class="pre">ZeroDivisionError</span></code> emerged when the total number of values was the same as the number of slots. The issue lay in the separation of these values for calculating the scrollbar’s height parameter. Unfortunately, this calculation error occurred when this would return us zero while updating the scrollbar. To counter this, I implemented a conditional check to ascertain whether the value is zero or not.</p> +<p><strong>Correcting ``ListBox2D`` Item Positioning:</strong> Another challenge I encountered related to the improper positioning of <code class="docutils literal notranslate"><span class="pre">ListBox2D</span></code> item’s background. When a slot was not visible, its background was resized to zero, and visibility was set to off. Consequently, during the calculation of updated positions, the height was considered zero, leading to mispositioning. I resolved this by refraining from resizing and solely toggling visibility, achieving the desired result.</p> +<img alt="ListBox2D mispositioning Before" class="align-center" src="https://github.com/fury-gl/fury/assets/64432063/e2805934-b037-47fd-872c-0b284b298d3c" /> +<img alt="Fixed ListBox2D mispositioning" class="align-center" src="https://github.com/fury-gl/fury/assets/64432063/3bc1aabb-bb79-4e26-817d-a2a2ddd20ea3" /> +</section> +<section id="did-you-get-stuck-anywhere"> +<h2>Did you get stuck anywhere?</h2> +<p>Among the challenges I faced, one notable instance involved addressing the visibility issue in <code class="docutils literal notranslate"><span class="pre">TreeUI</span></code>. Despite my attempts at various solutions, none yielded the desired outcome. The <code class="docutils literal notranslate"><span class="pre">TreeUI</span></code> exhibited either full visibility or no visibility at all. In this situation, I sought guidance from my mentor to find a viable solution.</p> +</section> +<section id="what-is-coming-up-next"> +<h2>What is coming up next?</h2> +<p>The <code class="docutils literal notranslate"><span class="pre">FileDialog</span></code> implementation is nearly finalized, and my plan is to work on any review, feedback or suggestions that might arise. Following this, I will shift my attention towards addressing the <code class="docutils literal notranslate"><span class="pre">TreeUI</span></code>.</p> +</section> +</section> + + + During this week, I initiated my work on the FileDialog PR, which had been started by Soham. The initial version of the FileDialog can be found at #294. To start, I focused on rebasing the PR. Since this PR was based on an older version, there were some updates to the overall UI structure that needed to be addressed for compatibility. While handling this, I identified a set of issues that I documented in the current PR #832. These mainly revolved around: + + 2023-08-19T00:00:00-04:00 + + + https://fury.gl/posts/2023/2023-08-16-week-11-tvcastillod.html + Week 11 : Adjusting ODF implementation and looking for solutions on issues found + 2023-08-16T00:00:00-04:00 + + Tania Castillo + + <section id="week-11-adjusting-odf-implementation-and-looking-for-solutions-on-issues-found"> + +<section id="what-did-i-do-this-week"> +<h2>What did I do this week?</h2> +<p>I continued to experiment with the ODF glyph implementation. Thanks to one of my mentors I figured out how to get the missing data corresponding to the SH coefficients <span class="math notranslate nohighlight">\(a^l_m\)</span> part of the function <span class="math notranslate nohighlight">\(f(\theta, \phi)\)</span> described <a class="reference external" href="https://dipy.org/documentation/1.7.0/theory/sh_basis/">here</a>. I also was told to make sure to implement the correct SH basis since there are different definitions from the literature, I have to focus now in the one proposed by Descoteaux, described in <a class="reference external" href="https://onlinelibrary.wiley.com/doi/10.1002/mrm.21277">this paper</a>, which is labeled in <em>dipy</em> as <em>descoteaux07</em>. To do this I had to make a small adjustment to the base implementation that I took as a reference, from which I obtained a first result using SH of order 4.</p> +<img alt="https://user-images.githubusercontent.com/31288525/260909561-fd90033c-018a-465b-bd16-3586bb31ca36.png" class="align-center" src="https://user-images.githubusercontent.com/31288525/260909561-fd90033c-018a-465b-bd16-3586bb31ca36.png" style="width: 600px;" /> +<p>It appears that the results on the shape are about the same, except for the direction, but there is still work to be done.</p> +</section> +<section id="what-is-coming-up-next"> +<h2>What is coming up next?</h2> +<p>For now, there are 3 things I will continue to work on:</p> +<ul> +<li><p>The color and lighting. As these objects present curvatures with quite a bit of detail in some cases, this is something that requires more specific lighting work, in addition to having now not only one color but a color map.</p></li> +<li><p>The scaling. This is something I still don’t know how to deal with. I had to adjust it manually for now, but the idea is to find a relationship between the coefficients and the final object size so it can be automatically scaled, or maybe there is a proper way to pre-process this data before passing it to the shaders to get the right result at once.</p></li> +<li><aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-16-week-11-tvcastillod.rst</span>, line 2); <em><a href="#id1">backlink</a></em></p> +<p>Duplicate explicit target name: “here”.</p> +</aside> +<p>How to pass the information of the coefficients efficiently. Right now I’m creating one actor per glyph since I’m using a uniform array to pass the coefficients, but the idea is to pass all the data at once. I found several ideas <a class="reference external" href="https://stackoverflow.com/questions/7954927/passing-a-list-of-values-to-fragment-shader">here</a> of how to pass a list of values to the fragment shader directly, I just need to explore deeper how this can be done on <strong>FURY</strong>, and see which option is most suitable.</p> +</li> +</ul> +</section> +<section id="did-i-get-stuck-anywhere"> +<h2>Did I get stuck anywhere?</h2> +<p>All the points mentioned above are things that I tried to fix, however, it is something that I need to look at in much more detail and that I know is going to take me some time to understand and test before I get to the expected result. I hope to get some ideas from my mentors and fellow GSoC contributors on how I can proceed to deal with each of the problems.</p> +</section> +</section> + + + I continued to experiment with the ODF glyph implementation. Thanks to one of my mentors I figured out how to get the missing data corresponding to the SH coefficients a^l_m part of the function f(\theta, \phi) described here. I also was told to make sure to implement the correct SH basis since there are different definitions from the literature, I have to focus now in the one proposed by Descoteaux, described in this paper, which is labeled in dipy as descoteaux07. To do this I had to make a small adjustment to the base implementation that I took as a reference, from which I obtained a first result using SH of order 4. + + 2023-08-16T00:00:00-04:00 + + + https://fury.gl/posts/2023/2023-08-14-week-11-joaodellagli.html + Week 11: A Refactor is Sometimes Needed + 2023-08-14T00:00:00-04:00 + + João Victor Dell Agli Floriano + + <section id="week-11-a-refactor-is-sometimes-needed"> + +<p>Hello everyone, it’s time for another weekly blogpost! Today I am going to share some updates on the API refactoring +I was working on with my mentors.</p> +<section id="last-week-s-effort"> +<h2>Last Week’s Effort</h2> +<p>As I shared with you <span class="xref std std-doc">last week</span>, the first draft of my API was finally ready for review, as +I finished tweaking some remaining details missing. I was tasked with finding a good example of the usage of the tools we proposed, +and I started to do that, however after testing it with some examples, I figured out some significant bugs were to be fixed. Also, +after some reviews and hints from some of my mentors and other GSoC contributors, we realised that some refactoring should be done, +mainly focused on avoiding bad API usage from the user.</p> +</section> +<section id="so-how-did-it-go"> +<h2>So how did it go?</h2> +<p>Initially, I thought only one bug was the source of the issues the rendering presented, but it turned out to be two, which I will +explain further.</p> +<p>The first bug was related to scaling and misalignment of the KDE render. The render of the points being post-processed was not only +with sizes different from the original set size, but it was also misaligned, making it appear in positions different from the points’ +original ones. After some time spent, I figured out the bug was related to the texture coordinates I was using. Before, this is how +my fragment shader looked:</p> +<div class="highlight-C notranslate"><div class="highlight"><pre><span></span><span class="n">vec2</span><span class="w"> </span><span class="n">res_factor</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">vec2</span><span class="p">(</span><span class="n">res</span><span class="p">.</span><span class="n">y</span><span class="o">/</span><span class="n">res</span><span class="p">.</span><span class="n">x</span><span class="p">,</span><span class="w"> </span><span class="mf">1.0</span><span class="p">);</span> +<span class="n">vec2</span><span class="w"> </span><span class="n">tex_coords</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">res_factor</span><span class="o">*</span><span class="n">normalizedVertexMCVSOutput</span><span class="p">.</span><span class="n">xy</span><span class="o">*</span><span class="mf">0.5</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mf">0.5</span><span class="p">;</span> +<span class="kt">float</span><span class="w"> </span><span class="n">intensity</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">texture</span><span class="p">(</span><span class="n">screenTexture</span><span class="p">,</span><span class="w"> </span><span class="n">tex_coords</span><span class="p">).</span><span class="n">r</span><span class="p">;</span> +</pre></div> +</div> +<p>It turns out using this texture coordinates for <em>this case</em> was not the best choice, as even though it matches the fragment positions, +the idea here was to render the offscreen window, which has the same size as the onscreen one, to the billboard actor. With that in mind, +I realised the best choice was using texture coordinates that matched the whole screen positions, coordinates that were derived from the +<code class="docutils literal notranslate"><span class="pre">gl_FragCoord.xy</span></code>, being the division of that by the resolution of the screen, for normalization. Below, the change made:</p> +<div class="highlight-C notranslate"><div class="highlight"><pre><span></span><span class="n">vec2</span><span class="w"> </span><span class="n">tex_coords</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">gl_FragCoord</span><span class="p">.</span><span class="n">xy</span><span class="o">/</span><span class="n">res</span><span class="p">;</span> +<span class="kt">float</span><span class="w"> </span><span class="n">intensity</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">texture</span><span class="p">(</span><span class="n">screenTexture</span><span class="p">,</span><span class="w"> </span><span class="n">tex_coords</span><span class="p">).</span><span class="n">r</span><span class="p">;</span> +</pre></div> +</div> +<p>This change worked initially, although with some problems, that later revealed the resolution of the offscreen window needed to be +updated inside the callback function as well. Fixing that, it was perfectly aligned and scaled!</p> +<p>The second bug was related with the handling of the bandwidth, former sigma parameter. I realised I wasn’t dealing properly with the option of the user passing only +one single bandwidth value being passed, so when trying that, only the first point was being rendered. I also fixed that and it worked, +so cheers!</p> +<p>As I previously said, the bugs were not the only details I spent my time on last week. Being reviewed, the API design, even +though simple, showed itself vulnerable to bad usage from the user side, requiring some changes. The changes suggested by mentors were, +to, basically, take the <code class="docutils literal notranslate"><span class="pre">kde</span></code> method out of the <code class="docutils literal notranslate"><span class="pre">EffectManager</span></code> class, and create a new class from it inside an <code class="docutils literal notranslate"><span class="pre">effects</span></code> module, +like it was a special effects class. With this change, the KDE setup would go from:</p> +<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">em</span> <span class="o">=</span> <span class="n">EffectManager</span><span class="p">(</span><span class="n">show_manager</span><span class="p">)</span> + +<span class="n">kde_actor</span> <span class="o">=</span> <span class="n">em</span><span class="o">.</span><span class="n">kde</span><span class="p">(</span><span class="o">...</span><span class="p">)</span> + +<span class="n">show_manager</span><span class="o">.</span><span class="n">scene</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">kde_actor</span><span class="p">)</span> +</pre></div> +</div> +<p>To:</p> +<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">em</span> <span class="o">=</span> <span class="n">EffectManager</span><span class="p">(</span><span class="n">show_manager</span><span class="p">)</span> + +<span class="n">kde_effect</span> <span class="o">=</span> <span class="n">KDE</span><span class="p">(</span><span class="o">...</span><span class="p">)</span> + +<span class="n">em</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">kde_effect</span><span class="p">)</span> +</pre></div> +</div> +<p>Not a gain in line shortening, however, a gain in security, as preventing users from misusing the kde_actor. Something worth noting is +that I learned how to use the <code class="docutils literal notranslate"><span class="pre">functools.partial</span></code> function, that allowed me to partially call the callback function with only some +parameters passed.</p> +</section> +<section id="this-week-s-goals"> +<h2>This Week’s Goals</h2> +<p>Having that refactoring made, now I am awaiting for a second review so we could finally wrap it up and merge the first stage of this API. +With that being done, I will write the final report and wrap this all up.</p> +<p>Let’s get to work!</p> +</section> +</section> + + + Hello everyone, it’s time for another weekly blogpost! Today I am going to share some updates on the API refactoring +I was working on with my mentors. + + 2023-08-14T00:00:00-04:00 + + + https://fury.gl/posts/2023/2023-08-12-week-11-praneeth.html + Week 11: Bye Bye SpinBox + 2023-08-12T00:00:00-04:00 + + Praneeth Shetty + + <section id="week-11-bye-bye-spinbox"> + +<section id="what-did-you-do-this-week"> +<h2>What did you do this week?</h2> +<p>Building upon the progress of the previous week, a major milestone was reached with the merging of PR <a class="reference external" href="https://github.com/fury-gl/fury/pull/830">#830</a>. This PR added essential “getters” and “setters” for the new features of <code class="docutils literal notranslate"><span class="pre">TextBlock</span></code>, making it easier to handle changes. This, in turn, facilitated the integration of <code class="docutils literal notranslate"><span class="pre">SpinBoxUI</span></code> with the updated <code class="docutils literal notranslate"><span class="pre">TextBlock</span></code>.</p> +<p>However, while working on <code class="docutils literal notranslate"><span class="pre">SpinBoxUI</span></code>, a critical issue emerged. As <code class="docutils literal notranslate"><span class="pre">SpinBoxUI</span></code> allows users to input characters and symbols into an editable textbox, it posed a risk of program crashes due to invalid inputs. To counter this, I introduced a validation check to ensure that the input was a valid number. If valid, the input was converted; otherwise, it reverted to the previous value. After thorough testing and review, PR <a class="reference external" href="https://github.com/fury-gl/fury/pull/499">#499</a> was successfully merged.</p> +<img alt="SpinBoxUI" class="align-center" src="https://user-images.githubusercontent.com/64432063/261409747-511e535b-185c-4e70-aaa8-5296c93e5344.gif" style="width: 500px;" /> +<p>Meanwhile, a concern with the textbox’s behavior was identified when <code class="docutils literal notranslate"><span class="pre">SpinBoxUI</span></code> was scaled to a larger size. Specifically, the text occasionally touched the top or bottom boundary, creating an overflow appearance. Although initial solutions were attempted, the complexity of the issue required further consideration. This issue has been documented in more detail in Issue <a class="reference external" href="https://github.com/fury-gl/fury/pull/838">#838</a>, where it is marked as a low-priority item.</p> +<figure class="align-center"> +<img alt="TextBlock2D text positioning issue" src="https://user-images.githubusercontent.com/64432063/133194003-53e2dac6-31e0-444e-b7f1-a9e71545f560.jpeg" /> +</figure> +</section> +<section id="did-you-get-stuck-anywhere"> +<h2>Did you get stuck anywhere?</h2> +<p>The challenge of the week centered around addressing the textbox’s overflow behavior in <code class="docutils literal notranslate"><span class="pre">SpinBoxUI</span></code>.</p> +</section> +<section id="what-is-coming-up-next"> +<h2>What is coming up next?</h2> +<p>Looking ahead, the focus remains on refining the FileDialog component, as the significant progress with <code class="docutils literal notranslate"><span class="pre">TextBlock</span></code> and <code class="docutils literal notranslate"><span class="pre">SpinBoxUI</span></code> prepares us to shift attention to other aspects of development.</p> +</section> +</section> + + + Building upon the progress of the previous week, a major milestone was reached with the merging of PR #830. This PR added essential “getters” and “setters” for the new features of TextBlock, making it easier to handle changes. This, in turn, facilitated the integration of SpinBoxUI with the updated TextBlock. + + 2023-08-12T00:00:00-04:00 + + + https://fury.gl/posts/2023/2023-08-08-week-10-tvcastillod.html + Week 10 : Start of SH implementation experiments + 2023-08-08T00:00:00-04:00 + + Tania Castillo + + <section id="week-10-start-of-sh-implementation-experiments"> + +<section id="what-did-i-do-this-week"> +<h2>What did I do this week?</h2> +<p>I started formally working on SH implementation. I was told to start first doing a simple program where I can modify in real-time the order <span class="math notranslate nohighlight">\(l\)</span> and degree <span class="math notranslate nohighlight">\(m\)</span>, parameters corresponding to the <a class="reference external" href="https://dipy.org/documentation/1.7.0/theory/sh_basis/">Spherical Harmonics function</a> <span class="math notranslate nohighlight">\(Y^m_l(\theta,\phi)=\)</span>, based on <a class="reference external" href="https://github.com/lenixlobo/fury/commit/2b7ce7a71fd422dc5a250d7b49e1eea2db9d3bce">previous work</a>. That is just one part of the final ODF calculation, but here is what a first experimental script looks like.</p> +<img alt="https://user-images.githubusercontent.com/31288525/260910073-10b0edd4-40e3-495c-85ad-79993aef3b19.png" class="align-center" src="https://user-images.githubusercontent.com/31288525/260910073-10b0edd4-40e3-495c-85ad-79993aef3b19.png" style="width: 600px;" /> +<p>I did it in order to make sure it was visually correct and also to understand better how those 2 parameters are related and need to be incorporated into the final calculation. There is one issue at first sight that needs to be addressed, and that is the scaling, since for SH with a degree near 0, the object gets out of bounds.</p> +</section> +<section id="what-is-coming-up-next"> +<h2>What is coming up next?</h2> +<p>I will keep polishing details from my current open PRs, hopefully, I will get another PR merged before the last GSoC week.</p> +</section> +<section id="did-i-get-stuck-anywhere"> +<h2>Did I get stuck anywhere?</h2> +<p>Not sure about how to use the current implementation I have to get similar visualizations made with <em>odf_slicer</em>, since the parameters that the function receive are different, so I need to take a deeper look and see where it might be the connection or if I should make some adjustments on the parameters.</p> +</section> +</section> + + + I started formally working on SH implementation. I was told to start first doing a simple program where I can modify in real-time the order l and degree m, parameters corresponding to the Spherical Harmonics function Y^m_l(\theta,\phi)=, based on previous work. That is just one part of the final ODF calculation, but here is what a first experimental script looks like. + + 2023-08-08T00:00:00-04:00 + + diff --git a/v0.10.x/blog/archive.html b/v0.10.x/blog/archive.html new file mode 100644 index 000000000..fe7cd8efc --- /dev/null +++ b/v0.10.x/blog/archive.html @@ -0,0 +1,2602 @@ + + + + + + + All posts — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + + +
+

+ Posted in + 2023 +

+ +
+

+ + 25 August 2023 + + - + Google Summer of Code Final Work Product +

+
+ +
+

+ + 24 August 2023 + + - + Week 12 : Experimenting with ODFs implementation +

+
+ +
+

+ + 24 August 2023 + + - + Google Summer of Code Final Work Product +

+
+ +
+

+ + 21 August 2023 + + - + Week 12: Now That is (almost) a Wrap! +

+
+ +
+

+ + 21 August 2023 + + - + Google Summer of Code Final Work Product +

+
+ +
+

+ + 19 August 2023 + + - + Week 12: FileDialog Quest Begins! +

+
+ +
+

+ + 16 August 2023 + + - + Week 11 : Adjusting ODF implementation and looking for solutions on issues found +

+
+ +
+

+ + 14 August 2023 + + - + Week 11: A Refactor is Sometimes Needed +

+
+ +
+

+ + 12 August 2023 + + - + Week 11: Bye Bye SpinBox +

+
+ +
+

+ + 08 August 2023 + + - + Week 10 : Start of SH implementation experiments +

+
+ +
+

+ + 07 August 2023 + + - + Week 10: Ready for Review! +

+
+ +
+

+ + 05 August 2023 + + - + Week 10: Its time for a Spin-Box! +

+
+ +
+

+ + 31 July 2023 + + - + Week 9: Tutorial done and polishing DTI uncertainty +

+
+ +
+

+ + 31 July 2023 + + - + Week 9: It is Polishing Time! +

+
+ +
+

+ + 29 July 2023 + + - + Week 9: TextBlock2D is Finally Merged! +

+
+ +
+

+ + 25 July 2023 + + - + Week 8: Working on Ellipsoid Tutorial and exploring SH +

+
+ +
+

+ + 24 July 2023 + + - + Week 8: The Birth of a Versatile API +

+
+ +
+

+ + 22 July 2023 + + - + Week 8: Another week with TextBlockUI +

+
+ +
+

+ + 17 July 2023 + + - + Week 7: Experimentation Done +

+
+ +
+

+ + 17 July 2023 + + - + Week 7: Adjustments on the Uncertainty Cones visualization +

+
+ +
+

+ + 15 July 2023 + + - + Week 7: Sowing the seeds for TreeUI +

+
+ +
+

+ + 10 July 2023 + + - + Week 6: Things are Starting to Build Up +

+
+ +
+

+ + 10 July 2023 + + - + Week 6: First draft of the Ellipsoid tutorial +

+
+ +
+

+ + 08 July 2023 + + - + Week 6: BoundingBox for TextBlock2D! +

+
+ +
+

+ + 03 July 2023 + + - + Week 5: Preparing the data for the Ellipsoid tutorial +

+
+ +
+

+ + 03 July 2023 + + - + Week 5: All Roads Lead to Rome +

+
+ +
+

+ + 01 July 2023 + + - + Week 5: Trying out PRs and Planning Ahead +

+
+ +
+

+ + 27 June 2023 + + - + Week 4: First draft of the DTI uncertainty visualization +

+
+ +
+

+ + 26 June 2023 + + - + Week 4: Nothing is Ever Lost +

+
+ +
+

+ + 24 June 2023 + + - + Week 4: Exam Preparations and Reviewing +

+
+ +
+

+ + 19 June 2023 + + - + Week 3: Working on uncertainty and details of the first PR +

+
+ +
+

+ + 19 June 2023 + + - + Week 3: Watch Your Expectations +

+
+ +
+

+ + 17 June 2023 + + - + Week 3: Resolving Combobox Icon Flaw and TextBox Justification +

+
+ +
+

+ + 12 June 2023 + + - + Week 2: The Importance of (good) Documentation +

+
+ +
+

+ + 12 June 2023 + + - + Week 2: Making adjustments to the Ellipsoid Actor +

+
+ +
+

+ + 11 June 2023 + + - + Week 2: Tackling Text Justification and Icon Flaw Issues +

+
+ +
+

+ + 05 June 2023 + + - + Week 1: Ellipsoid actor implemented with SDF +

+
+ +
+

+ + 05 June 2023 + + - + The FBO Saga - Week 1 +

+
+ +
+

+ + 03 June 2023 + + - + Week 1: Working with SpinBox and TextBox Enhancements +

+
+ +
+

+ + 02 June 2023 + + - + Week 0: Community Bounding Period +

+
+ +
+

+ + 02 June 2023 + + - + Week 0: Community Bounding Period +

+
+ +
+

+ + 29 May 2023 + + - + The Beginning of Everything - Week 0 +

+
+ +
+

+ + 15 April 2023 + + - + FURY 0.9.0 Released +

+
+ +
+

+ + 01 February 2023 + + - + Contribute to FURY via Google Summer of Code 2023 +

+
+ +
+

+ + 29 January 2023 + + - + Google Summer of Code Final Work Product +

+
+ +
+

+ + 29 January 2023 + + - + Google Summer of Code Final Work Product +

+
+ +
+

+ + 24 January 2023 + + - + Google Summer of Code Final Work Product +

+
+ +
+ + + +
+

+ Posted in + 2022 +

+ +
+

+ + 28 September 2022 + + - + Week 14: Keyframes animation is now a bit easier in FURY +

+
+ +
+

+ + 28 September 2022 + + - + Week 14 - Morphing is here! +

+
+ +
+

+ + 21 September 2022 + + - + Week 16 - Working with Rotations! +

+
+ +
+

+ + 20 September 2022 + + - + Week 13: Keyframes animation is now a bit easier in FURY +

+
+ +
+

+ + 15 September 2022 + + - + Week 13 - Multi-bone skeletal animation support +

+
+ +
+

+ + 14 September 2022 + + - + Week 15 - Highlighting DrawShapes +

+
+ +
+

+ + 08 September 2022 + + - + Week 12 - Adding skeleton as actors and fix global transformation +

+
+ +
+

+ + 07 September 2022 + + - + Week 14 - Updating DrawPanel architecture +

+
+ +
+

+ + 07 September 2022 + + - + Week 12: Adding new tutorials +

+
+ +
+

+ + 31 August 2022 + + - + Week 13 - Separating tests and fixing bugs +

+
+ +
+

+ + 31 August 2022 + + - + Week 11 - Multiple transformations support and adding tests +

+
+ +
+

+ + 30 August 2022 + + - + Week 11: Improving tutorials a little +

+
+ +
+

+ + 25 August 2022 + + - + Week 10 - Multi-node skinning support +

+
+ +
+

+ + 24 August 2022 + + - + Week 12 - Fixing translating issues and updating tests +

+
+ +
+

+ + 23 August 2022 + + - + Week 10: Supporting hierarchical animating +

+
+ +
+

+ + 17 August 2022 + + - + Week 9 - First working skeletal animation prototype +

+
+ +
+

+ + 17 August 2022 + + - + Week 11 - Creating a base for Freehand Drawing +

+
+ +
+

+ + 16 August 2022 + + - + Week 9: Animating primitives of the same actor +

+
+ +
+

+ + 10 August 2022 + + - + Week 8 - Fixing animation bugs +

+
+ +
+

+ + 10 August 2022 + + - + Week 10 - Understanding Codes and Playing with Animation +

+
+ +
+

+ + 09 August 2022 + + - + Week 8: Back to the shader-based version of the Timeline +

+
+ +
+

+ + 03 August 2022 + + - + Week 9 - Grouping and Transforming Shapes +

+
+ +
+

+ + 01 August 2022 + + - + Week 7: Billboard spheres and implementing interpolators using closures +

+
+ +
+

+ + 01 August 2022 + + - + Week 7 - Fixing bugs in animations +

+
+ +
+

+ + 27 July 2022 + + - + Week 8 - Working on the polyline feature +

+
+ +
+

+ + 25 July 2022 + + - + Week 6: Fixing the Timeline issues and equipping it with more features +

+
+ +
+

+ + 25 July 2022 + + - + Week 6 - Extracting the animation data +

+
+ +
+

+ + 20 July 2022 + + - + Week 7 - Working on Rotation PR and Trying Freehand Drawing +

+
+ +
+

+ + 19 July 2022 + + - + Week 5: Slerp implementation, documenting the Timeline, and adding unit tests +

+
+ +
+

+ + 19 July 2022 + + - + Week 5 - Creating PR for glTF exporter and fixing the loader +

+
+ +
+

+ + 13 July 2022 + + - + Week 6 - Supporting Rotation of the Shapes from the Center +

+
+ +
+

+ + 12 July 2022 + + - + Week 4 - Finalizing glTF loader +

+
+ +
+

+ + 11 July 2022 + + - + Week 4: Camera animation, interpolation in GLSL, and a single Timeline! +

+
+ +
+

+ + 06 July 2022 + + - + Week 5 - Working on new features +

+
+ +
+

+ + 04 July 2022 + + - + Week 3: Redesigning the API, Implementing cubic Bezier Interpolator, and making progress on the GPU side! +

+
+ +
+

+ + 04 July 2022 + + - + Week 3 - Fixing fetcher, adding tests and docs +

+
+ +
+

+ + 29 June 2022 + + - + Week 4 - Fixing the Clamping Issue +

+
+ +
+

+ + 29 June 2022 + + - + Week 2 - Improving Fetcher and Exporting glTF +

+
+ +
+

+ + 28 June 2022 + + - + Week 2: Implementing non-linear and color interpolators +

+
+ +
+

+ + 22 June 2022 + + - + Week 3 - Dealing with Problems +

+
+ +
+

+ + 20 June 2022 + + - + Week 1 - A Basic glTF Importer +

+
+ +
+

+ + 19 June 2022 + + - + Week 1: Implementing a basic Keyframe animation API +

+
+ +
+

+ + 15 June 2022 + + - + Week 2 - Improving DrawPanel UI +

+
+ +
+

+ + 08 June 2022 + + - + Week 1 - Laying the Foundation of DrawPanel UI +

+
+ +
+

+ + 25 May 2022 + + - + Pre-GSoC Journey +

+
+ +
+

+ + 24 May 2022 + + - + My Journey to GSoC 2022 +

+
+ +
+

+ + 23 May 2022 + + - + My journey till getting accepted into GSoC22 +

+
+ +
+

+ + 01 February 2022 + + - + Contribute to FURY via Google Summer of Code 2022 +

+
+ +
+

+ + 31 January 2022 + + - + FURY 0.8.0 Released +

+
+ +
+ + + +
+

+ Posted in + 2021 +

+ +
+

+ + 23 August 2021 + + - + Google Summer of Code Final Work Product +

+
+ +
+

+ + 23 August 2021 + + - + Google Summer of Code Final Work Product +

+
+ +
+

+ + 23 August 2021 + + - + Google Summer of Code 2021 - Final Report - Bruno Messias +

+
+ +
+

+ + 16 August 2021 + + - + Week #11: Removing the flickering effect +

+
+ +
+

+ + 16 August 2021 + + - + Week #11: Finalizing open Pull Requests +

+
+ +
+

+ + 16 August 2021 + + - + Tenth coding week! +

+
+ +
+

+ + 09 August 2021 + + - + Week#10: Accordion UI, Support for sprite sheet animations +

+
+ +
+

+ + 09 August 2021 + + - + Week #10: SDF Fonts +

+
+ +
+

+ + 09 August 2021 + + - + Ninth coding week! +

+
+ +
+

+ + 03 August 2021 + + - + FURY 0.7.0 Released +

+
+ +
+

+ + 02 August 2021 + + - + Week #9: More Layouts! +

+
+ +
+

+ + 02 August 2021 + + - + Week #09: Sphinx custom summary +

+
+ +
+

+ + 02 August 2021 + + - + Eighth coding week! +

+
+ +
+

+ + 26 July 2021 + + - + Weekly Check-In #8 +

+
+ +
+

+ + 26 July 2021 + + - + Week #8: Code Cleanup, Finishing up open PRs, Continuing work on Tree2D +

+
+ +
+

+ + 26 July 2021 + + - + Seventh week of coding! +

+
+ +
+

+ + 19 July 2021 + + - + Weekly Check-In #7 +

+
+ +
+

+ + 19 July 2021 + + - + Week #7: Finalizing the stalling PRs, finishing up Tree2D UI. +

+
+ +
+

+ + 19 July 2021 + + - + Sixth week of coding! +

+
+ +
+

+ + 12 July 2021 + + - + Week #6: Bug fixes, Working on Tree2D UI +

+
+ +
+

+ + 12 July 2021 + + - + Network layout algorithms using IPC +

+
+ +
+

+ + 12 July 2021 + + - + Fifth week of coding! +

+
+ +
+

+ + 05 July 2021 + + - + Weekly Check-In #5 +

+
+ +
+

+ + 05 July 2021 + + - + Week #5: Rebasing all PRs w.r.t the UI restructuring, Tree2D, Bug Fixes +

+
+ +
+

+ + 05 July 2021 + + - + SOLID, monkey patching a python issue and network visualization through WebRTC +

+
+ +
+

+ + 05 July 2021 + + - + Fourth week of coding! +

+
+ +
+

+ + 28 June 2021 + + - + Week #4: Adding Tree UI to the UI module +

+
+ +
+

+ + 28 June 2021 + + - + Third week of coding! +

+
+ +
+

+ + 21 June 2021 + + - + Weekly Check-In #3 +

+
+ +
+

+ + 21 June 2021 + + - + Week #3: Adapting GridLayout to work with UI +

+
+ +
+

+ + 21 June 2021 + + - + Second week of coding! +

+
+ +
+

+ + 14 June 2021 + + - + First week of coding! +

+
+ +
+

+ + 13 June 2021 + + - + Week #2: Feature additions in UI and IO modules +

+
+ +
+

+ + 13 June 2021 + + - + A Stadia-like system for data visualization +

+
+ +
+

+ + 08 June 2021 + + - + Welcome to my GSoC Blog! +

+
+ +
+

+ + 08 June 2021 + + - + Weekly Check-In #1 +

+
+ +
+

+ + 08 June 2021 + + - + Week #1: Welcome to my weekly Blogs! +

+
+ +
+

+ + 13 March 2021 + + - + FURY 0.7.0 Released +

+
+ +
+

+ + 09 March 2021 + + - + Google Summer of Code +

+
+ +
+ + + +
+

+ Posted in + 2020 +

+ +
+

+ + 24 August 2020 + + - + Shader Showcase +

+
+ +
+

+ + 24 August 2020 + + - + Google Summer of Code Final Work Product +

+
+ +
+

+ + 24 August 2020 + + - + Google Summer of Code 2020 Final Work Product +

+
+ +
+

+ + 23 August 2020 + + - + Part of the Journey is the end unless its Open Source! +

+
+ +
+

+ + 18 August 2020 + + - + FURY 0.6.1 Released +

+
+ +
+

+ + 17 August 2020 + + - + Outline Picker +

+
+ +
+

+ + 16 August 2020 + + - + Wrecking Ball Simulation, Scrollbars Update, Physics Tutorials. +

+
+ +
+

+ + 09 August 2020 + + - + More Shaders!! +

+
+ +
+

+ + 09 August 2020 + + - + Chain Simulation, Scrollbar Refactor, Tutorial Update. +

+
+ +
+

+ + 02 August 2020 + + - + Single Actor, Physics, Scrollbars. +

+
+ +
+

+ + 02 August 2020 + + - + More Shaders!! +

+
+ +
+

+ + 27 July 2020 + + - + Merging SDF primitives. +

+
+ +
+

+ + 26 July 2020 + + - + Tab UI, TabPanel2D, Tab UI Tutorial. +

+
+ +
+

+ + 20 July 2020 + + - + Improvements in SDF primitives. +

+
+ +
+

+ + 20 July 2020 + + - + FURY 0.6.0 Released +

+
+ +
+

+ + 19 July 2020 + + - + ComboBox2D, TextBlock2D, Clipping Overflow. +

+
+ +
+

+ + 13 July 2020 + + - + Multiple SDF primitives. +

+
+ +
+

+ + 12 July 2020 + + - + Orientation, Sizing, Tab UI. +

+
+ +
+

+ + 05 July 2020 + + - + Translation, Reposition, Rotation. +

+
+ +
+

+ + 05 July 2020 + + - + Spherical harmonics, Continued. +

+
+ +
+

+ + 28 June 2020 + + - + Spherical harmonics +

+
+ +
+

+ + 28 June 2020 + + - + May the Force be with you!! +

+
+ +
+

+ + 21 June 2020 + + - + TextBlock2D Progress!! +

+
+ +
+

+ + 21 June 2020 + + - + Raymarching continued +

+
+ +
+

+ + 14 June 2020 + + - + Raymarching!! +

+
+ +
+

+ + 14 June 2020 + + - + ComboBox2D Progress!! +

+
+ +
+

+ + 07 June 2020 + + - + First week of coding!! +

+
+ +
+

+ + 07 June 2020 + + - + First week of coding!! +

+
+ +
+

+ + 30 May 2020 + + - + Welcome to my GSoC Blog!!! +

+
+ +
+

+ + 30 May 2020 + + - + Weekly Check-in #1 +

+
+ +
+

+ + 09 April 2020 + + - + FURY 0.5.1 Released +

+
+ +
+

+ + 05 January 2020 + + - + Google Summer of Code +

+
+ +
+ + + +
+

+ Posted in + 2019 +

+ +
+

+ + 29 October 2019 + + - + FURY 0.4.0 Released +

+
+ +
+

+ + 02 August 2019 + + - + FURY 0.3.0 Released +

+
+ +
+

+ + 19 June 2019 + + - + Success on Brain Art Competition using FURY +

+
+ +
+

+ + 08 March 2019 + + - + FURY 0.2.0 Released +

+
+ +
+ + + +
+

+ Posted in + 2018 +

+ +
+

+ + 26 November 2018 + + - + FURY 0.1.4 Released +

+
+ +
+

+ + 31 October 2018 + + - + FURY 0.1.3 Released +

+
+ +
+

+ + 21 September 2018 + + - + FURY 0.1.0 Released +

+
+ +
+ + + +
+ + + +
+ +
+
+
+ +
+ + + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/blog/atom.xml b/v0.10.x/blog/atom.xml new file mode 100644 index 000000000..c97ae0fda --- /dev/null +++ b/v0.10.x/blog/atom.xml @@ -0,0 +1,1229 @@ + + + https://fury.gl/ + Blog + 2024-02-29T15:43:57.339142+00:00 + + + ABlog + + https://fury.gl/posts/2023/2023-08-25-final-report-praneeth.html + Google Summer of Code Final Work Product + 2023-08-25T00:00:00-04:00 + + Praneeth Shetty + + <a class="reference external image-reference" href="https://summerofcode.withgoogle.com/programs/2023/projects/BqfBWfwS"><img alt="https://developers.google.com/open-source/gsoc/resources/downloads/GSoC-logo-horizontal.svg" class="align-center" height="50" src="https://developers.google.com/open-source/gsoc/resources/downloads/GSoC-logo-horizontal.svg" /></a> +<a class="reference external image-reference" href="https://summerofcode.withgoogle.com/programs/2023/organizations/python-software-foundation"><img alt="https://www.python.org/static/community_logos/python-logo.png" src="https://www.python.org/static/community_logos/python-logo.png" style="width: 40%;" /></a> +<a class="reference external image-reference" href="https://fury.gl/latest/index.html"><img alt="https://python-gsoc.org/logos/FURY.png" src="https://python-gsoc.org/logos/FURY.png" style="width: 25%;" /></a> +<section id="google-summer-of-code-final-work-product"> + +<ul class="simple"> +<li><p><strong>Name:</strong> Praneeth Shetty</p></li> +<li><p><strong>Organisation:</strong> Python Software Foundation</p></li> +<li><p><strong>Sub-Organisation:</strong> FURY</p></li> +<li><p><strong>Project:</strong> <a class="reference external" href="https://github.com/fury-gl/fury/wiki/Google-Summer-of-Code-2023-(GSOC2023)#project-5-update-user-interface-widget--explore-new-ui-framework">FURY - Update user interface widget + Explore new UI Framework</a></p></li> +</ul> +<section id="proposed-objectives"> +<h2>Proposed Objectives</h2> +<ul class="simple"> +<li><p>SpinBoxUI</p></li> +<li><p>Scrollbar as Independent Element</p></li> +<li><p>FileDialog</p></li> +<li><p>TreeUI</p></li> +<li><p>AccordionUI</p></li> +<li><p>ColorPickerUI</p></li> +<li><dl class="simple"> +<dt>Stretch Goals:</dt><dd><ul> +<li><p>Exploring new UI Framework</p></li> +<li><p>Implementing Borders for UI elements</p></li> +</ul> +</dd> +</dl> +</li> +</ul> +</section> +<section id="objectives-completed"> +<h2>Objectives Completed</h2> +<ul> +<li><dl> +<dt><strong>SpinBoxUI:</strong></dt><dd><p>The <code class="docutils literal notranslate"><span class="pre">SpinBoxUI</span></code> element is essential for user interfaces as it allows users to pick a numeric value from a set range. While we had an active pull request (PR) to add this element, updates in the main code caused conflicts and required further changes for added features. At one point, we noticed that text alignment wasn’t centered properly within the box due to a flaw. To fix this, we began a PR to adjust the alignment, but it turned into a larger refactoring of the <code class="docutils literal notranslate"><span class="pre">TextBlock2D</span></code>, a core component connected to various parts. This was a complex task that needed careful handling. After sorting out the <code class="docutils literal notranslate"><span class="pre">TextBlock2D</span></code>, we returned to the <code class="docutils literal notranslate"><span class="pre">SpinBoxUI</span></code> and made a few tweaks. Once we were confident with the changes, the PR was successfully merged after thorough review and testing.</p> +<p><strong>Pull Requests:</strong></p> +</dd> +</dl> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 50)</p> +<p>Definition list ends without a blank line; unexpected unindent.</p> +</aside> +<ul> +<li><p><strong>SpinBoxUI (Merged)</strong> - <a class="github reference external" href="https://github.com/fury-gl/fury/pull/499">fury-gl/fury#499</a></p> +<blockquote> +<div><img alt="SpinBoxUI" class="align-center" src="https://user-images.githubusercontent.com/64432063/263165327-c0b19cdc-9ebd-433a-8ff1-99e706a76508.gif" style="height: 500px;" /> +</div></blockquote> +</li> +</ul> +</li> +<li><dl> +<dt><strong>`TextBlock2D` Refactoring:</strong></dt><dd><p>This was a significant aspect of the GSoC period and occupied a substantial portion of the timeline. The process began when we observed misaligned text in the <code class="docutils literal notranslate"><span class="pre">SpinBoxUI</span></code>, as previously discussed. The root cause of the alignment issue was the mispositioning of the text actor concerning the background actor. The text actor’s independent repositioning based on justification conflicted with the static position of the background actor, leading to the alignment problem.</p> +<p>To address this, the initial focus was on resolving the justification issue. However, as the work progressed, we recognized that solely adjusting justification would not suffice. The alignment was inherently linked to the UI’s size, which was currently retrieved only when a valid scene was present. This approach lacked scalability and efficiency, as it constrained size retrieval to scene availability.</p> +<p>To overcome these challenges, we devised a solution involving the creation of a bounding box around the <code class="docutils literal notranslate"><span class="pre">TextBlock2D</span></code>. This bounding box would encapsulate the size information, enabling proper text alignment. This endeavor spanned several weeks of development, culminating in a finalized solution that underwent rigorous testing before being merged.</p> +<p>As a result of this refactoring effort, the <code class="docutils literal notranslate"><span class="pre">TextBlock2D</span></code> now offers three distinct modes:</p> +<ol class="arabic simple"> +<li><p><strong>Fully Static Background:</strong> This mode requires background setup during initialization.</p></li> +<li><p><strong>Dynamic Background:</strong> The background dynamically scales based on the text content.</p></li> +<li><p><strong>Auto Font Scale Mode:</strong> The font within the background box automatically scales to fill the available space.</p></li> +</ol> +<p>An issue has been identified with <code class="docutils literal notranslate"><span class="pre">TextBlock2D</span></code> where its text actor aligns with the top boundary of the background actor, especially noticeable with letters like “g,” “y,” and “j”. These letters extend beyond the baseline of standard alphabets, causing the text box to shift upwards.</p> +<p>However, resolving this matter is complex. Adjusting the text’s position might lead to it touching the bottom boundary, especially in font scale mode, resulting in unexpected positioning and transformations. To address this, the plan is to defer discussions about this matter until after GSoC, allowing for thorough consideration and solutions.</p> +<p>For more detailed insights into the individual steps and nuances of this process, you can refer to the comprehensive weekly blog post provided below. It delves into the entire journey of this <code class="docutils literal notranslate"><span class="pre">TextBlock2D</span></code> refactoring effort.</p> +<p><strong>Pull Requests:</strong></p> +</dd> +</dl> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 79)</p> +<p>Definition list ends without a blank line; unexpected unindent.</p> +</aside> +<ul> +<li><p><strong>Fixing Justification Issue - 1st Draft (Closed)</strong> - <a class="github reference external" href="https://github.com/fury-gl/fury/pull/790">fury-gl/fury#790</a></p></li> +<li><p><strong>Adding BoundingBox and fixing Justificaiton (Merged)</strong> - <a class="github reference external" href="https://github.com/fury-gl/fury/pull/803">fury-gl/fury#803</a></p></li> +<li><p><strong>Adding getters and setter for properties (Merged)</strong> - <a class="github reference external" href="https://github.com/fury-gl/fury/pull/830">fury-gl/fury#830</a></p></li> +<li><p><strong>Text Offset PR (Closed)</strong> - <a class="github reference external" href="https://github.com/fury-gl/fury/pull/837">fury-gl/fury#837</a></p> +<img alt="TextBlock2D Feature Demo" class="align-center" src="https://user-images.githubusercontent.com/64432063/258603191-d540105a-0612-450e-8ae3-ca8aa87916e6.gif" style="height: 500px;" /> +<img alt="TextBlock2D All Justification" class="align-center" src="https://github-production-user-asset-6210df.s3.amazonaws.com/64432063/254652569-94212105-7259-48da-8fdc-41ee987bda84.png" style="height: 500px;" /> +</li> +</ul> +</li> +<li><dl> +<dt><strong>ScrollbarUI as Independent Element:</strong></dt><dd><p>We initially planned to make the scrollbar independent based on PR <a class="reference external" href="https://github.com/fury-gl/fury/pull/16">#16</a>. The main goal was to avoid redundancy by not rewriting the scrollbar code for each element that requires it, such as the <code class="docutils literal notranslate"><span class="pre">FileMenu2D</span></code>. However, upon further analysis, we realized that elements like the <code class="docutils literal notranslate"><span class="pre">FileMenu2D</span></code> and others utilize the <code class="docutils literal notranslate"><span class="pre">Listbox2D</span></code>, which already includes an integrated scrollbar. We also examined other UI libraries and found that they also have independent scrollbars but lack a proper use case. Typically, display containers like <code class="docutils literal notranslate"><span class="pre">Listbox2D</span></code> are directly used instead of utilizing an independent scrollbar.</p> +<p>Based on these findings, we have decided to close all related issues and pull requests for now. If the need arises in the future, we can revisit this topic.</p> +<p><strong>Topic:</strong> - <a class="github reference external" href="https://github.com/fury-gl/fury/discussions/816">fury-gl/fury#816</a></p> +</dd> +</dl> +</li> +</ul> +</section> +<section id="other-objectives"> +<h2>Other Objectives</h2> +<ul> +<li><dl> +<dt><strong>Reviewing &amp; Merging:</strong></dt><dd><p>In this phase, my focus was not on specific coding but rather on facilitating the completion of ongoing PRs. Here are two instances where I played a role:</p> +<ol class="arabic simple"> +<li><p><strong>CardUI PR:</strong> +I assisted with the <code class="docutils literal notranslate"><span class="pre">CardUI</span></code> PR by aiding in the rebase process and reviewing the changes. The CardUI is a simple UI element consisting of an image and a description, designed to function like a flash card. I worked closely with my mentor to ensure a smooth rebase and review process.</p></li> +<li><p><strong>ComboBox Issue:</strong> +There was an issue with the <code class="docutils literal notranslate"><span class="pre">ComboBox2D</span></code> functionality, where adding it to a <code class="docutils literal notranslate"><span class="pre">TabUI</span></code> caused all elements to open simultaneously, which shouldn’t be the case. I tested various PRs addressing this problem and identified a suitable solution. I then helped the lead in reviewing the PR that fixed the issue, which was successfully merged.</p></li> +</ol> +<p><strong>Pull Requests:</strong></p> +</dd> +</dl> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 116)</p> +<p>Definition list ends without a blank line; unexpected unindent.</p> +</aside> +<ul> +<li><p><strong>CardUI (Merged)</strong> - <a class="github reference external" href="https://github.com/fury-gl/fury/pull/398">fury-gl/fury#398</a></p></li> +<li><p><strong>ComboBox Flaw (Merged)</strong> - <a class="github reference external" href="https://github.com/fury-gl/fury/pull/768">fury-gl/fury#768</a></p> +<img alt="CardUI" class="align-center" src="https://user-images.githubusercontent.com/54466356/112532305-b090ef80-8dce-11eb-90a0-8d06eed55993.png" style="height: 500px;" /> +</li> +</ul> +</li> +<li><dl> +<dt><strong>Updating Broken Website Links:</strong></dt><dd><p>I addressed an issue with malfunctioning links in the Scientific Section of the website. The problem emerged from alterations introduced in PR <a class="reference external" href="https://github.com/fury-gl/fury/pull/769">#769</a>. These changes consolidated demos and examples into a unified “auto_examples” folder, and a toml file was utilized to retrieve this data and construct examples. However, this led to challenges with the paths employed in website generation. My responsibility was to rectify these links, ensuring they accurately direct users to the intended content.</p> +<p><strong>Pull Requests:</strong></p> +</dd> +</dl> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 130)</p> +<p>Definition list ends without a blank line; unexpected unindent.</p> +</aside> +<ul class="simple"> +<li><p><strong>Updating Broken Links (Merged)</strong> - <a class="github reference external" href="https://github.com/fury-gl/fury/pull/820">fury-gl/fury#820</a></p></li> +</ul> +</li> +</ul> +</section> +<section id="objectives-in-progress"> +<h2>Objectives in Progress</h2> +<ul> +<li><dl> +<dt><strong>FileDialogUI:</strong></dt><dd><p>An existing <code class="docutils literal notranslate"><span class="pre">FileDialog</span></code> PR by Soham (<a class="reference external" href="https://github.com/fury-gl/fury/pull/294">#294</a>) was worked upon. The primary task was to rebase the PR to match the current UI structure, resolving compatibility concerns with the older base. In PR <a class="reference external" href="https://github.com/fury-gl/fury/pull/832">#832</a>, we detailed issues encompassing resizing <code class="docutils literal notranslate"><span class="pre">FileDialog</span></code> and components, addressing text overflow, fixing <code class="docutils literal notranslate"><span class="pre">ZeroDivisionError</span></code>, and correcting <code class="docutils literal notranslate"><span class="pre">ListBox2D</span></code> item positioning. The PR is complete with comprehensive testing and documentation. Presently, it’s undergoing review, and upon approval, it will be prepared for integration.</p> +<p><strong>Pull Requests:</strong></p> +</dd> +</dl> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 140)</p> +<p>Definition list ends without a blank line; unexpected unindent.</p> +</aside> +<ul> +<li><p><strong>Soham’s FileDialog (Closed)</strong> - <a class="github reference external" href="https://github.com/fury-gl/fury/pull/294">fury-gl/fury#294</a></p></li> +<li><p><strong>FileDialogUI (Under Review)</strong> - <a class="github reference external" href="https://github.com/fury-gl/fury/pull/832">fury-gl/fury#832</a></p> +<img alt="FileDialogUI" class="align-center" src="https://user-images.githubusercontent.com/64432063/263189092-6b0891d5-f0ef-4185-8b17-c7104f1a7d60.gif" style="height: 500px;" /> +</li> +</ul> +</li> +<li><dl> +<dt><strong>TreeUI:</strong></dt><dd><p>Continuing Antriksh’s initial PR for <code class="docutils literal notranslate"><span class="pre">TreeUI</span></code> posed some challenges. Antriksh had set the foundation, and I picked up from there. The main issue was with the visibility of TreeUI due to updates in the <code class="docutils literal notranslate"><span class="pre">set_visibility</span></code> method of <code class="docutils literal notranslate"><span class="pre">Panel2D</span></code>. These updates affected how <code class="docutils literal notranslate"><span class="pre">TreeUI</span></code> was displayed, and after investigating the actors involved, it was clear that the visibility features had changed. This took some time to figure out, and I had a helpful pair programming session with my mentor, Serge, to narrow down the problem. Now, I’ve updated the code to address this issue. However, I’m still a bit cautious about potential future problems. The PR is now ready for review.</p> +<p><strong>Pull Requests:</strong></p> +</dd> +</dl> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 154)</p> +<p>Definition list ends without a blank line; unexpected unindent.</p> +</aside> +<ul> +<li><p><strong>TreeUI (In Progress)</strong> - <a class="github reference external" href="https://github.com/fury-gl/fury/pull/821">fury-gl/fury#821</a></p> +<img alt="TreeUI" class="align-center" src="https://user-images.githubusercontent.com/64432063/263237308-70e77ba0-1ce8-449e-a79c-d5e0fbb58b45.gif" style="height: 500px;" /> +</li> +</ul> +</li> +</ul> +</section> +<section id="gsoc-weekly-blogs"> +<h2>GSoC Weekly Blogs</h2> +<ul class="simple"> +<li><p>My blog posts can be found at <a class="reference external" href="https://fury.gl/latest/blog/author/praneeth-shetty.html">FURY website</a> +and <a class="reference external" href="https://blogs.python-gsoc.org/en/ganimtron_10s-blog-copy-2/">Python GSoC blog</a>.</p></li> +</ul> +</section> +<section id="timeline"> +<h2>Timeline</h2> +<table class="table"> +<colgroup> +<col style="width: 40.0%" /> +<col style="width: 40.0%" /> +<col style="width: 20.0%" /> +</colgroup> +<thead> +<tr class="row-odd"><th class="head"><p>Date</p></th> +<th class="head"><p>Description</p></th> +<th class="head"><p>Blog Post Link</p></th> +</tr> +</thead> +<tbody> +<tr class="row-even"><td><p>Week 0 (27-05-2023)</p></td> +<td><p>Community Bounding Period</p></td> +<td><p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-06-02-week-0-praneeth.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/ganimtron_10s-blog-copy-2/gsoc-2023-community-bonding-period/">Python</a></p></td> +</tr> +<tr class="row-odd"><td><p>Week 1 (03-06-2023)</p></td> +<td><p>Working with SpinBox and TextBox Enhancements</p></td> +<td><aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id5">backlink</a></em></p> +<p>Duplicate explicit target name: “fury”.</p> +</aside> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id6">backlink</a></em></p> +<p>Duplicate explicit target name: “python”.</p> +</aside> +<p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-06-03-week-1-praneeth.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/ganimtron_10s-blog-copy-2/week-1-working-with-spinbox-and-textbox-enhancements/">Python</a></p> +</td> +</tr> +<tr class="row-even"><td><p>Week 2 (10-06-2023)</p></td> +<td><p>Tackling Text Justification and Icon Flaw Issues</p></td> +<td><aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id7">backlink</a></em></p> +<p>Duplicate explicit target name: “fury”.</p> +</aside> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id8">backlink</a></em></p> +<p>Duplicate explicit target name: “python”.</p> +</aside> +<p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-06-11-week-2-praneeth.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/ganimtron_10s-blog-copy-2/week-2-tackling-text-justification-and-icon-flaw-issues/">Python</a></p> +</td> +</tr> +<tr class="row-odd"><td><p>Week 3 (17-06-2023)</p></td> +<td><p>Resolving Combobox Icon Flaw and TextBox Justification</p></td> +<td><aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id9">backlink</a></em></p> +<p>Duplicate explicit target name: “fury”.</p> +</aside> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id10">backlink</a></em></p> +<p>Duplicate explicit target name: “python”.</p> +</aside> +<p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-06-17-week-3-praneeth.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/ganimtron_10s-blog-copy-2/week-3-resolving-combobox-icon-flaw-and-textbox-justification/">Python</a></p> +</td> +</tr> +<tr class="row-even"><td><p>Week 4 (24-06-2023)</p></td> +<td><p>Exam Preparations and Reviewing</p></td> +<td><aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id11">backlink</a></em></p> +<p>Duplicate explicit target name: “fury”.</p> +</aside> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id12">backlink</a></em></p> +<p>Duplicate explicit target name: “python”.</p> +</aside> +<p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-06-24-week-4-praneeth.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/ganimtron_10s-blog-copy-2/week-4-exam-preparations-and-reviewing/">Python</a></p> +</td> +</tr> +<tr class="row-odd"><td><p>Week 5 (01-07-2023)</p></td> +<td><p>Trying out PRs and Planning Ahead</p></td> +<td><aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id13">backlink</a></em></p> +<p>Duplicate explicit target name: “fury”.</p> +</aside> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id14">backlink</a></em></p> +<p>Duplicate explicit target name: “python”.</p> +</aside> +<p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-07-01-week-5-praneeth.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/ganimtron_10s-blog-copy-2/week-5-testing-out-prs-and-planning-ahead/">Python</a></p> +</td> +</tr> +<tr class="row-even"><td><p>Week 6 (08-07-2023)</p></td> +<td><p>BoundingBox for TextBlock2D!</p></td> +<td><aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id15">backlink</a></em></p> +<p>Duplicate explicit target name: “fury”.</p> +</aside> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id16">backlink</a></em></p> +<p>Duplicate explicit target name: “python”.</p> +</aside> +<p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-07-08-week-6-praneeth.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/ganimtron_10s-blog-copy-2/week-6-boundingbox-for-textblock2d/">Python</a></p> +</td> +</tr> +<tr class="row-odd"><td><p>Week 7 (15-07-2023)</p></td> +<td><p>Sowing the seeds for TreeUI</p></td> +<td><aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id17">backlink</a></em></p> +<p>Duplicate explicit target name: “fury”.</p> +</aside> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id18">backlink</a></em></p> +<p>Duplicate explicit target name: “python”.</p> +</aside> +<p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-07-15-week-7-praneeth.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/ganimtron_10s-blog-copy-2/week-7-sowing-the-seeds-for-treeui/">Python</a></p> +</td> +</tr> +<tr class="row-even"><td><p>Week 8 (22-07-2023)</p></td> +<td><p>Another week with TextBlockUI</p></td> +<td><aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id19">backlink</a></em></p> +<p>Duplicate explicit target name: “fury”.</p> +</aside> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id20">backlink</a></em></p> +<p>Duplicate explicit target name: “python”.</p> +</aside> +<p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-07-22-week-8-praneeth.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/ganimtron_10s-blog-copy-2/week-8-another-week-with-textblockui/">Python</a></p> +</td> +</tr> +<tr class="row-odd"><td><p>Week 9 (29-07-2023)</p></td> +<td><p>TextBlock2D is Finally Merged!</p></td> +<td><aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id21">backlink</a></em></p> +<p>Duplicate explicit target name: “fury”.</p> +</aside> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id22">backlink</a></em></p> +<p>Duplicate explicit target name: “python”.</p> +</aside> +<p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-07-29-week-9-praneeth.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/ganimtron_10s-blog-copy-2/week-9-textblock2d-is-finally-merged/">Python</a></p> +</td> +</tr> +<tr class="row-even"><td><p>Week 10 (05-08-2023)</p></td> +<td><p>Its time for a Spin-Box!</p></td> +<td><aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id23">backlink</a></em></p> +<p>Duplicate explicit target name: “fury”.</p> +</aside> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id24">backlink</a></em></p> +<p>Duplicate explicit target name: “python”.</p> +</aside> +<p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-08-05-week-10-praneeth.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/ganimtron_10s-blog-copy-2/week-10-its-time-for-a-spin-box/">Python</a></p> +</td> +</tr> +<tr class="row-odd"><td><p>Week 11 (12-08-2023)</p></td> +<td><p>Bye Bye SpinBox</p></td> +<td><aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id25">backlink</a></em></p> +<p>Duplicate explicit target name: “fury”.</p> +</aside> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id26">backlink</a></em></p> +<p>Duplicate explicit target name: “python”.</p> +</aside> +<p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-08-12-week-11-praneeth.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/ganimtron_10s-blog-copy-2/week-11-bye-bye-spinbox/">Python</a></p> +</td> +</tr> +<tr class="row-even"><td><p>Week 12 (19-08-2023)</p></td> +<td><p>FileDialog Quest Begins!</p></td> +<td><aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id27">backlink</a></em></p> +<p>Duplicate explicit target name: “fury”.</p> +</aside> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id28">backlink</a></em></p> +<p>Duplicate explicit target name: “python”.</p> +</aside> +<p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-08-19-week-12-praneeth.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/ganimtron_10s-blog-copy-2/week-12-filedialog-quest-begins/">Python</a></p> +</td> +</tr> +</tbody> +</table> +</section> +</section> + + + Name: Praneeth Shetty + + 2023-08-25T00:00:00-04:00 + + + https://fury.gl/posts/2023/2023-08-24-week-12-tvcastillod.html + Week 12 : Experimenting with ODFs implementation + 2023-08-24T00:00:00-04:00 + + Tania Castillo + + <section id="week-12-experimenting-with-odfs-implementation"> + +<section id="what-did-i-do-this-week"> +<h2>What did I do this week?</h2> +<p>There were different issues I needed to address for the ODF implementation. Even though I could not solve any of them completely, I did check each of the issues and made some progress. All the work in progress is being recorded in the following branch <a class="reference external" href="https://github.com/tvcastillod/fury/tree/SH-for-ODF-impl">SH-for-ODF-impl</a>, which when ready will be associated with a well-structured PR.</p> +<p>First, about the scaling, I was suggested to check Generalized Fractional Anisotropy <strong>gfa</strong> metric to adjust the scaling depending on the shape of the ODF glyph, i.e., the less the <strong>gfa</strong> the more sphere-shaped and smaller, so I had to associate a greater scaling for those. However, this did not work very well as I was unable to define an appropriate scale relation that would give an equitable result for each glyph. For this reason, I opted to use peak values which are extracted from the ODFs, setting the scales as 1/peak_value*0.4 and I got a more uniformly sized glyph without the need of setting it manually. That is a temporal solution as I would like to see better why this happens and if possible do the adjustment inside the shader instead of a precalculation.</p> +<p>Second, for the direction, I made a small adjustment to the spherical coordinates which affected the direction of the ODF glyph. As you can see below,</p> +<img alt="https://user-images.githubusercontent.com/31288525/263122770-b9ee19d2-d82b-4d7f-a5bb-1cbbf5907049.png" class="align-center" src="https://user-images.githubusercontent.com/31288525/263122770-b9ee19d2-d82b-4d7f-a5bb-1cbbf5907049.png" style="width: 400px;" /> +<p>All the glyphs are aligned over the y-axis but not over the z-axis, to correct this I precalculated the main direction of each glyph using peaks and passed it to the shader as a <em>vec3</em>, then used <em>vec2vecrotmat</em> to align the main axis vector of the ODF to the required direction vector, the only problem with this is that not all the glyps are equally aligned to the axis, i.e., the first 3 glyphs are aligned with the x-axis but the last one is aligned with the y-axis, so the final rotation gives a different result for that one.</p> +<img alt="https://user-images.githubusercontent.com/31288525/263122752-b2aa696f-62a5-4b09-b8dd-0cb1ec49431c.png" class="align-center" src="https://user-images.githubusercontent.com/31288525/263122752-b2aa696f-62a5-4b09-b8dd-0cb1ec49431c.png" style="width: 400px;" /> +<p>As with the first small adjustment of the coordinates the direction was partially correct, I need to double check the theta, phi and r definitions to see if I can get the right direction without the need of the additional data of direction. Also, there might be a way to get the specific rotation angles associated to each individual glyph from the data associated with the ODFs.</p> +<p>Third, about passing the coefficients data through textures, I understand better now how to pass textures to the shaders but I still have problems understanding how to retrieve the data inside the shader. I used <a class="reference external" href="https://github.com/fury-gl/fury/blob/master/docs/experimental/viz_shader_texture.py">this base implementation</a>, suggested by one of my mentors, to store the data as a <a class="reference external" href="http://www.khronos.org/opengl/wiki/Cubemap_Texture#:~:text=A%20Cubemap%20Texture%20is%20a,the%20value%20to%20be%20accessed.">texture cubemap</a>, “a texture, where each mipmap level consists of six 2D images which must be square. The 6 images represent the faces of a cube”. I had 4x15 coefficients and inside the function, a grid of RGB colors is made so then it can be mapped as a texture. To check if was passing the data correctly, I used the same value, .5, for all the textures, so then I could pick a random texel get a specific color (gray), and pass it as <em>fragOutput0</em> to see if the value was correct. However, it didn’t appear to work correctly as I couldn’t get the expected color. To get the specific color I used <a class="reference external" href="https://registry.khronos.org/OpenGL-Refpages/gl4/html/texture.xhtml">texture(sampler, P)</a> which samples texels from the texture bound to sampler at texture coordinate P. Now, what I still need to figure out is which should be the corresponding texture coordinate. I have tried with random coordinates, as they are supposed to correspond to a point on the cube and since the information I have encoded in the texture is all the same, I assumed that I would get the expected result for any set of values. It might be a problem with the data normalization, or maybe there is something failing on the texture definition, but I need to review it in more detail to see where is the problem.</p> +<p>Lastly, about the colormapping, I created the texture based on a generic colormap from <a class="reference external" href="https://matplotlib.org/stable/tutorials/colors/colormaps.html">matplotlib</a>. I was able to give some color to the glyph but it does not match correctly its shape. Some adjustment must be done regarding the texels, as the colormap is mapped on a cube, but I need it to fit the shape of the glyph correctly.</p> +<img alt="https://user-images.githubusercontent.com/31288525/263122760-7d1fff5e-7787-473c-8053-ea69f3009fb4.png" class="align-center" src="https://user-images.githubusercontent.com/31288525/263122760-7d1fff5e-7787-473c-8053-ea69f3009fb4.png" style="width: 250px;" /> +</section> +<section id="what-is-coming-up-next"> +<h2>What is coming up next?</h2> +<p>I will continue to explore more on how to handle textures so I can solve the issues related to the coefficient data and colormapping. Also, take a deeper look at the SH implementation and check what is the information needed to adjust the main direction of the ODF correctly.</p> +</section> +<section id="did-i-get-stuck-anywhere"> +<h2>Did I get stuck anywhere?</h2> +<p>As I mentioned I had some drawbacks in understanding the use of textures and how to retrieve the data inside the shaders. This is a topic that might take some time to manage properly but if I can master it and understand it better, it is a tool that can be useful later. Additionally, there are details of the SH implementation that I still need to understand and explore better in order to make sure I get exactly the same result as the current <em>odf_slicer</em> implementation.</p> +</section> +</section> + + + There were different issues I needed to address for the ODF implementation. Even though I could not solve any of them completely, I did check each of the issues and made some progress. All the work in progress is being recorded in the following branch SH-for-ODF-impl, which when ready will be associated with a well-structured PR. + + 2023-08-24T00:00:00-04:00 + + + https://fury.gl/posts/2023/2023-08-24-final-report-tvcastillod.html + Google Summer of Code Final Work Product + 2023-08-24T00:00:00-04:00 + + Tania Castillo + + <a class="reference external image-reference" href="https://summerofcode.withgoogle.com/programs/2023/projects/ymwnLwtT"><img alt="https://developers.google.com/open-source/gsoc/resources/downloads/GSoC-logo-horizontal.svg" class="align-center" height="50" src="https://developers.google.com/open-source/gsoc/resources/downloads/GSoC-logo-horizontal.svg" /></a> +<a class="reference external image-reference" href="https://summerofcode.withgoogle.com/programs/2023/organizations/python-software-foundation"><img alt="https://www.python.org/static/community_logos/python-logo.png" src="https://www.python.org/static/community_logos/python-logo.png" style="width: 40%;" /></a> +<a class="reference external image-reference" href="https://fury.gl/latest/index.html"><img alt="https://python-gsoc.org/logos/FURY.png" src="https://python-gsoc.org/logos/FURY.png" style="width: 25%;" /></a> +<section id="google-summer-of-code-final-work-product"> + +<ul class="simple"> +<li><p><strong>Name:</strong> Tania Castillo</p></li> +<li><p><strong>Organisation:</strong> Python Software Foundation</p></li> +<li><p><strong>Sub-Organisation:</strong> FURY</p></li> +<li><p><strong>Project:</strong> <a class="reference external" href="https://github.com/fury-gl/fury/wiki/Google-Summer-of-Code-2023-(GSOC2023)#project-3-sdf-based-uncertainty-representation-for-dmri-glyphs">SDF-based uncertainty representation for dMRI glyphs</a></p></li> +</ul> +<section id="abstract"> +<h2>Abstract</h2> +<p>Diffusion Magnetic Resonance Imaging (dMRI) is a non-invasive imaging technique used by neuroscientists to measure the diffusion of water molecules in biological tissue. The directional information is reconstructed using either a Diffusion Tensor Imaging (DTI) or High Angular Resolution Diffusion Imaging (HARDI) based model, which is graphically represented as tensors and Orientation Distribution Functions (ODF). Traditional rendering engines discretize Tensor and ODF surfaces using triangles or quadrilateral polygons, making their visual quality depending on the number of polygons used to build the 3D mesh, which might compromise real-time display performance. This project proposes a methodological approach to further improve the visualization of DTI tensors and HARDI ODFs glyphs by using well-established techniques in the field of computer graphics, such as geometry amplification, billboarding, signed distance functions (SDFs), and ray marching.</p> +</section> +<section id="proposed-objectives"> +<h2>Proposed Objectives</h2> +<ul class="simple"> +<li><p>Implement a parallelized version of computer-generated billboards using geometry shaders for amplification.</p></li> +<li><p>Model the mathematical functions that express the geometry of ellipsoid glyphs and implement them using Ray Marching techniques.</p></li> +<li><p>Model the mathematical functions that express the geometry of ODF glyphs and implement them using Ray Marching techniques.</p></li> +<li><p>Use SDF properties and techniques to represent the uncertainty of dMRI reconstruction models.</p></li> +</ul> +</section> +<section id="objectives-completed"> +<h2>Objectives Completed</h2> +<section id="ellipsoid-actor-implemented-with-sdf"> +<h3>Ellipsoid actor implemented with SDF</h3> +<p>A first approach for tensor glyph generation has been made, using ray marching and SDF applied to a box. The current implementation (<code class="docutils literal notranslate"><span class="pre">tensor_slicer</span></code>) requires a sphere with a specific number of vertices to be deformed. Based on this model, a sphere with more vertices is needed to get a higher resolution. Because the ray marching technique does not use polygonal meshes, it is possible to define perfectly smooth surfaces and still obtain a fast rendering.</p> +<p>Details of the implementation:</p> +<ul class="simple"> +<li><p><em>Vertex shader pre-calculations</em>: Some minor calculations are done in the vertex shader. One, corresponding to the eigenvalues constraining and min-max normalization, are to avoid incorrect visualizations when the difference between the eigenvalues is too large. And the other is related to the tensor matrix calculation given by the diffusion tensor definition <span class="math notranslate nohighlight">\(T = R^{−1}\Lambda R\)</span>, where <span class="math notranslate nohighlight">\(R\)</span> is a rotation matrix that transforms the standard basis onto the eigenvector basis, and <span class="math notranslate nohighlight">\(\Lambda\)</span> is the diagonal matrix of eigenvalues <a class="footnote-reference brackets" href="#id10" id="id1" role="doc-noteref"><span class="fn-bracket">[</span>4<span class="fn-bracket">]</span></a>.</p></li> +<li><p><em>Ellipsoid SDF definition</em>: The definition of the SDF is done in the fragment shader inside the <code class="docutils literal notranslate"><span class="pre">map</span></code> function, which is used later for the ray marching algorithm and the normals calculation. We define the SDF more simply by transforming a sphere into an ellipsoid, considering that the SDF of a sphere is easily computed and the definition of a tensor gives us a linear transformation of a given geometry. Also, as scaling is not a rigid body transformation, we multiply the final result by a factor to compensate for the difference, which gave us the SDF of the ellipsoid defined as <code class="docutils literal notranslate"><span class="pre">sdSphere(tensorMatrix</span> <span class="pre">*</span> <span class="pre">(position</span> <span class="pre">-</span> <span class="pre">centerMCVSOutput),</span> <span class="pre">scaleVSOutput*0.48)</span> <span class="pre">*</span> <span class="pre">scFactor</span></code>.</p></li> +<li><p><em>Ray marching algorithm and lighting</em>: For the ray marching algorithm, a small value of 20 was taken as the maximum distance since we apply the technique to each individual object and not all at the same time. Additionally, we set the convergence precision to 0.001. We use the central differences method to compute the normals necessary for the scene’s illumination, besides the Blinn-Phong lighting technique, which is high-quality and computationally cheap.</p></li> +<li><p><em>Visualization example</em>: Below is a detailed visualization of the ellipsoids created from this new implementation.</p></li> +</ul> +<img alt="https://user-images.githubusercontent.com/31288525/244503195-a626718f-4a13-4275-a2b7-6773823e553c.png" class="align-center" src="https://user-images.githubusercontent.com/31288525/244503195-a626718f-4a13-4275-a2b7-6773823e553c.png" style="width: 376px;" /> +<p>This implementation does show a better quality in the displayed glyphs, and supports the display of a large amount of data, as seen in the image below. For this reason, a tutorial was made to justify in more detail the value of this new implementation. Below are some images generated for the tutorial.</p> +<img alt="https://user-images.githubusercontent.com/31288525/260906510-d422e7b4-3ba3-4de6-bfd0-09c04bec8876.png" class="align-center" src="https://user-images.githubusercontent.com/31288525/260906510-d422e7b4-3ba3-4de6-bfd0-09c04bec8876.png" style="width: 600px;" /> +<p><em>Pull Requests:</em></p> +<ul class="simple"> +<li><p><strong>Ellipsoid actor implemented with SDF (Merged)</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/791">fury-gl/fury#791</a></p></li> +<li><p><strong>Tutorial on using ellipsoid actor to visualize tensor ellipsoids for DTI (Merged)</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/818">fury-gl/fury#818</a></p></li> +</ul> +<p><strong>Future work:</strong> In line with one of the initial objectives, it is expected to implement billboards later on to improve the performance, i.e., higher frame rate and less memory usage for the tensor ellipsoid creation. In addition to looking for ways to optimize the naive ray marching algorithm and the definition of SDFs.</p> +</section> +</section> +<section id="objectives-in-progress"> +<h2>Objectives in Progress</h2> +<section id="dti-uncertainty-visualization"> +<h3>DTI uncertainty visualization</h3> +<p>The DTI visualization pipeline is fairly complex, as a level of uncertainty arises, which, if visualized, helps to assess the model’s accuracy. This measure is not currently implemented, and even though there are several methods to calculate and visualize the uncertainty in the DTI model, because of its simplicity and visual representation, we considered Matrix Perturbation Analysis (MPA) proposed by Basser <a class="footnote-reference brackets" href="#id7" id="id2" role="doc-noteref"><span class="fn-bracket">[</span>1<span class="fn-bracket">]</span></a>. This measurement is visualized as double cones representing the variance of the main direction of diffusion, for which the ray marching technique was also used to create these objects.</p> +<p>Details of the implementation:</p> +<ul class="simple"> +<li><p><em>Source of uncertainty</em>: The method of MPA arises from the susceptibility of DTI to dMRI noise present in diffusion-weighted images (DWIs), and also because the model is inherently statistical, making the tensor estimation and other derived quantities to be random variables <a class="footnote-reference brackets" href="#id7" id="id3" role="doc-noteref"><span class="fn-bracket">[</span>1<span class="fn-bracket">]</span></a>. For this reason, this method focus on the premise that image noise produces a random perturbation in the diffusion tensor estimation, and therefore in the calculation of eigenvalues and eigenvectors, particularly in the first eigenvector associated with the main diffusion direction.</p></li> +<li><p><em>Mathematical equation</em>: The description of the perturbation of the principal eigenvector is given by math formula where <span class="math notranslate nohighlight">\(\Delta D\)</span> corresponds to the estimated perturbation matrix of <span class="math notranslate nohighlight">\(D\)</span> given by the diagonal elements of the covariance matrix <span class="math notranslate nohighlight">\(\Sigma_{\alpha} \approx (B^T\Sigma^{−1}_{e}B)^{−1}\)</span>, where <span class="math notranslate nohighlight">\(\Sigma_{e}\)</span> is the covariance matrix of the error e, defined as a diagonal matrix made with the diagonal elements of <span class="math notranslate nohighlight">\((\Sigma^{−1}_{e}) = ⟨S(b)⟩^2 / \sigma^{2}_{\eta}\)</span>. Then, to get the angle <span class="math notranslate nohighlight">\(\theta\)</span> between the perturbed principal eigenvector of <span class="math notranslate nohighlight">\(D\)</span>, <span class="math notranslate nohighlight">\(\varepsilon_1 + \Delta\varepsilon_1\)</span>, and the estimated eigenvector <span class="math notranslate nohighlight">\(\varepsilon_1\)</span>, it can be approximated by <span class="math notranslate nohighlight">\(\theta = \tan^{−1}( \| \Delta\varepsilon_1 \|)\)</span> <a class="footnote-reference brackets" href="#id8" id="id4" role="doc-noteref"><span class="fn-bracket">[</span>2<span class="fn-bracket">]</span></a>. Taking into account the above, we define the function <code class="docutils literal notranslate"><span class="pre">main_dir_uncertainty(evals,</span> <span class="pre">evecs,</span> <span class="pre">signal,</span> <span class="pre">sigma,</span> <span class="pre">b_matrix)</span></code> that calculates the uncertainty of the eigenvector associated to the main direction of diffusion.</p></li> +<li><p><em>Double cone SDF definition</em>: The final SDF is composed by the union of 2 separately cones using the definition taken from this list of <a class="reference external" href="https://iquilezles.org/articles/distfunctions/#:~:text=Cone%20%2D%20exact,sign(s)%3B%0A%7D">distance functions</a>, in this way we have the SDF for the double cone defined as <code class="docutils literal notranslate"><span class="pre">opUnion(sdCone(p,a,h),</span> <span class="pre">sdCone(-p,a,h))</span> <span class="pre">*</span> <span class="pre">scaleVSOutput</span></code></p></li> +<li><p><em>Visualization example</em>: Below is a demo of how this new feature is intended to be used, an image of diffusion tensor ellipsoids and their associated uncertainty cones.</p></li> +</ul> +<img alt="https://user-images.githubusercontent.com/31288525/254747296-09a8674e-bfc0-4b3f-820f-8a1b1ad8c5c9.png" class="align-center" src="https://user-images.githubusercontent.com/31288525/254747296-09a8674e-bfc0-4b3f-820f-8a1b1ad8c5c9.png" style="width: 610px;" /> +<p>The implementation is almost complete, but as it is a new addition that includes mathematical calculations and for which there is no direct reference for comparison, it requires a more detail review before it can be incorporated.</p> +<p><em>Pull Request:</em></p> +<ul class="simple"> +<li><p><strong>DTI uncertainty visualization (Under Review)</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/810">fury-gl/fury#810</a></p></li> +</ul> +<p><strong>Future work:</strong> A tutorial will be made explaining in more detail how to calculate the parameters needed for the uncertainty cones using <strong>dipy</strong> functions, specifically: <a class="reference external" href="https://github.com/dipy/dipy/blob/321e06722ef42b5add3a7f570f6422845177eafa/dipy/denoise/noise_estimate.py#L272">estimate_sigma</a> for the noise variance calculation, <a class="reference external" href="https://github.com/dipy/dipy/blob/321e06722ef42b5add3a7f570f6422845177eafa/dipy/reconst/dti.py#L2112">design_matrix</a> to get the b-matrix, and <a class="reference external" href="https://github.com/dipy/dipy/blob/321e06722ef42b5add3a7f570f6422845177eafa/dipy/reconst/dti.py#L639">tensor_prediction</a> for the signal estimation. Additionally, when the ODF implementation is complete, uncertainty for this other reconstruction model is expected to be added, using semitransparent glyphs representing the mean directional information proposed by Tournier <a class="footnote-reference brackets" href="#id9" id="id5" role="doc-noteref"><span class="fn-bracket">[</span>3<span class="fn-bracket">]</span></a>.</p> +</section> +<section id="odf-actor-implemented-with-sdf"> +<h3>ODF actor implemented with SDF</h3> +<p>HARDI-based techniques require more images than DTI, however, they model the diffusion directions as probability distribution functions (PDFs), and the fitted values are returned as orientation distribution functions (ODFs). ODFs are more diffusion sensitive than the diffusion tensor and, therefore, can determine the structure of multi-directional voxels very common in the white matter regions of the brain <a class="footnote-reference brackets" href="#id9" id="id6" role="doc-noteref"><span class="fn-bracket">[</span>3<span class="fn-bracket">]</span></a>. The current actor to display this kind of glyphs is the <code class="docutils literal notranslate"><span class="pre">odf_slicer</span></code> which, given an array of spherical harmonics (SH) coefficients renders a grid of ODFs, which are created from a sphere with a specific number of vertices that fit the data.</p> +<p>For the application of this model using the same SDF ray marching techniques, we need the data of the SH coefficients, which are used to calculate the orientation distribution function (ODF) described <a class="reference external" href="https://dipy.org/documentation/1.7.0/theory/sh_basis/">here</a>. Different SH bases can be used, but for this first approach we focus on <code class="docutils literal notranslate"><span class="pre">descoteaux07</span></code> (as labeled in dipy). After performing the necessary calculations, we obtain an approximate result of the current implementation of FURY, as seen below.</p> +<img alt="https://user-images.githubusercontent.com/31288525/260909561-fd90033c-018a-465b-bd16-3586bb31ca36.png" class="align-center" src="https://user-images.githubusercontent.com/31288525/260909561-fd90033c-018a-465b-bd16-3586bb31ca36.png" style="width: 580px;" /> +<p>With a first implementation we start to solve some issues related to direction, color, and data handling, to obtain exactly the same results as the current implementation.</p> +<p>Details on the issues:</p> +<ul class="simple"> +<li><p><em>The direction and the scaling</em>: When the shape of the ODF is more sphere-like, the size of the glyph is smaller, so for the moment it needs to be adjusted manually, but the idea is to find a relationship between the coefficients and the final object size so it can be automatically scaled. Additionally, as seen in the image, the direction does not match. To fix this, an adjustment in the calculation of the spherical coordinates can be made, or pass the direction information directly.</p></li> +<li><p><em>Pass the coefficients data efficiently</em>: I’m currently creating one actor per glyph since I’m using a <em>uniform</em> array to pass the coefficients, but the idea is to pass all the data simultaneously. The first idea is to encode the coefficients data through a texture and retrieve them in the fragment shader.</p></li> +<li><p><em>The colormapping and the lighting</em>: As these objects present curvatures with quite a bit of detail in some cases, this requires more specific lighting work, in addition to having now not only one color but a color map. This can also be done with texture, but it is necessary to see in more detail how to adjust the texture to the glyph’s shape.</p></li> +</ul> +<p>More details on current progress can be seen in blogpost of <a class="reference external" href="https://fury.gl/latest/posts/2023/2023-08-16-week-11-tvcastillod.html">week 11</a> and <a class="reference external" href="https://fury.gl/latest/posts/2023/2023-08-24-week-12-tvcastillod.html">week 12</a>.</p> +<p><em>Working branch:</em></p> +<ul class="simple"> +<li><p><strong>ODF implementation (Under Development)</strong> +<a class="github reference external" href="https://github.com/tvcastillod/fury/tree/SH-for-ODF-impl">tvcastillod/fury</a></p></li> +</ul> +</section> +</section> +<section id="gsoc-weekly-blogs"> +<h2>GSoC Weekly Blogs</h2> +<ul class="simple"> +<li><p>My blog posts can be found on the <a class="reference external" href="https://fury.gl/latest/blog/author/tania-castillo.html">FURY website</a> and the <a class="reference external" href="https://blogs.python-gsoc.org/en/tvcastillods-blog/">Python GSoC blog</a>.</p></li> +</ul> +</section> +<section id="timeline"> +<h2>Timeline</h2> +<table class="table"> +<thead> +<tr class="row-odd"><th class="head"><p>Date</p></th> +<th class="head"><p>Description</p></th> +<th class="head"><p>Blog Post Link</p></th> +</tr> +</thead> +<tbody> +<tr class="row-even"><td><p>Week 0(02-06-2022)</p></td> +<td><p>Community Bounding Period</p></td> +<td><p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-06-02-week-0-tvcastillod.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/tvcastillods-blog/weekly-check-in-0-2">Python</a></p></td> +</tr> +<tr class="row-odd"><td><p>Week 1(05-06-2022)</p></td> +<td><p>Ellipsoid actor implemented with SDF</p></td> +<td><p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-06-05-week-1-tvcastillod.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/tvcastillods-blog/weekly-check-in-1-23">Python</a></p></td> +</tr> +<tr class="row-even"><td><p>Week 2(12-06-2022)</p></td> +<td><p>Making adjustments to the Ellipsoid Actor</p></td> +<td><p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-06-12-week-2-tvcastillod.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/tvcastillods-blog/weekly-check-in-2-18">Python</a></p></td> +</tr> +<tr class="row-odd"><td><p>Week 3(19-06-2022)</p></td> +<td><p>Working on uncertainty and details of the first PR</p></td> +<td><p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-06-19-week-3-tvcastillod.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/tvcastillods-blog/weekly-check-in-3-27">Python</a></p></td> +</tr> +<tr class="row-even"><td><p>Week 4(27-06-2022)</p></td> +<td><p>First draft of the DTI uncertainty visualization</p></td> +<td><p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-06-27-week-4-tvcastillod.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/tvcastillods-blog/weekly-check-in-4-24">Python</a></p></td> +</tr> +<tr class="row-odd"><td><p>Week 5(03-07-2022)</p></td> +<td><p>Preparing the data for the Ellipsoid tutorial</p></td> +<td><p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-07-03-week-5-tvcastillod.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/tvcastillods-blog/weekly-check-in-5-27">Python</a></p></td> +</tr> +<tr class="row-even"><td><p>Week 6(10-07-2022)</p></td> +<td><p>First draft of the Ellipsoid tutorial</p></td> +<td><p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-07-10-week-6-tvcastillod.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/tvcastillods-blog/weekly-check-in-6-26">Python</a></p></td> +</tr> +<tr class="row-odd"><td><p>Week 7(17-07-2022)</p></td> +<td><p>Adjustments on the Uncertainty Cones visualization</p></td> +<td><p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-07-17-week-7-tvcastillod.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/tvcastillods-blog/weekly-check-in-7-26">Python</a></p></td> +</tr> +<tr class="row-even"><td><p>Week 8(25-07-2022)</p></td> +<td><p>Working on Ellipsoid Tutorial and exploring SH</p></td> +<td><p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-07-25-week-8-tvcastillod.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/tvcastillods-blog/weekly-check-in-8-17">Python</a></p></td> +</tr> +<tr class="row-odd"><td><p>Week 9(31-07-2022)</p></td> +<td><p>Tutorial done and polishing DTI uncertainty</p></td> +<td><p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-07-31-week-9-tvcastillod.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/tvcastillods-blog/weekly-check-in-9-22">Python</a></p></td> +</tr> +<tr class="row-even"><td><p>Week 10(08-08-2022)</p></td> +<td><p>Start of SH implementation experiments</p></td> +<td><p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-08-08-week-10-tvcastillod.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/tvcastillods-blog/weekly-check-in-10-16">Python</a></p></td> +</tr> +<tr class="row-odd"><td><p>Week 11(16-08-2022)</p></td> +<td><p>Adjusting ODF implementation and looking for solutions on issues found</p></td> +<td><p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-08-16-week-11-tvcastillod.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/tvcastillods-blog/weekly-check-in-11-17">Python</a></p></td> +</tr> +<tr class="row-even"><td><p>Week 12(24-08-2022)</p></td> +<td><p>Experimenting with ODFs implementation</p></td> +<td><p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-08-24-week-12-tvcastillod.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/tvcastillods-blog/weekly-check-in-12-9">Python</a></p></td> +</tr> +</tbody> +</table> +</section> +<section id="references"> +<h2>References</h2> +<aside class="footnote-list brackets"> +<aside class="footnote brackets" id="id7" role="doc-footnote"> +<span class="label"><span class="fn-bracket">[</span>1<span class="fn-bracket">]</span></span> +<span class="backrefs">(<a role="doc-backlink" href="#id2">1</a>,<a role="doc-backlink" href="#id3">2</a>)</span> +<p>Basser, P. J. (1997). Quantifying errors in fiber direction and diffusion tensor field maps resulting from MR noise. In 5th Scientific Meeting of the ISMRM (Vol. 1740).</p> +</aside> +<aside class="footnote brackets" id="id8" role="doc-footnote"> +<span class="label"><span class="fn-bracket">[</span><a role="doc-backlink" href="#id4">2</a><span class="fn-bracket">]</span></span> +<p>Chang, L. C., Koay, C. G., Pierpaoli, C., &amp; Basser, P. J. (2007). Variance of estimated DTI‐derived parameters via first‐order perturbation methods. Magnetic Resonance in Medicine: An Official Journal of the International Society for Magnetic Resonance in Medicine, 57(1), 141-149.</p> +</aside> +<aside class="footnote brackets" id="id9" role="doc-footnote"> +<span class="label"><span class="fn-bracket">[</span>3<span class="fn-bracket">]</span></span> +<span class="backrefs">(<a role="doc-backlink" href="#id5">1</a>,<a role="doc-backlink" href="#id6">2</a>)</span> +<p>J-Donald Tournier, Fernando Calamante, David G Gadian, and Alan Connelly. Direct estimation of the fiber orientation density function from diffusion-weighted mri data using spherical deconvolution. Neuroimage, 23(3):1176–1185, 2004.</p> +</aside> +<aside class="footnote brackets" id="id10" role="doc-footnote"> +<span class="label"><span class="fn-bracket">[</span><a role="doc-backlink" href="#id1">4</a><span class="fn-bracket">]</span></span> +<p>Gordon Kindlmann. Superquadric tensor glyphs. In Proceedings of the Sixth Joint Eurographics-IEEE TCVG conference on Visualization, pages 147–154, 2004.</p> +</aside> +</aside> +</section> +</section> + + + Name: Tania Castillo + + 2023-08-24T00:00:00-04:00 + + + https://fury.gl/posts/2023/2023-08-21-week-12-joaodellagli.html + Week 12: Now That is (almost) a Wrap! + 2023-08-21T00:00:00-04:00 + + João Victor Dell Agli Floriano + + <section id="week-12-now-that-is-almost-a-wrap"> + +<p>Hello everyone, it’s time for another GSoC blogpost! Today, I am going to talk about some minor details I worked on last week on my +project.</p> +<section id="last-week-s-effort"> +<h2>Last Week’s Effort</h2> +<p>After the API refactoring was done last week, I focused on addressing the reviews I would get from it. The first issues I addressed was related to +style, as there were some minor details my GSoC contributors pointed out that needed change. Also, I have addressed an issue I was having +with the <cite>typed hint</cite> of one of my functions. Filipi, my mentor, showed me there is a way to have more than one typed hint in the same parameter, +all I needed to do was to use the <cite>Union</cite> class from the <cite>typing</cite> module, as shown below:</p> +<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">Union</span> <span class="k">as</span> <span class="n">tUnion</span> +<span class="kn">from</span> <span class="nn">numpy</span> <span class="kn">import</span> <span class="n">ndarray</span> + +<span class="k">def</span> <span class="nf">function</span><span class="p">(</span><span class="n">variable</span> <span class="p">:</span> <span class="n">tUnion</span><span class="p">(</span><span class="nb">float</span><span class="p">,</span> <span class="n">np</span><span class="o">.</span><span class="n">ndarray</span><span class="p">)):</span> + <span class="k">pass</span> +</pre></div> +</div> +<p>Using that, I could set the typedhint of the <cite>bandwidth</cite> variable to <cite>float</cite> and <cite>np.ndarray</cite>.</p> +</section> +<section id="so-how-did-it-go"> +<h2>So how did it go?</h2> +<p>All went fine with no difficult at all, thankfully.</p> +</section> +<section id="the-next-steps"> +<h2>The Next Steps</h2> +<p>My next plans are, after having PR <a class="reference external" href="https://github.com/fury-gl/fury/pull/826">#826</a> merged, to work on the float encoding issue described in +<span class="xref std std-doc">this blogpost</span>. Also, I plan to tackle the UI idea once again, to see if I can finally give the user +a way to control the intensities of the distributions.</p> +<p>Wish me luck!</p> +</section> +</section> + + + Hello everyone, it’s time for another GSoC blogpost! Today, I am going to talk about some minor details I worked on last week on my +project. + + 2023-08-21T00:00:00-04:00 + + + https://fury.gl/posts/2023/2023-08-21-joaodellagli-final-report.html + Google Summer of Code Final Work Product + 2023-08-21T00:00:00-04:00 + + João Victor Dell Agli Floriano + + <a class="reference external image-reference" href="https://summerofcode.withgoogle.com/programs/2023/projects/ED0203De"><img alt="https://developers.google.com/open-source/gsoc/resources/downloads/GSoC-logo-horizontal.svg" height="40" src="https://developers.google.com/open-source/gsoc/resources/downloads/GSoC-logo-horizontal.svg" /></a> +<a class="reference external image-reference" href="https://summerofcode.withgoogle.com/programs/2023/organizations/python-software-foundation"><img alt="https://www.python.org/static/img/python-logo&#64;2x.png" src="https://www.python.org/static/img/python-logo&#64;2x.png" style="height: 40px;" /></a> +<a class="reference external image-reference" href="https://fury.gl/latest/index.html"><img alt="https://python-gsoc.org/logos/fury_logo.png" src="https://python-gsoc.org/logos/fury_logo.png" style="width: 40px;" /></a> +<section id="google-summer-of-code-final-work-product"> + +<ul class="simple"> +<li><p><strong>Name:</strong> João Victor Dell Agli Floriano</p></li> +<li><p><strong>Organisation:</strong> Python Software Foundation</p></li> +<li><p><strong>Sub-Organisation:</strong> FURY</p></li> +<li><p><strong>Project:</strong> <a class="reference external" href="https://github.com/fury-gl/fury/wiki/Google-Summer-of-Code-2023-(GSOC2023)#project-2-fast-3d-kernel-based-density-rendering-using-billboards">FURY - Project 2. Fast 3D kernel-based density rendering using billboards.</a></p></li> +</ul> +<section id="abstract"> +<h2>Abstract</h2> +<p>This project had the goal to implement 3D Kernel Density Estimation rendering to FURY. Kernel Density Estimation, or KDE, is a +statistical method that uses kernel smoothing for modeling and estimating the density distribution of a set of points defined +inside a given region. For its graphical implementation, it was used post-processing techniques such as offscreen rendering to +framebuffers and colormap post-processing as tools to achieve the desired results. This was completed with a functional basic KDE +rendering result, that relies on a solid and easy-to-use API, as well as some additional features.</p> +</section> +<section id="proposed-objectives"> +<h2>Proposed Objectives</h2> +<ul class="simple"> +<li><dl class="simple"> +<dt><strong>First Phase</strong><span class="classifier">Implement framebuffer usage in FURY</span></dt><dd><ul> +<li><p>Investigate the usage of float framebuffers inside FURY’s environment.</p></li> +<li><p>Implement a float framebuffer API.</p></li> +</ul> +</dd> +</dl> +</li> +<li><dl class="simple"> +<dt><strong>Second Phase</strong><span class="classifier">Shader-framebuffer integration</span></dt><dd><ul> +<li><p>Implement a shader that uses a colormap to render framebuffers.</p></li> +<li><p>Escalate this rendering for composing multiple framebuffers.</p></li> +</ul> +</dd> +</dl> +</li> +<li><dl class="simple"> +<dt><strong>Third Phase</strong><span class="classifier">KDE Calculations</span></dt><dd><ul> +<li><p>Investigate KDE calculation for point-cloud datasets.</p></li> +<li><p>Implement KDE calculation inside the framebuffer rendering shaders.</p></li> +<li><p>Test KDE for multiple datasets.</p></li> +</ul> +</dd> +</dl> +</li> +</ul> +</section> +<section id="objectives-completed"> +<h2>Objectives Completed</h2> +<ul> +<li><dl> +<dt><strong>Implement framebuffer usage in FURY</strong></dt><dd><p>The first phase, addressed from <em>May/29</em> to <em>July/07</em>, started with the investigation of +<a class="reference external" href="https://vtk.org/doc/nightly/html/classvtkOpenGLFramebufferObject.html#details">VTK’s Framebuffer Object</a>, a vital part of this project, to understand +how to use it properly.</p> +<p>Framebuffer Objects, abbreviated as FBOs, are the key to post-processing effects in OpenGL, as they are used to render things offscreen and save the resulting image to a texture +that will be later used to apply the desired post-processing effects within the object’s <a class="reference external" href="https://www.khronos.org/opengl/wiki/Fragment_Shader">fragment shader</a> +rendered to screen, in this case, a <a class="reference external" href="http://www.opengl-tutorial.org/intermediate-tutorials/billboards-particles/billboards/">billboard</a>. In the case of the +<a class="reference external" href="https://en.wikipedia.org/wiki/Kernel_density_estimation">Kernel Density Estimation</a> post-processing effect, we need a special kind of FBO, one that stores textures’ +values as floats, different from the standard 8-bit unsigned int storage. This is necessary because the KDE rendering involves rendering every KDE point calculation +to separate billboards, rendered to the same scene, which will have their intensities, divided by the number of points rendered, blended with +<a class="reference external" href="https://www.khronos.org/opengl/wiki/Blending">OpenGL Additive Blending</a>, and if a relative big number of points are rendered at the +same time, 32-bit float precision is needed to guarantee that small-intensity values will not be capped to zero, and disappear.</p> +<p>After a month going through VTK’s FBO documentation and weeks spent trying different approaches to this method, it would not work +properly, as some details seemed to be missing from the documentation, and asking the community haven’t solved the problem as well. +Reporting that to my mentors, which unsuccessfully tried themselves to make it work, they decided it was better if another path was taken, using +<a class="reference external" href="https://vtk.org/doc/nightly/html/classvtkWindowToImageFilter.html">VTK’s WindowToImageFilter</a> method as a workaround, described +in this <a class="reference external" href="https://fury.gl/latest/posts/2023/2023-07-03-week-5-joaodellagli.html">blogpost</a>. This method helped the development of +three new functions to FURY, <em>window_to_texture()</em>, <em>texture_to_actor()</em> and <em>colormap_to_texture()</em>, that allow the passing of +different kinds of textures to FURY’s actor’s shaders, the first one to capture a window and pass it as a texture to an actor, +the second one to pass an external texture to an actor, and the third one to specifically pass a colormap as a texture to an +actor. It is important to say that <em>WindowToImageFilter()</em> is not the ideal way to make it work, as this method does not seem to +support float textures. However, a workaround to that is currently being worked on, as I will describe later on.</p> +<p><em>Pull Requests:</em></p> +<ul class="simple"> +<li><p><strong>KDE Rendering Experimental Program (Needs major revision):</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/804">fury-gl/fury#804</a></p></li> +</ul> +<p>The result of this whole FBO and WindowToImageFilter experimentation is well documented in PR +<a class="reference external" href="https://github.com/fury-gl/fury/pull/804">#804</a> that implements an experimental version of a KDE rendering program. +The future of this PR, as discussed with my mentors, is to be better documented to be used as an example for developers on +how to develop features in FURY with the tools used, and it shall be done soon.</p> +</dd> +</dl> +</li> +<li><dl> +<dt><strong>Shader-framebuffer integration</strong></dt><dd><aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-21-joaodellagli-final-report.rst</span>, line 16); <em><a href="#id2">backlink</a></em></p> +<p>Duplicate explicit target name: “blogpost”.</p> +</aside> +<p>The second phase, which initially was thought of as “Implement a shader that uses a colormap to render framebuffers” and “Escalate this +rendering for composing multiple framebuffers” was actually a pretty simple phase that could be addressed in one week, <em>July/10</em> +to <em>July/17</em>, done at the same time as the third phase goal, documented in this +<a class="reference external" href="https://fury.gl/latest/posts/2023/2023-07-17-week-7-joaodellagli.html">blogpost</a>. As FURY already had a tool for generating and +using colormaps, they were simply connected to the shader part of the program as textures, with the functions explained above. +Below, is the result of the <em>matplotlib viridis</em> colormap passed to a simple gaussian KDE render:</p> +<img alt="Final 2D plot" class="align-center" src="https://raw.githubusercontent.com/JoaoDell/gsoc_assets/main/images/final_2d_plot.png" /> +<aside class="system-message"> +<p class="system-message-title">System Message: INFO/1 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-21-joaodellagli-final-report.rst</span>, line 16); <em><a href="#id3">backlink</a></em></p> +<p>Duplicate explicit target name: “#804”.</p> +</aside> +<p>That is also included in PR <a class="reference external" href="https://github.com/fury-gl/fury/pull/804">#804</a>. Having the 2D plot ready, some time was taken to +figure out how to enable a 3D render, that includes rotation and other movement around the set rendered, which was solved by +learning about the callback properties that exist inside <em>VTK</em>. Callbacks are ways to enable code execution inside the VTK rendering +loop, enclosed inside <em>vtkRenderWindowInteractor.start()</em>. If it is desired to add a piece of code that, for example, passes a time +variable to the fragment shader over time, a callback function can be declared:</p> +<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">fury</span> <span class="kn">import</span> <span class="n">window</span> +<span class="n">t</span> <span class="o">=</span> <span class="mi">0</span> +<span class="n">showm</span> <span class="o">=</span> <span class="n">window</span><span class="o">.</span><span class="n">ShowManager</span><span class="p">(</span><span class="o">...</span><span class="p">)</span> + +<span class="k">def</span> <span class="nf">callback_function</span><span class="p">:</span> + <span class="n">t</span> <span class="o">+=</span> <span class="mf">0.01</span> + <span class="n">pass_shader_uniforms_to_fs</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="s2">&quot;t&quot;</span><span class="p">)</span> + +<span class="n">showm</span><span class="o">.</span><span class="n">add_iren_callback</span><span class="p">(</span><span class="n">callback_function</span><span class="p">,</span> <span class="s2">&quot;RenderEvent&quot;</span><span class="p">)</span> +</pre></div> +</div> +<p>The piece of code above created a function that updates the time variable <em>t</em> in every <em>“RenderEvent”</em>, and passes it to the +fragment shader. With that property, the camera and some other parameters could be updated, which enabled 3D visualization, that +then, outputted the following result, using <em>matplotlib inferno</em> colormap:</p> +<img alt="3D Render gif" class="align-center" src="https://raw.githubusercontent.com/JoaoDell/gsoc_assets/main/images/3d_kde_gif.gif" /> +</dd> +</dl> +</li> +<li><dl> +<dt><strong>KDE Calculations</strong> (ongoing)</dt><dd><p>As said before, the second and third phases were done simultaneously, so after having a way to capture the window and use it as a +texture ready, the colormap ready, and an initial KDE render ready, all it was needed to do was to improve the KDE calculations. +As this <a class="reference external" href="https://en.wikipedia.org/wiki/Kernel_density_estimation">Wikipedia page</a> explains, a KDE calculation is to estimate an +abstract density around a set of points defined inside a given region with a kernel, that is a function that models the density +around a point based on its associated distribution <span class="math notranslate nohighlight">\(\sigma\)</span>.</p> +<p>A well-known kernel is, for example, the <strong>Gaussian Kernel</strong>, that says that the density around a point <span class="math notranslate nohighlight">\(p\)</span> with distribution +<span class="math notranslate nohighlight">\(\sigma\)</span> is defined as:</p> +<div class="math notranslate nohighlight"> +\[GK_{\textbf{p}, \sigma} (\textbf{x}) = e^{-\frac{1}{2}\frac{||\textbf{x} - \textbf{p}||^2}{\sigma^2}}\]</div> +<p>Using that kernel, we can calculate the KDE of a set of points <span class="math notranslate nohighlight">\(P\)</span> with associated distributions <span class="math notranslate nohighlight">\(S\)</span> calculating their individual +Gaussian distributions, summing them up and dividing them by the total number of points <span class="math notranslate nohighlight">\(n\)</span>:</p> +<div class="math notranslate nohighlight"> +\[KDE(A, S)=\frac{1}{n}\sum_{i = 0}^{n}GK(x, p_{i}, \sigma_{i})\]</div> +<p>So I dove into implementing all of that into the offscreen rendering part, and that is when the lack of a float framebuffer would +charge its cost. As it can be seen above, just calculating each point’s density isn’t the whole part, as I also need to divide +everyone by the total number of points <span class="math notranslate nohighlight">\(n\)</span>, and then sum them all. The problem is that, if the number of points its big enough, +the individual densities will be really low, and that would not be a problem for a 32-bit precision float framebuffer, but that is +<em>definitely</em> a problem for a 8-bit integer framebuffer, as small enough values will simply underflow and disappear. That issue is +currently under investigation, and some solutions have already being presented, as I will show in the <strong>Objectives in Progress</strong> +section.</p> +<p>Apart from that, after having the experimental program ready, I focused on modularizing it into a functional and simple API +(without the <span class="math notranslate nohighlight">\(n\)</span> division for now), and I could get a good set of results from that. The API I first developed implemented the +<em>EffectManager</em> class, responsible for managing all of the behind-the-scenes steps necessary for the kde render to work, +encapsulated inside the <em>ÈffectManager.kde()</em> method. It had the following look:</p> +<aside class="system-message"> +<p class="system-message-title">System Message: ERROR/3 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-21-joaodellagli-final-report.rst</span>, line 162)</p> +<p>Error in “code-block” directive: +maximum 1 argument(s) allowed, 9 supplied.</p> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="o">..</span> <span class="n">code</span><span class="o">-</span><span class="n">block</span><span class="p">::</span> <span class="n">python</span> + <span class="kn">from</span> <span class="nn">fury.effect_manager</span> <span class="kn">import</span> <span class="n">EffectManager</span> + <span class="kn">from</span> <span class="nn">fury</span> <span class="kn">import</span> <span class="n">window</span> + + <span class="n">showm</span> <span class="o">=</span> <span class="n">window</span><span class="o">.</span><span class="n">ShowManager</span><span class="p">(</span><span class="o">...</span><span class="p">)</span> + + <span class="c1"># KDE rendering setup</span> + <span class="n">em</span> <span class="o">=</span> <span class="n">EffectManager</span><span class="p">(</span><span class="n">showm</span><span class="p">)</span> + <span class="n">kde_actor</span> <span class="o">=</span> <span class="n">em</span><span class="o">.</span><span class="n">kde</span><span class="p">(</span><span class="o">...</span><span class="p">)</span> + <span class="c1"># End of KDE rendering setup</span> + + <span class="n">showmn</span><span class="o">.</span><span class="n">scene</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">kde_actor</span><span class="p">)</span> + + <span class="n">showm</span><span class="o">.</span><span class="n">start</span><span class="p">()</span> +</pre></div> +</div> +</aside> +<p>Those straightforward instructions, that hid several lines of code and setup, could manage to output the following result:</p> +<img alt="API 3D KDE plot" class="align-center" src="https://raw.githubusercontent.com/JoaoDell/gsoc_assets/main/images/fianl_3d_plot.png" /> +<p>And this was not the only feature I had implemented for this API, as the use of <em>WindowToImageFilter</em> method opened doors for a +whole new world for FURY: The world of post-processing effects. With this features setup, I managed to implement a <em>gaussian blur</em> +effect, a <em>grayscale</em> effect and a <em>Laplacian</em> effect for calculating “borders”:</p> +<img alt="Gaussian Blur effect" class="align-center" src="https://raw.githubusercontent.com/JoaoDell/gsoc_assets/main/images/gaussian_blur.png" /> +<img alt="Grayscale effect" class="align-center" src="https://raw.githubusercontent.com/JoaoDell/gsoc_assets/main/images/grayscale.png" /> +<img alt="Laplacian effect" class="align-center" src="https://raw.githubusercontent.com/JoaoDell/gsoc_assets/main/images/laplacian1.gif" /> +<p>As this wasn’t the initial goal of the project and I still had several issues to deal with, I have decided to leave these features as a +future addition.</p> +<p>Talking with my mentors, we realized that the first KDE API, even though simple, could lead to bad usage from users, as the +<em>em.kde()</em> method, that outputted a <em>FURY actor</em>, had dependencies different from any other object of its kind, making it a new +class of actors, which could lead to confusion and bad handling. After some pair programming sessions, they instructed me to take +a similar, but different road from what I was doing, turning the kde actor into a new class, the <em>KDE</em> class. This class would +have almost the same set of instructions present in the prior method, but it would break them in a way it would only be completely +set up after being passed to the <em>EffectManager</em> via its add function. Below, how the refactoring handles it:</p> +<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">fury.effects</span> <span class="kn">import</span> <span class="n">EffectManager</span><span class="p">,</span> <span class="n">KDE</span> +<span class="kn">from</span> <span class="nn">fury</span> <span class="kn">import</span> <span class="n">window</span> + +<span class="n">showm</span> <span class="o">=</span> <span class="n">window</span><span class="o">.</span><span class="n">ShowManager</span><span class="p">(</span><span class="o">...</span><span class="p">)</span> + +<span class="c1"># KDE rendering setup</span> +<span class="n">em</span> <span class="o">=</span> <span class="n">EffectManager</span><span class="p">(</span><span class="n">showm</span><span class="p">)</span> +<span class="n">kde_effect</span> <span class="o">=</span> <span class="n">KDE</span><span class="p">(</span><span class="o">...</span><span class="p">)</span> +<span class="n">em</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">kde_effect</span><span class="p">)</span> +<span class="c1"># End of KDE rendering setup</span> + +<span class="n">showm</span><span class="o">.</span><span class="n">start</span><span class="p">()</span> +</pre></div> +</div> +<p>Which outputted the same results as shown above. It may have cost some simplicity as we are now one line farther from having it +working, but it is more explicit in telling the user this is not just a normal actor.</p> +<p>Another detail I worked on was the kernel variety. The Gaussian Kernel isn’t the only one available to model density distributions, +there are several others that can do that job, as it can be seen in this <a class="reference external" href="https://scikit-learn.org/stable/modules/density.html">scikit-learn piece of documentation</a> +and this <a class="reference external" href="https://en.wikipedia.org/wiki/Kernel_(statistics)">Wikipedia page on kernels</a>. Based on the scikit-learn KDE +implementation, I worked on implementing the following kernels inside our API, that can be chosen as a parameter when calling the +<em>KDE</em> class:</p> +<ul class="simple"> +<li><p>Cosine</p></li> +<li><p>Epanechnikov</p></li> +<li><p>Exponential</p></li> +<li><p>Gaussian</p></li> +<li><p>Linear</p></li> +<li><p>Tophat</p></li> +</ul> +<p>Below, the comparison between them using the same set of points and bandwidths:</p> +<img alt="Comparison between the six implemented kernels" class="align-center" src="https://raw.githubusercontent.com/JoaoDell/gsoc_assets/main/images/kernels.png" /> +<p><em>Pull Requests</em>:</p> +<ul class="simple"> +<li><p><strong>First Stage of the KDE Rendering API (will be merged soon)</strong>: <a class="github reference external" href="https://github.com/fury-gl/fury/pull/826">fury-gl/fury#826</a></p></li> +</ul> +<p>All of this work culminated in PR <a class="reference external" href="https://github.com/fury-gl/fury/pull/826/">#826</a>, that proposes to add the first stage of +this API (there are some details yet to be completed, like the <span class="math notranslate nohighlight">\(n\)</span> division) to FURY. This PR added the described API, and also +proposed some minor changes to some already existing FURY functions related to callbacks, changes necessary for this and other +future applications that would use it to work. It also added the six kernels described, and a simple documented example on how +to use this feature.</p> +</dd> +</dl> +</li> +</ul> +</section> +<section id="other-objectives"> +<h2>Other Objectives</h2> +<ul class="simple"> +<li><dl class="simple"> +<dt><strong>Stretch Goals</strong><span class="classifier">SDE Implementation, Network/Graph visualization using SDE/KDE, Tutorials</span></dt><dd><ul> +<li><p>Investigate SDE calculation for surface datasets.</p></li> +<li><p>Implement SDE calculation inside the framebuffer rendering shaders.</p></li> +<li><p>Test SDE for multiple datasets.</p></li> +<li><p>Develop comprehensive tutorials that explain SDE concepts and FURY API usage.</p></li> +<li><p>Create practical, scenario-based tutorials using real datasets and/or simulations.</p></li> +</ul> +</dd> +</dl> +</li> +</ul> +</section> +<section id="objectives-in-progress"> +<h2>Objectives in Progress</h2> +<ul> +<li><dl> +<dt><strong>KDE Calculations</strong> (ongoing)</dt><dd><p>The KDE rendering, even though almost complete, have the $n$ division, an important step, missing, as this normalization allows colormaps +to cover the whole range o values rendered. The lack of a float FBO made a big difference in the project, as the search for a functional implementation of it not only delayed the project, but it is vital for +the correct calculations to work.</p> +<p>For the last part, a workaround thought was to try an approach I later figured out is an old one, as it can be check in +<a class="reference external" href="https://developer.nvidia.com/gpugems/gpugems/part-ii-lighting-and-shadows/chapter-12-omnidirectional-shadow-mapping">GPU Gems 12.3.3 section</a>: +If I need 32-bit float precision and I got 4 8-bit integer precision available, why not trying to pack this float into this RGBA +texture? I have first tried to do one myself, but it didn’t work for some reason, so I tried <a class="reference external" href="https://aras-p.info/blog/2009/07/30/encoding-floats-to-rgba-the-final/">Aras Pranckevičius</a> +implementation, that does the following:</p> +<div class="highlight-GLSL notranslate"><div class="highlight"><pre><span></span><span class="kt">vec4</span><span class="w"> </span><span class="n">float_to_rgba</span><span class="p">(</span><span class="kt">float</span><span class="w"> </span><span class="n">value</span><span class="p">)</span><span class="w"> </span><span class="p">{</span> +<span class="w"> </span><span class="kt">vec4</span><span class="w"> </span><span class="n">bitEnc</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="kt">vec4</span><span class="p">(</span><span class="mf">1.</span><span class="p">,</span><span class="mf">256.</span><span class="p">,</span><span class="mf">65536.0</span><span class="p">,</span><span class="mf">16777216.0</span><span class="p">);</span> +<span class="w"> </span><span class="kt">vec4</span><span class="w"> </span><span class="n">enc</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">bitEnc</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">value</span><span class="p">;</span> +<span class="w"> </span><span class="n">enc</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">fract</span><span class="p">(</span><span class="n">enc</span><span class="p">);</span> +<span class="w"> </span><span class="n">enc</span><span class="w"> </span><span class="o">-=</span><span class="w"> </span><span class="n">enc</span><span class="p">.</span><span class="n">yzww</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="kt">vec2</span><span class="p">(</span><span class="mf">1.</span><span class="o">/</span><span class="mf">255.</span><span class="p">,</span><span class="w"> </span><span class="mf">0.</span><span class="p">).</span><span class="n">xxxy</span><span class="p">;</span> +<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="n">enc</span><span class="p">;</span> +<span class="p">}</span> +</pre></div> +</div> +<p>That initially worked, but for some reason I am still trying to understand, it is resulting in a really noisy texture:</p> +<img alt="Noisy KDE render" class="align-center" src="https://raw.githubusercontent.com/JoaoDell/gsoc_assets/main/images/noisy%20kde.png" /> +<p>One way to try to mitigate that while is to pass this by a gaussian blur filter, to try to smooth out the result:</p> +<img alt="Blurred result" class="align-center" src="https://raw.githubusercontent.com/JoaoDell/gsoc_assets/main/images/blurred_kde.png" /> +<p>But it is not an ideal solution as well, as it may lead to distortions in the actual density values, depending on the application of +the KDE. Now, my goal is to first find the root of the noise problem, and then, if that does not work, try to make the gaussian filter +work.</p> +<p>Another detail that would be a good addition to the API is UI controls. Filipi, one of my mentors, told me it would be a good feature +if the user could control the intensities of the bandwidths for a better structural visualization of the render, and knowing FURY already +have a good set of <a class="reference external" href="https://fury.gl/latest/auto_examples/index.html#user-interface-elements">UI elements</a>, I just needed to integrate +that into my program via callbacks. I tried implementing an intensity slider. However, for some reason, it is making the program crash +randomly, for reasons I still don’t know, so that is another issue under investigation. Below, we show a first version of that feature, +which was working before the crashes:</p> +<img alt="Slider for bandwidths" class="align-center" src="https://raw.githubusercontent.com/JoaoDell/gsoc_assets/main/images/slider.gif" /> +<p><em>Pull Requests</em></p> +<ul class="simple"> +<li><p><strong>UI intensity slider for the KDE rendering API (draft)</strong>: <a class="github reference external" href="https://github.com/fury-gl/fury/pull/849">fury-gl/fury#849</a></p></li> +<li><p><strong>Post-processing effects for FURY Effects API (draft)</strong>: <a class="github reference external" href="https://github.com/fury-gl/fury/pull/850">fury-gl/fury#850</a></p></li> +</ul> +</dd> +</dl> +</li> +</ul> +</section> +<section id="gsoc-weekly-blogs"> +<h2>GSoC Weekly Blogs</h2> +<ul class="simple"> +<li><p>My blog posts can be found at <a class="reference external" href="https://fury.gl/latest/blog/author/joao-victor-dell-agli-floriano.html">FURY website</a> and <a class="reference external" href="https://blogs.python-gsoc.org/en/joaodellaglis-blog/">Python GSoC blog</a>.</p></li> +</ul> +</section> +<section id="timeline"> +<h2>Timeline</h2> +<aside class="system-message"> +<p class="system-message-title">System Message: ERROR/3 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-21-joaodellagli-final-report.rst</span>, line 332)</p> +<p>Malformed table.</p> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>+---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Date | Description | Blog Post Link | ++=====================+====================================================+===========================================================================================================================================================================================================+ +| Week 0 (29-05-2023) | The Beginning of Everything | `FURY &lt;https://fury.gl/latest/posts/2023/2023-05-29-week-0-joaodellagli.html&gt;`__ - `Python &lt;https://blogs.python-gsoc.org/en/joaodellaglis-blog/the-beggining-of-everything-week-0/&gt;`__ | ++---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 1 (05-06-2022) | The FBO Saga | `FURY &lt;https://fury.gl/latest/posts/2023/2023-06-05-week-1-joaodellagli.html&gt;`__ - `Python &lt;https://blogs.python-gsoc.org/en/joaodellaglis-blog/the-fbo-saga-week-1/&gt;`__ | ++---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 2 (12-06-2022) | The Importance of (good) Documentation | `FURY &lt;https://fury.gl/latest/posts/2023/2023-06-12-week-2-joaodellagli.html&gt;`__ - `Python &lt;https://blogs.python-gsoc.org/en/joaodellaglis-blog/the-importance-of-good-documentation-week-2/&gt;`__ | ++---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 3 (19-06-2022) | Watch Your Expectations | `FURY &lt;https://fury.gl/latest/posts/2023/2023-06-19-week-3-joaodellagli.html&gt;`__ - `Python &lt;https://blogs.python-gsoc.org/en/joaodellaglis-blog/week-3-watch-your-expectations/&gt;`__ | ++---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 4 (26-06-2022) | Nothing is Ever Lost | `FURY &lt;https://fury.gl/latest/posts/2023/2023-06-26-week-4-joaodellagli.html&gt;`__ - `Python &lt;https://blogs.python-gsoc.org/en/joaodellaglis-blog/week-4-nothing-is-ever-lost/&gt;`__ | ++---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 5 (03-07-2022) | All Roads Lead to Rome | `FURY &lt;https://fury.gl/latest/posts/2023/2023-07-03-week-5-joaodellagli.html&gt;`__ - `Python &lt;https://blogs.python-gsoc.org/en/joaodellaglis-blog/week-5-all-roads-lead-to-rome/&gt;`__ | ++---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 6 (10-07-2022) | Things are Starting to Build Up | `FURY &lt;https://fury.gl/latest/posts/2023/2023-07-10-week-6-joaodellagli.html&gt;`__ - `Python &lt;https://blogs.python-gsoc.org/en/joaodellaglis-blog/week-6-things-are-starting-to-build-up/&gt;`__ | ++---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 7 (17-07-2022) | Experimentation Done | `FURY &lt;https://fury.gl/latest/posts/2023/2023-07-17-week-7-joaodellagli.html&gt;`__ - `Python &lt;https://blogs.python-gsoc.org/en/joaodellaglis-blog/week-7-experimentation-done/&gt;`__ | ++---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 8 (24-07-2022) | The Birth of a Versatile API | `FURY &lt;https://fury.gl/latest/posts/2023/2023-07-24-week-8-joaodellagli.html&gt;`__ - `Python &lt;https://blogs.python-gsoc.org/en/joaodellaglis-blog/week-8-the-birth-of-a-versatile-api/&gt;`__ | ++---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 9 (31-07-2022) | It is Polishing Time! | `FURY &lt;https://fury.gl/latest/posts/2023/2023-07-31-week-9-joaodellagli.html&gt;`__ - `Python &lt;https://blogs.python-gsoc.org/en/joaodellaglis-blog/week-9-it-is-polishing-time/&gt;`__ | ++---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 10 (07-08-2022)| Ready for Review! | `FURY &lt;https://fury.gl/latest/posts/2023/2023-08-07-week-10-joaodellagli.html&gt;`__ - `Python &lt;https://blogs.python-gsoc.org/en/joaodellaglis-blog/ready-for-review/&gt;`__ | ++---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 11 (14-08-2022)| A Refactor is Sometimes Needed | `FURY &lt;https://fury.gl/latest/posts/2023/2023-08-14-week-11-joaodellagli.html&gt;`__ - `Python &lt;https://blogs.python-gsoc.org/en/joaodellaglis-blog/a-refactor-is-sometimes-needed/&gt;`__ | ++---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 12 (21-08-2022)| Now That is (almost) a Wrap! | `FURY &lt;https://fury.gl/latest/posts/2023/2023-08-21-week-12-joaodellagli.html&gt;`__ - `Python &lt;https://blogs.python-gsoc.org/en/joaodellaglis-blog/week-12-now-that-is-almost-a-wrap/&gt;`__ | ++---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +</pre></div> +</div> +</aside> +</section> +</section> + + + Name: João Victor Dell Agli Floriano + + 2023-08-21T00:00:00-04:00 + + + https://fury.gl/posts/2023/2023-08-19-week-12-praneeth.html + Week 12: FileDialog Quest Begins! + 2023-08-19T00:00:00-04:00 + + Praneeth Shetty + + <section id="week-12-filedialog-quest-begins"> + +<section id="what-did-you-do-this-week"> +<h2>What did you do this week?</h2> +<p>During this week, I initiated my work on the <code class="docutils literal notranslate"><span class="pre">FileDialog</span></code> PR, which had been started by Soham. The initial version of the <code class="docutils literal notranslate"><span class="pre">FileDialog</span></code> can be found at <a class="reference external" href="https://github.com/fury-gl/fury/pull/294">#294</a>. To start, I focused on rebasing the PR. Since this PR was based on an older version, there were some updates to the overall UI structure that needed to be addressed for compatibility. While handling this, I identified a set of issues that I documented in the current PR <a class="reference external" href="https://github.com/fury-gl/fury/pull/832">#832</a>. These mainly revolved around:</p> +<ol class="arabic simple"> +<li><p>Resizing <code class="docutils literal notranslate"><span class="pre">FileDialog</span></code> and related components.</p></li> +<li><p>Rectifying the text overflow problem.</p></li> +<li><p>Dealing with a <code class="docutils literal notranslate"><span class="pre">ZeroDivisionError</span></code>.</p></li> +<li><p>Fixing the positioning of items in the <code class="docutils literal notranslate"><span class="pre">ListBox2D</span></code>.</p></li> +</ol> +<p>I systematically approached each of these challenges:</p> +<p><strong>Resizing FileMenu and Related Components:</strong> This was a fairly complex task since it involved intricate dependencies, such as the <code class="docutils literal notranslate"><span class="pre">FileDialog</span></code> relying on the <code class="docutils literal notranslate"><span class="pre">FileMenu</span></code>, which, in turn, was dependent on <code class="docutils literal notranslate"><span class="pre">ListBox2D</span></code> and <code class="docutils literal notranslate"><span class="pre">Panel2D</span></code> resizing. To make the process manageable, I decided to progress incrementally in a separate PR a bit later.</p> +<p><strong>Text Overflow Issue:</strong> The problem with text overflow was rooted in our previous approach, which involved executing these actions only when the <code class="docutils literal notranslate"><span class="pre">TextBlock2D</span></code> had a scene property. Although this approach suited the previous version of <code class="docutils literal notranslate"><span class="pre">TextBlock2D</span></code>, the recent refactoring led to the removal of this property. The scene was previously utilized to determine the text actor’s size. However, we had new methodologies to calculate these sizes, which are detailed in <a class="reference external" href="https://github.com/fury-gl/fury/pull/803">#803</a>.</p> +<img alt="Text Overflow Before" class="align-center" src="https://github.com/fury-gl/fury/assets/64432063/b001f9d3-a5e8-45ad-8605-85df595b5654" /> +<img alt="Text Overflow After" class="align-center" src="https://github.com/fury-gl/fury/assets/64432063/d3c9c3a3-e601-45ab-8975-2b1e98acf1d3" /> +<p><strong>Addressing ZeroDivisionError:</strong> The <code class="docutils literal notranslate"><span class="pre">ZeroDivisionError</span></code> emerged when the total number of values was the same as the number of slots. The issue lay in the separation of these values for calculating the scrollbar’s height parameter. Unfortunately, this calculation error occurred when this would return us zero while updating the scrollbar. To counter this, I implemented a conditional check to ascertain whether the value is zero or not.</p> +<p><strong>Correcting ``ListBox2D`` Item Positioning:</strong> Another challenge I encountered related to the improper positioning of <code class="docutils literal notranslate"><span class="pre">ListBox2D</span></code> item’s background. When a slot was not visible, its background was resized to zero, and visibility was set to off. Consequently, during the calculation of updated positions, the height was considered zero, leading to mispositioning. I resolved this by refraining from resizing and solely toggling visibility, achieving the desired result.</p> +<img alt="ListBox2D mispositioning Before" class="align-center" src="https://github.com/fury-gl/fury/assets/64432063/e2805934-b037-47fd-872c-0b284b298d3c" /> +<img alt="Fixed ListBox2D mispositioning" class="align-center" src="https://github.com/fury-gl/fury/assets/64432063/3bc1aabb-bb79-4e26-817d-a2a2ddd20ea3" /> +</section> +<section id="did-you-get-stuck-anywhere"> +<h2>Did you get stuck anywhere?</h2> +<p>Among the challenges I faced, one notable instance involved addressing the visibility issue in <code class="docutils literal notranslate"><span class="pre">TreeUI</span></code>. Despite my attempts at various solutions, none yielded the desired outcome. The <code class="docutils literal notranslate"><span class="pre">TreeUI</span></code> exhibited either full visibility or no visibility at all. In this situation, I sought guidance from my mentor to find a viable solution.</p> +</section> +<section id="what-is-coming-up-next"> +<h2>What is coming up next?</h2> +<p>The <code class="docutils literal notranslate"><span class="pre">FileDialog</span></code> implementation is nearly finalized, and my plan is to work on any review, feedback or suggestions that might arise. Following this, I will shift my attention towards addressing the <code class="docutils literal notranslate"><span class="pre">TreeUI</span></code>.</p> +</section> +</section> + + + During this week, I initiated my work on the FileDialog PR, which had been started by Soham. The initial version of the FileDialog can be found at #294. To start, I focused on rebasing the PR. Since this PR was based on an older version, there were some updates to the overall UI structure that needed to be addressed for compatibility. While handling this, I identified a set of issues that I documented in the current PR #832. These mainly revolved around: + + 2023-08-19T00:00:00-04:00 + + + https://fury.gl/posts/2023/2023-08-16-week-11-tvcastillod.html + Week 11 : Adjusting ODF implementation and looking for solutions on issues found + 2023-08-16T00:00:00-04:00 + + Tania Castillo + + <section id="week-11-adjusting-odf-implementation-and-looking-for-solutions-on-issues-found"> + +<section id="what-did-i-do-this-week"> +<h2>What did I do this week?</h2> +<p>I continued to experiment with the ODF glyph implementation. Thanks to one of my mentors I figured out how to get the missing data corresponding to the SH coefficients <span class="math notranslate nohighlight">\(a^l_m\)</span> part of the function <span class="math notranslate nohighlight">\(f(\theta, \phi)\)</span> described <a class="reference external" href="https://dipy.org/documentation/1.7.0/theory/sh_basis/">here</a>. I also was told to make sure to implement the correct SH basis since there are different definitions from the literature, I have to focus now in the one proposed by Descoteaux, described in <a class="reference external" href="https://onlinelibrary.wiley.com/doi/10.1002/mrm.21277">this paper</a>, which is labeled in <em>dipy</em> as <em>descoteaux07</em>. To do this I had to make a small adjustment to the base implementation that I took as a reference, from which I obtained a first result using SH of order 4.</p> +<img alt="https://user-images.githubusercontent.com/31288525/260909561-fd90033c-018a-465b-bd16-3586bb31ca36.png" class="align-center" src="https://user-images.githubusercontent.com/31288525/260909561-fd90033c-018a-465b-bd16-3586bb31ca36.png" style="width: 600px;" /> +<p>It appears that the results on the shape are about the same, except for the direction, but there is still work to be done.</p> +</section> +<section id="what-is-coming-up-next"> +<h2>What is coming up next?</h2> +<p>For now, there are 3 things I will continue to work on:</p> +<ul> +<li><p>The color and lighting. As these objects present curvatures with quite a bit of detail in some cases, this is something that requires more specific lighting work, in addition to having now not only one color but a color map.</p></li> +<li><p>The scaling. This is something I still don’t know how to deal with. I had to adjust it manually for now, but the idea is to find a relationship between the coefficients and the final object size so it can be automatically scaled, or maybe there is a proper way to pre-process this data before passing it to the shaders to get the right result at once.</p></li> +<li><aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-16-week-11-tvcastillod.rst</span>, line 2); <em><a href="#id1">backlink</a></em></p> +<p>Duplicate explicit target name: “here”.</p> +</aside> +<p>How to pass the information of the coefficients efficiently. Right now I’m creating one actor per glyph since I’m using a uniform array to pass the coefficients, but the idea is to pass all the data at once. I found several ideas <a class="reference external" href="https://stackoverflow.com/questions/7954927/passing-a-list-of-values-to-fragment-shader">here</a> of how to pass a list of values to the fragment shader directly, I just need to explore deeper how this can be done on <strong>FURY</strong>, and see which option is most suitable.</p> +</li> +</ul> +</section> +<section id="did-i-get-stuck-anywhere"> +<h2>Did I get stuck anywhere?</h2> +<p>All the points mentioned above are things that I tried to fix, however, it is something that I need to look at in much more detail and that I know is going to take me some time to understand and test before I get to the expected result. I hope to get some ideas from my mentors and fellow GSoC contributors on how I can proceed to deal with each of the problems.</p> +</section> +</section> + + + I continued to experiment with the ODF glyph implementation. Thanks to one of my mentors I figured out how to get the missing data corresponding to the SH coefficients a^l_m part of the function f(\theta, \phi) described here. I also was told to make sure to implement the correct SH basis since there are different definitions from the literature, I have to focus now in the one proposed by Descoteaux, described in this paper, which is labeled in dipy as descoteaux07. To do this I had to make a small adjustment to the base implementation that I took as a reference, from which I obtained a first result using SH of order 4. + + 2023-08-16T00:00:00-04:00 + + + https://fury.gl/posts/2023/2023-08-14-week-11-joaodellagli.html + Week 11: A Refactor is Sometimes Needed + 2023-08-14T00:00:00-04:00 + + João Victor Dell Agli Floriano + + <section id="week-11-a-refactor-is-sometimes-needed"> + +<p>Hello everyone, it’s time for another weekly blogpost! Today I am going to share some updates on the API refactoring +I was working on with my mentors.</p> +<section id="last-week-s-effort"> +<h2>Last Week’s Effort</h2> +<p>As I shared with you <span class="xref std std-doc">last week</span>, the first draft of my API was finally ready for review, as +I finished tweaking some remaining details missing. I was tasked with finding a good example of the usage of the tools we proposed, +and I started to do that, however after testing it with some examples, I figured out some significant bugs were to be fixed. Also, +after some reviews and hints from some of my mentors and other GSoC contributors, we realised that some refactoring should be done, +mainly focused on avoiding bad API usage from the user.</p> +</section> +<section id="so-how-did-it-go"> +<h2>So how did it go?</h2> +<p>Initially, I thought only one bug was the source of the issues the rendering presented, but it turned out to be two, which I will +explain further.</p> +<p>The first bug was related to scaling and misalignment of the KDE render. The render of the points being post-processed was not only +with sizes different from the original set size, but it was also misaligned, making it appear in positions different from the points’ +original ones. After some time spent, I figured out the bug was related to the texture coordinates I was using. Before, this is how +my fragment shader looked:</p> +<div class="highlight-C notranslate"><div class="highlight"><pre><span></span><span class="n">vec2</span><span class="w"> </span><span class="n">res_factor</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">vec2</span><span class="p">(</span><span class="n">res</span><span class="p">.</span><span class="n">y</span><span class="o">/</span><span class="n">res</span><span class="p">.</span><span class="n">x</span><span class="p">,</span><span class="w"> </span><span class="mf">1.0</span><span class="p">);</span> +<span class="n">vec2</span><span class="w"> </span><span class="n">tex_coords</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">res_factor</span><span class="o">*</span><span class="n">normalizedVertexMCVSOutput</span><span class="p">.</span><span class="n">xy</span><span class="o">*</span><span class="mf">0.5</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mf">0.5</span><span class="p">;</span> +<span class="kt">float</span><span class="w"> </span><span class="n">intensity</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">texture</span><span class="p">(</span><span class="n">screenTexture</span><span class="p">,</span><span class="w"> </span><span class="n">tex_coords</span><span class="p">).</span><span class="n">r</span><span class="p">;</span> +</pre></div> +</div> +<p>It turns out using this texture coordinates for <em>this case</em> was not the best choice, as even though it matches the fragment positions, +the idea here was to render the offscreen window, which has the same size as the onscreen one, to the billboard actor. With that in mind, +I realised the best choice was using texture coordinates that matched the whole screen positions, coordinates that were derived from the +<code class="docutils literal notranslate"><span class="pre">gl_FragCoord.xy</span></code>, being the division of that by the resolution of the screen, for normalization. Below, the change made:</p> +<div class="highlight-C notranslate"><div class="highlight"><pre><span></span><span class="n">vec2</span><span class="w"> </span><span class="n">tex_coords</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">gl_FragCoord</span><span class="p">.</span><span class="n">xy</span><span class="o">/</span><span class="n">res</span><span class="p">;</span> +<span class="kt">float</span><span class="w"> </span><span class="n">intensity</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">texture</span><span class="p">(</span><span class="n">screenTexture</span><span class="p">,</span><span class="w"> </span><span class="n">tex_coords</span><span class="p">).</span><span class="n">r</span><span class="p">;</span> +</pre></div> +</div> +<p>This change worked initially, although with some problems, that later revealed the resolution of the offscreen window needed to be +updated inside the callback function as well. Fixing that, it was perfectly aligned and scaled!</p> +<p>The second bug was related with the handling of the bandwidth, former sigma parameter. I realised I wasn’t dealing properly with the option of the user passing only +one single bandwidth value being passed, so when trying that, only the first point was being rendered. I also fixed that and it worked, +so cheers!</p> +<p>As I previously said, the bugs were not the only details I spent my time on last week. Being reviewed, the API design, even +though simple, showed itself vulnerable to bad usage from the user side, requiring some changes. The changes suggested by mentors were, +to, basically, take the <code class="docutils literal notranslate"><span class="pre">kde</span></code> method out of the <code class="docutils literal notranslate"><span class="pre">EffectManager</span></code> class, and create a new class from it inside an <code class="docutils literal notranslate"><span class="pre">effects</span></code> module, +like it was a special effects class. With this change, the KDE setup would go from:</p> +<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">em</span> <span class="o">=</span> <span class="n">EffectManager</span><span class="p">(</span><span class="n">show_manager</span><span class="p">)</span> + +<span class="n">kde_actor</span> <span class="o">=</span> <span class="n">em</span><span class="o">.</span><span class="n">kde</span><span class="p">(</span><span class="o">...</span><span class="p">)</span> + +<span class="n">show_manager</span><span class="o">.</span><span class="n">scene</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">kde_actor</span><span class="p">)</span> +</pre></div> +</div> +<p>To:</p> +<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">em</span> <span class="o">=</span> <span class="n">EffectManager</span><span class="p">(</span><span class="n">show_manager</span><span class="p">)</span> + +<span class="n">kde_effect</span> <span class="o">=</span> <span class="n">KDE</span><span class="p">(</span><span class="o">...</span><span class="p">)</span> + +<span class="n">em</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">kde_effect</span><span class="p">)</span> +</pre></div> +</div> +<p>Not a gain in line shortening, however, a gain in security, as preventing users from misusing the kde_actor. Something worth noting is +that I learned how to use the <code class="docutils literal notranslate"><span class="pre">functools.partial</span></code> function, that allowed me to partially call the callback function with only some +parameters passed.</p> +</section> +<section id="this-week-s-goals"> +<h2>This Week’s Goals</h2> +<p>Having that refactoring made, now I am awaiting for a second review so we could finally wrap it up and merge the first stage of this API. +With that being done, I will write the final report and wrap this all up.</p> +<p>Let’s get to work!</p> +</section> +</section> + + + Hello everyone, it’s time for another weekly blogpost! Today I am going to share some updates on the API refactoring +I was working on with my mentors. + + 2023-08-14T00:00:00-04:00 + + + https://fury.gl/posts/2023/2023-08-12-week-11-praneeth.html + Week 11: Bye Bye SpinBox + 2023-08-12T00:00:00-04:00 + + Praneeth Shetty + + <section id="week-11-bye-bye-spinbox"> + +<section id="what-did-you-do-this-week"> +<h2>What did you do this week?</h2> +<p>Building upon the progress of the previous week, a major milestone was reached with the merging of PR <a class="reference external" href="https://github.com/fury-gl/fury/pull/830">#830</a>. This PR added essential “getters” and “setters” for the new features of <code class="docutils literal notranslate"><span class="pre">TextBlock</span></code>, making it easier to handle changes. This, in turn, facilitated the integration of <code class="docutils literal notranslate"><span class="pre">SpinBoxUI</span></code> with the updated <code class="docutils literal notranslate"><span class="pre">TextBlock</span></code>.</p> +<p>However, while working on <code class="docutils literal notranslate"><span class="pre">SpinBoxUI</span></code>, a critical issue emerged. As <code class="docutils literal notranslate"><span class="pre">SpinBoxUI</span></code> allows users to input characters and symbols into an editable textbox, it posed a risk of program crashes due to invalid inputs. To counter this, I introduced a validation check to ensure that the input was a valid number. If valid, the input was converted; otherwise, it reverted to the previous value. After thorough testing and review, PR <a class="reference external" href="https://github.com/fury-gl/fury/pull/499">#499</a> was successfully merged.</p> +<img alt="SpinBoxUI" class="align-center" src="https://user-images.githubusercontent.com/64432063/261409747-511e535b-185c-4e70-aaa8-5296c93e5344.gif" style="width: 500px;" /> +<p>Meanwhile, a concern with the textbox’s behavior was identified when <code class="docutils literal notranslate"><span class="pre">SpinBoxUI</span></code> was scaled to a larger size. Specifically, the text occasionally touched the top or bottom boundary, creating an overflow appearance. Although initial solutions were attempted, the complexity of the issue required further consideration. This issue has been documented in more detail in Issue <a class="reference external" href="https://github.com/fury-gl/fury/pull/838">#838</a>, where it is marked as a low-priority item.</p> +<figure class="align-center"> +<img alt="TextBlock2D text positioning issue" src="https://user-images.githubusercontent.com/64432063/133194003-53e2dac6-31e0-444e-b7f1-a9e71545f560.jpeg" /> +</figure> +</section> +<section id="did-you-get-stuck-anywhere"> +<h2>Did you get stuck anywhere?</h2> +<p>The challenge of the week centered around addressing the textbox’s overflow behavior in <code class="docutils literal notranslate"><span class="pre">SpinBoxUI</span></code>.</p> +</section> +<section id="what-is-coming-up-next"> +<h2>What is coming up next?</h2> +<p>Looking ahead, the focus remains on refining the FileDialog component, as the significant progress with <code class="docutils literal notranslate"><span class="pre">TextBlock</span></code> and <code class="docutils literal notranslate"><span class="pre">SpinBoxUI</span></code> prepares us to shift attention to other aspects of development.</p> +</section> +</section> + + + Building upon the progress of the previous week, a major milestone was reached with the merging of PR #830. This PR added essential “getters” and “setters” for the new features of TextBlock, making it easier to handle changes. This, in turn, facilitated the integration of SpinBoxUI with the updated TextBlock. + + 2023-08-12T00:00:00-04:00 + + + https://fury.gl/posts/2023/2023-08-08-week-10-tvcastillod.html + Week 10 : Start of SH implementation experiments + 2023-08-08T00:00:00-04:00 + + Tania Castillo + + <section id="week-10-start-of-sh-implementation-experiments"> + +<section id="what-did-i-do-this-week"> +<h2>What did I do this week?</h2> +<p>I started formally working on SH implementation. I was told to start first doing a simple program where I can modify in real-time the order <span class="math notranslate nohighlight">\(l\)</span> and degree <span class="math notranslate nohighlight">\(m\)</span>, parameters corresponding to the <a class="reference external" href="https://dipy.org/documentation/1.7.0/theory/sh_basis/">Spherical Harmonics function</a> <span class="math notranslate nohighlight">\(Y^m_l(\theta,\phi)=\)</span>, based on <a class="reference external" href="https://github.com/lenixlobo/fury/commit/2b7ce7a71fd422dc5a250d7b49e1eea2db9d3bce">previous work</a>. That is just one part of the final ODF calculation, but here is what a first experimental script looks like.</p> +<img alt="https://user-images.githubusercontent.com/31288525/260910073-10b0edd4-40e3-495c-85ad-79993aef3b19.png" class="align-center" src="https://user-images.githubusercontent.com/31288525/260910073-10b0edd4-40e3-495c-85ad-79993aef3b19.png" style="width: 600px;" /> +<p>I did it in order to make sure it was visually correct and also to understand better how those 2 parameters are related and need to be incorporated into the final calculation. There is one issue at first sight that needs to be addressed, and that is the scaling, since for SH with a degree near 0, the object gets out of bounds.</p> +</section> +<section id="what-is-coming-up-next"> +<h2>What is coming up next?</h2> +<p>I will keep polishing details from my current open PRs, hopefully, I will get another PR merged before the last GSoC week.</p> +</section> +<section id="did-i-get-stuck-anywhere"> +<h2>Did I get stuck anywhere?</h2> +<p>Not sure about how to use the current implementation I have to get similar visualizations made with <em>odf_slicer</em>, since the parameters that the function receive are different, so I need to take a deeper look and see where it might be the connection or if I should make some adjustments on the parameters.</p> +</section> +</section> + + + I started formally working on SH implementation. I was told to start first doing a simple program where I can modify in real-time the order l and degree m, parameters corresponding to the Spherical Harmonics function Y^m_l(\theta,\phi)=, based on previous work. That is just one part of the final ODF calculation, but here is what a first experimental script looks like. + + 2023-08-08T00:00:00-04:00 + + diff --git a/v0.10.x/blog/author.html b/v0.10.x/blog/author.html new file mode 100644 index 000000000..b22d3eed9 --- /dev/null +++ b/v0.10.x/blog/author.html @@ -0,0 +1,2662 @@ + + + + + + + Authors — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + + +
+

+ Posts by + Antriksh Misri +

+ +
+

+ + 23 August 2021 + + - + Google Summer of Code Final Work Product +

+
+ +
+

+ + 16 August 2021 + + - + Week #11: Finalizing open Pull Requests +

+
+ +
+

+ + 09 August 2021 + + - + Week#10: Accordion UI, Support for sprite sheet animations +

+
+ +
+

+ + 02 August 2021 + + - + Week #9: More Layouts! +

+
+ +
+

+ + 26 July 2021 + + - + Week #8: Code Cleanup, Finishing up open PRs, Continuing work on Tree2D +

+
+ +
+

+ + 19 July 2021 + + - + Week #7: Finalizing the stalling PRs, finishing up Tree2D UI. +

+
+ +
+

+ + 12 July 2021 + + - + Week #6: Bug fixes, Working on Tree2D UI +

+
+ +
+

+ + 05 July 2021 + + - + Week #5: Rebasing all PRs w.r.t the UI restructuring, Tree2D, Bug Fixes +

+
+ +
+

+ + 28 June 2021 + + - + Week #4: Adding Tree UI to the UI module +

+
+ +
+

+ + 21 June 2021 + + - + Week #3: Adapting GridLayout to work with UI +

+
+ +
+

+ + 13 June 2021 + + - + Week #2: Feature additions in UI and IO modules +

+
+ +
+

+ + 08 June 2021 + + - + Week #1: Welcome to my weekly Blogs! +

+
+ +
+ + + +
+

+ Posts by + Bruno Messias +

+ +
+

+ + 23 August 2021 + + - + Google Summer of Code 2021 - Final Report - Bruno Messias +

+
+ +
+

+ + 16 August 2021 + + - + Week #11: Removing the flickering effect +

+
+ +
+

+ + 09 August 2021 + + - + Week #10: SDF Fonts +

+
+ +
+

+ + 02 August 2021 + + - + Week #09: Sphinx custom summary +

+
+ +
+

+ + 26 July 2021 + + - + Weekly Check-In #8 +

+
+ +
+

+ + 19 July 2021 + + - + Weekly Check-In #7 +

+
+ +
+

+ + 12 July 2021 + + - + Network layout algorithms using IPC +

+
+ +
+

+ + 05 July 2021 + + - + Weekly Check-In #5 +

+
+ +
+

+ + 05 July 2021 + + - + SOLID, monkey patching a python issue and network visualization through WebRTC +

+
+ +
+

+ + 21 June 2021 + + - + Weekly Check-In #3 +

+
+ +
+

+ + 13 June 2021 + + - + A Stadia-like system for data visualization +

+
+ +
+

+ + 08 June 2021 + + - + Weekly Check-In #1 +

+
+ +
+ + + +
+

+ Posts by + João Victor Dell Agli Floriano +

+ +
+

+ + 21 August 2023 + + - + Week 12: Now That is (almost) a Wrap! +

+
+ +
+

+ + 21 August 2023 + + - + Google Summer of Code Final Work Product +

+
+ +
+

+ + 14 August 2023 + + - + Week 11: A Refactor is Sometimes Needed +

+
+ +
+

+ + 07 August 2023 + + - + Week 10: Ready for Review! +

+
+ +
+

+ + 31 July 2023 + + - + Week 9: It is Polishing Time! +

+
+ +
+

+ + 24 July 2023 + + - + Week 8: The Birth of a Versatile API +

+
+ +
+

+ + 17 July 2023 + + - + Week 7: Experimentation Done +

+
+ +
+

+ + 10 July 2023 + + - + Week 6: Things are Starting to Build Up +

+
+ +
+

+ + 03 July 2023 + + - + Week 5: All Roads Lead to Rome +

+
+ +
+

+ + 26 June 2023 + + - + Week 4: Nothing is Ever Lost +

+
+ +
+

+ + 19 June 2023 + + - + Week 3: Watch Your Expectations +

+
+ +
+

+ + 12 June 2023 + + - + Week 2: The Importance of (good) Documentation +

+
+ +
+

+ + 05 June 2023 + + - + The FBO Saga - Week 1 +

+
+ +
+

+ + 29 May 2023 + + - + The Beginning of Everything - Week 0 +

+
+ +
+ + + +
+

+ Posts by + Lenix Lobo +

+ +
+

+ + 24 August 2020 + + - + Shader Showcase +

+
+ +
+

+ + 24 August 2020 + + - + Google Summer of Code 2020 Final Work Product +

+
+ +
+

+ + 17 August 2020 + + - + Outline Picker +

+
+ +
+

+ + 09 August 2020 + + - + More Shaders!! +

+
+ +
+

+ + 02 August 2020 + + - + More Shaders!! +

+
+ +
+

+ + 27 July 2020 + + - + Merging SDF primitives. +

+
+ +
+

+ + 20 July 2020 + + - + Improvements in SDF primitives. +

+
+ +
+

+ + 13 July 2020 + + - + Multiple SDF primitives. +

+
+ +
+

+ + 05 July 2020 + + - + Spherical harmonics, Continued. +

+
+ +
+

+ + 28 June 2020 + + - + Spherical harmonics +

+
+ +
+

+ + 21 June 2020 + + - + Raymarching continued +

+
+ +
+

+ + 14 June 2020 + + - + Raymarching!! +

+
+ +
+

+ + 07 June 2020 + + - + First week of coding!! +

+
+ +
+

+ + 30 May 2020 + + - + Weekly Check-in #1 +

+
+ +
+ + + +
+

+ Posts by + Mohamed Abouagour +

+ +
+

+ + 29 January 2023 + + - + Google Summer of Code Final Work Product +

+
+ +
+

+ + 28 September 2022 + + - + Week 14: Keyframes animation is now a bit easier in FURY +

+
+ +
+

+ + 20 September 2022 + + - + Week 13: Keyframes animation is now a bit easier in FURY +

+
+ +
+

+ + 07 September 2022 + + - + Week 12: Adding new tutorials +

+
+ +
+

+ + 30 August 2022 + + - + Week 11: Improving tutorials a little +

+
+ +
+

+ + 23 August 2022 + + - + Week 10: Supporting hierarchical animating +

+
+ +
+

+ + 16 August 2022 + + - + Week 9: Animating primitives of the same actor +

+
+ +
+

+ + 09 August 2022 + + - + Week 8: Back to the shader-based version of the Timeline +

+
+ +
+

+ + 01 August 2022 + + - + Week 7: Billboard spheres and implementing interpolators using closures +

+
+ +
+

+ + 25 July 2022 + + - + Week 6: Fixing the Timeline issues and equipping it with more features +

+
+ +
+

+ + 19 July 2022 + + - + Week 5: Slerp implementation, documenting the Timeline, and adding unit tests +

+
+ +
+

+ + 11 July 2022 + + - + Week 4: Camera animation, interpolation in GLSL, and a single Timeline! +

+
+ +
+

+ + 04 July 2022 + + - + Week 3: Redesigning the API, Implementing cubic Bezier Interpolator, and making progress on the GPU side! +

+
+ +
+

+ + 28 June 2022 + + - + Week 2: Implementing non-linear and color interpolators +

+
+ +
+

+ + 19 June 2022 + + - + Week 1: Implementing a basic Keyframe animation API +

+
+ +
+

+ + 23 May 2022 + + - + My journey till getting accepted into GSoC22 +

+
+ +
+ + + +
+

+ Posts by + Praneeth Shetty +

+ +
+

+ + 25 August 2023 + + - + Google Summer of Code Final Work Product +

+
+ +
+

+ + 19 August 2023 + + - + Week 12: FileDialog Quest Begins! +

+
+ +
+

+ + 12 August 2023 + + - + Week 11: Bye Bye SpinBox +

+
+ +
+

+ + 05 August 2023 + + - + Week 10: Its time for a Spin-Box! +

+
+ +
+

+ + 29 July 2023 + + - + Week 9: TextBlock2D is Finally Merged! +

+
+ +
+

+ + 22 July 2023 + + - + Week 8: Another week with TextBlockUI +

+
+ +
+

+ + 15 July 2023 + + - + Week 7: Sowing the seeds for TreeUI +

+
+ +
+

+ + 08 July 2023 + + - + Week 6: BoundingBox for TextBlock2D! +

+
+ +
+

+ + 01 July 2023 + + - + Week 5: Trying out PRs and Planning Ahead +

+
+ +
+

+ + 24 June 2023 + + - + Week 4: Exam Preparations and Reviewing +

+
+ +
+

+ + 17 June 2023 + + - + Week 3: Resolving Combobox Icon Flaw and TextBox Justification +

+
+ +
+

+ + 11 June 2023 + + - + Week 2: Tackling Text Justification and Icon Flaw Issues +

+
+ +
+

+ + 03 June 2023 + + - + Week 1: Working with SpinBox and TextBox Enhancements +

+
+ +
+

+ + 02 June 2023 + + - + Week 0: Community Bounding Period +

+
+ +
+

+ + 24 January 2023 + + - + Google Summer of Code Final Work Product +

+
+ +
+

+ + 21 September 2022 + + - + Week 16 - Working with Rotations! +

+
+ +
+

+ + 14 September 2022 + + - + Week 15 - Highlighting DrawShapes +

+
+ +
+

+ + 07 September 2022 + + - + Week 14 - Updating DrawPanel architecture +

+
+ +
+

+ + 31 August 2022 + + - + Week 13 - Separating tests and fixing bugs +

+
+ +
+

+ + 24 August 2022 + + - + Week 12 - Fixing translating issues and updating tests +

+
+ +
+

+ + 17 August 2022 + + - + Week 11 - Creating a base for Freehand Drawing +

+
+ +
+

+ + 10 August 2022 + + - + Week 10 - Understanding Codes and Playing with Animation +

+
+ +
+

+ + 03 August 2022 + + - + Week 9 - Grouping and Transforming Shapes +

+
+ +
+

+ + 27 July 2022 + + - + Week 8 - Working on the polyline feature +

+
+ +
+

+ + 20 July 2022 + + - + Week 7 - Working on Rotation PR and Trying Freehand Drawing +

+
+ +
+

+ + 13 July 2022 + + - + Week 6 - Supporting Rotation of the Shapes from the Center +

+
+ +
+

+ + 06 July 2022 + + - + Week 5 - Working on new features +

+
+ +
+

+ + 29 June 2022 + + - + Week 4 - Fixing the Clamping Issue +

+
+ +
+

+ + 22 June 2022 + + - + Week 3 - Dealing with Problems +

+
+ +
+

+ + 15 June 2022 + + - + Week 2 - Improving DrawPanel UI +

+
+ +
+

+ + 08 June 2022 + + - + Week 1 - Laying the Foundation of DrawPanel UI +

+
+ +
+

+ + 25 May 2022 + + - + Pre-GSoC Journey +

+
+ +
+ + + +
+

+ Posts by + Sajag Swami +

+ +
+

+ + 23 August 2021 + + - + Google Summer of Code Final Work Product +

+
+ +
+

+ + 16 August 2021 + + - + Tenth coding week! +

+
+ +
+

+ + 09 August 2021 + + - + Ninth coding week! +

+
+ +
+

+ + 02 August 2021 + + - + Eighth coding week! +

+
+ +
+

+ + 26 July 2021 + + - + Seventh week of coding! +

+
+ +
+

+ + 19 July 2021 + + - + Sixth week of coding! +

+
+ +
+

+ + 12 July 2021 + + - + Fifth week of coding! +

+
+ +
+

+ + 05 July 2021 + + - + Fourth week of coding! +

+
+ +
+

+ + 28 June 2021 + + - + Third week of coding! +

+
+ +
+

+ + 21 June 2021 + + - + Second week of coding! +

+
+ +
+

+ + 14 June 2021 + + - + First week of coding! +

+
+ +
+

+ + 08 June 2021 + + - + Welcome to my GSoC Blog! +

+
+ +
+ + + +
+

+ Posts by + Shivam Anand +

+ +
+

+ + 29 January 2023 + + - + Google Summer of Code Final Work Product +

+
+ +
+

+ + 28 September 2022 + + - + Week 14 - Morphing is here! +

+
+ +
+

+ + 15 September 2022 + + - + Week 13 - Multi-bone skeletal animation support +

+
+ +
+

+ + 08 September 2022 + + - + Week 12 - Adding skeleton as actors and fix global transformation +

+
+ +
+

+ + 31 August 2022 + + - + Week 11 - Multiple transformations support and adding tests +

+
+ +
+

+ + 25 August 2022 + + - + Week 10 - Multi-node skinning support +

+
+ +
+

+ + 17 August 2022 + + - + Week 9 - First working skeletal animation prototype +

+
+ +
+

+ + 10 August 2022 + + - + Week 8 - Fixing animation bugs +

+
+ +
+

+ + 01 August 2022 + + - + Week 7 - Fixing bugs in animations +

+
+ +
+

+ + 25 July 2022 + + - + Week 6 - Extracting the animation data +

+
+ +
+

+ + 19 July 2022 + + - + Week 5 - Creating PR for glTF exporter and fixing the loader +

+
+ +
+

+ + 12 July 2022 + + - + Week 4 - Finalizing glTF loader +

+
+ +
+

+ + 04 July 2022 + + - + Week 3 - Fixing fetcher, adding tests and docs +

+
+ +
+

+ + 29 June 2022 + + - + Week 2 - Improving Fetcher and Exporting glTF +

+
+ +
+

+ + 20 June 2022 + + - + Week 1 - A Basic glTF Importer +

+
+ +
+ + + +
+

+ Posts by + Shivam Sahu +

+ +
+

+ + 24 May 2022 + + - + My Journey to GSoC 2022 +

+
+ +
+ + + +
+

+ Posts by + Soham Biswas +

+ +
+

+ + 24 August 2020 + + - + Google Summer of Code Final Work Product +

+
+ +
+

+ + 23 August 2020 + + - + Part of the Journey is the end unless its Open Source! +

+
+ +
+

+ + 16 August 2020 + + - + Wrecking Ball Simulation, Scrollbars Update, Physics Tutorials. +

+
+ +
+

+ + 09 August 2020 + + - + Chain Simulation, Scrollbar Refactor, Tutorial Update. +

+
+ +
+

+ + 02 August 2020 + + - + Single Actor, Physics, Scrollbars. +

+
+ +
+

+ + 26 July 2020 + + - + Tab UI, TabPanel2D, Tab UI Tutorial. +

+
+ +
+

+ + 19 July 2020 + + - + ComboBox2D, TextBlock2D, Clipping Overflow. +

+
+ +
+

+ + 12 July 2020 + + - + Orientation, Sizing, Tab UI. +

+
+ +
+

+ + 05 July 2020 + + - + Translation, Reposition, Rotation. +

+
+ +
+

+ + 28 June 2020 + + - + May the Force be with you!! +

+
+ +
+

+ + 21 June 2020 + + - + TextBlock2D Progress!! +

+
+ +
+

+ + 14 June 2020 + + - + ComboBox2D Progress!! +

+
+ +
+

+ + 07 June 2020 + + - + First week of coding!! +

+
+ +
+

+ + 30 May 2020 + + - + Welcome to my GSoC Blog!!! +

+
+ +
+ + + +
+

+ Posts by + Tania Castillo +

+ +
+

+ + 24 August 2023 + + - + Week 12 : Experimenting with ODFs implementation +

+
+ +
+

+ + 24 August 2023 + + - + Google Summer of Code Final Work Product +

+
+ +
+

+ + 16 August 2023 + + - + Week 11 : Adjusting ODF implementation and looking for solutions on issues found +

+
+ +
+

+ + 08 August 2023 + + - + Week 10 : Start of SH implementation experiments +

+
+ +
+

+ + 31 July 2023 + + - + Week 9: Tutorial done and polishing DTI uncertainty +

+
+ +
+

+ + 25 July 2023 + + - + Week 8: Working on Ellipsoid Tutorial and exploring SH +

+
+ +
+

+ + 17 July 2023 + + - + Week 7: Adjustments on the Uncertainty Cones visualization +

+
+ +
+

+ + 10 July 2023 + + - + Week 6: First draft of the Ellipsoid tutorial +

+
+ +
+

+ + 03 July 2023 + + - + Week 5: Preparing the data for the Ellipsoid tutorial +

+
+ +
+

+ + 27 June 2023 + + - + Week 4: First draft of the DTI uncertainty visualization +

+
+ +
+

+ + 19 June 2023 + + - + Week 3: Working on uncertainty and details of the first PR +

+
+ +
+

+ + 12 June 2023 + + - + Week 2: Making adjustments to the Ellipsoid Actor +

+
+ +
+

+ + 05 June 2023 + + - + Week 1: Ellipsoid actor implemented with SDF +

+
+ +
+

+ + 02 June 2023 + + - + Week 0: Community Bounding Period +

+
+ +
+ + + +
+

+ Posts by + Serge Koudoro +

+ +
+

+ + 15 April 2023 + + - + FURY 0.9.0 Released +

+
+ +
+

+ + 01 February 2023 + + - + Contribute to FURY via Google Summer of Code 2023 +

+
+ +
+

+ + 01 February 2022 + + - + Contribute to FURY via Google Summer of Code 2022 +

+
+ +
+

+ + 31 January 2022 + + - + FURY 0.8.0 Released +

+
+ +
+

+ + 03 August 2021 + + - + FURY 0.7.0 Released +

+
+ +
+

+ + 13 March 2021 + + - + FURY 0.7.0 Released +

+
+ +
+

+ + 09 March 2021 + + - + Google Summer of Code +

+
+ +
+

+ + 18 August 2020 + + - + FURY 0.6.1 Released +

+
+ +
+

+ + 20 July 2020 + + - + FURY 0.6.0 Released +

+
+ +
+

+ + 09 April 2020 + + - + FURY 0.5.1 Released +

+
+ +
+

+ + 05 January 2020 + + - + Google Summer of Code +

+
+ +
+

+ + 29 October 2019 + + - + FURY 0.4.0 Released +

+
+ +
+

+ + 02 August 2019 + + - + FURY 0.3.0 Released +

+
+ +
+

+ + 19 June 2019 + + - + Success on Brain Art Competition using FURY +

+
+ +
+

+ + 08 March 2019 + + - + FURY 0.2.0 Released +

+
+ +
+

+ + 26 November 2018 + + - + FURY 0.1.4 Released +

+
+ +
+

+ + 31 October 2018 + + - + FURY 0.1.3 Released +

+
+ +
+

+ + 21 September 2018 + + - + FURY 0.1.0 Released +

+
+ +
+ + + +
+ + + +
+ +
+
+
+ +
+ + + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/blog/author/antriksh-misri.html b/v0.10.x/blog/author/antriksh-misri.html new file mode 100644 index 000000000..54795fe91 --- /dev/null +++ b/v0.10.x/blog/author/antriksh-misri.html @@ -0,0 +1,1318 @@ + + + + + + + Posts by Antriksh Misri — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +
+

+ + Posts by + + Antriksh Misri + +

+ + +
+

+ Google Summer of Code Final Work Product +

+
    +
  • + + + 23 August 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Antriksh Misri + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Name: Antriksh Misri

+

+ +

Read more ...

+
+
+ +
+

+ Week #11: Finalizing open Pull Requests +

+
    +
  • + + + 16 August 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Antriksh Misri + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Below are the tasks that I worked on:

+

+ +

Read more ...

+
+
+ +
+

+ Week#10: Accordion UI, Support for sprite sheet animations +

+
    +
  • + + + 09 August 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Antriksh Misri + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Below are the tasks that I worked on:

+

+ +

Read more ...

+
+
+ +
+

+ Week #9: More Layouts! +

+
    +
  • + + + 02 August 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Antriksh Misri + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Below are the tasks that I worked on:

+

+ +

Read more ...

+
+
+ +
+

+ Week #8: Code Cleanup, Finishing up open PRs, Continuing work on Tree2D +

+
    +
  • + + + 26 July 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Antriksh Misri + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week I had to work on the open PRs specifically work on the bugs that were pointed out in last week’s meeting. Along side the bugs I had to continue the work on Tree2D UI element. Below is the detailed description of what I worked on this week:

+

+ +

Read more ...

+
+
+ +
+

+ Week #7: Finalizing the stalling PRs, finishing up Tree2D UI. +

+
    +
  • + + + 19 July 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Antriksh Misri + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week I had limited tasks to do, mostly tasks related to existing PRs. Other than some minor fixes I had to implement some more things in Tree2D which included some minor UI fixes, some changes in tutorial, adding tests. Below is the detailed description of what I worked on this week:

+

+ +

Read more ...

+
+
+ +
+

+ Week #6: Bug fixes, Working on Tree2D UI +

+
    +
  • + + + 12 July 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Antriksh Misri + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week I had relatively few tasks and most of them were to fix some bugs/design flaws that were discussed in last week’s meeting. Other than that, I had to implement a few things in the Tree2D UI element that will be discussed in detail below. I also had to update some existing PRs in order to make things work well. Below are the list of things I worked on this week:

+

+ +

Read more ...

+
+
+ +
+

+ Week #5: Rebasing all PRs w.r.t the UI restructuring, Tree2D, Bug Fixes +

+
    +
  • + + + 05 July 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Antriksh Misri + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

The UI restructuring was finally merged this week. This means UI is now a submodule in itself and provides different UI elements based on their types which are, core, elements, containers and some helper methods/classes. So, this week my main tasks were to rebase and fix merge conflicts of my open PR’s. Other than that, I had to continue my work on Tree2D UI element and finish the remaining aspects of it. Also, I had to create an example demonstrating how to use the newly added UI element. Many use cases were discussed in the open meeting like, an image gallery which displays preview image on the title and when expanded reveals the full scale image. I am thinking of adding multiple examples for the Tree2D to brainstorm on its certain features. Also, I had this annoying bug in Panel2D which didn’t allow it to be resized from the bottom right corner. It was resizing from the top right corner. I had to address this bug as well. Below are the tasks in detail:

+

+ +

Read more ...

+
+
+ +
+

+ Week #4: Adding Tree UI to the UI module +

+
    +
  • + + + 28 June 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Antriksh Misri + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week I had very few tasks to do, almost all of them revolved around UI elements and adding stuff to the UI module. Earlier, it was pointed out that due to some design issues, importing certain modules into others caused circular imports which led to importing the specific modules inside a class/method which is not the best approach. This will be resolved as soon as the PR that fixes this issue is reviewed/merged in the codebase. In the meantime, all the PR’s related to UI will be on hold, which is why this I had few tasks this week. The tasks are described below in detail:

+

+ +

Read more ...

+
+
+ +
+

+ Week #3: Adapting GridLayout to work with UI +

+
    +
  • + + + 21 June 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Antriksh Misri + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week my tasks revolved around layout and UI elements. The primary goal for this week was to adapt the GridLayout to work with different UI elements. Currently, GridLayout just supports vtk actors and not UI elements, my task was to modify the class to support UI elements. The other tasks for this week are described below in detail:

+

+ +

Read more ...

+
+
+ +
+

+ Week #2: Feature additions in UI and IO modules +

+
    +
  • + + + 13 June 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Antriksh Misri + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week I had to work on 3 PRs as well as some documentation. I really enjoyed this week’s work as the tasks were really interesting. The aim for these PRs were to actually add a couple of features in the UI as well as the IO module, which includes, adding support for border in Panel2D, adding support for network/URL images in load_image method in IO module, adding resizing Panel2D from bottom right corner, completing the document with layout solutions provided by Unity/Unreal engine. Below are the PRs that I worked on:

+

+ +

Read more ...

+
+
+ +
+

+ Week #1: Welcome to my weekly Blogs! +

+
    +
  • + + + 08 June 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Antriksh Misri + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hi everyone! I am Antriksh Misri. I am a Pre-Final year student at MIT Pune. This summer, I will be working on Layout Management under FURY’s UI module as my primary goal. This includes addition of different classes under Layout Management to provide different layouts/arrangements in which the UI elements can be arranged. As my stretch goals, I will be working on a couple of UI components for FURY’s UI module. These 2D and 3D components will be sci-fi like as seen in the movie “Guardians of The Galaxy”. My objective for the stretch goals would be to develop these UI components with their respective test and tutorials such that it adds on to the UI module of FURY and doesn’t hinder existing functionalities/performance.

+

+ +

Read more ...

+
+
+ + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/blog/author/antriksh-misri/atom.xml b/v0.10.x/blog/author/antriksh-misri/atom.xml new file mode 100644 index 000000000..2c419ed45 --- /dev/null +++ b/v0.10.x/blog/author/antriksh-misri/atom.xml @@ -0,0 +1,566 @@ + + + https://fury.gl/ + Blog - Posts by Antriksh Misri + 2024-02-29T15:43:57.377649+00:00 + + + ABlog + + https://fury.gl/posts/2021/2021-08-23-final-work-antriksh.html + Google Summer of Code Final Work Product + 2021-08-23T00:00:00-04:00 + + Antriksh Misri + + <a class="reference external image-reference" href="https://summerofcode.withgoogle.com/projects/#6653942668197888"><img alt="https://developers.google.com/open-source/gsoc/resources/downloads/GSoC-logo-horizontal.svg" class="align-center" height="50" src="https://developers.google.com/open-source/gsoc/resources/downloads/GSoC-logo-horizontal.svg" /></a> +<a class="reference external image-reference" href="https://blogs.python-gsoc.org/en/nibba2018s-blog/"><img alt="https://www.python.org/static/community_logos/python-logo.png" src="https://www.python.org/static/community_logos/python-logo.png" style="width: 40%;" /></a> +<a class="reference external image-reference" href="https://fury.gl/latest/community.html"><img alt="https://python-gsoc.org/logos/FURY.png" src="https://python-gsoc.org/logos/FURY.png" style="width: 25%;" /></a> +<section id="google-summer-of-code-final-work-product"> + +<ul class="simple"> +<li><p><strong>Name:</strong> Antriksh Misri</p></li> +<li><p><strong>Organisation:</strong> Python Software Foundation</p></li> +<li><p><strong>Sub-Organisation:</strong> FURY</p></li> +<li><p><strong>Project:</strong> <a class="reference external" href="https://github.com/fury-gl/fury/wiki/Google-Summer-of-Code-2021#project-3-create-new-user-interface-widget">FURY: Create new user interface widget</a></p></li> +</ul> +<section id="proposed-objectives"> +<h2>Proposed Objectives</h2> +<ul class="simple"> +<li><p>Add support for Layouts in UI elements</p></li> +<li><p>Add support for Horizontal Layout</p></li> +<li><p>Add support for Vertical Layout</p></li> +<li><p>Add support for Layout along X, Y, Z axes.</p></li> +<li><p>Stretch Goals:</p> +<ul> +<li><p>Add Tree2D UI element to the UI sub-module</p></li> +<li><p>Add Accordion2D UI element to the UI sub-module</p></li> +<li><p>Add SpinBox2D UI element to the UI sub-module</p></li> +</ul> +</li> +</ul> +</section> +<section id="objectives-completed"> +<h2>Objectives Completed</h2> +<ul> +<li><p><strong>Add support for Horizontal Layout</strong></p> +<p>Added support for Horizontal Layout in the layout module. This layout allows the user to stack actors in a horizontal fashion. Primarily, should be used for laying out UI elements as there is no meaning of horizontal/vertical in 3D space.</p> +<p><em>Pull Requests:</em></p> +<ul class="simple"> +<li><p><strong>Horizontal Layout:</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/480">fury-gl/fury#480</a></p></li> +<li><p><strong>Ribbon Representation demo:</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/480">fury-gl/fury#480</a></p></li> +</ul> +</li> +<li><p><strong>Add support for Vertical Layout</strong></p> +<p>Added support for Vertical Layout in the layout module. This layout allows the user to stack actors in a vertical fashion. Primarily, should be used for laying out UI elements as there is no meaning of horizontal/vertical in 3D space.</p> +<p><em>Pull Requests:</em></p> +<ul class="simple"> +<li><p><strong>Vertical Layout:</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/479">fury-gl/fury#479</a></p></li> +<li><p><strong>Vertical Layout demo:</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/479">fury-gl/fury#479</a></p></li> +</ul> +</li> +<li><p><strong>Add support for Layout along X, Y, Z axes</strong></p> +<p>Added support for Layout along x, y, z axes. Allows user to layout different actors along any given axes. Also it allows users to switch the stacking order by passing a axis+ or axis- to the constructor.</p> +<p><em>Pull Requests:</em></p> +<ul class="simple"> +<li><p><strong>X, Y, Z axes Layout:</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/486">fury-gl/fury#486</a></p></li> +<li><p><strong>X, Y, Z axes Layout demo:</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/486">fury-gl/fury#486</a></p></li> +</ul> +</li> +<li><p><strong>Add Tree2D UI element to the UI sub-module</strong></p> +<p>Added Tree2D UI element to the UI sub-module. This allows user to visualize some data in a hierarchical fashion. Each node inside the tree can have N child nodes and the depth can be infinite. Each node can be clicked to trigger a user defined callback to perform some action. Tests and two demos were added for this UI element. Below is a screenshot for reference:</p> +<img alt="https://camo.githubusercontent.com/dd23b7c8503e4d01c80f2d9e84ee173e06c61eeb7c348c35aeadc75f722647ca/68747470733a2f2f692e696d6775722e636f6d2f4e49334873746c2e706e67" src="https://camo.githubusercontent.com/dd23b7c8503e4d01c80f2d9e84ee173e06c61eeb7c348c35aeadc75f722647ca/68747470733a2f2f692e696d6775722e636f6d2f4e49334873746c2e706e67" style="width: 200px; height: 200px;" /> +<p><em>Pull Requests:</em></p> +<ul class="simple"> +<li><p><strong>Tree2D UI element:</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/460">fury-gl/fury#460</a></p></li> +<li><p><strong>Tree2D UI element demo:</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/460">fury-gl/fury#460</a></p></li> +</ul> +</li> +<li><p><strong>Add Accordion2D UI element to the UI sub-module</strong></p> +<p>Added Accordion2D to the UI sub-module. This Ui element allows users to visualize data in a tree with depth of one. Each node has a title and a content panel. The children for each node can be N if and only if the children are not nodes themselves. The child UIs can be placed inside the content panel by passing some coordinates, which can be absolute or normalized w.r.t the node content panel size. Tests and two demos were added for this UI element. Below is a screenshot for reference</p> +<img alt="https://camo.githubusercontent.com/9395d0ea572d7f253a051823f02496450c9f79d19ff0baf32841ec648b6f2860/68747470733a2f2f692e696d6775722e636f6d2f7854754f645a742e706e67" src="https://camo.githubusercontent.com/9395d0ea572d7f253a051823f02496450c9f79d19ff0baf32841ec648b6f2860/68747470733a2f2f692e696d6775722e636f6d2f7854754f645a742e706e67" style="width: 200px; height: 200px;" /> +<p><em>Pull Requests:</em></p> +<ul class="simple"> +<li><p><strong>Accordion2D UI element:</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/487">fury-gl/fury#487</a></p></li> +<li><p><strong>Accordion2D UI element demo:</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/487">fury-gl/fury#487</a></p></li> +</ul> +</li> +</ul> +</section> +<section id="objectives-in-progress"> +<h2>Objectives in Progress</h2> +<ul> +<li><p><strong>Add support for Layout in UI elements</strong></p> +<p>Currently all the available layouts are only available for actors i.e. of type vtkActor2D. In order to add support for the layouts in UI elements there needs to be some tweaking in the base Layout class. Currently, the PR that adds these functionalities in stalling because of some circular imports. These will hopefully be fixed soon and as soon as the circular imports are fixed, the PR will be merged.</p> +<p><em>Pull Requests:</em></p> +<ul class="simple"> +<li><p><strong>Add support for Layout in UI elements:</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/443">fury-gl/fury#443</a></p></li> +</ul> +</li> +<li><p><strong>Method to process and load sprite sheets</strong></p> +<p>This method adds support for loading and processing a sprite sheet. This will be very useful in playing animations from a n*m sprite sheet. This also has a flag to convert the processed chunks into vtkimageData which can be directly used to update the texture in some UI elements. The primary use of this method will in a tutorial for Card2D, wherein, the image panel of the card will play the animation directly from the sprite sheet.</p> +<p><em>Pull Requests:</em></p> +<ul class="simple"> +<li><p><strong>Method to process and load sprite sheets:</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/491">fury-gl/fury#491</a></p></li> +</ul> +</li> +</ul> +</section> +<section id="other-objectives"> +<h2>Other Objectives</h2> +<ul> +<li><p><strong>Add Card2D UI element to UI sub-module</strong></p> +<p>Added Card2D UI element to the UI sub-module. A Card2D is generally divided into two parts i.e. the image content and the text content. This version of card has an image which can be fetched from a URL and the text content which is yet again divided into two parts i.e. the title and the body. The space distribution between the image and the text content is decided by a float between 0 and 1. A value of 0 means the image takes up no space and a value of 1 means the image consumes the whole space. Below is a demonstration:</p> +<img alt="https://camo.githubusercontent.com/a2e461352799b6490088de15ac041162d7bf8adf9c07485ea921b525fecd0a8e/68747470733a2f2f692e696d6775722e636f6d2f446c69537066302e676966" src="https://camo.githubusercontent.com/a2e461352799b6490088de15ac041162d7bf8adf9c07485ea921b525fecd0a8e/68747470733a2f2f692e696d6775722e636f6d2f446c69537066302e676966" style="width: 200px; height: 200px;" /> +<p><em>Pull Requests:</em></p> +<ul class="simple"> +<li><p><strong>Add Card2D UI element to UI sub-module:</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/398">fury-gl/fury#398</a></p></li> +</ul> +</li> +<li><p><strong>Resize Panel2D with WindowResizeEvent or from corner placeholder</strong></p> +<p>Currently, the size of the Panel2D is static and cannot be changed dynamically. The size is passed in during the initialization and cannot be changed easily at runtime. This PR adds support for resizing the Panel2D dynamically by adding a placeholder icon at the bottom right corner of the panel. This icon can be click and dragged on to change the size accordingly. Other than this, the panel also retains a specific size ratio when the window is resized. This means if the window is resized in any direction the panel adapts itself w.r.t the updated size. This is done by adding relevant observers for the WindowResizeEvent and binding the relevant callback to it. Below is a quick demonstration:</p> +<blockquote> +<div><img alt="https://camo.githubusercontent.com/3b1bf6a1b6522a6079055ff196551362fcf89a41b35ac4b32315ce02333e496d/68747470733a2f2f692e696d6775722e636f6d2f3837504e3754512e676966" src="https://camo.githubusercontent.com/3b1bf6a1b6522a6079055ff196551362fcf89a41b35ac4b32315ce02333e496d/68747470733a2f2f692e696d6775722e636f6d2f3837504e3754512e676966" style="width: 200px; height: 200px;" /> +</div></blockquote> +<p><em>Pull Requests:</em></p> +<ul class="simple"> +<li><p><strong>Resize Panel2D with WindowResizeEvent or from corner placeholder:</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/446">fury-gl/fury#446</a></p></li> +</ul> +</li> +<li><p><strong>Added the watcher class to UI</strong></p> +<p>This PR adds support for a watcher class in the UI elements. The purpose of this class is to monitor a particular attribute from the UI element after it has been added to the scene. If the attribute changes in the real time, a user defined callback is triggered and the scene is force rendered.</p> +<p><em>Pull Requests:</em></p> +<ul class="simple"> +<li><p><strong>Added wathcer class to the UI sub-module:</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/448">fury-gl/fury#448</a></p></li> +</ul> +</li> +<li><p><strong>Added support for borders in Panel2D</strong></p> +<p>The Panel2D previously, didn’t support any sort of effect, the main reason behind this is that, all UI elements are individual entities that are comprised of different actors. These are not the widgets provided by vtk and in order to have some effects provided by vtk shaders must be involved. This obviously makes the whole system very complicated. The border on the other hand uses 4 Rectangle2Ds to draw the 4 borders. This makes the whole process easier but makes the Panel2D very performance heavy as we are adding 5 actors to the scene. Future iterations will replace these rectangles by textures, that way we don’t compromise performance and we can have different patterns in the border. Below is a demonstration:</p> +<img alt="https://user-images.githubusercontent.com/54466356/121709989-bd340280-caf6-11eb-9b8a-81c65260d277.png" src="https://user-images.githubusercontent.com/54466356/121709989-bd340280-caf6-11eb-9b8a-81c65260d277.png" style="width: 200px; height: 200px;" /> +<p><em>Pull Requests:</em></p> +<ul class="simple"> +<li><p><strong>Added support for borders in Panel2D:</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/441">fury-gl/fury#441</a></p></li> +</ul> +</li> +<li><p><strong>GSoC weekly Blogs</strong></p> +<blockquote> +<div><p>Weekly blogs were added for FURY’s Website.</p> +<p><em>Pull Requests:</em></p> +<ul class="simple"> +<li><p><strong>First Evaluation:</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/477">fury-gl/fury#477</a></p></li> +<li><p><strong>Second Evaluation:</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/494">fury-gl/fury#494</a></p></li> +</ul> +</div></blockquote> +</li> +</ul> +</section> +<section id="timeline"> +<h2>Timeline</h2> +<table class="table"> +<thead> +<tr class="row-odd"><th class="head"><p>Date</p></th> +<th class="head"><p>Description</p></th> +<th class="head"><p>Blog Link</p></th> +</tr> +</thead> +<tbody> +<tr class="row-even"><td><p>Week 1(08-06-2021)</p></td> +<td><p>Welcome to my weekly Blogs!</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/antrikshmisris-blog/week-1-welcome-to-my-weekly-blogs/">Weekly Check-in #1</a></p></td> +</tr> +<tr class="row-odd"><td><p>Week 2(14-06-2021)</p></td> +<td><p>Feature additions in UI and IO modules</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/antrikshmisris-blog/week-2-feature-additions-in-ui-and-io-modules/">Weekly Check-in #2</a></p></td> +</tr> +<tr class="row-even"><td><p>Week 3(21-06-2021)</p></td> +<td><p>Adapting GridLayout to work with UI</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/antrikshmisris-blog/week-3-adapting-gridlayout-to-work-with-ui/">Weekly Check-in #3</a></p></td> +</tr> +<tr class="row-odd"><td><p>Week 4(28-06-2021)</p></td> +<td><p>Adding Tree UI to the UI module</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/antrikshmisris-blog/week-4-adding-tree-ui-to-the-ui-module/">Weekly Check-in #4</a></p></td> +</tr> +<tr class="row-even"><td><p>Week 5(05-07-2021)</p></td> +<td><p>Rebasing all PR’s w.r.t the UI restructuring, Tree2D, Bug Fixes</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/antrikshmisris-blog/week-5-rebasing-all-pr-s-w-r-t-the-ui-restructuring-tree2d-bug-fixes/">Weekly Check-in #5</a></p></td> +</tr> +<tr class="row-odd"><td><p>Week 6(12-07-2021)</p></td> +<td><p>Bug fixes, Working on Tree2D UI</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/antrikshmisris-blog/week-6-bug-fixes-working-on-tree2d-ui/">Weekly Check-in #6</a></p></td> +</tr> +<tr class="row-even"><td><p>Week 7(19-07-2021)</p></td> +<td><p>Finalizing the stalling PR’s, finishing up Tree2D UI.</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/antrikshmisris-blog/week-7-finalizing-the-stalling-pr-s-finishing-up-tree2d-ui/">Weekly Check-in #7</a></p></td> +</tr> +<tr class="row-odd"><td><p>Week 8(26-07-2020)</p></td> +<td><p>Code Cleanup, Finishing up open PR’s, Continuing work on Tree2D.</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/antrikshmisris-blog/week-8-code-cleanup-finishing-up-open-pr-s-continuing-work-on-tree2d/">Weekly Check-in #8</a></p></td> +</tr> +<tr class="row-even"><td><p>Week 9(02-08-2021)</p></td> +<td><p>More Layouts!</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/antrikshmisris-blog/week-9-more-layouts/">Weekly Check-in #9</a></p></td> +</tr> +<tr class="row-odd"><td><p>Week 10(09-08-2021)</p></td> +<td><p>Accordion UI, Support for sprite sheet animations.</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/antrikshmisris-blog/week-10-accordion-ui-support-for-sprite-sheet-animations/">Weekly Check-in #10</a></p></td> +</tr> +<tr class="row-even"><td><p>Week 11(16-08-2021)</p></td> +<td><p>More tutorials for Accordion2D, Finalizing remaining PRs.</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/antrikshmisris-blog/week-11-2/">Weekly Check-in #11</a></p></td> +</tr> +</tbody> +</table> +<p>Detailed weekly tasks and work done can be found +<a class="reference external" href="https://blogs.python-gsoc.org/en/antrikshmisris-blog/">here</a>.</p> +</section> +</section> + + + Name: Antriksh Misri + + 2021-08-23T00:00:00-04:00 + + + https://fury.gl/posts/2021/2021-08-16-week-11-antriksh.html + Week #11: Finalizing open Pull Requests + 2021-08-16T00:00:00-04:00 + + Antriksh Misri + + <section id="week-11-finalizing-open-pull-requests"> + +<section id="what-did-i-do-this-week"> +<h2>What did I do this week?</h2> +<p>Below are the tasks that I worked on:</p> +<ul class="simple"> +<li><p><a class="reference external" href="https://github.com/fury-gl/fury/pull/491">Created PR for sprite sheet animation</a> : This PR adds support for playing animations from a sprite sheet. This feature will be used in Card2D to create a tutorial in which the card will show the animation in the image box. Previously, the utility functions for this were added directly inside the tutorial but now they are refactored to go in their respective modules.</p></li> +<li><p><a class="reference external" href="https://github.com/fury-gl/fury/pull/486">Finalized the x, y, z layouts</a> : The PR that adds these layouts needed some updates for it to work as intended. These changes were added and this PR is ready to go.</p></li> +<li><p><a class="reference external" href="https://github.com/fury-gl/fury/pull/443">Resolved all conflicts in the GridLayout PR</a> : As the Horizontal and Vertical layouts were merged this week the GridLayout PR had got some conflicts. These conflicts were resolved and the PR is almost ready.</p></li> +<li><p><strong>Continuing the work on custom font rendering</strong> : In the last meeting, a few points were brought up. Firstly, to position each glyph to their respective location in the atlas a separate module is used which is freetype-gl. The python bindings for this module are not available which means either we have to write the bindings ourselves or the freetype team will be emailed about this and they will add bindings for that. On the other hand, I looked how latex is rendered in matplotlib. <a class="reference external" href="https://github.com/matplotlib/matplotlib/blob/3a4fdea8d23207d67431973fe5df1811605c4132/lib/matplotlib/text.py#L106">This</a> is the Text class that is used to represent the string that is to be drawn and <a href="#id1"><span class="problematic" id="id2">`This is the class that it inherits from.&lt;https://github.com/matplotlib/matplotlib/blob/3a4fdea8d23207d67431973fe5df1811605c4132/lib/matplotlib/artist.py#L94&gt;`_</span></a> Everything is handled internally in matplotlib, to draw the rasterized text <a class="reference external" href="https://github.com/matplotlib/matplotlib/blob/3a4fdea8d23207d67431973fe5df1811605c4132/lib/matplotlib/text.py#L672">this function is used.</a> The text can be rendered in two ways, the first one is by using the default renderer and the second way is by using PathEffectRenderer that is used to add effects like outlines, anti-aliasing etc. It is a very rigid way of rendering text and is designed to be used internally.</p></li> +</ul> +</section> +<section id="did-i-get-stuck-anywhere"> +<h2>Did I get stuck anywhere?</h2> +<p>No, I did not get stuck anywhere.</p> +</section> +<section id="what-is-coming-up-next-week"> +<h2>What is coming up next week?</h2> +<p>Hopefully everything is resolved by the end of this week and next week I will hopefully submit my final code in a gist format.</p> +<p><strong>See you guys next week!</strong></p> +</section> +</section> + + + Below are the tasks that I worked on: + + 2021-08-16T00:00:00-04:00 + + + https://fury.gl/posts/2021/2021-08-09-week-10-antriksh.html + Week#10: Accordion UI, Support for sprite sheet animations + 2021-08-09T00:00:00-04:00 + + Antriksh Misri + + <section id="week-10-accordion-ui-support-for-sprite-sheet-animations"> + +<section id="what-did-i-do-this-week"> +<h2>What did I do this week?</h2> +<p>Below are the tasks that I worked on:</p> +<ul> +<li><p><a class="reference external" href="https://github.com/fury-gl/fury/pull/487">Added Accordion2D to UI sub-module</a> : This PR adds the Accordion UI to the UI sub-module. This UI inherits from the Tree2D UI and can only be merged once the Tree2D UI is in. Here’s a screenshot for reference:</p> +<blockquote> +<div><img alt="https://i.imgur.com/klI4Tb5.png" src="https://i.imgur.com/klI4Tb5.png" style="width: 200px; height: 200px;" /> +</div></blockquote> +</li> +<li><p><a class="reference external" href="https://github.com/fury-gl/fury/pull/486">Adding X, Y, Z Layouts</a> : It was pointed out in last week’s meeting that in 3D space horizontal/vertical means nothing. Instead X, Y, Z are used, so, these three layouts were added on top of horizontal/vertical layouts. They also have functionality of changing the direction i.e. reverse the stacking order.</p></li> +<li><p><a class="reference external" href="https://github.com/fury-gl/fury/pull/398">Added support of sprite sheet animation in Card2D</a> : The image in Card2D was static in nature and wasn’t very interesting. So, to make things a bit interesting support for animated images were added. These animations are played from a sprite sheet or a texture atlas. A buffer of processed sprite chunks is maintained and with the help of a timer callback the image in the card is updated after a certain delay which is dependent of the frame rate. Below is the demonstration:</p> +<blockquote> +<div><img alt="https://i.imgur.com/DliSpf0.gif" src="https://i.imgur.com/DliSpf0.gif" style="width: 200px; height: 200px;" /> +</div></blockquote> +</li> +<li><p><strong>Researching more about Freetype/Freetype-GL</strong>: Apart from coding stuff, i did some more research on custom font using freetype and freetype-gl. I found some examples that used the python bindings of the c++ library and displayed custom fonts that were transformable i.e. can be rotated by some angle. Hopefully I can create a working example by this weeks meeting.</p></li> +</ul> +</section> +<section id="did-i-get-stuck-anywhere"> +<h2>Did I get stuck anywhere?</h2> +<p>No, I did not get stuck anywhere.</p> +</section> +<section id="what-is-coming-up-next-week"> +<h2>What is coming up next week?</h2> +<p>Next week I will finish up my remaining work. Which includes addressing all PR reviews and adding some more features.</p> +<p><strong>See you guys next week!</strong></p> +</section> +</section> + + + Below are the tasks that I worked on: + + 2021-08-09T00:00:00-04:00 + + + https://fury.gl/posts/2021/2021-08-02-week-9-antriksh.html + Week #9: More Layouts! + 2021-08-02T00:00:00-04:00 + + Antriksh Misri + + <section id="week-9-more-layouts"> + +<section id="what-did-i-do-this-week"> +<h2>What did I do this week?</h2> +<p>Below are the tasks that I worked on:</p> +<ul> +<li><p><a class="reference external" href="https://github.com/fury-gl/fury/pull/480">Added Horizontal/Vertical Layout to the layout module</a> : These PRs add support for Horizontal/Vertical layouts. These layouts allow the actors to be placed in a horizontal/vertical stack.</p> +<blockquote> +<div><img alt="https://user-images.githubusercontent.com/54466356/127688192-8412b604-d6c7-4da9-87c4-dfae044a136e.png" src="https://user-images.githubusercontent.com/54466356/127688192-8412b604-d6c7-4da9-87c4-dfae044a136e.png" style="width: 200px; height: 200px;" /> +<img alt="https://user-images.githubusercontent.com/54466356/127620054-7e14f86e-1579-46ac-b4a6-ac98c109094a.png" src="https://user-images.githubusercontent.com/54466356/127620054-7e14f86e-1579-46ac-b4a6-ac98c109094a.png" style="width: 200px; height: 200px;" /> +</div></blockquote> +</li> +<li><p><a class="reference external" href="https://github.com/fury-gl/fury/pull/398">Finalizing Card2D UI element</a> : As panel border, wrap overflow PRs were merged this week I updated the Card2D UI to take advantage of these features.</p></li> +<li><p><a class="reference external" href="https://github.com/fury-gl/fury/pull/477">Added GSoC blog posts</a> : Added GSoC blog posts in .rst format for the FURY’s blog website. Also reviewed the blog posts of other members.</p></li> +<li><p><a class="reference external" href="https://github.com/fury-gl/fury/pull/460">Added support for dragging by label text/icon in Tree2D UI</a> : Added support for dragging TreeNode2D by the label text/icon. This will help making the Tree2D as well as TreeNode2D UIs more mobile.</p></li> +</ul> +</section> +<section id="did-i-get-stuck-anywhere"> +<h2>Did I get stuck anywhere?</h2> +<p>For now I am not stuck anywhere but I have yet to start my work on freetype this could pose some trouble.</p> +</section> +<section id="what-is-coming-up-next-week"> +<h2>What is coming up next week?</h2> +<p>Next week I will finish the remaining UI elements which includes Accordion2D, SpinBox2D.</p> +<p><strong>See you guys next week!</strong></p> +</section> +</section> + + + Below are the tasks that I worked on: + + 2021-08-02T00:00:00-04:00 + + + https://fury.gl/posts/2021/2021-07-26-week-8-antriksh.html + Week #8: Code Cleanup, Finishing up open PRs, Continuing work on Tree2D + 2021-07-26T00:00:00-04:00 + + Antriksh Misri + + <section id="week-8-code-cleanup-finishing-up-open-prs-continuing-work-on-tree2d"> + +<section id="what-did-i-do-this-week"> +<h2>What did I do this week?</h2> +<p>This week I had to work on the open PRs specifically work on the bugs that were pointed out in last week’s meeting. Along side the bugs I had to continue the work on Tree2D UI element. Below is the detailed description of what I worked on this week:</p> +<ul class="simple"> +<li><p><a class="reference external" href="https://github.com/fury-gl/fury/pull/460">Added new tutorial, code clean-up, bug fixes</a> : The Tree2D had some issues with its resizing of child nodes. The size for the nodes was calculated automatically based on the vertical size occupied by its children but this could be problematic when working with sliders or UI elements that take up a lot of vertical size. To avoid this the children sizes are calculated relative to each other and the vertical size is calculated such that all children fit in perfectly. Besides this, a multiselection flag has been added that decides whether multiple child nodes can be selected or not.</p></li> +<li><p><a class="reference external" href="https://github.com/fury-gl/fury/pull/446">Adding tests for corner resize callback</a> : This PR is almost done as it was decided that WindowsResizeEvent will be ignored for now. Which leaves us with corner resizing, the callback for corner resizing didn’t have any tests so the recording was redone and tests for the corner resize callback was added.</p></li> +<li><p><a class="reference external" href="https://github.com/fury-gl/fury/pull/443">Fixing the failing CI’s for #443</a> : The solution that ended up working was creating custom objects for testing of is_ui method. With this update there will be no circular dependencies and no failing CI’s.</p></li> +<li><p><a class="reference external" href="https://github.com/fury-gl/fury/pull/442">Addressing all comments regarding #442</a> : In the last meeting, a bug was pointed out wherein the text wouldn’t wrap as expected. The reason for this was some minor calculation mistakes. The whole wrap_overflow method was redone and now everything works as expected. Hopefully, no bugs pop up during this week’s meeting.</p></li> +<li><p><a class="reference external" href="https://github.com/fury-gl/fury/pull/441">Addressing some minor comments</a> : This PR is almost done too, there were some minor changes that were required to be addressed before this could be merged. So, these comments were fixed and hopefully this will be merged soon.</p></li> +<li><p>Using different fonts using FreeType python API: A major thing that FURY needs right now is using different fonts on the fly. This is more complicated than it seems, in case of browser environment this is not a problem as browsers can support and render all fonts using various techniques. In case of a desktop environment, we need to generate the bitmap for the fonts and then use them in form of textures. For now I have created a small example that generates these bitmaps from a python API called freetype-py, the fonts are fetched from google fonts and then they are displayed as textures.</p></li> +<li><p><strong>Starting working on Vertical Layout</strong>: As majority of PRs are almost done, I started working on Vertical Layout. This will be hihgly inspired from the Grid Layout with obvious differences. The same techniques are being used in the Tree2D so this shouldn’t be difficult to implement.</p></li> +</ul> +</section> +<section id="did-i-get-stuck-anywhere"> +<h2>Did I get stuck anywhere?</h2> +<p>The failing CI’s for Grid Layout Pr needed some custom objects to remove circular dependencies. I couldn’t figure out where should these custom objects go but fortunaltely the mentors showed me a quick example of where it should go.</p> +</section> +<section id="what-is-coming-up-next-week"> +<h2>What is coming up next week?</h2> +<p>Next week I will continue my work on some other UI’s and the remaining Layouts.</p> +<p><strong>See you guys next week!</strong></p> +</section> +</section> + + + This week I had to work on the open PRs specifically work on the bugs that were pointed out in last week’s meeting. Along side the bugs I had to continue the work on Tree2D UI element. Below is the detailed description of what I worked on this week: + + 2021-07-26T00:00:00-04:00 + + + https://fury.gl/posts/2021/2021-07-19-week-7-antriksh.html + Week #7: Finalizing the stalling PRs, finishing up Tree2D UI. + 2021-07-19T00:00:00-04:00 + + Antriksh Misri + + <section id="week-7-finalizing-the-stalling-prs-finishing-up-tree2d-ui"> + +<section id="what-did-i-do-this-week"> +<h2>What did I do this week?</h2> +<p>This week I had limited tasks to do, mostly tasks related to existing PRs. Other than some minor fixes I had to implement some more things in Tree2D which included some minor UI fixes, some changes in tutorial, adding tests. Below is the detailed description of what I worked on this week:</p> +<ul class="simple"> +<li><p><a class="reference external" href="https://github.com/fury-gl/fury/pull/460">Tests, tutorial changes, UI fixes for Tree2D</a> : The Tree2D lacked some things like proper UI resizing, relative indentation, tests for the UI class. These were added with this PR. Currently, the indentation, resizing needs some improvement, which will be fixed after feedback from this week’s meeting. Also, tests for Tree2D, TreeNode2D were added as well.</p></li> +<li><p><a class="reference external" href="https://github.com/fury-gl/fury/pull/446">Updating Panel2D tests, re-recording the events</a> : This PR is almost done with just some tests blocking the PR. The tests were added this week, but tests for some callbacks that are associated with window event are still not added. This is because there is no way to count the WindowResizeEvent without actually using the API of the window provided by the OS. This can become very complicated very soon so, these tests may be added in the future.</p></li> +<li><p><a class="reference external" href="https://github.com/fury-gl/fury/pull/443">Fixing the failing CI’s for #443</a> : The CI was failing on this PR and needed some fixing which was done this week. This PR still needs some refactoring before the all CI’s pass. This will hopefully be fixed before this week’s meeting.</p></li> +<li><p><a class="reference external" href="https://github.com/fury-gl/fury/pull/442">Addressing all comments regarding #442</a> : Previously, it was pointed out that the some code can be extracted into a function and can be reused in other methods. So, this week the extracted method was updated to reuse even more code and now almost no code is repeated.</p></li> +<li><p><a class="reference external" href="https://github.com/fury-gl/fury/pull/441">Adding has_border flag in Panel2D</a> : Adding a has_border flag in Panel2D: Previously, to create the borders 4 Rectangle2D’s were used and they were created every time even when border_width was set to 0. This would take a lot of wasted system resources. To fix this, a flag is added in the the constructor which is by default set to False. If false, the borders are not initialized and the resources are saved.</p></li> +</ul> +</section> +<section id="did-i-get-stuck-anywhere"> +<h2>Did I get stuck anywhere?</h2> +<p>Fortunately, this week I didn’t get stuck anywhere.</p> +<p><strong>See you guys next week!</strong></p> +</section> +</section> + + + This week I had limited tasks to do, mostly tasks related to existing PRs. Other than some minor fixes I had to implement some more things in Tree2D which included some minor UI fixes, some changes in tutorial, adding tests. Below is the detailed description of what I worked on this week: + + 2021-07-19T00:00:00-04:00 + + + https://fury.gl/posts/2021/2021-07-12-week-6-antriksh.html + Week #6: Bug fixes, Working on Tree2D UI + 2021-07-12T00:00:00-04:00 + + Antriksh Misri + + <section id="week-6-bug-fixes-working-on-tree2d-ui"> + +<section id="what-did-i-do-this-week"> +<h2>What did I do this week?</h2> +<p>This week I had relatively few tasks and most of them were to fix some bugs/design flaws that were discussed in last week’s meeting. Other than that, I had to implement a few things in the Tree2D UI element that will be discussed in detail below. I also had to update some existing PRs in order to make things work well. Below are the list of things I worked on this week:</p> +<ul class="simple"> +<li><p><a class="reference external" href="https://github.com/fury-gl/fury/pull/459">Extracted Button2D class from elements to core</a> : Button2D was placed in elements during the UI restructuring. The problem with that was that Button2D was needed in other UI elements outside UI elements present in elements in Panel2D. So, it was decided to create a rule that only the UI elements that do not depend on any other UI element are allowed to be placed in core UI elements. Button2D does not depend on any other UI element so it was extracted from elements to core.</p></li> +<li><p><a class="reference external" href="https://github.com/fury-gl/fury/pull/443">Adapting GridLayout to work with UI elements</a> : This was a PR that aimed to add support for UI elements to be placed in a grid fashion. the problem was that there still some circular imports even after UI restructuring, primarily because UI was being imported in the layout module that in turn indirectly imported some UI elements making them circularly dependent. To remove the circular imports, it was decided to determine the UI element by checking for a add_to_scene method attribute in the instance. I updated the existing PR to implement the same.</p></li> +<li><p><a class="reference external" href="https://github.com/fury-gl/fury/pull/460">Continuing my work on Tree2D</a>: The Tree2D lacked some important things related to design and visual aspect of it. Before, if the children of any node exceeded its height they would just overflow. To prevent this I came up with a few solutions two of which were to either add a scrollbar on the overflowing node or to simply auto resize the parent node. Currently, there is no global API for the scrollbar and it has to be manually setup in a UI element, this will be hopefully implemented in the near future probably using layout management. Till then the auto resizing has been implemented for the nodes. In future, an option for scrollbar will be added.</p></li> +</ul> +</section> +<section id="did-i-get-stuck-anywhere"> +<h2>Did I get stuck anywhere?</h2> +<p>I am still stuck with adding tests for panel resizing PR. As it needs windows events to be recorded as well. I tried to propagate the event to the interactor first but that just lead to that particular event being registered multiple times. I will try to find a workaround for it.</p> +</section> +<section id="what-is-coming-up-next"> +<h2>What is coming up next?</h2> +<p>If the Tree2D gets merged by this week then I’ll probably work on other UI elements. Other tasks will be decided in the next meeting.</p> +<p><strong>See you guys next week!</strong></p> +</section> +</section> + + + This week I had relatively few tasks and most of them were to fix some bugs/design flaws that were discussed in last week’s meeting. Other than that, I had to implement a few things in the Tree2D UI element that will be discussed in detail below. I also had to update some existing PRs in order to make things work well. Below are the list of things I worked on this week: + + 2021-07-12T00:00:00-04:00 + + + https://fury.gl/posts/2021/2021-07-05-week-5-antriksh.html + Week #5: Rebasing all PRs w.r.t the UI restructuring, Tree2D, Bug Fixes + 2021-07-05T00:00:00-04:00 + + Antriksh Misri + + <section id="week-5-rebasing-all-prs-w-r-t-the-ui-restructuring-tree2d-bug-fixes"> + +<section id="what-did-i-do-this-week"> +<h2>What did I do this week?</h2> +<p>The UI restructuring was finally merged this week. This means UI is now a submodule in itself and provides different UI elements based on their types which are, core, elements, containers and some helper methods/classes. So, this week my main tasks were to rebase and fix merge conflicts of my open PR’s. Other than that, I had to continue my work on Tree2D UI element and finish the remaining aspects of it. Also, I had to create an example demonstrating how to use the newly added UI element. Many use cases were discussed in the open meeting like, an image gallery which displays preview image on the title and when expanded reveals the full scale image. I am thinking of adding multiple examples for the Tree2D to brainstorm on its certain features. Also, I had this annoying bug in Panel2D which didn’t allow it to be resized from the bottom right corner. It was resizing from the top right corner. I had to address this bug as well. Below are the tasks in detail:</p> +<ul> +<li><p><a class="reference external" href="https://github.com/fury-gl/fury/pulls/antrikshmisri">Rebasing all PRs w.r.t the UI restructuring</a>: As discussed in the earlier blogs, due to circular imports and large size of the UI module, a bit of restructuring was required. This week the PR that converts the UI into a sub module was finally merged. This meant I had to fix all the merge conflicts and rebase all UI related PR’s. So, I rebased all the UI related PR’s and fixed the merge conflicts. Currently, there are still some PR’s that need some attention as still some of the imports are circular in nature. This means if the issue is correct then some more restructuring is required, which will be hopefully done in the near future.</p></li> +<li><p><a class="reference external" href="https://github.com/antrikshmisri/fury/blob/86b16ba3f74c3bdcf9aab58f546b37b919254cd1/fury/ui/elements.py#L3278">Continuing the work on Tree2D</a> : This week I continued my work on Tree2D, TreeNode2D. I had to fix/add multiple features on both the classes but my priority was to fix the looks of the UI element as well as make it easier for the user to manipulate the UI element. The first thing that I fixed was node offsetting, when a node is collapsed and expanded the nodes below the current node should also offset. Previously, only the child nodes within the same parents were offset and not the nodes/parent beyond that. With some minor adjusting, now the nodes are offset recursively and all child/parent nodes below the current nodes are offset. Secondly, before only a node could be added to a node which meant it wasn’t any easy way to add any other UI element to a node but with some updates/fixes any UI element can be added to a node. Also, the Tree2D lacked some properties/methods to easily manipulate it. So, i added some properties/methods that allow to easily/efficiently manipulate individual node inside the Tree2D. Below is the current state of the Tree2D. In the below tree, two panels are added to a child node after the tree has been initialized. Also, the coordinated of the child elements are totally fluid i.e they can be placed anywhere inside the content panel by passing normalized or absolute coordinates.</p> +<blockquote> +<div><img alt="https://i.imgur.com/rQQvLqs.png" src="https://i.imgur.com/rQQvLqs.png" style="width: 200px; height: 200px;" /> +</div></blockquote> +</li> +<li><p>Fixed Panel2D bottom corner resizing: Previously, the panel would not resize from the bottom left corner but it would resize from top right corner. I didn’t understand what was going wrong and was stuck on this for a long time. But I finally figured out the problem, I was calculating the Y-offset wrong as well as the panel resized from the top side instead of bottom. With some minor tweaking the bug was gone and the panel resizes correctly from the bottom right corner.</p></li> +</ul> +</section> +<section id="did-i-get-stuck-anywhere"> +<h2>Did I get stuck anywhere?</h2> +<p>I got stuck on recording events for the updated panel UI element. The panel updates w.r.t the window size but I couldn’t figure out how to record the events invoked by the window. Unfortunately, I still haven’t figured out how this will be done. My guess is that I have to propagate the event first to the interactor and then to the UI element.</p> +</section> +<section id="what-is-coming-up-next"> +<h2>What is coming up next?</h2> +<p>I will probably finish up the GridLayout, Tree2D UI along side some other UI’s. This will be decided in the next meeting.</p> +<p><strong>See you guys next week!</strong></p> +</section> +</section> + + + The UI restructuring was finally merged this week. This means UI is now a submodule in itself and provides different UI elements based on their types which are, core, elements, containers and some helper methods/classes. So, this week my main tasks were to rebase and fix merge conflicts of my open PR’s. Other than that, I had to continue my work on Tree2D UI element and finish the remaining aspects of it. Also, I had to create an example demonstrating how to use the newly added UI element. Many use cases were discussed in the open meeting like, an image gallery which displays preview image on the title and when expanded reveals the full scale image. I am thinking of adding multiple examples for the Tree2D to brainstorm on its certain features. Also, I had this annoying bug in Panel2D which didn’t allow it to be resized from the bottom right corner. It was resizing from the top right corner. I had to address this bug as well. Below are the tasks in detail: + + 2021-07-05T00:00:00-04:00 + + + https://fury.gl/posts/2021/2021-06-28-week-4-antriksh.html + Week #4: Adding Tree UI to the UI module + 2021-06-28T00:00:00-04:00 + + Antriksh Misri + + <section id="week-4-adding-tree-ui-to-the-ui-module"> + +<section id="what-did-i-do-this-week"> +<h2>What did I do this week?</h2> +<p>This week I had very few tasks to do, almost all of them revolved around UI elements and adding stuff to the UI module. Earlier, it was pointed out that due to some design issues, importing certain modules into others caused circular imports which led to importing the specific modules inside a class/method which is not the best approach. This will be resolved as soon as the PR that fixes this issue is reviewed/merged in the codebase. In the meantime, all the PR’s related to UI will be on hold, which is why this I had few tasks this week. The tasks are described below in detail:</p> +<ul> +<li><p><a class="reference external" href="https://github.com/fury-gl/fury/pull/448">Addition of watcher class in UI</a> :This is finally done, as described in the previous blogs this was something that was on hold for a long time. Primarily, due to other tasks I couldn’t work on this but this week due to less tasks I was able to complete the watcher class and create a PR. This PR adds support for a watcher class in the UI elements. The purpose of this class is to monitor a particular attribute from the UI element after it has been added to the scene. If the attribute changes in the real time, a user defined callback is triggered and the scene is force rendered. Currently, if any attribute of the UI element changes after it is added to the scene it does not get updated accordingly. The only way to update the UI element would be to add a custom user hook that will be triggered when a particular event that can change the attribute is invoked. This is highly ambiguous as some unmonitored event can easily change many attributes of the UI element. Also it would be really hard to add user hooks for so many events. The watcher class does this automatically, it monitors the attribute for changes and if the attribute changes, a user defined callback is triggered. If this is something that is required in the UI module, then in the future a good addition would be to monitor the UI element instance as a whole instead of a single attribute .</p></li> +<li><p><a class="reference external" href="https://github.com/antrikshmisri/fury/blob/bb45d1c5b6fc0495dfe4d7814fab9aefbf9f7727/fury/ui.py#L5249">Addition of Tree UI in the UI module</a> : Another task for this week was to work on either Tree UI or the Accordion UI. I chose to work on Tree UI as it is very interesting to implement and the logic for Tree is almost similar to that of an Accordion. So far, I have managed to implement TreeNode2D. The Tree UI contains several nodes and each node can have its own sub-nodes/children. Also, each node has an expand/collapse button which can be used to chow/hide the underlying children. The Tree UI would take some sort of data structure that contains nodes/sub-nodes and convert each node to TreeNode2D and add all the processed node to the main Panel. So far this the result I have achieved:</p> +<blockquote> +<div><img alt="https://i.imgur.com/WIMWsrp.png" src="https://i.imgur.com/WIMWsrp.png" style="width: 200px; height: 200px;" /> +<img alt="https://i.imgur.com/u33D7Qi.png" src="https://i.imgur.com/u33D7Qi.png" style="width: 200px; height: 200px;" /> +</div></blockquote> +</li> +<li><p><a class="reference external" href="https://github.com/fury-gl/fury/pull/446">Resize Panel2D on window resizing</a> : This PR adds support for resizing Panel2D on WindowResizeEvent. This means that the Panle2D resizes itself with respect to the changed window size. It also retains its maximum possible size and does not overflow. Also, this PR adds support for resizing the Panel2D for the bottom right corner. A placeholder button is placed at the bottom right corner of the Panel2D and when it is dragged by the placeholder the Panel2D resize accordingly. Below is an example:</p> +<blockquote> +<div><img alt="https://i.imgur.com/87PN7TQ.gif" src="https://i.imgur.com/87PN7TQ.gif" style="width: 200px; height: 200px;" /> +</div></blockquote> +</li> +<li><p>Also, I did some testing of GridLayout when placed inside a resizable Panel2D. This will need to be worked on before advancing any further. Currently the elements present in the Panel2D do not resize properly w.r.t the changed panel size. Hopefully, this will be fixed in the future PRs.</p></li> +</ul> +</section> +<section id="did-i-get-stuck-anywhere"> +<h2>Did I get stuck anywhere?</h2> +<p>Fortunately, I did not get stuck this week.</p> +</section> +<section id="what-is-coming-up-next"> +<h2>What is coming up next?</h2> +<p>The tasks for the next week will be decided in this weeks meeting.</p> +<p><strong>See you guys next week!</strong></p> +</section> +</section> + + + This week I had very few tasks to do, almost all of them revolved around UI elements and adding stuff to the UI module. Earlier, it was pointed out that due to some design issues, importing certain modules into others caused circular imports which led to importing the specific modules inside a class/method which is not the best approach. This will be resolved as soon as the PR that fixes this issue is reviewed/merged in the codebase. In the meantime, all the PR’s related to UI will be on hold, which is why this I had few tasks this week. The tasks are described below in detail: + + 2021-06-28T00:00:00-04:00 + + + https://fury.gl/posts/2021/2021-06-21-week-3-antriksh.html + Week #3: Adapting GridLayout to work with UI + 2021-06-21T00:00:00-04:00 + + Antriksh Misri + + <section id="week-3-adapting-gridlayout-to-work-with-ui"> + +<section id="what-did-i-do-this-week"> +<h2>What did I do this week?</h2> +<p>This week my tasks revolved around layout and UI elements. The primary goal for this week was to adapt the GridLayout to work with different UI elements. Currently, GridLayout just supports vtk actors and not UI elements, my task was to modify the class to support UI elements. The other tasks for this week are described below in detail:</p> +<ul> +<li><p><a class="reference external" href="https://github.com/fury-gl/fury/pull/443">Adapt GridLayout to support UI elements</a> : This was the main task for the week and the aim for this was to actually modify GridLayout to support UI elements. This was not possible before because GridLayout only supported vtk actors (because of certain methods only being provided by vtk actors). I modified the main class itself along with some utility functions. The problem that I faced during this was circular imports. Currently, the structure of FURY doesn’t allow certain modules to be imported into other modules because of circular imports. A way to get around this was to actually import the modules inside the methods but this is not ideal always. This will be fixed in the future PRs where the UI module will be redesigned. I also added support for grid position offsetting, which basically means that the position of the UI elements that are placed in the Grid can be offset by a global offset passed in the constructor of GridLayout class. Below is an example showing the current state of GridLayout with different UI elements. I also created a brief example to demonstrate how to use GridLayout of different cellshapes with UI elements link to which is <a class="reference external" href="https://github.com/fury-gl/fury/pull/443/files#diff-853d17c3134e7d22de88523bb787dc05d52ec798dc2111aa0419dfd5d634350a">here</a>.</p> +<blockquote> +<div><img alt="https://i.imgur.com/EX2cN1i.png" src="https://i.imgur.com/EX2cN1i.png" style="width: 200px; height: 200px;" /> +</div></blockquote> +</li> +<li><p><a class="reference external" href="https://github.com/fury-gl/fury/pull/294">Reviewed the FileDialog2D PR</a> : This PR added support for FileDialog2D in the UI module. The PR needed to be reviewed in order to merge it as soon as other required PRs were merged. One of the mentors already reviewed the PR briefly my job was to review the PR for any remaining bugs.</p></li> +<li><p><a class="reference external" href="https://github.com/fury-gl/fury/pull/422">Study #422 PR to understand contours around the drawn markers</a> : In my previous week’s tasks I created a PR to add support for borders in Panel2D. The borders were individually customizable just like in CSS which meant 4 Rectangle2D objects were needed to represent border in each direction. This is not ideal for a scenario where a lot of Panel2D are present in the scene as it can be performance taxing. A possible solution for this was to actually look how this was implemented in the #422. This PR allowed drawing millions of markers in one call that too from the GPU. Interestingly, each marker had a contour surrounding it which is exactly what we needed for Panel2D. This is something that can be considered in the future for border implementation in other complex UI elements.</p></li> +<li><p>I also continued my work on the watcher class that I mentioned in the previous week’s blog. The work for this is almost done and just needs some tests implemented, which should be done soon.</p></li> +</ul> +</section> +<section id="did-i-get-stuck-anywhere"> +<h2>Did I get stuck anywhere?</h2> +<p>Fortunately, I did not get stuck this week.</p> +</section> +<section id="what-is-coming-up-next"> +<h2>What is coming up next?</h2> +<p>Next week I would probably continue to work on GridLayout and possibly other layouts as well, other tasks will be decided in the next meeting.</p> +<p><strong>See you guys next week!</strong></p> +</section> +</section> + + + This week my tasks revolved around layout and UI elements. The primary goal for this week was to adapt the GridLayout to work with different UI elements. Currently, GridLayout just supports vtk actors and not UI elements, my task was to modify the class to support UI elements. The other tasks for this week are described below in detail: + + 2021-06-21T00:00:00-04:00 + + diff --git a/v0.10.x/blog/author/bruno-messias.html b/v0.10.x/blog/author/bruno-messias.html new file mode 100644 index 000000000..439fe1d44 --- /dev/null +++ b/v0.10.x/blog/author/bruno-messias.html @@ -0,0 +1,1356 @@ + + + + + + + Posts by Bruno Messias — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +
+

+ + Posts by + + Bruno Messias + +

+ + +
+

+ Google Summer of Code 2021 - Final Report - Bruno Messias +

+
    +
  • + + + 23 August 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Bruno Messias + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

We have changed some points of my project in the first meeting. +Specifically, we focused the efforts into developing a streaming system +using the WebRTC protocol that could be used in more generic scenarios +than just the network visualization. In addition to that, we have opted +to develop the network visualization for fury as a separated repository +and package available here. The +name Helios was selected for this new network visualization system based +on the Fury rendering pipeline.

+

+ +

Read more ...

+
+
+ +
+

+ Week #11: Removing the flickering effect +

+
    +
  • + + + 16 August 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Bruno Messias + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

PR fury-gl/fury#489:

+

+ +

Read more ...

+
+
+ +
+

+ Week #10: SDF Fonts +

+
    +
  • + + + 09 August 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Bruno Messias + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

PR fury-gl/helios#22 +: Helios Documentation +Improvements.

+

+ +

Read more ...

+
+
+ +
+

+ Week #09: Sphinx custom summary +

+
    +
  • + + + 02 August 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Bruno Messias + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

PR fury-gl/helios#22 +: Helios Documentation +Improvements. +I’ve spent some time studying sphinx in order to discover how I could create a +custom summary inside of a template module.

+

+ +

Read more ...

+
+
+ +
+

+ Weekly Check-In #8 +

+
    +
  • + + + 26 July 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Bruno Messias + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

PR fury-gl/helios#18 (merged): Helios Documentation/ +I’ve been working on Helios documentation. Now it’s available +online at https://fury-gl.github.io/helios-website image1

+

+ +

Read more ...

+
+
+ +
+

+ Weekly Check-In #7 +

+
    +
  • + + + 19 July 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Bruno Messias + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

PR fury-gl/helios#16 +(merged): Helios IPC +network layout support for MacOs

+

+ +

Read more ...

+
+
+ +
+

+ Network layout algorithms using IPC +

+
    +
  • + + + 12 July 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Bruno Messias + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hi all. In the past weeks, I’ve been focusing on developing Helios; the +network visualization library for FURY. I improved the visual aspects of +the network rendering as well as implemented the most relevant network +layout methods.

+

+ +

Read more ...

+
+
+ +
+

+ Weekly Check-In #5 +

+
    +
  • + + + 05 July 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Bruno Messias + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Before the 8c670c2 commit, for some versions of MacOs the +streaming system was falling in a silent bug. I’ve spent a lot of +time researching to found a cause for this. Fortunately, I could found +the cause and the solution. This troublesome MacOs was falling in a +silent bug because the SharedMemory Object was creating a memory +resource with at least 4086 bytes independent if I’ve requested less +than that. If we look into the MultiDimensionalBuffer Object +(stream/tools.py) before the 8c670c2 commit we can see that Object +has max_size parameter which needs to be updated if the SharedMemory +was created with a “wrong” size.

+

+ +

Read more ...

+
+
+ +
+

+ SOLID, monkey patching a python issue and network visualization through WebRTC +

+
    +
  • + + + 05 July 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Bruno Messias + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

These past two weeks I’ve spent most of my time in the Streaming System +PR and the Network Layout +PR . In this post I’ll +focus on the most relevant things I’ve made for those PRs.

+

+ +

Read more ...

+
+
+ +
+

+ Weekly Check-In #3 +

+
    +
  • + + + 21 June 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Bruno Messias + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

PR fury-gl/fury#422 +(merged): +Integrated the 3d impostor spheres with the marker actor.

+

+ +

Read more ...

+
+
+ +
+

+ A Stadia-like system for data visualization +

+
    +
  • + + + 13 June 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Bruno Messias + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hi all! In this post I’ll talk about the PR +#437.

+

+ +

Read more ...

+
+
+ +
+

+ Weekly Check-In #1 +

+
    +
  • + + + 08 June 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Bruno Messias + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hi everyone! My name is Bruno Messias currently I’m a Ph.D student at +USP/Brazil. In this summer I’ll develop new tools and features for +FURY-GL. Specifically, I’ll focus into developing a system for +collaborative visualization of large network layouts using FURY and VTK.

+

+ +

Read more ...

+
+
+ + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/blog/author/bruno-messias/atom.xml b/v0.10.x/blog/author/bruno-messias/atom.xml new file mode 100644 index 000000000..a93e52447 --- /dev/null +++ b/v0.10.x/blog/author/bruno-messias/atom.xml @@ -0,0 +1,1298 @@ + + + https://fury.gl/ + Blog - Posts by Bruno Messias + 2024-02-29T15:43:57.394626+00:00 + + + ABlog + + https://fury.gl/posts/2021/2021-08-23-gsoc-devmessias-final-report.html + Google Summer of Code 2021 - Final Report - Bruno Messias + 2021-08-23T00:00:00-04:00 + + Bruno Messias + + <section id="google-summer-of-code-2021-final-report-bruno-messias"> + +<section id="abstract"> +<h2>Abstract</h2> +<p>We have changed some points of my project in the first meeting. +Specifically, we focused the efforts into developing a streaming system +using the WebRTC protocol that could be used in more generic scenarios +than just the network visualization. In addition to that, we have opted +to develop the network visualization for fury as a separated repository +and package available <a class="reference external" href="https://github.com/fury-gl/helios">here</a>. The +name Helios was selected for this new network visualization system based +on the Fury rendering pipeline.</p> +</section> +<section id="proposed-objectives"> +<h2>Proposed Objectives</h2> +<ul class="simple"> +<li><p>Create a streaming system (stadia-like) for FURY</p> +<ul> +<li><p>Should work in a low-bandwidth scenario</p></li> +<li><p>Should allow user interactions and collaboration across the +Internet using a web-browser</p></li> +</ul> +</li> +<li><p>Helios Network System objectives:</p> +<ul> +<li><p>Implement the Force-Directed Algorithm with examples</p></li> +<li><p>Implement the ForceAtlas2 algorithm using cugraph with examples</p></li> +<li><p>Implement Minimum-Distortion Embeddings algorithm (PyMDE) and +examples</p></li> +<li><p>Non-blocking network algorithms computation avoiding the GIL using +the Shared Memory approach</p></li> +<li><p>Create the documentation and the actions for the CI</p></li> +</ul> +</li> +<li><p>Stretch Goals:</p> +<ul> +<li><p>Create an actor in FURY to draw text efficiently using shaders</p></li> +<li><p>Add support to draw millions of nodes using FURY</p></li> +<li><p>Add support to control the opengl state on FURY</p></li> +</ul> +</li> +</ul> +</section> +<section id="objectives-completed"> +<h2>Objectives Completed</h2> +<ul> +<li><p class="rubric" id="create-a-streaming-system-stadia-like-for-fury">Create a streaming system (stadia-like) for FURY</p> +<p>To construct the streaming system for my project we have opted to +follow three main properties and behaviors:</p> +<ol class="arabic simple"> +<li><p>avoid blocking the code execution in the main thread (where the +vtk/fury instance resides)</p></li> +<li><p>work inside of a low bandwidth environment</p></li> +<li><p>make it easy and cheap to share the rendering result. For example, +using the free version of <code class="docutils literal notranslate"><span class="pre">ngrok</span></code></p></li> +</ol> +<p>To achieve the first property we need to circumvent the GIL and allow +python code to execute in parallel. Using the threading module alone +is not good enough to reach real parallelism as Python calls in the +same process can not execute concurrently. In addition to that, to +achieve better organization it is desirable to define the server +system as an uncoupled module from the rendering pipeline. Therefore, +I have chosen to employ the multiprocessing approach for that. The +second and third property can be only achieved choosing a suitable +protocol for transferring the rendered results to the client. We have +opted to implement two streaming protocols: the MJPEG and the WebRTC. +The latter is more suitable for low-bandwidth scenarios [1].</p> +<p>The image below shows a simple representation of the streaming +system.</p> +</li> +</ul> + <center> + <img alt="..." height="400" + src="https://user-images.githubusercontent.com/6979335/121934889-33ff1480-cd1e-11eb-89a4-562fbb953ba4.png"/> + </center> + +The video below shows how our streaming system works smothly and can +be easily integrated inside of a Jupyter notebook.<p><a class="reference external" href="https://user-images.githubusercontent.com/6979335/130284952-2ffbf117-7119-4048-b7aa-428e0162fb7a.mp4">Video: WebRTC Streaming + +Ngrok</a></p> +<p><a class="reference external" href="https://user-images.githubusercontent.com/6979335/130284261-20e84622-427e-4a59-a46f-6a33f5473025.mp4">Video: WebRTC Streaming + +Jupyter</a></p> +<p><em>Pull Requests:</em> * <a class="github reference external" href="https://github.com/fury-gl/fury/pull/480">fury-gl/fury#480</a></p> +<ul> +<li><p class="rubric" id="d-and-3d-marker-actor">2D and 3D marker actor</p> +<p>This feature gave FURY the ability to efficiently draw millions of +markers and impostor 3D spheres. This feature was essential for the +development of Helios. This feature work with signed distance fields +(SDFs) you can get more information about how SDFs works here [4] .</p> +<p>The image below shows 1 million of markers rendered using an Intel +HD graphics 3000.</p> +</li> +</ul> +<center> + <img src="https://user-images.githubusercontent.com/6979335/116004971-70927780-a5db-11eb-8363-8c0757574eb4.png"/> +</center><ul> +<li><p class="rubric" id="fine-tunning-the-opengl-state">Fine-Tunning the OpenGl State</p> +<p>Sometimes users may need to have finer control on how OpenGL will +render the actors. This can be useful when they need to create +specialized visualization effects or to improve the performance.</p> +<p>In this PR I have worked in a feature that allows FURY to control the +OpenGL context created by VTK</p> +<p><em>Pull Request:</em></p> +<ul class="simple"> +<li><p><a class="github reference external" href="https://github.com/fury-gl/fury/pull/432">fury-gl/fury#432</a></p></li> +</ul> +</li> +<li><p class="rubric" id="helios-network-visualization-lib-network-layout-algorithms">Helios Network Visualization Lib: Network Layout +Algorithms</p> +<p><strong>Case 1:</strong> Suppose that you need to monitor a hashtag and build a +social graph. You want to interact with the graph and at the same +time get insights about the structure of the user interactions. To +get those insights you can perform a node embedding using any kind of +network layout algorithm, such as force-directed or minimum +distortion embeddings.</p> +<p><strong>Case 2:</strong> Suppose that you are modelling a network dynamic such as +an epidemic spreading or a Kuramoto model. In some of those network +dynamics a node can change the state and the edges related to the +node must be deleted. For example, in an epidemic model a node can +represent a person who died due to a disease. Consequently, the +layout of the network must be recomputed to give better insights.</p> +<p>In the described cases, if we want a better (UX) and at the same time +a more practical and insightful application of Helios, the employed +layout algorithms should not block any kind of computation in the +main thread.</p> +<p>In Helios we already have a lib written in C (with a python wrapper) +which performs the force-directed layout algorithm using separated +threads avoiding the GIL problem and consequently avoiding blocking +the main thread. But what about the other open-source network layout +libs available on the internet? Unfortunately, most of those libs +have not been implemented like Helios force-directed methods and +consequently, if we want to update the network layout the Python +interpreter will block the computation and user interaction in your +network visualization.</p> +<p>My solution for having PyMDE and CuGraph-ForceAtlas not blocking the +main thread was to break the network layout method into two different +types of processes: A and B and communicate both process using the +Shared Memory approach. You can more information about this PR +through my following posts [2], [3].</p> +</li> +</ul> +<p>The image below show an example that I made and is available at +<a class="github reference external" href="https://github.com/fury-gl/helios/blob/main/docs/examples/viz_mde.py">fury-gl/helios</a></p> +<p><img alt="image2" src="https://user-images.githubusercontent.com/6979335/125310065-a3a9f480-e308-11eb-98d9-0ff5406a0e96.gif" /> <em>Pull Requests:</em></p> +<ul> +<li><p><strong>MDE Layout:</strong> <a class="github reference external" href="https://github.com/fury-gl/helios/pull/6">fury-gl/helios#6</a></p></li> +<li><p><strong>CuGraph ForceAtlas2</strong> <a class="github reference external" href="https://github.com/fury-gl/helios/pull/13">fury-gl/helios#13</a></p></li> +<li><p><strong>Force-Directed and MDE improvements</strong> +<a class="github reference external" href="https://github.com/fury-gl/helios/pull/14">fury-gl/helios#14</a></p></li> +<li><p class="rubric" id="helios-network-visualization-lib-visual-aspects">Helios Network Visualization Lib: Visual Aspects</p> +</li> +</ul> +<p>I’ve made several stuffs to give Helios a better visual aspects. One of +them was to give a smooth real-time network layout animations. Because +the layout computations happens into a different process that the +process responsible to render the network was necessary to record the +positions and communicate the state of layout between both process.</p> +<p>The GIF below shows how the network layout through IPC behaved before +these modification</p> +<center> +<img src="https://user-images.githubusercontent.com/6979335/125310065-a3a9f480-e308-11eb-98d9-0ff5406a0e96.gif"/> +</center><p>below, you can see how after those modifications the visual aspect is +better.</p> +<center> +<img alt="..." height="300" +src="https://user-images.githubusercontent.com/6979335/126175583-c7d85f0a-3d0c-400e-bbdd-4cbcd2a36fed.gif"/> +</center><p><em>Pull Requests:</em></p> +<ul> +<li><p><strong>OpenGL SuperActors:</strong> <a class="github reference external" href="https://github.com/fury-gl/helios/pull/1">fury-gl/helios#1</a></p></li> +<li><p><strong>Fixed the flickering effect</strong> +<a class="github reference external" href="https://github.com/fury-gl/helios/pull/10">fury-gl/helios#10</a></p></li> +<li><p><strong>Improvements in the network node visual aspects</strong> +<a class="github reference external" href="https://github.com/fury-gl/helios/pull/15">fury-gl/helios#15</a></p></li> +<li><p><strong>Smooth animations when using IPC layouts</strong> +<a class="github reference external" href="https://github.com/fury-gl/helios/pull/17">fury-gl/helios#17</a></p></li> +<li><p class="rubric" id="helios-network-visualization-lib-ci-and-documentation">Helios Network Visualization Lib: CI and Documentation</p> +</li> +</ul> +<p>Because Helios was an project that begins in my GSoC project It was +necessary to create the documentation, hosting and more. Now we have a +online documentation available at <a class="reference external" href="https://heliosnetwork.io/">https://heliosnetwork.io/</a> although the +documentation still need some improvements.</p> +<p>The Helios Logo which was developed by +Filipi Nascimento.</p> +<img alt="Helios Network Logo" height="100" src="https://fury-gl.github.io/helios-website/_images/logo.png"/><p><em>Pull Requests:</em></p> +<ul> +<li><p><strong>CI and pytests:</strong> <a class="github reference external" href="https://github.com/fury-gl/helios/pull/5">fury-gl/helios#5</a>, +<a class="github reference external" href="https://github.com/fury-gl/helios/pull/20">fury-gl/helios#20</a></p></li> +<li><p><strong>Helios Logo, Sphinx Gallery and API documentation</strong> +<a class="github reference external" href="https://github.com/fury-gl/helios/pull/18">fury-gl/helios#18</a></p></li> +<li><p><strong>Documentation improvements:</strong> +<a class="github reference external" href="https://github.com/fury-gl/helios/pull/8">fury-gl/helios#8</a></p></li> +<li><p class="rubric" id="objectives-in-progress">Objectives in Progress</p> +</li> +<li><p class="rubric" id="draw-texts-on-fury-and-helios">Draw texts on FURY and Helios</p> +<p>This two PRs allows FURY and Helios to draw millions of characters in +VTK windows instance with low computational resources consumptions. I +still working on that, finishing the SDF font rendering which the +theory behinds was developed here [5].</p> +<p><em>Pull Requests:</em></p> +<ul> +<li><p><a class="github reference external" href="https://github.com/fury-gl/helios/pull/24">fury-gl/helios#24</a></p></li> +<li><p><a class="github reference external" href="https://github.com/fury-gl/fury/pull/489">fury-gl/fury#489</a></p> +<center> +<img alt="..." height="400" src="https://user-images.githubusercontent.com/6979335/129643743-6cb12c06-3415-4a02-ba43-ccc97003b02d.png"/> +</center></li> +</ul> +</li> +<li><p class="rubric" id="gsoc-weekly-blogs">GSoC weekly Blogs</p> +<p>Weekly blogs were added to the FURY Website.</p> +<p><em>Pull Requests:</em></p> +<ul class="simple"> +<li><p><strong>First Evaluation:</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/476">fury-gl/fury#476</a></p></li> +<li><p><strong>Second Evaluation:</strong> TBD</p></li> +</ul> +</li> +</ul> +</section> +<section id="timeline"> +<h2>Timeline</h2> +<table class="table"> +<thead> +<tr class="row-odd"><th class="head"><p>Date</p></th> +<th class="head"><p>Description</p></th> +<th class="head"><p>Blog Link</p></th> +</tr> +</thead> +<tbody> +<tr class="row-even"><td><p>Week 1 +(08-06-2021)</p></td> +<td><p>Welcome to my weekly Blogs!</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/demvessiass-blog/weekly-check-in-1-21/">Weekly Check-in +#1</a></p></td> +</tr> +<tr class="row-odd"><td><p>Week 2 +(14-06-2021)</p></td> +<td><p>Post #1: A Stadia-like +system for data +visualization</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/demvessiass-blog/post-1-a-stadia-like-system-for-data-visualization/">Weekly Check-in +# +2</a></p></td> +</tr> +<tr class="row-even"><td><p>Week 3 +(21-06-2021)</p></td> +<td><p>2d and 3d fake impostors +marker; fine-tunning +open-gl state; Shared +Memory support for the +streaming system; +first-version of helios: +the network visualization +lib for helios</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/demvessiass-blog/weekly-check-in-3-15/">Weekly Check-in +#3</a></p></td> +</tr> +<tr class="row-odd"><td><p>Week 4 +(28-06-2020)</p></td> +<td><p>Post #2: SOLID, monkey +patching a python issue and +network layouts through +WebRTC</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/demvessiass-blog/post-2-solid-monkey-patching-a-python-issue-and-network-layouts-through-webrtc/">Weekly Check-in +#4</a></p></td> +</tr> +<tr class="row-even"><td><p>Week 5 +(05-07-2021)</p></td> +<td><p>Code refactoring; 2d +network layouts for Helios; +Implemented the Minimum +distortion embedding +algorithm using the IPC +approach</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/demvessiass-blog/weekly-check-in-5-14/">Weekly Check-in +#5</a></p></td> +</tr> +<tr class="row-odd"><td><p>Week 6 +(12-07-2020)</p></td> +<td><p>Post #3: Network layout +algorithms using IPC</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/demvessiass-blog/post-3-network-layout-algorithms-using-ipc/">Weekly Check-in +#6</a></p></td> +</tr> +<tr class="row-even"><td><p>Week 7 +(19-07-2020)</p></td> +<td><p>Helios IPC network layout +algorithms support for +MacOs; Smooth animations +for IPC layouts; +ForceAtlas2 network layout +using cugraph/cuda</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/demvessiass-blog/weekly-check-in-7-14/">Weekly Check-in +#7</a></p></td> +</tr> +<tr class="row-odd"><td><p>Week 8 +(26-07-2020)</p></td> +<td><p>Helios CI, Helios +documentation</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/demvessiass-blog/weekly-check-in-8-9/">Weekly Check-in +#8</a></p></td> +</tr> +<tr class="row-even"><td><p>Week 9 +(02-08-2020)</p></td> +<td><p>Helios documentation; +improved the examples and +documentation of the WebRTC +streaming system and made +some improvements in the +compatibility removing some +dependencies</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/demvessiass-blog/weekly-check-in-9-16/">Weekly Check-in +#9</a></p></td> +</tr> +<tr class="row-odd"><td><p>Week 10 +(09-08-2020)</p></td> +<td><p>Helios documentation +improvements; found and +fixed a bug in fury w.r.t. +the time management system; +improved the memory +management system for the +network layout algorithms +using IPC</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/demvessiass-blog/weekly-check-in-10-12/">Weekly Check-in +#10</a></p></td> +</tr> +<tr class="row-even"><td><p>Week 11 +(16-08-2020)</p></td> +<td><p>Created a PR that allows +FURY to draw hundred of +thousands of characters +without any expensive GPU; +fixed the flickering effect +on the streaming system; +helios node labels feature; +finalizing remaining PRs</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/demvessiass-blog/weekly-check-in-11-13/">Weekly Check-in +#11</a></p></td> +</tr> +</tbody> +</table> +<p>Detailed weekly tasks, progress and work done can be found +<a class="reference external" href="https://blogs.python-gsoc.org/en/demvessiass-blog/">here</a>.</p> +<section id="references"> +<h3>References</h3> +<p>[1] ( Python GSoC - Post #1 - A Stadia-like system for data +visualization - demvessias s Blog, n.d.; +<a class="reference external" href="https://blogs.python-gsoc.org/en/demvessiass-blog/post-1-a-stadia-like-system-for-data-visualization/">https://blogs.python-gsoc.org/en/demvessiass-blog/post-1-a-stadia-like-system-for-data-visualization/</a></p> +<p>[2] Python GSoC - Post #2: SOLID, monkey patching a python issue and +network layouts through WebRTC - demvessias s Blog, n.d.; +<a class="reference external" href="https://blogs.python-gsoc.org/en/demvessiass-blog/post-2-solid-monkey-patching-a-python-issue-and-network-layouts-through-webrtc/">https://blogs.python-gsoc.org/en/demvessiass-blog/post-2-solid-monkey-patching-a-python-issue-and-network-layouts-through-webrtc/</a></p> +<p>[3] Python GSoC - Post #3: Network layout algorithms using IPC - +demvessias s Blog, +n.d.)https://blogs.python-gsoc.org/en/demvessiass-blog/post-3-network-layout-algorithms-using-ipc/</p> +<p>[4] Rougier, N.P., 2018. An open access book on Python, OpenGL and +Scientific Visualization [WWW Document]. An open access book on Python, +OpenGL and Scientific Visualization. URL +<a class="github reference external" href="https://github.com/rougier/python-opengl">rougier/python-opengl</a> (accessed 8.21.21).</p> +<p>[5] Green, C., 2007. Improved alpha-tested magnification for vector +textures and special effects, in: ACM SIGGRAPH 2007 Courses on - +SIGGRAPH ’07. Presented at the ACM SIGGRAPH 2007 courses, ACM Press, San +Diego, California, p. 9. <a class="reference external" href="https://doi.org/10.1145/1281500.1281665">https://doi.org/10.1145/1281500.1281665</a></p> +</section> +</section> +</section> + + + We have changed some points of my project in the first meeting. +Specifically, we focused the efforts into developing a streaming system +using the WebRTC protocol that could be used in more generic scenarios +than just the network visualization. In addition to that, we have opted +to develop the network visualization for fury as a separated repository +and package available here. The +name Helios was selected for this new network visualization system based +on the Fury rendering pipeline. + + 2021-08-23T00:00:00-04:00 + + + https://fury.gl/posts/2021/2021-16-08-gsoc-devmessias-11.html + Week #11: Removing the flickering effect + 2021-08-16T00:00:00-04:00 + + Bruno Messias + + <section id="week-11-removing-the-flickering-effect"> + +<section id="what-did-i-do-this-week"> +<h2>What did I do this week?</h2> +<section id="fury"> +<h3>FURY</h3> +<ul class="simple"> +<li><p><a class="reference external" href="https://github.com/fury-gl/fury/pull/489">PR fury-gl/fury#489:</a></p></li> +</ul> +<blockquote> +<div><p>This PR give to FURY three +pre-built texture maps using different fonts. However, is quite easy +to create new fonts to be used in a visualization.</p> +</div></blockquote> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2021/2021-16-08-gsoc-devmessias-11.rst</span>, line 20)</p> +<p>Block quote ends without a blank line; unexpected unindent.</p> +</aside> +<div class="line-block"> +<div class="line">It’s was quite hard to develop the shader code and find the correct +positions of the texture maps to be used in the shader. Because we +used the freetype-py to generate the texture and packing the glyps. +However, the lib has some examples with bugs. But fortunelly, now +everything is woking on FURY. I’ve also created two different examples +to show how this PR works.</div> +</div> +<blockquote> +<div><p>The first example, viz_huge_amount_of_labels.py, shows that the user can +draw hundreds of thousands of characters.</p> +<p><img alt="image2" src="https://user-images.githubusercontent.com/6979335/129643743-6cb12c06-3415-4a02-ba43-ccc97003b02d.png" /></p> +<p>The second example, viz_billboad_labels.py, shows the different behaviors of the label actor. In addition, presents +to the user how to create a new texture atlas font to be used across different visualizations.</p> +</div></blockquote> +<ul> +<li><p><a class="reference external" href="https://github.com/fury-gl/fury/pull/437">PR fury-gl/fury#437:</a></p> +<ul> +<li><dl class="simple"> +<dt>Fix: avoid multiple OpenGl context on windows using asyncio</dt><dd><p>The streaming system must be generic, but opengl and vtk behaves in uniques ways in each Operating System. Thus, can be tricky +to have the same behavior acrros different OS. One hard stuff that we founded is that was not possible to use my +TimeIntervals objects (implemented with threading module) with vtk. The reason for this impossibility is because we can’t use +vtk in windows in different threads. But fortunely, moving from the threading (multithreading) to the asyncio approcach (concurrency) +have fixed this issue and now the streaming system is ready to be used anywhere.</p> +</dd> +</dl> +</li> +<li><p>Flickering:</p> +<blockquote> +<div><p>Finally, I could found the cause of the flickering effect on the streaming system. +This flickering was appearing only when the streaming was created using the Widget object. +The cause seems to be a bug or a strange behavior from vtk. +Calling iren.MouseWheelForwardEvent() or iren.MouseWheelBackwardEvent() +inside of a thread without invoking the +Start method from a vtk instance produces a memory corruption. +Fortunately, I could fix this behavior and now the streaming system is +working without this glitch effect.</p> +</div></blockquote> +</li> +</ul> +</li> +</ul> +</section> +<section id="fury-helios"> +<h3>FURY/Helios</h3> +<ul class="simple"> +<li><p><a class="reference external" href="https://github.com/fury-gl/helios/pull/24">PR fury-gl/helios#24 +:</a></p></li> +</ul> +<p>This uses the +<a class="reference external" href="https://github.com/fury-gl/fury/pull/489">PRfury-gl/fury#489:</a> to +give the network label feature to helios. Is possible to draw node +labels, update the colors, change the positions at runtime. In addition, +when a network layout algorithm is running this will automatically +update the node labels positions to follow the nodes across the screen.</p> +<p><img alt="image1" src="https://user-images.githubusercontent.com/6979335/129642582-fc6785d8-0e4f-4fdd-81f4-b2552e1ff7c7.png" /></p> +<ul class="simple"> +<li><p><a class="reference external" href="https://github.com/fury-gl/helios/pull/23">PR fury-gl/helios#23: +Merged.</a></p></li> +</ul> +<p>This PR granted compatibility between IPC Layouts and Windows. Besides +that , now is quite easier to create new network layouts using inter +process communication</p> +</section> +</section> +<section id="did-i-get-stuck-anywhere"> +<h2>Did I get stuck anywhere?</h2> +<p>I did not get stuck this week.</p> +</section> +</section> + + + PR fury-gl/fury#489: + + 2021-08-16T00:00:00-04:00 + + + https://fury.gl/posts/2021/2021-09-08-gsoc-devmessias-10.html + Week #10: SDF Fonts + 2021-08-09T00:00:00-04:00 + + Bruno Messias + + <section id="week-10-sdf-fonts"> + +<section id="what-did-i-do-this-week"> +<h2>What did I do this week?</h2> +<section id="fury-helios"> +<h3>FURY/Helios</h3> +<ul class="simple"> +<li><p><a class="reference external" href="https://github.com/fury-gl/helios/pull/22">PR fury-gl/helios#22 +:</a> Helios Documentation +Improvements.</p></li> +<li><p><a class="reference external" href="https://github.com/fury-gl/helios/pull/23">PR fury-gl/helios#23:</a> +A PR that makes helios IPCLayout system compatible with Windows.</p></li> +</ul> +</section> +<section id="fury"> +<h3>FURY</h3> +<ul class="simple"> +<li><p><a class="reference external" href="https://github.com/fury-gl/fury/pull/484">PR fury-gl/fury#484: I’ve found and fixed a bug in FURY time +management system</a></p></li> +<li><p><a class="reference external" href="https://github.com/fury-gl/fury/pull/437">PR fury-gl/fury#437:</a></p> +<ul> +<li><p>Fixed the tests on Windows</p></li> +<li><p>Improve the streaming memory management system for IPC +communication</p></li> +</ul> +</li> +<li><p>I’ve developing a feature that will allows FURY to draw hundreds +thousands of labels using texture maps and signed distance functions. +Until now I’ve a sketch that at least is able to draw the labels +using the markers billboards and bitmap fonts <img alt="image1" src="https://user-images.githubusercontent.com/6979335/128761833-53f53e2c-5bc0-4ff3-93c4-0ad01dc7d8eb.png" /></p></li> +<li><p><a class="reference external" href="https://github.com/fury-gl/fury/pull/432">PR fury-gl/fury#432:</a> +minor improvements</p></li> +<li><p><a class="reference external" href="https://github.com/fury-gl/fury/pull/474">PR #474</a> Helped to +review this PR</p></li> +</ul> +</section> +</section> +<section id="did-i-get-stuck-anywhere"> +<h2>Did I get stuck anywhere?</h2> +<p>I did not get stuck this week.</p> +</section> +<section id="what-is-coming-up-next"> +<h2>What is coming up next?</h2> +<p>I’ll discuss that with my mentors tomorrow.</p> +</section> +</section> + + + PR fury-gl/helios#22 +: Helios Documentation +Improvements. + + 2021-08-09T00:00:00-04:00 + + + https://fury.gl/posts/2021/2021-08-02-gsoc-devmessias-9.html + Week #09: Sphinx custom summary + 2021-08-02T00:00:00-04:00 + + Bruno Messias + + <section id="week-09-sphinx-custom-summary"> + +<section id="what-did-i-do-this-week"> +<h2>What did I do this week?</h2> +<section id="fury-helios"> +<h3>FURY/Helios</h3> +<ul class="simple"> +<li><p><a class="reference external" href="https://github.com/fury-gl/helios/pull/22">PR fury-gl/helios#22 +:</a> Helios Documentation +Improvements. +I’ve spent some time studying sphinx in order to discover how I could create a +custom summary inside of a template module.</p></li> +</ul> +</section> +<section id="fury"> +<h3>FURY</h3> +<p>Added my GSoC blogs to the FURY blogs as requested by my mentors. +- <a class="reference external" href="https://github.com/fury-gl/fury/pull/437">PR fury-gl/fury#437:</a></p> +<blockquote> +<div><ul class="simple"> +<li><p>Docstrings improvements</p></li> +<li><p>Covered more tests</p></li> +<li><p>Covered tests using optional dependencies.</p></li> +<li><p>Aiortc now it’s not a mandatory dependency</p></li> +<li><p>improvements in memory management</p></li> +</ul> +</div></blockquote> +<ul class="simple"> +<li><p>PR #432 Fixed some typos, improved the tests and docstrings</p></li> +<li><p><a class="reference external" href="https://github.com/fury-gl/fury/pull/474">PR fury-gl/fury#474:</a></p></li> +<li><p>Helped to review and made some suggestions to the PR #474 made by &#64;mehabhalodiya.</p></li> +</ul> +</section> +</section> +<section id="did-i-get-stuck-anywhere"> +<h2>Did I get stuck anywhere?</h2> +<p>I did not get stuck this week.</p> +</section> +<section id="what-is-coming-up-next"> +<h2>What is coming up next?</h2> +<p>I’ll discuss that with my mentors tomorrow.</p> +</section> +</section> + + + PR fury-gl/helios#22 +: Helios Documentation +Improvements. +I’ve spent some time studying sphinx in order to discover how I could create a +custom summary inside of a template module. + + 2021-08-02T00:00:00-04:00 + + + https://fury.gl/posts/2021/2021-07-26-gsoc-devmessias-8.html + Weekly Check-In #8 + 2021-07-26T00:00:00-04:00 + + Bruno Messias + + <section id="weekly-check-in-8"> + +<section id="what-did-i-do-this-week"> +<h2>What did I do this week?</h2> +<ul class="simple"> +<li><p><a class="reference external" href="https://github.com/fury-gl/helios/pull/18">PR fury-gl/helios#18 (merged):</a> Helios Documentation/ +I’ve been working on Helios documentation. Now it’s available +online at <a class="reference external" href="https://fury-gl.github.io/helios-website">https://fury-gl.github.io/helios-website</a> <img alt="image1" src="https://fury-gl.github.io/helios-website/_images/logo.png" /></p></li> +<li><p><a class="reference external" href="https://github.com/fury-gl/helios/pull/17">PR fury-gl/helios#17 (merged):</a> Helios CI for tests and code +coverage</p></li> +</ul> +</section> +<section id="did-i-get-stuck-anywhere"> +<h2>Did I get stuck anywhere?</h2> +<p>I did not get stuck this week.</p> +</section> +<section id="what-is-coming-up-next"> +<h2>What is coming up next?</h2> +<p>I’ll discuss that with my mentors tomorrow.</p> +</section> +</section> + + + PR fury-gl/helios#18 (merged): Helios Documentation/ +I’ve been working on Helios documentation. Now it’s available +online at https://fury-gl.github.io/helios-website image1 + + 2021-07-26T00:00:00-04:00 + + + https://fury.gl/posts/2021/2021-07-19-gsoc-devmessias-7.html + Weekly Check-In #7 + 2021-07-19T00:00:00-04:00 + + Bruno Messias + + <section id="weekly-check-in-7"> + +<section id="what-did-i-do-this-week"> +<h2>What did I do this week?</h2> +<ul> +<li><p><a class="reference external" href="https://github.com/fury-gl/helios/pull/16">PR fury-gl/helios#16 +(merged):</a> Helios IPC +network layout support for MacOs</p></li> +<li><p><a class="reference external" href="https://github.com/fury-gl/helios/pull/17">PR fury-gl/helios#17 +(merged):</a> Smooth +animations for IPC network layout algorithms</p> +<p>Before this commit was not possible to record the positions to have a +smooth animations with IPCLayout approach. See the animation below</p> +<p><img alt="image1" src="https://user-images.githubusercontent.com/6979335/126175596-e6e2b415-bd79-4d99-82e7-53e10548be8c.gif" /></p> +<p>After this PR now it’s possible to tell Helios to store the evolution +of the network positions using the record_positions parameter. This +parameter should be passed on the start method. Notice in the image +below how this gives to us a better visualization</p> +<p><img alt="image2" src="https://user-images.githubusercontent.com/6979335/126175583-c7d85f0a-3d0c-400e-bbdd-4cbcd2a36fed.gif" /></p> +</li> +<li><p><a class="reference external" href="https://github.com/fury-gl/helios/pull/13">PR fury-gl/helios#13 +(merged)</a> Merged the +forceatlas2 cugraph layout algorithm</p></li> +</ul> +</section> +<section id="did-i-get-stuck-anywhere"> +<h2>Did I get stuck anywhere?</h2> +<p>I did not get stuck this week.</p> +</section> +<section id="what-is-coming-up-next"> +<h2>What is coming up next?</h2> +<p>Probably, I’ll work more on Helios. Specifically I want to improve the +memory management system. It seems that some shared memory resources are +not been released when using the IPCLayout approach.</p> +</section> +</section> + + + PR fury-gl/helios#16 +(merged): Helios IPC +network layout support for MacOs + + 2021-07-19T00:00:00-04:00 + + + https://fury.gl/posts/2021/2021-07-12-gsoc-devmessias-6.html + Network layout algorithms using IPC + 2021-07-12T00:00:00-04:00 + + Bruno Messias + + <section id="network-layout-algorithms-using-ipc"> + +<p>Hi all. In the past weeks, I’ve been focusing on developing Helios; the +network visualization library for FURY. I improved the visual aspects of +the network rendering as well as implemented the most relevant network +layout methods.</p> +<p>In this post I will discuss the most challenging task that I faced to +implement those new network layout methods and how I solved it.</p> +<section id="the-problem-network-layout-algorithm-implementations-with-a-blocking-behavior"> +<h2>The problem: network layout algorithm implementations with a blocking behavior</h2> +<p><strong>Case 1:</strong> Suppose that you need to monitor a hashtag and build a +social graph. You want to interact with the graph and at the same time +get insights about the structure of the user interactions. To get those +insights you can perform a node embedding using any kind of network +layout algorithm, such as force-directed or minimum distortion +embeddings.</p> +<p><strong>Case 2:</strong> Suppose that you are modelling a network dynamic such as an +epidemic spreading or a Kuramoto model. In some of those network +dynamics a node can change the state and the edges related to the node +must be deleted. For example, in an epidemic model a node can represent +a person who died due to a disease. Consequently, the layout of the +network must be recomputed to give better insights.</p> +<p>In described cases if we want a better (UX) and at the same time a more +practical and insightful application of Helios layouts algorithms +shouldn’t block any kind of computation in the main thread.</p> +<p>In Helios we already have a lib written in C (with a python wrapper) +which performs the force-directed layout algorithm using separated +threads avoiding the GIL problem and consequently avoiding the blocking. +But and the other open-source network layout libs available on the +internet? Unfortunately, most of those libs have not been implemented +like Helios force-directed methods and consequently, if we want to +update the network layout the python interpreter will block the +computation and user interaction in your network visualization. How to +solve this problem?</p> +</section> +<section id="why-is-using-the-python-threading-is-not-a-good-solution"> +<h2>Why is using the python threading is not a good solution?</h2> +<p>One solution to remove the blocking behavior of the network layout libs +like PyMDE is to use the threading module from python. However, remember +the GIL problem: only one thread can execute python code at once. +Therefore, this solution will be unfeasible for networks with more than +some hundreds of nodes or even less! Ok, then how to solve it well?</p> +</section> +<section id="ipc-using-python"> +<h2>IPC using python</h2> +<p>As I said in my previous posts I’ve created a streaming system for data +visualization for FURY using webrtc. The streaming system is already +working and an important piece in this system was implemented using the +python SharedMemory from multiprocessing. We can get the same ideas from +the streaming system to remove the blocking behavior of the network +layout libs.</p> +<p>My solution to have PyMDE and CuGraph-ForceAtlas without blocking was to +break the network layout method into two different types of processes: A +and B. The list below describes the most important behaviors and +responsibilities for each process</p> +<p><strong>Process A:</strong></p> +<ul class="simple"> +<li><p>Where the visualization (NetworkDraw) will happen</p></li> +<li><p>Create the shared memory resources: edges, weights, positions, info..</p></li> +<li><p>Check if the process B has updated the shared memory resource which +stores the positions using the timestamp stored in the info_buffer</p></li> +<li><p>Update the positions inside of NetworkDraw instance</p></li> +</ul> +<p><strong>Process B:</strong></p> +<ul class="simple"> +<li><p>Read the network information stored in the shared memory resources: +edges , weights, positions</p></li> +<li><p>Execute the network layout algorithm</p></li> +<li><p>Update the positions values inside of the shared memory resource</p></li> +<li><p>Update the timestamp inside of the shared memory resource</p></li> +</ul> +<p>I used the timestamp information to avoid unnecessary updates in the +FURY/VTK window instance, which can consume a lot of computational +resources.</p> +<section id="how-have-i-implemented-the-code-for-a-and-b"> +<h3>How have I implemented the code for A and B?</h3> +<p>Because we need to deal with a lot of different data and share them +between different processes I’ve created a set of tools to deal with +that, take a look for example in the <a class="reference external" href="https://github.com/fury-gl/helios/blob/14e39e0350b4b9666775ba0c4840d2e9887678c2/helios/layouts/ipc_tools.py#L188">ShmManagerMultiArrays +Object</a> +, which makes the memory management less painful.</p> +<p>I’m breaking the layout method into two different processes. Thus I’ve +created two abstract objects to deal with any kind of network layout +algorithm which must be performed using inter-process-communication +(IPC). Those objects are: +<a class="reference external" href="https://github.com/devmessias/helios/blob/a0a24525697ec932a398db6413899495fb5633dd/helios/layouts/base.py#L65">NetworkLayoutIPCServerCalc</a> +; used by processes of type B and +<a class="reference external" href="https://github.com/devmessias/helios/blob/a0a24525697ec932a398db6413899495fb5633dd/helios/layouts/base.py#L135">NetworkLayoutIPCRender</a> +; which should be used by processes of type A.</p> +<p>I’ll not bore you with the details of the implementation. But let’s take +a look into some important points. As I’ve said saving the timestamp +after each step of the network layout algorithm. Take a look into the +method _check_and_sync from NetworkLayoutIPCRender +<a class="reference external" href="https://github.com/fury-gl/helios/blob/a0a24525697ec932a398db6413899495fb5633dd/helios/layouts/base.py#L266">here</a>. +Notice that the update happens only if the stored timestamp has been +changed. Also, look at this line +<a class="reference external" href="https://github.com/fury-gl/helios/blob/a0a24525697ec932a398db6413899495fb5633dd/helios/layouts/mde.py#L180">helios/layouts/mde.py#L180</a>, +the IPC-PyMDE implementation This line writes a value 1 into the second +element of the info_buffer. This value is used to inform the process A +that everything worked well. I used that info for example in the tests +for the network layout method, see the link +<a class="reference external" href="https://github.com/fury-gl/helios/blob/a0a24525697ec932a398db6413899495fb5633dd/helios/tests/test_mde_layouts.py#L43">helios/tests/test_mde_layouts.py#L43</a></p> +</section> +</section> +<section id="results"> +<h2>Results</h2> +<p>Until now Helios has three network layout methods implemented: Force +Directed , Minimum Distortion Embeddings and Force Atlas 2. Here +<a class="reference external" href="https://github.com/fury-gl/helios/blob/a0a24525697ec932a398db6413899495fb5633dd/docs/examples/viz_helios_mde.ipynb">docs/examples/viz_helios_mde.ipynb</a> +you can get a jupyter notebook that I’ve a created showing how to use +MDE with IPC in Helios.</p> +<p>In the animation below we can see the result of the Helios-MDE +application into a network with a set of anchored nodes.</p> +<p><img alt="image1" src="https://user-images.githubusercontent.com/6979335/125310065-a3a9f480-e308-11eb-98d9-0ff5406a0e96.gif" /></p> +</section> +<section id="next-steps"> +<h2>Next steps</h2> +<p>I’ll probably focus on the Helios network visualization system. +Improving the documentation and testing the ForceAtlas2 in a computer +with cuda installed. See the list of opened +<a class="reference external" href="https://github.com/fury-gl/helios/issues">issues</a></p> +</section> +<section id="summary-of-most-important-pull-requests"> +<h2>Summary of most important pull-requests:</h2> +<ul class="simple"> +<li><p>IPC tools for network layout methods (helios issue #7) +<a class="reference external" href="https://github.com/fury-gl/helios/pull/6">fury-gl/helios/pull/6</a></p></li> +<li><p>New network layout methods for fury (helios issue #7) +<a class="reference external" href="https://github.com/fury-gl/helios/pull/9">fury-gl/helios/pull/9</a> +<a class="reference external" href="https://github.com/fury-gl/helios/pull/14">fury-gl/helios/pull/14</a> +<a class="reference external" href="https://github.com/fury-gl/helios/pull/13">fury-gl/helios/pull/13</a></p></li> +<li><p>Improved the visual aspects and configurations of the network +rendering(helios issue #12) +<a class="github reference external" href="https://github.com/devmessias/helios/tree/fury_network_actors_improvements">devmessias/helios</a></p></li> +<li><p>Tests, examples and documentation for Helios (helios issues #3 and +#4) +<a class="reference external" href="https://github.com/fury-gl/helios/pull/5">fury-gl/helios/pull/5</a></p></li> +<li><p>Reduced the flickering effect on the FURY/Helios streaming system +<a class="reference external" href="https://github.com/fury-gl/helios/pull/10">fury-gl/helios/pull/10</a> +<a class="reference external" href="https://github.com/fury-gl/fury/pull/437/commits/a94e22dbc2854ec87b8c934f6cabdf48931dc279">fury-gl/fury/pull/437/commits/a94e22dbc2854ec87b8c934f6cabdf48931dc279</a></p></li> +</ul> +</section> +</section> + + + Hi all. In the past weeks, I’ve been focusing on developing Helios; the +network visualization library for FURY. I improved the visual aspects of +the network rendering as well as implemented the most relevant network +layout methods. + + 2021-07-12T00:00:00-04:00 + + + https://fury.gl/posts/2021/2021-07-05-gsoc-devmessias-5.html + Weekly Check-In #5 + 2021-07-05T00:00:00-04:00 + + Bruno Messias + + <section id="weekly-check-in-5"> + +<section id="what-did-you-do-this-week"> +<h2>What did you do this week?</h2> +<section id="fury-gl-fury-pr-437-webrtc-streaming-system-for-fury"> +<h3><a class="reference external" href="https://github.com/fury-gl/fury/pull/427">fury-gl/fury PR#437: WebRTC streaming system for FURY</a></h3> +<ul class="simple"> +<li><p>Before the <a class="reference external" href="https://github.com/fury-gl/fury/pull/437/commits/8c670c284368029cdb5b54c178a792ec615e4d4d">8c670c2</a> commit, for some versions of MacOs the +streaming system was falling in a silent bug. I’ve spent a lot of +time researching to found a cause for this. Fortunately, I could found +the cause and the solution. This troublesome MacOs was falling in a +silent bug because the SharedMemory Object was creating a memory +resource with at least 4086 bytes independent if I’ve requested less +than that. If we look into the MultiDimensionalBuffer Object +(stream/tools.py) before the 8c670c2 commit we can see that Object +has max_size parameter which needs to be updated if the SharedMemory +was created with a “wrong” size.</p></li> +</ul> +</section> +<section id="fury-gl-helios-pr-1-network-layout-and-superactors"> +<h3><a class="reference external" href="https://github.com/fury-gl/helios/pull/1">fury-gl/helios PR 1: Network Layout and SuperActors</a></h3> +<p>In the past week I’ve made a lot of improvements in this PR, from +performance improvements to visual effects. Below are the list of the +tasks related with this PR:</p> +<ul class="simple"> +<li><p>Code refactoring.</p></li> +<li><p>Visual improvements: Using the UniformTools from my pull request +<a class="reference external" href="https://github.com/fury-gl/fury/pull/424">#424</a> now is possible to control all the visual characteristics at +runtime.</p></li> +<li><p>2D Layout: Meanwhile 3d network representations are very usefully +for exploring a dataset is hard to convince a group of network +scientists to use a visualization system which doesn’t allow 2d +representations. Because of that I started to coding the 2d behavior +in the network visualization system.</p></li> +<li><p>Minimum Distortion Embeddings examples: I’ve created some examples +which shows how integrate pymde (Python Minimum Distortion +Embeddings) with fury/helios. The image below shows the result of +this integration: a “perfect” graph embedding</p></li> +</ul> +<img alt="https://user-images.githubusercontent.com/6979335/124524052-da937e00-ddcf-11eb-83ca-9b58ca692c2e.png" src="https://user-images.githubusercontent.com/6979335/124524052-da937e00-ddcf-11eb-83ca-9b58ca692c2e.png" /> +</section> +</section> +<section id="what-is-coming-up-next-week"> +<h2>What is coming up next week?</h2> +<p>I’ll probably focus on the <a class="reference internal" href="#heliospr-1">heliosPR#1</a>. Specifically, writing tests +and improving the minimum distortion embedding layout.</p> +</section> +<section id="did-you-get-stuck-anywhere"> +<h2>Did you get stuck anywhere?</h2> +<p>I did not get stuck this week.</p> +<aside class="system-message"> +<p class="system-message-title">System Message: INFO/1 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2021/2021-07-05-gsoc-devmessias-5.rst</span>, line 60); <em><a href="#id1">backlink</a></em></p> +<p>Duplicate implicit target name: “fury-gl/fury pr#437: webrtc streaming system for fury”.</p> +</aside> +<aside class="system-message"> +<p class="system-message-title">System Message: INFO/1 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2021/2021-07-05-gsoc-devmessias-5.rst</span>, line 62); <em><a href="#id2">backlink</a></em></p> +<p>Duplicate implicit target name: “fury-gl/helios pr 1: network layout and superactors”.</p> +</aside> +<span class="target" id="heliospr-1"></span></section> +</section> + + + Before the 8c670c2 commit, for some versions of MacOs the +streaming system was falling in a silent bug. I’ve spent a lot of +time researching to found a cause for this. Fortunately, I could found +the cause and the solution. This troublesome MacOs was falling in a +silent bug because the SharedMemory Object was creating a memory +resource with at least 4086 bytes independent if I’ve requested less +than that. If we look into the MultiDimensionalBuffer Object +(stream/tools.py) before the 8c670c2 commit we can see that Object +has max_size parameter which needs to be updated if the SharedMemory +was created with a “wrong” size. + + 2021-07-05T00:00:00-04:00 + + + https://fury.gl/posts/2021/2021-06-28-gsoc-devmessias-4.html + SOLID, monkey patching a python issue and network visualization through WebRTC + 2021-07-05T00:00:00-04:00 + + Bruno Messias + + <section id="solid-monkey-patching-a-python-issue-and-network-visualization-through-webrtc"> + +<p>These past two weeks I’ve spent most of my time in the <a class="reference external" href="https://github.com/fury-gl/fury/pull/437">Streaming System +PR</a> and the <a class="reference external" href="https://github.com/fury-gl/helios/pull/1/">Network Layout +PR</a> . In this post I’ll +focus on the most relevant things I’ve made for those PRs.</p> +<section id="streaming-system"> +<h2>Streaming System</h2> +<p><strong>Pull +request</strong> : <a class="reference external" href="https://github.com/fury-gl/fury/pull/437/">fury-gl/fury/pull/437</a>.</p> +<section id="code-refactoring"> +<h3>Code Refactoring</h3> +<section id="abstract-class-and-solid"> +<h4>Abstract class and SOLID</h4> +<p>The past weeks I’ve spent some time refactoring the code to see what +I’ve done let’ s take a look into this +<a class="reference external" href="https://github.com/devmessias/fury/blob/b1e985bd6a0088acb4a116684577c4733395c9b3/fury/stream/client.py#L20">fury/blob/b1e985…/fury/stream/client.py#L20</a>, +the FuryStreamClient Object before the refactoring.</p> +<p>The code is a mess. To see why this code is not good according to SOLID +principles let’s just list all the responsibilities of FuryStreamClient:</p> +<ul class="simple"> +<li><p>Creates a RawArray or SharedMemory to store the n-buffers</p></li> +<li><p>Creates a RawArray or SharedMemory to store the information about +each buffer</p></li> +<li><p>Cleanup the shared memory resources if the SharedMemory was used</p></li> +<li><p>Write the vtk buffer into the shared memory resource</p></li> +<li><p>Creates the vtk callbacks to update the vtk-buffer</p></li> +</ul> +<p>That’s a lot and those responsibilities are not even related to each +other. How can we be more SOLID[1]? An obvious solution is to create a +specific object to deal with the shared memory resources. But it’s not +good enough because we still have a poor generalization since this new +object still needs to deal with different memory management systems: +rawarray or shared memory (maybe sockets in the future). Fortunately, we +can use the python Abstract Classes[2] to organize the code.</p> +<p>To use the ABC from python I first listed all the behaviors that should +be mandatory in the new abstract class. If we are using SharedMemory or +RawArrays we need first to create the memory resource in a proper way. +Therefore, the GenericImageBufferManager must have a abstract method +create_mem_resource. Now take a look into the ImageBufferManager inside +of +<a class="reference external" href="https://github.com/devmessias/fury/blob/c196cf43c0135dada4e2c5d59d68bcc009542a6c/fury/stream/server/server.py#L40">stream/server/server.py</a>, +sometimes it is necessary to load the memory resource in a proper way. +Because of that, the GenericImageBufferManager needs to have a +load_mem_resource abstract method. Finally, each type of +ImageBufferManager should have a different cleanup method. The code +below presents the sketch of the abstract class</p> +<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">abc</span> <span class="kn">import</span> <span class="n">ABC</span><span class="p">,</span> <span class="n">abstractmethod</span> + +<span class="n">GenericImageBufferManager</span><span class="p">(</span><span class="n">ABC</span><span class="p">):</span> + <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span> + <span class="bp">self</span><span class="p">,</span> <span class="n">max_window_size</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">num_buffers</span><span class="o">=</span><span class="mi">2</span><span class="p">,</span> <span class="n">use_shared_mem</span><span class="o">=</span><span class="kc">False</span><span class="p">):</span> + <span class="o">...</span> + <span class="nd">@abstractmethod</span> + <span class="k">def</span> <span class="nf">load_mem_resource</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> + <span class="k">pass</span> + <span class="nd">@abstractmethod</span> + <span class="k">def</span> <span class="nf">create_mem_resource</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> + <span class="k">pass</span> + <span class="nd">@abstractmethod</span> + <span class="k">def</span> <span class="nf">cleanup</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> + <span class="k">pass</span> +</pre></div> +</div> +<p>Now we can look for those behaviors inside of FuryStreamClient.py and +ImageBufferManger.py that does not depend if we are using the +SharedMemory or RawArrays. These behaviors should be methods inside of +the new GenericImageBufferManager.</p> +<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># code at: https://github.com/devmessias/fury/blob/440a39d427822096679ba384c7d1d9a362dab061/fury/stream/tools.py#L491</span> + +<span class="k">class</span> <span class="nc">GenericImageBufferManager</span><span class="p">(</span><span class="n">ABC</span><span class="p">):</span> + <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span> + <span class="bp">self</span><span class="p">,</span> <span class="n">max_window_size</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">num_buffers</span><span class="o">=</span><span class="mi">2</span><span class="p">,</span> <span class="n">use_shared_mem</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span> + <span class="bp">self</span><span class="o">.</span><span class="n">max_window_size</span> <span class="o">=</span> <span class="n">max_window_size</span> + <span class="bp">self</span><span class="o">.</span><span class="n">num_buffers</span> <span class="o">=</span> <span class="n">num_buffers</span> + <span class="bp">self</span><span class="o">.</span><span class="n">info_buffer_size</span> <span class="o">=</span> <span class="n">num_buffers</span><span class="o">*</span><span class="mi">2</span> <span class="o">+</span> <span class="mi">2</span> + <span class="bp">self</span><span class="o">.</span><span class="n">_use_shared_mem</span> <span class="o">=</span> <span class="n">use_shared_mem</span> + <span class="c1"># omitted code</span> + <span class="nd">@property</span> + <span class="k">def</span> <span class="nf">next_buffer_index</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> + <span class="n">index</span> <span class="o">=</span> <span class="nb">int</span><span class="p">((</span><span class="bp">self</span><span class="o">.</span><span class="n">info_buffer_repr</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span><span class="o">+</span><span class="mi">1</span><span class="p">)</span> <span class="o">%</span> <span class="bp">self</span><span class="o">.</span><span class="n">num_buffers</span><span class="p">)</span> + <span class="k">return</span> <span class="n">index</span> + <span class="nd">@property</span> + <span class="k">def</span> <span class="nf">buffer_index</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> + <span class="n">index</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">info_buffer_repr</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span> + <span class="k">return</span> <span class="n">index</span> + <span class="k">def</span> <span class="nf">write_into</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">w</span><span class="p">,</span> <span class="n">h</span><span class="p">,</span> <span class="n">np_arr</span><span class="p">):</span> + <span class="n">buffer_size</span> <span class="o">=</span> <span class="n">buffer_size</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">h</span><span class="o">*</span><span class="n">w</span><span class="p">)</span> + <span class="n">next_buffer_index</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">next_buffer_index</span> + <span class="c1"># omitted code</span> + + <span class="k">def</span> <span class="nf">get_current_frame</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> + <span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">_use_shared_mem</span><span class="p">:</span> + <span class="c1"># omitted code</span> + <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">width</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">height</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">image_buffer_repr</span> + + <span class="k">def</span> <span class="nf">get_jpeg</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> + <span class="n">width</span><span class="p">,</span> <span class="n">height</span><span class="p">,</span> <span class="n">image</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">get_current_frame</span><span class="p">()</span> + <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_use_shared_mem</span><span class="p">:</span> + <span class="c1"># omitted code</span> + <span class="k">return</span> <span class="n">image_encoded</span><span class="o">.</span><span class="n">tobytes</span><span class="p">()</span> + + <span class="k">async</span> <span class="k">def</span> <span class="nf">async_get_jpeg</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">ms</span><span class="o">=</span><span class="mi">33</span><span class="p">):</span> + <span class="c1"># omitted code</span> + <span class="nd">@abstractmethod</span> + <span class="k">def</span> <span class="nf">load_mem_resource</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> + <span class="k">pass</span> + + <span class="nd">@abstractmethod</span> + <span class="k">def</span> <span class="nf">create_mem_resource</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> + <span class="k">pass</span> + + <span class="nd">@abstractmethod</span> + <span class="k">def</span> <span class="nf">cleanup</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> + <span class="n">Pass</span> +</pre></div> +</div> +<p>With the +<a class="reference external" href="https://github.com/devmessias/fury/blob/440a39d427822096679ba384c7d1d9a362dab061/fury/stream/tools.py#L491">GenericImageBufferManager</a> +the +<a class="reference external" href="https://github.com/devmessias/fury/blob/440a39d427822096679ba384c7d1d9a362dab061/fury/stream/tools.py#L609">RawArrayImageBufferManager</a> +and +<a class="reference external" href="https://github.com/devmessias/fury/blob/440a39d427822096679ba384c7d1d9a362dab061/fury/stream/tools.py#L681">SharedMemImageBufferManager</a> +is now implemented with less duplication of code (DRY principle). This +makes the code more readable and easier to find bugs. In addition, later +we can implement other memory management systems in the streaming system +without modifying the behavior of FuryStreamClient or the code inside of +server.py.</p> +<p>I’ve also applied the same SOLID principles to improve the CircularQueue +object. Although the CircularQueue and FuryStreamInteraction were not +violating the S from SOLID, the head-tail buffer from the CircularQueue +must have a way to lock the write/read if the memory resource is busy. +Meanwhile the +<a class="reference external" href="https://docs.python.org/3/library/multiprocessing.html#multiprocessing.Array">multiprocessing.Arrays</a> +already has a context which allows lock (.get_lock()) SharedMemory +doesn’t[2]. The use of abstract class allowed me to deal with those +peculiarities. <a class="reference external" href="https://github.com/fury-gl/fury/pull/437/commits/358402ea2f06833f66f45f3818ccc3448b2da9cd">commit +358402e</a></p> +</section> +<section id="using-namedtuples-to-grant-immutability-and-to-avoid-silent-bugs"> +<h4>Using namedtuples to grant immutability and to avoid silent bugs</h4> +<p>The circular queue and the user interaction are implemented in the +streaming system using numbers to identify the type of event (mouse +click, mouse weel, …) and where to store the specific values +associated with the event , for example if the ctrl key is pressed or +not. Therefore, those numbers appear in different files and locations: +tests/test_stream.py, stream/client.py, steam/server/app_async.py. This +can be problematic because a typo can create a silent bug. One +possibility to mitigate this is to use a python dictionary to store the +constant values, for example</p> +<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">EVENT_IDS</span> <span class="o">=</span> <span class="p">{</span> + <span class="s2">&quot;mouse_move&quot;</span> <span class="p">:</span> <span class="mi">2</span><span class="p">,</span> <span class="s2">&quot;mouse_weel&quot;</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span> <span class="c1">#...</span> +<span class="p">}</span> +</pre></div> +</div> +<p>But this solution has another issue, anywhere in the code we can change +the values of EVENT_IDS and this will produce a new silent bug. To avoid +this I chose to use +<a class="reference external" href="https://docs.python.org/3/library/collections.html#collections.namedtuple">namedtuples</a> +to create an immutable object which holds all the constant values +associated with the user interactions. +<a class="reference external" href="https://github.com/devmessias/fury/blob/b1e985bd6a0088acb4a116684577c4733395c9b3/fury/stream/constants.py#L59">stream/constants.py</a></p> +<p>The namedtuple has several advantages when compared to dictionaries for +this specific situation. In addition, it has a better performance. A +good tutorial about namedtuples it’s available here +<a class="reference external" href="https://realpython.com/python-namedtuple/">https://realpython.com/python-namedtuple/</a></p> +</section> +</section> +<section id="testing"> +<h3>Testing</h3> +<p>My mentors asked me to write tests for this PR. Therefore, this past +week I’ve implemented the most important tests for the streaming system: +<a class="reference external" href="https://github.com/devmessias/fury/blob/440a39d427822096679ba384c7d1d9a362dab061/fury/tests/test_stream.py">/fury/tests/test_stream.py</a></p> +</section> +<section id="most-relevant-bugs"> +<h3>Most relevant bugs</h3> +<p>As I discussed in my <a class="reference external" href="https://blogs.python-gsoc.org/en/demvessiass-blog/weekly-check-in-3-15/">third +week</a> +check-in there is an open issue related to SharedMemory in python. +This”bug” happens in the streaming system through the following scenario</p> +<div class="highlight-bash notranslate"><div class="highlight"><pre><span></span><span class="m">1</span>-Process<span class="w"> </span>A<span class="w"> </span>creates<span class="w"> </span>a<span class="w"> </span>shared<span class="w"> </span>memory<span class="w"> </span>X +<span class="m">2</span>-Process<span class="w"> </span>A<span class="w"> </span>creates<span class="w"> </span>a<span class="w"> </span>subprocess<span class="w"> </span>B<span class="w"> </span>using<span class="w"> </span>popen<span class="w"> </span><span class="o">(</span><span class="nv">shell</span><span class="o">=</span>False<span class="o">)</span> +<span class="m">3</span>-Process<span class="w"> </span>B<span class="w"> </span>reads<span class="w"> </span>X +<span class="m">4</span>-Process<span class="w"> </span>B<span class="w"> </span>closes<span class="w"> </span>X +<span class="m">5</span>-Process<span class="w"> </span>A<span class="w"> </span>kills<span class="w"> </span>B +<span class="m">4</span>-Process<span class="w"> </span>A<span class="w"> </span>closes<span class="w"> </span>X +<span class="m">5</span>-Process<span class="w"> </span>A<span class="w"> </span>unlink<span class="o">()</span><span class="w"> </span>the<span class="w"> </span>shared<span class="w"> </span>memory<span class="w"> </span>resource +</pre></div> +</div> +<p>In python, this scenario translates to</p> +<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">multiprocessing</span> <span class="kn">import</span> <span class="n">shared_memory</span> <span class="k">as</span> <span class="n">sh</span> +<span class="kn">import</span> <span class="nn">time</span> +<span class="kn">import</span> <span class="nn">subprocess</span> +<span class="kn">import</span> <span class="nn">sys</span> + +<span class="n">shm_a</span> <span class="o">=</span> <span class="n">sh</span><span class="o">.</span><span class="n">SharedMemory</span><span class="p">(</span><span class="n">create</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">size</span><span class="o">=</span><span class="mi">10000</span><span class="p">)</span> +<span class="n">command_string</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">&quot;from multiprocessing import shared_memory as sh;import time;shm_b = sh.SharedMemory(&#39;</span><span class="si">{</span><span class="n">shm_a</span><span class="o">.</span><span class="n">name</span><span class="si">}</span><span class="s2">&#39;);shm_b.close();&quot;</span> +<span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span> +<span class="n">p</span> <span class="o">=</span> <span class="n">subprocess</span><span class="o">.</span><span class="n">Popen</span><span class="p">(</span> + <span class="p">[</span><span class="n">sys</span><span class="o">.</span><span class="n">executable</span><span class="p">,</span> <span class="s1">&#39;-c&#39;</span><span class="p">,</span> <span class="n">command_string</span><span class="p">],</span> + <span class="n">stdout</span><span class="o">=</span><span class="n">subprocess</span><span class="o">.</span><span class="n">PIPE</span><span class="p">,</span> <span class="n">stderr</span><span class="o">=</span><span class="n">subprocess</span><span class="o">.</span><span class="n">PIPE</span><span class="p">,</span> <span class="n">shell</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span> +<span class="n">p</span><span class="o">.</span><span class="n">wait</span><span class="p">()</span> +<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;</span><span class="se">\n</span><span class="s2">STDOUT&quot;</span><span class="p">)</span> +<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;=======</span><span class="se">\n</span><span class="s2">&quot;</span><span class="p">)</span> +<span class="nb">print</span><span class="p">(</span><span class="n">p</span><span class="o">.</span><span class="n">stdout</span><span class="o">.</span><span class="n">read</span><span class="p">())</span> +<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;</span><span class="se">\n</span><span class="s2">STDERR&quot;</span><span class="p">)</span> +<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;=======</span><span class="se">\n</span><span class="s2">&quot;</span><span class="p">)</span> +<span class="nb">print</span><span class="p">(</span><span class="n">p</span><span class="o">.</span><span class="n">stderr</span><span class="o">.</span><span class="n">read</span><span class="p">())</span> +<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;========</span><span class="se">\n</span><span class="s2">&quot;</span><span class="p">)</span> +<span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span> +<span class="n">shm_a</span><span class="o">.</span><span class="n">close</span><span class="p">()</span> +<span class="n">shm_a</span><span class="o">.</span><span class="n">unlink</span><span class="p">()</span> +</pre></div> +</div> +<p>Fortunately, I could use a monkey-patching[3] solution to fix that; +meanwhile we’re waiting for the python-core team to fix the +resource_tracker (38119) issue [4].</p> +</section> +</section> +<section id="network-layout-helios-fury"> +<h2>Network Layout (Helios-FURY)</h2> +<p><strong>Pull +request</strong><a class="reference external" href="https://github.com/fury-gl/helios/pull/1/">fury-gl/helios/pull/1</a></p> +<p>Finally, the first version of FURY network layout is working as you can +see in the video below.</p> +<p>In addition, this already can be used with the streaming system allowing +user interactions across the internet with WebRTC protocol.</p> +<p>One of the issues that I had to solve to achieve the result presented in +the video above was to find a way to update the positions of the vtk +objects without blocking the main thread and at the same time allowing +the vtk events calls. My solution was to define an interval timer using +the python threading module: +<a class="reference external" href="https://github.com/devmessias/fury/blob/440a39d427822096679ba384c7d1d9a362dab061/fury/stream/tools.py#L776">/fury/stream/tools.py#L776</a>, +<a class="reference external" href="https://github.com/devmessias/fury/blob/440a39d427822096679ba384c7d1d9a362dab061/fury/stream/client.py#L112">/fury/stream/client.py#L112</a> +<a class="reference external" href="https://github.com/devmessias/fury/blob/440a39d427822096679ba384c7d1d9a362dab061/fury/stream/client.py#L296">/fury/stream/client.py#L296</a></p> +</section> +<section id="refs"> +<h2>Refs:</h2> +<ul class="simple"> +<li><p>[1] A. Souly,”5 Principles to write SOLID Code (examples in Python),” +Medium, Apr. 26, 2021. +<a class="reference external" href="https://towardsdatascience.com/5-principles-to-write-solid-code-examples-in-python-9062272e6bdc">https://towardsdatascience.com/5-principles-to-write-solid-code-examples-in-python-9062272e6bdc</a> +(accessed Jun. 28, 2021).</p></li> +<li><p>[2]”[Python-ideas] Re: How to prevent shared memory from being +corrupted ?” +<a class="reference external" href="https://www.mail-archive.com/python-ideas&#64;python.org/msg22935.html">https://www.mail-archive.com/python-ideas&#64;python.org/msg22935.html</a> +(accessed Jun. 28, 2021).</p></li> +<li><p>[3]“Message 388287 - Python tracker.” +<a class="reference external" href="https://bugs.python.org/msg388287">https://bugs.python.org/msg388287</a> (accessed Jun. 28, 2021).</p></li> +<li><p>[4]“bpo-38119: Fix shmem resource tracking by vinay0410 · Pull +Request #21516 · python/cpython,” GitHub. +<a class="github reference external" href="https://github.com/python/cpython/pull/21516">python/cpython#21516</a> (accessed Jun. 28, +2021).</p></li> +</ul> +</section> +</section> + + + These past two weeks I’ve spent most of my time in the Streaming System +PR and the Network Layout +PR . In this post I’ll +focus on the most relevant things I’ve made for those PRs. + + 2021-07-05T00:00:00-04:00 + + + https://fury.gl/posts/2021/2021-06-21-gsoc-devmessias-3.html + Weekly Check-In #3 + 2021-06-21T00:00:00-04:00 + + Bruno Messias + + <section id="weekly-check-in-3"> + +<section id="what-did-you-do-this-week"> +<h2>What did you do this week?</h2> +<ul class="simple"> +<li><p><a class="reference external" href="https://github.com/fury-gl/fury/pull/422/commits/8a0012b66b95987bafdb71367a64897b25c89368">PR fury-gl/fury#422 +(merged):</a> +Integrated the 3d impostor spheres with the marker actor.</p></li> +<li><p><a class="reference external" href="https://github.com/fury-gl/fury/pull/422">PR fury-gl/fury#422 +(merged):</a> Fixed some +issues with my maker PR which now it’s merged on fury.</p></li> +<li><p><a class="reference external" href="https://github.com/fury-gl/fury/pull/432">PR fury-gl/fury#432</a> +I’ve made some improvements in my PR which can be used to fine tune +the opengl state on VTK.</p></li> +<li><p><a class="reference external" href="https://github.com/fury-gl/fury/pull/437">PR fury-gl/fury#437</a> +I’ve made several improvements in my streamer proposal for FURY related to memory management.</p></li> +<li><p><a class="reference external" href="https://github.com/fury-gl/helios/pull/1">PR fury-gl/helios#1</a> +First version of async network layout using force-directed.</p></li> +</ul> +</section> +<section id="did-i-get-stuck-anywhere"> +<h2>Did I get stuck anywhere?</h2> +<section id="a-python-core-issue"> +<h3>A python-core issue</h3> +<p>I’ve spent some hours trying to discover this issue. But now it’s solved +through the commit +<a class="reference external" href="https://github.com/devmessias/fury/commit/071dab85a86ec4f97eba36721b247ca9233fd59e">devmessias/fury/commit/071dab85</a></p> +<p>The <a class="reference external" href="https://docs.python.org/3/library/multiprocessing.shared_memory.html">SharedMemory</a> +from python&gt;=3.8 offers a new a way to share memory resources between +unrelated process. One of the advantages of using the SharedMemory +instead of the RawArray from multiprocessing is that the SharedMemory +allows to share memory blocks without those processes be related with a +fork or spawm method. The SharedMemory behavior allowed to achieve our +jupyter integration and <a class="reference external" href="https://github.com/fury-gl/fury/pull/437/files#diff-7680a28c3a88a93b8dae7b777c5db5805e1157365805eeaf2e58fd12a00df046">simplifies the use of the streaming +system</a>. +However, I saw a issue in the shared memory implementation.</p> +<p>Let’s see the following scenario:</p> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="mi">1</span><span class="o">-</span><span class="n">Process</span> <span class="n">A</span> <span class="n">creates</span> <span class="n">a</span> <span class="n">shared</span> <span class="n">memory</span> <span class="n">X</span> +<span class="mi">2</span><span class="o">-</span><span class="n">Process</span> <span class="n">A</span> <span class="n">creates</span> <span class="n">a</span> <span class="n">subprocess</span> <span class="n">B</span> <span class="n">using</span> <span class="n">popen</span> <span class="p">(</span><span class="n">shell</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span> +<span class="mi">3</span><span class="o">-</span><span class="n">Process</span> <span class="n">B</span> <span class="n">reads</span> <span class="n">X</span> +<span class="mi">4</span><span class="o">-</span><span class="n">Process</span> <span class="n">B</span> <span class="n">closes</span> <span class="n">X</span> +<span class="mi">5</span><span class="o">-</span><span class="n">Process</span> <span class="n">A</span> <span class="n">kills</span> <span class="n">B</span> +<span class="mi">4</span><span class="o">-</span><span class="n">Process</span> <span class="n">A</span> <span class="n">closes</span> <span class="n">X</span> +<span class="mi">5</span><span class="o">-</span><span class="n">Process</span> <span class="n">A</span> <span class="n">unlink</span><span class="p">()</span> <span class="n">the</span> <span class="n">shared</span> <span class="n">memory</span> <span class="n">resource</span> <span class="n">X</span> +</pre></div> +</div> +<p>The above scenario should work flawless. Calling unlink() in X is the right way as +discussed in the python official documentation. However, there is a open +issue related the unlink method</p> +<ul class="simple"> +<li><p><a class="reference external" href="https://bugs.python.org/issue38119">Issue: +https://bugs.python.org/issue38119</a></p></li> +<li><p><a class="reference external" href="https://github.com/python/cpython/pull/21516">PR +python/cpython/pull/21516</a></p></li> +</ul> +<p>Fortunately, I could use a +<a class="reference external" href="https://bugs.python.org/msg388287">monkey-patching</a> solution to fix +that meanwhile we wait to the python-core team to fix the +resource_tracker (38119) issue.</p> +</section> +</section> +<section id="what-is-coming-up-next"> +<h2>What is coming up next?</h2> +<p>I’m planning to work in the +<a class="reference external" href="https://github.com/fury-gl/fury/pull/432">fury-gl/fury#432</a> and +<a class="reference external" href="https://github.com/fury-gl/helios/pull/1">fury-gl/helios#1</a>.</p> +</section> +</section> + + + PR fury-gl/fury#422 +(merged): +Integrated the 3d impostor spheres with the marker actor. + + 2021-06-21T00:00:00-04:00 + + diff --git a/v0.10.x/blog/author/joao-victor-dell-agli-floriano.html b/v0.10.x/blog/author/joao-victor-dell-agli-floriano.html new file mode 100644 index 000000000..3cf846a66 --- /dev/null +++ b/v0.10.x/blog/author/joao-victor-dell-agli-floriano.html @@ -0,0 +1,1466 @@ + + + + + + + Posts by João Victor Dell Agli Floriano — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +
+

+ + Posts by + + João Victor Dell Agli Floriano + +

+ + +
+

+ Week 12: Now That is (almost) a Wrap! +

+ +

Hello everyone, it’s time for another GSoC blogpost! Today, I am going to talk about some minor details I worked on last week on my +project.

+

+ +

Read more ...

+
+
+ +
+

+ Google Summer of Code Final Work Product +

+ +

Name: João Victor Dell Agli Floriano

+

+ +

Read more ...

+
+
+ +
+

+ Week 11: A Refactor is Sometimes Needed +

+ +

Hello everyone, it’s time for another weekly blogpost! Today I am going to share some updates on the API refactoring +I was working on with my mentors.

+

+ +

Read more ...

+
+
+ +
+

+ Week 10: Ready for Review! +

+ +

Hello everyone, it’s time for another weekly blogpost!

+

+ +

Read more ...

+
+
+ +
+

+ Week 9: It is Polishing Time! +

+ +

Hello everyone, it’s time for another weekly blogpost! Today, I am going to update you on my project’s latest changes.

+

+ +

Read more ...

+
+
+ +
+

+ Week 8: The Birth of a Versatile API +

+ +

Hello everyone, it’s time for another weekly blogpost! Today, I am going to tell you all about how is the KDE API development going, and +to show you the potential this holds for the future!

+

+ +

Read more ...

+
+
+ +
+

+ Week 7: Experimentation Done +

+ +

Hello everyone, welcome to another weekly blogpost! Let’s talk about the current status of my project (spoiler: it is beautiful).

+

+ +

Read more ...

+
+
+ +
+

+ Week 6: Things are Starting to Build Up +

+ +

Hello everyone, time for a other weekly blogpost! Today, I will show you my current progress on my project and latest activities.

+

+ +

Read more ...

+
+
+ +
+

+ Week 5: All Roads Lead to Rome +

+ +

Hello everyone, time for another weekly blogpost! Today, we will talk about taking different paths to reach your objective.

+

+ +

Read more ...

+
+
+ +
+

+ Week 4: Nothing is Ever Lost +

+ +

Welcome again to another weekly blogpost! Today, let’s talk about the importance of guidance throughout a project.

+

+ +

Read more ...

+
+
+ +
+

+ Week 3: Watch Your Expectations +

+ +

Hello everyone, it’s time for another weekly blogpost! This week, +I will talk about how you should watch your expectations when working with any project.

+

+ +

Read more ...

+
+
+ +
+

+ Week 2: The Importance of (good) Documentation +

+ +

Hello everybody, welcome to the week 2 of this project! I must admit I thought this would be simpler than it is currently being, but I forgot that when it comes to dealing with computer graphics’ applications, things never are. Below, some updates on what I have been up to for this past week.

+

+ +

Read more ...

+
+
+ +
+

+ The FBO Saga - Week 1 +

+ +

As mentioned in the last week’s blogpost, the goal for that week was to investigate VTK’s Framebuffer Object framework. +An update on that is that indeed, VTK has one more low-level working FBO class that can be used inside FURY, however, +they come with some issues that I will explain further below.

+

+ +

Read more ...

+
+
+ +
+

+ The Beginning of Everything - Week 0 +

+ +

Hello everyone, welcome to the beginning of my journey through GSoC 2023! I would like to thank everyone involved for the opportunity provided, it is an honour to be working side by side with professionals and so many experienced people from around the world.

+

+ +

Read more ...

+
+
+ + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/blog/author/joao-victor-dell-agli-floriano/atom.xml b/v0.10.x/blog/author/joao-victor-dell-agli-floriano/atom.xml new file mode 100644 index 000000000..a9267ddce --- /dev/null +++ b/v0.10.x/blog/author/joao-victor-dell-agli-floriano/atom.xml @@ -0,0 +1,1013 @@ + + + https://fury.gl/ + Blog - Posts by João Victor Dell Agli Floriano + 2024-02-29T15:43:57.418808+00:00 + + + ABlog + + https://fury.gl/posts/2023/2023-08-21-week-12-joaodellagli.html + Week 12: Now That is (almost) a Wrap! + 2023-08-21T00:00:00-04:00 + + João Victor Dell Agli Floriano + + <section id="week-12-now-that-is-almost-a-wrap"> + +<p>Hello everyone, it’s time for another GSoC blogpost! Today, I am going to talk about some minor details I worked on last week on my +project.</p> +<section id="last-week-s-effort"> +<h2>Last Week’s Effort</h2> +<p>After the API refactoring was done last week, I focused on addressing the reviews I would get from it. The first issues I addressed was related to +style, as there were some minor details my GSoC contributors pointed out that needed change. Also, I have addressed an issue I was having +with the <cite>typed hint</cite> of one of my functions. Filipi, my mentor, showed me there is a way to have more than one typed hint in the same parameter, +all I needed to do was to use the <cite>Union</cite> class from the <cite>typing</cite> module, as shown below:</p> +<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">Union</span> <span class="k">as</span> <span class="n">tUnion</span> +<span class="kn">from</span> <span class="nn">numpy</span> <span class="kn">import</span> <span class="n">ndarray</span> + +<span class="k">def</span> <span class="nf">function</span><span class="p">(</span><span class="n">variable</span> <span class="p">:</span> <span class="n">tUnion</span><span class="p">(</span><span class="nb">float</span><span class="p">,</span> <span class="n">np</span><span class="o">.</span><span class="n">ndarray</span><span class="p">)):</span> + <span class="k">pass</span> +</pre></div> +</div> +<p>Using that, I could set the typedhint of the <cite>bandwidth</cite> variable to <cite>float</cite> and <cite>np.ndarray</cite>.</p> +</section> +<section id="so-how-did-it-go"> +<h2>So how did it go?</h2> +<p>All went fine with no difficult at all, thankfully.</p> +</section> +<section id="the-next-steps"> +<h2>The Next Steps</h2> +<p>My next plans are, after having PR <a class="reference external" href="https://github.com/fury-gl/fury/pull/826">#826</a> merged, to work on the float encoding issue described in +<span class="xref std std-doc">this blogpost</span>. Also, I plan to tackle the UI idea once again, to see if I can finally give the user +a way to control the intensities of the distributions.</p> +<p>Wish me luck!</p> +</section> +</section> + + + Hello everyone, it’s time for another GSoC blogpost! Today, I am going to talk about some minor details I worked on last week on my +project. + + 2023-08-21T00:00:00-04:00 + + + https://fury.gl/posts/2023/2023-08-21-joaodellagli-final-report.html + Google Summer of Code Final Work Product + 2023-08-21T00:00:00-04:00 + + João Victor Dell Agli Floriano + + <a class="reference external image-reference" href="https://summerofcode.withgoogle.com/programs/2023/projects/ED0203De"><img alt="https://developers.google.com/open-source/gsoc/resources/downloads/GSoC-logo-horizontal.svg" height="40" src="https://developers.google.com/open-source/gsoc/resources/downloads/GSoC-logo-horizontal.svg" /></a> +<a class="reference external image-reference" href="https://summerofcode.withgoogle.com/programs/2023/organizations/python-software-foundation"><img alt="https://www.python.org/static/img/python-logo&#64;2x.png" src="https://www.python.org/static/img/python-logo&#64;2x.png" style="height: 40px;" /></a> +<a class="reference external image-reference" href="https://fury.gl/latest/index.html"><img alt="https://python-gsoc.org/logos/fury_logo.png" src="https://python-gsoc.org/logos/fury_logo.png" style="width: 40px;" /></a> +<section id="google-summer-of-code-final-work-product"> + +<ul class="simple"> +<li><p><strong>Name:</strong> João Victor Dell Agli Floriano</p></li> +<li><p><strong>Organisation:</strong> Python Software Foundation</p></li> +<li><p><strong>Sub-Organisation:</strong> FURY</p></li> +<li><p><strong>Project:</strong> <a class="reference external" href="https://github.com/fury-gl/fury/wiki/Google-Summer-of-Code-2023-(GSOC2023)#project-2-fast-3d-kernel-based-density-rendering-using-billboards">FURY - Project 2. Fast 3D kernel-based density rendering using billboards.</a></p></li> +</ul> +<section id="abstract"> +<h2>Abstract</h2> +<p>This project had the goal to implement 3D Kernel Density Estimation rendering to FURY. Kernel Density Estimation, or KDE, is a +statistical method that uses kernel smoothing for modeling and estimating the density distribution of a set of points defined +inside a given region. For its graphical implementation, it was used post-processing techniques such as offscreen rendering to +framebuffers and colormap post-processing as tools to achieve the desired results. This was completed with a functional basic KDE +rendering result, that relies on a solid and easy-to-use API, as well as some additional features.</p> +</section> +<section id="proposed-objectives"> +<h2>Proposed Objectives</h2> +<ul class="simple"> +<li><dl class="simple"> +<dt><strong>First Phase</strong><span class="classifier">Implement framebuffer usage in FURY</span></dt><dd><ul> +<li><p>Investigate the usage of float framebuffers inside FURY’s environment.</p></li> +<li><p>Implement a float framebuffer API.</p></li> +</ul> +</dd> +</dl> +</li> +<li><dl class="simple"> +<dt><strong>Second Phase</strong><span class="classifier">Shader-framebuffer integration</span></dt><dd><ul> +<li><p>Implement a shader that uses a colormap to render framebuffers.</p></li> +<li><p>Escalate this rendering for composing multiple framebuffers.</p></li> +</ul> +</dd> +</dl> +</li> +<li><dl class="simple"> +<dt><strong>Third Phase</strong><span class="classifier">KDE Calculations</span></dt><dd><ul> +<li><p>Investigate KDE calculation for point-cloud datasets.</p></li> +<li><p>Implement KDE calculation inside the framebuffer rendering shaders.</p></li> +<li><p>Test KDE for multiple datasets.</p></li> +</ul> +</dd> +</dl> +</li> +</ul> +</section> +<section id="objectives-completed"> +<h2>Objectives Completed</h2> +<ul> +<li><dl> +<dt><strong>Implement framebuffer usage in FURY</strong></dt><dd><p>The first phase, addressed from <em>May/29</em> to <em>July/07</em>, started with the investigation of +<a class="reference external" href="https://vtk.org/doc/nightly/html/classvtkOpenGLFramebufferObject.html#details">VTK’s Framebuffer Object</a>, a vital part of this project, to understand +how to use it properly.</p> +<p>Framebuffer Objects, abbreviated as FBOs, are the key to post-processing effects in OpenGL, as they are used to render things offscreen and save the resulting image to a texture +that will be later used to apply the desired post-processing effects within the object’s <a class="reference external" href="https://www.khronos.org/opengl/wiki/Fragment_Shader">fragment shader</a> +rendered to screen, in this case, a <a class="reference external" href="http://www.opengl-tutorial.org/intermediate-tutorials/billboards-particles/billboards/">billboard</a>. In the case of the +<a class="reference external" href="https://en.wikipedia.org/wiki/Kernel_density_estimation">Kernel Density Estimation</a> post-processing effect, we need a special kind of FBO, one that stores textures’ +values as floats, different from the standard 8-bit unsigned int storage. This is necessary because the KDE rendering involves rendering every KDE point calculation +to separate billboards, rendered to the same scene, which will have their intensities, divided by the number of points rendered, blended with +<a class="reference external" href="https://www.khronos.org/opengl/wiki/Blending">OpenGL Additive Blending</a>, and if a relative big number of points are rendered at the +same time, 32-bit float precision is needed to guarantee that small-intensity values will not be capped to zero, and disappear.</p> +<p>After a month going through VTK’s FBO documentation and weeks spent trying different approaches to this method, it would not work +properly, as some details seemed to be missing from the documentation, and asking the community haven’t solved the problem as well. +Reporting that to my mentors, which unsuccessfully tried themselves to make it work, they decided it was better if another path was taken, using +<a class="reference external" href="https://vtk.org/doc/nightly/html/classvtkWindowToImageFilter.html">VTK’s WindowToImageFilter</a> method as a workaround, described +in this <a class="reference external" href="https://fury.gl/latest/posts/2023/2023-07-03-week-5-joaodellagli.html">blogpost</a>. This method helped the development of +three new functions to FURY, <em>window_to_texture()</em>, <em>texture_to_actor()</em> and <em>colormap_to_texture()</em>, that allow the passing of +different kinds of textures to FURY’s actor’s shaders, the first one to capture a window and pass it as a texture to an actor, +the second one to pass an external texture to an actor, and the third one to specifically pass a colormap as a texture to an +actor. It is important to say that <em>WindowToImageFilter()</em> is not the ideal way to make it work, as this method does not seem to +support float textures. However, a workaround to that is currently being worked on, as I will describe later on.</p> +<p><em>Pull Requests:</em></p> +<ul class="simple"> +<li><p><strong>KDE Rendering Experimental Program (Needs major revision):</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/804">fury-gl/fury#804</a></p></li> +</ul> +<p>The result of this whole FBO and WindowToImageFilter experimentation is well documented in PR +<a class="reference external" href="https://github.com/fury-gl/fury/pull/804">#804</a> that implements an experimental version of a KDE rendering program. +The future of this PR, as discussed with my mentors, is to be better documented to be used as an example for developers on +how to develop features in FURY with the tools used, and it shall be done soon.</p> +</dd> +</dl> +</li> +<li><dl> +<dt><strong>Shader-framebuffer integration</strong></dt><dd><aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-21-joaodellagli-final-report.rst</span>, line 16); <em><a href="#id2">backlink</a></em></p> +<p>Duplicate explicit target name: “blogpost”.</p> +</aside> +<p>The second phase, which initially was thought of as “Implement a shader that uses a colormap to render framebuffers” and “Escalate this +rendering for composing multiple framebuffers” was actually a pretty simple phase that could be addressed in one week, <em>July/10</em> +to <em>July/17</em>, done at the same time as the third phase goal, documented in this +<a class="reference external" href="https://fury.gl/latest/posts/2023/2023-07-17-week-7-joaodellagli.html">blogpost</a>. As FURY already had a tool for generating and +using colormaps, they were simply connected to the shader part of the program as textures, with the functions explained above. +Below, is the result of the <em>matplotlib viridis</em> colormap passed to a simple gaussian KDE render:</p> +<img alt="Final 2D plot" class="align-center" src="https://raw.githubusercontent.com/JoaoDell/gsoc_assets/main/images/final_2d_plot.png" /> +<aside class="system-message"> +<p class="system-message-title">System Message: INFO/1 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-21-joaodellagli-final-report.rst</span>, line 16); <em><a href="#id3">backlink</a></em></p> +<p>Duplicate explicit target name: “#804”.</p> +</aside> +<p>That is also included in PR <a class="reference external" href="https://github.com/fury-gl/fury/pull/804">#804</a>. Having the 2D plot ready, some time was taken to +figure out how to enable a 3D render, that includes rotation and other movement around the set rendered, which was solved by +learning about the callback properties that exist inside <em>VTK</em>. Callbacks are ways to enable code execution inside the VTK rendering +loop, enclosed inside <em>vtkRenderWindowInteractor.start()</em>. If it is desired to add a piece of code that, for example, passes a time +variable to the fragment shader over time, a callback function can be declared:</p> +<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">fury</span> <span class="kn">import</span> <span class="n">window</span> +<span class="n">t</span> <span class="o">=</span> <span class="mi">0</span> +<span class="n">showm</span> <span class="o">=</span> <span class="n">window</span><span class="o">.</span><span class="n">ShowManager</span><span class="p">(</span><span class="o">...</span><span class="p">)</span> + +<span class="k">def</span> <span class="nf">callback_function</span><span class="p">:</span> + <span class="n">t</span> <span class="o">+=</span> <span class="mf">0.01</span> + <span class="n">pass_shader_uniforms_to_fs</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="s2">&quot;t&quot;</span><span class="p">)</span> + +<span class="n">showm</span><span class="o">.</span><span class="n">add_iren_callback</span><span class="p">(</span><span class="n">callback_function</span><span class="p">,</span> <span class="s2">&quot;RenderEvent&quot;</span><span class="p">)</span> +</pre></div> +</div> +<p>The piece of code above created a function that updates the time variable <em>t</em> in every <em>“RenderEvent”</em>, and passes it to the +fragment shader. With that property, the camera and some other parameters could be updated, which enabled 3D visualization, that +then, outputted the following result, using <em>matplotlib inferno</em> colormap:</p> +<img alt="3D Render gif" class="align-center" src="https://raw.githubusercontent.com/JoaoDell/gsoc_assets/main/images/3d_kde_gif.gif" /> +</dd> +</dl> +</li> +<li><dl> +<dt><strong>KDE Calculations</strong> (ongoing)</dt><dd><p>As said before, the second and third phases were done simultaneously, so after having a way to capture the window and use it as a +texture ready, the colormap ready, and an initial KDE render ready, all it was needed to do was to improve the KDE calculations. +As this <a class="reference external" href="https://en.wikipedia.org/wiki/Kernel_density_estimation">Wikipedia page</a> explains, a KDE calculation is to estimate an +abstract density around a set of points defined inside a given region with a kernel, that is a function that models the density +around a point based on its associated distribution <span class="math notranslate nohighlight">\(\sigma\)</span>.</p> +<p>A well-known kernel is, for example, the <strong>Gaussian Kernel</strong>, that says that the density around a point <span class="math notranslate nohighlight">\(p\)</span> with distribution +<span class="math notranslate nohighlight">\(\sigma\)</span> is defined as:</p> +<div class="math notranslate nohighlight"> +\[GK_{\textbf{p}, \sigma} (\textbf{x}) = e^{-\frac{1}{2}\frac{||\textbf{x} - \textbf{p}||^2}{\sigma^2}}\]</div> +<p>Using that kernel, we can calculate the KDE of a set of points <span class="math notranslate nohighlight">\(P\)</span> with associated distributions <span class="math notranslate nohighlight">\(S\)</span> calculating their individual +Gaussian distributions, summing them up and dividing them by the total number of points <span class="math notranslate nohighlight">\(n\)</span>:</p> +<div class="math notranslate nohighlight"> +\[KDE(A, S)=\frac{1}{n}\sum_{i = 0}^{n}GK(x, p_{i}, \sigma_{i})\]</div> +<p>So I dove into implementing all of that into the offscreen rendering part, and that is when the lack of a float framebuffer would +charge its cost. As it can be seen above, just calculating each point’s density isn’t the whole part, as I also need to divide +everyone by the total number of points <span class="math notranslate nohighlight">\(n\)</span>, and then sum them all. The problem is that, if the number of points its big enough, +the individual densities will be really low, and that would not be a problem for a 32-bit precision float framebuffer, but that is +<em>definitely</em> a problem for a 8-bit integer framebuffer, as small enough values will simply underflow and disappear. That issue is +currently under investigation, and some solutions have already being presented, as I will show in the <strong>Objectives in Progress</strong> +section.</p> +<p>Apart from that, after having the experimental program ready, I focused on modularizing it into a functional and simple API +(without the <span class="math notranslate nohighlight">\(n\)</span> division for now), and I could get a good set of results from that. The API I first developed implemented the +<em>EffectManager</em> class, responsible for managing all of the behind-the-scenes steps necessary for the kde render to work, +encapsulated inside the <em>ÈffectManager.kde()</em> method. It had the following look:</p> +<aside class="system-message"> +<p class="system-message-title">System Message: ERROR/3 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-21-joaodellagli-final-report.rst</span>, line 162)</p> +<p>Error in “code-block” directive: +maximum 1 argument(s) allowed, 9 supplied.</p> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="o">..</span> <span class="n">code</span><span class="o">-</span><span class="n">block</span><span class="p">::</span> <span class="n">python</span> + <span class="kn">from</span> <span class="nn">fury.effect_manager</span> <span class="kn">import</span> <span class="n">EffectManager</span> + <span class="kn">from</span> <span class="nn">fury</span> <span class="kn">import</span> <span class="n">window</span> + + <span class="n">showm</span> <span class="o">=</span> <span class="n">window</span><span class="o">.</span><span class="n">ShowManager</span><span class="p">(</span><span class="o">...</span><span class="p">)</span> + + <span class="c1"># KDE rendering setup</span> + <span class="n">em</span> <span class="o">=</span> <span class="n">EffectManager</span><span class="p">(</span><span class="n">showm</span><span class="p">)</span> + <span class="n">kde_actor</span> <span class="o">=</span> <span class="n">em</span><span class="o">.</span><span class="n">kde</span><span class="p">(</span><span class="o">...</span><span class="p">)</span> + <span class="c1"># End of KDE rendering setup</span> + + <span class="n">showmn</span><span class="o">.</span><span class="n">scene</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">kde_actor</span><span class="p">)</span> + + <span class="n">showm</span><span class="o">.</span><span class="n">start</span><span class="p">()</span> +</pre></div> +</div> +</aside> +<p>Those straightforward instructions, that hid several lines of code and setup, could manage to output the following result:</p> +<img alt="API 3D KDE plot" class="align-center" src="https://raw.githubusercontent.com/JoaoDell/gsoc_assets/main/images/fianl_3d_plot.png" /> +<p>And this was not the only feature I had implemented for this API, as the use of <em>WindowToImageFilter</em> method opened doors for a +whole new world for FURY: The world of post-processing effects. With this features setup, I managed to implement a <em>gaussian blur</em> +effect, a <em>grayscale</em> effect and a <em>Laplacian</em> effect for calculating “borders”:</p> +<img alt="Gaussian Blur effect" class="align-center" src="https://raw.githubusercontent.com/JoaoDell/gsoc_assets/main/images/gaussian_blur.png" /> +<img alt="Grayscale effect" class="align-center" src="https://raw.githubusercontent.com/JoaoDell/gsoc_assets/main/images/grayscale.png" /> +<img alt="Laplacian effect" class="align-center" src="https://raw.githubusercontent.com/JoaoDell/gsoc_assets/main/images/laplacian1.gif" /> +<p>As this wasn’t the initial goal of the project and I still had several issues to deal with, I have decided to leave these features as a +future addition.</p> +<p>Talking with my mentors, we realized that the first KDE API, even though simple, could lead to bad usage from users, as the +<em>em.kde()</em> method, that outputted a <em>FURY actor</em>, had dependencies different from any other object of its kind, making it a new +class of actors, which could lead to confusion and bad handling. After some pair programming sessions, they instructed me to take +a similar, but different road from what I was doing, turning the kde actor into a new class, the <em>KDE</em> class. This class would +have almost the same set of instructions present in the prior method, but it would break them in a way it would only be completely +set up after being passed to the <em>EffectManager</em> via its add function. Below, how the refactoring handles it:</p> +<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">fury.effects</span> <span class="kn">import</span> <span class="n">EffectManager</span><span class="p">,</span> <span class="n">KDE</span> +<span class="kn">from</span> <span class="nn">fury</span> <span class="kn">import</span> <span class="n">window</span> + +<span class="n">showm</span> <span class="o">=</span> <span class="n">window</span><span class="o">.</span><span class="n">ShowManager</span><span class="p">(</span><span class="o">...</span><span class="p">)</span> + +<span class="c1"># KDE rendering setup</span> +<span class="n">em</span> <span class="o">=</span> <span class="n">EffectManager</span><span class="p">(</span><span class="n">showm</span><span class="p">)</span> +<span class="n">kde_effect</span> <span class="o">=</span> <span class="n">KDE</span><span class="p">(</span><span class="o">...</span><span class="p">)</span> +<span class="n">em</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">kde_effect</span><span class="p">)</span> +<span class="c1"># End of KDE rendering setup</span> + +<span class="n">showm</span><span class="o">.</span><span class="n">start</span><span class="p">()</span> +</pre></div> +</div> +<p>Which outputted the same results as shown above. It may have cost some simplicity as we are now one line farther from having it +working, but it is more explicit in telling the user this is not just a normal actor.</p> +<p>Another detail I worked on was the kernel variety. The Gaussian Kernel isn’t the only one available to model density distributions, +there are several others that can do that job, as it can be seen in this <a class="reference external" href="https://scikit-learn.org/stable/modules/density.html">scikit-learn piece of documentation</a> +and this <a class="reference external" href="https://en.wikipedia.org/wiki/Kernel_(statistics)">Wikipedia page on kernels</a>. Based on the scikit-learn KDE +implementation, I worked on implementing the following kernels inside our API, that can be chosen as a parameter when calling the +<em>KDE</em> class:</p> +<ul class="simple"> +<li><p>Cosine</p></li> +<li><p>Epanechnikov</p></li> +<li><p>Exponential</p></li> +<li><p>Gaussian</p></li> +<li><p>Linear</p></li> +<li><p>Tophat</p></li> +</ul> +<p>Below, the comparison between them using the same set of points and bandwidths:</p> +<img alt="Comparison between the six implemented kernels" class="align-center" src="https://raw.githubusercontent.com/JoaoDell/gsoc_assets/main/images/kernels.png" /> +<p><em>Pull Requests</em>:</p> +<ul class="simple"> +<li><p><strong>First Stage of the KDE Rendering API (will be merged soon)</strong>: <a class="github reference external" href="https://github.com/fury-gl/fury/pull/826">fury-gl/fury#826</a></p></li> +</ul> +<p>All of this work culminated in PR <a class="reference external" href="https://github.com/fury-gl/fury/pull/826/">#826</a>, that proposes to add the first stage of +this API (there are some details yet to be completed, like the <span class="math notranslate nohighlight">\(n\)</span> division) to FURY. This PR added the described API, and also +proposed some minor changes to some already existing FURY functions related to callbacks, changes necessary for this and other +future applications that would use it to work. It also added the six kernels described, and a simple documented example on how +to use this feature.</p> +</dd> +</dl> +</li> +</ul> +</section> +<section id="other-objectives"> +<h2>Other Objectives</h2> +<ul class="simple"> +<li><dl class="simple"> +<dt><strong>Stretch Goals</strong><span class="classifier">SDE Implementation, Network/Graph visualization using SDE/KDE, Tutorials</span></dt><dd><ul> +<li><p>Investigate SDE calculation for surface datasets.</p></li> +<li><p>Implement SDE calculation inside the framebuffer rendering shaders.</p></li> +<li><p>Test SDE for multiple datasets.</p></li> +<li><p>Develop comprehensive tutorials that explain SDE concepts and FURY API usage.</p></li> +<li><p>Create practical, scenario-based tutorials using real datasets and/or simulations.</p></li> +</ul> +</dd> +</dl> +</li> +</ul> +</section> +<section id="objectives-in-progress"> +<h2>Objectives in Progress</h2> +<ul> +<li><dl> +<dt><strong>KDE Calculations</strong> (ongoing)</dt><dd><p>The KDE rendering, even though almost complete, have the $n$ division, an important step, missing, as this normalization allows colormaps +to cover the whole range o values rendered. The lack of a float FBO made a big difference in the project, as the search for a functional implementation of it not only delayed the project, but it is vital for +the correct calculations to work.</p> +<p>For the last part, a workaround thought was to try an approach I later figured out is an old one, as it can be check in +<a class="reference external" href="https://developer.nvidia.com/gpugems/gpugems/part-ii-lighting-and-shadows/chapter-12-omnidirectional-shadow-mapping">GPU Gems 12.3.3 section</a>: +If I need 32-bit float precision and I got 4 8-bit integer precision available, why not trying to pack this float into this RGBA +texture? I have first tried to do one myself, but it didn’t work for some reason, so I tried <a class="reference external" href="https://aras-p.info/blog/2009/07/30/encoding-floats-to-rgba-the-final/">Aras Pranckevičius</a> +implementation, that does the following:</p> +<div class="highlight-GLSL notranslate"><div class="highlight"><pre><span></span><span class="kt">vec4</span><span class="w"> </span><span class="n">float_to_rgba</span><span class="p">(</span><span class="kt">float</span><span class="w"> </span><span class="n">value</span><span class="p">)</span><span class="w"> </span><span class="p">{</span> +<span class="w"> </span><span class="kt">vec4</span><span class="w"> </span><span class="n">bitEnc</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="kt">vec4</span><span class="p">(</span><span class="mf">1.</span><span class="p">,</span><span class="mf">256.</span><span class="p">,</span><span class="mf">65536.0</span><span class="p">,</span><span class="mf">16777216.0</span><span class="p">);</span> +<span class="w"> </span><span class="kt">vec4</span><span class="w"> </span><span class="n">enc</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">bitEnc</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">value</span><span class="p">;</span> +<span class="w"> </span><span class="n">enc</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">fract</span><span class="p">(</span><span class="n">enc</span><span class="p">);</span> +<span class="w"> </span><span class="n">enc</span><span class="w"> </span><span class="o">-=</span><span class="w"> </span><span class="n">enc</span><span class="p">.</span><span class="n">yzww</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="kt">vec2</span><span class="p">(</span><span class="mf">1.</span><span class="o">/</span><span class="mf">255.</span><span class="p">,</span><span class="w"> </span><span class="mf">0.</span><span class="p">).</span><span class="n">xxxy</span><span class="p">;</span> +<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="n">enc</span><span class="p">;</span> +<span class="p">}</span> +</pre></div> +</div> +<p>That initially worked, but for some reason I am still trying to understand, it is resulting in a really noisy texture:</p> +<img alt="Noisy KDE render" class="align-center" src="https://raw.githubusercontent.com/JoaoDell/gsoc_assets/main/images/noisy%20kde.png" /> +<p>One way to try to mitigate that while is to pass this by a gaussian blur filter, to try to smooth out the result:</p> +<img alt="Blurred result" class="align-center" src="https://raw.githubusercontent.com/JoaoDell/gsoc_assets/main/images/blurred_kde.png" /> +<p>But it is not an ideal solution as well, as it may lead to distortions in the actual density values, depending on the application of +the KDE. Now, my goal is to first find the root of the noise problem, and then, if that does not work, try to make the gaussian filter +work.</p> +<p>Another detail that would be a good addition to the API is UI controls. Filipi, one of my mentors, told me it would be a good feature +if the user could control the intensities of the bandwidths for a better structural visualization of the render, and knowing FURY already +have a good set of <a class="reference external" href="https://fury.gl/latest/auto_examples/index.html#user-interface-elements">UI elements</a>, I just needed to integrate +that into my program via callbacks. I tried implementing an intensity slider. However, for some reason, it is making the program crash +randomly, for reasons I still don’t know, so that is another issue under investigation. Below, we show a first version of that feature, +which was working before the crashes:</p> +<img alt="Slider for bandwidths" class="align-center" src="https://raw.githubusercontent.com/JoaoDell/gsoc_assets/main/images/slider.gif" /> +<p><em>Pull Requests</em></p> +<ul class="simple"> +<li><p><strong>UI intensity slider for the KDE rendering API (draft)</strong>: <a class="github reference external" href="https://github.com/fury-gl/fury/pull/849">fury-gl/fury#849</a></p></li> +<li><p><strong>Post-processing effects for FURY Effects API (draft)</strong>: <a class="github reference external" href="https://github.com/fury-gl/fury/pull/850">fury-gl/fury#850</a></p></li> +</ul> +</dd> +</dl> +</li> +</ul> +</section> +<section id="gsoc-weekly-blogs"> +<h2>GSoC Weekly Blogs</h2> +<ul class="simple"> +<li><p>My blog posts can be found at <a class="reference external" href="https://fury.gl/latest/blog/author/joao-victor-dell-agli-floriano.html">FURY website</a> and <a class="reference external" href="https://blogs.python-gsoc.org/en/joaodellaglis-blog/">Python GSoC blog</a>.</p></li> +</ul> +</section> +<section id="timeline"> +<h2>Timeline</h2> +<aside class="system-message"> +<p class="system-message-title">System Message: ERROR/3 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-21-joaodellagli-final-report.rst</span>, line 332)</p> +<p>Malformed table.</p> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>+---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Date | Description | Blog Post Link | ++=====================+====================================================+===========================================================================================================================================================================================================+ +| Week 0 (29-05-2023) | The Beginning of Everything | `FURY &lt;https://fury.gl/latest/posts/2023/2023-05-29-week-0-joaodellagli.html&gt;`__ - `Python &lt;https://blogs.python-gsoc.org/en/joaodellaglis-blog/the-beggining-of-everything-week-0/&gt;`__ | ++---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 1 (05-06-2022) | The FBO Saga | `FURY &lt;https://fury.gl/latest/posts/2023/2023-06-05-week-1-joaodellagli.html&gt;`__ - `Python &lt;https://blogs.python-gsoc.org/en/joaodellaglis-blog/the-fbo-saga-week-1/&gt;`__ | ++---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 2 (12-06-2022) | The Importance of (good) Documentation | `FURY &lt;https://fury.gl/latest/posts/2023/2023-06-12-week-2-joaodellagli.html&gt;`__ - `Python &lt;https://blogs.python-gsoc.org/en/joaodellaglis-blog/the-importance-of-good-documentation-week-2/&gt;`__ | ++---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 3 (19-06-2022) | Watch Your Expectations | `FURY &lt;https://fury.gl/latest/posts/2023/2023-06-19-week-3-joaodellagli.html&gt;`__ - `Python &lt;https://blogs.python-gsoc.org/en/joaodellaglis-blog/week-3-watch-your-expectations/&gt;`__ | ++---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 4 (26-06-2022) | Nothing is Ever Lost | `FURY &lt;https://fury.gl/latest/posts/2023/2023-06-26-week-4-joaodellagli.html&gt;`__ - `Python &lt;https://blogs.python-gsoc.org/en/joaodellaglis-blog/week-4-nothing-is-ever-lost/&gt;`__ | ++---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 5 (03-07-2022) | All Roads Lead to Rome | `FURY &lt;https://fury.gl/latest/posts/2023/2023-07-03-week-5-joaodellagli.html&gt;`__ - `Python &lt;https://blogs.python-gsoc.org/en/joaodellaglis-blog/week-5-all-roads-lead-to-rome/&gt;`__ | ++---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 6 (10-07-2022) | Things are Starting to Build Up | `FURY &lt;https://fury.gl/latest/posts/2023/2023-07-10-week-6-joaodellagli.html&gt;`__ - `Python &lt;https://blogs.python-gsoc.org/en/joaodellaglis-blog/week-6-things-are-starting-to-build-up/&gt;`__ | ++---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 7 (17-07-2022) | Experimentation Done | `FURY &lt;https://fury.gl/latest/posts/2023/2023-07-17-week-7-joaodellagli.html&gt;`__ - `Python &lt;https://blogs.python-gsoc.org/en/joaodellaglis-blog/week-7-experimentation-done/&gt;`__ | ++---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 8 (24-07-2022) | The Birth of a Versatile API | `FURY &lt;https://fury.gl/latest/posts/2023/2023-07-24-week-8-joaodellagli.html&gt;`__ - `Python &lt;https://blogs.python-gsoc.org/en/joaodellaglis-blog/week-8-the-birth-of-a-versatile-api/&gt;`__ | ++---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 9 (31-07-2022) | It is Polishing Time! | `FURY &lt;https://fury.gl/latest/posts/2023/2023-07-31-week-9-joaodellagli.html&gt;`__ - `Python &lt;https://blogs.python-gsoc.org/en/joaodellaglis-blog/week-9-it-is-polishing-time/&gt;`__ | ++---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 10 (07-08-2022)| Ready for Review! | `FURY &lt;https://fury.gl/latest/posts/2023/2023-08-07-week-10-joaodellagli.html&gt;`__ - `Python &lt;https://blogs.python-gsoc.org/en/joaodellaglis-blog/ready-for-review/&gt;`__ | ++---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 11 (14-08-2022)| A Refactor is Sometimes Needed | `FURY &lt;https://fury.gl/latest/posts/2023/2023-08-14-week-11-joaodellagli.html&gt;`__ - `Python &lt;https://blogs.python-gsoc.org/en/joaodellaglis-blog/a-refactor-is-sometimes-needed/&gt;`__ | ++---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 12 (21-08-2022)| Now That is (almost) a Wrap! | `FURY &lt;https://fury.gl/latest/posts/2023/2023-08-21-week-12-joaodellagli.html&gt;`__ - `Python &lt;https://blogs.python-gsoc.org/en/joaodellaglis-blog/week-12-now-that-is-almost-a-wrap/&gt;`__ | ++---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +</pre></div> +</div> +</aside> +</section> +</section> + + + Name: João Victor Dell Agli Floriano + + 2023-08-21T00:00:00-04:00 + + + https://fury.gl/posts/2023/2023-08-14-week-11-joaodellagli.html + Week 11: A Refactor is Sometimes Needed + 2023-08-14T00:00:00-04:00 + + João Victor Dell Agli Floriano + + <section id="week-11-a-refactor-is-sometimes-needed"> + +<p>Hello everyone, it’s time for another weekly blogpost! Today I am going to share some updates on the API refactoring +I was working on with my mentors.</p> +<section id="last-week-s-effort"> +<h2>Last Week’s Effort</h2> +<p>As I shared with you <span class="xref std std-doc">last week</span>, the first draft of my API was finally ready for review, as +I finished tweaking some remaining details missing. I was tasked with finding a good example of the usage of the tools we proposed, +and I started to do that, however after testing it with some examples, I figured out some significant bugs were to be fixed. Also, +after some reviews and hints from some of my mentors and other GSoC contributors, we realised that some refactoring should be done, +mainly focused on avoiding bad API usage from the user.</p> +</section> +<section id="so-how-did-it-go"> +<h2>So how did it go?</h2> +<p>Initially, I thought only one bug was the source of the issues the rendering presented, but it turned out to be two, which I will +explain further.</p> +<p>The first bug was related to scaling and misalignment of the KDE render. The render of the points being post-processed was not only +with sizes different from the original set size, but it was also misaligned, making it appear in positions different from the points’ +original ones. After some time spent, I figured out the bug was related to the texture coordinates I was using. Before, this is how +my fragment shader looked:</p> +<div class="highlight-C notranslate"><div class="highlight"><pre><span></span><span class="n">vec2</span><span class="w"> </span><span class="n">res_factor</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">vec2</span><span class="p">(</span><span class="n">res</span><span class="p">.</span><span class="n">y</span><span class="o">/</span><span class="n">res</span><span class="p">.</span><span class="n">x</span><span class="p">,</span><span class="w"> </span><span class="mf">1.0</span><span class="p">);</span> +<span class="n">vec2</span><span class="w"> </span><span class="n">tex_coords</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">res_factor</span><span class="o">*</span><span class="n">normalizedVertexMCVSOutput</span><span class="p">.</span><span class="n">xy</span><span class="o">*</span><span class="mf">0.5</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mf">0.5</span><span class="p">;</span> +<span class="kt">float</span><span class="w"> </span><span class="n">intensity</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">texture</span><span class="p">(</span><span class="n">screenTexture</span><span class="p">,</span><span class="w"> </span><span class="n">tex_coords</span><span class="p">).</span><span class="n">r</span><span class="p">;</span> +</pre></div> +</div> +<p>It turns out using this texture coordinates for <em>this case</em> was not the best choice, as even though it matches the fragment positions, +the idea here was to render the offscreen window, which has the same size as the onscreen one, to the billboard actor. With that in mind, +I realised the best choice was using texture coordinates that matched the whole screen positions, coordinates that were derived from the +<code class="docutils literal notranslate"><span class="pre">gl_FragCoord.xy</span></code>, being the division of that by the resolution of the screen, for normalization. Below, the change made:</p> +<div class="highlight-C notranslate"><div class="highlight"><pre><span></span><span class="n">vec2</span><span class="w"> </span><span class="n">tex_coords</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">gl_FragCoord</span><span class="p">.</span><span class="n">xy</span><span class="o">/</span><span class="n">res</span><span class="p">;</span> +<span class="kt">float</span><span class="w"> </span><span class="n">intensity</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">texture</span><span class="p">(</span><span class="n">screenTexture</span><span class="p">,</span><span class="w"> </span><span class="n">tex_coords</span><span class="p">).</span><span class="n">r</span><span class="p">;</span> +</pre></div> +</div> +<p>This change worked initially, although with some problems, that later revealed the resolution of the offscreen window needed to be +updated inside the callback function as well. Fixing that, it was perfectly aligned and scaled!</p> +<p>The second bug was related with the handling of the bandwidth, former sigma parameter. I realised I wasn’t dealing properly with the option of the user passing only +one single bandwidth value being passed, so when trying that, only the first point was being rendered. I also fixed that and it worked, +so cheers!</p> +<p>As I previously said, the bugs were not the only details I spent my time on last week. Being reviewed, the API design, even +though simple, showed itself vulnerable to bad usage from the user side, requiring some changes. The changes suggested by mentors were, +to, basically, take the <code class="docutils literal notranslate"><span class="pre">kde</span></code> method out of the <code class="docutils literal notranslate"><span class="pre">EffectManager</span></code> class, and create a new class from it inside an <code class="docutils literal notranslate"><span class="pre">effects</span></code> module, +like it was a special effects class. With this change, the KDE setup would go from:</p> +<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">em</span> <span class="o">=</span> <span class="n">EffectManager</span><span class="p">(</span><span class="n">show_manager</span><span class="p">)</span> + +<span class="n">kde_actor</span> <span class="o">=</span> <span class="n">em</span><span class="o">.</span><span class="n">kde</span><span class="p">(</span><span class="o">...</span><span class="p">)</span> + +<span class="n">show_manager</span><span class="o">.</span><span class="n">scene</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">kde_actor</span><span class="p">)</span> +</pre></div> +</div> +<p>To:</p> +<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">em</span> <span class="o">=</span> <span class="n">EffectManager</span><span class="p">(</span><span class="n">show_manager</span><span class="p">)</span> + +<span class="n">kde_effect</span> <span class="o">=</span> <span class="n">KDE</span><span class="p">(</span><span class="o">...</span><span class="p">)</span> + +<span class="n">em</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">kde_effect</span><span class="p">)</span> +</pre></div> +</div> +<p>Not a gain in line shortening, however, a gain in security, as preventing users from misusing the kde_actor. Something worth noting is +that I learned how to use the <code class="docutils literal notranslate"><span class="pre">functools.partial</span></code> function, that allowed me to partially call the callback function with only some +parameters passed.</p> +</section> +<section id="this-week-s-goals"> +<h2>This Week’s Goals</h2> +<p>Having that refactoring made, now I am awaiting for a second review so we could finally wrap it up and merge the first stage of this API. +With that being done, I will write the final report and wrap this all up.</p> +<p>Let’s get to work!</p> +</section> +</section> + + + Hello everyone, it’s time for another weekly blogpost! Today I am going to share some updates on the API refactoring +I was working on with my mentors. + + 2023-08-14T00:00:00-04:00 + + + https://fury.gl/posts/2023/2023-08-07-week-10-joaodellagli.html + Week 10: Ready for Review! + 2023-08-07T00:00:00-04:00 + + João Victor Dell Agli Floriano + + <section id="week-10-ready-for-review"> + +<p>Hello everyone, it’s time for another weekly blogpost!</p> +<section id="last-week-s-effort"> +<h2>Last Week’s Effort</h2> +<p>After talking with my mentors, I was tasked with getting my API PR <a class="reference external" href="https://github.com/fury-gl/fury/pull/826">#826</a> ready for review, +as it still needed some polishing, and the most important of all, it needed its tests working, as this was something I haven’t invested time since its creation. +Having that in mind, I have spent the whole week cleaning whatever needed, writing the tests, and also writing a simple example of its +usage. I also tried implementing a little piece of UI so the user could control the intensity of the bandwidth of the KDE render, but +I had a little problem I will talk about below.</p> +</section> +<section id="so-how-did-it-go"> +<h2>So how did it go?</h2> +<p>Fortunately, for the cleaning part, I didn’t have any trouble, and my PR is finally ready for review! The most complicated part was to write the tests, as this is something that +requires attention to understand what needs to be tested, exactly. As for the UI part, I managed to have a slider working for the +intensity, however, it was crashing the whole program for a reason, so I decided to leave this idea behind for now. +Below, an example of how this should work:</p> +<img alt="Buggy slider for the intensity control of the bandwidth of the KDE" class="align-center" src="https://raw.githubusercontent.com/JoaoDell/gsoc_assets/main/images/slider.gif" /> +</section> +<section id="this-week-s-goals"> +<h2>This Week’s Goals</h2> +<p>After a meeting with my mentors, we decided that this week’s focus should be on finding a good usage example of the KDE rendering feature, +to have it as a showcase of the capability of this API. Also, they hinted me some changes that need to be done regarding the API, so I +will also invest some time on refactoring it.</p> +<p>Wish me luck!</p> +</section> +</section> + + + Hello everyone, it’s time for another weekly blogpost! + + 2023-08-07T00:00:00-04:00 + + + https://fury.gl/posts/2023/2023-07-31-week-9-joaodellagli.html + Week 9: It is Polishing Time! + 2023-07-31T00:00:00-04:00 + + João Victor Dell Agli Floriano + + <section id="week-9-it-is-polishing-time"> + +<p>Hello everyone, it’s time for another weekly blogpost! Today, I am going to update you on my project’s latest changes.</p> +<section id="last-week-s-effort"> +<h2>Last Week’s Effort</h2> +<p>After having finished a first draft of the API that will be used for the KDE rendering, and showing how it could be used +for other post-processing effects, my goal was to clean the code and try some details that would add to it so it could be better +complete. Having that in mind, I invested in three work fronts:</p> +<ol class="arabic simple"> +<li><p>Fixing some bugs related to the rendering more than one post-processing effect actor.</p></li> +<li><p>Experimenting with other rendering kernels (I was using the <em>gaussian</em> one only).</p></li> +<li><p>Completing the KDE render by renormalizing the values in relation to the number of points (one of the core KDE details).</p></li> +</ol> +<p>Both three turned out more complicated than it initially seemed, as I will show below.</p> +</section> +<section id="so-how-did-it-go"> +<h2>So how did it go?</h2> +<p>The first one I did on monday-tuesday, and I had to deal with some issues regarding scaling and repositioning. Due to implementation +choices, the final post-processed effects were rendered either bigger than they were in reality, or out of their original place. +After some time dedicated to finding the root of the problems, I could fix the scaling issue, however I realised I would need to, +probably, rethink the way the API was implemented. As this general post-processing effects is a side-project that comes as a consequence of +my main one, I decided to leave that investment to another time, as I would need to guarantee the quality of the second.</p> +<p>The second was an easy and rather interesting part of my week, as I just needed to setup new kernel shaders. Based on +<a class="reference external" href="https://scikit-learn.org/stable/modules/density.html">scikit-learn KDE documentation</a>, I could successfully implement the following kernels:</p> +<ul class="simple"> +<li><p>Gaussian</p></li> +</ul> +<div class="math notranslate nohighlight"> +\[K(x, y) = e^{\frac{-(x^2 + y^2)}{2\sigma^2}}\]</div> +<ul class="simple"> +<li><p>Tophat</p></li> +</ul> +<div class="math notranslate nohighlight"> +\[K(x, y) = 1.0, \ \ |x^2 + y^2| &lt; \sigma\]</div> +<ul class="simple"> +<li><p>Epanechnikov</p></li> +</ul> +<div class="math notranslate nohighlight"> +\[K(x, y) = 1 - \frac{x^2 + y^2}{\sigma^2}\]</div> +<ul class="simple"> +<li><p>Exponential</p></li> +</ul> +<div class="math notranslate nohighlight"> +\[K(x, y) = e^{\frac{-|x^2 + y^2|}{\sigma}}\]</div> +<ul class="simple"> +<li><p>Linear</p></li> +</ul> +<div class="math notranslate nohighlight"> +\[K(x, y) = 1 - \frac{|x^2 + y^2|}{\sigma}, \ \ |x^2 + y^2| &lt; \sigma\]</div> +<ul class="simple"> +<li><p>Cosine</p></li> +</ul> +<div class="math notranslate nohighlight"> +\[K(x, y) = cos(\frac{\pi|x^2 + y^2|}{2\sigma})\]</div> +<p>That outputted the following (beautiful) results for a set of 1000 random points with random sigmas:</p> +<img alt="Different kernel approaches" class="align-center" src="https://raw.githubusercontent.com/JoaoDell/gsoc_assets/main/images/kernels.png" /> +<p>The third one is still being a trickier challenge. If you recall from my first blogposts, I spent something around <em>one month</em> trying to setup +float framebuffer objects to FURY with VTK so I could use them in my project. After spending all of that time with no results, +me and Bruno, my mentor, <span class="xref std std-doc">found a way</span> to do what we wanted to do, but using a different VTK class, +<a class="reference external" href="https://vtk.org/doc/nightly/html/classvtkWindowToImageFilter.html">vtkWindowToImageFilter</a>. Well, it was a good workaround back then and +it lead me all the way here, however now it is costing a price. The float framebuffers were an important part of the project because they +would allow us to pass <em>32-bit float information</em> from one shader to another, which would be important as they would allow the densities to +have higher precision and more fidelity to the calculations. When rendering a KDE of a given set of points, we use the below function:</p> +<div class="math notranslate nohighlight"> +\[KDE(x, y) = \frac{1}{n} \sum_{i = 0}^n K(x, y)\]</div> +<p>If the number of points <span class="math notranslate nohighlight">\(n\)</span> is big enough, some KDE results will be really low. This presents a real problem to our implementation because, without +the float framebuffers, it is currently only being possible to pass <em>8-bit unsigned char</em> information, that only allows 256 values. +This is far from ideal, as low values would have alone densities low enough to disappear. This presented a problem as to renormalize the +densities, I was retrieving the texture to the CPU, calculating its minimum and maximum values, and passing to the fragment shader as uniforms +for the renormalization, which didn’t work if the maximum values calculated were zero.</p> +<p>One solution I thought to solve that was a really heavy workaround: if an unsigned float is 32-bit and I have exactly 4 8-bit +unsigned chars, why not try to pack this float into these 4 chars? Well, this is an interesting approach which I figured out is already an +old one, being reported in <a class="reference external" href="https://developer.nvidia.com/gpugems/gpugems/part-ii-lighting-and-shadows/chapter-12-omnidirectional-shadow-mapping">GPU Gems’s chapter 12</a>. +Unfortunately I haven’t tried yet this implementation yet, and went for one I thought myself, which haven’t exactly worked. I also tried +this implementation from <a class="reference external" href="https://aras-p.info/blog/2009/07/30/encoding-floats-to-rgba-the-final/">Aras Pranckevičius’ website</a>, which seems +to be working, even though not perfectly:</p> +<img alt="Noisy float to RGBA encoding" class="align-center" src="https://raw.githubusercontent.com/JoaoDell/gsoc_assets/main/images/noisy%20kde.png" /> +<p>As you can see, this implementation is <em>really noisy</em>. I think this has to deal with floating point rounding errors, so to try to mitigate +that, I experimented applying a <em>13x13 gaussian blur</em> to it. Below, what I got from that:</p> +<img alt="Blurred KDE result" class="align-center" src="https://raw.githubusercontent.com/JoaoDell/gsoc_assets/main/images/blurred_kde.png" /> +<p>That looks way better, even though not ideal yet.</p> +</section> +<section id="this-week-s-goals"> +<h2>This Week’s Goals</h2> +<p>Talking with my mentors, we decided it was better if I focused on the version without the renormalization for now, as it was already +done and running fine. So for this week, I plan to clean my PR to finally have it ready for a first review, and maybe add to it a little +UI tool to control the intensity of the densities. That should take me some time and discussion, but I hope for it to be ready by the +end of the week.</p> +<p>Let’s get to work!</p> +</section> +</section> + + + Hello everyone, it’s time for another weekly blogpost! Today, I am going to update you on my project’s latest changes. + + 2023-07-31T00:00:00-04:00 + + + https://fury.gl/posts/2023/2023-07-24-week-8-joaodellagli.html + Week 8: The Birth of a Versatile API + 2023-07-24T00:00:00-04:00 + + João Victor Dell Agli Floriano + + <section id="week-8-the-birth-of-a-versatile-api"> + +<p>Hello everyone, it’s time for another weekly blogpost! Today, I am going to tell you all about how is the KDE API development going, and +to show you the potential this holds for the future!</p> +<section id="last-week-s-effort"> +<h2>Last Week’s Effort</h2> +<p>Last week I told you how I managed to render some KDE renders to the screen, both in 2D and 3D, as you may check by my last blogpost. +My new task was, as I had this example working, to start the API development. In a meeting with Bruno, one of my mentors, we debated +on how could this work, reaching two options:</p> +<ol class="arabic simple"> +<li><p>Implement the KDE in a single, simple actor.</p></li> +<li><p>Implement a KDE rendering manager, as a class.</p></li> +</ol> +<p>The first one would have the advantage of being simple and pretty straightforward, as a user would only need to call the actor and have +it working on their hands, having the tradeoff of leaving some important steps for a clean API hidden and static. These steps I mention +are related to how this rendering works, as I have previously <span class="xref std std-doc">showed you</span>, it relies on post-processing effects, +which need an offscreen rendering, that for example are done by the <em>callback functions</em>.</p> +<p>In short, these functions are instructions the user gives to the interactor to run inside the interaction loop. Inside FURY there are tree +types of callbacks passed to the window interactor:</p> +<ol class="arabic simple"> +<li><p><strong>Timer Callbacks</strong>: Added to the window interactor, they are a set of instructions that will be called from time to time, with interval defined by the user.</p></li> +<li><p><strong>Window Callbacks</strong>: Added directly to the window, they are a set of instructions called whenever an specific event is triggered.</p></li> +<li><p><strong>Interactor Callbacks</strong>: Added to the window interactor, they are a set of instructions called whenever an specific interaction, for example a mouse left-click, is triggered.</p></li> +</ol> +<p>In this API, I will be using the <em>Interactor Callback</em>, set by the <code class="docutils literal notranslate"><span class="pre">window.add_iren_callback()</span></code> function, that will be called whenever a <em>Render</em> +interaction is detected, and needs to be first passed to the onscreen manager.</p> +<p>These details are more complicated, and would need, for example, for the user to pass the onscreen manager to the <code class="docutils literal notranslate"><span class="pre">actor.kde()</span></code> function. +Also, in the case of a kde actor not being used anymore and being declared, the callback then passed would still exist inside the manager and +be called even when the kde actor is not on screen anymore, which is not ideal.</p> +<p>Knowing these problems, we thought of a second option, that would have the advantage of not leaving those details and steps behind. It has +the tradeoff of maybe complicating things as it would need to be called after calling the effects manager, but as I will show you below, +it is not that complicated <em>at all</em>.</p> +<p>I also reviewed my fellow GSoC contributors PR’s as well, PR <a class="reference external" href="https://github.com/fury-gl/fury/pull/810">#810</a> and +<a class="reference external" href="https://github.com/fury-gl/fury/pull/803">#803</a>. Bruno told me to take a look as well on <a class="reference external" href="https://www.conventionalcommits.org">Conventional Commits</a> , a way to standardize +commits by prefixes, so I did that as well.</p> +</section> +<section id="so-how-did-it-go"> +<h2>So how did it go?</h2> +<p>Well, the implemented manager class is named <code class="docutils literal notranslate"><span class="pre">EffectManager()</span></code> and to initialize it you only need to pass the onscreen manager. +The onscreen manager is the standard FURY window manager you would use in a normal FURY-based program:</p> +<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># Onscreen manager setup</span> +<span class="kn">from</span> <span class="nn">fury</span> <span class="kn">import</span> <span class="n">window</span> + +<span class="n">scene</span> <span class="o">=</span> <span class="n">window</span><span class="o">.</span><span class="n">Scene</span><span class="p">()</span> + +<span class="n">onscreen_manager</span> <span class="o">=</span> <span class="n">window</span><span class="o">.</span><span class="n">ShowManager</span><span class="p">(</span><span class="n">scene</span><span class="p">,</span> <span class="s2">&quot;demo&quot;</span><span class="p">,</span> <span class="p">(</span><span class="n">width</span><span class="p">,</span> <span class="n">height</span><span class="p">))</span> + +<span class="n">effects</span> <span class="o">=</span> <span class="n">EffectManager</span><span class="p">(</span><span class="n">onscreen_manager</span><span class="p">)</span> +</pre></div> +</div> +<p>After that, to render a KDE calculation of points to the screen, you need only to call its <code class="docutils literal notranslate"><span class="pre">kde()</span></code> function:</p> +<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">kde_actor</span> <span class="o">=</span> <span class="n">effects</span><span class="o">.</span><span class="n">kde</span><span class="p">(</span><span class="n">center</span><span class="p">,</span> <span class="n">points</span><span class="p">,</span> <span class="n">sigmas</span><span class="p">,</span> <span class="n">scale</span> <span class="o">=</span> <span class="mf">10.0</span><span class="p">,</span> <span class="n">colormap</span> <span class="o">=</span> <span class="s2">&quot;inferno&quot;</span><span class="p">)</span> +<span class="c1"># Those last two are optional</span> +</pre></div> +</div> +<p>Pass it to the onscreen manager scene:</p> +<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">onscreen_manager</span><span class="o">.</span><span class="n">scene</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">kde_actor</span><span class="p">)</span> +</pre></div> +</div> +<p>And to start it, as usual:</p> +<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">onscreen_manager</span><span class="o">.</span><span class="n">start</span><span class="p">()</span> +</pre></div> +</div> +<p>As simple as that. This three lines of code output the same result as I showed you last week, this time, with different sigmas for each +point:</p> +<img alt="3D KDE render" class="align-center" src="https://raw.githubusercontent.com/JoaoDell/gsoc_assets/main/images/3d_kde_gif.gif" /> +<p>After having that working, I experimented beyond. See, as I previously said, we are dealing here with <em>post-processing effects</em>, with KDE +being only one of the many existing ones, as this <a class="reference external" href="https://en.wikipedia.org/wiki/Video_post-processing">Wikipedia Page</a> on post processing shows. +Knowing that, I tried one of the first filters I learned, the Laplacian one. This filter is, as its name hints, applying the +<a class="reference external" href="https://en.wikipedia.org/wiki/Discrete_Laplace_operator">Discrete Laplace Operator</a> in an image. This filter shows sudden changes of value, a +good way to detect borders. The process is the same as the kde actor, requiring only the actor you want to apply the filter to. +Below, the result I got from applying that to a box actor:</p> +<img alt="Laplacian filter applied to a cube object." class="align-center" src="https://raw.githubusercontent.com/JoaoDell/gsoc_assets/main/images/laplacian1.gif" /> +<p>Something I found important to leave as an option was filter compositing. What if an user wanted to, for example, apply one laplacian filter +after another? Well, the example below shows that is possible as well:</p> +<img alt="Double laplacian application on the box actor." class="align-center" src="https://raw.githubusercontent.com/JoaoDell/gsoc_assets/main/images/laplacian2.gif" /> +<p>It still needs some tweaks and suffers from some bugs, but it works! Those represent important progress as it shows the versatility this +API may present. I have also already implemented <cite>grayscale</cite> and <cite>3x3 gaussian blur</cite> as well:</p> +<img alt="3x3 Gaussian Blur filter applied to a cube." class="align-center" src="https://raw.githubusercontent.com/JoaoDell/gsoc_assets/main/images/gaussian_blur.png" /> +<img alt="Grayscale filter applied to a cube." class="align-center" src="https://raw.githubusercontent.com/JoaoDell/gsoc_assets/main/images/grayscale.png" /> +</section> +<section id="this-week-s-goals"> +<h2>This Week’s Goals</h2> +<p>My plans for this week are to keep working and polishing the API, mainly the KDE part, so it can be ready for a first review. +When that is ready, I plan to experiment with more filters and make this more dynamic, maybe implementing a way to apply custom kernel +transformations, passed by the user, to the rendering process. This has been a really exciting journey and I am getting happy with the results!</p> +<p>Wish me luck!</p> +</section> +</section> + + + Hello everyone, it’s time for another weekly blogpost! Today, I am going to tell you all about how is the KDE API development going, and +to show you the potential this holds for the future! + + 2023-07-24T00:00:00-04:00 + + + https://fury.gl/posts/2023/2023-07-17-week-7-joaodellagli.html + Week 7: Experimentation Done + 2023-07-17T00:00:00-04:00 + + João Victor Dell Agli Floriano + + <section id="week-7-experimentation-done"> + +<p>Hello everyone, welcome to another weekly blogpost! Let’s talk about the current status of my project (spoiler: it is beautiful).</p> +<section id="last-week-s-effort"> +<h2>Last Week’s Effort</h2> +<p>Having accomplished a KDE rendering to a billboard last week, I was then tasked with trying a different approach to how the +rendering was done. So, to recap, below was how I was doing it:</p> +<ol class="arabic simple"> +<li><p>Render one point’s KDE offscreen to a single billboard, passing its position and sigma to the fragment shader as uniforms.</p></li> +<li><p>Capture the last rendering’s screen as a texture.</p></li> +<li><p>Render the next point’s KDE, and sum it up with the last rendering’s texture.</p></li> +<li><p>Do this until the end of the points.</p></li> +<li><p>Capture the final render screen as a texture.</p></li> +<li><p>Apply post processing effects (colormapping).</p></li> +<li><p>Render the result to the screen.</p></li> +</ol> +<p>This approach was good, but it had some later limitations and issues that would probably take more processing time and attention to details (correct matrix +transformations, etc) than the ideal. The different idea is pretty similar, but with some differences:</p> +<ol class="arabic simple"> +<li><p>Activate additive blending in OpenGL.</p></li> +<li><p>Render each point’s KDE to its own billboard, with position defined by the point’s position, all together in one pass.</p></li> +<li><p>Capture the rendered screen as a texture.</p></li> +<li><p>Pass this texture to a billboard.</p></li> +<li><p>Apply post processing effects (colormapping).</p></li> +<li><p>Render the result to the screen.</p></li> +</ol> +<p>So I needed to basically do that.</p> +</section> +<section id="was-it-hard"> +<h2>Was it Hard?</h2> +<p>Fortunately, it wasn’t so hard to do it in the end. Following those steps turned out pretty smooth, and after some days, +I had the below result:</p> +<img alt="Final 2D KDE render" class="align-center" src="https://raw.githubusercontent.com/JoaoDell/gsoc_assets/main/images/final_2d_plot.png" /> +<p>This is a 2D KDE render of random 1000 points. For this I used the <em>“viridis”</em> colormap from <cite>matplotlib</cite>. Some details worth noting:</p> +<ul class="simple"> +<li><p>For this to work, I have implemented three texture helper functions: <cite>window_to_texture()</cite>, <cite>texture_to_actor()</cite> and <cite>colormap_to_texture()</cite>. The first one captures a window and pass it as a texture to an actor, the second one passes an imported texture to an actor, and the last one passes a colormap, prior passed as an array, as a texture to an actor.</p></li> +<li><p>The colormap is directly get from <cite>matplotlib</cite>, available in its <cite>colormaps</cite> object.</p></li> +<li><p>This was only a 2D flatten plot. At first, I could not figure out how to make the connection between the offscreen interactor and the onscreen one, so rotating and moving around the render was not happening. After some ponder and talk to my mentors, they told me to use <em>callback</em> functions inside the interactor, and after doing that, I managed to make the 3D render work, which had the following result:</p></li> +</ul> +<img alt="3D KDE render" class="align-center" src="https://raw.githubusercontent.com/JoaoDell/gsoc_assets/main/images/3d_kde_gif.gif" /> +<p>After those results, I refactored my PR <a class="reference external" href="https://github.com/fury-gl/fury/pull/804">#804</a> to better fit its current status, and it is +now ready for review. Success!</p> +</section> +<section id="this-week-s-goals"> +<h2>This Week’s Goals</h2> +<p>After finishing the first iteration of my experimental program, the next step is to work on an API for KDE rendering. I plan to meet +with my mentors and talk about the details of this API, so expect an update next week. Also, I plan to take a better look on my fellow GSoC FURY +contributors work so when their PRs are ready for review, I will have to be better prepared for it.</p> +<p>Let’s get to work!</p> +</section> +</section> + + + Hello everyone, welcome to another weekly blogpost! Let’s talk about the current status of my project (spoiler: it is beautiful). + + 2023-07-17T00:00:00-04:00 + + + https://fury.gl/posts/2023/2023-07-10-week-6-joaodellagli.html + Week 6: Things are Starting to Build Up + 2023-07-10T00:00:00-04:00 + + João Victor Dell Agli Floriano + + <section id="week-6-things-are-starting-to-build-up"> + +<p>Hello everyone, time for a other weekly blogpost! Today, I will show you my current progress on my project and latest activities.</p> +<section id="what-i-did-last-week"> +<h2>What I did Last Week</h2> +<p>Last week I had the goal to implement KDE rendering to the screen (if you want to understand what this is, check my <a href="#id1"><span class="problematic" id="id2">:doc:`last blogpost &lt;2023-07-03-week-5-joaodellagli&gt;`_</span></a>). +After some days diving into the code, I finally managed to do it:</p> +<aside class="system-message" id="id1"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-07-10-week-6-joaodellagli.rst</span>, line 14); <em><a href="#id2">backlink</a></em></p> +<p>Mismatch: both interpreted text role prefix and reference suffix.</p> +</aside> +<img alt="KDE render to a billboard" class="align-center" src="https://raw.githubusercontent.com/JoaoDell/gsoc_assets/main/images/buffer_compose.png" /> +<p>This render may seem clean and working, but the code isn’t exactly like that. For this to work, some tricks and work arounds needed to +be done, as I will describe in the section below.</p> +<p>Also, I reviewed the shader part of Tania’s PR <a class="reference external" href="https://github.com/fury-gl/fury/pull/791">#791</a>, that implement ellipsoid actors inside +FURY. It was my first review of a PR that isn’t a blogpost, so it was an interesting experience and I hope I can get better at it.</p> +<p>It is important as well to point out that I had to dedicate myself to finishing my graduation capstone project’s presentation that I will attend +to this week, so I had limited time to polish my code, which I plan to do better this week.</p> +</section> +<section id="where-the-problem-was"> +<h2>Where the Problem Was</h2> +<p>The KDE render basically works rendering the KDE of a point to a texture and summing that texture to the next render. For this to work, +the texture, rendered to a billboard, needs to be the same size of the screen, otherwise the captured texture will include the black background. +The problem I faced with that is that the billboard scaling isn’t exactly well defined, so I had to guess for a fixed screen size +(in this example, I worked with <em>600x600</em>) what scaling value made the billboard fit exactly inside the screen (it’s <em>3.4</em>). That is far from ideal as I +will need to modularize this behavior inside a function that needs to work for every case, so I will need to figure out a way to fix that +for every screen size. For that, I have two options:</p> +<ol class="arabic simple"> +<li><p>Find the scaling factor function that makes the billboard fit into any screen size.</p></li> +<li><p>Figure out how the scaling works inside the billboard actor to understand if it needs to be refactored.</p></li> +</ol> +<p>The first seems ok to do, but it is kind of a work around as well. The second one is a good general solution, but it is a more delicate one, +as it deals with how the billboard works and already existing applications of it may suffer problems if the scaling is changed. +I will see what is better talking with my mentors.</p> +<p>Another problem I faced (that is already fixed) relied on shaders. I didn’t fully understood how shaders work inside FURY so I was +using my own fragment shader implementation, replacing the already existing one completely. That was working, but I was having an issue +with the texture coordinates of the rendering texture. As I completely replaced the fragment shader, I had to pass custom texture coordinates +to it, resulting in distorted textures that ruined the calculations. Those issues motivated me to learn the shaders API, which allowed me +to use the right texture coordinates and finally render the results you see above.</p> +</section> +<section id="this-week-s-goals"> +<h2>This Week’s Goals</h2> +<p>For this week, I plan to try a different approach Filipi, one of my mentors, told me to do. This approach was supposed to be the original +one, but a communication failure lead to this path I am currently in. This approach renders each KDE calculation into its own billboard, +and those are rendered together with additive blending. After this first pass, this render is captured into a texture and then rendered to +another big billboard.</p> +<p>Also, I plan to refactor my draft PR <a class="reference external" href="https://github.com/fury-gl/fury/pull/804">#804</a> to make it more understandable, as its description still dates back to the time I was using the +flawed Framebuffer implementation, and my fellow GSoC contributors will eventually review it, and to do so, they will need to understand it.</p> +<p>Wish me luck!</p> +</section> +</section> + + + Hello everyone, time for a other weekly blogpost! Today, I will show you my current progress on my project and latest activities. + + 2023-07-10T00:00:00-04:00 + + + https://fury.gl/posts/2023/2023-07-03-week-5-joaodellagli.html + Week 5: All Roads Lead to Rome + 2023-07-03T00:00:00-04:00 + + João Victor Dell Agli Floriano + + <section id="week-5-all-roads-lead-to-rome"> + +<p>Hello everyone, time for another weekly blogpost! Today, we will talk about taking different paths to reach your objective.</p> +<section id="last-week-s-effort"> +<h2>Last Week’s Effort</h2> +<p>After having the FBO properly set up, the plan was to finally <em>render</em> something to it. Well, I wished for a less bumpy road +at my <span class="xref std std-doc">last blogpost</span> but as in this project things apparently tend to go wrong, +of course the same happened with this step.</p> +</section> +<section id="where-the-problem-was"> +<h2>Where the Problem Was</h2> +<p>Days passed without anything being rendered to the FBO. The setup I was working on followed the simplest OpenGL pipeline of rendering to +an FBO:</p> +<ol class="arabic simple"> +<li><p>Setup the FBO</p></li> +<li><p>Attach a texture to it’s color attachment</p></li> +<li><p>Setup the shader to be used in the FBO render and the shader to render the FBO’s Color Attachment</p></li> +<li><p>Render to the FBO</p></li> +<li><p>Use the color attachment as texture attached to a billboard to render what was on the screen</p></li> +</ol> +<p>But it seems like this pipeline doesn’t translate well into VTK. I paired again on wednesday with my mentors, Bruno and Filipi, to try to figure out +where the problem was, but after hours we could not find it. Wednesday passed and then thursday came, and with thursday, a solution: +Bruno didn’t give up on the idea and dug deep on VTK’s documentation until he found a workaround to do what we wanted, that was retrieving a +texture from what was rendered to the screen and pass it as a texture to render to the billboard. To do it, he figured out we needed to use +a different class, <a class="reference external" href="https://vtk.org/doc/nightly/html/classvtkWindowToImageFilter.html">vtkWindowToImageFilter</a>, a class that has the specific +job of doing exactly what I described above. Below, the steps to do it:</p> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">windowToImageFilter</span> <span class="o">=</span> <span class="n">vtk</span><span class="o">.</span><span class="n">vtkWindowToImageFilter</span><span class="p">()</span> +<span class="n">windowToImageFilter</span><span class="o">.</span><span class="n">SetInput</span><span class="p">(</span><span class="n">scene</span><span class="o">.</span><span class="n">GetRenderWindow</span><span class="p">())</span> +<span class="n">windowToImageFilter</span><span class="o">.</span><span class="n">Update</span><span class="p">()</span> + +<span class="n">texture</span> <span class="o">=</span> <span class="n">vtk</span><span class="o">.</span><span class="n">vtkTexture</span><span class="p">()</span> +<span class="n">texture</span><span class="o">.</span><span class="n">SetInputConnection</span><span class="p">(</span><span class="n">windowToImageFilter</span><span class="o">.</span><span class="n">GetOutputPort</span><span class="p">())</span> + +<span class="c1"># Bind the framebuffer texture to the desired actor</span> +<span class="n">actor</span><span class="o">.</span><span class="n">SetTexture</span><span class="p">(</span><span class="n">texture</span><span class="p">)</span> +</pre></div> +</div> +<p>This is enough to bind to the desired actor a texture that corresponds to what was prior rendered to the screen.</p> +</section> +<section id="this-week-s-goals"> +<h2>This Week’s Goals</h2> +<p>Having a solution to that, now its time to finally render some KDE’s! This week’s plans involve implementing the first version of a KDE +calculation. For anyone interested in understanding what a Kernel Density Estimation is, here is a brief summary from this +<a class="reference external" href="https://en.wikipedia.org/wiki/Kernel_density_estimation">Wikipedia page</a>:</p> +<blockquote> +<div><p>In statistics, kernel density estimation (KDE) is the application of kernel smoothing for probability density estimation, i.e., a +non-parametric method to estimate the probability density function of a random variable based on kernels as weights. KDE answers a +fundamental data smoothing problem where inferences about the population are made, based on a finite data sample. In some fields +such as signal processing and econometrics it is also termed the Parzen–Rosenblatt window method, after Emanuel Parzen and Murray +Rosenblatt, who are usually credited with independently creating it in its current form. One of the famous applications of +kernel density estimation is in estimating the class-conditional marginal densities of data when using a naive Bayes classifier, +which can improve its prediction accuracy.</p> +</div></blockquote> +<p>This complicated sentence can be translated into the below image:</p> +<img alt="KDE plot of 100 random points" class="align-center" src="https://raw.githubusercontent.com/JoaoDell/gsoc_assets/main/images/KDE_plot.png" /> +<p>That is what a KDE plot of 100 random points looks like. The greener the area, the greater the density of points. The plan is to implement +something like that with the tools we now have available.</p> +<p>Let’s get to work!</p> +</section> +</section> + + + Hello everyone, time for another weekly blogpost! Today, we will talk about taking different paths to reach your objective. + + 2023-07-03T00:00:00-04:00 + + + https://fury.gl/posts/2023/2023-06-26-week-4-joaodellagli.html + Week 4: Nothing is Ever Lost + 2023-06-26T00:00:00-04:00 + + João Victor Dell Agli Floriano + + <section id="week-4-nothing-is-ever-lost"> + +<p>Welcome again to another weekly blogpost! Today, let’s talk about the importance of guidance throughout a project.</p> +<section id="last-week-s-effort"> +<h2>Last Week’s Effort</h2> +<p>So, last week my project was struggling with some supposedly simple in concept, yet intricate in execution issues. If you recall from +my <span class="xref std std-doc">last blogpost</span>, I could not manage to make the Framebuffer Object setup work, as its method, +<code class="docutils literal notranslate"><span class="pre">SetContext()</span></code>, wasn’t being able to generate the FBO inside OpenGL. Well, after some (more) research about that as I also dived in my +plan B, that involved studying numba as a way to accelerate a data structure I implemented on my PR <a class="reference external" href="https://github.com/fury-gl/fury/pull/783">#783</a>, +me and one of my mentors decided we needed a pair programming session, that finally happened on thursday. After that session, +we could finally understand what was going on.</p> +</section> +<section id="where-the-problem-was"> +<h2>Where the Problem Was</h2> +<p>Apparently, for the FBO generation to work, it is first needed to initialize the context interactor:</p> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">FBO</span> <span class="o">=</span> <span class="n">vtk</span><span class="o">.</span><span class="n">vtkOpenGLFramebufferObject</span><span class="p">()</span> + +<span class="n">manager</span><span class="o">.</span><span class="n">window</span><span class="o">.</span><span class="n">SetOffScreenRendering</span><span class="p">(</span><span class="kc">True</span><span class="p">)</span> <span class="c1"># so the window doesn&#39;t show up, but important for later as well</span> +<span class="n">manager</span><span class="o">.</span><span class="n">initialize</span><span class="p">()</span> <span class="c1"># missing part that made everything work</span> + +<span class="n">FBO</span><span class="o">.</span><span class="n">SetContext</span><span class="p">(</span><span class="n">manager</span><span class="o">.</span><span class="n">window</span><span class="p">)</span> <span class="c1"># Sets the context for the FBO. Finally, it works</span> +<span class="n">FBO</span><span class="o">.</span><span class="n">PopulateFramebuffer</span><span class="p">(</span><span class="n">width</span><span class="p">,</span> <span class="n">height</span><span class="p">,</span> <span class="kc">True</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="n">vtk</span><span class="o">.</span><span class="n">VTK_UNSIGNED_CHAR</span><span class="p">,</span> <span class="kc">False</span><span class="p">,</span> <span class="mi">24</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span> <span class="c1"># And now I could populate the FBO with textures</span> +</pre></div> +</div> +<aside class="system-message"> +<p class="system-message-title">System Message: INFO/1 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-06-26-week-4-joaodellagli.rst</span>, line 37)</p> +<p>Possible title underline, too short for the title. +Treating it as ordinary text because it’s so short.</p> +</aside> +<p>This simple missing line of code was responsible for ending weeks of suffer, as after that, I called:</p> +<aside class="system-message"> +<p class="system-message-title">System Message: ERROR/3 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-06-26-week-4-joaodellagli.rst</span>, line 38)</p> +<p>Unexpected indentation.</p> +</aside> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="nb">print</span><span class="p">(</span><span class="s2">&quot;FBO of index:&quot;</span><span class="p">,</span> <span class="n">FBO</span><span class="o">.</span><span class="n">GetFBOIndex</span><span class="p">())</span> +<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;Number of color attachments:&quot;</span><span class="p">,</span> <span class="n">FBO</span><span class="o">.</span><span class="n">GetNumberOfColorAttachments</span><span class="p">())</span> +</pre></div> +</div> +<aside class="system-message"> +<p class="system-message-title">System Message: INFO/1 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-06-26-week-4-joaodellagli.rst</span>, line 42)</p> +<p>Possible title underline, too short for the title. +Treating it as ordinary text because it’s so short.</p> +</aside> +<p>That outputted:</p> +<aside class="system-message"> +<p class="system-message-title">System Message: ERROR/3 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-06-26-week-4-joaodellagli.rst</span>, line 43)</p> +<p>Unexpected indentation.</p> +</aside> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">FBO</span> <span class="n">of</span> <span class="n">index</span><span class="p">:</span> <span class="mi">4</span> +<span class="n">Number</span> <span class="n">of</span> <span class="n">color</span> <span class="n">attachments</span><span class="p">:</span> <span class="mi">1</span> +</pre></div> +</div> +<p>That means the FBO generation was successful! One explanation that seems reasonable to me on why was that happening is that, as it was +not initialized, the context was being passed <code class="docutils literal notranslate"><span class="pre">null</span></code> to the <code class="docutils literal notranslate"><span class="pre">SetContext()</span></code> method, that returned without any warning of what was happening.</p> +<p>Here, I would like to point out how my mentor was <strong>essential</strong> to this solution to come: I had struggled for some time with that, and could +not find a way out, but a single session of synchronous pair programming where I could expose clearly my problem and talk to someone +way more experienced than I, someone designated for that, was my way out of this torment, so value your mentors! Thanks Bruno!</p> +</section> +<section id="this-week-s-goals"> +<h2>This Week’s Goals</h2> +<p>Now, with the FBO working, I plan to finally <em>render</em> something to it. For this week, I plan to come back to my original plan and +experiment with simple shaders just as a proof of concept that the FBO will be really useful for this project. I hope the road is less +bumpier by now and I don’t step on any other complicated problem.</p> +<p>Wish me luck!</p> +</section> +</section> + + + Welcome again to another weekly blogpost! Today, let’s talk about the importance of guidance throughout a project. + + 2023-06-26T00:00:00-04:00 + + diff --git a/v0.10.x/blog/author/lenix-lobo.html b/v0.10.x/blog/author/lenix-lobo.html new file mode 100644 index 000000000..51641e50e --- /dev/null +++ b/v0.10.x/blog/author/lenix-lobo.html @@ -0,0 +1,1463 @@ + + + + + + + Posts by Lenix Lobo — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +
+

+ + Posts by + + Lenix Lobo + +

+ + +
+

+ Shader Showcase +

+
    +
  • + + + 24 August 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Lenix Lobo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Make sure to check out Project FURY

+

+ +

Read more ...

+
+
+ +
+

+ Google Summer of Code 2020 Final Work Product +

+
    +
  • + + + 24 August 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Lenix Lobo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Name: Lenix Lobo

+

+ +

Read more ...

+
+
+ +
+

+ Outline Picker +

+
    +
  • + + + 17 August 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Lenix Lobo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Make sure to check out Project FURY

+

+ +

Read more ...

+
+
+ +
+

+ More Shaders!! +

+
    +
  • + + + 09 August 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Lenix Lobo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Make sure to check out Project FURY

+

+ +

Read more ...

+
+
+ +
+

+ More Shaders!! +

+
    +
  • + + + 02 August 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Lenix Lobo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Make sure to check out Project FURY

+

+ +

Read more ...

+
+
+ +
+

+ Merging SDF primitives. +

+
    +
  • + + + 27 July 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Lenix Lobo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Make sure to check out Project FURY

+

+ +

Read more ...

+
+
+ +
+

+ Improvements in SDF primitives. +

+
    +
  • + + + 20 July 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Lenix Lobo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Make sure to check out Project FURY

+

+ +

Read more ...

+
+
+ +
+

+ Multiple SDF primitives. +

+
    +
  • + + + 13 July 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Lenix Lobo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Make sure to check out Project FURY

+

+ +

Read more ...

+
+
+ +
+

+ Spherical harmonics, Continued. +

+
    +
  • + + + 05 July 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Lenix Lobo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Make sure to check out Project FURY

+

+ +

Read more ...

+
+
+ +
+

+ Spherical harmonics +

+
    +
  • + + + 28 June 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Lenix Lobo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Make sure to check out Project FURY

+

+ +

Read more ...

+
+
+ +
+

+ Raymarching continued +

+
    +
  • + + + 21 June 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Lenix Lobo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Make sure to check out Project FURY

+

+ +

Read more ...

+
+
+ +
+

+ Raymarching!! +

+
    +
  • + + + 14 June 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Lenix Lobo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Make sure to check out Project FURY

+

+ +

Read more ...

+
+
+ +
+

+ First week of coding!! +

+
    +
  • + + + 07 June 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Lenix Lobo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hey everyone! +This week : Geometry Shaders!

+

+ +

Read more ...

+
+
+ +
+

+ Weekly Check-in #1 +

+
    +
  • + + + 30 May 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Lenix Lobo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hey everyone! +This is my blog for this summer’s GSoC @ PSF +I am Lenix Lobo, an undergraduate student from India, and this summer I will be working with project Fury under the umbrella of the Python Software foundation. I will be working on improving the current shader framework.

+

+ +

Read more ...

+
+
+ + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/blog/author/lenix-lobo/atom.xml b/v0.10.x/blog/author/lenix-lobo/atom.xml new file mode 100644 index 000000000..3845dc50a --- /dev/null +++ b/v0.10.x/blog/author/lenix-lobo/atom.xml @@ -0,0 +1,485 @@ + + + https://fury.gl/ + Blog - Posts by Lenix Lobo + 2024-02-29T15:43:57.448784+00:00 + + + ABlog + + https://fury.gl/posts/2020/2020-08-24-week-13-lenix.html + Shader Showcase + 2020-08-24T00:00:00-04:00 + + Lenix Lobo + + <section id="shader-showcase"> + +<p>Make sure to check out Project <a class="reference external" href="https://github.com/fury-gl/fury">FURY</a></p> +<p>Hey Everyone! +Today marked the official end of the coding period for Google Summer of Code 2020. On this day I would like to take the opportunity to thank all my mentors and Soham who have shown immense support during this time and helped me grow not only to be a better programmer but also to be a better team member. While the GSoC period ends, I will try my best to be active and contribute to the project and help it grow. +Cheers!</p> +<section id="what-did-you-do-this-week"> +<h2>What did you do this week?</h2> +<p>This being the final week of GSoC , my task was to create a PR which showcases not only the shader capabilities of the project but also to create a example which integrates both the UI and shader system of project FURY. This example can help new users to get familiar with both the UI and shaders. +Apart from this i also worked on a Toon Shader.</p> +<p>The output for the above task is given below :</p> +<img alt="https://raw.githubusercontent.com/lenixlobo/fury-outputs/master/blog-week-13.gif" src="https://raw.githubusercontent.com/lenixlobo/fury-outputs/master/blog-week-13.gif" /> +<p>The shader demos are available <a class="reference external" href="https://github.com/lenixlobo/fury/tree/shader-demos">here</a></p> +</section> +<section id="what-is-coming-up-next-week"> +<h2>What is coming up next week?</h2> +<p>The next week I will work on the final GSoC documentation which explains what I worked on throughout the GSoC period. In case of any changes are requested by the mentors I will also try to implement them.</p> +</section> +<section id="did-you-get-stuck-anywhere"> +<h2>Did you get stuck anywhere?</h2> +<p>With the help of Soham and the mentors this week went smoothly.</p> +</section> +</section> + + + Make sure to check out Project FURY + + 2020-08-24T00:00:00-04:00 + + + https://fury.gl/posts/2020/2020-08-24-final-work-lenix.html + Google Summer of Code 2020 Final Work Product + 2020-08-24T00:00:00-04:00 + + Lenix Lobo + + <img alt="https://developers.google.com/open-source/gsoc/resources/downloads/GSoC-logo-horizontal.svg" class="align-center" height="50" src="https://developers.google.com/open-source/gsoc/resources/downloads/GSoC-logo-horizontal.svg" /><img alt="https://www.python.org/static/community_logos/python-logo.png" src="https://www.python.org/static/community_logos/python-logo.png" style="width: 40%;" /> +<img alt="https://python-gsoc.org/logos/FURY.png" src="https://python-gsoc.org/logos/FURY.png" style="height: 30px;" /> +<section id="google-summer-of-code-2020-final-work-product"> + +<ul class="simple"> +<li><p><strong>Name:</strong> Lenix Lobo</p></li> +<li><p><strong>Organisation:</strong> Python Software Foundation</p></li> +<li><p><strong>Sub-Organisation:</strong> FURY</p></li> +<li><p><strong>Project:</strong> <a class="reference external" href="https://github.com/fury-gl/fury/wiki/Google-Summer-of-Code-2020">FURY - Improve Shader Framework</a></p></li> +</ul> +<section id="introduction"> +<h2>Introduction</h2> +<p>The current shader framework for FURY is based on VTK and lacks documentation to get started which can be overwhelming for new users. The objective of this project is to enable users to be easily able to understand and use the shader framework to render stunning visual representations of data. The project involves programming vertex and fragment shaders to generate effects for more immersive visualization.</p> +</section> +<section id="proposed-objectives"> +<h2>Proposed Objectives</h2> +<p><strong>Adding SDF actor to the API</strong></p> +<p>This actor uses raymarching to model actors using SDF. The method provides several actors including <cite>ellipsoid</cite>, <cite>sphere</cite> and <cite>torus</cite>. +<strong>Shader demos</strong></p> +<blockquote> +<div><p>Use the FURY shader system to create and visualize different shading algorithms. Implementations include <cite>SphereMap</cite>, <cite>Toon</cite>, <cite>Gooch</cite> and <cite>Vertex Noise</cite></p> +</div></blockquote> +</section> +<section id="unsubmitted-functionalities"> +<h2>Unsubmitted Functionalities</h2> +<p><strong>Spherical Harmonics using Shaders.</strong></p> +<p>The spherical harmonics algorithm is used to generate spherical surfaces using biases and coefficients computed. The general approach to achieve this is computationally expensive. The idea proposed was to leverage the GPU hardware using shaders to provide a faster more efficient alternative to the current implementations. The second month of the coding period was devoted to the same task but unfortunately, the observed performance was quite unsatisfactory than the expected performance. Moreover, the output shape of the geometry was distorted. It was then decided to continue the work after the GSoC period and prioritize the task at hand.</p> +<p>The Work in Progress can be accessed here. <a class="github reference external" href="https://github.com/lenixlobo/fury/tree/Spherical-Harmonics">lenixlobo/fury</a></p> +<p><strong>Dynamic Texture using Geometry Shader</strong></p> +<p>Geometry Shaders provide a lot of flexibility to users to create custom geometry behaviors such as instancing. The idea was to create a dynamic Fur/Hair effect on top of a FURY actor. Unfortunately due to missing documentation on VTK geometry shaders and lack of resources, the project was not completed during the GSoC period. However, I will continue to try to solve the issue.</p> +<p>The source code for the current progress can be accessed here. <a class="github reference external" href="https://github.com/lenixlobo/fury/tree/Dynamic-Texture">lenixlobo/fury</a></p> +</section> +<section id="objectives-completed"> +<h2>Objectives Completed</h2> +<p><strong>SDF based Actor</strong></p> +<blockquote> +<div><p>The objective here was to provide an alternative approach to users to use SDF modeled actors in the scene. This actor is modeled using the raymarching algorithm which provides much better performance than conventional polygon-based actors. Currently, the shapes supported include ellipsoid, sphere and torus</p> +<p><em>Pull Requests:</em> +<strong>SDF Actor method:</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/250">fury-gl/fury#250</a></p> +</div></blockquote> +<p><strong>Multiple SDF Actor</strong></p> +<blockquote> +<div><p>The objective was to create a method through which multiple SDF primitives are rendered within a single cube. This task helped us explore the limitations of the shader system and also benchmarking the performance.</p> +<p><em>Pull Requests:</em> +<strong>MultiSDF Shader:</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/blob/master/docs/experimental/viz_multisdf.py">fury-gl/fury</a></p> +</div></blockquote> +<p><strong>Shader Demos</strong></p> +<blockquote> +<div><p>The task here was to create a pull request showcasing the capabilities of the FURY shader system and to also provide examples or new users to get started with integrating custom shaders into the scenes.</p> +<p><em>Pull Requests:</em> +<strong>Shader Demos:</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/296">fury-gl/fury#296</a></p> +</div></blockquote> +</section> +<section id="other-objectives"> +<h2>Other Objectives</h2> +<ul> +<li><p><strong>Tutorials</strong></p> +<blockquote> +<div><p>Create Tutorials for new users to get familiar with the Shader System</p> +<p><em>Pull Requests:</em> +- <strong>Shader UI Tutorial</strong></p> +<p><a class="github reference external" href="https://github.com/fury-gl/fury/pull/296">fury-gl/fury#296</a></p> +<p>-<strong>SDF Actor Tutorial</strong></p> +<p><a class="github reference external" href="https://github.com/fury-gl/fury/pull/267">fury-gl/fury#267</a></p> +</div></blockquote> +</li> +<li><p><strong>GSoC weekly Blogs</strong></p> +<p>Weekly blogs were added for FURY’s Website.</p> +<p><em>Pull Requests:</em> +- <strong>First &amp; Second Evaluation:</strong></p> +<p><a class="github reference external" href="https://github.com/fury-gl/fury/pull/250">fury-gl/fury#250</a> +<a class="github reference external" href="https://github.com/fury-gl/fury/pull/267">fury-gl/fury#267</a></p> +<ul class="simple"> +<li><p><strong>Third Evaluation:</strong></p></li> +</ul> +<p><a class="github reference external" href="https://github.com/fury-gl/fury/pull/296">fury-gl/fury#296</a></p> +</li> +</ul> +</section> +<section id="timeline"> +<h2>Timeline</h2> +<table class="table"> +<thead> +<tr class="row-odd"><th class="head"><p>Date</p></th> +<th class="head"><p>Description</p></th> +<th class="head"><p>Blog Link</p></th> +</tr> +</thead> +<tbody> +<tr class="row-even"><td><p>Week 1(30-05-2020)</p></td> +<td><p>Welcome to my GSoC Blog!</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/lenixlobos-blog/gsoc-blog-week-1/">Weekly Check-in #1</a></p></td> +</tr> +<tr class="row-odd"><td><p>Week 2(07-06-2020)</p></td> +<td><p>Geometry Shaders!</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/lenixlobos-blog/weekly-check-in-week-2/">Weekly Check-in #2</a></p></td> +</tr> +<tr class="row-even"><td><p>Week 3(14-06-2020)</p></td> +<td><p>Ray Marching!</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/lenixlobos-blog/weekly-check-in-week-3/">Weekly Check-in #3</a></p></td> +</tr> +<tr class="row-odd"><td><p>Week 4(21-06-2020)</p></td> +<td><p>RayMarching Continued</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/lenixlobos-blog/weekly-check-in-week-4/">Weekly Check-in #4</a></p></td> +</tr> +<tr class="row-even"><td><p>Week 5(28-06-2020)</p></td> +<td><p>Spherical Harmonics</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/lenixlobos-blog/weekly-check-in-week-5/">Weekly Check-in #5</a></p></td> +</tr> +<tr class="row-odd"><td><p>Week 6(05-07-2020)</p></td> +<td><p>Spherical Harmonics Continued</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/lenixlobos-blog/weekly-check-in-week-6/">Weekly Check-in #6</a></p></td> +</tr> +<tr class="row-even"><td><p>Week 7(12-07-2020)</p></td> +<td><p>Multiple SDF Primitives</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/lenixlobos-blog/weekly-check-in-week-7/">Weekly Check-in #7</a></p></td> +</tr> +<tr class="row-odd"><td><p>Week 8(19-07-2020)</p></td> +<td><p>Improvements in SDF primitives</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/lenixlobos-blog/weekly-check-in-week-8/">Weekly Check-in #8</a></p></td> +</tr> +<tr class="row-even"><td><p>Week 9(26-07-2020)</p></td> +<td><p>Merging SDF Actor and Benchmarks!</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/lenixlobos-blog/weekly-check-in-week-9/">Weekly Check-in #9</a></p></td> +</tr> +<tr class="row-odd"><td><p>Week 10(02-08-2020)</p></td> +<td><p>More Shaders</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/lenixlobos-blog/weekly-check-in-week-10/">Weekly Check-in #10</a></p></td> +</tr> +<tr class="row-even"><td><p>Week 11(08-08-2020)</p></td> +<td><p>Even More Shaders</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/lenixlobos-blog/weekly-check-in-week-11/">Weekly Check-in #11</a></p></td> +</tr> +<tr class="row-odd"><td><p>Week 12(16-08-2020)</p></td> +<td><p>Picking Outline</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/lenixlobos-blog/weekly-check-in-week-12/">Weekly Check-in #12</a></p></td> +</tr> +<tr class="row-even"><td><p>Week 13(23-08-2020)</p></td> +<td><p>Final Week</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/lenixlobos-blog/weekly-check-in-week-13/">Weekly Check-in #13</a></p></td> +</tr> +</tbody> +</table> +<p>Detailed weekly tasks and work done can be found +<a class="reference external" href="https://blogs.python-gsoc.org/en/lenixlobos-blog/">here</a>.</p> +</section> +</section> + + + Name: Lenix Lobo + + 2020-08-24T00:00:00-04:00 + + + https://fury.gl/posts/2020/2020-08-17-week-12-lenix.html + Outline Picker + 2020-08-17T00:00:00-04:00 + + Lenix Lobo + + <section id="outline-picker"> + +<p>Make sure to check out Project <a class="reference external" href="https://github.com/fury-gl/fury">FURY</a></p> +<p>Hey ! +This week, Picking Outline!</p> +<section id="what-did-you-do-this-week"> +<h2>What did you do this week?</h2> +<p>We needed a Outline feature in FURY to indicate which model we choose in the scene. So the task assigned was to find options to achieve this. There were two ways to do this, 1. Using shader and 2. Using Vtk PolyData Silhouette. Despite trying multiple implementation methods the shader approach was not working . I also tried using VTKs inbuilt function , but there is a bug when i use some models. When i choose a model, it renders outline for every polygon , which is not what we want to achieve. The bug is shown below:</p> +<p>Below are the outputs of the techniques i worked on :</p> +<img alt="https://raw.githubusercontent.com/lenixlobo/fury-outputs/master/blog-week-12.gif" src="https://raw.githubusercontent.com/lenixlobo/fury-outputs/master/blog-week-12.gif" /> +<p>The shader demos are available <a class="reference external" href="https://github.com/lenixlobo/fury/tree/shader-demos">here</a></p> +</section> +<section id="what-is-coming-up-next-week"> +<h2>What is coming up next week?</h2> +<p>With the end of GSoC approaching soon, the next task is to create a PR which can help new users to test different shaders using UI to get started.</p> +</section> +<section id="did-you-get-stuck-anywhere"> +<h2>Did you get stuck anywhere?</h2> +<p>I still was not able to figure out how we can achieve the outline effect. Am currently looking into other approaches we could use</p> +</section> +</section> + + + Make sure to check out Project FURY + + 2020-08-17T00:00:00-04:00 + + + https://fury.gl/posts/2020/2020-08-09-week-11-lenix.html + More Shaders!! + 2020-08-09T00:00:00-04:00 + + Lenix Lobo + + <section id="more-shaders"> + +<p>Make sure to check out Project <a class="reference external" href="https://github.com/fury-gl/fury">FURY</a></p> +<p>Hey ! +This week, More Shaders!</p> +<section id="what-did-you-do-this-week"> +<h2>What did you do this week?</h2> +<p>The task assigned for this week was to explore more shader techniques which could be implemented using FURY and which would demonstrate the capability of FURY shader system. So i decided to work on implementing shading examples such as Gooch shading and reflection shader using textures.</p> +<p>Below are the outputs of the techniques i worked on :</p> +<img alt="https://raw.githubusercontent.com/lenixlobo/fury-outputs/master/blog-week-11a.gif" src="https://raw.githubusercontent.com/lenixlobo/fury-outputs/master/blog-week-11a.gif" /> +<img alt="https://raw.githubusercontent.com/lenixlobo/fury-outputs/master/blog-week-11b.gif" src="https://raw.githubusercontent.com/lenixlobo/fury-outputs/master/blog-week-11b.gif" /> +<img alt="https://raw.githubusercontent.com/lenixlobo/fury-outputs/master/blog-week-11c.gif" src="https://raw.githubusercontent.com/lenixlobo/fury-outputs/master/blog-week-11c.gif" /> +<p>The shader demos are available <a class="reference external" href="https://github.com/lenixlobo/fury/tree/shader-demos">here</a></p> +</section> +<section id="what-is-coming-up-next-week"> +<h2>What is coming up next week?</h2> +<p>The next week will involve working on more such demos which can demonstrate the capabilities of FURY</p> +</section> +<section id="did-you-get-stuck-anywhere"> +<h2>Did you get stuck anywhere?</h2> +<p>No issues were faced this week</p> +</section> +</section> + + + Make sure to check out Project FURY + + 2020-08-09T00:00:00-04:00 + + + https://fury.gl/posts/2020/2020-08-02-week-10-lenix.html + More Shaders!! + 2020-08-02T00:00:00-04:00 + + Lenix Lobo + + <section id="more-shaders"> + +<p>Make sure to check out Project <a class="reference external" href="https://github.com/fury-gl/fury">FURY</a></p> +<p>Hey ! +This week, More Shaders!</p> +<section id="what-did-you-do-this-week"> +<h2>What did you do this week?</h2> +<p>After merging the SDF actor last week , the mentors and I decided to work on another project idea which was discussed prior to GSoC . So the next step assigned to me was to look into the current shader framework and create immersive visualizations using shaders. Being interested in volumetric rendering I looked into volumetric cloud rendering algorithms and created a basic shader-based render in FURY.</p> +<p>The output for the same is given below:</p> +<img alt="https://raw.githubusercontent.com/lenixlobo/fury-outputs/master/blog-week-10a.gif" src="https://raw.githubusercontent.com/lenixlobo/fury-outputs/master/blog-week-10a.gif" /> +<img alt="https://raw.githubusercontent.com/lenixlobo/fury-outputs/master/blog-week-10b.gif" src="https://raw.githubusercontent.com/lenixlobo/fury-outputs/master/blog-week-10b.gif" /> +<p>The shader demos are available <a class="reference external" href="https://github.com/lenixlobo/fury/tree/shader-demos">here</a></p> +</section> +<section id="what-is-coming-up-next-week"> +<h2>What is coming up next week?</h2> +<p>The main focus now is to discuss and work on shader demos which an demonstrate the capabilities of FURY</p> +</section> +<section id="did-you-get-stuck-anywhere"> +<h2>Did you get stuck anywhere?</h2> +<p>No issues were faced this week</p> +</section> +</section> + + + Make sure to check out Project FURY + + 2020-08-02T00:00:00-04:00 + + + https://fury.gl/posts/2020/2020-07-27-week-9-lenix.html + Merging SDF primitives. + 2020-07-27T00:00:00-04:00 + + Lenix Lobo + + <section id="merging-sdf-primitives"> + +<p>Make sure to check out Project <a class="reference external" href="https://github.com/fury-gl/fury">FURY</a></p> +<p>Hey Everyone! +This week, Merging SDF primitives.</p> +<section id="what-did-you-do-this-week"> +<h2>What did you do this week?</h2> +<p>Since GSoC started I have been working on adding support for raymarching based SDF actors as primitives in the FURY codebase. This week with the release of FURY 0.6.0 , the task assigned to me was to complete the remaining parts of the SDF actor including tests and tutorial. THe SDF actor is now part of the FURY actor and can be accessed using sdf_actor. +Currently we support , ellipsoids, spheres and torus as primitive options. As expected, SDF based actors have shown tremendous performance improvements over traditional polygon based actor.</p> +<p>Despite using 100,000 torus the FPS is higher than 60 :</p> +<img alt="https://raw.githubusercontent.com/lenixlobo/fury-outputs/master/blog-week-9.gif" src="https://raw.githubusercontent.com/lenixlobo/fury-outputs/master/blog-week-9.gif" /> +<p>10,000 actors :</p> +<img alt="https://raw.githubusercontent.com/lenixlobo/fury-outputs/master/blog-week-9b.gif" src="https://raw.githubusercontent.com/lenixlobo/fury-outputs/master/blog-week-9b.gif" /> +<p>I also made a tutorial for new users to get started <a class="reference external" href="https://fury.gl/latest/auto_tutorials/04_shaders/viz_sdfactor.html#sphx-glr-auto-tutorials-04-shaders-viz-sdfactor-py">here</a></p> +</section> +<section id="what-is-coming-up-next-week"> +<h2>What is coming up next week?</h2> +<p>Now that the SDF actor is merged , the next step is to focus on spherical harmonics and i will also be working on creating shader visualization to showcase the features of FURY</p> +</section> +<section id="did-you-get-stuck-anywhere"> +<h2>Did you get stuck anywhere?</h2> +<p>This week involved a lot of work , including making tests, tutorial and looking for bugs but everything went smoothly .</p> +</section> +</section> + + + Make sure to check out Project FURY + + 2020-07-27T00:00:00-04:00 + + + https://fury.gl/posts/2020/2020-07-20-week-8-lenix.html + Improvements in SDF primitives. + 2020-07-20T00:00:00-04:00 + + Lenix Lobo + + <section id="improvements-in-sdf-primitives"> + +<p>Make sure to check out Project <a class="reference external" href="https://github.com/fury-gl/fury">FURY</a></p> +<p>Hey Everyone! +This week, Improvements in SDF primitives.</p> +<section id="what-did-you-do-this-week"> +<h2>What did you do this week?</h2> +<p>Over the past few weeks i have been working on adding SDF based actors in FURY. The task for this week was to complete the remaining features such as support for scaling and rotation based on user direction for the actors. The main objective is to complete the SDF actor and make it ready to merge into the FURY codebase. Below are the outputs after added the improvements to the SDF primitives.</p> +<p>Scaling:</p> +<img alt="https://raw.githubusercontent.com/lenixlobo/fury-outputs/master/blog-week-8b.gif" src="https://raw.githubusercontent.com/lenixlobo/fury-outputs/master/blog-week-8b.gif" /> +<p>Rotation based on passed directions:</p> +<img alt="https://raw.githubusercontent.com/lenixlobo/fury-outputs/master/blog-week-8a.gif" src="https://raw.githubusercontent.com/lenixlobo/fury-outputs/master/blog-week-8a.gif" /> +<p>The code for the above render is available at the <a class="reference external" href="https://github.com/lenixlobo/fury/tree/SDF-Experiments">branch</a></p> +</section> +<section id="what-is-coming-up-next-week"> +<h2>What is coming up next week?</h2> +<p>Since the features are almost done the task for next week is clean the code and test for bugs. And then to eventually merge the sdf_actor into the fury codebase.</p> +</section> +<section id="did-you-get-stuck-anywhere"> +<h2>Did you get stuck anywhere?</h2> +<p>No major issues this week.</p> +</section> +</section> + + + Make sure to check out Project FURY + + 2020-07-20T00:00:00-04:00 + + + https://fury.gl/posts/2020/2020-07-13-week-7-lenix.html + Multiple SDF primitives. + 2020-07-13T00:00:00-04:00 + + Lenix Lobo + + <section id="multiple-sdf-primitives"> + +<p>Make sure to check out Project <a class="reference external" href="https://github.com/fury-gl/fury">FURY</a></p> +<p>Hey Everyone! +This week, multiple SDF primitives.</p> +<section id="what-did-you-do-this-week"> +<h2>What did you do this week?</h2> +<p>The objective of this week was to understand the capabilities of the multiple SDF primitives within the same cube project. To get a clearer understanding of what we can achieve with this approach, i added support for real time rotating primitives. The output of 2 cubes with rotating SDFs is shown below.</p> +<img alt="https://raw.githubusercontent.com/lenixlobo/fury-outputs/master/blog-week-7.gif" src="https://raw.githubusercontent.com/lenixlobo/fury-outputs/master/blog-week-7.gif" /> +<p>The code for the above render is available at the <a class="reference external" href="https://github.com/lenixlobo/fury/tree/SDF-Experiments">branch</a></p> +</section> +<section id="what-is-coming-up-next-week"> +<h2>What is coming up next week?</h2> +<p>The task for next week is to implement features in the SDF actor and also to fix minor bugs within the shaders. Once everything is done as planned, the PR will be merged for users to access the features.</p> +</section> +<section id="did-you-get-stuck-anywhere"> +<h2>Did you get stuck anywhere?</h2> +<p>No issues this week</p> +</section> +</section> + + + Make sure to check out Project FURY + + 2020-07-13T00:00:00-04:00 + + + https://fury.gl/posts/2020/2020-07-05-week-6-lenix.html + Spherical harmonics, Continued. + 2020-07-05T00:00:00-04:00 + + Lenix Lobo + + <section id="spherical-harmonics-continued"> + +<p>Make sure to check out Project <a class="reference external" href="https://github.com/fury-gl/fury">FURY</a></p> +<p>Hey ! +Spherical harmonics, Continued!</p> +<section id="what-did-you-do-this-week"> +<h2>What did you do this week?</h2> +<p>Last week I added a basic implementation of Spherical harmonics based actors. However, the implementation was quite restricted and we needed to add support for more accurate generation of spherical harmonics. So the task assigned this week was to implement the spherical harmonics function within the shader rather than passing variables as uniforms. This was quite an challenging task as it involved understanding of mathematical formulae and implementing them using existing GLSL functions. +The output of the implementation is shown below :</p> +<img alt="https://raw.githubusercontent.com/lenixlobo/fury-outputs/master/blog-week-6.gif" src="https://raw.githubusercontent.com/lenixlobo/fury-outputs/master/blog-week-6.gif" /> +<p>While , i was able to complete the task the frame rate for the generated output was quite lower than expected. +The code for the above render is available at the <a class="reference external" href="https://github.com/lenixlobo/fury/tree/Spherical-Harmonics">branch</a></p> +</section> +<section id="what-is-coming-up-next-week"> +<h2>What is coming up next week?</h2> +<p>The next task is to discuss possible performance improvements with the mentors and also look into alternative ideas to add spherical harmonics as actors in FURY.</p> +</section> +<section id="did-you-get-stuck-anywhere"> +<h2>Did you get stuck anywhere?</h2> +<p>Spherical harmonics involve a lot of complicated math behind the hood as a result the generated output has a very poor frame rate. Currently, we are looking into improving this.</p> +</section> +</section> + + + Make sure to check out Project FURY + + 2020-07-05T00:00:00-04:00 + + + https://fury.gl/posts/2020/2020-06-28-week-5-lenix.html + Spherical harmonics + 2020-06-28T00:00:00-04:00 + + Lenix Lobo + + <section id="spherical-harmonics"> + +<p>Make sure to check out Project <a class="reference external" href="https://github.com/fury-gl/fury">FURY</a></p> +<p>Hey ! +This week, Spherical harmonics!</p> +<section id="what-did-you-do-this-week"> +<h2>What did you do this week?</h2> +<p>The main task for the week was to include an implementation of spherical harmonics (upto the order of 4) as a FURY actor. This was the initial milestone to be achieved to work towards the support of using spherical harmonics as an visualization technique. I have added the GIFs for both the renders below. I also worked on a occlusion based lighting model.</p> +<p>Spherical harmonics for different values of order and degree:</p> +<img alt="https://raw.githubusercontent.com/lenixlobo/fury-outputs/master/blog-week-5a.gif" src="https://raw.githubusercontent.com/lenixlobo/fury-outputs/master/blog-week-5a.gif" /> +<img alt="https://raw.githubusercontent.com/lenixlobo/fury-outputs/master/blog-week-5b.gif" src="https://raw.githubusercontent.com/lenixlobo/fury-outputs/master/blog-week-5b.gif" /> +</section> +<section id="what-is-coming-up-next-week"> +<h2>What is coming up next week?</h2> +<p>The next task to add support for the user to be able to render different spherical harmonics by passing arguments</p> +</section> +<section id="did-you-get-stuck-anywhere"> +<h2>Did you get stuck anywhere?</h2> +<p>Spherical harmonics involve a lot of complicated math behind the hood. So the initial days were spent understanding the math .I was confused while working on the implementation but eventually got it working.</p> +</section> +</section> + + + Make sure to check out Project FURY + + 2020-06-28T00:00:00-04:00 + + diff --git a/v0.10.x/blog/author/mohamed-abouagour.html b/v0.10.x/blog/author/mohamed-abouagour.html new file mode 100644 index 000000000..56a398780 --- /dev/null +++ b/v0.10.x/blog/author/mohamed-abouagour.html @@ -0,0 +1,1604 @@ + + + + + + + Posts by Mohamed Abouagour — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +
+

+ + Posts by + + Mohamed Abouagour + +

+ + +
+

+ Google Summer of Code Final Work Product +

+
    +
  • + + + 29 January 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Mohamed Abouagour + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Name: Mohamed Abouagour

+

+ +

Read more ...

+
+
+ +
+

+ Week 14: Keyframes animation is now a bit easier in FURY +

+
    +
  • + + + 28 September 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Mohamed Abouagour + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Separated the Timeline into a Timeline and an Animation. So, instead of having the Timeline do everything. It’s now more like doing animations in Blender and other 3D editing software where the timeline handles the playback of several animations #694.

+

+ +

Read more ...

+
+
+ +
+

+ Week 13: Keyframes animation is now a bit easier in FURY +

+
    +
  • + + + 20 September 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Mohamed Abouagour + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Added the ability to have the ShowManager stored inside the Timeline. That way the user does not have to update and render the animations because it will be done internally.

+

+ +

Read more ...

+
+
+ +
+

+ Week 12: Adding new tutorials +

+
    +
  • + + + 07 September 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Mohamed Abouagour + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Restructured tutorials to be more readable and more focused on a specific topic.

+

+ +

Read more ...

+
+
+ +
+

+ Week 11: Improving tutorials a little +

+
    +
  • + + + 30 August 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Mohamed Abouagour + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Fixed some issues in the hierarchical order animation support PR that we discussed during last week’s meeting (mostly naming issues).

+

+ +

Read more ...

+
+
+ +
+

+ Week 10: Supporting hierarchical animating +

+
    +
  • + + + 23 August 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Mohamed Abouagour + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Implemented hierarchical order support for animations using matrices in this PR.

+

+ +

Read more ...

+
+
+ +
+

+ Week 9: Animating primitives of the same actor +

+
    +
  • + + + 16 August 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Mohamed Abouagour + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Made two tutorials in this PR that show two approaches on how to animate primitives of the same FURY actor using the Timeline.

+

+ +

Read more ...

+
+
+ +
+

+ Week 8: Back to the shader-based version of the Timeline +

+
    +
  • + + + 09 August 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Mohamed Abouagour + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

First, I made some modifications to the main animation PR. Then as Filipi requested, I integrated the vertex shader that I was implementing a few weeks ago to work with the new improved version of the Timeline.

+

+ +

Read more ...

+
+
+ +
+

+ Week 7: Billboard spheres and implementing interpolators using closures +

+
    +
  • + + + 01 August 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Mohamed Abouagour + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Restructured the keyframe animation interpolators using closures to be functions instead of classes #647. Now it is easier to implement new interpolators with the help of the functions existing in fury/animation/helpers.py. Also, now unit tests can be added for the latter functions.

+

+ +

Read more ...

+
+
+ +
+

+ Week 6: Fixing the Timeline issues and equipping it with more features +

+
    +
  • + + + 25 July 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Mohamed Abouagour + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Improved the PlaybackPanel by adding speed control and the ability to loop the animation. Also, fixed the lagging issue of play and pause buttons and composed them into a single play/pause button.

+

+ +

Read more ...

+
+
+ +
+

+ Week 5: Slerp implementation, documenting the Timeline, and adding unit tests +

+
    +
  • + + + 19 July 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Mohamed Abouagour + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Implemented Slerp (spherical linear interpolation) for rotation keyframes.

+

+ +

Read more ...

+
+
+ +
+

+ Week 4: Camera animation, interpolation in GLSL, and a single Timeline! +

+
    +
  • + + + 11 July 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Mohamed Abouagour + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Managed to implement a single Timeline using the Container class. So, instead of having two classes: Timeline and CompositeTimeline, now the Timeline can have multiple Timeline objects and controls them as in the code below.

+

+ +

Read more ...

+
+
+ +
+

+ Week 3: Redesigning the API, Implementing cubic Bezier Interpolator, and making progress on the GPU side! +

+
    +
  • + + + 04 July 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Mohamed Abouagour + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Redesigned the keyframe animations API to optimize having a lot of timelines by composing them into a parent Timeline called CompositeTimeline while maintaining playing individual timelines separately.

+

+ +

Read more ...

+
+
+ +
+

+ Week 2: Implementing non-linear and color interpolators +

+
    +
  • + + + 28 June 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Mohamed Abouagour + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Implemented some other general interpolators such as n-th degree spline and cubic spline interpolators. Also implemented HSV and LAB color interpolators.

+

+ +

Read more ...

+
+
+ +
+

+ Week 1: Implementing a basic Keyframe animation API +

+
    +
  • + + + 19 June 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Mohamed Abouagour + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

During the community bonding period, we had weekly meetings in which I got to know the mentors better and bonded with Shivam and Praneeth, my fellow contributors. +We talked about the importance of open-source contribution and discussed scientific visualization, how important it is and how it differs from game engines despite having some similarities. +We also discussed how important the code review is and how to do a proper code review.

+

+ +

Read more ...

+
+
+ +
+

+ My journey till getting accepted into GSoC22 +

+
    +
  • + + + 23 May 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Mohamed Abouagour + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

My name is Mohamed and I’m from Egypt. I am pursuing a Bachelor of Engineering in Computer Engineering and Automatic Control (expected: 2023), Tanta University, Egypt.

+

+ +

Read more ...

+
+
+ + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/blog/author/mohamed-abouagour/atom.xml b/v0.10.x/blog/author/mohamed-abouagour/atom.xml new file mode 100644 index 000000000..1a7328cac --- /dev/null +++ b/v0.10.x/blog/author/mohamed-abouagour/atom.xml @@ -0,0 +1,762 @@ + + + https://fury.gl/ + Blog - Posts by Mohamed Abouagour + 2024-02-29T15:43:57.462379+00:00 + + + ABlog + + https://fury.gl/posts/2023/2023-01-29-final-report-mohamed.html + Google Summer of Code Final Work Product + 2023-01-29T00:00:00-05:00 + + Mohamed Abouagour + + <center><a href="https://summerofcode.withgoogle.com/programs/2022/projects/ZZQ6IrHq"><img src="https://developers.google.com/open-source/gsoc/resources/downloads/GSoC-logo-horizontal.svg" alt="gsoc" height="50"/></a></center><center> +<a href="https://summerofcode.withgoogle.com/projects/#6653942668197888"><img src="https://www.python.org/static/community_logos/python-logo.png" height="45"/></a> +<a href="https://fury.gl/latest/community.html"><img src="https://python-gsoc.org/logos/FURY.png" alt="fury" height="45"/></a> +</center><section id="google-summer-of-code-final-work-product"> + +<ul class="simple"> +<li><p><strong>Name:</strong> Mohamed Abouagour</p></li> +<li><p><strong>Organisation:</strong> Python Software Foundation</p></li> +<li><p><strong>Sub-Organisation:</strong> FURY</p></li> +<li><p><strong>Project:</strong> <a class="reference external" href="https://github.com/fury-gl/fury/wiki/Google-Summer-of-Code-2022-(GSOC2022)#project-2-keyframe-animations-in-fury">FURY - Keyframe animations API</a></p></li> +</ul> +<section id="proposed-objectives"> +<h2>Proposed Objectives</h2> +<ul class="simple"> +<li><p>Keyframe animations API</p> +<ul> +<li><p>Basic playback functions, such as playing, pausing, and rewinding the timeline.</p></li> +<li><p>Adding keyframes at a specific time for transformations of FURY actors and cameras such as translation, scale, rotation, color, and opacity.</p></li> +<li><p>Implement quaternion-based interpolation (SLERP)</p></li> +<li><p>Allow the camera to be interpolated by the keyframe system.</p></li> +<li><p>Allow the creation and removal of actors from the scene according to the keyframes.</p></li> +<li><p>Visualize the motion path of positional animation.</p></li> +<li><p>Speed the animation using GLSL vertex and fragment shaders.</p></li> +</ul> +</li> +</ul> +</section> +<section id="modified-objectives"> +<h2>Modified Objectives</h2> +<ul class="simple"> +<li><p>Adding a playback panel for controlling the timeline.</p></li> +<li><p>Billboard actor using the geometry shader.</p></li> +<li><p>Hierarchical animation support.</p></li> +<li><p>Animating primitives of the same Fury actor separately.</p></li> +<li><p>Color interpolators.</p></li> +</ul> +</section> +<section id="objectives-completed"> +<h2>Objectives Completed</h2> +<ul> +<li><p>Keyframes Animation API</p> +<ul> +<li><p><code class="docutils literal notranslate"><span class="pre">Animation</span></code> Class</p></li> +<li><p>The <code class="docutils literal notranslate"><span class="pre">Animation</span></code> class is the main part of the FURY animation module. It is responsible for keyframe animations for a single or a group of FURY actors. The <code class="docutils literal notranslate"><span class="pre">Animation</span></code> is able to handle multiple attributes and properties of Fury actors such as position, color, scale, rotation, and opacity. It is also capable of doing the following:</p> +<ul class="simple"> +<li><p>Set animation keyframes and events.</p></li> +<li><p>Animate custom properties.</p></li> +<li><p>Support add-to-scene/remove-from-scene events.</p></li> +<li><p>Can animate other animations (Hierarchical animation)</p></li> +<li><p>Set or change the keyframes interpolation method.</p></li> +<li><p>Visualize the motion path of the positional animation.</p></li> +<li><p><code class="docutils literal notranslate"><span class="pre">Timeline</span></code> Class +The <code class="docutils literal notranslate"><span class="pre">Timeline</span></code> is the player of FURY <code class="docutils literal notranslate"><span class="pre">Animations</span></code>; it controls the playback of one or more FURY animations. It also has the option to include a very useful playback panel to help control the playback of the animation. The <code class="docutils literal notranslate"><span class="pre">Timeline</span></code> can have a fixed length or get its duration from the animations added to it dynamically. It can loop, play once, change speed, play, pause, and stop.</p></li> +</ul> +</li> +<li><dl class="simple"> +<dt>Keyframes Interpolators</dt><dd><p>Interpolation is also a core part of the keyframes animation. It is responsible for filling in the blanks between the keyframes so that we have transitional states between the set keyframes. Another factor is that interpolators must be super-optimized to interpolate data in a minimum amount of time as possible or else it would be the bottleneck that lags the animation. +The following interpolators have been implemented as a part of the keyframes animation API:</p> +</dd> +</dl> +<ul class="simple"> +<li><p>Step Interpolator</p></li> +<li><p>Linear Interpolator</p></li> +<li><p>Spherical Linear Interpolator (Slerp)</p></li> +<li><p>Spline Interpolator</p></li> +<li><p>Cubic Spline Interpolator</p></li> +<li><p>Cubic Bézier Interpolator</p></li> +<li><p>Color Interpolators:</p> +<ul> +<li><p>XYZ Color Interpolator</p></li> +<li><p>Lab Color Interpolator</p></li> +<li><p>HSV Color Interpolator</p></li> +</ul> +</li> +</ul> +<img alt="https://user-images.githubusercontent.com/63170874/217738142-2dba8f6a-f8ff-4231-babd-048055074cc0.gif" class="align-center" src="https://user-images.githubusercontent.com/63170874/217738142-2dba8f6a-f8ff-4231-babd-048055074cc0.gif" style="width: 560px;" /> +<img alt="https://user-images.githubusercontent.com/63170874/190892795-f47ceaf1-8dd0-4235-99be-2cf0aec323bb.gif" class="align-center" src="https://user-images.githubusercontent.com/63170874/190892795-f47ceaf1-8dd0-4235-99be-2cf0aec323bb.gif" style="width: 560px;" /> +<ul> +<li><dl class="simple"> +<dt>Tutorials</dt><dd><p>Also included 11 tutorials demonstrating how the FURY keyframe animation API works and how to use it to make some interesting animations. These tutorial will be added soon to the FURY website. +Subjects explained in the tutorials are:</p> +</dd> +</dl> +<ul class="simple"> +<li><p><strong>Introduction</strong></p></li> +<li><p><strong>Timeline</strong></p></li> +<li><p><strong>Interpolators</strong></p></li> +<li><p><strong>Camera Animation</strong></p></li> +<li><p><strong>Hierarchical Animation</strong></p></li> +<li><p><strong>Using Color Interpolators</strong></p></li> +<li><p><strong>Using Bezier Interpolator</strong></p></li> +<li><p><strong>Using Spline Interpolator</strong></p></li> +<li><p><strong>Using time-based functions</strong></p></li> +<li><p><strong>Creating Custom Interpolators</strong></p></li> +<li><p><strong>Arm Robot Animation</strong></p></li> +</ul> +</li> +</ul> +</li> +</ul> +<p><em>Pull Requests:</em></p> +<ul class="simple"> +<li><p><strong>Keyframe animations and interpolators (Merged):</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/647">fury-gl/fury#647</a></p></li> +<li><p><strong>Separating the ``Timeline`` (Ready to be Merged):</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/694">fury-gl/fury#694</a></p></li> +<li><p><strong>Timeline hierarchical transformation (Merged):</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/665">fury-gl/fury#665</a></p></li> +<li><p><strong>Add Timelines to ShowManager directly (Ready to be Merged):</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/690">fury-gl/fury#690</a></p></li> +<li><p><strong>Updating animation tutorials (Ready to be Merged):</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/680">fury-gl/fury#680</a></p></li> +<li><p><strong>Record keyframe animation as GIF and MP4 (Under Development):</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/687">fury-gl/fury#687</a></p></li> +</ul> +</li> +<li><p>PlaybackPanel UI component</p> +<p>At first, while in the early development stage of the FURY keyframe animation API, basic playback buttons were used to play, pause, and stop the animation. As the API kept growing, more controllers needed to be implemented, such as the time progress slider, the speed changer, and the loop toggle. And composing all of these controllers into a single UI element was inevitable. +While the PlaybackPanel is a main part of the <code class="docutils literal notranslate"><span class="pre">Timeline</span></code>, the goal was to make it completely independent from the keyframes animation API so that it can be used for anything else, i.e. a video player actor or a continuous time simulation or any other time-dependent applications.</p> +<a class="reference external image-reference" href="https://user-images.githubusercontent.com/63170874/194377387-bfeeea2c-b4ee-4d26-82c0-b76c27fa0f90.png"><img alt="image" src="https://user-images.githubusercontent.com/63170874/194377387-bfeeea2c-b4ee-4d26-82c0-b76c27fa0f90.png" /></a> +<p><em>Pull Requests:</em></p> +<ul class="simple"> +<li><p><strong>``PlaybackPanel`` initial implementation (Merged):</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/647">fury-gl/fury#647</a></p> +<ul> +<li><p><strong>Set position and width of the ``PlaybackPanel`` (Merged):</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/692">fury-gl/fury#692</a></p></li> +</ul> +</li> +</ul> +</li> +<li><dl class="simple"> +<dt>Billboard actor using the geometry shader</dt><dd><p>Fury already has a billboard actor implemented using two triangles to construct the billboard. But the new approach uses only one vertex and the canvas of the billboard is generated by the geometry shader. This approach is faster in initialization since only the center is needed and no additional computations to generate the primitive on the CPU side. Also, animating these new billboards using the method mentioned above in the previous objective is way much faster, and faster is one of the reasons why we use billboards.</p> +</dd> +</dl> +<p><em>Pull Requests:</em></p> +<ul class="simple"> +<li><p><strong>billboards using geometry shader (Ready to be Merged):</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/631">fury-gl/fury#631</a></p></li> +</ul> +</li> +</ul> +</section> +<section id="objectives-in-progress"> +<h2>Objectives in Progress</h2> +<ul> +<li><dl class="simple"> +<dt>Animating primitives of the same FURY Actor separately</dt><dd><p>Animating FURY actors is not a problem and can be done easily using the FURY animation module. The problem appears when trying to animate a massive amount of actors, thousands or even hundreds of thousands of actors, it’s impossible to do that using the animation module. Instead, primitives of the same actor can be animated by changing their vertices and then sending the new vertices buffer to the GPU. This also needs some discussion to find the cleanest way to implement it.</p> +</dd> +</dl> +<p><em>Pull Requests:</em></p> +<ul class="simple"> +<li><p><strong>Animating primitives of the same actor (Draft):</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/660">fury-gl/fury#660</a></p></li> +<li><p><strong>Added primitives count to the polydata (Merged):</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/617">fury-gl/fury#617</a></p></li> +</ul> +</li> +<li><dl class="simple"> +<dt>Speeding up the animation using GLSL shaders</dt><dd><p>Using the power of the GPU to help speed up the animations since some interpolators are relatively slow, such as the spline interpolator. Besides, morphing and skeletal animation would be tremendously optimized if they were computed on the GPU side!</p> +</dd> +</dl> +<p><em>Pull Requests:</em></p> +<ul class="simple"> +<li><p><strong>Adding shader support for doing the animations (Open):</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/702">fury-gl/fury#702</a></p></li> +</ul> +</li> +</ul> +</section> +<section id="other-objectives"> +<h2>Other Objectives</h2> +<ul> +<li><dl> +<dt>Added more enhancements to the <code class="docutils literal notranslate"><span class="pre">vector_text</span></code> actor</dt><dd><p>Added the ability to change the direction of the <code class="docutils literal notranslate"><span class="pre">vector_text</span></code> actor, as well as giving it the option to follow the camera. Also added the option to extrude the text which makes it more like 3D text.</p> +<p><em>Pull Requests:</em></p> +</dd> +</dl> +<ul class="simple"> +<li><p><strong>Improving ``vector_text`` (Merged)</strong> : <a class="github reference external" href="https://github.com/fury-gl/fury/pull/661">fury-gl/fury#661</a></p></li> +</ul> +</li> +<li><p>Other PRs</p> +<ul class="simple"> +<li><p><strong>Fixed multi_samples not being used (Merged)</strong>: <a class="github reference external" href="https://github.com/fury-gl/fury/pull/594">fury-gl/fury#594</a></p></li> +<li><p><strong>Added an accurate way to calculate FPS (Merged)</strong>: <a class="github reference external" href="https://github.com/fury-gl/fury/pull/597">fury-gl/fury#597</a></p></li> +<li><p><strong>Implemented two new hooks for UI sliders (Merged)</strong>: <a class="github reference external" href="https://github.com/fury-gl/fury/pull/634">fury-gl/fury#634</a></p></li> +<li><p><strong>Fixed some old tutorials (Merged)</strong>: <a class="github reference external" href="https://github.com/fury-gl/fury/pull/591">fury-gl/fury#591</a></p></li> +<li><p><strong>Returning the Timer id while initialization (Merged)</strong>: <a class="github reference external" href="https://github.com/fury-gl/fury/pull/598">fury-gl/fury#598</a></p></li> +</ul> +</li> +<li><p>GSoC Weekly Blogs</p> +<ul class="simple"> +<li><p>My blog posts can be found on <a class="reference external" href="https://fury.gl/latest/blog/author/mohamed-abouagour.html">the FURY website</a> and <a class="reference external" href="https://blogs.python-gsoc.org/en/m-agours-blog/">the Python GSoC blog</a>.</p></li> +</ul> +</li> +</ul> +</section> +<section id="timeline"> +<h2>Timeline</h2> +<table class="table"> +<thead> +<tr class="row-odd"><th class="head"><p>Date</p></th> +<th class="head"><p>Description</p></th> +<th class="head"><p>Blog Post Link</p></th> +</tr> +</thead> +<tbody> +<tr class="row-even"><td><p>Week 0 <span class="raw-html"><br></span>(23-05-2022)</p></td> +<td><p>My journey till getting accepted into GSoC22</p></td> +<td><p><a class="reference external" href="https://fury.gl/latest/posts/2022/2022-05-23-first-post-mohamed.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/m-agours-blog/my-journey-till-getting-accepted-into-gsoc22/">Python</a></p></td> +</tr> +<tr class="row-odd"><td><p>Week 1<span class="raw-html"><br></span>(08-06-2022)</p></td> +<td><p>Implementing a basic Keyframe animation API</p></td> +<td><aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-01-29-final-report-mohamed.rst</span>, line 18); <em><a href="#id1">backlink</a></em></p> +<p>Duplicate explicit target name: “fury”.</p> +</aside> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-01-29-final-report-mohamed.rst</span>, line 18); <em><a href="#id2">backlink</a></em></p> +<p>Duplicate explicit target name: “python”.</p> +</aside> +<p><a class="reference external" href="https://fury.gl/latest/posts/2022/2022-06-08-week-1-mohamed.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/m-agours-blog/week-1-implementing-a-basic-keyframe-animation-api/">Python</a></p> +</td> +</tr> +<tr class="row-even"><td><p>Week 2<span class="raw-html"><br></span>(28-06-2022)</p></td> +<td><p>Implementing non-linear and color interpolators</p></td> +<td><aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-01-29-final-report-mohamed.rst</span>, line 18); <em><a href="#id3">backlink</a></em></p> +<p>Duplicate explicit target name: “fury”.</p> +</aside> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-01-29-final-report-mohamed.rst</span>, line 18); <em><a href="#id4">backlink</a></em></p> +<p>Duplicate explicit target name: “python”.</p> +</aside> +<p><a class="reference external" href="https://fury.gl/latest/posts/2022/2022-06-28-week-2-mohamed.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/m-agours-blog/week-2-implementing-non-linear-and-color-interpolators/">Python</a></p> +</td> +</tr> +<tr class="row-odd"><td><p>Week 3<span class="raw-html"><br></span>(04-07-2022)</p></td> +<td><p>Redesigning the API,<span class="raw-html"><br></span> Implementing cubic Bezier Interpolator,<span class="raw-html"><br></span> and making progress on the GPU side!</p></td> +<td><aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-01-29-final-report-mohamed.rst</span>, line 18); <em><a href="#id5">backlink</a></em></p> +<p>Duplicate explicit target name: “fury”.</p> +</aside> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-01-29-final-report-mohamed.rst</span>, line 18); <em><a href="#id6">backlink</a></em></p> +<p>Duplicate explicit target name: “python”.</p> +</aside> +<p><a class="reference external" href="https://fury.gl/latest/posts/2022/2022-07-04-week-3-mohamed.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/m-agours-blog/week-3-redesigning-the-api-implementing-cubic-bezier-interpolator-and-making-progress-on-the-gpu-side/">Python</a></p> +</td> +</tr> +<tr class="row-even"><td><p>Week 4<span class="raw-html"><br></span>(11-07-2022)</p></td> +<td><p>Camera animation, <span class="raw-html"><br></span>interpolation in GLSL, and a single Timeline!</p></td> +<td><aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-01-29-final-report-mohamed.rst</span>, line 18); <em><a href="#id7">backlink</a></em></p> +<p>Duplicate explicit target name: “fury”.</p> +</aside> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-01-29-final-report-mohamed.rst</span>, line 18); <em><a href="#id8">backlink</a></em></p> +<p>Duplicate explicit target name: “python”.</p> +</aside> +<p><a class="reference external" href="https://fury.gl/latest/posts/2022/2022-07-11-week-4-mohamed.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/m-agours-blog/week-4-camera-animation-interpolation-in-glsl-and-a-single-timeline/">Python</a></p> +</td> +</tr> +<tr class="row-odd"><td><p>Week 5<span class="raw-html"><br></span>(19-07-2022)</p></td> +<td><p>Slerp implementation, <span class="raw-html"><br></span>documenting the Timeline, and adding unit tests</p></td> +<td><aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-01-29-final-report-mohamed.rst</span>, line 18); <em><a href="#id9">backlink</a></em></p> +<p>Duplicate explicit target name: “fury”.</p> +</aside> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-01-29-final-report-mohamed.rst</span>, line 18); <em><a href="#id10">backlink</a></em></p> +<p>Duplicate explicit target name: “python”.</p> +</aside> +<p><a class="reference external" href="https://fury.gl/latest/posts/2022/2022-07-19-week-5-mohamed.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/m-agours-blog/week-5-slerp-implementation-documenting-the-timeline-and-adding-unit-tests/">Python</a></p> +</td> +</tr> +<tr class="row-even"><td><p>Week 6<span class="raw-html"><br></span>(25-07-2022)</p></td> +<td><p>Fixing the Timeline issues and equipping it with<span class="raw-html"><br></span> more features</p></td> +<td><aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-01-29-final-report-mohamed.rst</span>, line 18); <em><a href="#id11">backlink</a></em></p> +<p>Duplicate explicit target name: “fury”.</p> +</aside> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-01-29-final-report-mohamed.rst</span>, line 18); <em><a href="#id12">backlink</a></em></p> +<p>Duplicate explicit target name: “python”.</p> +</aside> +<p><a class="reference external" href="https://fury.gl/latest/posts/2022/2022-07-25-week-6-mohamed.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/m-agours-blog/week-6-fixing-the-timeline-issues-and-equipping-it-with-more-features/">Python</a></p> +</td> +</tr> +<tr class="row-odd"><td><p>Week 7<span class="raw-html"><br></span>(01-08-2022)</p></td> +<td><p>Billboard spheres and implementing interpolators<span class="raw-html"><br></span> using closures</p></td> +<td><aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-01-29-final-report-mohamed.rst</span>, line 18); <em><a href="#id13">backlink</a></em></p> +<p>Duplicate explicit target name: “fury”.</p> +</aside> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-01-29-final-report-mohamed.rst</span>, line 18); <em><a href="#id14">backlink</a></em></p> +<p>Duplicate explicit target name: “python”.</p> +</aside> +<p><a class="reference external" href="https://fury.gl/latest/posts/2022/2022-08-01-week-7-mohamed.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/m-agours-blog/week-7-billboard-spheres-and-implementing-interpolators-using-closures/">Python</a></p> +</td> +</tr> +<tr class="row-even"><td><p>Week 8<span class="raw-html"><br></span>(09-08-2022)</p></td> +<td><p>Back to the shader-based version of the Timeline</p></td> +<td><aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-01-29-final-report-mohamed.rst</span>, line 18); <em><a href="#id15">backlink</a></em></p> +<p>Duplicate explicit target name: “fury”.</p> +</aside> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-01-29-final-report-mohamed.rst</span>, line 18); <em><a href="#id16">backlink</a></em></p> +<p>Duplicate explicit target name: “python”.</p> +</aside> +<p><a class="reference external" href="https://fury.gl/latest/posts/2022/2022-08-09-week-8-mohamed.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/m-agours-blog/week-8-back-to-the-shader-based-version-of-the-timeline/">Python</a></p> +</td> +</tr> +<tr class="row-odd"><td><p>Week 9<span class="raw-html"><br></span>(16-08-2022)</p></td> +<td><p>Animating primitives of the same actor</p></td> +<td><aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-01-29-final-report-mohamed.rst</span>, line 18); <em><a href="#id17">backlink</a></em></p> +<p>Duplicate explicit target name: “fury”.</p> +</aside> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-01-29-final-report-mohamed.rst</span>, line 18); <em><a href="#id18">backlink</a></em></p> +<p>Duplicate explicit target name: “python”.</p> +</aside> +<p><a class="reference external" href="https://fury.gl/latest/posts/2022/2022-08-16-week-9-mohamed.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/m-agours-blog/week-9-animating-primitives-of-the-same-actor/">Python</a></p> +</td> +</tr> +<tr class="row-even"><td><p>Week 10<span class="raw-html"><br></span>(23-08-2022)</p></td> +<td><p>Supporting hierarchical animating</p></td> +<td><aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-01-29-final-report-mohamed.rst</span>, line 18); <em><a href="#id19">backlink</a></em></p> +<p>Duplicate explicit target name: “fury”.</p> +</aside> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-01-29-final-report-mohamed.rst</span>, line 18); <em><a href="#id20">backlink</a></em></p> +<p>Duplicate explicit target name: “python”.</p> +</aside> +<p><a class="reference external" href="https://fury.gl/latest/posts/2022/2022-08-23-week-10-mohamed.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/m-agours-blog/week-10-supporting-hierarchical-animations/">Python</a></p> +</td> +</tr> +<tr class="row-odd"><td><p>Week 11<span class="raw-html"><br></span>(30-08-2022)</p></td> +<td><p>Improving tutorials a little</p></td> +<td><aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-01-29-final-report-mohamed.rst</span>, line 18); <em><a href="#id21">backlink</a></em></p> +<p>Duplicate explicit target name: “fury”.</p> +</aside> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-01-29-final-report-mohamed.rst</span>, line 18); <em><a href="#id22">backlink</a></em></p> +<p>Duplicate explicit target name: “python”.</p> +</aside> +<p><a class="reference external" href="https://fury.gl/latest/posts/2022/2022-08-30-week-11-mohamed.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/m-agours-blog/week-11-improving-tutorials-a-little/">Python</a></p> +</td> +</tr> +<tr class="row-even"><td><p>Week 12<span class="raw-html"><br></span>(7-09-2022)</p></td> +<td><p>Adding new tutorials</p></td> +<td><aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-01-29-final-report-mohamed.rst</span>, line 18); <em><a href="#id23">backlink</a></em></p> +<p>Duplicate explicit target name: “fury”.</p> +</aside> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-01-29-final-report-mohamed.rst</span>, line 18); <em><a href="#id24">backlink</a></em></p> +<p>Duplicate explicit target name: “python”.</p> +</aside> +<p><a class="reference external" href="https://fury.gl/latest/posts/2022/2022-09-7-week-12-mohamed.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/m-agours-blog/week-12-adding-new-tutorials/">Python</a></p> +</td> +</tr> +<tr class="row-odd"><td><p>Week 13<span class="raw-html"><br></span>(20-09-2022)</p></td> +<td><p>Keyframes animation is now a bit easier in FURY</p></td> +<td><aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-01-29-final-report-mohamed.rst</span>, line 18); <em><a href="#id25">backlink</a></em></p> +<p>Duplicate explicit target name: “fury”.</p> +</aside> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-01-29-final-report-mohamed.rst</span>, line 18); <em><a href="#id26">backlink</a></em></p> +<p>Duplicate explicit target name: “python”.</p> +</aside> +<p><a class="reference external" href="https://fury.gl/latest/posts/2022/2022-09-20-week-13-mohamed.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/m-agours-blog/week-13-keyframes-animation-is-now-a-bit-easier-in-fury/">Python</a></p> +</td> +</tr> +</tbody> +</table> +</section> +</section> + + + Name: Mohamed Abouagour + + 2023-01-29T00:00:00-05:00 + + + https://fury.gl/posts/2022/2022-09-28-week-14-mohamed.html + Week 14: Keyframes animation is now a bit easier in FURY + 2022-09-28T00:00:00-04:00 + + Mohamed Abouagour + + <section id="week-14-keyframes-animation-is-now-a-bit-easier-in-fury"> + +<section id="what-did-you-do-this-week"> +<h2>What did you do this week?</h2> +<ul class="simple"> +<li><p>Separated the <code class="docutils literal notranslate"><span class="pre">Timeline</span></code> into a <code class="docutils literal notranslate"><span class="pre">Timeline</span></code> and an <code class="docutils literal notranslate"><span class="pre">Animation</span></code>. So, instead of having the <code class="docutils literal notranslate"><span class="pre">Timeline</span></code> do everything. It’s now more like doing animations in Blender and other 3D editing software where the timeline handles the playback of several animations <a class="reference external" href="https://github.com/fury-gl/fury/pull/694">#694</a>.</p></li> +<li><p>Added unit tests for the billboards based on geometry shader.</p></li> +<li><p>Tried to solve the issue with actors not being rendered when their positions are changed in the vertex shader. For now, I just found a way to force invoke the shader callbacks, but force rendering the actor itself still needs more investigation.</p></li> +</ul> +</section> +<section id="what-is-coming-up-next-week"> +<h2>What is coming up next week?</h2> +<ul class="simple"> +<li><p>Add unit testing for the <code class="docutils literal notranslate"><span class="pre">Animation</span></code>, document it well, and implement more properties suggested by Shivam (&#64;xtanion).</p></li> +<li><p>Modify <a class="reference external" href="https://github.com/fury-gl/fury/pull/690">Add Timelines to ShowManager directly</a> PR to allow adding <code class="docutils literal notranslate"><span class="pre">Animation</span></code> to the <code class="docutils literal notranslate"><span class="pre">ShowManager</span></code> as well.</p></li> +<li><p>Update tutorials to adapt to all the new changes in the <code class="docutils literal notranslate"><span class="pre">animation</span></code> module.</p></li> +</ul> +</section> +<section id="did-you-get-stuck-anywhere"> +<h2>Did you get stuck anywhere?</h2> +<ul class="simple"> +<li><p>I got stuck trying to solve the issue mentioned above with actors not being rendered.</p></li> +</ul> +</section> +</section> + + + Separated the Timeline into a Timeline and an Animation. So, instead of having the Timeline do everything. It’s now more like doing animations in Blender and other 3D editing software where the timeline handles the playback of several animations #694. + + 2022-09-28T00:00:00-04:00 + + + https://fury.gl/posts/2022/2022-09-20-week-13-mohamed.html + Week 13: Keyframes animation is now a bit easier in FURY + 2022-09-20T00:00:00-04:00 + + Mohamed Abouagour + + <section id="week-13-keyframes-animation-is-now-a-bit-easier-in-fury"> + +<section id="what-did-you-do-this-week"> +<h2>What did you do this week?</h2> +<ul> +<li><p>Added the ability to have the ShowManager stored inside the Timeline. That way the user does not have to update and render the animations because it will be done internally.</p></li> +<li><p>Added a record method to the Timeline that records the animation and saves it as either GIF or MP4 (requires OpenCV). This record functionality has the option to show/hide the PlaybackPanel which makes it better than recording the animation using a third-party software.</p> +<blockquote> +<div><img alt="https://user-images.githubusercontent.com/63170874/190892795-f47ceaf1-8dd0-4235-99be-2cf0aec323bb.gif" class="align-center" src="https://user-images.githubusercontent.com/63170874/190892795-f47ceaf1-8dd0-4235-99be-2cf0aec323bb.gif" style="width: 600px;" /> +</div></blockquote> +</li> +<li><p>Fixed some issues that Serge mentioned while reviewing PR <a class="reference external" href="https://github.com/fury-gl/fury/pull/665">#665</a>.</p></li> +</ul> +</section> +<section id="what-is-coming-up-next-week"> +<h2>What is coming up next week?</h2> +<ul class="simple"> +<li><p>Instead of adding the ShowManager to the Timeline, doing it the other way around is a better choice and makes the code more readable.</p></li> +<li><p>Add tests for the Timeline’s record method.</p></li> +<li><p>Add tests for the billboard actor to test consistency among different approaches..</p></li> +</ul> +</section> +<section id="did-you-get-stuck-anywhere"> +<h2>Did you get stuck anywhere?</h2> +<p>I didn’t get stuck this week.</p> +</section> +</section> + + + Added the ability to have the ShowManager stored inside the Timeline. That way the user does not have to update and render the animations because it will be done internally. + + 2022-09-20T00:00:00-04:00 + + + https://fury.gl/posts/2022/2022-09-7-week-12-mohamed.html + Week 12: Adding new tutorials + 2022-09-07T00:00:00-04:00 + + Mohamed Abouagour + + <section id="week-12-adding-new-tutorials"> + +<section id="what-did-you-do-this-week"> +<h2>What did you do this week?</h2> +<ul class="simple"> +<li><p>Restructured tutorials to be more readable and more focused on a specific topic.</p></li> +<li><p>Replaced the old animation introductory tutorial with a lot simpler one, and added tutorial to explain keyframes and interpolators.</p></li> +<li><p>Simplified setting lighting uniforms for the geometry-based-billboard actor by getting the <code class="docutils literal notranslate"><span class="pre">Scene</span></code> from the actor using <code class="docutils literal notranslate"><span class="pre">actor.GetConsumer(scene_idx)</span></code>.</p></li> +</ul> +</section> +<section id="what-is-coming-up-next-week"> +<h2>What is coming up next week?</h2> +<ul class="simple"> +<li><p>Allow the <code class="docutils literal notranslate"><span class="pre">Timeline</span></code> to take the <code class="docutils literal notranslate"><span class="pre">ShowManager</span></code> as an argument to reduce the amount of code the user has to write every time using FURY animations.</p></li> +<li><p>Fix some typos in the tutorials and write some info about <code class="docutils literal notranslate"><span class="pre">Slerp</span></code>.</p></li> +<li><p>Find a way to fix the shader-callback problem of not being executed when the actor is out of the camera’s frustum.</p></li> +</ul> +</section> +<section id="did-you-get-stuck-anywhere"> +<h2>Did you get stuck anywhere?</h2> +<p>I didn’t get stuck this week.</p> +</section> +</section> + + + Restructured tutorials to be more readable and more focused on a specific topic. + + 2022-09-07T00:00:00-04:00 + + + https://fury.gl/posts/2022/2022-08-30-week-11-mohamed.html + Week 11: Improving tutorials a little + 2022-08-30T00:00:00-04:00 + + Mohamed Abouagour + + <section id="week-11-improving-tutorials-a-little"> + +<section id="what-did-you-do-this-week"> +<h2>What did you do this week?</h2> +<ul class="simple"> +<li><p>Fixed some issues in the hierarchical order animation support <a class="reference external" href="https://github.com/fury-gl/fury/pull/665">PR</a> that we discussed during last week’s meeting (mostly naming issues).</p></li> +<li><p>Explained the introductory tutorial a little. But it is not suitable for beginners. So, I will spend time improving tutorials this week.</p></li> +<li><p>Added extrusion to <a class="reference external" href="https://github.com/fury-gl/fury/pull/661">vector_text</a> to allow the z-scaling to be functional.</p></li> +<li><p>Fixed <code class="docutils literal notranslate"><span class="pre">lightColor0</span></code> being <a class="reference external" href="https://github.com/fury-gl/fury/blob/464b3dd3f5be5159f5f9617a2c7b6f7bd65c0c80/fury/actor.py#L2395">hard-set</a> to <code class="docutils literal notranslate"><span class="pre">(1,</span> <span class="pre">1,</span> <span class="pre">1)</span></code>. Instead, it’s now using the <code class="docutils literal notranslate"><span class="pre">Scene</span></code> to set the lighting uniforms.</p></li> +</ul> +</section> +<section id="what-is-coming-up-next-week"> +<h2>What is coming up next week?</h2> +<ul class="simple"> +<li><p>Improve tutorials.</p></li> +<li><p>Find out how to get the <code class="docutils literal notranslate"><span class="pre">Scene</span></code> from the actor instead of manually assigning it.</p></li> +<li><p>If I have time, I will try to implement recording animation as GIF or as a video.</p></li> +</ul> +</section> +<section id="did-you-get-stuck-anywhere"> +<h2>Did you get stuck anywhere?</h2> +<p>I didn’t get stuck this week.</p> +</section> +</section> + + + Fixed some issues in the hierarchical order animation support PR that we discussed during last week’s meeting (mostly naming issues). + + 2022-08-30T00:00:00-04:00 + + + https://fury.gl/posts/2022/2022-08-23-week-10-mohamed.html + Week 10: Supporting hierarchical animating + 2022-08-23T00:00:00-04:00 + + Mohamed Abouagour + + <section id="week-10-supporting-hierarchical-animating"> + +<section id="what-did-you-do-this-week"> +<h2>What did you do this week?</h2> +<ul> +<li><p>Implemented hierarchical order support for animations using matrices in this <a class="reference external" href="https://github.com/fury-gl/fury/pull/665">PR</a>.</p></li> +<li><p>Improved the API of a <a class="reference external" href="https://github.com/fury-gl/fury/pull/660">PartialActor</a> by adding some methods to control the scales, positions and colors.</p></li> +<li><p>Added a new example of using the new hierarchical feature to animate an arm robot.</p> +<blockquote> +<div><iframe id="player" type="text/html" width="440" height="390" src="https://user-images.githubusercontent.com/63170874/185803285-9184c561-a787-4ad0-ac1a-0b22854da889.mp4" frameborder="0"></iframe></div></blockquote> +</li> +<li><p>Improved <a class="reference external" href="https://github.com/fury-gl/fury/pull/661">vector_text</a> a little by adding options to control its direction.</p></li> +</ul> +</section> +<section id="what-is-coming-up-next-week"> +<h2>What is coming up next week?</h2> +<ul class="simple"> +<li><p>Finish the hierarchical order animation support <a class="reference external" href="https://github.com/fury-gl/fury/pull/665">PR</a>.</p></li> +<li><p>Explain tutorials in more detail. See this <a class="reference external" href="https://github.com/fury-gl/fury/issues/664">issue</a>.</p></li> +<li><p>Fix issues discovered by Serge in this <a class="reference external" href="https://github.com/fury-gl/fury/pull/647#pullrequestreview-1061261078">review</a>.</p></li> +<li><p>Fix <code class="docutils literal notranslate"><span class="pre">lightColor0</span></code> being <a class="reference external" href="https://github.com/fury-gl/fury/blob/464b3dd3f5be5159f5f9617a2c7b6f7bd65c0c80/fury/actor.py#L2395">hard-set</a> to <code class="docutils literal notranslate"><span class="pre">(1,</span> <span class="pre">1,</span> <span class="pre">1)</span></code>. Instead, find a way to get this property the same way other polygon-based actor gets it.</p></li> +<li><p>Try to get PRs and issues mentioned above merged, closed or ready for a final review.</p></li> +</ul> +</section> +<section id="did-you-get-stuck-anywhere"> +<h2>Did you get stuck anywhere?</h2> +<p>I didn’t get stuck this week.</p> +</section> +</section> + + + Implemented hierarchical order support for animations using matrices in this PR. + + 2022-08-23T00:00:00-04:00 + + + https://fury.gl/posts/2022/2022-08-16-week-9-mohamed.html + Week 9: Animating primitives of the same actor + 2022-08-16T00:00:00-04:00 + + Mohamed Abouagour + + <section id="week-9-animating-primitives-of-the-same-actor"> + +<section id="what-did-you-do-this-week"> +<h2>What did you do this week?</h2> +<ul> +<li><p>Made two tutorials in this <a class="reference external" href="https://github.com/fury-gl/fury/pull/660">PR</a> that show two approaches on how to animate primitives of the same FURY actor using the <code class="docutils literal notranslate"><span class="pre">Timeline</span></code>.</p> +<blockquote> +<div><iframe id="player" type="text/html" width="440" height="390" src="https://user-images.githubusercontent.com/63170874/184627836-6b022832-043b-4c28-85b3-d5911808e1a4.mp4" frameborder="0"></iframe></div></blockquote> +</li> +<li><p>Tried sending all keyframes at once as uniforms, but I faced a performance issue doing this.</p></li> +<li><p>Set uniforms that are not being sent by VTK for the billboard actor.</p></li> +</ul> +</section> +<section id="what-is-coming-up-next-week"> +<h2>What is coming up next week?</h2> +<ul class="simple"> +<li><p>Alter the <code class="docutils literal notranslate"><span class="pre">Timeline</span></code> to use matrices instead of setting values directly to allow hierarchical transformation.</p></li> +<li><p>Improve the API of the <code class="docutils literal notranslate"><span class="pre">PartialActor</span></code> to act almost like a normal actor.</p></li> +</ul> +</section> +<section id="did-you-get-stuck-anywhere"> +<h2>Did you get stuck anywhere?</h2> +<p>I had some issues trying to get shader’s uniforms to hold their data, and solving this issue led to another issue, which was a performance issue.</p> +</section> +</section> + + + Made two tutorials in this PR that show two approaches on how to animate primitives of the same FURY actor using the Timeline. + + 2022-08-16T00:00:00-04:00 + + + https://fury.gl/posts/2022/2022-08-09-week-8-mohamed.html + Week 8: Back to the shader-based version of the Timeline + 2022-08-09T00:00:00-04:00 + + Mohamed Abouagour + + <section id="week-8-back-to-the-shader-based-version-of-the-timeline"> + +<section id="what-did-you-do-this-week"> +<h2>What did you do this week?</h2> +<ul> +<li><p>First, I made some modifications to the main animation PR. Then as Filipi requested, I integrated the vertex shader that I was implementing a few weeks ago to work with the new improved version of the <code class="docutils literal notranslate"><span class="pre">Timeline</span></code>.</p></li> +<li><p>As for how keyframes are sent to the GPU, the method being used is to send the needed keyframes for each draw. This is heavy because we only roll out the interpolation part, which with linear or step interpolation won’t make any difference! Instead, I tried setting all the keyframes at once as a GLSL variable using string manipulation before animation starts. This also was slow to initialize, and the shader was getting bigger and slower to bind and unbind. To solve this problem, I made a uniform that holds all the keyframes of the animation and sent data as vectors, which was faster than string manipulation, also it was faster to render since data are now stored directly in memory, and the shader program was a lot more compact. But this method had an issue; uniforms do not keep data stored as expected! If two or more actors have the same uniform name in their shader program and only one of them was set, the other actor will get this value as well. A way around this is to change the names of the uniforms so that they maintain their data.</p></li> +<li><p>Tested animating 160K billboard spheres animation but this time using translation as well. And they performed very well.</p> +<blockquote> +<div><iframe id="player" type="text/html" width="440" height="390" src="https://user-images.githubusercontent.com/63170874/183534269-73bf6158-cd54-4011-9742-0483d67ca802.mp4" frameborder="0"></iframe></div></blockquote> +</li> +</ul> +</section> +<section id="what-is-coming-up-next-week"> +<h2>What is coming up next week?</h2> +<ul class="simple"> +<li><p>Fix issues I encountered this week working with GLSL shaders.</p></li> +<li><p>Implement slerp in GLSL as well as figure out a way to optimize sending keyframes to the shader program.</p></li> +<li><p>Figure a way to animate primitives of the same actor by different timelines.</p></li> +</ul> +</section> +<section id="did-you-get-stuck-anywhere"> +<h2>Did you get stuck anywhere?</h2> +<p>I had two issues, one mentioned above which was uniforms not being able to hold data. The second one is that VTK does not send specular-related uniforms and <code class="docutils literal notranslate"><span class="pre">lightColor0</span></code> to the <code class="docutils literal notranslate"><span class="pre">point</span></code> primitive, which are needed for light calculations.</p> +</section> +</section> + + + First, I made some modifications to the main animation PR. Then as Filipi requested, I integrated the vertex shader that I was implementing a few weeks ago to work with the new improved version of the Timeline. + + 2022-08-09T00:00:00-04:00 + + + https://fury.gl/posts/2022/2022-08-01-week-7-mohamed.html + Week 7: Billboard spheres and implementing interpolators using closures + 2022-08-01T00:00:00-04:00 + + Mohamed Abouagour + + <section id="week-7-billboard-spheres-and-implementing-interpolators-using-closures"> + +<section id="what-did-you-do-this-week"> +<h2>What did you do this week?</h2> +<ul> +<li><p>Restructured the keyframe animation interpolators using closures to be functions instead of classes <a class="reference external" href="https://github.com/fury-gl/fury/pull/647">#647</a>. Now it is easier to implement new interpolators with the help of the functions existing in <a class="reference external" href="https://github.com/fury-gl/fury/blob/670d3a41645eb7bcd445a7d8ae9ddd7bebc376b7/fury/animation/helpers.py">fury/animation/helpers.py</a>. Also, now unit tests can be added for the latter functions.</p></li> +<li><p>Added two examples explaining how to implement a custom interpolator that can be used by the <code class="docutils literal notranslate"><span class="pre">Timeline</span></code>, one using <a class="reference external" href="https://github.com/fury-gl/fury/blob/e0539269adc2a51e35282f83b8b0672bbe047a39/docs/tutorials/05_animation/viz_keyframe_custom_interpolator.py">classes</a> and the other using <a class="reference external" href="https://github.com/fury-gl/fury/blob/670d3a41645eb7bcd445a7d8ae9ddd7bebc376b7/docs/tutorials/05_animation/viz_keyframe_custom_interpolator.py">closures</a>.</p></li> +<li><p>Fixed rotation issue that Shivam discovered while using the <code class="docutils literal notranslate"><span class="pre">Timeline</span></code> to animate glTF models. So, rotation in VTK is done by rotating first around Z-axis, then X-axis, then finally around Y-axis, which was not the order I was using to convert from quaternions to Euler degrees.</p></li> +<li><p>Made changes requested by Javier and Filipi on the billboards using geometry shader <a class="reference external" href="https://github.com/fury-gl/fury/pull/631">PR</a>, and made an example of how to use this billboard to show an impostor sphere which looks almost like a real high poly sphere. Also benchmarked using this version of billboard vs using a quad-based billboard, and how they both affect the FPS of the animation.</p> +<blockquote> +<div><iframe id="player" type="text/html" width="440" height="390" src="https://user-images.githubusercontent.com/63170874/182064895-27fdd00a-6372-4caa-aff6-3a4bad64e407.mp4" frameborder="0"></iframe></div></blockquote> +</li> +</ul> +</section> +<section id="what-is-coming-up-next-week"> +<h2>What is coming up next week?</h2> +<ul class="simple"> +<li><p>Document the new closure-based interpolators. And make some slight renaming changes that we discussed in today’s meeting.</p></li> +<li><p>Add tests to the functions inside <a class="reference external" href="https://github.com/fury-gl/fury/blob/670d3a41645eb7bcd445a7d8ae9ddd7bebc376b7/fury/animation/helpers.py">fury/animation/helpers.py</a>.</p></li> +<li><p>Make changes to the geometry-shader-based billboard to make it more like the quad-based billboard actor while maintaining the new features.</p></li> +<li><p>Integrate the already-implemented shader functionality to the new <code class="docutils literal notranslate"><span class="pre">Timeline</span></code> in a separate draft or PR.</p></li> +</ul> +</section> +<section id="did-you-get-stuck-anywhere"> +<h2>Did you get stuck anywhere?</h2> +<p>I got stuck trying to get and modify the vertices (centers) of the billboard actor.</p> +</section> +</section> + + + Restructured the keyframe animation interpolators using closures to be functions instead of classes #647. Now it is easier to implement new interpolators with the help of the functions existing in fury/animation/helpers.py. Also, now unit tests can be added for the latter functions. + + 2022-08-01T00:00:00-04:00 + + + https://fury.gl/posts/2022/2022-07-25-week-6-mohamed.html + Week 6: Fixing the Timeline issues and equipping it with more features + 2022-07-25T00:00:00-04:00 + + Mohamed Abouagour + + <section id="week-6-fixing-the-timeline-issues-and-equipping-it-with-more-features"> + +<section id="what-did-you-do-this-week"> +<h2>What did you do this week?</h2> +<ul> +<li><p>Improved the <code class="docutils literal notranslate"><span class="pre">PlaybackPanel</span></code> by adding speed control and the ability to loop the animation. Also, fixed the lagging issue of play and pause buttons and composed them into a single play/pause button.</p></li> +<li><p>Updated the old tutorials’ syntax to match the other tutorials and added a new tutorial on position animation using spline interpolation. Added unit tests for the <code class="docutils literal notranslate"><span class="pre">PlaybackPanel</span></code> and the newly added color converters in <code class="docutils literal notranslate"><span class="pre">colormap.py</span></code>.</p></li> +<li><p>Added more hooks to the 2D sliders to cover two more states:</p> +<ol class="arabic simple"> +<li><p><code class="docutils literal notranslate"><span class="pre">on_value_changed</span></code>, which gets called whenever the value of the slider is changed without interacting with the slider.</p></li> +<li><p><code class="docutils literal notranslate"><span class="pre">on_moving_slider</span></code>, which gets called when the position of the slider is changed by user interaction. <a class="reference external" href="https://github.com/fury-gl/fury/pull/634">#634</a>.</p></li> +</ol> +<ul class="simple"> +<li><p>The reason for adding these two hooks is that there was only the <code class="docutils literal notranslate"><span class="pre">on_change</span></code> hook, which always gets called when the value of the slider is changed without considering how the value is changed, hence, the functionality of the slider was limited.</p></li> +</ul> +</li> +<li><p>Provided the ability to add static actors to the <code class="docutils literal notranslate"><span class="pre">Timeline</span></code>, which might be needed in the animation part of Shivam’s glTF project <a class="reference external" href="https://github.com/fury-gl/fury/pull/643">#643</a>.</p> +<ul class="simple"> +<li><p>If an <code class="docutils literal notranslate"><span class="pre">actor</span></code> is added to the <code class="docutils literal notranslate"><span class="pre">Timeline</span></code> as a static actor, it won’t be animated by the <code class="docutils literal notranslate"><span class="pre">Timeline</span></code>, but it will get added to the scene along with the <code class="docutils literal notranslate"><span class="pre">Timeline</span></code>.</p></li> +</ul> +</li> +<li><p>Implemented a custom evaluator for the <code class="docutils literal notranslate"><span class="pre">Timeline</span></code>’s properties.</p> +<ul class="simple"> +<li><p>A custom evaluator uses a user-provided function that takes time as input and evaluates the property at that time. This feature is yet to be discussed more in today’s meeting.</p></li> +</ul> +</li> +<li><p>Fixed camera rotation and the view-up issue when interacting with the scene.</p></li> +</ul> +</section> +<section id="what-is-coming-up-next-week"> +<h2>What is coming up next week?</h2> +<ul class="simple"> +<li><p>Make a tutorial on how to implement a new custom Interpolator to work with the <code class="docutils literal notranslate"><span class="pre">Timeline</span></code>.</p></li> +<li><p>Add motion path visualization feature for both position and color properties.</p></li> +<li><p>Add custom evaluation functions directly, without using the <code class="docutils literal notranslate"><span class="pre">CustomInterpolator</span></code>.</p></li> +<li><p>Implement an already existing complex interpolator using closures instead of classes.</p></li> +</ul> +</section> +<section id="did-you-get-stuck-anywhere"> +<h2>Did you get stuck anywhere?</h2> +<p>I didn’t get stuck this week.</p> +</section> +</section> + + + Improved the PlaybackPanel by adding speed control and the ability to loop the animation. Also, fixed the lagging issue of play and pause buttons and composed them into a single play/pause button. + + 2022-07-25T00:00:00-04:00 + + diff --git a/v0.10.x/blog/author/praneeth-shetty.html b/v0.10.x/blog/author/praneeth-shetty.html new file mode 100644 index 000000000..13030e48e --- /dev/null +++ b/v0.10.x/blog/author/praneeth-shetty.html @@ -0,0 +1,2745 @@ + + + + + + + Posts by Praneeth Shetty — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +
+

+ + Posts by + + Praneeth Shetty + +

+ + +
+

+ Google Summer of Code Final Work Product +

+
    +
  • + + + 25 August 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Name: Praneeth Shetty

+

+ +

Read more ...

+
+
+ +
+

+ Week 12: FileDialog Quest Begins! +

+
    +
  • + + + 19 August 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

During this week, I initiated my work on the FileDialog PR, which had been started by Soham. The initial version of the FileDialog can be found at #294. To start, I focused on rebasing the PR. Since this PR was based on an older version, there were some updates to the overall UI structure that needed to be addressed for compatibility. While handling this, I identified a set of issues that I documented in the current PR #832. These mainly revolved around:

+

+ +

Read more ...

+
+
+ +
+

+ Week 11: Bye Bye SpinBox +

+
    +
  • + + + 12 August 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Building upon the progress of the previous week, a major milestone was reached with the merging of PR #830. This PR added essential “getters” and “setters” for the new features of TextBlock, making it easier to handle changes. This, in turn, facilitated the integration of SpinBoxUI with the updated TextBlock.

+

+ +

Read more ...

+
+
+ +
+

+ Week 10: Its time for a Spin-Box! +

+
    +
  • + + + 05 August 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week, my focus shifted to the SpinBoxUI after wrapping up work on TextBlock2D. SpinBoxUI is a component that allows users to select a value by spinning through a range. To ensure a smooth transition, I made adjustments in SpinBoxUI to align it with the recent updates in TextBlock2D. To make things even clearer and more user-friendly, I initiated a continuous code improvement process. I introduced setters and getters that enable easier customization of TextBlock2D’s new features, such as auto_font_scale and dynamic_bbox. These tools simplify the process of adjusting these settings, and you can see the ongoing changes in pull request #830.

+

+ +

Read more ...

+
+
+ +
+

+ Week 9: TextBlock2D is Finally Merged! +

+
    +
  • + + + 29 July 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Continuing from the previous week, it seemed like we were almost done with the TextBlock2D, but there remained a final task of addressing conflicting issues. Being a core part of the UI, TextBlock2D had a few compatibility problems with certain other UI elements.

+

+ +

Read more ...

+
+
+ +
+

+ Week 8: Another week with TextBlockUI +

+
    +
  • + + + 22 July 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week, I delved deeper into the TextBlock2D Bounding Box PR to address the challenges with tests and offsetting issues. In a pair programming session with my mentor, we discovered that the offsetting background problem stemmed from the dynamic nature of the bounding box. The issue arose when the RingSlider2D component began with an initial text size larger than the current text, which changed as the value was adjusted between 0-100%. This resulted in problems with offsetting and shrinking the bounding box. To resolve this, we decided to make the dynamic bounding box an optional feature.

+

+ +

Read more ...

+
+
+ +
+

+ Week 7: Sowing the seeds for TreeUI +

+
    +
  • + + + 15 July 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week, I focused on completing the TextBlock2D Bounding Box feature. However, the tests were failing due to automatic background resizing based on content and improper text actor alignment during setup. I encountered difficulties while positioning the text, which caused the text to appear offset and led to test failures.

+

+ +

Read more ...

+
+
+ +
+

+ Week 6: BoundingBox for TextBlock2D! +

+
    +
  • + + + 08 July 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week, I worked on improving the TextBlock2D component in the UI system. I started from scratch to address alignment and scaling issues. When resizing the TextBlock2D, the text alignment and justification with the background rectangle were inconsistent. To resolve this, I introduced a new “boundingbox” property that calculates the text bounding box based on its content. Additionally, I separated the scaling mode from the resizing action with the new “auto_font_scale” property, enabling automatic font scaling according to the bounding box. This will provide better alignment, justified text, and smoother font scaling for the TextBlock2D component. Try it out at PR #803.

+

+ +

Read more ...

+
+
+ +
+

+ Week 5: Trying out PRs and Planning Ahead +

+
    +
  • + + + 01 July 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Due to ongoing exams, my productivity was limited this week. However, I managed to find some time to explore and review a few PRs submitted by contributors:

+

+ +

Read more ...

+
+
+ +
+

+ Week 4: Exam Preparations and Reviewing +

+
    +
  • + + + 24 June 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week, amidst end-semester exams, I managed to accomplish a few notable tasks. Let’s dive into the highlights:

+

+ +

Read more ...

+
+
+ +
+

+ Week 3: Resolving Combobox Icon Flaw and TextBox Justification +

+
    +
  • + + + 17 June 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week, I tackled the ComboBox2D icon flaw, which was addressed using Pull Request (PR) #576. The problem arose when we added a ComboBox2D to the TabUI. The TabUI would propagate the set_visibility = true for all its child elements, causing the combobox to appear on the screen without the icon change. To fix this issue, PR #768 updated the set_visibility method of the UI class, ensuring that the icon change was applied correctly.

+

+ +

Read more ...

+
+
+ +
+

+ Week 2: Tackling Text Justification and Icon Flaw Issues +

+
    +
  • + + + 11 June 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week, I continued tweaking the text justification PR #790 and encountered a new issue when combining both justification and vertical_justification. The problem arose because the vertical_justification did not take into account the applied justification, resulting in unexpected behavior. I focused on resolving this issue by ensuring that both justifications work together correctly. Additionally, during the weekly meeting, we discussed the problem and decided to introduce new properties such as boundaries and padding to enhance the functionality of the text justification feature.

+

+ +

Read more ...

+
+
+ +
+

+ Week 1: Working with SpinBox and TextBox Enhancements +

+
    +
  • + + + 03 June 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week, my focus was on reviewing pull requests (PRs) and issues related to the user interface (UI) of the project. I meticulously went through each PR and issue, identifying those specifically associated with UI improvements. To streamline the process, I categorized them accordingly under the UI category. One of the key tasks was PR #499, which involved the implementation of SpinBoxUI. After rebasing the PR, I identified an alignment issue with the textbox component.

+

+ +

Read more ...

+
+
+ +
+

+ Week 0: Community Bounding Period +

+
    +
  • + + + 02 June 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hello All!

+

+ +

Read more ...

+
+
+ +
+

+ Google Summer of Code Final Work Product +

+
    +
  • + + + 24 January 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Name: Praneeth Shetty

+

+ +

Read more ...

+
+
+ +
+

+ Week 16 - Working with Rotations! +

+
    +
  • + + + 21 September 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Last week my mentors noticed that each DrawShape has its individual rotation_slider which increases redundancy and complexity in setting its visibility on and off. Instead, they suggested moving the rotation_slider to DrawPanel and keeping a common slider for all the shapes.

+

+ +

Read more ...

+
+
+ +
+

+ Week 15 - Highlighting DrawShapes +

+
    +
  • + + + 14 September 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week I started with highlighting the shapes. As discussed earlier, I had two ways, but while implementing them, I found out both ways aren’t that good to continue with. +The first way in which we thought of creating the scaled shapes in the background had an issue with the stacking. The border(blue rectangle) and the shape(grey rectangle) both seem to look like different shapes just grouped together as shown below.

+

+ +

Read more ...

+
+
+ +
+

+ Week 14 - Updating DrawPanel architecture +

+
    +
  • + + + 07 September 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week I continued updating the DrawShape and DrawPanel.

+

+ +

Read more ...

+
+
+ +
+

+ Week 13 - Separating tests and fixing bugs +

+
    +
  • + + + 31 August 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week I managed to fix the translation issue in PR #653. This was happening because of the calculation error while repositioning the shapes. Now it works as intended.

+

+ +

Read more ...

+
+
+ +
+

+ Week 12 - Fixing translating issues and updating tests +

+
    +
  • + + + 24 August 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

I started with updating the tests for PR #623 as some of the tests weren’t covering all the aspects in the code. +Previously I was just creating the DrawShape and adding it to the scene but now I had to analyze the scene to see whether they were properly added or not.

+

+ +

Read more ...

+
+
+ +
+

+ Week 11 - Creating a base for Freehand Drawing +

+
    +
  • + + + 17 August 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week I tried to imitate the working of vtkImageTracer. Previously, I had created a small prototype for freehand drawing by adding points at the mouse position (which you can check out here). As mentioned, there were some drawback of this method. +So to overcome these issues, I tried combining both methods. Considering points using the previous method and instead of adding points I tried creating lines between them which looks promising. Below you can see a demo.

+

+ +

Read more ...

+
+
+ +
+

+ Week 10 - Understanding Codes and Playing with Animation +

+
    +
  • + + + 10 August 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

I started working on the PR #645 created last week and tested a few more corner cases such as What happens if the maximum value is exceeded?? What if we give a value less than the minimum value range?? +Most of these worked as intended.

+

+ +

Read more ...

+
+
+ +
+

+ Week 9 - Grouping and Transforming Shapes +

+
    +
  • + + + 03 August 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

I started this week by creating a quick PR #645 for the UI sliders. The sliders raised ZeroDivsionError when the min and max values were the same. To solve this, I handled the case where the value_range becomes zero and then manually set the handle position to zero.

+

+ +

Read more ...

+
+
+ +
+

+ Week 8 - Working on the polyline feature +

+
    +
  • + + + 27 July 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week I started working on the polyline feature. After a lot of investigating and trying out different things, I found a way to call the dragging event manually without any prior click event. VTK actually captures the mouse movement using the MouseMoveEvent. This event is then modified by FURY to only be called after the click event. So I added a new callback to track the mouse movement and set the current canvas as an active prop because it is required to capture the drag event happening on it.

+

+ +

Read more ...

+
+
+ +
+

+ Week 7 - Working on Rotation PR and Trying Freehand Drawing +

+
    +
  • + + + 20 July 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

I continued PR #623 and fixed the displacement of the shape from its original position when applying rotation. This was happening because most of the calculations resulted in float values, but as the pixel position were integers we had to explicitly convert these values into int. This conversion rounded off the values and as we call this function continuously, each time the round-off would happen, the shape would get displaced.

+

+ +

Read more ...

+
+
+ +
+

+ Week 6 - Supporting Rotation of the Shapes from the Center +

+
    +
  • + + + 13 July 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week I started implementing a new feature to rotate the shapes from the center using RingSlider2D. I already had a rotate function that rotates the shape around its pivot vertex, so I updated it to support rotation from the center.

+

+ +

Read more ...

+
+
+ +
+

+ Week 5 - Working on new features +

+
    +
  • + + + 06 July 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week I tried to create a base for some upcoming new features. +The first thing I updated was the Properties panel which I prototyped in Week 3. +So previously, it was just displaying the properties but now after the update, it is able to modify the properties(such as color, position, and rotation) too. This was a quick change to test the callbacks.

+

+ +

Read more ...

+
+
+ +
+

+ Week 4 - Fixing the Clamping Issue +

+
    +
  • + + + 29 June 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Phew!! This week was a tedious week for me as parallelly my End-Sem exams also started. So as usual I started from where I left off last week, The Clamping Issue. As per the discussion with the mentors, we decided to use the AABB bounding box method to calculate the bounding box around the shape and then reposition or transform respectively, as now we had a fixed reference point. So after doing some calculations with the mouse positions and the bounding box points at last, I was able to clamp all the shapes successfully.

+

+ +

Read more ...

+
+
+ +
+

+ Week 3 - Dealing with Problems +

+
    +
  • + + + 22 June 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week was full of researching, playing around with things, prototyping ideas, etc. +I started with last week’s clamping issue and managed to solve this issue while drawing shapes by clipping the mouse position according to canvas size, but it didn’t solve the problem with translating these shapes. I tried solving this using various approaches, but if one thing would get fixed, other things would raise a new error.

+

+ +

Read more ...

+
+
+ +
+

+ Week 2 - Improving DrawPanel UI +

+
    +
  • + + + 15 June 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week I had to refactor and make my code cleaner along with some bug fixing, I started by adding tests and tutorials so that my changes could be tested by everyone. Then I separated the mode for selection so that it would be easy to select an individual element and work along with it. Once the selection mode was complete I started with the deletion of the elements.

+

+ +

Read more ...

+
+
+ +
+

+ Week 1 - Laying the Foundation of DrawPanel UI +

+
    +
  • + + + 08 June 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week we started with our first technical meeting in which the weekly tasks were assigned. So I had to start with some background or canvas and draw a line using mouse clicks.

+

+ +

Read more ...

+
+
+ +
+

+ Pre-GSoC Journey +

+
    +
  • + + + 25 May 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hello Guys!! I am Praneeth Shetty, currently pursuing Bachelor of Engineering in Computer Engineering, and here is my journey from where I started to the selection into GSoC22.

+

+ +

Read more ...

+
+
+ + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/blog/author/praneeth-shetty/atom.xml b/v0.10.x/blog/author/praneeth-shetty/atom.xml new file mode 100644 index 000000000..363ade9eb --- /dev/null +++ b/v0.10.x/blog/author/praneeth-shetty/atom.xml @@ -0,0 +1,686 @@ + + + https://fury.gl/ + Blog - Posts by Praneeth Shetty + 2024-02-29T15:43:57.483503+00:00 + + + ABlog + + https://fury.gl/posts/2023/2023-08-25-final-report-praneeth.html + Google Summer of Code Final Work Product + 2023-08-25T00:00:00-04:00 + + Praneeth Shetty + + <a class="reference external image-reference" href="https://summerofcode.withgoogle.com/programs/2023/projects/BqfBWfwS"><img alt="https://developers.google.com/open-source/gsoc/resources/downloads/GSoC-logo-horizontal.svg" class="align-center" height="50" src="https://developers.google.com/open-source/gsoc/resources/downloads/GSoC-logo-horizontal.svg" /></a> +<a class="reference external image-reference" href="https://summerofcode.withgoogle.com/programs/2023/organizations/python-software-foundation"><img alt="https://www.python.org/static/community_logos/python-logo.png" src="https://www.python.org/static/community_logos/python-logo.png" style="width: 40%;" /></a> +<a class="reference external image-reference" href="https://fury.gl/latest/index.html"><img alt="https://python-gsoc.org/logos/FURY.png" src="https://python-gsoc.org/logos/FURY.png" style="width: 25%;" /></a> +<section id="google-summer-of-code-final-work-product"> + +<ul class="simple"> +<li><p><strong>Name:</strong> Praneeth Shetty</p></li> +<li><p><strong>Organisation:</strong> Python Software Foundation</p></li> +<li><p><strong>Sub-Organisation:</strong> FURY</p></li> +<li><p><strong>Project:</strong> <a class="reference external" href="https://github.com/fury-gl/fury/wiki/Google-Summer-of-Code-2023-(GSOC2023)#project-5-update-user-interface-widget--explore-new-ui-framework">FURY - Update user interface widget + Explore new UI Framework</a></p></li> +</ul> +<section id="proposed-objectives"> +<h2>Proposed Objectives</h2> +<ul class="simple"> +<li><p>SpinBoxUI</p></li> +<li><p>Scrollbar as Independent Element</p></li> +<li><p>FileDialog</p></li> +<li><p>TreeUI</p></li> +<li><p>AccordionUI</p></li> +<li><p>ColorPickerUI</p></li> +<li><dl class="simple"> +<dt>Stretch Goals:</dt><dd><ul> +<li><p>Exploring new UI Framework</p></li> +<li><p>Implementing Borders for UI elements</p></li> +</ul> +</dd> +</dl> +</li> +</ul> +</section> +<section id="objectives-completed"> +<h2>Objectives Completed</h2> +<ul> +<li><dl> +<dt><strong>SpinBoxUI:</strong></dt><dd><p>The <code class="docutils literal notranslate"><span class="pre">SpinBoxUI</span></code> element is essential for user interfaces as it allows users to pick a numeric value from a set range. While we had an active pull request (PR) to add this element, updates in the main code caused conflicts and required further changes for added features. At one point, we noticed that text alignment wasn’t centered properly within the box due to a flaw. To fix this, we began a PR to adjust the alignment, but it turned into a larger refactoring of the <code class="docutils literal notranslate"><span class="pre">TextBlock2D</span></code>, a core component connected to various parts. This was a complex task that needed careful handling. After sorting out the <code class="docutils literal notranslate"><span class="pre">TextBlock2D</span></code>, we returned to the <code class="docutils literal notranslate"><span class="pre">SpinBoxUI</span></code> and made a few tweaks. Once we were confident with the changes, the PR was successfully merged after thorough review and testing.</p> +<p><strong>Pull Requests:</strong></p> +</dd> +</dl> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 50)</p> +<p>Definition list ends without a blank line; unexpected unindent.</p> +</aside> +<ul> +<li><p><strong>SpinBoxUI (Merged)</strong> - <a class="github reference external" href="https://github.com/fury-gl/fury/pull/499">fury-gl/fury#499</a></p> +<blockquote> +<div><img alt="SpinBoxUI" class="align-center" src="https://user-images.githubusercontent.com/64432063/263165327-c0b19cdc-9ebd-433a-8ff1-99e706a76508.gif" style="height: 500px;" /> +</div></blockquote> +</li> +</ul> +</li> +<li><dl> +<dt><strong>`TextBlock2D` Refactoring:</strong></dt><dd><p>This was a significant aspect of the GSoC period and occupied a substantial portion of the timeline. The process began when we observed misaligned text in the <code class="docutils literal notranslate"><span class="pre">SpinBoxUI</span></code>, as previously discussed. The root cause of the alignment issue was the mispositioning of the text actor concerning the background actor. The text actor’s independent repositioning based on justification conflicted with the static position of the background actor, leading to the alignment problem.</p> +<p>To address this, the initial focus was on resolving the justification issue. However, as the work progressed, we recognized that solely adjusting justification would not suffice. The alignment was inherently linked to the UI’s size, which was currently retrieved only when a valid scene was present. This approach lacked scalability and efficiency, as it constrained size retrieval to scene availability.</p> +<p>To overcome these challenges, we devised a solution involving the creation of a bounding box around the <code class="docutils literal notranslate"><span class="pre">TextBlock2D</span></code>. This bounding box would encapsulate the size information, enabling proper text alignment. This endeavor spanned several weeks of development, culminating in a finalized solution that underwent rigorous testing before being merged.</p> +<p>As a result of this refactoring effort, the <code class="docutils literal notranslate"><span class="pre">TextBlock2D</span></code> now offers three distinct modes:</p> +<ol class="arabic simple"> +<li><p><strong>Fully Static Background:</strong> This mode requires background setup during initialization.</p></li> +<li><p><strong>Dynamic Background:</strong> The background dynamically scales based on the text content.</p></li> +<li><p><strong>Auto Font Scale Mode:</strong> The font within the background box automatically scales to fill the available space.</p></li> +</ol> +<p>An issue has been identified with <code class="docutils literal notranslate"><span class="pre">TextBlock2D</span></code> where its text actor aligns with the top boundary of the background actor, especially noticeable with letters like “g,” “y,” and “j”. These letters extend beyond the baseline of standard alphabets, causing the text box to shift upwards.</p> +<p>However, resolving this matter is complex. Adjusting the text’s position might lead to it touching the bottom boundary, especially in font scale mode, resulting in unexpected positioning and transformations. To address this, the plan is to defer discussions about this matter until after GSoC, allowing for thorough consideration and solutions.</p> +<p>For more detailed insights into the individual steps and nuances of this process, you can refer to the comprehensive weekly blog post provided below. It delves into the entire journey of this <code class="docutils literal notranslate"><span class="pre">TextBlock2D</span></code> refactoring effort.</p> +<p><strong>Pull Requests:</strong></p> +</dd> +</dl> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 79)</p> +<p>Definition list ends without a blank line; unexpected unindent.</p> +</aside> +<ul> +<li><p><strong>Fixing Justification Issue - 1st Draft (Closed)</strong> - <a class="github reference external" href="https://github.com/fury-gl/fury/pull/790">fury-gl/fury#790</a></p></li> +<li><p><strong>Adding BoundingBox and fixing Justificaiton (Merged)</strong> - <a class="github reference external" href="https://github.com/fury-gl/fury/pull/803">fury-gl/fury#803</a></p></li> +<li><p><strong>Adding getters and setter for properties (Merged)</strong> - <a class="github reference external" href="https://github.com/fury-gl/fury/pull/830">fury-gl/fury#830</a></p></li> +<li><p><strong>Text Offset PR (Closed)</strong> - <a class="github reference external" href="https://github.com/fury-gl/fury/pull/837">fury-gl/fury#837</a></p> +<img alt="TextBlock2D Feature Demo" class="align-center" src="https://user-images.githubusercontent.com/64432063/258603191-d540105a-0612-450e-8ae3-ca8aa87916e6.gif" style="height: 500px;" /> +<img alt="TextBlock2D All Justification" class="align-center" src="https://github-production-user-asset-6210df.s3.amazonaws.com/64432063/254652569-94212105-7259-48da-8fdc-41ee987bda84.png" style="height: 500px;" /> +</li> +</ul> +</li> +<li><dl> +<dt><strong>ScrollbarUI as Independent Element:</strong></dt><dd><p>We initially planned to make the scrollbar independent based on PR <a class="reference external" href="https://github.com/fury-gl/fury/pull/16">#16</a>. The main goal was to avoid redundancy by not rewriting the scrollbar code for each element that requires it, such as the <code class="docutils literal notranslate"><span class="pre">FileMenu2D</span></code>. However, upon further analysis, we realized that elements like the <code class="docutils literal notranslate"><span class="pre">FileMenu2D</span></code> and others utilize the <code class="docutils literal notranslate"><span class="pre">Listbox2D</span></code>, which already includes an integrated scrollbar. We also examined other UI libraries and found that they also have independent scrollbars but lack a proper use case. Typically, display containers like <code class="docutils literal notranslate"><span class="pre">Listbox2D</span></code> are directly used instead of utilizing an independent scrollbar.</p> +<p>Based on these findings, we have decided to close all related issues and pull requests for now. If the need arises in the future, we can revisit this topic.</p> +<p><strong>Topic:</strong> - <a class="github reference external" href="https://github.com/fury-gl/fury/discussions/816">fury-gl/fury#816</a></p> +</dd> +</dl> +</li> +</ul> +</section> +<section id="other-objectives"> +<h2>Other Objectives</h2> +<ul> +<li><dl> +<dt><strong>Reviewing &amp; Merging:</strong></dt><dd><p>In this phase, my focus was not on specific coding but rather on facilitating the completion of ongoing PRs. Here are two instances where I played a role:</p> +<ol class="arabic simple"> +<li><p><strong>CardUI PR:</strong> +I assisted with the <code class="docutils literal notranslate"><span class="pre">CardUI</span></code> PR by aiding in the rebase process and reviewing the changes. The CardUI is a simple UI element consisting of an image and a description, designed to function like a flash card. I worked closely with my mentor to ensure a smooth rebase and review process.</p></li> +<li><p><strong>ComboBox Issue:</strong> +There was an issue with the <code class="docutils literal notranslate"><span class="pre">ComboBox2D</span></code> functionality, where adding it to a <code class="docutils literal notranslate"><span class="pre">TabUI</span></code> caused all elements to open simultaneously, which shouldn’t be the case. I tested various PRs addressing this problem and identified a suitable solution. I then helped the lead in reviewing the PR that fixed the issue, which was successfully merged.</p></li> +</ol> +<p><strong>Pull Requests:</strong></p> +</dd> +</dl> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 116)</p> +<p>Definition list ends without a blank line; unexpected unindent.</p> +</aside> +<ul> +<li><p><strong>CardUI (Merged)</strong> - <a class="github reference external" href="https://github.com/fury-gl/fury/pull/398">fury-gl/fury#398</a></p></li> +<li><p><strong>ComboBox Flaw (Merged)</strong> - <a class="github reference external" href="https://github.com/fury-gl/fury/pull/768">fury-gl/fury#768</a></p> +<img alt="CardUI" class="align-center" src="https://user-images.githubusercontent.com/54466356/112532305-b090ef80-8dce-11eb-90a0-8d06eed55993.png" style="height: 500px;" /> +</li> +</ul> +</li> +<li><dl> +<dt><strong>Updating Broken Website Links:</strong></dt><dd><p>I addressed an issue with malfunctioning links in the Scientific Section of the website. The problem emerged from alterations introduced in PR <a class="reference external" href="https://github.com/fury-gl/fury/pull/769">#769</a>. These changes consolidated demos and examples into a unified “auto_examples” folder, and a toml file was utilized to retrieve this data and construct examples. However, this led to challenges with the paths employed in website generation. My responsibility was to rectify these links, ensuring they accurately direct users to the intended content.</p> +<p><strong>Pull Requests:</strong></p> +</dd> +</dl> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 130)</p> +<p>Definition list ends without a blank line; unexpected unindent.</p> +</aside> +<ul class="simple"> +<li><p><strong>Updating Broken Links (Merged)</strong> - <a class="github reference external" href="https://github.com/fury-gl/fury/pull/820">fury-gl/fury#820</a></p></li> +</ul> +</li> +</ul> +</section> +<section id="objectives-in-progress"> +<h2>Objectives in Progress</h2> +<ul> +<li><dl> +<dt><strong>FileDialogUI:</strong></dt><dd><p>An existing <code class="docutils literal notranslate"><span class="pre">FileDialog</span></code> PR by Soham (<a class="reference external" href="https://github.com/fury-gl/fury/pull/294">#294</a>) was worked upon. The primary task was to rebase the PR to match the current UI structure, resolving compatibility concerns with the older base. In PR <a class="reference external" href="https://github.com/fury-gl/fury/pull/832">#832</a>, we detailed issues encompassing resizing <code class="docutils literal notranslate"><span class="pre">FileDialog</span></code> and components, addressing text overflow, fixing <code class="docutils literal notranslate"><span class="pre">ZeroDivisionError</span></code>, and correcting <code class="docutils literal notranslate"><span class="pre">ListBox2D</span></code> item positioning. The PR is complete with comprehensive testing and documentation. Presently, it’s undergoing review, and upon approval, it will be prepared for integration.</p> +<p><strong>Pull Requests:</strong></p> +</dd> +</dl> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 140)</p> +<p>Definition list ends without a blank line; unexpected unindent.</p> +</aside> +<ul> +<li><p><strong>Soham’s FileDialog (Closed)</strong> - <a class="github reference external" href="https://github.com/fury-gl/fury/pull/294">fury-gl/fury#294</a></p></li> +<li><p><strong>FileDialogUI (Under Review)</strong> - <a class="github reference external" href="https://github.com/fury-gl/fury/pull/832">fury-gl/fury#832</a></p> +<img alt="FileDialogUI" class="align-center" src="https://user-images.githubusercontent.com/64432063/263189092-6b0891d5-f0ef-4185-8b17-c7104f1a7d60.gif" style="height: 500px;" /> +</li> +</ul> +</li> +<li><dl> +<dt><strong>TreeUI:</strong></dt><dd><p>Continuing Antriksh’s initial PR for <code class="docutils literal notranslate"><span class="pre">TreeUI</span></code> posed some challenges. Antriksh had set the foundation, and I picked up from there. The main issue was with the visibility of TreeUI due to updates in the <code class="docutils literal notranslate"><span class="pre">set_visibility</span></code> method of <code class="docutils literal notranslate"><span class="pre">Panel2D</span></code>. These updates affected how <code class="docutils literal notranslate"><span class="pre">TreeUI</span></code> was displayed, and after investigating the actors involved, it was clear that the visibility features had changed. This took some time to figure out, and I had a helpful pair programming session with my mentor, Serge, to narrow down the problem. Now, I’ve updated the code to address this issue. However, I’m still a bit cautious about potential future problems. The PR is now ready for review.</p> +<p><strong>Pull Requests:</strong></p> +</dd> +</dl> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 154)</p> +<p>Definition list ends without a blank line; unexpected unindent.</p> +</aside> +<ul> +<li><p><strong>TreeUI (In Progress)</strong> - <a class="github reference external" href="https://github.com/fury-gl/fury/pull/821">fury-gl/fury#821</a></p> +<img alt="TreeUI" class="align-center" src="https://user-images.githubusercontent.com/64432063/263237308-70e77ba0-1ce8-449e-a79c-d5e0fbb58b45.gif" style="height: 500px;" /> +</li> +</ul> +</li> +</ul> +</section> +<section id="gsoc-weekly-blogs"> +<h2>GSoC Weekly Blogs</h2> +<ul class="simple"> +<li><p>My blog posts can be found at <a class="reference external" href="https://fury.gl/latest/blog/author/praneeth-shetty.html">FURY website</a> +and <a class="reference external" href="https://blogs.python-gsoc.org/en/ganimtron_10s-blog-copy-2/">Python GSoC blog</a>.</p></li> +</ul> +</section> +<section id="timeline"> +<h2>Timeline</h2> +<table class="table"> +<colgroup> +<col style="width: 40.0%" /> +<col style="width: 40.0%" /> +<col style="width: 20.0%" /> +</colgroup> +<thead> +<tr class="row-odd"><th class="head"><p>Date</p></th> +<th class="head"><p>Description</p></th> +<th class="head"><p>Blog Post Link</p></th> +</tr> +</thead> +<tbody> +<tr class="row-even"><td><p>Week 0 (27-05-2023)</p></td> +<td><p>Community Bounding Period</p></td> +<td><p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-06-02-week-0-praneeth.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/ganimtron_10s-blog-copy-2/gsoc-2023-community-bonding-period/">Python</a></p></td> +</tr> +<tr class="row-odd"><td><p>Week 1 (03-06-2023)</p></td> +<td><p>Working with SpinBox and TextBox Enhancements</p></td> +<td><aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id5">backlink</a></em></p> +<p>Duplicate explicit target name: “fury”.</p> +</aside> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id6">backlink</a></em></p> +<p>Duplicate explicit target name: “python”.</p> +</aside> +<p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-06-03-week-1-praneeth.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/ganimtron_10s-blog-copy-2/week-1-working-with-spinbox-and-textbox-enhancements/">Python</a></p> +</td> +</tr> +<tr class="row-even"><td><p>Week 2 (10-06-2023)</p></td> +<td><p>Tackling Text Justification and Icon Flaw Issues</p></td> +<td><aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id7">backlink</a></em></p> +<p>Duplicate explicit target name: “fury”.</p> +</aside> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id8">backlink</a></em></p> +<p>Duplicate explicit target name: “python”.</p> +</aside> +<p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-06-11-week-2-praneeth.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/ganimtron_10s-blog-copy-2/week-2-tackling-text-justification-and-icon-flaw-issues/">Python</a></p> +</td> +</tr> +<tr class="row-odd"><td><p>Week 3 (17-06-2023)</p></td> +<td><p>Resolving Combobox Icon Flaw and TextBox Justification</p></td> +<td><aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id9">backlink</a></em></p> +<p>Duplicate explicit target name: “fury”.</p> +</aside> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id10">backlink</a></em></p> +<p>Duplicate explicit target name: “python”.</p> +</aside> +<p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-06-17-week-3-praneeth.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/ganimtron_10s-blog-copy-2/week-3-resolving-combobox-icon-flaw-and-textbox-justification/">Python</a></p> +</td> +</tr> +<tr class="row-even"><td><p>Week 4 (24-06-2023)</p></td> +<td><p>Exam Preparations and Reviewing</p></td> +<td><aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id11">backlink</a></em></p> +<p>Duplicate explicit target name: “fury”.</p> +</aside> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id12">backlink</a></em></p> +<p>Duplicate explicit target name: “python”.</p> +</aside> +<p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-06-24-week-4-praneeth.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/ganimtron_10s-blog-copy-2/week-4-exam-preparations-and-reviewing/">Python</a></p> +</td> +</tr> +<tr class="row-odd"><td><p>Week 5 (01-07-2023)</p></td> +<td><p>Trying out PRs and Planning Ahead</p></td> +<td><aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id13">backlink</a></em></p> +<p>Duplicate explicit target name: “fury”.</p> +</aside> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id14">backlink</a></em></p> +<p>Duplicate explicit target name: “python”.</p> +</aside> +<p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-07-01-week-5-praneeth.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/ganimtron_10s-blog-copy-2/week-5-testing-out-prs-and-planning-ahead/">Python</a></p> +</td> +</tr> +<tr class="row-even"><td><p>Week 6 (08-07-2023)</p></td> +<td><p>BoundingBox for TextBlock2D!</p></td> +<td><aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id15">backlink</a></em></p> +<p>Duplicate explicit target name: “fury”.</p> +</aside> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id16">backlink</a></em></p> +<p>Duplicate explicit target name: “python”.</p> +</aside> +<p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-07-08-week-6-praneeth.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/ganimtron_10s-blog-copy-2/week-6-boundingbox-for-textblock2d/">Python</a></p> +</td> +</tr> +<tr class="row-odd"><td><p>Week 7 (15-07-2023)</p></td> +<td><p>Sowing the seeds for TreeUI</p></td> +<td><aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id17">backlink</a></em></p> +<p>Duplicate explicit target name: “fury”.</p> +</aside> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id18">backlink</a></em></p> +<p>Duplicate explicit target name: “python”.</p> +</aside> +<p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-07-15-week-7-praneeth.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/ganimtron_10s-blog-copy-2/week-7-sowing-the-seeds-for-treeui/">Python</a></p> +</td> +</tr> +<tr class="row-even"><td><p>Week 8 (22-07-2023)</p></td> +<td><p>Another week with TextBlockUI</p></td> +<td><aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id19">backlink</a></em></p> +<p>Duplicate explicit target name: “fury”.</p> +</aside> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id20">backlink</a></em></p> +<p>Duplicate explicit target name: “python”.</p> +</aside> +<p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-07-22-week-8-praneeth.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/ganimtron_10s-blog-copy-2/week-8-another-week-with-textblockui/">Python</a></p> +</td> +</tr> +<tr class="row-odd"><td><p>Week 9 (29-07-2023)</p></td> +<td><p>TextBlock2D is Finally Merged!</p></td> +<td><aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id21">backlink</a></em></p> +<p>Duplicate explicit target name: “fury”.</p> +</aside> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id22">backlink</a></em></p> +<p>Duplicate explicit target name: “python”.</p> +</aside> +<p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-07-29-week-9-praneeth.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/ganimtron_10s-blog-copy-2/week-9-textblock2d-is-finally-merged/">Python</a></p> +</td> +</tr> +<tr class="row-even"><td><p>Week 10 (05-08-2023)</p></td> +<td><p>Its time for a Spin-Box!</p></td> +<td><aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id23">backlink</a></em></p> +<p>Duplicate explicit target name: “fury”.</p> +</aside> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id24">backlink</a></em></p> +<p>Duplicate explicit target name: “python”.</p> +</aside> +<p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-08-05-week-10-praneeth.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/ganimtron_10s-blog-copy-2/week-10-its-time-for-a-spin-box/">Python</a></p> +</td> +</tr> +<tr class="row-odd"><td><p>Week 11 (12-08-2023)</p></td> +<td><p>Bye Bye SpinBox</p></td> +<td><aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id25">backlink</a></em></p> +<p>Duplicate explicit target name: “fury”.</p> +</aside> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id26">backlink</a></em></p> +<p>Duplicate explicit target name: “python”.</p> +</aside> +<p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-08-12-week-11-praneeth.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/ganimtron_10s-blog-copy-2/week-11-bye-bye-spinbox/">Python</a></p> +</td> +</tr> +<tr class="row-even"><td><p>Week 12 (19-08-2023)</p></td> +<td><p>FileDialog Quest Begins!</p></td> +<td><aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id27">backlink</a></em></p> +<p>Duplicate explicit target name: “fury”.</p> +</aside> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id28">backlink</a></em></p> +<p>Duplicate explicit target name: “python”.</p> +</aside> +<p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-08-19-week-12-praneeth.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/ganimtron_10s-blog-copy-2/week-12-filedialog-quest-begins/">Python</a></p> +</td> +</tr> +</tbody> +</table> +</section> +</section> + + + Name: Praneeth Shetty + + 2023-08-25T00:00:00-04:00 + + + https://fury.gl/posts/2023/2023-08-19-week-12-praneeth.html + Week 12: FileDialog Quest Begins! + 2023-08-19T00:00:00-04:00 + + Praneeth Shetty + + <section id="week-12-filedialog-quest-begins"> + +<section id="what-did-you-do-this-week"> +<h2>What did you do this week?</h2> +<p>During this week, I initiated my work on the <code class="docutils literal notranslate"><span class="pre">FileDialog</span></code> PR, which had been started by Soham. The initial version of the <code class="docutils literal notranslate"><span class="pre">FileDialog</span></code> can be found at <a class="reference external" href="https://github.com/fury-gl/fury/pull/294">#294</a>. To start, I focused on rebasing the PR. Since this PR was based on an older version, there were some updates to the overall UI structure that needed to be addressed for compatibility. While handling this, I identified a set of issues that I documented in the current PR <a class="reference external" href="https://github.com/fury-gl/fury/pull/832">#832</a>. These mainly revolved around:</p> +<ol class="arabic simple"> +<li><p>Resizing <code class="docutils literal notranslate"><span class="pre">FileDialog</span></code> and related components.</p></li> +<li><p>Rectifying the text overflow problem.</p></li> +<li><p>Dealing with a <code class="docutils literal notranslate"><span class="pre">ZeroDivisionError</span></code>.</p></li> +<li><p>Fixing the positioning of items in the <code class="docutils literal notranslate"><span class="pre">ListBox2D</span></code>.</p></li> +</ol> +<p>I systematically approached each of these challenges:</p> +<p><strong>Resizing FileMenu and Related Components:</strong> This was a fairly complex task since it involved intricate dependencies, such as the <code class="docutils literal notranslate"><span class="pre">FileDialog</span></code> relying on the <code class="docutils literal notranslate"><span class="pre">FileMenu</span></code>, which, in turn, was dependent on <code class="docutils literal notranslate"><span class="pre">ListBox2D</span></code> and <code class="docutils literal notranslate"><span class="pre">Panel2D</span></code> resizing. To make the process manageable, I decided to progress incrementally in a separate PR a bit later.</p> +<p><strong>Text Overflow Issue:</strong> The problem with text overflow was rooted in our previous approach, which involved executing these actions only when the <code class="docutils literal notranslate"><span class="pre">TextBlock2D</span></code> had a scene property. Although this approach suited the previous version of <code class="docutils literal notranslate"><span class="pre">TextBlock2D</span></code>, the recent refactoring led to the removal of this property. The scene was previously utilized to determine the text actor’s size. However, we had new methodologies to calculate these sizes, which are detailed in <a class="reference external" href="https://github.com/fury-gl/fury/pull/803">#803</a>.</p> +<img alt="Text Overflow Before" class="align-center" src="https://github.com/fury-gl/fury/assets/64432063/b001f9d3-a5e8-45ad-8605-85df595b5654" /> +<img alt="Text Overflow After" class="align-center" src="https://github.com/fury-gl/fury/assets/64432063/d3c9c3a3-e601-45ab-8975-2b1e98acf1d3" /> +<p><strong>Addressing ZeroDivisionError:</strong> The <code class="docutils literal notranslate"><span class="pre">ZeroDivisionError</span></code> emerged when the total number of values was the same as the number of slots. The issue lay in the separation of these values for calculating the scrollbar’s height parameter. Unfortunately, this calculation error occurred when this would return us zero while updating the scrollbar. To counter this, I implemented a conditional check to ascertain whether the value is zero or not.</p> +<p><strong>Correcting ``ListBox2D`` Item Positioning:</strong> Another challenge I encountered related to the improper positioning of <code class="docutils literal notranslate"><span class="pre">ListBox2D</span></code> item’s background. When a slot was not visible, its background was resized to zero, and visibility was set to off. Consequently, during the calculation of updated positions, the height was considered zero, leading to mispositioning. I resolved this by refraining from resizing and solely toggling visibility, achieving the desired result.</p> +<img alt="ListBox2D mispositioning Before" class="align-center" src="https://github.com/fury-gl/fury/assets/64432063/e2805934-b037-47fd-872c-0b284b298d3c" /> +<img alt="Fixed ListBox2D mispositioning" class="align-center" src="https://github.com/fury-gl/fury/assets/64432063/3bc1aabb-bb79-4e26-817d-a2a2ddd20ea3" /> +</section> +<section id="did-you-get-stuck-anywhere"> +<h2>Did you get stuck anywhere?</h2> +<p>Among the challenges I faced, one notable instance involved addressing the visibility issue in <code class="docutils literal notranslate"><span class="pre">TreeUI</span></code>. Despite my attempts at various solutions, none yielded the desired outcome. The <code class="docutils literal notranslate"><span class="pre">TreeUI</span></code> exhibited either full visibility or no visibility at all. In this situation, I sought guidance from my mentor to find a viable solution.</p> +</section> +<section id="what-is-coming-up-next"> +<h2>What is coming up next?</h2> +<p>The <code class="docutils literal notranslate"><span class="pre">FileDialog</span></code> implementation is nearly finalized, and my plan is to work on any review, feedback or suggestions that might arise. Following this, I will shift my attention towards addressing the <code class="docutils literal notranslate"><span class="pre">TreeUI</span></code>.</p> +</section> +</section> + + + During this week, I initiated my work on the FileDialog PR, which had been started by Soham. The initial version of the FileDialog can be found at #294. To start, I focused on rebasing the PR. Since this PR was based on an older version, there were some updates to the overall UI structure that needed to be addressed for compatibility. While handling this, I identified a set of issues that I documented in the current PR #832. These mainly revolved around: + + 2023-08-19T00:00:00-04:00 + + + https://fury.gl/posts/2023/2023-08-12-week-11-praneeth.html + Week 11: Bye Bye SpinBox + 2023-08-12T00:00:00-04:00 + + Praneeth Shetty + + <section id="week-11-bye-bye-spinbox"> + +<section id="what-did-you-do-this-week"> +<h2>What did you do this week?</h2> +<p>Building upon the progress of the previous week, a major milestone was reached with the merging of PR <a class="reference external" href="https://github.com/fury-gl/fury/pull/830">#830</a>. This PR added essential “getters” and “setters” for the new features of <code class="docutils literal notranslate"><span class="pre">TextBlock</span></code>, making it easier to handle changes. This, in turn, facilitated the integration of <code class="docutils literal notranslate"><span class="pre">SpinBoxUI</span></code> with the updated <code class="docutils literal notranslate"><span class="pre">TextBlock</span></code>.</p> +<p>However, while working on <code class="docutils literal notranslate"><span class="pre">SpinBoxUI</span></code>, a critical issue emerged. As <code class="docutils literal notranslate"><span class="pre">SpinBoxUI</span></code> allows users to input characters and symbols into an editable textbox, it posed a risk of program crashes due to invalid inputs. To counter this, I introduced a validation check to ensure that the input was a valid number. If valid, the input was converted; otherwise, it reverted to the previous value. After thorough testing and review, PR <a class="reference external" href="https://github.com/fury-gl/fury/pull/499">#499</a> was successfully merged.</p> +<img alt="SpinBoxUI" class="align-center" src="https://user-images.githubusercontent.com/64432063/261409747-511e535b-185c-4e70-aaa8-5296c93e5344.gif" style="width: 500px;" /> +<p>Meanwhile, a concern with the textbox’s behavior was identified when <code class="docutils literal notranslate"><span class="pre">SpinBoxUI</span></code> was scaled to a larger size. Specifically, the text occasionally touched the top or bottom boundary, creating an overflow appearance. Although initial solutions were attempted, the complexity of the issue required further consideration. This issue has been documented in more detail in Issue <a class="reference external" href="https://github.com/fury-gl/fury/pull/838">#838</a>, where it is marked as a low-priority item.</p> +<figure class="align-center"> +<img alt="TextBlock2D text positioning issue" src="https://user-images.githubusercontent.com/64432063/133194003-53e2dac6-31e0-444e-b7f1-a9e71545f560.jpeg" /> +</figure> +</section> +<section id="did-you-get-stuck-anywhere"> +<h2>Did you get stuck anywhere?</h2> +<p>The challenge of the week centered around addressing the textbox’s overflow behavior in <code class="docutils literal notranslate"><span class="pre">SpinBoxUI</span></code>.</p> +</section> +<section id="what-is-coming-up-next"> +<h2>What is coming up next?</h2> +<p>Looking ahead, the focus remains on refining the FileDialog component, as the significant progress with <code class="docutils literal notranslate"><span class="pre">TextBlock</span></code> and <code class="docutils literal notranslate"><span class="pre">SpinBoxUI</span></code> prepares us to shift attention to other aspects of development.</p> +</section> +</section> + + + Building upon the progress of the previous week, a major milestone was reached with the merging of PR #830. This PR added essential “getters” and “setters” for the new features of TextBlock, making it easier to handle changes. This, in turn, facilitated the integration of SpinBoxUI with the updated TextBlock. + + 2023-08-12T00:00:00-04:00 + + + https://fury.gl/posts/2023/2023-08-05-week-10-praneeth.html + Week 10: Its time for a Spin-Box! + 2023-08-05T00:00:00-04:00 + + Praneeth Shetty + + <section id="week-10-its-time-for-a-spin-box"> + +<section id="what-did-you-do-this-week"> +<h2>What did you do this week?</h2> +<p>This week, my focus shifted to the <code class="docutils literal notranslate"><span class="pre">SpinBoxUI</span></code> after wrapping up work on <code class="docutils literal notranslate"><span class="pre">TextBlock2D</span></code>. <code class="docutils literal notranslate"><span class="pre">SpinBoxUI</span></code> is a component that allows users to select a value by spinning through a range. To ensure a smooth transition, I made adjustments in <code class="docutils literal notranslate"><span class="pre">SpinBoxUI</span></code> to align it with the recent updates in <code class="docutils literal notranslate"><span class="pre">TextBlock2D</span></code>. To make things even clearer and more user-friendly, I initiated a continuous code improvement process. I introduced setters and getters that enable easier customization of <code class="docutils literal notranslate"><span class="pre">TextBlock2D</span></code>’s new features, such as <strong>auto_font_scale</strong> and <strong>dynamic_bbox</strong>. These tools simplify the process of adjusting these settings, and you can see the ongoing changes in pull request <a class="reference external" href="https://github.com/fury-gl/fury/pull/830">#830</a>.</p> +<p>Simultaneously, I worked on improving the <code class="docutils literal notranslate"><span class="pre">FileDialog</span></code> component. Since the <code class="docutils literal notranslate"><span class="pre">FileDialog</span></code> PR was based on an older version, it required updates to match the recent developments in <code class="docutils literal notranslate"><span class="pre">TextBlock2D</span></code>. This involved restructuring the code and making sure that everything worked smoothly together. You can checkout the progress here at PR <a class="reference external" href="https://github.com/fury-gl/fury/pull/832">#832</a>.</p> +</section> +<section id="did-you-get-stuck-anywhere"> +<h2>Did you get stuck anywhere?</h2> +<p>Thankfully, this week was quite smooth sailing without any major roadblocks.</p> +</section> +<section id="what-is-coming-up-next"> +<h2>What is coming up next?</h2> +<p>Looking ahead, my plan is to finalize the integration of the updated <code class="docutils literal notranslate"><span class="pre">TextBlock</span></code> and <code class="docutils literal notranslate"><span class="pre">SpinBoxUI</span></code> components. This entails making sure that everything works seamlessly together and is ready for the next stages of development.</p> +</section> +</section> + + + This week, my focus shifted to the SpinBoxUI after wrapping up work on TextBlock2D. SpinBoxUI is a component that allows users to select a value by spinning through a range. To ensure a smooth transition, I made adjustments in SpinBoxUI to align it with the recent updates in TextBlock2D. To make things even clearer and more user-friendly, I initiated a continuous code improvement process. I introduced setters and getters that enable easier customization of TextBlock2D’s new features, such as auto_font_scale and dynamic_bbox. These tools simplify the process of adjusting these settings, and you can see the ongoing changes in pull request #830. + + 2023-08-05T00:00:00-04:00 + + + https://fury.gl/posts/2023/2023-07-29-week-9-praneeth.html + Week 9: TextBlock2D is Finally Merged! + 2023-07-29T00:00:00-04:00 + + Praneeth Shetty + + <section id="week-9-textblock2d-is-finally-merged"> + +<section id="what-did-you-do-this-week"> +<h2>What did you do this week?</h2> +<p>Continuing from the previous week, it seemed like we were almost done with the <em>TextBlock2D</em>, but there remained a final task of addressing conflicting issues. Being a core part of the UI, <em>TextBlock2D</em> had a few compatibility problems with certain other UI elements.</p> +<p>The default behavior of <em>TextBox2D</em> now includes a dynamic bounding box, which scales automatically based on the contained text. Users can customize this option through a simple flag setting. However, this change affected some UI elements like <em>Combobox2d</em>, which relied on the default textbox size. Consequently, I had to make updates to ensure compatibility. Additionally, the default initialization of the <em>TextBlock2D</em> was completely static, which led to the possibility of the text extending beyond the background and failing certain tests. To tackle this, I made adjustments to the overflow helper function in the <em>test_elements.py</em> file. After a few tweaks and issue resolutions, the PR was ready for review and was successfully merged after passing the review process.</p> +<img alt="TextBlock2D with different attributes" class="align-center" src="https://user-images.githubusercontent.com/64432063/258603191-d540105a-0612-450e-8ae3-ca8aa87916e6.gif" /> +</section> +<section id="did-you-get-stuck-anywhere"> +<h2>Did you get stuck anywhere?</h2> +<p>I encountered some peculiar test failures that were indirectly related to the <em>TextBlock2D</em> which at first glance didn’t came up. Although after some debugging and a thorough line-by-line analysis, I managed to identify and resolve them.</p> +</section> +<section id="what-is-coming-up-next"> +<h2>What is coming up next?</h2> +<p>My next priority will be completing the <em>SpinBoxUI</em> now that the <em>TextBlock2D</em> is fixed and successfully integrated.</p> +</section> +</section> + + + Continuing from the previous week, it seemed like we were almost done with the TextBlock2D, but there remained a final task of addressing conflicting issues. Being a core part of the UI, TextBlock2D had a few compatibility problems with certain other UI elements. + + 2023-07-29T00:00:00-04:00 + + + https://fury.gl/posts/2023/2023-07-22-week-8-praneeth.html + Week 8: Another week with TextBlockUI + 2023-07-22T00:00:00-04:00 + + Praneeth Shetty + + <section id="week-8-another-week-with-textblockui"> + +<section id="what-did-you-do-this-week"> +<h2>What did you do this week?</h2> +<p>This week, I delved deeper into the <strong>TextBlock2D</strong> Bounding Box PR to address the challenges with tests and offsetting issues. In a pair programming session with my mentor, we discovered that the offsetting background problem stemmed from the dynamic nature of the bounding box. The issue arose when the <strong>RingSlider2D</strong> component began with an initial text size larger than the current text, which changed as the value was adjusted between 0-100%. This resulted in problems with offsetting and shrinking the bounding box. To resolve this, we decided to make the dynamic bounding box an optional feature.</p> +<p>Now, the <strong>TextBlock2D</strong> component offers three main features:</p> +<ol class="arabic simple"> +<li><p>Completely static background</p></li> +<li><p>Dynamic bounding box scaled according to the text</p></li> +<li><p>Font scaling based on the bounding box</p></li> +</ol> +<p>After tweaking and testing, all the features work seamlessly.</p> +</section> +<section id="did-you-get-stuck-anywhere"> +<h2>Did you get stuck anywhere?</h2> +<p>The pair programming session with my mentor proved to be immensely helpful, as it guided me through the whole week.</p> +</section> +<section id="what-is-coming-up-next"> +<h2>What is coming up next?</h2> +<p>I will dedicate time to further enhancing the <strong>TreeUI</strong>. My focus will be on updating tree nodes and ensuring proper node positioning during movement.</p> +</section> +</section> + + + This week, I delved deeper into the TextBlock2D Bounding Box PR to address the challenges with tests and offsetting issues. In a pair programming session with my mentor, we discovered that the offsetting background problem stemmed from the dynamic nature of the bounding box. The issue arose when the RingSlider2D component began with an initial text size larger than the current text, which changed as the value was adjusted between 0-100%. This resulted in problems with offsetting and shrinking the bounding box. To resolve this, we decided to make the dynamic bounding box an optional feature. + + 2023-07-22T00:00:00-04:00 + + + https://fury.gl/posts/2023/2023-07-15-week-7-praneeth.html + Week 7: Sowing the seeds for TreeUI + 2023-07-15T00:00:00-04:00 + + Praneeth Shetty + + <section id="week-7-sowing-the-seeds-for-treeui"> + +<section id="what-did-you-do-this-week"> +<h2>What did you do this week?</h2> +<p>This week, I focused on completing the <strong>TextBlock2D</strong> Bounding Box feature. However, the tests were failing due to automatic background resizing based on content and improper text actor alignment during setup. I encountered difficulties while positioning the text, which caused the text to appear offset and led to test failures.</p> +<p>Text background greater than the actual maximum size:</p> +<img alt="Text background greater than the actual maximum size in ComboBox2D" class="align-center" src="https://github.com/fury-gl/fury/assets/64432063/aaf4a764-4480-4f96-9adf-29d9e28135a6" /> +<p>Text offset from center:</p> +<img alt="Text offset from center in RingSlider2D" class="align-center" src="https://github.com/fury-gl/fury/assets/64432063/0a3bc1e6-a566-4c08-9ca4-a191525b9c97" /> +<p>Additionally, I reviewed PR <a class="reference external" href="https://github.com/fury-gl/fury/pull/814">#814</a> and noticed that after PR <a class="reference external" href="https://github.com/fury-gl/fury/pull/769">#769</a>, all demos and examples were merged into a single folder, which affected the paths used in the Scientific Domain Section. To address this, I created PR <a class="reference external" href="https://github.com/fury-gl/fury/pull/820">#820</a> to redirect the links to the correct path.</p> +<p>As I faced issues with the <strong>TextBlock2D</strong> PR, I took the opportunity to rebase and continue working on the <strong>TreeUI</strong> PR since there were no updates from the author.</p> +</section> +<section id="did-you-get-stuck-anywhere"> +<h2>Did you get stuck anywhere?</h2> +<p>While fixing the issues with the tests for the <strong>TextBlock2D</strong> bounding box, I encountered a weird behavior in text positioning when using the center alignment. The output varied depending on the sequence of repositioning which we are still investigating.</p> +</section> +<section id="what-is-coming-up-next"> +<h2>What is coming up next?</h2> +<p>I will continue working on the <strong>TreeUI</strong> and resolve the <strong>TextBlock2D</strong> error to ensure both PRs progress smoothly.</p> +</section> +</section> + + + This week, I focused on completing the TextBlock2D Bounding Box feature. However, the tests were failing due to automatic background resizing based on content and improper text actor alignment during setup. I encountered difficulties while positioning the text, which caused the text to appear offset and led to test failures. + + 2023-07-15T00:00:00-04:00 + + + https://fury.gl/posts/2023/2023-07-08-week-6-praneeth.html + Week 6: BoundingBox for TextBlock2D! + 2023-07-08T00:00:00-04:00 + + Praneeth Shetty + + <section id="week-6-boundingbox-for-textblock2d"> + +<section id="what-did-you-do-this-week"> +<h2>What did you do this week?</h2> +<p>This week, I worked on improving the <strong>TextBlock2D</strong> component in the UI system. I started from scratch to address alignment and scaling issues. When resizing the <strong>TextBlock2D</strong>, the text alignment and justification with the background rectangle were inconsistent. To resolve this, I introduced a new “boundingbox” property that calculates the text bounding box based on its content. Additionally, I separated the scaling mode from the resizing action with the new “auto_font_scale” property, enabling automatic font scaling according to the bounding box. This will provide better alignment, justified text, and smoother font scaling for the <strong>TextBlock2D</strong> component. Try it out at <a class="reference external" href="https://github.com/fury-gl/fury/pull/803">PR #803</a>.</p> +<img alt="TextBlock2D will different justifications" class="align-center" src="https://github.com/fury-gl/fury/assets/64432063/94212105-7259-48da-8fdc-41ee987bda84" /> +<p>As discussed last week, we also made a decision regarding the scrollbar. After exploring different use cases, we concluded that creating an independent scrollbar is not necessary at the moment. Therefore, we will close the related pull requests. You can find out more about it in the discussion <a class="reference external" href="https://github.com/fury-gl/fury/discussions/816">here</a>.</p> +</section> +<section id="did-you-get-stuck-anywhere"> +<h2>Did you get stuck anywhere?</h2> +<p>Implementing the bounding box feature took some extra time as I needed to carefully consider its impact on other UI elements that rely on the <strong>TextBlock2D</strong> component.</p> +</section> +<section id="what-is-coming-up-next"> +<h2>What is coming up next?</h2> +<p>Next, I will focus on completing the TextBlock2D Bounding Box PR, which will also indirectly finalize the Spinbox PR.</p> +</section> +</section> + + + This week, I worked on improving the TextBlock2D component in the UI system. I started from scratch to address alignment and scaling issues. When resizing the TextBlock2D, the text alignment and justification with the background rectangle were inconsistent. To resolve this, I introduced a new “boundingbox” property that calculates the text bounding box based on its content. Additionally, I separated the scaling mode from the resizing action with the new “auto_font_scale” property, enabling automatic font scaling according to the bounding box. This will provide better alignment, justified text, and smoother font scaling for the TextBlock2D component. Try it out at PR #803. + + 2023-07-08T00:00:00-04:00 + + + https://fury.gl/posts/2023/2023-07-01-week-5-praneeth.html + Week 5: Trying out PRs and Planning Ahead + 2023-07-01T00:00:00-04:00 + + Praneeth Shetty + + <section id="week-5-trying-out-prs-and-planning-ahead"> + +<section id="what-did-you-do-this-week"> +<h2>What did you do this week?</h2> +<p>Due to ongoing exams, my productivity was limited this week. However, I managed to find some time to explore and review a few PRs submitted by contributors:</p> +<ol class="arabic simple"> +<li><p>Ellipsoid PR <a class="reference external" href="https://github.com/fury-gl/fury/pull/791">#791</a>: +This PR focuses on creating a new ellipsoid actor defined with SDF and raymarching techniques.</p></li> +<li><p>Website Improvement PR <a class="reference external" href="https://github.com/fury-gl/fury/pull/812">#812</a>: +This PR includes changes for the new compatibility section on the FURY home page.</p></li> +</ol> +<p>Towards the end of the week, I had a meeting with my mentor. We discussed the current status of ongoing PRs and identified action points to focus on in the upcoming weeks. This discussion provided clarity on the challenges faced with certain PRs and issues.</p> +</section> +<section id="did-you-get-stuck-anywhere"> +<h2>Did you get stuck anywhere?</h2> +<p>Fortunately, I didn’t encounter any major roadblocks or challenges that hindered my progress this week.</p> +</section> +<section id="what-is-coming-up-next"> +<h2>What is coming up next?</h2> +<p>With the action points provided by my mentor, I will be dedicating the next week to completing those tasks.</p> +</section> +</section> + + + Due to ongoing exams, my productivity was limited this week. However, I managed to find some time to explore and review a few PRs submitted by contributors: + + 2023-07-01T00:00:00-04:00 + + + https://fury.gl/posts/2023/2023-06-24-week-4-praneeth.html + Week 4: Exam Preparations and Reviewing + 2023-06-24T00:00:00-04:00 + + Praneeth Shetty + + <section id="week-4-exam-preparations-and-reviewing"> + +<section id="what-did-i-do-this-week"> +<h2>What did I do this week?</h2> +<p>This week, amidst end-semester exams, I managed to accomplish a few notable tasks. Let’s dive into the highlights:</p> +<ol class="arabic"> +<li><p>Merging <strong>CardUI</strong>: The PR <a class="reference external" href="https://github.com/fury-gl/fury/pull/398">#398</a> introduced the <strong>CardUI</strong> to the UI system of FURY. After a successful review and test check, it was merged into the codebase.</p></li> +<li><aside class="system-message"> +<p class="system-message-title">System Message: INFO/1 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-06-24-week-4-praneeth.rst</span>, line 2); <em><a href="#id3">backlink</a></em></p> +<p>Duplicate explicit target name: “#540”.</p> +</aside> +<p>Revisiting PR <a class="reference external" href="https://github.com/fury-gl/fury/pull/540">#540</a>: I restarted working on PR <a class="reference external" href="https://github.com/fury-gl/fury/pull/540">#540</a> as I wasn’t satisfied with the previous approach when I checked it for rebasing. I took the opportunity to update the code and ensure that the unit tests passed successfully. Although there are a few issues remaining in the tests, I am determined to resolve them and move forward with the implementation. This PR aims to improve the usage of the <strong>numpy_to_vtk_image_data</strong> utility function.</p> +</li> +<li><p>Independent Scrollbar Consideration: We are currently evaluating the necessity of making the Scrollbar an independent element. Currently it is only used by the <strong>ListBox2D</strong>, we are exploring various use cases to determine if there are other scenarios where the Scrollbar can be employed independently. This evaluation will help us make an informed decision about its future implementation.</p></li> +<li><p>PR Reviews: In the brief intervals between exams, I utilized the time to review two PRs: <a class="reference external" href="https://github.com/fury-gl/fury/pull/446">#446</a> - Resize panel and <a class="reference external" href="https://github.com/fury-gl/fury/pull/460">#460</a> - Tree UI.</p></li> +</ol> +</section> +<section id="did-i-get-stuck-anywhere"> +<h2>Did I get stuck anywhere?</h2> +<p>No, fortunately, I didn’t encounter any major obstacles or challenges during my tasks this week.</p> +</section> +<section id="what-is-coming-up-next"> +<h2>What is coming up next?</h2> +<aside class="system-message"> +<p class="system-message-title">System Message: INFO/1 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-06-24-week-4-praneeth.rst</span>, line 2); <em><a href="#id6">backlink</a></em></p> +<p>Duplicate explicit target name: “#540”.</p> +</aside> +<p>Once the exams are over, I am eagerly looking forward to making a full comeback to development. My immediate plans include addressing the remaining issues in PR <a class="reference external" href="https://github.com/fury-gl/fury/pull/540">#540</a> and completing the pending tasks. I will also catch up on any missed discussions and sync up with the team to align our goals for the upcoming weeks.</p> +</section> +</section> + + + This week, amidst end-semester exams, I managed to accomplish a few notable tasks. Let’s dive into the highlights: + + 2023-06-24T00:00:00-04:00 + + diff --git a/v0.10.x/blog/author/sajag-swami.html b/v0.10.x/blog/author/sajag-swami.html new file mode 100644 index 000000000..526e33e2e --- /dev/null +++ b/v0.10.x/blog/author/sajag-swami.html @@ -0,0 +1,1321 @@ + + + + + + + Posts by Sajag Swami — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +
+

+ + Posts by + + Sajag Swami + +

+ + +
+

+ Google Summer of Code Final Work Product +

+
    +
  • + + + 23 August 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Sajag Swami + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Name: Sajag Swami

+

+ +

Read more ...

+
+
+ +
+

+ Tenth coding week! +

+
    +
  • + + + 16 August 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Sajag Swami + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Welcome to the eleventh weekly check-in. I’ll be sharing my progress for the tenth week of coding.

+

+ +

Read more ...

+
+
+ +
+

+ Ninth coding week! +

+
    +
  • + + + 09 August 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Sajag Swami + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Welcome to the tenth weekly check-in. I’ll be sharing my progress for the ninth week of coding.

+

+ +

Read more ...

+
+
+ +
+

+ Eighth coding week! +

+
    +
  • + + + 02 August 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Sajag Swami + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Welcome to the ninth weekly check-in. I’ll be sharing my progress for the eighth week of coding.

+

+ +

Read more ...

+
+
+ +
+

+ Seventh week of coding! +

+
    +
  • + + + 26 July 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Sajag Swami + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Welcome to the eighth weekly check-in. I’ll be sharing my progress for the seventh week of coding.

+

+ +

Read more ...

+
+
+ +
+

+ Sixth week of coding! +

+
    +
  • + + + 19 July 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Sajag Swami + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Welcome to the seventh weekly check-in. I’ll be sharing my progress for the sixth week of coding.

+

+ +

Read more ...

+
+
+ +
+

+ Fifth week of coding! +

+
    +
  • + + + 12 July 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Sajag Swami + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Welcome to the sixth weekly check-in. I’ll be sharing my progress for the fifth week of coding.

+

+ +

Read more ...

+
+
+ +
+

+ Fourth week of coding! +

+
    +
  • + + + 05 July 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Sajag Swami + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Welcome to the fifth weekly check-in. I’ll be sharing my progress for the fourth week of coding.

+

+ +

Read more ...

+
+
+ +
+

+ Third week of coding! +

+
    +
  • + + + 28 June 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Sajag Swami + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Welcome to the fourth weekly check-in. I’ll be sharing my progress for the third week of coding.

+

+ +

Read more ...

+
+
+ +
+

+ Second week of coding! +

+
    +
  • + + + 21 June 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Sajag Swami + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Welcome to the third weekly check-in. I’ll be sharing my progress for the second week of coding.

+

+ +

Read more ...

+
+
+ +
+

+ First week of coding! +

+
    +
  • + + + 14 June 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Sajag Swami + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Welcome to the second weekly check-in. I’ll be sharing my progress for the first week of coding.

+

+ +

Read more ...

+
+
+ +
+

+ Welcome to my GSoC Blog! +

+
    +
  • + + + 08 June 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Sajag Swami + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hi all! +I’m Sajag Swami, a sophomore at Indian Institute of Technology, Roorkee. This summer, I will be working on adding a new functionality to FURY which shall enable users to +visualise various types of proteins via different representations like Richardson aka Ribbon diagrams and molecular surface diagrams. +As a part of my stretch goals, I’ll try to expand protein diagrams via other representations including:

+

+ +

Read more ...

+
+
+ + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/blog/author/sajag-swami/atom.xml b/v0.10.x/blog/author/sajag-swami/atom.xml new file mode 100644 index 000000000..c27aec88b --- /dev/null +++ b/v0.10.x/blog/author/sajag-swami/atom.xml @@ -0,0 +1,683 @@ + + + https://fury.gl/ + Blog - Posts by Sajag Swami + 2024-02-29T15:43:57.502953+00:00 + + + ABlog + + https://fury.gl/posts/2021/2021-08-23-final-work-sajag.html + Google Summer of Code Final Work Product + 2021-08-23T00:00:00-04:00 + + Sajag Swami + + <a class="reference external image-reference" href="https://summerofcode.withgoogle.com/projects/#6653942668197888"><img alt="https://developers.google.com/open-source/gsoc/resources/downloads/GSoC-logo-horizontal.svg" class="align-center" height="50" src="https://developers.google.com/open-source/gsoc/resources/downloads/GSoC-logo-horizontal.svg" /></a> +<a class="reference external image-reference" href="https://blogs.python-gsoc.org/en/nibba2018s-blog/"><img alt="https://www.python.org/static/community_logos/python-logo.png" src="https://www.python.org/static/community_logos/python-logo.png" style="width: 40%;" /></a> +<a class="reference external image-reference" href="https://fury.gl/latest/community.html"><img alt="https://python-gsoc.org/logos/FURY.png" src="https://python-gsoc.org/logos/FURY.png" style="width: 25%;" /></a> +<section id="google-summer-of-code-final-work-product"> + +<ul class="simple"> +<li><p><strong>Name:</strong> Sajag Swami</p></li> +<li><p><strong>Organisation:</strong> Python Software Foundation</p></li> +<li><p><strong>Sub-Organisation:</strong> FURY</p></li> +<li><p><strong>Project:</strong> <a class="reference external" href="https://github.com/fury-gl/fury/wiki/Google-Summer-of-Code-2021">FURY: Ribbon and Molecular Surface Representations for +Proteins</a></p></li> +</ul> +<section id="proposed-objectives"> +<h2>Proposed Objectives</h2> +<ul class="simple"> +<li><p>Ribbon Representation</p></li> +<li><p>Molecular Surface Representation</p></li> +<li><p>Stretch Goals:</p> +<ul> +<li><p>Stick Representation</p></li> +<li><p>Ball and stick Representation</p></li> +<li><p>Wire Representation</p></li> +<li><p>Pipes and Planks Representation</p></li> +<li><p>Sphere Representation</p></li> +</ul> +</li> +</ul> +</section> +<section id="objectives-completed"> +<h2>Objectives Completed</h2> +<ul> +<li><p><strong>Ribbon Representation</strong></p> +<p>Ribbon diagrams, also known as Richardson diagrams, +are 3D schematic representations of protein structure. Ribbon diagrams are +generated by interpolating a smooth curve through the polypeptide backbone. +α-helices are shown as coiled ribbons. β-strands as sheets, and non-repetitive +coils or loops as lines or thin strips. It was implemented by using +<cite>vtkProteinRibbonFilter</cite>. Generating a <cite>vtkPolyData</cite> of appropriate format +required by <cite>vtkProteinRibbonFilter</cite> was initially unclear due to lack of +examples. I was able to understand what kind of output the filter required +after a meeting with mentors. Tests were added and a demo was created.</p> +<p><em>Pull Requests:</em></p> +<ul class="simple"> +<li><p><strong>Ribbon representation:</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/452">fury-gl/fury#452</a></p></li> +<li><p><strong>Ribbon Representation demo:</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/452">fury-gl/fury#452</a></p></li> +</ul> +</li> +<li><p><strong>Ball and Stick Representation</strong></p> +<p>The ball-and-stick model is a molecular model of a chemical substance which +displays both the three-dimensional position of the atoms and the bonds between +them. The atoms are typically represented by spheres, connected by tubes which +represent the bonds. It was created by using <cite>vtkOpenGLMoleculeMapper</cite>. +Added <cite>vtkSimpleBondPerceiver</cite> for detection of bonds. Tests were added and a +demo was created.</p> +<p><em>Pull Requests:</em></p> +<ul class="simple"> +<li><p><strong>Ball and Stick Representation:</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/452">fury-gl/fury#452</a></p></li> +<li><p><strong>Ball and Stick Representation demo:</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/452">fury-gl/fury#452</a></p></li> +</ul> +</li> +<li><p><strong>Stick Representation</strong></p> +<p>Stick model is a special case of Ball and Stick model where atomic radius of all +molecules is set equal to the radius of tubes used to create bonds. It was created +by using <cite>vtkOpenGLMoleculeMapper</cite>. Tests were added and a demo was created.</p> +<p><em>Pull Requests:</em></p> +<ul class="simple"> +<li><p><strong>Stick Representation:</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/452">fury-gl/fury#452</a></p></li> +<li><p><strong>Stick Representation demo:</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/452">fury-gl/fury#452</a></p></li> +</ul> +</li> +<li><p><strong>Sphere Representation</strong></p> +<p>In chemistry, a space-filling model, also known as a calotte or sphere model, is a +type of three-dimensional (3D) molecular model where the atoms are represented by +spheres whose radii are proportional to the radii of the atoms. It was created by +using <cite>vtkOpenGLMoleculeMapper</cite>. Tests were added and a demo was created.</p> +<p><em>Pull Requests:</em></p> +<ul class="simple"> +<li><p><strong>Sphere Representation:</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/452">fury-gl/fury#452</a></p></li> +<li><p><strong>Sphere Representation demo:</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/452">fury-gl/fury#452</a></p></li> +</ul> +</li> +</ul> +</section> +<section id="objectives-in-progress"> +<h2>Objectives in Progress</h2> +<ul> +<li><p><strong>Molecular Surfaces</strong></p> +<p>There are three types of molecular surfaces:</p> +<ul class="simple"> +<li><p>Van der Waals</p></li> +<li><p>Solvent Accessible</p></li> +<li><p>Solvent Excluded</p></li> +</ul> +<p>Currently the first two molecular surfaces i.e. Van der Waals and Solvent +Accessible are implemented. The code is based on the paper “Generating +Triangulated Macromolecular Surfaces by Euclidean Distance Transform” by +Dong Xu and Yang Zhang.</p> +<p><em>Pull Requests:</em></p> +<ul class="simple"> +<li><p><strong>Molecular Surfaces Implementation:</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/492">fury-gl/fury#492</a></p></li> +</ul> +</li> +</ul> +</section> +<section id="other-objectives"> +<h2>Other Objectives</h2> +<ul> +<li><p><strong>2D Animated Surfaces</strong></p> +<p>This was a simple demonstration that animated Two-Dimensional (2D) functions using FURY. +Created a grid of x-y coordinates and mapped the heights (z-values) to the corresponding x, y +coordinates to generate the surfaces. Used colormaps to color the surfaces.</p> +<p><em>Pull Requests:</em></p> +<ul class="simple"> +<li><p><strong>Animated Surfaces:</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/362">fury-gl/fury#362</a></p></li> +</ul> +</li> +<li><p><strong>Updated miscellaneous animations</strong></p> +<ul class="simple"> +<li><p>Updated the demo of helical motion to stop using multiple line actors as discussed in the meeting.</p></li> +<li><p>Updated the demo of brownian motion to make it more scientifically useful (removed unnecessary rotation of camera +during animation and box actor).</p></li> +<li><p>Display simulation data for brownian motion and helical motion animations (number of simulated steps for brownian +motion and velocity of the particle for helical motion).</p></li> +<li><p>Created utility functions to make the code understandable and used these in emwave, helical and brownian +animations.</p></li> +</ul> +<p><em>Pull Requests:</em></p> +<ul class="simple"> +<li><p><strong>Updated helical, brownian, emwave animations:</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/462">fury-gl/fury#462</a></p></li> +</ul> +</li> +<li><p><strong>GSoC weekly Blogs</strong></p> +<blockquote> +<div><p>Weekly blogs were added for FURY’s Website.</p> +<p><em>Pull Requests:</em></p> +<ul class="simple"> +<li><p><strong>First Evaluation:</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/475">fury-gl/fury#475</a></p></li> +<li><p><strong>Second Evaluation:</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/493">fury-gl/fury#493</a></p></li> +</ul> +</div></blockquote> +</li> +</ul> +</section> +<section id="timeline"> +<h2>Timeline</h2> +<table class="table"> +<thead> +<tr class="row-odd"><th class="head"><p>Date</p></th> +<th class="head"><p>Description</p></th> +<th class="head"><p>Blog Link</p></th> +</tr> +</thead> +<tbody> +<tr class="row-even"><td><p>Week 1(08-06-2021)</p></td> +<td><p>Welcome to my GSoC Blog!</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/suntzunamis-blog/weekly-check-in-1-11/">Weekly Check-in #1</a></p></td> +</tr> +<tr class="row-odd"><td><p>Week 2(14-06-2021)</p></td> +<td><p>First Week of coding: sphere model.</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/suntzunamis-blog/weekly-check-in-2-11/">Weekly Check-in #2</a></p></td> +</tr> +<tr class="row-even"><td><p>Week 3(21-06-2021)</p></td> +<td><p>Bonding algorithms, Ball and Stick model progress.</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/suntzunamis-blog/weekly-check-in-3-13/">Weekly Check-in #3</a></p></td> +</tr> +<tr class="row-odd"><td><p>Week 4(28-06-2021)</p></td> +<td><p>VTK molecular visualization classes.</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/suntzunamis-blog/weekly-check-in-4-14/">Weekly Check-in #4</a></p></td> +</tr> +<tr class="row-even"><td><p>Week 5(05-07-2021)</p></td> +<td><p>Genesis of <cite>molecular</cite> module.</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/suntzunamis-blog/weekly-check-in-5-13/">Weekly Check-in #5</a></p></td> +</tr> +<tr class="row-odd"><td><p>Week 6(12-07-2021)</p></td> +<td><p>Ribbon representation, updated <cite>molecular</cite> module (more pythonic)</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/suntzunamis-blog/weekly-check-in-6-18/">Weekly Check-in #6</a></p></td> +</tr> +<tr class="row-even"><td><p>Week 7(19-07-2021)</p></td> +<td><p>More features to <cite>molecular</cite>, updated misc. animations.</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/suntzunamis-blog/weekly-check-in-7-16/">Weekly Check-in #7</a></p></td> +</tr> +<tr class="row-odd"><td><p>Week 8(26-07-2020)</p></td> +<td><p>Ribbon to <cite>molecular</cite>, tests for <cite>molecular</cite>, animated surfaces.</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/suntzunamis-blog/weekly-check-in-8-11/">Weekly Check-in #8</a></p></td> +</tr> +<tr class="row-even"><td><p>Week 9(02-08-2021)</p></td> +<td><p>Optimized <cite>molecular</cite> with mentors, GSoC blogs to FURY docs.</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/suntzunamis-blog/weekly-check-in-9-11/">Weekly Check-in #9</a></p></td> +</tr> +<tr class="row-odd"><td><p>Week 10(09-08-2021)</p></td> +<td><p>Bounding box, <cite>molecular</cite> tutorial, molecular surfaces progress.</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/suntzunamis-blog/weekly-check-in-10-11/">Weekly Check-in #10</a></p></td> +</tr> +<tr class="row-even"><td><p>Week 11(16-08-2021)</p></td> +<td><p>Molecular Surfaces (VDW, SAS) implementation.</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/suntzunamis-blog/weekly-check-in-11-9/">Weekly Check-in #11</a></p></td> +</tr> +</tbody> +</table> +<p>Detailed weekly tasks and work done can be found +<a class="reference external" href="https://blogs.python-gsoc.org/en/suntzunamis-blog/">here</a>.</p> +</section> +</section> + + + Name: Sajag Swami + + 2021-08-23T00:00:00-04:00 + + + https://fury.gl/posts/2021/2021-08-16-week-11-sajag.html + Tenth coding week! + 2021-08-16T00:00:00-04:00 + + Sajag Swami + + <section id="tenth-coding-week"> + +<p>Welcome to the eleventh weekly check-in. I’ll be sharing my progress for the tenth week of coding.</p> +<section id="what-did-you-do-this-week"> +<h2>What did you do this week?</h2> +<ol class="arabic"> +<li><p>Implemented <a class="reference external" href="https://journals.plos.org/plosone/article?id=10.1371/journal.pone.0008140">this paper</a> to generate Van der Waals surface and solvent-accessible surface (PR created: <a class="reference external" href="https://github.com/fury-gl/fury/pull/492">PR #492</a>). It was a good learning experience because the first time I read the paper, I didn’t understand the underlying math, it all seemed alien to me. I had to read it many times, read about the algorithms used and understand the terminologies. I had a meeting with the mentors to understand a bit of the theory which proved to be quite fruitful as I understood how to go about making the space-filling model. <a class="reference external" href="ttps://pyscience.wordpress.com/2014/09/11/surface-extraction-creating-a-mesh-from-pixel-data-using-python-and-vtk/">This</a> blog was helpful in understanding how to use vtkMarchingCubes with numpy arrays. One of the earliest SAS rendering looked like this (this implementation was not strictly according to the paper):</p> +<blockquote> +<div><figure class="align-default" id="id1"> +<img alt="https://user-images.githubusercontent.com/65067354/129559593-baf201bf-720c-45f7-9269-3b31954efd5e.png" src="https://user-images.githubusercontent.com/65067354/129559593-baf201bf-720c-45f7-9269-3b31954efd5e.png" style="width: 300px; height: 300px;" /> +<figcaption> +<p><span class="caption-text">Notice that it’s rather rough</span></p> +</figcaption> +</figure> +</div></blockquote> +<p>Current implementation (this implementation was according to the paper):</p> +<blockquote> +<div><figure class="align-default" id="id2"> +<img alt="https://user-images.githubusercontent.com/65067354/129560374-14180b22-14b2-449b-88a6-b3140226418d.png" src="https://user-images.githubusercontent.com/65067354/129560374-14180b22-14b2-449b-88a6-b3140226418d.png" style="width: 300px; height: 300px;" /> +<figcaption> +<p><span class="caption-text">grid dimensions = 256 × 256 × 256, used smoothing algorithms recommended by vtk</span></p> +</figcaption> +</figure> +</div></blockquote> +</li> +</ol> +<p>I also understood how to go about rendering volumes. I think that the ability to render volumes with FURY will be a cool capability and I’ll discuss my implementation and request the mentors for feedback and ideas in the weekly meeting. Example of volume rendering:</p> +<blockquote> +<div><figure class="align-default" id="id3"> +<img alt="https://user-images.githubusercontent.com/65067354/129562606-50a9f0cf-e16d-4501-b0fa-a0038fda406b.png" src="https://user-images.githubusercontent.com/65067354/129562606-50a9f0cf-e16d-4501-b0fa-a0038fda406b.png" style="width: 300px; height: 300px;" /> +<figcaption> +<p><span class="caption-text">grid dimensions = 256 × 256 × 256</span></p> +</figcaption> +</figure> +</div></blockquote> +</section> +<section id="what-is-coming-up-next-week"> +<h2>What is coming up next week?</h2> +<p>I’ll try to get <a class="reference external" href="https://github.com/fury-gl/fury/pull/452">PR #452</a> merged. Documentation work to be done as GSoC coding period has come to an end.</p> +</section> +<section id="did-you-get-stuck-anywhere"> +<h2>Did you get stuck anywhere?</h2> +<p>No.</p> +<p><code class="docutils literal notranslate"><span class="pre">Au</span> <span class="pre">Revoir!</span></code></p> +</section> +</section> + + + Welcome to the eleventh weekly check-in. I’ll be sharing my progress for the tenth week of coding. + + 2021-08-16T00:00:00-04:00 + + + https://fury.gl/posts/2021/2021-08-09-week-10-sajag.html + Ninth coding week! + 2021-08-09T00:00:00-04:00 + + Sajag Swami + + <section id="ninth-coding-week"> + +<p>Welcome to the tenth weekly check-in. I’ll be sharing my progress for the ninth week of coding.</p> +<section id="what-did-you-do-this-week"> +<h2>What did you do this week?</h2> +<ol class="arabic"> +<li><p>Updated <a class="reference external" href="https://github.com/fury-gl/fury/pull/452">PR #452</a> :</p> +<blockquote> +<div><ul class="simple"> +<li><p>Made ribbon representation faster.</p></li> +<li><p>Added an actor to display bounding box around the molecule.</p></li> +</ul> +<blockquote> +<div><figure class="align-default" id="id1"> +<img alt="https://user-images.githubusercontent.com/65067354/128624529-03c026be-7f80-4792-b57e-eceeb1767ec2.png" src="https://user-images.githubusercontent.com/65067354/128624529-03c026be-7f80-4792-b57e-eceeb1767ec2.png" style="width: 300px; height: 300px;" /> +<figcaption> +<p><span class="caption-text">Bounding Box</span></p> +</figcaption> +</figure> +</div></blockquote> +</div></blockquote> +</li> +<li><p>Made a tutorial which showcases the abilities of molecular module (will create a PR after molecular module is merged).</p></li> +<li><p>I’m trying to implement a native implementation of molecular surfaces in FURY. Currently searching for recent research papers to find good algorithms to generate the molecular surfaces (the ones I’d collected in the research period were archaic and rather time consuming). The papers that I’ve read so far seem a tad bit intimidating as I’ve never done math related to this domain yet. Implementing them will be a good learning experience I reckon.</p></li> +</ol> +</section> +<section id="what-is-coming-up-next-week"> +<h2>What is coming up next week?</h2> +<ol class="arabic simple"> +<li><p>Try to create a native implementation of molecular surface.</p></li> +<li><p>Small fixes to <a class="reference external" href="https://github.com/fury-gl/fury/pull/362">PR #362</a>, <a class="reference external" href="https://github.com/fury-gl/fury/pull/462">PR #462</a>.</p></li> +</ol> +</section> +<section id="did-you-get-stuck-anywhere"> +<h2>Did you get stuck anywhere?</h2> +<p>No.</p> +<p><code class="docutils literal notranslate"><span class="pre">Au</span> <span class="pre">Revoir!</span></code></p> +</section> +</section> + + + Welcome to the tenth weekly check-in. I’ll be sharing my progress for the ninth week of coding. + + 2021-08-09T00:00:00-04:00 + + + https://fury.gl/posts/2021/2021-08-02-week-9-sajag.html + Eighth coding week! + 2021-08-02T00:00:00-04:00 + + Sajag Swami + + <section id="eighth-coding-week"> + +<p>Welcome to the ninth weekly check-in. I’ll be sharing my progress for the eighth week of coding.</p> +<section id="what-did-you-do-this-week"> +<h2>What did you do this week?</h2> +<ol class="arabic"> +<li><p>Updated <a class="reference external" href="https://github.com/fury-gl/fury/pull/452">PR #452</a>: Had an extra meeting with the mentors in which we fine-tuned the molecular module and optimised the code to make it more pythonic.</p></li> +<li><p>I was able to generate vertices and triangles for Solvent Excluded Surfaces (SES) by using a bioconda package called <a class="reference external" href="https://anaconda.org/bioconda/msms">msms</a>. It’s based on <a class="reference external" href="https://onlinelibrary.wiley.com/doi/10.1002/%28SICI%291097-0282%28199603%2938%3A3%3C305%3A%3AAID-BIP4%3E3.0.CO%3B2-Y">this paper</a> by Michel F. Sanner, Arthur J. Olson &amp; Jean-Claude Spehner. The vertices and triangles were then sent to surface actor to generate a surface.</p> +<blockquote> +<div><figure class="align-default" id="id1"> +<img alt="https://user-images.githubusercontent.com/65067354/128756004-553d1880-b6e1-4a43-99fa-5bd6a2ee70d4.png" src="https://user-images.githubusercontent.com/65067354/128756004-553d1880-b6e1-4a43-99fa-5bd6a2ee70d4.png" style="width: 300px; height: 300px;" /> +<figcaption> +<p><span class="caption-text">SES surface generated via msms and surface actor</span></p> +</figcaption> +</figure> +</div></blockquote> +</li> +<li><p>Added my GSoC blogs to the FURY blogs directory. (<a class="reference external" href="https://github.com/fury-gl/fury/pull/475">PR #475</a>)</p></li> +</ol> +<p>Other goals will be decided in the meeting with mentors.</p> +</section> +<section id="what-is-coming-up-next-week"> +<h2>What is coming up next week?</h2> +<ol class="arabic simple"> +<li><p>Research about recent papers having good (fast) algorithms to create the molecular surfaces.</p></li> +<li><p>Create tutorials to explain how to use molecular module.</p></li> +</ol> +</section> +<section id="did-you-get-stuck-anywhere"> +<h2>Did you get stuck anywhere?</h2> +<p>No.</p> +<p><code class="docutils literal notranslate"><span class="pre">Au</span> <span class="pre">Revoir!</span></code></p> +</section> +</section> + + + Welcome to the ninth weekly check-in. I’ll be sharing my progress for the eighth week of coding. + + 2021-08-02T00:00:00-04:00 + + + https://fury.gl/posts/2021/2021-07-26-week-8-sajag.html + Seventh week of coding! + 2021-07-26T00:00:00-04:00 + + Sajag Swami + + <section id="seventh-week-of-coding"> + +<p>Welcome to the eighth weekly check-in. I’ll be sharing my progress for the seventh week of coding.</p> +<section id="what-did-you-do-this-week"> +<h2>What did you do this week?</h2> +<ol class="arabic"> +<li><p>Updated <a class="reference external" href="https://github.com/fury-gl/fury/pull/452">PR #452</a>:</p> +<ul class="simple"> +<li><p>Added ribbon actor to the molecular module.</p></li> +<li><p>Added tests for all functions in the molecular module.</p></li> +</ul> +</li> +<li><p>Updated <a class="reference external" href="https://github.com/fury-gl/fury/pull/462">PR #462</a>: Addressed the reviews of team members and +mentors, added new features.</p> +<p><img alt="image1" src="https://user-images.githubusercontent.com/65067354/126382288-b755c01d-8010-43ab-87db-2f1a4fb5b015.png" style="width: 300px; height: 300px;" /></p> +</li> +<li><p>Updated <a class="reference external" href="https://github.com/fury-gl/fury/pull/362">PR #362</a>: Addressed the feedbacks of team members and +mentors.</p></li> +</ol> +</section> +<section id="what-is-coming-up-next-week"> +<h2>What is coming up next week?</h2> +<ol class="arabic simple"> +<li><p>Work more on molecular module, meeting with mentors and core team on +Thursday to optimize the module and merge <a class="reference external" href="https://github.com/fury-gl/fury/pull/452">PR #452</a>.</p></li> +<li><p>Start working upon molecular surface model.</p></li> +</ol> +</section> +<section id="did-you-get-stuck-anywhere"> +<h2>Did you get stuck anywhere?</h2> +<p>No.</p> +<p><code class="docutils literal notranslate"><span class="pre">Au</span> <span class="pre">Revoir!</span></code></p> +</section> +</section> + + + Welcome to the eighth weekly check-in. I’ll be sharing my progress for the seventh week of coding. + + 2021-07-26T00:00:00-04:00 + + + https://fury.gl/posts/2021/2021-07-19-week-7-sajag.html + Sixth week of coding! + 2021-07-19T00:00:00-04:00 + + Sajag Swami + + <section id="sixth-week-of-coding"> + +<p>Welcome to the seventh weekly check-in. I’ll be sharing my progress for the sixth week of coding.</p> +<section id="what-did-you-do-this-week"> +<h2>What did you do this week?</h2> +<ol class="arabic"> +<li><p>Updated <a class="reference external" href="https://github.com/fury-gl/fury/pull/452">Molecular module</a>: made it more pythonic, implemented +ribbon actor, added support to pass numpy arrays (earlier, atomic +data could only be added by using the add_atom).</p></li> +<li><p>Created <a class="reference external" href="https://github.com/fury-gl/fury/pull/462">PR #462</a> to:</p> +<ul> +<li><p>Update the helical motion animation to use a single line actor, +added textblocks to display velocity of the particle.</p> +<p><img alt="image1" src="https://user-images.githubusercontent.com/65067354/126033284-882ed6fd-fcc3-4a1c-8dfd-3220908859b1.png" style="width: 400px; height: 300px;" /></p> +</li> +<li><p>For brownian motion animation, I removed rotation(azimuth) and box +actor, added textblock to display the number of particles and to +show the simulation steps.</p> +<p><img alt="image2" src="https://user-images.githubusercontent.com/65067354/126033291-da68cb0d-b856-48ad-9aa4-c46621052267.png" style="width: 400px; height: 400px;" /></p> +</li> +</ul> +</li> +<li><p>Updated surface animation (used gridUI, added multiple animations).</p> +<p><img alt="image3" src="https://user-images.githubusercontent.com/65067354/126061012-b183a47d-ed5e-4026-938b-4124da291524.png" style="width: 400px; height: 400px;" /></p> +</li> +<li><p>Created a <a class="reference external" href="https://discourse.vtk.org/t/vtkmoleculemapper-gaps-in-bonds-on-zooming-in/6183">topic</a> on vtk discourse forum to query about gaps in +bonds (tried resolving it by manipulating vtkProperties: +BackfaceCulling, FrontfaceCulling but was unsuccessful).</p></li> +<li><p>Read about molecular surface (theory behind it).</p></li> +</ol> +</section> +<section id="what-is-coming-up-next-week"> +<h2>What is coming up next week?</h2> +<ol class="arabic simple"> +<li><p>Update molecular module by adding tests, ribbon actor.</p></li> +<li><p>Try to implement molecular surface representation.</p></li> +<li><p>Interactivity of the molecules.</p></li> +</ol> +</section> +<section id="did-you-get-stuck-anywhere"> +<h2>Did you get stuck anywhere?</h2> +<p>I didn’t get stuck anywhere this week.</p> +<p><code class="docutils literal notranslate"><span class="pre">Au</span> <span class="pre">Revoir!</span></code></p> +</section> +</section> + + + Welcome to the seventh weekly check-in. I’ll be sharing my progress for the sixth week of coding. + + 2021-07-19T00:00:00-04:00 + + + https://fury.gl/posts/2021/2021-07-12-week-6-sajag.html + Fifth week of coding! + 2021-07-12T00:00:00-04:00 + + Sajag Swami + + <section id="fifth-week-of-coding"> + +<p>Welcome to the sixth weekly check-in. I’ll be sharing my progress for the fifth week of coding.</p> +<section id="what-did-you-do-this-week"> +<h2>What did you do this week?</h2> +<ol class="arabic simple"> +<li><p>Generalised the vtkProteinRibbonFilter implementation.</p></li> +<li><p>Updated the molecular module based on suggestions of team members +and mentors (<a class="reference external" href="https://github.com/fury-gl/fury/pull/452">PR #452</a>).</p></li> +<li><p>Updated wave function animation (<a class="reference external" href="https://github.com/fury-gl/fury/pull/362">PR #362</a>).</p></li> +</ol> +<blockquote> +<div><figure class="align-default" id="id1"> +<img alt="https://user-images.githubusercontent.com/65067354/125155195-d4105800-e17b-11eb-9e6d-2b66ba7a8f6e.gif" src="https://user-images.githubusercontent.com/65067354/125155195-d4105800-e17b-11eb-9e6d-2b66ba7a8f6e.gif" style="width: 300px; height: 300px;" /> +<figcaption> +<p><span class="caption-text">an animation</span></p> +</figcaption> +</figure> +</div></blockquote> +</section> +<section id="what-is-coming-up-next-week"> +<h2>What is coming up next week?</h2> +<ol class="arabic simple"> +<li><p>Update molecular module based on team members’ suggestions and add +tests for the same.</p></li> +<li><p>Add protein ribbon implementation to the molecular module.</p></li> +<li><p>Begin working on molecular surface model.</p></li> +</ol> +</section> +<section id="did-you-get-stuck-anywhere"> +<h2>Did you get stuck anywhere?</h2> +<p>No! <strong>I was finally able to generalise the vtkProteinRibbonFilter implementation!!</strong> I’m +grateful to the mentors for keeping a meeting and for helping me debug +the code. I figured out most of the stuff courtesy the meeting.</p> +<p><code class="docutils literal notranslate"><span class="pre">Au</span> <span class="pre">Revoir!</span></code></p> +</section> +</section> + + + Welcome to the sixth weekly check-in. I’ll be sharing my progress for the fifth week of coding. + + 2021-07-12T00:00:00-04:00 + + + https://fury.gl/posts/2021/2021-07-05-week-5-sajag.html + Fourth week of coding! + 2021-07-05T00:00:00-04:00 + + Sajag Swami + + <section id="fourth-week-of-coding"> + +<p>Welcome to the fifth weekly check-in. I’ll be sharing my progress for the fourth week of coding.</p> +<section id="what-did-you-do-this-week"> +<h2>What did you do this week?</h2> +<p>Created a <a class="reference external" href="https://github.com/fury-gl/fury/pull/452">PR</a> for the molecular module. Enables the ability to create +three types of molecular representations:</p> +<ol class="arabic simple"> +<li><p>Space-filling model aka calotte model and CPK model.</p></li> +<li><p>Stick model.</p></li> +<li><p>Ball and Stick model.</p></li> +</ol> +</section> +<section id="what-is-coming-up-next-week"> +<h2>What is coming up next week?</h2> +<p>Mentors suggested changes to be made to the molecular module which I +shall make. Other goals to be decided post mid-week meeting.</p> +</section> +<section id="did-you-get-stuck-anywhere"> +<h2>Did you get stuck anywhere?</h2> +<p>Sending protein data to ProteinRibbonFilter via a vtkPolyData has been +unsuccessful so far.</p> +<p><code class="docutils literal notranslate"><span class="pre">Au</span> <span class="pre">Revoir!</span></code></p> +</section> +</section> + + + Welcome to the fifth weekly check-in. I’ll be sharing my progress for the fourth week of coding. + + 2021-07-05T00:00:00-04:00 + + + https://fury.gl/posts/2021/2021-06-28-week-4-sajag.html + Third week of coding! + 2021-06-28T00:00:00-04:00 + + Sajag Swami + + <section id="third-week-of-coding"> + +<p>Welcome to the fourth weekly check-in. I’ll be sharing my progress for the third week of coding.</p> +<section id="what-did-you-do-this-week"> +<h2>What did you do this week?</h2> +<p>I made a document with code snippets and visuals to show how one can use +some vtk classes in python for molecular visualization. Classes of +interest:</p> +<ul class="simple"> +<li><p>vtkMolecule (store atomic information about the molecule).</p></li> +<li><p>vtkSimpleBondPerceiver (calculate bonding info for a vtkMolecule).</p></li> +<li><p>vtkMoleculeMapper (mapper to draw vtkMolecule object).</p></li> +<li><p>vtkPeriodicTable (stores chemical data sourced from the Blue Obelisk +Data).</p></li> +</ul> +<p>Link to the document: <a class="reference external" href="https://docs.google.com/document/d/1LC2MgT9mUQK0Yo9hsI4lWqaTXHWAkSNxyBKWGAqHqe8/edit">Molecular_viz_vtk</a>. In addition to the +document, I read some research papers recommended by my mentors to +understand some other (and potentially better) methods of ribbon +visualization. Tried to implement vtkProteinRibbonFilter usage without +using vtkPDBReader but was unsuccessful in this endeavor.</p> +</section> +<section id="what-is-coming-up-next-week"> +<h2>What is coming up next week?</h2> +<p>Three goals for next week:</p> +<ol class="arabic simple"> +<li><p>Implement vtkProteinRibbonFilter usage without using vtkPDBReader.</p></li> +<li><p>Make a class for vtkMolecule which can store molecular data and pass +it on to different function for rendering purposes.</p></li> +<li><p>Read papers on surface model.</p></li> +</ol> +</section> +<section id="did-you-get-stuck-anywhere"> +<h2>Did you get stuck anywhere?</h2> +<p>Implementing vtkProteinRibbonFilter usage via vtkPolyData without using +vtkPDBReader has confounded me for some time now.</p> +<p><code class="docutils literal notranslate"><span class="pre">Au</span> <span class="pre">Revoir!</span></code></p> +</section> +</section> + + + Welcome to the fourth weekly check-in. I’ll be sharing my progress for the third week of coding. + + 2021-06-28T00:00:00-04:00 + + + https://fury.gl/posts/2021/2021-06-21-week-3-sajag.html + Second week of coding! + 2021-06-21T00:00:00-04:00 + + Sajag Swami + + <section id="second-week-of-coding"> + +<p>Welcome to the third weekly check-in. I’ll be sharing my progress for the second week of coding.</p> +<section id="what-did-you-do-this-week"> +<h2>What did you do this week?</h2> +<p>I created an example to demonstrate how one can render multiple bonds (double and triple). This required me to write an algorithm to detect bonding. +I used <a class="reference external" href="https://www.kaggle.com/aekoch95/bonds-from-structure-data">this blog</a> as a reference and made a few tweaks of my own to detect the presence of double/triple bonds from interatomic distances. +The math involved in generating the coordinates of bonds was quite intriguing. Preview:</p> +<blockquote> +<div><figure class="align-default" id="id1"> +<img alt="https://user-images.githubusercontent.com/65067354/122672109-7d040c80-d1e7-11eb-815d-1d07fe47bbc4.png" src="https://user-images.githubusercontent.com/65067354/122672109-7d040c80-d1e7-11eb-815d-1d07fe47bbc4.png" style="width: 300px; height: 300px;" /> +<figcaption> +<p><span class="caption-text">molecules rendered: Ethane, Ethene, Ethyne (from left to right)</span></p> +</figcaption> +</figure> +</div></blockquote> +<p>In addition to this, I tried understanding the codebase of vtkMolecule, vtkSimpleBondPerceiver, vtkMoleculeMapper, vtkPeriodicTable and was able to render bond-stick models and stick models using it. +This will be of great help although it’s rather slow in rendering large molecules (using shaders to improve its speed will be crucial if it’s to be utilised).</p> +<blockquote> +<div><figure class="align-default" id="id2"> +<img alt="https://github.com/SunTzunami/gsoc2021_blog_data/blob/master/visuals/week2_wire_rep.png?raw=true" src="https://github.com/SunTzunami/gsoc2021_blog_data/blob/master/visuals/week2_wire_rep.png?raw=true" style="width: 300px; height: 300px;" /> +<figcaption> +<p><span class="caption-text">Stick representation using vtkMoleculeMapper</span></p> +</figcaption> +</figure> +<figure class="align-default" id="id3"> +<img alt="https://raw.githubusercontent.com/SunTzunami/gsoc2021_blog_data/master/visuals/week2_bs_rep.png" src="https://raw.githubusercontent.com/SunTzunami/gsoc2021_blog_data/master/visuals/week2_bs_rep.png" style="width: 300px; height: 300px;" /> +<figcaption> +<p><span class="caption-text">Ball and Stick representation using vtkMoleculeMapper</span></p> +</figcaption> +</figure> +</div></blockquote> +</section> +<section id="what-is-coming-up-next-week"> +<h2>What is coming up next week?</h2> +<p>Try to see if the above models can be implemented using shaders. Try implementing the ribbon model using the vtkProteinRibbonFilter. The rest will be decided in the meeting with the mentors.</p> +</section> +<section id="did-you-get-stuck-anywhere"> +<h2>Did you get stuck anywhere?</h2> +<p>Predicting bonds had been a problem since the past few weeks, it was resolved to a large extent by vtkSimpleBondPerceiver (the only limitation of vtkSimpleBondPerceiver being its inability to predict multiple bonds).</p> +<p><code class="docutils literal notranslate"><span class="pre">Au</span> <span class="pre">Revoir!</span></code></p> +</section> +</section> + + + Welcome to the third weekly check-in. I’ll be sharing my progress for the second week of coding. + + 2021-06-21T00:00:00-04:00 + + diff --git a/v0.10.x/blog/author/serge-koudoro.html b/v0.10.x/blog/author/serge-koudoro.html new file mode 100644 index 000000000..8cec50133 --- /dev/null +++ b/v0.10.x/blog/author/serge-koudoro.html @@ -0,0 +1,1757 @@ + + + + + + + Posts by Serge Koudoro — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +
+

+ + Posts by + + Serge Koudoro + +

+ + +
+

+ FURY 0.9.0 Released +

+
    +
  • + + + 15 April 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Serge Koudoro + + + +
  • + + + + +
  • + + + Category: + + + + + release + + + +
  • + + +
  • + + + + Tag: + + + + + fury + + + +
  • + + +
    +
+

The FURY project is happy to announce the release of FURY 0.9.0! +FURY is a free and open source software library for scientific visualization and 3D animations.

+

+ +

Read more ...

+
+
+ +
+

+ Contribute to FURY via Google Summer of Code 2023 +

+
    +
  • + + + 01 February 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Serge Koudoro + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

FURY is participating in the Google Summer of Code 2023 under the umbrella of the Python Software Foundation.

+

+ +

Read more ...

+
+
+ +
+

+ Contribute to FURY via Google Summer of Code 2022 +

+
    +
  • + + + 01 February 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Serge Koudoro + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

FURY is participating in the Google Summer of Code 2022 under the umbrella of the Python Software Foundation.

+

+ +

Read more ...

+
+
+ +
+

+ FURY 0.8.0 Released +

+
    +
  • + + + 31 January 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Serge Koudoro + + + +
  • + + + + +
  • + + + Category: + + + + + release + + + +
  • + + +
  • + + + + Tag: + + + + + fury + + + +
  • + + +
    +
+

The FURY project is happy to announce the release of FURY 0.8.0! +FURY is a free and open source software library for scientific visualization and 3D animations.

+

+ +

Read more ...

+
+
+ +
+

+ FURY 0.7.0 Released +

+
    +
  • + + + 03 August 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Serge Koudoro + + + +
  • + + + + +
  • + + + Category: + + + + + release + + + +
  • + + +
  • + + + + Tag: + + + + + fury + + + +
  • + + +
    +
+

The FURY project is happy to announce the release of FURY 0.7.1! +FURY is a free and open source software library for scientific visualization and 3D animations.

+

+ +

Read more ...

+
+
+ +
+

+ FURY 0.7.0 Released +

+
    +
  • + + + 13 March 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Serge Koudoro + + + +
  • + + + + +
  • + + + Category: + + + + + release + + + +
  • + + +
  • + + + + Tag: + + + + + fury + + + +
  • + + +
    +
+

The FURY project is happy to announce the release of FURY 0.7.0! +FURY is a free and open source software library for scientific visualization and 3D animations.

+

+ +

Read more ...

+
+
+ +
+

+ Google Summer of Code +

+
    +
  • + + + 09 March 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Serge Koudoro + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

FURY is participating in the Google Summer of Code 2021 under the umbrella of the Python Software Foundation.

+

+ +

Read more ...

+
+
+ +
+

+ FURY 0.6.1 Released +

+
    +
  • + + + 18 August 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Serge Koudoro + + + +
  • + + + + +
  • + + + Category: + + + + + release + + + +
  • + + +
  • + + + + Tag: + + + + + fury + + + +
  • + + +
    +
+

The FURY project is happy to announce the release of FURY 0.6.1! +FURY is a free and open source software library for scientific visualization and 3D animations.

+

+ +

Read more ...

+
+
+ +
+

+ FURY 0.6.0 Released +

+
    +
  • + + + 20 July 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Serge Koudoro + + + +
  • + + + + +
  • + + + Category: + + + + + release + + + +
  • + + +
  • + + + + Tag: + + + + + fury + + + +
  • + + +
    +
+

The FURY project is happy to announce the release of FURY 0.6.0! +FURY is a free and open source software library for scientific visualization and 3D animations.

+

+ +

Read more ...

+
+
+ +
+

+ FURY 0.5.1 Released +

+
    +
  • + + + 09 April 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Serge Koudoro + + + +
  • + + + + +
  • + + + Category: + + + + + release + + + +
  • + + +
  • + + + + Tag: + + + + + fury + + + +
  • + + +
    +
+

The FURY project is happy to announce the release of FURY 0.5.1! +FURY is a free and open source software library for scientific visualization and 3D animations.

+

+ +

Read more ...

+
+
+ +
+

+ Google Summer of Code +

+
    +
  • + + + 05 January 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Serge Koudoro + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

FURY is participating in the Google Summer of Code 2020 under the umbrella of the Python Software Foundation.

+

+ +

Read more ...

+
+
+ +
+

+ FURY 0.4.0 Released +

+
    +
  • + + + 29 October 2019 + +
  • +
    + + +
  • + + + Author: + + + + + Serge Koudoro + + + +
  • + + + + +
  • + + + Category: + + + + + release + + + +
  • + + +
  • + + + + Tag: + + + + + fury + + + +
  • + + +
    +
+

The FURY project is happy to announce the release of FURY 0.4.0! +FURY is a free and open source software library for scientific visualization and 3D animations.

+

+ +

Read more ...

+
+
+ +
+

+ FURY 0.3.0 Released +

+
    +
  • + + + 02 August 2019 + +
  • +
    + + +
  • + + + Author: + + + + + Serge Koudoro + + + +
  • + + + + +
  • + + + Category: + + + + + release + + + +
  • + + +
  • + + + + Tag: + + + + + fury + + + +
  • + + +
    +
+

The FURY project is happy to announce the release of FURY 0.3.0! +FURY is a free and open source software library for scientific visualization and 3D animations.

+

+ +

Read more ...

+
+
+ +
+

+ Success on Brain Art Competition using FURY +

+
    +
  • + + + 19 June 2019 + +
  • +
    + + +
  • + + + Author: + + + + + Serge Koudoro + + + +
  • + + + + +
  • + + + Category: + + + + + news + + + +
  • + + +
  • + + + + Tag: + + + + + shader + + + +
  • + + +
    +
+

Congratulations to David who won the OHBM BrainArt (MELPOMENE category) by using DIPY and FURY!!!

+

+ +

Read more ...

+
+
+ +
+

+ FURY 0.2.0 Released +

+
    +
  • + + + 08 March 2019 + +
  • +
    + + +
  • + + + Author: + + + + + Serge Koudoro + + + +
  • + + + + +
  • + + + Category: + + + + + release + + + +
  • + + +
  • + + + + Tag: + + + + + fury + + + +
  • + + +
    +
+

The FURY project is happy to announce the release of FURY 0.2.0! +FURY is a free and open source software library for scientific visualization and 3D animations.

+

+ +

Read more ...

+
+
+ +
+

+ FURY 0.1.4 Released +

+
    +
  • + + + 26 November 2018 + +
  • +
    + + +
  • + + + Author: + + + + + Serge Koudoro + + + +
  • + + + + +
  • + + + Category: + + + + + release + + + +
  • + + +
  • + + + + Tag: + + + + + fury + + + +
  • + + +
    +
+

The FURY project is happy to announce the release of FURY 0.1.4! +FURY is a free and open source software library for scientific visualization and 3D animations.

+

+ +

Read more ...

+
+
+ +
+

+ FURY 0.1.3 Released +

+
    +
  • + + + 31 October 2018 + +
  • +
    + + +
  • + + + Author: + + + + + Serge Koudoro + + + +
  • + + + + +
  • + + + Category: + + + + + release + + + +
  • + + +
  • + + + + Tag: + + + + + fury + + + +
  • + + +
    +
+

The FURY project is happy to announce the release of FURY 0.1.3! +FURY is a free and open source software library for scientific visualization and 3D animations.

+

+ +

Read more ...

+
+
+ +
+

+ FURY 0.1.0 Released +

+
    +
  • + + + 21 September 2018 + +
  • +
    + + +
  • + + + Author: + + + + + Serge Koudoro + + + +
  • + + + + +
  • + + + Category: + + + + + release + + + +
  • + + +
  • + + + + Tag: + + + + + fury + + + +
  • + + +
    +
+

The FURY project is happy to announce the release of FURY 0.1.0! +FURY is a free and open source software library for scientific visualization and 3D animations.

+

+ +

Read more ...

+
+
+ + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/blog/author/serge-koudoro/atom.xml b/v0.10.x/blog/author/serge-koudoro/atom.xml new file mode 100644 index 000000000..ab1f245d5 --- /dev/null +++ b/v0.10.x/blog/author/serge-koudoro/atom.xml @@ -0,0 +1,542 @@ + + + https://fury.gl/ + Blog - Posts by Serge Koudoro + 2024-02-29T15:43:57.577702+00:00 + + + ABlog + + https://fury.gl/posts/2023/2023-04-14-release-announcement.html + FURY 0.9.0 Released + 2023-04-15T00:00:00-04:00 + + Serge Koudoro + + <section id="fury-0-9-0-released"> + +<p>The FURY project is happy to announce the release of FURY 0.9.0! +FURY is a free and open source software library for scientific visualization and 3D animations.</p> +<p>You can show your support by <a class="reference external" href="https://github.com/fury-gl/fury/stargazers">adding a star</a> on FURY github project.</p> +<p>This Release is mainly a maintenance release. The <strong>major highlights</strong> of this release are:</p> +<ul class="simple"> +<li><p>New Streaming System added.</p></li> +<li><p>Large improvement of Signed Distance Functions actors (SDF).</p></li> +<li><p>Continuous Integration (CI) platform updated. Migrate Windows CI from Azure to Github Actions</p></li> +<li><p>Migration from setuptools to hatching. versioning system updated also.</p></li> +<li><p>New module fury.animation added.</p></li> +<li><p>New module fury.gltf added. Module to support glTF 2.0.</p></li> +<li><p>Multiple tutorials added and updated.</p></li> +<li><p>Documentation updated.</p></li> +<li><p>Website updated.</p></li> +</ul> +<div class="admonition note"> +<p class="admonition-title">Note</p> +<p>The complete release notes are available <a class="reference internal" href="../../release_notes/releasev0.9.0.html#releasev0-9-0"><span class="std std-ref">here</span></a></p> +</div> +<p><strong>To upgrade or install FURY</strong></p> +<p>Run the following command in your terminal:</p> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">pip</span> <span class="n">install</span> <span class="o">--</span><span class="n">upgrade</span> <span class="n">fury</span> +</pre></div> +</div> +<p>or:</p> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">conda</span> <span class="n">install</span> <span class="o">-</span><span class="n">c</span> <span class="n">conda</span><span class="o">-</span><span class="n">forge</span> <span class="n">fury</span> +</pre></div> +</div> +<p><strong>Questions or suggestions?</strong></p> +<p>For any questions go to <a class="reference external" href="http://fury.gl">http://fury.gl</a>, or send an e-mail to <a class="reference external" href="mailto:fury&#37;&#52;&#48;python&#46;org">fury<span>&#64;</span>python<span>&#46;</span>org</a> +We can also join our <a class="reference external" href="https://discord.gg/6btFPPj">discord community</a></p> +<p>We would like to thanks to <a class="reference internal" href="../../community.html#community"><span class="std std-ref">all contributors</span></a> for this release:</p> +<ul class="simple"> +<li><p>Anand Shivam</p></li> +<li><p>Antriksh Misri</p></li> +<li><p>Bruno Messias</p></li> +<li><p>Dwij Raj Hari</p></li> +<li><p>Eleftherios Garyfallidis</p></li> +<li><p>Filipi Nascimento Silva</p></li> +<li><p>Francois Rheault</p></li> +<li><p>Frank Cerasoli</p></li> +<li><p>Javier Guaje</p></li> +<li><p>Johny Daras</p></li> +<li><p>Mohamed Agour</p></li> +<li><p>Nasim Anousheh</p></li> +<li><p>Praneeth Shetty</p></li> +<li><p>Rohit Kharsan</p></li> +<li><p>Sara Hamza</p></li> +<li><p>Serge Koudoro</p></li> +<li><p>Siddharth Gautam</p></li> +<li><p>Soham Biswas</p></li> +<li><p>Sreekar Chigurupati</p></li> +<li><p>Tania Castillo</p></li> +<li><p>Zhiwen Shi</p></li> +<li><p>maharshigor</p></li> +<li><p>sailesh</p></li> +<li><p>sparshg</p></li> +</ul> +<p>On behalf of the <a class="reference internal" href="../../community.html#community"><span class="std std-ref">FURY developers</span></a>,</p> +<p>Serge K.</p> +</section> + + + The FURY project is happy to announce the release of FURY 0.9.0! +FURY is a free and open source software library for scientific visualization and 3D animations. + + 2023-04-15T00:00:00-04:00 + + + https://fury.gl/posts/2023/2023-02-01-gsoc.html + Contribute to FURY via Google Summer of Code 2023 + 2023-02-01T00:00:00-05:00 + + Serge Koudoro + + <section id="contribute-to-fury-via-google-summer-of-code-2023"> + +<p>FURY is participating in the <a class="reference external" href="https://summerofcode.withgoogle.com">Google Summer of Code 2023</a> under the umbrella of the <a class="reference external" href="https://python-gsoc.org/">Python Software Foundation</a>.</p> +<p>FURY is a free and open source software library for scientific visualization and 3D animations. FURY contains many tools for visualizing a series of scientific data including graph and imaging data.</p> +<p>A list of project ideas and application info is on our <a class="reference external" href="https://github.com/fury-gl/fury/wiki/Google-Summer-of-Code-2023-(GSOC2023)">GitHub Wiki</a>.</p> +<p>If you are interested in talking to us about projects, applications join us to our <a class="reference external" href="https://discord.gg/aXRZmmM">discord community</a> or drop us a line on our <a class="reference external" href="https://mail.python.org/mailman3/lists/fury.python.org">mailing list</a>.</p> +<p>Be part of our community and Enjoy your summer of code!</p> +<p>Serge K.</p> +</section> + + + FURY is participating in the Google Summer of Code 2023 under the umbrella of the Python Software Foundation. + + 2023-02-01T00:00:00-05:00 + + + https://fury.gl/posts/2022/2022-02-01-gsoc.html + Contribute to FURY via Google Summer of Code 2022 + 2022-02-01T00:00:00-05:00 + + Serge Koudoro + + <section id="contribute-to-fury-via-google-summer-of-code-2022"> + +<p>FURY is participating in the <a class="reference external" href="https://summerofcode.withgoogle.com">Google Summer of Code 2022</a> under the umbrella of the <a class="reference external" href="https://python-gsoc.org/">Python Software Foundation</a>.</p> +<p>FURY is a free and open source software library for scientific visualization and 3D animations. FURY contains many tools for visualizing a series of scientific data including graph and imaging data.</p> +<p>A list of project ideas and application info is on our <a class="reference external" href="https://github.com/fury-gl/fury/wiki/Google-Summer-of-Code-2022-(GSOC2022)">GitHub Wiki</a>.</p> +<p>If you are interested in talking to us about projects, applications join us to our <a class="reference external" href="https://discord.gg/aXRZmmM">discord community</a> or drop us a line on our <a class="reference external" href="https://mail.python.org/mailman3/lists/fury.python.org">mailing list</a>.</p> +<p>Be part of our community and Enjoy your summer of code!</p> +<p>Serge K.</p> +</section> + + + FURY is participating in the Google Summer of Code 2022 under the umbrella of the Python Software Foundation. + + 2022-02-01T00:00:00-05:00 + + + https://fury.gl/posts/2022/2022-01-31-release-announcement.html + FURY 0.8.0 Released + 2022-01-31T00:00:00-05:00 + + Serge Koudoro + + <section id="fury-0-8-0-released"> + +<p>The FURY project is happy to announce the release of FURY 0.8.0! +FURY is a free and open source software library for scientific visualization and 3D animations.</p> +<p>You can show your support by <a class="reference external" href="https://github.com/fury-gl/fury/stargazers">adding a star</a> on FURY github project.</p> +<p>This Release is mainly a maintenance release. The <strong>major highlights</strong> of this release are:</p> +<ul class="simple"> +<li><p>New Physically Based Rendering (PBR) added. It includes anisotropic rotation and index of refraction among other material properties.</p></li> +<li><p>New Principled BRDF shader unique to FURY added. BRDF stands for bidirectional reflectance distribution function.</p></li> +<li><p>VTK 9.1.0 defined as minimum version.</p></li> +<li><p>Continuous Integration (CI) platform updated.</p></li> +<li><p>New actors added (Rhombicuboctahedron, Pentagonal Prism).</p></li> +<li><p>New UI layouts added (Vertical and Horizontal).</p></li> +<li><p>New module fury.molecular added.</p></li> +<li><p>New module fury.lib added. Module improved loading speed.</p></li> +<li><p>Demos added and updated.</p></li> +<li><p>Documentation updated.</p></li> +</ul> +<div class="admonition note"> +<p class="admonition-title">Note</p> +<p>The complete release notes are available <a class="reference internal" href="../../release_notes/releasev0.8.0.html#releasev0-8-0"><span class="std std-ref">here</span></a></p> +</div> +<p><strong>To upgrade or install FURY</strong></p> +<p>Run the following command in your terminal:</p> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">pip</span> <span class="n">install</span> <span class="o">--</span><span class="n">upgrade</span> <span class="n">fury</span> +</pre></div> +</div> +<p>or:</p> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">conda</span> <span class="n">install</span> <span class="o">-</span><span class="n">c</span> <span class="n">conda</span><span class="o">-</span><span class="n">forge</span> <span class="n">fury</span> +</pre></div> +</div> +<p><strong>Questions or suggestions?</strong></p> +<p>For any questions go to <a class="reference external" href="http://fury.gl">http://fury.gl</a>, or send an e-mail to <a class="reference external" href="mailto:fury&#37;&#52;&#48;python&#46;org">fury<span>&#64;</span>python<span>&#46;</span>org</a> +We can also join our <a class="reference external" href="https://discord.gg/6btFPPj">discord community</a></p> +<p>We would like to thanks to <a class="reference internal" href="../../community.html#community"><span class="std std-ref">all contributors</span></a> for this release:</p> +<ul class="simple"> +<li><p>Anand Shivam</p></li> +<li><p>Antriksh Misri</p></li> +<li><p>Bruno Messias</p></li> +<li><p>Eleftherios Garyfallidis</p></li> +<li><p>Javier Guaje</p></li> +<li><p>Marc-Alexandre Côté</p></li> +<li><p>Meha Bhalodiya</p></li> +<li><p>Praneeth Shetty</p></li> +<li><p>PrayasJ</p></li> +<li><p>Sajag Swami</p></li> +<li><p>Serge Koudoro</p></li> +<li><p>Shivam Anand</p></li> +</ul> +<p>On behalf of the <a class="reference internal" href="../../community.html#community"><span class="std std-ref">FURY developers</span></a>,</p> +<p>Serge K.</p> +</section> + + + The FURY project is happy to announce the release of FURY 0.8.0! +FURY is a free and open source software library for scientific visualization and 3D animations. + + 2022-01-31T00:00:00-05:00 + + + https://fury.gl/posts/2021/2021-08-03-release-announcement.html + FURY 0.7.0 Released + 2021-08-03T00:00:00-04:00 + + Serge Koudoro + + <section id="fury-0-7-0-released"> + +<p>The FURY project is happy to announce the release of FURY 0.7.1! +FURY is a free and open source software library for scientific visualization and 3D animations.</p> +<p>You can show your support by <a class="reference external" href="https://github.com/fury-gl/fury/stargazers">adding a star</a> on FURY github project.</p> +<p>This Release is mainly a maintenance release. The <strong>major highlights</strong> of this release are:</p> +<ul class="simple"> +<li><p>FURY paper added.</p></li> +<li><p>Fast selection of multiple objects added.</p></li> +<li><p>UI refactored.</p></li> +<li><p>Tests coverage increased.</p></li> +<li><p>New actor (Marker) added.</p></li> +<li><p>New primitive (Triangular Prism) added.</p></li> +<li><p>Demos added and updated.</p></li> +<li><p>Large Documentation Update.</p></li> +</ul> +<div class="admonition note"> +<p class="admonition-title">Note</p> +<p>The complete release notes are available <a class="reference internal" href="../../release_notes/releasev0.7.1.html#releasev0-7-1"><span class="std std-ref">here</span></a></p> +</div> +<p><strong>To upgrade or install FURY</strong></p> +<p>Run the following command in your terminal:</p> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">pip</span> <span class="n">install</span> <span class="o">--</span><span class="n">upgrade</span> <span class="n">fury</span> +</pre></div> +</div> +<p>or:</p> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">conda</span> <span class="n">install</span> <span class="o">-</span><span class="n">c</span> <span class="n">conda</span><span class="o">-</span><span class="n">forge</span> <span class="n">fury</span> +</pre></div> +</div> +<p><strong>Questions or suggestions?</strong></p> +<p>For any questions go to <a class="reference external" href="http://fury.gl">http://fury.gl</a>, or send an e-mail to <a class="reference external" href="mailto:fury&#37;&#52;&#48;python&#46;org">fury<span>&#64;</span>python<span>&#46;</span>org</a> +We can also join our <a class="reference external" href="https://discord.gg/6btFPPj">discord community</a></p> +<p>We would like to thanks to <a class="reference internal" href="../../community.html#community"><span class="std std-ref">all contributors</span></a> for this release:</p> +<ul class="simple"> +<li><p>Amit Chaudhari</p></li> +<li><p>Antriksh Misri</p></li> +<li><p>Bruno Messias</p></li> +<li><p>Daniel S. Katz</p></li> +<li><p>Eleftherios Garyfallidis</p></li> +<li><p>Gurdit Siyan</p></li> +<li><p>Javier Guaje</p></li> +<li><p>Jhalak Gupta</p></li> +<li><p>LoopThrough-i-j</p></li> +<li><p>MIHIR</p></li> +<li><p>Praneeth Shetty</p></li> +<li><p>Sajag Swami</p></li> +<li><p>Serge Koudoro</p></li> +<li><p>Hariharan Ayappane</p></li> +</ul> +<p>On behalf of the <a class="reference internal" href="../../community.html#community"><span class="std std-ref">FURY developers</span></a>,</p> +<p>Serge K.</p> +</section> + + + The FURY project is happy to announce the release of FURY 0.7.1! +FURY is a free and open source software library for scientific visualization and 3D animations. + + 2021-08-03T00:00:00-04:00 + + + https://fury.gl/posts/2021/2021-03-13-release-announcement.html + FURY 0.7.0 Released + 2021-03-13T00:00:00-05:00 + + Serge Koudoro + + <section id="fury-0-7-0-released"> + +<p>The FURY project is happy to announce the release of FURY 0.7.0! +FURY is a free and open source software library for scientific visualization and 3D animations.</p> +<p>You can show your support by <a class="reference external" href="https://github.com/fury-gl/fury/stargazers">adding a star</a> on FURY github project.</p> +<p>This Release is mainly a maintenance release. The <strong>major highlights</strong> of this release are:</p> +<ul class="simple"> +<li><p>New SDF actors added.</p></li> +<li><p>Materials module added.</p></li> +<li><p>ODF slicer actor performance improved.</p></li> +<li><p>New primitive (Cylinder) added.</p></li> +<li><p>Compatibility with VTK 9 added.</p></li> +<li><p>Five new demos added.</p></li> +<li><p>Large Documentation Update.</p></li> +<li><p>Migration from Travis to Github Action.</p></li> +</ul> +<div class="admonition note"> +<p class="admonition-title">Note</p> +<p>The complete release notes are available <a class="reference internal" href="../../release_notes/releasev0.7.0.html#releasev0-7-0"><span class="std std-ref">here</span></a></p> +</div> +<p><strong>To upgrade or install FURY</strong></p> +<p>Run the following command in your terminal:</p> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">pip</span> <span class="n">install</span> <span class="o">--</span><span class="n">upgrade</span> <span class="n">fury</span> +</pre></div> +</div> +<p>or:</p> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">conda</span> <span class="n">install</span> <span class="o">-</span><span class="n">c</span> <span class="n">conda</span><span class="o">-</span><span class="n">forge</span> <span class="n">fury</span> +</pre></div> +</div> +<p><strong>Questions or suggestions?</strong></p> +<p>For any questions go to <a class="reference external" href="http://fury.gl">http://fury.gl</a>, or send an e-mail to <a class="reference external" href="mailto:fury&#37;&#52;&#48;python&#46;org">fury<span>&#64;</span>python<span>&#46;</span>org</a> +We can also join our <a class="reference external" href="https://discord.gg/6btFPPj">discord community</a></p> +<p>We would like to thanks to <a class="reference internal" href="../../community.html#community"><span class="std std-ref">all contributors</span></a> for this release:</p> +<ul class="simple"> +<li><p>Eleftherios Garyfallidis</p></li> +<li><p>Serge Koudoro</p></li> +<li><p>Charles Poirier</p></li> +<li><p>Javier Guaje</p></li> +<li><p>Soham Biswas</p></li> +<li><p>Sajag Swami</p></li> +<li><p>Lenix Lobo</p></li> +<li><p>Pietro Astolfi</p></li> +<li><p>Sanjay Marreddi</p></li> +<li><p>Tushar</p></li> +<li><p>ganimtron-10</p></li> +<li><p>haran2001</p></li> +<li><p>Aju100</p></li> +<li><p>Aman Soni</p></li> +</ul> +<p>On behalf of the <a class="reference internal" href="../../community.html#community"><span class="std std-ref">FURY developers</span></a>,</p> +<p>Serge K.</p> +</section> + + + The FURY project is happy to announce the release of FURY 0.7.0! +FURY is a free and open source software library for scientific visualization and 3D animations. + + 2021-03-13T00:00:00-05:00 + + + https://fury.gl/posts/2021/2021-03-09-gsoc.html + Google Summer of Code + 2021-03-09T00:00:00-05:00 + + Serge Koudoro + + <section id="google-summer-of-code"> + +<p>FURY is participating in the <a class="reference external" href="https://summerofcode.withgoogle.com/">Google Summer of Code 2021</a> under the umbrella of the <a class="reference external" href="https://python-gsoc.org/">Python Software Foundation</a>.</p> +<p>FURY is a free and open source software library for scientific visualization and 3D animations. FURY contains many tools for visualizing a series of scientific data including graph and imaging data.</p> +<p>A list of project ideas and application info is on our <a class="reference external" href="https://github.com/fury-gl/fury/wiki/Google-Summer-of-Code-2021">GitHub Wiki</a>.</p> +<p>If you are interested in talking to us about projects, applications join us to our <a class="reference external" href="https://discord.gg/aXRZmmM">discord community</a> or drop us a line on our <a class="reference external" href="https://mail.python.org/mailman3/lists/fury.python.org">mailing list</a>.</p> +<p>Be part of our community and Enjoy your summer of code!</p> +<p>Serge K.</p> +</section> + + + FURY is participating in the Google Summer of Code 2021 under the umbrella of the Python Software Foundation. + + 2021-03-09T00:00:00-05:00 + + + https://fury.gl/posts/2020/2020-08-18-release-announcement.html + FURY 0.6.1 Released + 2020-08-18T00:00:00-04:00 + + Serge Koudoro + + <section id="fury-0-6-1-released"> + +<p>The FURY project is happy to announce the release of FURY 0.6.1! +FURY is a free and open source software library for scientific visualization and 3D animations.</p> +<p>You can show your support by <a class="reference external" href="https://github.com/fury-gl/fury/stargazers">adding a star</a> on FURY github project.</p> +<p>This Release is mainly a maintenance release. The <strong>major highlights</strong> of this release are:</p> +<ul class="simple"> +<li><p>Added Shaders Manager.</p></li> +<li><p>Standardized colors across API.</p></li> +<li><p>Added a new UI Tab.</p></li> +<li><p>Added Physics Engine Tutorial.</p></li> +<li><p>Large documentation update, examples and tutorials (4 new).</p></li> +<li><p>Increased tests coverage and code quality.</p></li> +</ul> +<div class="admonition note"> +<p class="admonition-title">Note</p> +<p>The complete release notes are available <a class="reference internal" href="../../release_notes/releasev0.6.1.html#releasev0-6-1"><span class="std std-ref">here</span></a></p> +</div> +<p><strong>To upgrade or install FURY</strong></p> +<p>Run the following command in your terminal:</p> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">pip</span> <span class="n">install</span> <span class="o">--</span><span class="n">upgrade</span> <span class="n">fury</span> +</pre></div> +</div> +<p>or:</p> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">conda</span> <span class="n">install</span> <span class="o">-</span><span class="n">c</span> <span class="n">conda</span><span class="o">-</span><span class="n">forge</span> <span class="n">fury</span> +</pre></div> +</div> +<p><strong>Questions or suggestions?</strong></p> +<p>For any questions go to <a class="reference external" href="http://fury.gl">http://fury.gl</a>, or send an e-mail to <a class="reference external" href="mailto:fury&#37;&#52;&#48;python&#46;org">fury<span>&#64;</span>python<span>&#46;</span>org</a> +We can also join our <a class="reference external" href="https://discord.gg/6btFPPj">discord community</a></p> +<p>We would like to thanks to <a class="reference internal" href="../../community.html#community"><span class="std std-ref">all contributors</span></a> for this release:</p> +<ul class="simple"> +<li><p>Eleftherios Garyfallidis</p></li> +<li><p>Javier Guaje</p></li> +<li><p>Lenix Lobo</p></li> +<li><p>Melina Raglin</p></li> +<li><p>Nasim Anousheh</p></li> +<li><p>Serge Koudoro</p></li> +<li><p>Soham Biswas</p></li> +<li><p>Vivek Choudhary</p></li> +</ul> +<p>On behalf of the <a class="reference internal" href="../../community.html#community"><span class="std std-ref">FURY developers</span></a>,</p> +<p>Serge K.</p> +</section> + + + The FURY project is happy to announce the release of FURY 0.6.1! +FURY is a free and open source software library for scientific visualization and 3D animations. + + 2020-08-18T00:00:00-04:00 + + + https://fury.gl/posts/2020/2020-07-20-release-announcement.html + FURY 0.6.0 Released + 2020-07-20T00:00:00-04:00 + + Serge Koudoro + + <section id="fury-0-6-0-released"> + +<p>The FURY project is happy to announce the release of FURY 0.6.0! +FURY is a free and open source software library for scientific visualization and 3D animations.</p> +<p>You can show your support by <a class="reference external" href="https://github.com/fury-gl/fury/stargazers">adding a star</a> on FURY github project.</p> +<p>The <strong>major highlights</strong> of this release are:</p> +<ul class="simple"> +<li><p>Added new features: Picking and double-click callback.</p></li> +<li><p>Added Signed Distance Field actor.</p></li> +<li><p>Added a new UI ComboBox.</p></li> +<li><p>Added multiples primitives (Rhombocuboctahedron, …).</p></li> +<li><p>Huge improvement of multiple UIs and actors.</p></li> +<li><p>Fixed Compatibility with VTK9.</p></li> +<li><p>Large documentation update, examples and tutorials (5 new).</p></li> +<li><p>Added a blog system.</p></li> +<li><p>Increased tests coverage and code quality.</p></li> +</ul> +<div class="admonition note"> +<p class="admonition-title">Note</p> +<p>The complete release notes are available <a class="reference internal" href="../../release_notes/releasev0.6.0.html#releasev0-6-0"><span class="std std-ref">here</span></a></p> +</div> +<p><strong>To upgrade or install FURY</strong></p> +<p>Run the following command in your terminal:</p> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">pip</span> <span class="n">install</span> <span class="o">--</span><span class="n">upgrade</span> <span class="n">fury</span> +</pre></div> +</div> +<p>or:</p> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">conda</span> <span class="n">install</span> <span class="o">-</span><span class="n">c</span> <span class="n">conda</span><span class="o">-</span><span class="n">forge</span> <span class="n">fury</span> +</pre></div> +</div> +<p><strong>Questions or suggestions?</strong></p> +<p>For any questions go to <a class="reference external" href="http://fury.gl">http://fury.gl</a>, or send an e-mail to <a class="reference external" href="mailto:fury&#37;&#52;&#48;python&#46;org">fury<span>&#64;</span>python<span>&#46;</span>org</a> +We can also join our <a class="reference external" href="https://discord.gg/6btFPPj">discord community</a></p> +<p>We would like to thanks to <a class="reference internal" href="../../community.html#community"><span class="std std-ref">all contributors</span></a> for this release:</p> +<ul class="simple"> +<li><p>Eleftherios Garyfallidis</p></li> +<li><p>Liam Donohue</p></li> +<li><p>Marc-Alexandre Côté</p></li> +<li><p>Melina Raglin</p></li> +<li><p>Naman Bansal</p></li> +<li><p>Serge Koudoro</p></li> +<li><p>Soham Biswas</p></li> +<li><p>Tushar</p></li> +<li><p>Lenix Lobo</p></li> +</ul> +<p>On behalf of the <a class="reference internal" href="../../community.html#community"><span class="std std-ref">FURY developers</span></a>,</p> +<p>Serge K.</p> +</section> + + + The FURY project is happy to announce the release of FURY 0.6.0! +FURY is a free and open source software library for scientific visualization and 3D animations. + + 2020-07-20T00:00:00-04:00 + + + https://fury.gl/posts/2020/2020-04-09-release-announcement.html + FURY 0.5.1 Released + 2020-04-09T00:00:00-04:00 + + Serge Koudoro + + <section id="fury-0-5-1-released"> + +<p>The FURY project is happy to announce the release of FURY 0.5.1! +FURY is a free and open source software library for scientific visualization and 3D animations.</p> +<p>You can show your support by <a class="reference external" href="https://github.com/fury-gl/fury/stargazers">adding a star</a> on FURY github project.</p> +<p>The <strong>major highlights</strong> of this release are:</p> +<ul class="simple"> +<li><p>Remove python 2 compatibility</p></li> +<li><p>Added texture management</p></li> +<li><p>Added multiples primitives.</p></li> +<li><p>Added multiples actors (contour_from_label, billboard…)</p></li> +<li><p>Huge improvement of multiple UI (RangeSlider, …)</p></li> +<li><p>Improved security (from md5 to sha256)</p></li> +<li><p>Large documentation update, examples and tutorials</p></li> +<li><p>Increased tests coverage and code quality</p></li> +</ul> +<div class="admonition note"> +<p class="admonition-title">Note</p> +<p>The complete release notes are available <a class="reference internal" href="../../release_notes/releasev0.5.1.html#releasev0-5-1"><span class="std std-ref">here</span></a></p> +</div> +<p><strong>To upgrade or install FURY</strong></p> +<p>Run the following command in your terminal:</p> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">pip</span> <span class="n">install</span> <span class="o">--</span><span class="n">upgrade</span> <span class="n">fury</span> +</pre></div> +</div> +<p>or:</p> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">conda</span> <span class="n">install</span> <span class="o">-</span><span class="n">c</span> <span class="n">conda</span><span class="o">-</span><span class="n">forge</span> <span class="n">fury</span> +</pre></div> +</div> +<p><strong>Questions or suggestions?</strong></p> +<p>For any questions go to <a class="reference external" href="http://fury.gl">http://fury.gl</a>, or send an e-mail to <a class="reference external" href="mailto:fury&#37;&#52;&#48;python&#46;org">fury<span>&#64;</span>python<span>&#46;</span>org</a> +We can also join our <a class="reference external" href="https://discord.gg/6btFPPj">discord community</a></p> +<p>We would like to thanks to <a class="reference internal" href="../../community.html#community"><span class="std std-ref">all contributors</span></a> for this release:</p> +<ul class="simple"> +<li><p>ChenCheng0630</p></li> +<li><p>Devanshu Modi</p></li> +<li><p>Eleftherios Garyfallidis</p></li> +<li><p>Etienne St-Onge</p></li> +<li><p>Filipi Nascimento Silva</p></li> +<li><p>Gottipati Gautam</p></li> +<li><p>Javier Guaje</p></li> +<li><p>Jon Haitz Legarreta Gorroño</p></li> +<li><p>Liam Donohue</p></li> +<li><p>Marc-Alexandre Côté</p></li> +<li><p>Marssis</p></li> +<li><p>Naman Bansal</p></li> +<li><p>Nasim</p></li> +<li><p>Saransh Jain</p></li> +<li><p>Serge Koudoro</p></li> +<li><p>Shreyas Bhujbal</p></li> +<li><p>Soham Biswas</p></li> +<li><p>Vivek Choudhary</p></li> +<li><p>ibrahimAnis</p></li> +<li><p>lenixlobo</p></li> +</ul> +<p>On behalf of the <a class="reference internal" href="../../community.html#community"><span class="std std-ref">FURY developers</span></a>,</p> +<p>Serge K.</p> +</section> + + + The FURY project is happy to announce the release of FURY 0.5.1! +FURY is a free and open source software library for scientific visualization and 3D animations. + + 2020-04-09T00:00:00-04:00 + + diff --git a/v0.10.x/blog/author/shivam-anand.html b/v0.10.x/blog/author/shivam-anand.html new file mode 100644 index 000000000..9e3bb1a2f --- /dev/null +++ b/v0.10.x/blog/author/shivam-anand.html @@ -0,0 +1,1537 @@ + + + + + + + Posts by Shivam Anand — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +
+

+ + Posts by + + Shivam Anand + +

+ + +
+

+ Google Summer of Code Final Work Product +

+
    +
  • + + + 29 January 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Shivam Anand + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Name: Shivam Anand

+

+ +

Read more ...

+
+
+ +
+

+ Week 14 - Morphing is here! +

+
    +
  • + + + 28 September 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Shivam Anand + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week, I started with multiple actor support in skinning and managed to do it +successfully. Here’s the preview using the BrainStem model.

+

+ +

Read more ...

+
+
+ +
+

+ Week 13 - Multi-bone skeletal animation support +

+
    +
  • + + + 15 September 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Shivam Anand + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week I fixed all the issues with skeletal animations, and we got to see our first render of skeletal animation :).

+

+ +

Read more ...

+
+
+ +
+

+ Week 12 - Adding skeleton as actors and fix global transformation +

+
    +
  • + + + 08 September 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Shivam Anand + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

I started this week by fixing the segmentation fault for the skinning test. I could not fix this as of now.

+

+ +

Read more ...

+
+
+ +
+

+ Week 11 - Multiple transformations support and adding tests +

+
    +
  • + + + 31 August 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Shivam Anand + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

As decided last week, I added support for multiple animations at the same timestamp. But this didn’t solve the animation problems of RiggedSimple model.

+

+ +

Read more ...

+
+
+ +
+

+ Week 10 - Multi-node skinning support +

+
    +
  • + + + 25 August 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Shivam Anand + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

As we figured out that the SimpleSkin model is not animated as intended. This week I started working with that model; +I figured out that we need to apply the InverseBindMatrix to each timer callback. I had a hard time figuring out what inverse bind matrix actually does. +Here’s a good blog that answers that.

+

+ +

Read more ...

+
+
+ +
+

+ Week 9 - First working skeletal animation prototype +

+
    +
  • + + + 17 August 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Shivam Anand + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week I had the first working example of skeletal animation ready. I was able to render the SimpleSkin model. Here’s a quick preview:

+

+ +

Read more ...

+
+
+ +
+

+ Week 8 - Fixing animation bugs +

+
    +
  • + + + 10 August 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Shivam Anand + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week I had to fix the transformation issue in glTF animation. As discussed in the last meeting, I disabled vertex transformation and applied the transformation after the actor was formed.

+

+ +

Read more ...

+
+
+ +
+

+ Week 7 - Fixing bugs in animations +

+
    +
  • + + + 01 August 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Shivam Anand + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week I started with implementing scaling to the animation example.

+

+ +

Read more ...

+
+
+ +
+

+ Week 6 - Extracting the animation data +

+
    +
  • + + + 25 July 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Shivam Anand + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week, it was all about reading docs and extracting the animation data from buffers.

+

+ +

Read more ...

+
+
+ +
+

+ Week 5 - Creating PR for glTF exporter and fixing the loader +

+
    +
  • + + + 19 July 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Shivam Anand + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Finalised the glTF export PR #630., adding tutorial, docs, and tests for all functions.

+

+ +

Read more ...

+
+
+ +
+

+ Week 4 - Finalizing glTF loader +

+
    +
  • + + + 12 July 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Shivam Anand + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week I had to travel back to my college since the summer vacations have ended. +I had a coding session with Serge this week, we modified the exporter function and looked at some bugs I faced.

+

+ +

Read more ...

+
+
+ +
+

+ Week 3 - Fixing fetcher, adding tests and docs +

+
    +
  • + + + 04 July 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Shivam Anand + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

The first task for this week was to fix the glTF fetcher. We noticed that while running tests it reaches the API limit. So we decided to use a JSON file that contains the download URLs for all models.

+

+ +

Read more ...

+
+
+ +
+

+ Week 2 - Improving Fetcher and Exporting glTF +

+
    +
  • + + + 29 June 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Shivam Anand + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week I worked primarily on the glTF fetcher and exporting scenes to a glTF file. I added tests and docstrings for all functions. I modified the fetch_gltf function to return the downloaded files. As we planned, the PR for the glTF fetcher was merged this week.

+

+ +

Read more ...

+
+
+ +
+

+ Week 1 - A Basic glTF Importer +

+
    +
  • + + + 20 June 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Shivam Anand + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

In the community bonding period I met with my mentor Serge Koudoro, along with other mentors in FURY and gsoc contributors. +We discussed about my project and set up project timeline on github projects section. As my project (glTF Integration) +and Keyframe animations were related so we discussed on that too.

+

+ +

Read more ...

+
+
+ + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/blog/author/shivam-anand/atom.xml b/v0.10.x/blog/author/shivam-anand/atom.xml new file mode 100644 index 000000000..f5b06fa7e --- /dev/null +++ b/v0.10.x/blog/author/shivam-anand/atom.xml @@ -0,0 +1,820 @@ + + + https://fury.gl/ + Blog - Posts by Shivam Anand + 2024-02-29T15:43:57.519350+00:00 + + + ABlog + + https://fury.gl/posts/2023/2023-01-29-final-report-shivam.html + Google Summer of Code Final Work Product + 2023-01-29T00:00:00-05:00 + + Shivam Anand + + <center><a href="https://summerofcode.withgoogle.com/programs/2022/projects/ZZQ6IrHq"><img src="https://developers.google.com/open-source/gsoc/resources/downloads/GSoC-logo-horizontal.svg" alt="gsoc" height="50"/></a></center><center> +<a href="https://summerofcode.withgoogle.com/projects/#6653942668197888"><img src="https://www.python.org/static/community_logos/python-logo.png" height="45"/></a> +<a href="https://fury.gl/latest/community.html"><img src="https://python-gsoc.org/logos/FURY.png" alt="fury" height="45"/></a> +</center><section id="google-summer-of-code-final-work-product"> + +<ul class="simple"> +<li><p><strong>Name:</strong> Shivam Anand</p></li> +<li><p><strong>Organisation:</strong> Python Software Foundation</p></li> +<li><p><strong>Sub-Organisation:</strong> FURY</p></li> +<li><p><strong>Project:</strong> <a class="reference external" href="https://github.com/fury-gl/fury/wiki/Google-Summer-of-Code-2022">FURY - glTF +Integration</a></p></li> +</ul> +<section id="proposed-objectives"> +<h2>Proposed Objectives</h2> +<ul class="simple"> +<li><p>Ability to load glTF models</p> +<ul> +<li><p>Should be able to load static glTF models</p></li> +<li><p>Should be able to add model to the scene.</p></li> +</ul> +</li> +<li><p>Exporting scene data as glTF file</p></li> +<li><p>Materials &amp; Textures</p> +<ul> +<li><p>Textures</p></li> +<li><p>PBRs</p></li> +</ul> +</li> +<li><p>Animations</p> +<ul> +<li><p>Simple Actor animations</p></li> +<li><p>Skinning</p></li> +<li><p>Morphing</p></li> +</ul> +</li> +<li><p>Stretch Goals</p> +<ul> +<li><p>Ability to load <code class="docutils literal notranslate"><span class="pre">.glb</span></code> files</p></li> +</ul> +</li> +</ul> +</section> +<section id="objectives-completed"> +<h2>Objectives Completed</h2> +<section id="loading-static-gltf-models"> +<h3>Loading Static glTF models</h3> +<p>A glTF file is a JSON like file format containing required data for 3D scenes. VTK has two built-in glTF loaders. However, they lack ability to animate and apply materials. Added methods to load binary +data and create actors from them. These actors can be added directly +to the scene. The glTF class reads texture data from either +<code class="docutils literal notranslate"><span class="pre">base64</span></code> encoded string or from the image file, and maps the +texture to the actor using the given UV data. It is capable of doing +the following:</p> +<ul class="simple"> +<li><p>Loading both <code class="docutils literal notranslate"><span class="pre">gltf</span></code> and <code class="docutils literal notranslate"><span class="pre">glb</span></code> files. Get actors from the +model.</p></li> +<li><p>Applying textures and colors from materials.</p></li> +<li><p>Setting cameras if the model contains multiple cameras.</p></li> +<li><p>Apply normals (for a smoother surface).</p></li> +</ul> +<figure class="align-default"> +<img alt="image" src="https://user-images.githubusercontent.com/74976752/174492510-b9f10816-3058-4a7b-a260-0627406354ba.png" /> +</figure> +<p><em>Pull Requests:</em></p> +<ul class="simple"> +<li><p><strong>Importing glTF files: (Merged)</strong> +<a class="github reference external" href="https://github.com/fury-gl/fury/pull/600">fury-gl/fury#600</a></p></li> +<li><p><strong>Loading glTF Demo (with textures) (Merged):</strong> +<a class="github reference external" href="https://github.com/fury-gl/fury/pull/600">fury-gl/fury#600</a></p></li> +</ul> +</section> +<section id="exporting-scene-as-a-gltf"> +<h3>Exporting Scene as a glTF</h3> +<p>The fury scene can contain multiple objects such as actors, cameras, +textures, etc. We need to get the primitive information (such as +Vertices, Triangles, UVs, Normals, etc.) from these objects and store +them into a <code class="docutils literal notranslate"><span class="pre">.bin</span></code> file. Added methods that export these +information to a <code class="docutils literal notranslate"><span class="pre">.gltf</span></code> or <code class="docutils literal notranslate"><span class="pre">.glb</span></code> file format.</p> +<p><em>Pull Requests:</em></p> +<ul class="simple"> +<li><p><strong>Exporting scene as glTF: (Merged)</strong> +<a class="github reference external" href="https://github.com/fury-gl/fury/pull/630">fury-gl/fury#630</a></p></li> +<li><p><strong>Exporting scene as glTF Tutorial: (Merged)</strong> +<a class="github reference external" href="https://github.com/fury-gl/fury/pull/630">fury-gl/fury#630</a></p></li> +</ul> +</section> +<section id="simple-actor-animations"> +<h3>Simple Actor Animations</h3> +<p>Added simple actor animations (translation, rotation &amp; scale of +actors) support. The animation data (transformation and timestamp) is +stored in buffers. It converts the binary data to ndarrays and +creates a timleline for each animation in glTF animations. This +timeline contains actors an can be added to the scene. We can animate +the scene by updating timeline inside a timer callback.</p> +<img alt="https://user-images.githubusercontent.com/74976752/217645594-6054ea83-12e5-4868-b6a1-eee5a154bd26.gif" class="align-center" src="https://user-images.githubusercontent.com/74976752/217645594-6054ea83-12e5-4868-b6a1-eee5a154bd26.gif" style="width: 480px;" /> +<p><em>Pull Requests:</em></p> +<ul class="simple"> +<li><p><strong>Simple Animations in glTF: (Merged)</strong> +<a class="github reference external" href="https://github.com/fury-gl/fury/pull/643">fury-gl/fury#643</a></p></li> +<li><p><strong>Simple Animations in glTF Tutorial: (Merged)</strong> +<a class="github reference external" href="https://github.com/fury-gl/fury/pull/643">fury-gl/fury#643</a></p></li> +</ul> +</section> +<section id="morphing-in-gltf"> +<h3>Morphing in glTF</h3> +<p>glTF allows us to animate meshes using morph targets. A morph target +stores displacements or differences for certain mesh attributes. At +runtime, these differences may be added to the original mesh, with +different weights, to animate parts of the mesh. Added methods to +extract this information, update the timeline and apply morphing to +each actor in the scene.</p> +<img alt="https://user-images.githubusercontent.com/74976752/217645485-153ec403-6c87-4282-8907-30d921106b34.gif" class="align-center" src="https://user-images.githubusercontent.com/74976752/217645485-153ec403-6c87-4282-8907-30d921106b34.gif" style="width: 480px;" /> +<p><em>Pull Requests:</em></p> +<ul class="simple"> +<li><p><strong>Morphing support in glTF: (Under Review)</strong> +<a class="github reference external" href="https://github.com/fury-gl/fury/pull/700">fury-gl/fury#700</a></p></li> +<li><p><strong>Morphing in glTF demo: (Under Review)</strong> +<a class="github reference external" href="https://github.com/fury-gl/fury/pull/700">fury-gl/fury#700</a></p></li> +</ul> +</section> +<section id="skeletal-animations-skining"> +<h3>Skeletal Animations (Skining)</h3> +<p>Another way of animating a glTF is by skinning. It allows the +geometry (vertices) of a mesh to be deformed based on the pose of a +skeleton. This is essential in order to give animated geometry. It +combines every parameter of a glTF file. While working with skinning, +we need to keep track of the parent-child hierarchy of +transformations. Vertex Skinning takes full advantage of newly +implemented <code class="docutils literal notranslate"><span class="pre">Timeline</span></code> &amp; <code class="docutils literal notranslate"><span class="pre">Animation</span></code> modules to track +hierarchical transformation order. Though the current version of the +skinning implementation works with most of the glTF sample modes, It +struggles with models that have multiple actors (e.g. BrainStem). It +can be fixed by using the vertex shader to update the vertices. The +current implementation of skinning supports the following:</p> +<ul class="simple"> +<li><p>Multiple animation support</p></li> +<li><p>Multiple node and multiple actor animation with textures</p></li> +<li><p>Show or hide bones/skeleton of the model.</p></li> +</ul> +<img alt="https://user-images.githubusercontent.com/74976752/217645367-f901c6ed-ca20-40d6-92dd-f1cd8899ac7a.gif" class="align-center" src="https://user-images.githubusercontent.com/74976752/217645367-f901c6ed-ca20-40d6-92dd-f1cd8899ac7a.gif" style="width: 480px;" /> +<p><em>Pull Requests:</em></p> +<ul class="simple"> +<li><p><strong>Skinning support in glTF: (Under Review)</strong> +<a class="github reference external" href="https://github.com/fury-gl/fury/pull/685">fury-gl/fury#685</a></p></li> +<li><p><strong>Skinning in glTF demo: (Under Review)</strong> +<a class="github reference external" href="https://github.com/fury-gl/fury/pull/685">fury-gl/fury#685</a></p></li> +</ul> +</section> +</section> +<section id="objectives-in-progress"> +<h2>Objectives in Progress</h2> +<section id="pbr-and-emission-materials-in-gltf"> +<h3>PBR and emission materials in glTF</h3> +<p>The glTF format supports Physically based rendering also. PBR allow +renderers to display objects with a realistic appearance under +different lighting conditions, the shading model has to take the +physical properties of the object surface into account. There are +different representations of these physical material properties. One +that is frequently used is the metallic-roughness-model. We have +various material properties already in FURY, we need to apply it to +glTF models as well.</p> +</section> +<section id="skinning-for-models-with-no-indices"> +<h3>Skinning for models with no indices</h3> +<p>The glTF format supports non-indexed geometry (e.g., the <code class="docutils literal notranslate"><span class="pre">Fox</span></code> +model). We currently do not know how to render the model without +indices. I tried estimating it in this +<a class="reference external" href="https://github.com/xtanion/fury/blob/gltf-indices-fix/fury/gltf.py">branch</a>. +However, It fails to render in skinning.</p> +<p><em>Branch URL:</em></p> +<ul class="simple"> +<li><p><strong>Rendering glTF with no indices: (in-progress)</strong> +<a class="github reference external" href="https://github.com/xtanion/fury/blob/gltf-indices-fix/fury/gltf.py">xtanion/fury</a></p></li> +</ul> +</section> +</section> +<section id="other-objectives"> +<h2>Other Objectives</h2> +<section id="fetcher-for-importing-gltf-files-from-khronos-gltf-samples"> +<h3>Fetcher for importing glTF files from Khronos-glTF-Samples</h3> +<p>The +<a class="reference external" href="https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0/">KhronosGroup/gltf-samples</a> +contain multiple glTF sample models to test a glTF viewer for free. +Implemented new methods in fetcher that can load all of these models +by (using type) asynchronously. The glTF fetcher is capable +of the following:</p> +<ul class="simple"> +<li><p>Downloading multiple models asynchronously.</p></li> +<li><p>Get the path to the downloaded model using it - Download any model using the URL of the model.</p></li> +</ul> +<p><em>Pull Requests:</em></p> +<ul class="simple"> +<li><p><strong>Fetching glTF sample models from github: (Merged)</strong> +<a class="github reference external" href="https://github.com/fury-gl/fury/pull/602">fury-gl/fury#602</a></p></li> +<li><p><strong>Fixing github API limit: (Merged)</strong> +<a class="github reference external" href="https://github.com/fury-gl/fury/pull/616">fury-gl/fury#616</a></p></li> +</ul> +</section> +<section id="other-pull-requests"> +<h3>Other Pull Requests</h3> +<ul class="simple"> +<li><p><strong>Sphere actor uses repeat_primitive by default</strong>: +<a class="reference external" href="https://github.com/fury-gl/fury/pull/533">fury-gl/fury/#533</a></p></li> +<li><p><strong>Cone actor uses repeat primitive by default</strong>: +<a class="reference external" href="https://github.com/fury-gl/fury/pull/547">fury-gl/fury/#547</a></p></li> +<li><p><strong>Updated code of viz_network_animated to use fury.utils</strong>: +<a class="reference external" href="https://github.com/fury-gl/fury/pull/556">fury-gl/fury/#556</a></p></li> +<li><p><strong>Added simulation for Tesseract</strong>: +<a class="reference external" href="https://github.com/fury-gl/fury/pull/559">fury-gl/fury/#559</a></p></li> +<li><p><strong>GLTF actor colors from material</strong> +<a class="reference external" href="https://github.com/fury-gl/fury/pull/689">fury-gl/fury/#689</a></p></li> +</ul> +</section> +<section id="gsoc-weekly-blogs"> +<h3>GSoC weekly blogs</h3> +<ul class="simple"> +<li><p>My blog posts can be found on the <a class="reference external" href="https://fury.gl/latest/blog/author/Shivam-Anand.html">FURY +website</a> +and the <a class="reference external" href="https://blogs.python-gsoc.org/en/xtanions-blog/">Python GSoC +blog</a>.</p></li> +</ul> +</section> +</section> +<section id="timeline"> +<h2>Timeline</h2> +<table class="table"> +<thead> +<tr class="row-odd"><th class="head"><p>Date</p></th> +<th class="head"><p>Description</p></th> +<th class="head"><p>Blog Post Link</p></th> +</tr> +</thead> +<tbody> +<tr class="row-even"><td><p>Week 0 <span class="raw-html"><br></span>(24-05-2022)</p></td> +<td><p>My journey to GSoC 2022</p></td> +<td><p><a class="reference external" href="https://fury.gl/latest/posts/2022/2022-05-24-my-journey-to-gsoc-2022-shivam.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/xtanions-blog/my-journey-to-gsoc-2022-1/">Python</a></p></td> +</tr> +<tr class="row-odd"><td><p>Week 1<span class="raw-html"><br></span>(20-06-2022)</p></td> +<td><p>A basic glTF Importer</p></td> +<td><aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-01-29-final-report-shivam.rst</span>, line 18); <em><a href="#id1">backlink</a></em></p> +<p>Duplicate explicit target name: “fury”.</p> +</aside> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-01-29-final-report-shivam.rst</span>, line 18); <em><a href="#id2">backlink</a></em></p> +<p>Duplicate explicit target name: “python”.</p> +</aside> +<p><a class="reference external" href="https://fury.gl/latest/posts/2022/2022-06-20-week1-shivam.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/xtanions-blog/week-1-a-basic-gltf-importer/">Python</a></p> +</td> +</tr> +<tr class="row-even"><td><p>Week 2<span class="raw-html"><br></span>(29-06-2022)</p></td> +<td><p>Improving Fetcher and Exporting glTF</p></td> +<td><aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-01-29-final-report-shivam.rst</span>, line 18); <em><a href="#id3">backlink</a></em></p> +<p>Duplicate explicit target name: “fury”.</p> +</aside> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-01-29-final-report-shivam.rst</span>, line 18); <em><a href="#id4">backlink</a></em></p> +<p>Duplicate explicit target name: “python”.</p> +</aside> +<p><a class="reference external" href="https://fury.gl/latest/posts/2022/2022-06-29-week2-shivam.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/xtanions-blog/week-2-improving-fetcher-and-exporting-gltf/">Python</a></p> +</td> +</tr> +<tr class="row-odd"><td><p>Week 3<span class="raw-html"><br></span>(04-07-2022)</p></td> +<td><p>Fixing fetcher adding tests and docs</p></td> +<td><aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-01-29-final-report-shivam.rst</span>, line 18); <em><a href="#id5">backlink</a></em></p> +<p>Duplicate explicit target name: “fury”.</p> +</aside> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-01-29-final-report-shivam.rst</span>, line 18); <em><a href="#id6">backlink</a></em></p> +<p>Duplicate explicit target name: “python”.</p> +</aside> +<p><a class="reference external" href="https://fury.gl/latest/posts/2022/2022-07-04-week3-shivam.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/xtanions-blog/week-3-fixing-fetcher-adding-tests-and-docs/">Python</a></p> +</td> +</tr> +<tr class="row-even"><td><p>Week 4<span class="raw-html"><br></span>(12-07-2022)</p></td> +<td><p>Finalizing glTF loader</p></td> +<td><aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-01-29-final-report-shivam.rst</span>, line 18); <em><a href="#id7">backlink</a></em></p> +<p>Duplicate explicit target name: “fury”.</p> +</aside> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-01-29-final-report-shivam.rst</span>, line 18); <em><a href="#id8">backlink</a></em></p> +<p>Duplicate explicit target name: “python”.</p> +</aside> +<p><a class="reference external" href="https://fury.gl/latest/posts/2022/2022-07-12-week4-shivam.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/xtanions-blog/week-4-finalizing-gltf-loader/">Python</a></p> +</td> +</tr> +<tr class="row-odd"><td><p>Week 5<span class="raw-html"><br></span>(19-07-2022)</p></td> +<td><p>Creating PR for glTF exporter and fixing the loader</p></td> +<td><aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-01-29-final-report-shivam.rst</span>, line 18); <em><a href="#id9">backlink</a></em></p> +<p>Duplicate explicit target name: “fury”.</p> +</aside> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-01-29-final-report-shivam.rst</span>, line 18); <em><a href="#id10">backlink</a></em></p> +<p>Duplicate explicit target name: “python”.</p> +</aside> +<p><a class="reference external" href="https://fury.gl/latest/posts/2022/2022-07-19-week5-shivam.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/xtanions-blog/week-5-creating-pr-for-gltf-exporter-and-fixing-the-loader/">Python</a></p> +</td> +</tr> +<tr class="row-even"><td><p>Week 6<span class="raw-html"><br></span>(25-07-2022)</p></td> +<td><p>Extracting the animation data</p></td> +<td><aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-01-29-final-report-shivam.rst</span>, line 18); <em><a href="#id11">backlink</a></em></p> +<p>Duplicate explicit target name: “fury”.</p> +</aside> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-01-29-final-report-shivam.rst</span>, line 18); <em><a href="#id12">backlink</a></em></p> +<p>Duplicate explicit target name: “python”.</p> +</aside> +<p><a class="reference external" href="https://fury.gl/latest/posts/2022/2022-07-25-week-6-shivam.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/xtanions-blog/week-6-extracting-the-animation-data/">Python</a></p> +</td> +</tr> +<tr class="row-odd"><td><p>Week 7<span class="raw-html"><br></span>(01-08-2022)</p></td> +<td><p>Fixing bugs in animations</p></td> +<td><aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-01-29-final-report-shivam.rst</span>, line 18); <em><a href="#id13">backlink</a></em></p> +<p>Duplicate explicit target name: “fury”.</p> +</aside> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-01-29-final-report-shivam.rst</span>, line 18); <em><a href="#id14">backlink</a></em></p> +<p>Duplicate explicit target name: “python”.</p> +</aside> +<p><a class="reference external" href="https://fury.gl/latest/posts/2022/2022-08-01-week-7-shivam.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/xtanions-blog/week-7-fixing-bugs-in-animations/">Python</a></p> +</td> +</tr> +<tr class="row-even"><td><p>Week 8<span class="raw-html"><br></span>(09-08-2022)</p></td> +<td><p>Fixing animation bugs</p></td> +<td><aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-01-29-final-report-shivam.rst</span>, line 18); <em><a href="#id15">backlink</a></em></p> +<p>Duplicate explicit target name: “fury”.</p> +</aside> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-01-29-final-report-shivam.rst</span>, line 18); <em><a href="#id16">backlink</a></em></p> +<p>Duplicate explicit target name: “python”.</p> +</aside> +<p><a class="reference external" href="https://fury.gl/latest/posts/2022/2022-08-09-week-08-shivam.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/xtanions-blog/week-8-fixing-animation-bugs/">Python</a></p> +</td> +</tr> +<tr class="row-odd"><td><p>Week 9<span class="raw-html"><br></span>(17-08-2022)</p></td> +<td><p>First working skeletal animation prototype</p></td> +<td><aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-01-29-final-report-shivam.rst</span>, line 18); <em><a href="#id17">backlink</a></em></p> +<p>Duplicate explicit target name: “fury”.</p> +</aside> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-01-29-final-report-shivam.rst</span>, line 18); <em><a href="#id18">backlink</a></em></p> +<p>Duplicate explicit target name: “python”.</p> +</aside> +<p><a class="reference external" href="https://fury.gl/latest/posts/2022/2022-08-17-week-09-shivam.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/xtanions-blog/week-9-first-working-skeletal-animation-prototype/">Python</a></p> +</td> +</tr> +<tr class="row-even"><td><p>Week 10<span class="raw-html"><br></span>(25-08-2022)</p></td> +<td><p>Multi-node skinning support</p></td> +<td><aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-01-29-final-report-shivam.rst</span>, line 18); <em><a href="#id19">backlink</a></em></p> +<p>Duplicate explicit target name: “fury”.</p> +</aside> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-01-29-final-report-shivam.rst</span>, line 18); <em><a href="#id20">backlink</a></em></p> +<p>Duplicate explicit target name: “python”.</p> +</aside> +<p><a class="reference external" href="https://fury.gl/latest/posts/2022/2022-08-25-week-10-shivam.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/xtanions-blog/week-10-multi-node-skinning-support/">Python</a></p> +</td> +</tr> +<tr class="row-odd"><td><p>Week 11<span class="raw-html"><br></span>(31-08-2022)</p></td> +<td><p>Multiple transformations support and adding tests</p></td> +<td><aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-01-29-final-report-shivam.rst</span>, line 18); <em><a href="#id21">backlink</a></em></p> +<p>Duplicate explicit target name: “fury”.</p> +</aside> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-01-29-final-report-shivam.rst</span>, line 18); <em><a href="#id22">backlink</a></em></p> +<p>Duplicate explicit target name: “python”.</p> +</aside> +<p><a class="reference external" href="https://fury.gl/latest/posts/2022/2022-08-31-week-11-shivam.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/xtanions-blog/week-11-multiple-transformations-support-and-adding-tests/">Python</a></p> +</td> +</tr> +<tr class="row-even"><td><p>Week 12<span class="raw-html"><br></span>(08-09-2022)</p></td> +<td><p>Adding skeleton as actors and fix global transformation</p></td> +<td><aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-01-29-final-report-shivam.rst</span>, line 18); <em><a href="#id23">backlink</a></em></p> +<p>Duplicate explicit target name: “fury”.</p> +</aside> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-01-29-final-report-shivam.rst</span>, line 18); <em><a href="#id24">backlink</a></em></p> +<p>Duplicate explicit target name: “python”.</p> +</aside> +<p><a class="reference external" href="https://fury.gl/latest/posts/2022/2022-09-08-week-12-shivam.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/xtanions-blog/week-12-adding-skeleton-as-actors-and-fix-global-transformation/">Python</a></p> +</td> +</tr> +<tr class="row-odd"><td><p>Week 13<span class="raw-html"><br></span>(15-09-2022)</p></td> +<td><p>Multi bone skeletal animations</p></td> +<td><aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-01-29-final-report-shivam.rst</span>, line 18); <em><a href="#id25">backlink</a></em></p> +<p>Duplicate explicit target name: “fury”.</p> +</aside> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-01-29-final-report-shivam.rst</span>, line 18); <em><a href="#id26">backlink</a></em></p> +<p>Duplicate explicit target name: “python”.</p> +</aside> +<p><a class="reference external" href="https://fury.gl/latest/posts/2022/2022-09-15-week-13-shivam.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/xtanions-blog/week-13-multi-bone-skeletal-animation-support/">Python</a></p> +</td> +</tr> +<tr class="row-even"><td><p>Week 14<span class="raw-html"><br></span>(28-09-2022)</p></td> +<td><p>Morphing is here !</p></td> +<td><aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-01-29-final-report-shivam.rst</span>, line 18); <em><a href="#id27">backlink</a></em></p> +<p>Duplicate explicit target name: “fury”.</p> +</aside> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-01-29-final-report-shivam.rst</span>, line 18); <em><a href="#id28">backlink</a></em></p> +<p>Duplicate explicit target name: “python”.</p> +</aside> +<p><a class="reference external" href="https://fury.gl/latest/posts/2022/2022-09-28-week-14-shivam.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/xtanions-blog/week-14-morphing-is-here/">Python</a></p> +</td> +</tr> +</tbody> +</table> +</section> +</section> + + + Name: Shivam Anand + + 2023-01-29T00:00:00-05:00 + + + https://fury.gl/posts/2022/2022-09-28-week-14-shivam.html + Week 14 - Morphing is here! + 2022-09-28T00:00:00-04:00 + + Shivam Anand + + <section id="week-14-morphing-is-here"> + +<section id="what-did-you-do-this-week"> +<h2>What did you do this week?</h2> +<ul class="simple"> +<li><p>This week, I started with multiple actor support in skinning and managed to do it +successfully. Here’s the preview using the BrainStem model.</p></li> +</ul> +<iframe id="player" type="text/html" width="600" height="340" src="https://user-images.githubusercontent.com/74976752/195650455-927a0238-5db1-4349-99d4-c021db356b66.mp4" frameborder="0"></iframe><ul class="simple"> +<li><p>Implementing multiple animation channels support (as seen in the <code class="docutils literal notranslate"><span class="pre">Fox</span></code> model). The <code class="docutils literal notranslate"><span class="pre">get_skin_timelines()</span></code> method now returns a dictionary of all animation channels with Timeline as their value.</p></li> +<li><p>We merged two PRs, <a class="reference external" href="https://github.com/fury-gl/fury/pull/689/">#689</a> (colors from Material) and <a class="reference external" href="https://github.com/fury-gl/fury/pull/643/">#643</a> (simple animations).</p></li> +<li><p>Added ability to load morphing information and create timelines from it. Here’s a preview of the <code class="docutils literal notranslate"><span class="pre">AnimatedMorphCube</span></code> and <code class="docutils literal notranslate"><span class="pre">AnimatedMorphSphere</span></code> models:</p></li> +</ul> +<iframe id="player" type="text/html" width="600" height="340" src="https://user-images.githubusercontent.com/74976752/195654414-b290900c-b80f-40c7-a49d-5ea8413e906a.mp4" frameborder="0"></iframe></section> +<section id="what-is-coming-up-next-week"> +<h2>What is coming up next week?</h2> +<ul class="simple"> +<li><p>Cleaning and Rebasing Skinning animation PR <a class="reference external" href="https://github.com/fury-gl/fury/pull/685/">#685</a>.</p></li> +<li><p>Creating a PR for morphing code.</p></li> +<li><p>Multi primitive (actor) support in morphing.</p></li> +</ul> +</section> +<section id="did-you-get-stuck-anywhere"> +<h2>Did you get stuck anywhere?</h2> +<ul class="simple"> +<li><p>No, I didn’t get stuck this week.</p></li> +</ul> +</section> +</section> + + + This week, I started with multiple actor support in skinning and managed to do it +successfully. Here’s the preview using the BrainStem model. + + 2022-09-28T00:00:00-04:00 + + + https://fury.gl/posts/2022/2022-09-15-week-13-blog.html + Week 13 - Multi-bone skeletal animation support + 2022-09-15T00:00:00-04:00 + + Shivam Anand + + <section id="week-13-multi-bone-skeletal-animation-support"> + +<section id="what-did-you-do-this-week"> +<h2>What did you do this week?</h2> +<p>This week I fixed all the issues with skeletal animations, and we got to see our first render of skeletal animation :).</p> +<ul class="simple"> +<li><p>Implemented a hierarchical timeline system (i.e., one timeline for each bone, and the timeline will contain its parent timeline in a hierarchy).</p></li> +<li><p>I figured out that we don’t need to apply the parent transform as we’re applying it to the vertex data while forming the actor. So the skin matrix becomes</p></li> +</ul> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2022/2022-09-15-week-13-blog.rst</span>, line 18)</p> +<p>Bullet list ends without a blank line; unexpected unindent.</p> +</aside> +<p><code class="docutils literal notranslate"><span class="pre">SkinMatrix</span> <span class="pre">=</span> <span class="pre">InverseBindPose</span> <span class="pre">*</span> <span class="pre">BoneDeform</span></code> where <code class="docutils literal notranslate"><span class="pre">BoneDeform</span> <span class="pre">=</span> <span class="pre">CurrentBoneTransform</span> <span class="pre">*</span> <span class="pre">ParentBonetransform</span></code>.</p> +<p>Here’s a preview using the <code class="docutils literal notranslate"><span class="pre">CesiumMan</span></code> model:</p> +<blockquote> +<div><iframe id="player" type="text/html" width="1280" height="600" src="https://user-images.githubusercontent.com/74976752/190474528-9d66651b-032f-4c7d-9bb6-5ad140017d0c.mp4" frameborder="0"></iframe></div></blockquote> +</section> +<section id="what-is-coming-up-next-week"> +<h2>What is coming up next week?</h2> +<ul class="simple"> +<li><p>Add tests for simple animation PR <a class="reference external" href="https://github.com/fury-gl/fury/pull/643/">#643</a>.</p></li> +<li><p>Multiple actor support for skeletal animation.</p></li> +<li><p>Take a look at Morphing.</p></li> +</ul> +</section> +<section id="did-you-get-stuck-anywhere"> +<h2>Did you get stuck anywhere?</h2> +<ul class="simple"> +<li><p>No, I didn’t get stuck this week.</p></li> +</ul> +</section> +</section> + + + This week I fixed all the issues with skeletal animations, and we got to see our first render of skeletal animation :). + + 2022-09-15T00:00:00-04:00 + + + https://fury.gl/posts/2022/2022-09-08-week-12-shivam.html + Week 12 - Adding skeleton as actors and fix global transformation + 2022-09-08T00:00:00-04:00 + + Shivam Anand + + <section id="week-12-adding-skeleton-as-actors-and-fix-global-transformation"> + +<section id="what-did-you-do-this-week"> +<h2>What did you do this week?</h2> +<ul class="simple"> +<li><p>I started this week by fixing the segmentation fault for the skinning test. I could not fix this as of now.</p></li> +<li><p>I imported the <code class="docutils literal notranslate"><span class="pre">RiggedFigure</span></code> model into the Blender and I was quite impressed with how it visualizes each bone. So, I created a function that creates an arrow actor in place of a bone, and by applying the correct transformation, we get the bones of a model in place. Here’s a quick preview of bones in Blender vs bones in FURY:</p></li> +</ul> +<img alt="https://user-images.githubusercontent.com/74976752/189194609-e55f6285-b5ed-4eb3-9e78-5fb462fb2dee.png" class="align-center" src="https://user-images.githubusercontent.com/74976752/189194609-e55f6285-b5ed-4eb3-9e78-5fb462fb2dee.png" style="width: 500px;" /> +<img alt="https://user-images.githubusercontent.com/74976752/189195853-5b1f8945-9822-48f5-8d55-f13e822a43a7.png" class="align-center" src="https://user-images.githubusercontent.com/74976752/189195853-5b1f8945-9822-48f5-8d55-f13e822a43a7.png" style="width: 500px;" /> +<ul class="simple"> +<li><p>After having the bones actor, I noticed that some bones are not aligned correctly. It was happening due to multiplication of the same transformation matrix twice.</p></li> +<li><p>I also created a function that calculates the total transformation of a node, it eliminates the need to use <code class="docutils literal notranslate"><span class="pre">timeline.get_value</span></code> in <code class="docutils literal notranslate"><span class="pre">get_skin_timeline</span></code> function.</p></li> +</ul> +</section> +<section id="what-is-coming-up-next-week"> +<h2>What is coming up next week?</h2> +<ul class="simple"> +<li><p>It seems like I fixed everything, but we are not getting the correct model at timestamp 0. We need to find the cause and fix it!</p></li> +<li><p>Cleaning the Simple Animation PR <a class="reference external" href="https://github.com/fury-gl/fury/pull/643/">#643</a>, and merging it.</p></li> +</ul> +</section> +<section id="did-you-get-stuck-anywhere"> +<h2>Did you get stuck anywhere?</h2> +<ul class="simple"> +<li><p>While applying the timeline, we were getting the identity matrix for timestamp 0.0s, it was set to a new value before. We figured this in our meeting that it’s happening due to some model’s animation not starting from 0.0s.</p></li> +</ul> +<img alt="https://user-images.githubusercontent.com/74976752/189196234-b28f86f7-223b-40e4-94bf-2ec18d914487.png" class="align-center" src="https://user-images.githubusercontent.com/74976752/189196234-b28f86f7-223b-40e4-94bf-2ec18d914487.png" style="width: 400px;" /> +</section> +</section> + + + I started this week by fixing the segmentation fault for the skinning test. I could not fix this as of now. + + 2022-09-08T00:00:00-04:00 + + + https://fury.gl/posts/2022/2022-08-31-week-11-shivam.html + Week 11 - Multiple transformations support and adding tests + 2022-08-31T00:00:00-04:00 + + Shivam Anand + + <section id="week-11-multiple-transformations-support-and-adding-tests"> + +<section id="what-did-you-do-this-week"> +<h2>What did you do this week?</h2> +<p>As decided last week, I added support for multiple animations at the same timestamp. But this didn’t solve the animation problems of <code class="docutils literal notranslate"><span class="pre">RiggedSimple</span></code> model.</p> +<ul> +<li><p>I figured out that I was not applying the global transform of joints in the skinning matrix causing the joints to move to a new position. I referred to this <a class="reference external" href="https://www.gamedev.net/forums/topic/703803-gltf-skinning-matrix-calculation/">answer by irradicator</a>.</p></li> +<li><p>We had to invert the multiplication order (ie, <code class="docutils literal notranslate"><span class="pre">np.dot(skin_mat,</span> <span class="pre">vertex)</span></code> instead of <code class="docutils literal notranslate"><span class="pre">np.dot(vertex,</span> <span class="pre">skin_mat)</span></code>) for this model. We still need to figure out from where we get the multiplication order of the two.</p> +<blockquote> +<div><iframe id="player" type="text/html" width="600" height="390" src="https://user-images.githubusercontent.com/74976752/187798821-7306cb13-dfc8-477c-8f86-1f5a6181f08a.mp4" frameborder="0"></iframe></div></blockquote> +</li> +<li><p>I also tried to create a custom Interpolator that does all calculations required for vertex skinning. However, we couldn’t get this working. I got a few suggestions from Mohamed in our meeting, I’ll try to implement those.</p></li> +<li><p>Added tests for animations.</p></li> +</ul> +</section> +<section id="what-is-coming-up-next-week"> +<h2>What is coming up next week?</h2> +<ul class="simple"> +<li><p>Adding more tests.</p></li> +<li><p>Fixing the Interpolator.</p></li> +<li><p>Order of multiplication in the skinning matrix.</p></li> +</ul> +</section> +<section id="did-you-get-stuck-anywhere"> +<h2>Did you get stuck anywhere?</h2> +<p>No, I didn’t get stuck this week.</p> +</section> +</section> + + + As decided last week, I added support for multiple animations at the same timestamp. But this didn’t solve the animation problems of RiggedSimple model. + + 2022-08-31T00:00:00-04:00 + + + https://fury.gl/posts/2022/2022-08-25-week-10-shivam.html + Week 10 - Multi-node skinning support + 2022-08-25T00:00:00-04:00 + + Shivam Anand + + <section id="week-10-multi-node-skinning-support"> + +<section id="what-did-you-do-this-week"> +<h2>What did you do this week?</h2> +<p>As we figured out that the <code class="docutils literal notranslate"><span class="pre">SimpleSkin</span></code> model is not animated as intended. This week I started working with that model; +I figured out that we need to apply the InverseBindMatrix to each timer callback. I had a hard time figuring out what inverse bind matrix actually does. +Here’s a good <a class="reference external" href="https://stackoverflow.com/questions/17127994/opengl-bone-animation-why-do-i-need-inverse-of-bind-pose-when-working-with-gp">blog</a> that answers that.</p> +<p><strong>In short: The InverseBindMatrix “undoes” any transformation that has already been applied to your model in its bind pose.</strong> Note: Inverse bind matrix shouldn’t be applied with weights.</p> +<ul> +<li><p>I got the <code class="docutils literal notranslate"><span class="pre">SimpleSkin</span></code> model to work perfectly. Here’s a preview:</p> +<blockquote> +<div><iframe id="player" type="text/html" width="600" height="390" src="https://user-images.githubusercontent.com/74976752/186712241-eaf8d1b3-f983-4e21-8264-c191b3eb6e4b.mp4" frameborder="0"></iframe></div></blockquote> +</li> +<li><p>Support for multiple transformations is still missing. However <code class="docutils literal notranslate"><span class="pre">RiggedSimple</span></code> is also working fine, except that It doesn’t interpolate translation and scaling matrices.</p> +<blockquote> +<div><iframe id="player" type="text/html" width="600" height="390" src="https://user-images.githubusercontent.com/74976752/186712256-af02c902-f60f-43b9-b257-f706c999557e.mp4" frameborder="0"></iframe></div></blockquote> +</li> +</ul> +</section> +<section id="what-is-coming-up-next-week"> +<h2>What is coming up next week?</h2> +<ul class="simple"> +<li><p>Adding tests and adding support for combining transformation matrices for the same timestamp.</p></li> +<li><p>Write an Interpolator that applies skinning to the mesh internally.</p></li> +</ul> +</section> +<section id="did-you-get-stuck-anywhere"> +<h2>Did you get stuck anywhere?</h2> +<p>No, I didn’t get stuck this week.</p> +</section> +</section> + + + As we figured out that the SimpleSkin model is not animated as intended. This week I started working with that model; +I figured out that we need to apply the InverseBindMatrix to each timer callback. I had a hard time figuring out what inverse bind matrix actually does. +Here’s a good blog that answers that. + + 2022-08-25T00:00:00-04:00 + + + https://fury.gl/posts/2022/2022-08-17-week-09-shivam.html + Week 9 - First working skeletal animation prototype + 2022-08-17T00:00:00-04:00 + + Shivam Anand + + <section id="week-9-first-working-skeletal-animation-prototype"> + +<section id="what-did-you-do-this-week"> +<h2>What did you do this week?</h2> +<ul> +<li><p>This week I had the first working <a class="reference external" href="https://github.com/xtanion/fury/blob/gltf-skin-test/docs/tutorials/01_introductory/viz_skinning.py">example</a> of skeletal animation ready. I was able to render the <a class="reference external" href="https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0/SimpleSkin">SimpleSkin</a> model. Here’s a quick preview:</p> +<blockquote> +<div><iframe id="player" type="text/html" width="600" height="390" src="https://user-images.githubusercontent.com/74976752/184981715-a83a8a36-f2bf-4ff1-9366-0c302dcf3f9b.mp4" frameborder="0"></iframe></div></blockquote> +</li> +<li><p>I wrote a custom <a class="reference external" href="https://github.com/xtanion/fury/blob/e5b2b9b4984f244fb4a8e8b410d494ba7d17cb49/fury/gltf.py#L684">interpolator</a> (just like the tangent cubic spline interpolator) for interpolating two transformation matrices.</p></li> +</ul> +</section> +<section id="what-is-coming-up-next-week"> +<h2>What is coming up next week?</h2> +<ul class="simple"> +<li><p>Generalising the skinning code to work with other models as well (it supports only the <code class="docutils literal notranslate"><span class="pre">SimpleSkin</span></code> model as of now).</p></li> +<li><p>Creating a custom interpolator to interpolate more than 4 matrices at once.</p></li> +</ul> +</section> +<section id="did-you-get-stuck-anywhere"> +<h2>Did you get stuck anywhere?</h2> +<p>No, I didn’t get stuck this week.</p> +</section> +</section> + + + This week I had the first working example of skeletal animation ready. I was able to render the SimpleSkin model. Here’s a quick preview: + + 2022-08-17T00:00:00-04:00 + + + https://fury.gl/posts/2022/2022-08-09-week-08-shivam.html + Week 8 - Fixing animation bugs + 2022-08-10T00:00:00-04:00 + + Shivam Anand + + <section id="week-8-fixing-animation-bugs"> + +<section id="what-did-you-do-this-week"> +<h2>What did you do this week?</h2> +<p>This week I had to fix the transformation issue in glTF animation. As discussed in the last meeting, I disabled vertex transformation and applied the transformation after the actor was formed.</p> +<ul> +<li><p>Creating transformation matrix using the TRS data from nodes.</p></li> +<li><p>Extract Translation, Rotation, and Scale matrices from the transformation matrix.</p> +<iframe id="player" type="text/html" width="640" height="360" src="https://user-images.githubusercontent.com/74976752/184015060-48d79f0d-1377-4f69-b147-cd53448ccf02.mp4" frameborder="0"></iframe></li> +</ul> +<p>I also started investigating more on the skinning animation.</p> +<ul class="simple"> +<li><p>I created functions to extract and apply the <code class="docutils literal notranslate"><span class="pre">InvertBindMatrices</span></code> to the vertices.</p></li> +<li><p>Also, applying the <code class="docutils literal notranslate"><span class="pre">globalTransformMatrices</span></code> to the mesh.</p></li> +</ul> +</section> +<section id="what-is-coming-up-next-week"> +<h2>What is coming up next week?</h2> +<ul class="simple"> +<li><p>Skeletal animations support</p></li> +</ul> +</section> +<section id="did-you-get-stuck-anywhere"> +<h2>Did you get stuck anywhere?</h2> +<ul> +<li><p>Even after applying the transformation to the actor, after it’s created. Some models did not behave as intended. We still need to figure this issue out and fix it.</p> +<iframe id="player" type="text/html" width="640" height="360" src="https://user-images.githubusercontent.com/74976752/184015110-035f1ce7-5a5c-4480-b49c-ae575d4b7ccd.mp4" frameborder="0"></iframe></li> +</ul> +</section> +</section> + + + This week I had to fix the transformation issue in glTF animation. As discussed in the last meeting, I disabled vertex transformation and applied the transformation after the actor was formed. + + 2022-08-10T00:00:00-04:00 + + + https://fury.gl/posts/2022/2022-08-01-week-7-shivam.html + Week 7 - Fixing bugs in animations + 2022-08-01T00:00:00-04:00 + + Shivam Anand + + <section id="week-7-fixing-bugs-in-animations"> + +<section id="what-did-you-do-this-week"> +<h2>What did you do this week?</h2> +<ul> +<li><p>This week I started with implementing scaling to the animation example.</p></li> +<li><p>I had a meeting with Mohamed in which we discussed the rotation issue, and we found out that glTF uses <code class="docutils literal notranslate"><span class="pre">Slerp</span></code> interpolator instead of the <code class="docutils literal notranslate"><span class="pre">LinearInterpolator</span></code>. Using <code class="docutils literal notranslate"><span class="pre">Slerp</span></code> interpolator for rotation fixed the rotation issue.</p></li> +<li><p>Another issue we faced was with the multi-actor system. Some actors weren’t rotating or translating as intended. This was caused because the transformations were applied to the <code class="docutils literal notranslate"><span class="pre">polydata</span></code> before creating an actor; Mohamed suggested applying transformation after the actor is created from polydata (keeping the center to origin).</p> +<iframe id="player" type="text/html" width="640" height="360" src="https://user-images.githubusercontent.com/74976752/182166133-585d06ef-55ff-48db-8ce7-98b377ebf8ec.mp4" frameborder="0"></iframe></li> +</ul> +<p>Expected animation: <a class="reference external" href="https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0/InterpolationTest">Interpolation Test Sample</a></p> +<ul class="simple"> +<li><p>Created functions to return a list of animation timelines and apply them to the main timeline for keyframe animations.</p></li> +<li><p><code class="docutils literal notranslate"><span class="pre">CubicSpline</span></code> has not been implemented to glTF animation yet since it works differently than other Interpolators (takes tangent input to smoothen the curve) but it’ll be done before our next meeting.</p></li> +</ul> +</section> +<section id="what-is-coming-up-next-week"> +<h2>What is coming up next week?</h2> +<ul class="simple"> +<li><p>Adding skinning animations support</p></li> +</ul> +</section> +<section id="did-you-get-stuck-anywhere"> +<h2>Did you get stuck anywhere?</h2> +<p>I still need to figure out how to apply the transformation matrix to the actor and not to the polydata.</p> +</section> +</section> + + + This week I started with implementing scaling to the animation example. + + 2022-08-01T00:00:00-04:00 + + + https://fury.gl/posts/2022/2022-07-25-week-6-shivam.html + Week 6 - Extracting the animation data + 2022-07-25T00:00:00-04:00 + + Shivam Anand + + <section id="week-6-extracting-the-animation-data"> + +<section id="what-did-you-do-this-week"> +<h2>What did you do this week?</h2> +<ul> +<li><p>This week, it was all about reading docs and extracting the animation data from buffers.</p></li> +<li><p>Currently, the glTF class can extract simple node transformation and morphing data, as they are stored in the <code class="docutils literal notranslate"><span class="pre">Animations</span></code> of the glTF file.</p></li> +<li><p>Skinning (Skeletal Animation) data is stored in <code class="docutils literal notranslate"><span class="pre">Nodes</span></code> inside the skin parameter. We shall be able to load that before our next meeting on Wednesday.</p></li> +<li><p>Created a <a class="reference external" href="https://github.com/xtanion/fury/blob/gltf-anim-merge-kf/docs/tutorials/01_introductory/viz_simple_gltf_animation.py">tutorial</a> using keyframe animations (<a class="reference external" href="https://github.com/fury-gl/fury/pull/626">#626</a>) and adding multiple <code class="docutils literal notranslate"><span class="pre">timelines</span></code> into a main <code class="docutils literal notranslate"><span class="pre">timeline</span></code> as suggested by Mohamed.</p> +<iframe id="player" type="text/html" width="550" height="400" src="https://user-images.githubusercontent.com/74976752/180841262-7356204e-2097-4ea4-ab71-39f04a1e7a07.mp4" frameborder="0"></iframe></li> +</ul> +</section> +<section id="what-is-coming-up-next-week"> +<h2>What is coming up next week?</h2> +<p>As of now, we’ve decided the following:</p> +<ul class="simple"> +<li><p>Create a custom Interpolator (for simple node transformations, morph and Skeletal animations).</p></li> +</ul> +</section> +<section id="did-you-get-stuck-anywhere"> +<h2>Did you get stuck anywhere?</h2> +<p>No, I didn’t get stuck this week.</p> +</section> +</section> + + + This week, it was all about reading docs and extracting the animation data from buffers. + + 2022-07-25T00:00:00-04:00 + + diff --git a/v0.10.x/blog/author/shivam-sahu.html b/v0.10.x/blog/author/shivam-sahu.html new file mode 100644 index 000000000..7f6df17ae --- /dev/null +++ b/v0.10.x/blog/author/shivam-sahu.html @@ -0,0 +1,537 @@ + + + + + + + Posts by Shivam Sahu — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +
+

+ + Posts by + + Shivam Sahu + +

+ + +
+

+ My Journey to GSoC 2022 +

+
    +
  • + + + 24 May 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Shivam Sahu + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hi! I’m Shivam, currently pursuing my bachelor’s (expected 2024) in Production and Industrial engineering from the Indian Institute of Technology (IIT) Roorkee.

+

+ +

Read more ...

+
+
+ + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/blog/author/shivam-sahu/atom.xml b/v0.10.x/blog/author/shivam-sahu/atom.xml new file mode 100644 index 000000000..72b18eb5d --- /dev/null +++ b/v0.10.x/blog/author/shivam-sahu/atom.xml @@ -0,0 +1,57 @@ + + + https://fury.gl/ + Blog - Posts by Shivam Sahu + 2024-02-29T15:43:57.538507+00:00 + + + ABlog + + https://fury.gl/posts/2022/2022-05-24-my-journey-to-gsoc-2022-shivam.html + My Journey to GSoC 2022 + 2022-05-24T00:00:00-04:00 + + Shivam Sahu + + <section id="my-journey-to-gsoc-2022"> + +<section id="about-myself"> +<h2>About Myself</h2> +<p>Hi! I’m Shivam, currently pursuing my bachelor’s (expected 2024) in Production and Industrial engineering from the Indian Institute of Technology (IIT) Roorkee.</p> +<p>I was introduced to the C programming language through the Introduction to programming course in my first year of college. I always liked computers, and I was overwhelmed by printing “hello world” in the terminal. The course continued to teach us data structures and algorithms. It was a lot of fun competing with friends over a programming question. I learned python on my own and did a lot of projects. After learning basic programming, I participated in many hackathons and won some, but lost a lot. Coding was enjoyable, and I knew this was what I wanted to do for the rest of my life. +In my second semester, I learned about open-source, git, and GitHub. I came across some computer graphics enthusiasts in my college; they told me that they created a 2D game engine on their own using OpenGL. This gave me enough motivation to learn OpenGL and basic computer graphics.</p> +</section> +<section id="intro-to-open-source-and-gsoc"> +<h2>Intro to Open-Source and GSoC</h2> +<p>In October 2021, I participated in Hactoberfest and completed it successfully. I learned a lot about Free and Open Source Software during this time. I heard about GSoC around this time from one of my seniors and asked him about the program.</p> +<p>I went through the previous year’s accepted organizations list and shortlisted 2-3 organizations. I started contributing to a few projects based on android and kotlin, but I lost interest after some time. +It was about December, and I hadn’t chosen any organization yet.</p> +<p>I heard about FURY from one of my seniors. I started looking at its docs. Picked up some books from the library to brush up on my concepts of computer graphics. The documentation of FURY is remarkable. I created my <a class="reference external" href="https://github.com/fury-gl/fury/pull/520">first pull request</a> by improving one of the tutorials, and It got merged in a few days.</p> +<p>I started looking at the source code of FURY and tried to understand it again. I read the <cite>API reference</cite> part of FURY docs this time along with the documentation of <cite>VTK</cite>. I also tried to solve some of the open issues. I created a few pull requests for the same. My first contribution was in the fury <cite>primitive</cite> class, I created a sphere primitive (inspired by the sphere in Blender).</p> +<p>I started looking at bugs and improvements that can be made to the source code and created PRs for the same. During this time I was also learning how computer graphics work from the <a class="reference external" href="https://www.youtube.com/channel/UCSynd9Z5RdIpKfvTCITV_8A/videos">UCSC lectures</a> &amp; <a class="reference external" href="https://youtube.com/playlist?list=PLPaoO-vpZnumdcb4tZc4x5Q-v7CkrQ6M-">OpenGL by Victor Gordon</a>.</p> +<p>After the accepted organizations were announced, I was so happy that FURY got selected this year for GSoC and went straight to the Ideas list. The first project idea was <cite>glTF Integration</cite>. I heard about the <cite>glTF</cite> file format before but didn’t know how it works. So I went straight through the reference materials provided on the <a class="reference external" href="https://github.com/fury-gl/fury/wiki/Google-Summer-of-Code-2022-(GSOC2022)">wiki</a>. I read a lot of documentation by the Khronos group. I also tried to implement a basic glTF loader during this time using VTK’s built-in <cite>glTFReader</cite>.</p> +<p>I also liked the Improve UI drawing project idea (I had a basic understanding of line drawing algorithms and rasterizations at that time) and thought I’ll make a proposal for that too. After completing my proposal for glTF integration I started my research on this one too.</p> +<p>I started writing the proposal early so that I could get my proposal reviewed at least once with the project mentors. I almost forgot the fact that I had my end-term examinations at hand (Somehow I managed to pass all of my courses), I kept contributing to the project till the end of April 2022.</p> +<p>Code contributions:</p> +<ol class="arabic simple"> +<li><p>[<a class="github reference external" href="https://github.com/fury-gl/fury/pull/520">fury-gl/fury#520</a>]</p></li> +<li><p>[<a class="github reference external" href="https://github.com/fury-gl/fury/pull/525">fury-gl/fury#525</a>]</p></li> +<li><p>[<a class="github reference external" href="https://github.com/fury-gl/fury/pull/533">fury-gl/fury#533</a>]</p></li> +<li><p>[<a class="github reference external" href="https://github.com/fury-gl/fury/pull/547">fury-gl/fury#547</a>]</p></li> +<li><p>[<a class="github reference external" href="https://github.com/fury-gl/fury/pull/556">fury-gl/fury#556</a>]</p></li> +<li><p>[<a class="github reference external" href="https://github.com/fury-gl/fury/pull/559">fury-gl/fury#559</a>]</p></li> +</ol> +</section> +<section id="the-day"> +<h2>The Day</h2> +<p>May 18: I was a bit anxious since on May 18th the GSoC website was showing my proposal for glTF integration had been rejected. (p.s. maybe it was a bug of some sort that they fixed later on).</p> +<p>May 20: I woke up very early in the morning and started checking the contributor’s profile. I kept checking for new emails but didn’t receive any emails that day. “The result will be announced at 11:30 PM, isn’t it? “ My dad said, It was 8:00 AM Indian Standard Time. I called my friends in the night to join me on discord, I was talking to them and refreshing the GSoC site at the same time. One of my friends shouted that he got selected in NumFocus. I refreshed the page again, my proposal for glTF Integration was accepted. I can’t express what I felt at that moment. I told my friends and my parents, they were happy for me and I got a lot of blessings :). I received an official email the next day.</p> +</section> +</section> + + + Hi! I’m Shivam, currently pursuing my bachelor’s (expected 2024) in Production and Industrial engineering from the Indian Institute of Technology (IIT) Roorkee. + + 2022-05-24T00:00:00-04:00 + + diff --git a/v0.10.x/blog/author/soham-biswas.html b/v0.10.x/blog/author/soham-biswas.html new file mode 100644 index 000000000..322b7d73b --- /dev/null +++ b/v0.10.x/blog/author/soham-biswas.html @@ -0,0 +1,1460 @@ + + + + + + + Posts by Soham Biswas — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +
+

+ + Posts by + + Soham Biswas + +

+ + +
+

+ Google Summer of Code Final Work Product +

+
    +
  • + + + 24 August 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Soham Biswas + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Name: Soham Biswas

+

+ +

Read more ...

+
+
+ +
+

+ Part of the Journey is the end unless its Open Source! +

+
    +
  • + + + 23 August 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Soham Biswas + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hello and welcome to my final weekly check-in. Today officially marks the end of the coding period for GSoC 2020. I enjoyed every bit of it. This was a life-changing experience for me and now I observe and interpret everything from a different perspective altogether. I have grown into a better developer and a person since GSoC. I would like to thank all my mentors and especially Serge for his immense support and mentorship. I would love to contribute to fury even after GSoC is over but unfortunately my semester break is over so I won’t be as active as I was during the summer.

+

+ +

Read more ...

+
+
+ +
+

+ Wrecking Ball Simulation, Scrollbars Update, Physics Tutorials. +

+
    +
  • + + + 16 August 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Soham Biswas + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hello and welcome to my 12th weekly check-in. In this blog I will be discussing my progress with the wrecking ball simulation and my scrollbar separation work. Apart from this I have also finalized the physics simulation tutorials and have created a Pull Request to finally get it merged with the official repository. The official repository of my sub-org can be found here.

+

+ +

Read more ...

+
+
+ +
+

+ Chain Simulation, Scrollbar Refactor, Tutorial Update. +

+
    +
  • + + + 09 August 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Soham Biswas + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hello and welcome to my 11th weekly check-in. In this blog I will be discussing my progress with multiple topics related to physics and ui components. I was actively working on a couple of things, specifically Joint simulations in pyBullet and scrollbar UI component. I also took up the responsibility to complete an incomplete Pull Request which was pending for quite a while. The official repository of my sub-org can be found here.

+

+ +

Read more ...

+
+
+ +
+

+ Single Actor, Physics, Scrollbars. +

+
    +
  • + + + 02 August 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Soham Biswas + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hello and welcome to my 10th weekly check-in. Second evaluation ended this week and now we move on to our 3rd and final coding period. In today’s check-in I will be sharing my progress with the single actor physics simulation that I facing some issues with and I will also be discussing my future plans regarding UI components. The official repository of my sub-org, FURY can always be found here.

+

+ +

Read more ...

+
+
+ +
+

+ Tab UI, TabPanel2D, Tab UI Tutorial. +

+
    +
  • + + + 26 July 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Soham Biswas + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hello and welcome to my 9th weekly check-in. I will be sharing my progress with TabUI and its corresponding tutorial. The official repository of my sub-org, FURY can always be found here.

+

+ +

Read more ...

+
+
+ +
+

+ ComboBox2D, TextBlock2D, Clipping Overflow. +

+
    +
  • + + + 19 July 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Soham Biswas + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hello and welcome to my 8th weekly check-in. I will be sharing my progress with ComboBox2D and TextBlock2D UI components. After solving TextBlock2D sizing issue, I was finally able to complete the implementation of combo box. I also faced some problems while refactoring TextBlock2D. The official repository of my sub-org, FURY can always be found here.

+

+ +

Read more ...

+
+
+ +
+

+ Orientation, Sizing, Tab UI. +

+
    +
  • + + + 12 July 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Soham Biswas + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hello and welcome to my 7th weekly check-in. I will be sharing my progress with single actor physics simulation and TextBlock2D sizing issue which was pending for quite a while now. I will also be sharing my thoughts regarding the TAB UI component. The official repository of my sub-org, FURY can always be found here.

+

+ +

Read more ...

+
+
+ +
+

+ Translation, Reposition, Rotation. +

+
    +
  • + + + 05 July 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Soham Biswas + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hello and welcome to my 6th weekly check-in. The first evaluation period officially ends and I am very excited to move on to the second coding period. I will be sharing my progress with handling specific object’s properties among various multiple objects rendered by a single actor. I am mainly focusing on making it easier to translate, rotate and reposition a particular object, so that I can use them to render physics simulations more efficiently. The official repository of my sub-org, FURY can always be found here.

+

+ +

Read more ...

+
+
+ +
+

+ May the Force be with you!! +

+
    +
  • + + + 28 June 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Soham Biswas + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hello and welcome to my 5th weekly check-in, I will be sharing my progress of pyBullet Physics Engine Integration with FURY. The official repository of my sub-org, FURY can always be found here.

+

+ +

Read more ...

+
+
+ +
+

+ TextBlock2D Progress!! +

+
    +
  • + + + 21 June 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Soham Biswas + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hello and welcome to my 4th weekly check-in, I will be sharing my progress with TextBlock2D UI component. The official repository of my sub-org, FURY can always be found here.

+

+ +

Read more ...

+
+
+ +
+

+ ComboBox2D Progress!! +

+
    +
  • + + + 14 June 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Soham Biswas + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hello and welcome to my third weekly check-in, I will be sharing my progress with the project so far. In case you wondered, the sub-org that I am affiliated to is FURY. Make sure to check out the official repository here.

+

+ +

Read more ...

+
+
+ +
+

+ First week of coding!! +

+
    +
  • + + + 07 June 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Soham Biswas + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hello and welcome to my second weekly check-in, I will be sharing my progress for the first week of coding.

+

+ +

Read more ...

+
+
+ +
+

+ Welcome to my GSoC Blog!!! +

+
    +
  • + + + 30 May 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Soham Biswas + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hello Everyone, this is Soham Biswas currently in 2nd year pursuing my Bachelor’s(B.Tech) degree in Computer Science & Engineering from Institute of Engineering & Management, Kolkata. I have been selected for GSoC’ 20 at sub-org FURY under the umbrella organization of Python Software Foundation. I will be working on building sci-fi-like 2D and 3D interfaces and provide physics engine integration under project titled “Create new UI widgets & Physics Engine Integration”.

+

+ +

Read more ...

+
+
+ + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/blog/author/soham-biswas/atom.xml b/v0.10.x/blog/author/soham-biswas/atom.xml new file mode 100644 index 000000000..49224c5da --- /dev/null +++ b/v0.10.x/blog/author/soham-biswas/atom.xml @@ -0,0 +1,678 @@ + + + https://fury.gl/ + Blog - Posts by Soham Biswas + 2024-02-29T15:43:57.540462+00:00 + + + ABlog + + https://fury.gl/posts/2020/2020-08-24-final-work-soham.html + Google Summer of Code Final Work Product + 2020-08-24T00:00:00-04:00 + + Soham Biswas + + <a class="reference external image-reference" href="https://summerofcode.withgoogle.com/projects/#6653942668197888"><img alt="https://developers.google.com/open-source/gsoc/resources/downloads/GSoC-logo-horizontal.svg" class="align-center" height="50" src="https://developers.google.com/open-source/gsoc/resources/downloads/GSoC-logo-horizontal.svg" /></a> +<a class="reference external image-reference" href="https://blogs.python-gsoc.org/en/nibba2018s-blog/"><img alt="https://www.python.org/static/community_logos/python-logo.png" src="https://www.python.org/static/community_logos/python-logo.png" style="width: 40%;" /></a> +<a class="reference external image-reference" href="https://fury.gl/latest/community.html"><img alt="https://python-gsoc.org/logos/FURY.png" src="https://python-gsoc.org/logos/FURY.png" style="width: 25%;" /></a> +<section id="google-summer-of-code-final-work-product"> + +<ul class="simple"> +<li><p><strong>Name:</strong> Soham Biswas</p></li> +<li><p><strong>Organisation:</strong> Python Software Foundation</p></li> +<li><p><strong>Sub-Organisation:</strong> FURY</p></li> +<li><p><strong>Project:</strong> <a class="reference external" href="https://github.com/fury-gl/fury/wiki/Google-Summer-of-Code-2020">FURY - Create new UI Widgets &amp; Physics Engine +Integration</a></p></li> +</ul> +<section id="proposed-objectives"> +<h2>Proposed Objectives</h2> +<ul class="simple"> +<li><p>ComboBox</p></li> +<li><p>Tab UI</p></li> +<li><p>File Dialog Improvements</p></li> +</ul> +</section> +<section id="modified-objectives"> +<h2>Modified Objectives</h2> +<ul class="simple"> +<li><p>Combobox</p></li> +<li><p>Tab UI</p></li> +<li><p>File Dialog Improvements</p></li> +<li><p>Double Click Callback</p></li> +<li><p>TextBlock2D Improvements</p></li> +<li><p>Scrollbars as a Standalone Component</p></li> +<li><p>Physics Engine Integration</p></li> +</ul> +</section> +<section id="objectives-completed"> +<h2>Objectives Completed</h2> +<ul> +<li><p><strong>ComboBox2D UI Component</strong></p> +<p>A combobox is a commonly used graphical user interface widget. +Traditionally, it is a combination of a drop-down list or list box and a +single-line textbox, allowing the user to select a value from the list. +The term “combo box” is sometimes used to mean “drop-down list”. +Respective components, tests and tutorials were created.</p> +<p><em>Pull Requests:</em></p> +<ul class="simple"> +<li><p><strong>Combobox UI component:</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/240">fury-gl/fury#240</a></p></li> +<li><p><strong>Combobox UI Tutorial:</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/246">fury-gl/fury#246</a></p></li> +</ul> +</li> +<li><p><strong>Tab UI Component</strong></p> +<p>In interface design, a tabbed document interface or Tab is a graphical +control element that allows multiple documents or panels to be contained +within a single window, using tabs as a navigational widget for +switching between sets of documents. Respective components, tests and +tutorials were created.</p> +<p><em>Pull Requests:</em></p> +<ul class="simple"> +<li><p><strong>Tab UI component:</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/252">fury-gl/fury#252</a></p></li> +<li><p><strong>Tab UI tutorial:</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/275">fury-gl/fury#275</a></p></li> +</ul> +</li> +<li><p><strong>Double Click Callback</strong></p> +<p>Double click callbacks aren’t implemented in VTK by default so they need +to be implemented manually. With my mentor’s help I was able to +implement double click callbacks for all the three mouse buttons +successfully.</p> +<p><em>Pull Requests:</em></p> +<ul class="simple"> +<li><p><strong>Adding Double Click Callback:</strong> +<a class="github reference external" href="https://github.com/fury-gl/fury/pull/231">fury-gl/fury#231</a></p></li> +</ul> +</li> +<li><p><strong>TextBlock2D Improvements</strong></p> +<p>The previous implementation of <code class="docutils literal notranslate"><span class="pre">TextBlock2D</span></code> was lacking a few +features such as size arguments and text overflow. There was no specific +way to create Texts occupying a said height or width area. Apart from +that UI components like <code class="docutils literal notranslate"><span class="pre">ListBoxItem2D</span></code>, <code class="docutils literal notranslate"><span class="pre">FileMenu2D</span></code> etc had an +issue where text would overflow from their specified width. In order to +tackle these problems, a modification was done to <code class="docutils literal notranslate"><span class="pre">TextBlock2D</span></code> to +accept size as an argument and a new method was added to clip +overflowing text based on a specified width and to replace the +overflowing characters with <code class="docutils literal notranslate"><span class="pre">...</span></code>.</p> +<p><em>Pull Requests:</em></p> +<ul class="simple"> +<li><p><strong>Setting Bounding Box for TextBlock2D:</strong> +<a class="github reference external" href="https://github.com/fury-gl/fury/pull/248">fury-gl/fury#248</a></p></li> +<li><p><strong>Clip Text Overflow:</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/268">fury-gl/fury#268</a></p></li> +</ul> +</li> +<li><p><strong>Physics Engine Integration</strong></p> +<p>Optional support for Physics engine integration of Pybullet was added to +Fury. Pybullet’s engine was used for the simulations and FURY was used +for rendering the said simulations. Exhaustive examples were added to +demonstrate various types of physics simulations possible using pybullet +and fury. The said examples are as follows:</p> +<ul class="simple"> +<li><p>Brick Wall Simulation</p> +<ul> +<li><p>Explains how to render and simulate external forces, objects and +gravity.</p></li> +</ul> +</li> +<li><p>Ball Collision Simulation</p> +<ul> +<li><p>Explains how collisions work and how to detect said collisions.</p></li> +</ul> +</li> +<li><p>Chain Simulation</p> +<ul> +<li><p>Explains how to render and simulate joints.</p></li> +</ul> +</li> +<li><p>Wrecking Ball Simulation</p> +<ul> +<li><p>A more complicated simulation that combines concepts explained by +the other examples.</p></li> +</ul> +</li> +</ul> +<p>Apart from that, a document was created to explain the integration +process between pybullet and fury in detail.</p> +<p><em>Pull Requests:</em></p> +<ul class="simple"> +<li><p><strong>Physics Simulation Examples:</strong> +<a class="github reference external" href="https://github.com/fury-gl/fury/pull/287">fury-gl/fury#287</a></p></li> +<li><p><strong>Fury-Pybullet Integration Docs:</strong> +<a class="reference external" href="https://docs.google.com/document/d/1XJcG1TL5ZRJZDyi8V76leYZt_maxGp0kOB7OZIxKsTA/edit?usp=sharing">https://docs.google.com/document/d/1XJcG1TL5ZRJZDyi8V76leYZt_maxGp0kOB7OZIxKsTA/edit?usp=sharing</a></p></li> +</ul> +</li> +</ul> +</section> +<section id="objectives-in-progress"> +<h2>Objectives in Progress</h2> +<ul> +<li><p><strong>Scrollbars as a standalone component</strong></p> +<p>The previous implementation of scrollbars were hard coded into +<code class="docutils literal notranslate"><span class="pre">ListBox2D</span></code>. Therefore, it was not possible to use scrollbars with any +other UI component. Apart from that, scrollbars in terms of design were +limited. Creating a horizontal scrollbar was not possible. The objective +of this PR is to make scrollbars separate so that other UI elements can +also make use of it.</p> +<p>Currently, the skeletal and design aspects of the scrollbars are +implemented but the combination of scrollbars with other UI components +are still in progress.</p> +<p><em>Pull Requests:</em></p> +<ul class="simple"> +<li><p><strong>Scrollbars as a Standalone API:</strong> +<a class="github reference external" href="https://github.com/fury-gl/fury/pull/285">fury-gl/fury#285</a></p></li> +</ul> +</li> +<li><p><strong>File Dialog Improvements</strong></p> +<p>Currently, we have access to <code class="docutils literal notranslate"><span class="pre">FileMenu2D</span></code> which allows us to navigate +through the filesystem but it does not provide a user friendly Dialog to +read and write files in Fury. Hence the idea is to create a file dialog +which can easily open or save file at runtime. As of now, <code class="docutils literal notranslate"><span class="pre">Open</span></code> and +<code class="docutils literal notranslate"><span class="pre">Save</span></code> operations are implemented. Corresponding tests and tutorials +are in progress.</p> +<p><em>Pull Requests:</em></p> +<ul class="simple"> +<li><p><strong>File Dialog UI component:</strong> +<a class="github reference external" href="https://github.com/fury-gl/fury/pull/294">fury-gl/fury#294</a></p></li> +</ul> +</li> +</ul> +</section> +<section id="other-objectives"> +<h2>Other Objectives</h2> +<ul> +<li><p><strong>Radio Checkbox Tutorial using FURY API</strong></p> +<p>The objects for Radio button and Checkbox tutorial were rendered using +VTK’s method by a fellow contributor so I decided to replace them with +native FURY API. The methods were rewritten keeping the previous commits +intact.</p> +<p><em>Pull Requests:</em></p> +<ul class="simple"> +<li><p><strong>Radio Checkbox tutorial using FURY API:</strong> +<a class="github reference external" href="https://github.com/fury-gl/fury/pull/281">fury-gl/fury#281</a></p></li> +</ul> +</li> +<li><p><strong>GSoC weekly Blogs</strong></p> +<p>Weekly blogs were added for FURY’s Website.</p> +<p><em>Pull Requests:</em></p> +<ul class="simple"> +<li><p><strong>First &amp; Second Evaluation:</strong> +<a class="github reference external" href="https://github.com/fury-gl/fury/pull/272">fury-gl/fury#272</a></p></li> +<li><p><strong>Third Evaluation:</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/286">fury-gl/fury#286</a></p></li> +</ul> +</li> +</ul> +</section> +<section id="timeline"> +<h2>Timeline</h2> +<table class="table"> +<thead> +<tr class="row-odd"><th class="head"><p>Date</p></th> +<th class="head"><p>Description</p></th> +<th class="head"><p>Blog Link</p></th> +</tr> +</thead> +<tbody> +<tr class="row-even"><td><p>Week 1(30-05-2020)</p></td> +<td><p>Welcome to my GSoC Blog!!</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/nibba2018s-blog/weekly-check-in-1-5/">Weekly Check-in #1</a></p></td> +</tr> +<tr class="row-odd"><td><p>Week 2(07-06-2020)</p></td> +<td><p>First Week of Coding!!</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/nibba2018s-blog/weekly-check-in-2-3/">Weekly Check-in #2</a></p></td> +</tr> +<tr class="row-even"><td><p>Week 3(14-06-2020)</p></td> +<td><p>ComboBox2D Progress!!</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/nibba2018s-blog/weekly-check-in-3-4/">Weekly Check-in #3</a></p></td> +</tr> +<tr class="row-odd"><td><p>Week 4(21-06-2020)</p></td> +<td><p>TextBlock2D Progress!!</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/nibba2018s-blog/weekly-check-in-4-4/">Weekly Check-in #4</a></p></td> +</tr> +<tr class="row-even"><td><p>Week 5(28-06-2020)</p></td> +<td><p>May the Force be with you!!</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/nibba2018s-blog/weekly-check-in-5-4/">Weekly Check-in #5</a></p></td> +</tr> +<tr class="row-odd"><td><p>Week 6(05-07-2020)</p></td> +<td><p>Translation, Reposition, Rotation.</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/nibba2018s-blog/weekly-check-in-6-7/">Weekly Check-in #6</a></p></td> +</tr> +<tr class="row-even"><td><p>Week 7(12-07-2020)</p></td> +<td><p>Orientation, Sizing, Tab UI.</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/nibba2018s-blog/weekly-check-in-7-4/">Weekly Check-in #7</a></p></td> +</tr> +<tr class="row-odd"><td><p>Week 8(19-07-2020)</p></td> +<td><p>ComboBox2D, TextBlock2D, ClippingOverflow.</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/nibba2018s-blog/weekly-check-in-8-2/">Weekly Check-in #8</a></p></td> +</tr> +<tr class="row-even"><td><p>Week 9(26-07-2020)</p></td> +<td><p>Tab UI, TabPanel2D, Tab UI Tutorial.</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/nibba2018s-blog/weekly-check-in-9-4/">Weekly Check-in #9</a></p></td> +</tr> +<tr class="row-odd"><td><p>Week 10(02-08-2020)</p></td> +<td><p>Single Actor, Physics, Scrollbars.</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/nibba2018s-blog/weekly-check-in-10-2/">Weekly Check-in #10</a></p></td> +</tr> +<tr class="row-even"><td><p>Week 11(09-08-2020)</p></td> +<td><p>Chain Simulation, Scrollbar Refactor,Tutorial Update.</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/nibba2018s-blog/weekly-check-in-11-1/">Weekly Check-in #11</a></p></td> +</tr> +<tr class="row-odd"><td><p>Week 12(16-08-2020)</p></td> +<td><p>Wrecking Ball Simulation, ScrollbarsUpdate, Physics Tutorials.</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/nibba2018s-blog/weekly-check-in-12/">Weekly Check-in #12</a></p></td> +</tr> +<tr class="row-even"><td><p>Week 13(23-08-2020)</p></td> +<td><p>Part of the Journey is the end unless itsOpen Source!</p></td> +<td><p><a class="reference external" href="https://blogs.python-gsoc.org/en/nibba2018s-blog/weekly-check-in-13/">Weekly Check-in #13</a></p></td> +</tr> +</tbody> +</table> +<p>Detailed weekly tasks and work done can be found +<a class="reference external" href="https://blogs.python-gsoc.org/en/nibba2018s-blog/">here</a>.</p> +</section> +</section> + + + Name: Soham Biswas + + 2020-08-24T00:00:00-04:00 + + + https://fury.gl/posts/2020/2020-08-23-week-13-soham.html + Part of the Journey is the end unless its Open Source! + 2020-08-23T00:00:00-04:00 + + Soham Biswas + + <section id="part-of-the-journey-is-the-end-unless-its-open-source"> + +<p>Hello and welcome to my final weekly check-in. Today officially marks the end of the coding period for GSoC 2020. I enjoyed every bit of it. This was a life-changing experience for me and now I observe and interpret everything from a different perspective altogether. I have grown into a better developer and a person since GSoC. I would like to thank all my mentors and especially Serge for his immense support and mentorship. I would love to contribute to fury even after GSoC is over but unfortunately my semester break is over so I won’t be as active as I was during the summer.</p> +<p>Now, regarding work I will be sharing my progress with the File Dialog UI component. The official repository of my sub-org can be found <a class="reference external" href="https://github.com/fury-gl/fury/">here</a>.</p> +<section id="what-did-you-do-this-week"> +<h2>What did you do this week?</h2> +<p>This week I worked on the File Dialog UI component. Fury previously had a FileMenu component which could browse through the file system but we needed a dialog like implementation for it so that its easier for the users to read and write files during runtime. I tried implementing a simple design for it. It specifically has two modes, one for saving files and the other for writing files. The implementation can be demonstrated as follows:</p> +<section id="open-dialog"> +<h3>Open Dialog:</h3> +<img alt="https://user-images.githubusercontent.com/29832615/90978632-df12c780-e56c-11ea-8517-6243ea06bdd2.gif" src="https://user-images.githubusercontent.com/29832615/90978632-df12c780-e56c-11ea-8517-6243ea06bdd2.gif" /> +</section> +<section id="save-dialog"> +<h3>Save Dialog:</h3> +<img alt="https://user-images.githubusercontent.com/29832615/90978638-eafe8980-e56c-11ea-835a-3a82ccee2973.gif" src="https://user-images.githubusercontent.com/29832615/90978638-eafe8980-e56c-11ea-835a-3a82ccee2973.gif" /> +</section> +</section> +<section id="what-is-coming-up-next-week"> +<h2>What is coming up next week?</h2> +<p>Next week I will start with my final GSoC documentation and code submission. I will also try to implement the tests and tutorials for File Dialog or any further changes requested by my mentors. If I am not able to finish it within the next week, I will get it done after GSoC.</p> +</section> +<section id="did-you-get-stuck-anywhere"> +<h2>Did you get stuck anywhere?</h2> +<p>I did not face any major issues this week.</p> +<p><code class="docutils literal notranslate"><span class="pre">Thank</span> <span class="pre">you</span> <span class="pre">all</span> <span class="pre">for</span> <span class="pre">your</span> <span class="pre">love</span> <span class="pre">and</span> <span class="pre">support.</span> <span class="pre">❤️😄</span></code></p> +</section> +</section> + + + Hello and welcome to my final weekly check-in. Today officially marks the end of the coding period for GSoC 2020. I enjoyed every bit of it. This was a life-changing experience for me and now I observe and interpret everything from a different perspective altogether. I have grown into a better developer and a person since GSoC. I would like to thank all my mentors and especially Serge for his immense support and mentorship. I would love to contribute to fury even after GSoC is over but unfortunately my semester break is over so I won’t be as active as I was during the summer. + + 2020-08-23T00:00:00-04:00 + + + https://fury.gl/posts/2020/2020-08-16-week-12-soham.html + Wrecking Ball Simulation, Scrollbars Update, Physics Tutorials. + 2020-08-16T00:00:00-04:00 + + Soham Biswas + + <section id="wrecking-ball-simulation-scrollbars-update-physics-tutorials"> + +<p>Hello and welcome to my 12th weekly check-in. In this blog I will be discussing my progress with the wrecking ball simulation and my scrollbar separation work. Apart from this I have also finalized the physics simulation tutorials and have created a Pull Request to finally get it merged with the official repository. The official repository of my sub-org can be found <a class="reference external" href="https://github.com/fury-gl/fury/">here</a>.</p> +<section id="what-did-you-do-this-week"> +<h2>What did you do this week?</h2> +<p>This week I was mainly focusing on the wrecking ball simulation. This simulation is basically the combination of chain simulation and brick wall simulation. A sphere attached to a chain smashes a “NxNxN” brick wall. The simulation is as follows:</p> +<img alt="https://user-images.githubusercontent.com/29832615/90336291-84232280-dff8-11ea-869b-21a99b203c31.gif" src="https://user-images.githubusercontent.com/29832615/90336291-84232280-dff8-11ea-869b-21a99b203c31.gif" /> +<p>There’s a rendering bug with the cylinders because of which the chain segments look weird. My mentors confirmed that this bug originated from VTK’s <cite>cylinder source</cite> method and they are currently working on it to fix it. The simulation will render correctly once that bug is fixed.</p> +<p>Regarding the scrollbar separation task, I was able to fix those callback issues that I was facing. The mouse callbacks on the scrollbar now work correctly:</p> +<img alt="https://user-images.githubusercontent.com/29832615/90337280-1af2dd80-dfff-11ea-94c4-508121307583.gif" src="https://user-images.githubusercontent.com/29832615/90337280-1af2dd80-dfff-11ea-94c4-508121307583.gif" /> +<p>I have also created a pull request to add the following physics simulations with proper documentation to the main repository:</p> +<ul class="simple"> +<li><p>Brick Wall Simulation</p></li> +<li><p>Ball Collision Simulation</p></li> +<li><p>Chain Simulation</p></li> +<li><p>Wrecking Ball Simulation</p></li> +</ul> +</section> +<section id="what-is-coming-up-next-week"> +<h2>What is coming up next week?</h2> +<p>Currently I am a bit confused with the implementation of scrollbars with UI components. I had a meeting with my mentor and he decided to help me out with this. So most probably I will be working with the scrollbar component and its implementation. Next week will also be the final week for GSoC 2020 before the evaluations start so I would work on getting the final documentation and formalities ready.</p> +</section> +<section id="did-you-get-stuck-anywhere"> +<h2>Did you get stuck anywhere?</h2> +<p>Apart from the scrollbar implementation idea, I did not face any major issues.</p> +<p><code class="docutils literal notranslate"><span class="pre">Thank</span> <span class="pre">you</span> <span class="pre">for</span> <span class="pre">reading,</span> <span class="pre">see</span> <span class="pre">you</span> <span class="pre">next</span> <span class="pre">week!!</span></code></p> +</section> +</section> + + + Hello and welcome to my 12th weekly check-in. In this blog I will be discussing my progress with the wrecking ball simulation and my scrollbar separation work. Apart from this I have also finalized the physics simulation tutorials and have created a Pull Request to finally get it merged with the official repository. The official repository of my sub-org can be found here. + + 2020-08-16T00:00:00-04:00 + + + https://fury.gl/posts/2020/2020-08-09-week-11-soham.html + Chain Simulation, Scrollbar Refactor, Tutorial Update. + 2020-08-09T00:00:00-04:00 + + Soham Biswas + + <section id="chain-simulation-scrollbar-refactor-tutorial-update"> + +<p>Hello and welcome to my 11th weekly check-in. In this blog I will be discussing my progress with multiple topics related to physics and ui components. I was actively working on a couple of things, specifically Joint simulations in pyBullet and scrollbar UI component. I also took up the responsibility to complete an incomplete Pull Request which was pending for quite a while. The official repository of my sub-org can be found <a class="reference external" href="https://github.com/fury-gl/fury/">here</a>.</p> +<section id="what-did-you-do-this-week"> +<h2>What did you do this week?</h2> +<p>The first thing that I did this week was to figure out joint simulations in pybullet. Due to lack of proper documentation I was not aware that Joints are kept stiff by default, hence I had no idea what was wrong with my simulations. Thankfully, while I was browsing pybullet forums, I found this <a class="reference external" href="https://pybullet.org/Bullet/phpBB3/viewtopic.php?f=24&amp;t=13035">post</a> regarding rope simulations when I realized that I had to explicitly set the friction force to prevent stiffness among the Joints. Keeping this point in mind I was able to simulate the following Chain of hexagonal prisms:</p> +<img alt="https://user-images.githubusercontent.com/29832615/89737601-b7613100-da8f-11ea-947f-a96c66caefae.gif" src="https://user-images.githubusercontent.com/29832615/89737601-b7613100-da8f-11ea-947f-a96c66caefae.gif" /> +<p>This week I was mainly supposed to work on refactoring scrollbars as a standalone component. I have made some progress for now. I am able to render the scrollbars properly, with proper size, orientation and color but I am having some issues regarding its scrolling callbacks. I need to look further into it. Here’s a brief glimpse:</p> +<img alt="https://user-images.githubusercontent.com/29832615/89738159-28a2e300-da94-11ea-9167-e825f82edf98.png" src="https://user-images.githubusercontent.com/29832615/89738159-28a2e300-da94-11ea-9167-e825f82edf98.png" /> +<p>This particular <a class="reference external" href="https://github.com/fury-gl/fury/pull/208">PR</a> by a fellow contributor was pending for quite a while, so I decided to look into it and complete it. The objective of the PR was to add examples for the <code class="docutils literal notranslate"><span class="pre">CheckBox</span></code> and <code class="docutils literal notranslate"><span class="pre">RadioButton</span></code> UI components, but the problem was that the objects were not rendered using FURY API in the tutorial, so I decided to complete that. It was already a well made tutorial. I only had to replace the appropriate functions with FURY’s API calls.</p> +<p>The <code class="docutils literal notranslate"><span class="pre">CheckBox</span></code> tutorial:</p> +<img alt="https://user-images.githubusercontent.com/29832615/89438967-20326b80-d767-11ea-8f47-e7711e900c9f.gif" src="https://user-images.githubusercontent.com/29832615/89438967-20326b80-d767-11ea-8f47-e7711e900c9f.gif" /> +<p>There’s still some internal issues while updating the colors of the cube which is currently being worked on by my mentors.</p> +<p>The <code class="docutils literal notranslate"><span class="pre">RadioButton</span></code> tutorial:</p> +<img alt="https://user-images.githubusercontent.com/29832615/89438999-2e808780-d767-11ea-8b08-2a36a05294bc.gif" src="https://user-images.githubusercontent.com/29832615/89438999-2e808780-d767-11ea-8b08-2a36a05294bc.gif" /> +</section> +<section id="what-is-coming-up-next-week"> +<h2>What is coming up next week?</h2> +<p>Next week I will continue working on the scrollbar component and try to fix the issues that I am having with its callbacks. I will also try to work on the wrecking ball simulation.</p> +</section> +<section id="did-you-get-stuck-anywhere"> +<h2>Did you get stuck anywhere?</h2> +<p>Apart from the scrollbar callbacks and stiff joints, I did not face any major issues.</p> +<p><code class="docutils literal notranslate"><span class="pre">Thank</span> <span class="pre">you</span> <span class="pre">for</span> <span class="pre">reading,</span> <span class="pre">see</span> <span class="pre">you</span> <span class="pre">next</span> <span class="pre">week!!</span></code></p> +</section> +</section> + + + Hello and welcome to my 11th weekly check-in. In this blog I will be discussing my progress with multiple topics related to physics and ui components. I was actively working on a couple of things, specifically Joint simulations in pyBullet and scrollbar UI component. I also took up the responsibility to complete an incomplete Pull Request which was pending for quite a while. The official repository of my sub-org can be found here. + + 2020-08-09T00:00:00-04:00 + + + https://fury.gl/posts/2020/2020-08-02-week-10-soham.html + Single Actor, Physics, Scrollbars. + 2020-08-02T00:00:00-04:00 + + Soham Biswas + + <section id="single-actor-physics-scrollbars"> + +<p>Hello and welcome to my 10th weekly check-in. Second evaluation ended this week and now we move on to our 3rd and final coding period. In today’s check-in I will be sharing my progress with the single actor physics simulation that I facing some issues with and I will also be discussing my future plans regarding UI components. The official repository of my sub-org, FURY can always be found <a class="reference external" href="https://github.com/fury-gl/fury/">here</a>.</p> +<section id="what-did-you-do-this-week"> +<h2>What did you do this week?</h2> +<p>This week I was able to figure out the uncontrollable spinning problem that I was facing while rendering physics simulations. Specifically the simulation where a brick wall was rendered by a single actor. The spinning problem was as follows:</p> +<img alt="https://user-images.githubusercontent.com/29832615/88485303-87476780-cf92-11ea-850c-cc63e1376ef8.gif" src="https://user-images.githubusercontent.com/29832615/88485303-87476780-cf92-11ea-850c-cc63e1376ef8.gif" /> +<p>Here’s how the fixed simulation looks like:</p> +<img alt="https://user-images.githubusercontent.com/29832615/89126963-946ed400-d507-11ea-93cd-aad3a9f59ab0.gif" src="https://user-images.githubusercontent.com/29832615/89126963-946ed400-d507-11ea-93cd-aad3a9f59ab0.gif" /> +<p>I was facing this particular issue because I was directly syncing the orientation of the objects in pyBullet world to the objects in the Fury world. So I decided to apply the change in orientation instead and it worked. In order to achieve this I had to keep track of the bricks’ orientation at each step of the simulation, sync the change and then update the tracked orientation. Thankfully, pybullet had convenient tools to achieve this. Here’s a snippet on how to update individual objects rendered by a single actor:</p> +<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">sync_brick</span><span class="p">(</span><span class="n">object_index</span><span class="p">,</span> <span class="n">multibody</span><span class="p">):</span> + <span class="n">pos</span><span class="p">,</span> <span class="n">orn</span> <span class="o">=</span> <span class="n">p</span><span class="o">.</span><span class="n">getBasePositionAndOrientation</span><span class="p">(</span><span class="n">multibody</span><span class="p">)</span> + + <span class="n">rot_mat</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">reshape</span><span class="p">(</span> + <span class="n">p</span><span class="o">.</span><span class="n">getMatrixFromQuaternion</span><span class="p">(</span> + <span class="n">p</span><span class="o">.</span><span class="n">getDifferenceQuaternion</span><span class="p">(</span><span class="n">orn</span><span class="p">,</span> <span class="n">brick_orns</span><span class="p">[</span><span class="n">object_index</span><span class="p">])),</span> + <span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="mi">3</span><span class="p">))</span> + + <span class="n">vertices</span><span class="p">[</span><span class="n">object_index</span> <span class="o">*</span> <span class="n">sec</span><span class="p">:</span> <span class="n">object_index</span> <span class="o">*</span> <span class="n">sec</span> <span class="o">+</span> <span class="n">sec</span><span class="p">]</span> <span class="o">=</span> \ + <span class="p">(</span><span class="n">vertices</span><span class="p">[</span><span class="n">object_index</span> <span class="o">*</span> <span class="n">sec</span><span class="p">:</span> <span class="n">object_index</span> <span class="o">*</span> <span class="n">sec</span> <span class="o">+</span> <span class="n">sec</span><span class="p">]</span> <span class="o">-</span> + <span class="n">brick_centers</span><span class="p">[</span><span class="n">object_index</span><span class="p">])</span><span class="nd">@rot_mat</span> <span class="o">+</span> <span class="n">pos</span> + + <span class="n">brick_centers</span><span class="p">[</span><span class="n">object_index</span><span class="p">]</span> <span class="o">=</span> <span class="n">pos</span> + <span class="n">brick_orns</span><span class="p">[</span><span class="n">object_index</span><span class="p">]</span> <span class="o">=</span> <span class="n">orn</span> +</pre></div> +</div> +<p>All the necessary information is updated <a class="reference external" href="https://docs.google.com/document/d/1XJcG1TL5ZRJZDyi8V76leYZt_maxGp0kOB7OZIxKsTA/edit?usp=sharing">here</a>.</p> +</section> +<section id="what-is-coming-up-next-week"> +<h2>What is coming up next week?</h2> +<p>Currently, the scrollbars are native to <code class="docutils literal notranslate"><span class="pre">ListBox2D</span></code> only. We are planning to separate scrollbars from <code class="docutils literal notranslate"><span class="pre">ListBox2D</span></code> to create a standalone UI component. This was in progress previously but was later discontinued, so I was given the responsibility to complete it. After this we plan to improve File Dialog capabilities later on.</p> +</section> +<section id="did-you-get-stuck-anywhere"> +<h2>Did you get stuck anywhere?</h2> +<p>I did not face any major issues but it took me some time to understand and evaluate the existing discontinued <a class="reference external" href="https://github.com/fury-gl/fury/pull/222">PR</a> regarding scrollbar separation.</p> +<p><code class="docutils literal notranslate"><span class="pre">Thank</span> <span class="pre">you</span> <span class="pre">for</span> <span class="pre">reading,</span> <span class="pre">see</span> <span class="pre">you</span> <span class="pre">next</span> <span class="pre">week!!</span></code></p> +</section> +</section> + + + Hello and welcome to my 10th weekly check-in. Second evaluation ended this week and now we move on to our 3rd and final coding period. In today’s check-in I will be sharing my progress with the single actor physics simulation that I facing some issues with and I will also be discussing my future plans regarding UI components. The official repository of my sub-org, FURY can always be found here. + + 2020-08-02T00:00:00-04:00 + + + https://fury.gl/posts/2020/2020-07-26-week-9-soham.html + Tab UI, TabPanel2D, Tab UI Tutorial. + 2020-07-26T00:00:00-04:00 + + Soham Biswas + + <section id="tab-ui-tabpanel2d-tab-ui-tutorial"> + +<p>Hello and welcome to my 9th weekly check-in. I will be sharing my progress with <code class="docutils literal notranslate"><span class="pre">TabUI</span></code> and its corresponding tutorial. The official repository of my sub-org, FURY can always be found <a class="reference external" href="https://github.com/fury-gl/fury/">here</a>.</p> +<section id="what-did-you-do-this-week"> +<h2>What did you do this week?</h2> +<p>This week I finished the basic implementation of <code class="docutils literal notranslate"><span class="pre">TabUI</span></code>. Apart from that I was also able to finish the tutorial which showcases different features of this said UI. With the help of this UI one can have multiple panels containing different UI elements within them. The basic implementation can be demonstrated as follows:</p> +<img alt="https://user-images.githubusercontent.com/29832615/88484746-87456880-cf8e-11ea-9e96-9cba111b90d3.gif" src="https://user-images.githubusercontent.com/29832615/88484746-87456880-cf8e-11ea-9e96-9cba111b90d3.gif" /> +<p>After finishing with the basic implementation I moved on to create its tutorial. For that, I decided to combine 3 of the existing UI tutorials to be rendered with the help of Tab UI. I implemented the following in individual tabs:</p> +<ul class="simple"> +<li><p>Controlling a cube with the help of <code class="docutils literal notranslate"><span class="pre">LineSlider2D</span></code> and <code class="docutils literal notranslate"><span class="pre">RingSlider2D</span></code>.</p></li> +<li><p>Using a <code class="docutils literal notranslate"><span class="pre">CheckBox</span></code> to render a cylinder or a sphere or both.</p></li> +<li><p>Using <code class="docutils literal notranslate"><span class="pre">ComboBox</span></code> to set the color of a label.</p></li> +</ul> +<p>The above tutorial can be demonstrated as follows:</p> +<img alt="https://user-images.githubusercontent.com/29832615/88481324-6a9e3600-cf78-11ea-8c5b-e26bf158388a.gif" src="https://user-images.githubusercontent.com/29832615/88481324-6a9e3600-cf78-11ea-8c5b-e26bf158388a.gif" /> +</section> +<section id="what-is-coming-up-next-week"> +<h2>What is coming up next week?</h2> +<p>Next week I will continue working on the Physics engine integration. Previously we were facing a problem regarding the uncontrollable spinning of objects rendered by a single actor. There must be an issue with mismatching axes alignment of FURY and pyBullet. The spinning problem is as following:</p> +<img alt="https://user-images.githubusercontent.com/29832615/88485303-87476780-cf92-11ea-850c-cc63e1376ef8.gif" src="https://user-images.githubusercontent.com/29832615/88485303-87476780-cf92-11ea-850c-cc63e1376ef8.gif" /> +</section> +<section id="did-you-get-stuck-anywhere"> +<h2>Did you get stuck anywhere?</h2> +<p>I did get stuck with the collapsing functionality of Tab UI and the uncontrollable spinning of the bricks in the Physics simulation. Apart from that I did not face any major issues.</p> +<p><code class="docutils literal notranslate"><span class="pre">Thank</span> <span class="pre">you</span> <span class="pre">for</span> <span class="pre">reading,</span> <span class="pre">see</span> <span class="pre">you</span> <span class="pre">next</span> <span class="pre">week!!</span></code></p> +</section> +</section> + + + Hello and welcome to my 9th weekly check-in. I will be sharing my progress with TabUI and its corresponding tutorial. The official repository of my sub-org, FURY can always be found here. + + 2020-07-26T00:00:00-04:00 + + + https://fury.gl/posts/2020/2020-07-19-week-8-soham.html + ComboBox2D, TextBlock2D, Clipping Overflow. + 2020-07-19T00:00:00-04:00 + + Soham Biswas + + <section id="combobox2d-textblock2d-clipping-overflow"> + +<p>Hello and welcome to my 8th weekly check-in. I will be sharing my progress with <code class="docutils literal notranslate"><span class="pre">ComboBox2D</span></code> and <code class="docutils literal notranslate"><span class="pre">TextBlock2D</span></code> UI components. After solving <code class="docutils literal notranslate"><span class="pre">TextBlock2D</span></code> sizing issue, I was finally able to complete the implementation of combo box. I also faced some problems while refactoring <code class="docutils literal notranslate"><span class="pre">TextBlock2D</span></code>. The official repository of my sub-org, FURY can always be found <a class="reference external" href="https://github.com/fury-gl/fury/">here</a>.</p> +<section id="what-did-you-do-this-week"> +<h2>What did you do this week?</h2> +<p>This week I finished the implementation of <code class="docutils literal notranslate"><span class="pre">TextBlock2D</span></code> and <code class="docutils literal notranslate"><span class="pre">ComboBox2D</span></code>. I also added necessary tests and tutorials to aid the implementation. It still needs some color design, which will be decided later on. Here’s an overview of the tutorial:</p> +<img alt="https://user-images.githubusercontent.com/29832615/87884567-a8f19d80-ca2c-11ea-8fd2-e7e37b30602f.gif" src="https://user-images.githubusercontent.com/29832615/87884567-a8f19d80-ca2c-11ea-8fd2-e7e37b30602f.gif" /> +<p>Its a simple tutorial where I change the color of the label based on the option selected on the combo box.</p> +<p>Now while refactoring TextBlock2D, I noticed that the Text Overflow workaround on ListBox2D broke and started acting weird. This was mainly because the size implementation was changed and the code that I wrote a few months back wasn’t relevant anymore. So I removed the previous code and had to re-implement the same. I later found out that I would be needing such an implementation for most of my UI components so I decided to create a separate method for clipping overflowing texts.</p> +<p>I had to figure out a specific algorithm to achieve this as the height and width of each characters were different and the combined width of multiple characters were not equal to the sum of their widths. I decided to go for a binary search implementation as it was faster compared to a simple linear checking algorithm. The said algorithm works as expected and is more effective compared to its previous implementation. I tweaked the previous combo box example to showcase this algorithm.</p> +<img alt="https://user-images.githubusercontent.com/29832615/87884568-aabb6100-ca2c-11ea-9ab8-b05bdb8b0631.gif" src="https://user-images.githubusercontent.com/29832615/87884568-aabb6100-ca2c-11ea-9ab8-b05bdb8b0631.gif" /> +<p>The extremely long text is now clipped correctly.</p> +</section> +<section id="what-is-coming-up-next-week"> +<h2>What is coming up next week?</h2> +<p>Next week, I have a couple of things to work on. Firstly, the single actor wall brick simulation is yet to be completed. Once I am done with that I will continue working on Tab UI and try to finish its skeletal implementation.</p> +</section> +<section id="did-you-get-stuck-anywhere"> +<h2>Did you get stuck anywhere?</h2> +<p>I did get stuck regarding the previous implementation of Text Overflow in ListBox2D. Before the current implementation it looked something like this:</p> +<img alt="https://user-images.githubusercontent.com/29832615/87430848-6b8fa900-c603-11ea-87b8-327f6e7f2ee0.png" src="https://user-images.githubusercontent.com/29832615/87430848-6b8fa900-c603-11ea-87b8-327f6e7f2ee0.png" /> +<p>Apart from that, I did not face any major issues.</p> +<p><code class="docutils literal notranslate"><span class="pre">Thank</span> <span class="pre">you</span> <span class="pre">for</span> <span class="pre">reading,</span> <span class="pre">see</span> <span class="pre">you</span> <span class="pre">next</span> <span class="pre">week!!</span></code></p> +</section> +</section> + + + Hello and welcome to my 8th weekly check-in. I will be sharing my progress with ComboBox2D and TextBlock2D UI components. After solving TextBlock2D sizing issue, I was finally able to complete the implementation of combo box. I also faced some problems while refactoring TextBlock2D. The official repository of my sub-org, FURY can always be found here. + + 2020-07-19T00:00:00-04:00 + + + https://fury.gl/posts/2020/2020-07-12-week-7-soham.html + Orientation, Sizing, Tab UI. + 2020-07-12T00:00:00-04:00 + + Soham Biswas + + <section id="orientation-sizing-tab-ui"> + +<p>Hello and welcome to my 7th weekly check-in. I will be sharing my progress with single actor physics simulation and <code class="docutils literal notranslate"><span class="pre">TextBlock2D</span></code> sizing issue which was pending for quite a while now. I will also be sharing my thoughts regarding the <code class="docutils literal notranslate"><span class="pre">TAB</span> <span class="pre">UI</span></code> component. The official repository of my sub-org, FURY can always be found <a class="reference external" href="https://github.com/fury-gl/fury/">here</a>.</p> +<section id="what-did-you-do-this-week"> +<h2>What did you do this week?</h2> +<p>This week I was working with the orientation problem I mentioned in my previous check-in. I did have some problems regarding it, but thanks to my mentor I was able to figure it out and implement it with the help of scipy’s Quaternion to Rotation Matrix <a class="reference external" href="https://github.com/scipy/scipy/blob/v1.5.1/scipy/spatial/transform/rotation.py#L174-L1978">method</a>. After understanding the orientation implementation, I spent some time regarding the design of the TAB UI component. I expect the design to be something similar as follows:</p> +<img alt="https://user-images.githubusercontent.com/29832615/87254337-906b0b80-c49f-11ea-93f3-3af0f2d8de10.png" src="https://user-images.githubusercontent.com/29832615/87254337-906b0b80-c49f-11ea-93f3-3af0f2d8de10.png" /> +<p>Fortunately, we have good news this week. The <code class="docutils literal notranslate"><span class="pre">TextBlock2D</span></code> sizing issue that we were facing for quite a while has now been fixed. We simply have to keep track of the <code class="docutils literal notranslate"><span class="pre">scene</span></code> parameter in the <code class="docutils literal notranslate"><span class="pre">_add_to_scene</span></code> method of each UI component. This scene parameter inherits <code class="docutils literal notranslate"><span class="pre">vtkViewport</span></code>, hence it allows us to determine the necessary details about the environment of the 3D objects.</p> +</section> +<section id="what-is-coming-up-next-week"> +<h2>What is coming up next week?</h2> +<p>As the sizing issue regarding <code class="docutils literal notranslate"><span class="pre">TextBlock2D</span></code> has been fixed, I am very much eager to finish the remaining work left. <code class="docutils literal notranslate"><span class="pre">ComboBox2D</span></code> and <code class="docutils literal notranslate"><span class="pre">TextBlock2D</span></code> were left incomplete because of the issue. Therefore, my main objective next week would be to finish them first. Once I am done with it, I will move on to <code class="docutils literal notranslate"><span class="pre">Tab</span> <span class="pre">UI</span></code>. If not, I will continue with the physics simulation.</p> +</section> +<section id="did-you-get-stuck-anywhere"> +<h2>Did you get stuck anywhere?</h2> +<p>Apart from the orientation and sizing problem, I did not face any major issues.</p> +<p><code class="docutils literal notranslate"><span class="pre">Thank</span> <span class="pre">you</span> <span class="pre">for</span> <span class="pre">reading,</span> <span class="pre">see</span> <span class="pre">you</span> <span class="pre">next</span> <span class="pre">week!!</span></code></p> +</section> +</section> + + + Hello and welcome to my 7th weekly check-in. I will be sharing my progress with single actor physics simulation and TextBlock2D sizing issue which was pending for quite a while now. I will also be sharing my thoughts regarding the TAB UI component. The official repository of my sub-org, FURY can always be found here. + + 2020-07-12T00:00:00-04:00 + + + https://fury.gl/posts/2020/2020-07-05-week-6-soham.html + Translation, Reposition, Rotation. + 2020-07-05T00:00:00-04:00 + + Soham Biswas + + <section id="translation-reposition-rotation"> + +<p>Hello and welcome to my 6th weekly check-in. The first evaluation period officially ends and I am very excited to move on to the second coding period. I will be sharing my progress with handling specific object’s properties among various multiple objects rendered by a single actor. I am mainly focusing on making it easier to translate, rotate and reposition a particular object, so that I can use them to render physics simulations more efficiently. The official repository of my sub-org, FURY can always be found <a class="reference external" href="https://github.com/fury-gl/fury/">here</a>.</p> +<section id="what-did-you-do-this-week"> +<h2>What did you do this week?</h2> +<p>Last week I worked on physics simulations rendered in FURY with the help of pyBullet. Now the simulations were highly un-optimized, specially the brick wall simulation as each brick was rendered by its own actor. In other words, 1 brick = 1 actor. Now my objective was to render all the bricks using a single actor, but before jumping into the simulation I had to figure out how to modify specific properties of an individual object. Thanks to my mentor’s <a class="reference external" href="https://github.com/fury-gl/fury/pull/233">PR</a>, I was able to experiment my implementations quickly.</p> +<section id="translation"> +<h3>Translation:</h3> +<img alt="https://user-images.githubusercontent.com/29832615/86536066-5085b080-bf02-11ea-9bcd-9e555adc2ca1.gif" src="https://user-images.githubusercontent.com/29832615/86536066-5085b080-bf02-11ea-9bcd-9e555adc2ca1.gif" /> +<p>The algorithm behind translation is to first identify the vertices of the object, then bring the vertices to the origin by subtracting their centers and then adding the displacement vector. The said operation can be achieved by the following snippet:</p> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span># Update vertices positions +vertices[object_index * sec: object_index * sec + sec] = \ + (vertices[object_index * sec: object_index * sec + sec] - centers[object_index]) + transln_vector​ +</pre></div> +</div> +</section> +<section id="rotation"> +<h3>Rotation:</h3> +<img alt="https://user-images.githubusercontent.com/29832615/86536065-4fed1a00-bf02-11ea-815d-f7f297165c53.gif" src="https://user-images.githubusercontent.com/29832615/86536065-4fed1a00-bf02-11ea-815d-f7f297165c53.gif" /> +<p>The algorithm behind rotation is to first calculate the difference between the vertices and the center of the object. Once we get the resultant matrix, we matrix multiply it with the rotation matrix and then we further add the centers back to it so that we preserve the position of the object. Rotation matrix can be defined as:</p> +<img alt="https://wikimedia.org/api/rest_v1/media/math/render/svg/242deb7010fd504134a6cacab3d0ef4ce02e7613" src="https://wikimedia.org/api/rest_v1/media/math/render/svg/242deb7010fd504134a6cacab3d0ef4ce02e7613" /> +<p>where gamma, beta and alpha corresponds to the angle of rotation along Z-axis, Y-axis and X-axis.</p> +<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">get_R</span><span class="p">(</span><span class="n">gamma</span><span class="p">,</span> <span class="n">beta</span><span class="p">,</span> <span class="n">alpha</span><span class="p">):</span> +<span class="w"> </span><span class="sd">&quot;&quot;&quot; Returns rotational matrix.</span> +<span class="sd"> &quot;&quot;&quot;</span> + <span class="n">r</span> <span class="o">=</span> <span class="p">[</span> + <span class="p">[</span><span class="n">np</span><span class="o">.</span><span class="n">cos</span><span class="p">(</span><span class="n">alpha</span><span class="p">)</span><span class="o">*</span><span class="n">np</span><span class="o">.</span><span class="n">cos</span><span class="p">(</span><span class="n">beta</span><span class="p">),</span> <span class="n">np</span><span class="o">.</span><span class="n">cos</span><span class="p">(</span><span class="n">alpha</span><span class="p">)</span><span class="o">*</span><span class="n">np</span><span class="o">.</span><span class="n">sin</span><span class="p">(</span><span class="n">beta</span><span class="p">)</span><span class="o">*</span><span class="n">np</span><span class="o">.</span><span class="n">sin</span><span class="p">(</span><span class="n">gamma</span><span class="p">)</span> <span class="o">-</span> <span class="n">np</span><span class="o">.</span><span class="n">sin</span><span class="p">(</span><span class="n">alpha</span><span class="p">)</span><span class="o">*</span><span class="n">np</span><span class="o">.</span><span class="n">cos</span><span class="p">(</span><span class="n">gamma</span><span class="p">),</span> + <span class="n">np</span><span class="o">.</span><span class="n">cos</span><span class="p">(</span><span class="n">alpha</span><span class="p">)</span><span class="o">*</span><span class="n">np</span><span class="o">.</span><span class="n">sin</span><span class="p">(</span><span class="n">beta</span><span class="p">)</span><span class="o">*</span><span class="n">np</span><span class="o">.</span><span class="n">cos</span><span class="p">(</span><span class="n">gamma</span><span class="p">)</span> <span class="o">+</span> <span class="n">np</span><span class="o">.</span><span class="n">sin</span><span class="p">(</span><span class="n">alpha</span><span class="p">)</span><span class="o">*</span><span class="n">np</span><span class="o">.</span><span class="n">sin</span><span class="p">(</span><span class="n">gamma</span><span class="p">)],</span> + <span class="p">[</span><span class="n">np</span><span class="o">.</span><span class="n">sin</span><span class="p">(</span><span class="n">alpha</span><span class="p">)</span><span class="o">*</span><span class="n">np</span><span class="o">.</span><span class="n">cos</span><span class="p">(</span><span class="n">beta</span><span class="p">),</span> <span class="n">np</span><span class="o">.</span><span class="n">sin</span><span class="p">(</span><span class="n">alpha</span><span class="p">)</span><span class="o">*</span><span class="n">np</span><span class="o">.</span><span class="n">sin</span><span class="p">(</span><span class="n">beta</span><span class="p">)</span><span class="o">*</span><span class="n">np</span><span class="o">.</span><span class="n">sin</span><span class="p">(</span><span class="n">gamma</span><span class="p">)</span> <span class="o">+</span> <span class="n">np</span><span class="o">.</span><span class="n">cos</span><span class="p">(</span><span class="n">alpha</span><span class="p">)</span><span class="o">*</span><span class="n">np</span><span class="o">.</span><span class="n">cos</span><span class="p">(</span><span class="n">gamma</span><span class="p">),</span> + <span class="n">np</span><span class="o">.</span><span class="n">sin</span><span class="p">(</span><span class="n">alpha</span><span class="p">)</span><span class="o">*</span><span class="n">np</span><span class="o">.</span><span class="n">sin</span><span class="p">(</span><span class="n">beta</span><span class="p">)</span><span class="o">*</span><span class="n">np</span><span class="o">.</span><span class="n">cos</span><span class="p">(</span><span class="n">gamma</span><span class="p">)</span> <span class="o">-</span> <span class="n">np</span><span class="o">.</span><span class="n">cos</span><span class="p">(</span><span class="n">alpha</span><span class="p">)</span><span class="o">*</span><span class="n">np</span><span class="o">.</span><span class="n">sin</span><span class="p">(</span><span class="n">gamma</span><span class="p">)],</span> + <span class="p">[</span><span class="o">-</span><span class="n">np</span><span class="o">.</span><span class="n">sin</span><span class="p">(</span><span class="n">beta</span><span class="p">),</span> <span class="n">np</span><span class="o">.</span><span class="n">cos</span><span class="p">(</span><span class="n">beta</span><span class="p">)</span><span class="o">*</span><span class="n">np</span><span class="o">.</span><span class="n">sin</span><span class="p">(</span><span class="n">gamma</span><span class="p">),</span> <span class="n">np</span><span class="o">.</span><span class="n">cos</span><span class="p">(</span><span class="n">beta</span><span class="p">)</span><span class="o">*</span><span class="n">np</span><span class="o">.</span><span class="n">cos</span><span class="p">(</span><span class="n">gamma</span><span class="p">)]</span> + <span class="p">]</span> + <span class="n">r</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">(</span><span class="n">r</span><span class="p">)</span> + <span class="k">return</span> <span class="n">r</span> + +<span class="n">vertices</span><span class="p">[</span><span class="n">object_index</span> <span class="o">*</span> <span class="n">sec</span><span class="p">:</span> <span class="n">object_index</span> <span class="o">*</span> <span class="n">sec</span> <span class="o">+</span> <span class="n">sec</span><span class="p">]</span> <span class="o">=</span> \ + <span class="p">(</span><span class="n">vertices</span><span class="p">[</span><span class="n">object_index</span> <span class="o">*</span> <span class="n">sec</span><span class="p">:</span> <span class="n">object_index</span> <span class="o">*</span> <span class="n">sec</span> <span class="o">+</span> <span class="n">sec</span><span class="p">]</span> <span class="o">-</span> + <span class="n">centers</span><span class="p">[</span><span class="n">object_index</span><span class="p">])</span><span class="nd">@get_R</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">np</span><span class="o">.</span><span class="n">pi</span><span class="o">/</span><span class="mi">4</span><span class="p">,</span> <span class="n">np</span><span class="o">.</span><span class="n">pi</span><span class="o">/</span><span class="mi">4</span><span class="p">)</span> <span class="o">+</span> <span class="n">centers</span><span class="p">[</span><span class="n">object_index</span><span class="p">]</span> +</pre></div> +</div> +</section> +<section id="reposition"> +<h3>Reposition:</h3> +<img alt="https://user-images.githubusercontent.com/29832615/86536063-4ebbed00-bf02-11ea-8592-a695d7b91426.gif" src="https://user-images.githubusercontent.com/29832615/86536063-4ebbed00-bf02-11ea-8592-a695d7b91426.gif" /> +<p>Repositioning is similar to that of translation, except in this case, while repositioning we update centers with the new position value.</p> +<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">new_pos</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">([</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">])</span> + +<span class="c1"># Update vertices positions</span> +<span class="n">vertices</span><span class="p">[</span><span class="n">object_index</span> <span class="o">*</span> <span class="n">sec</span><span class="p">:</span> <span class="n">object_index</span> <span class="o">*</span> <span class="n">sec</span> <span class="o">+</span> <span class="n">sec</span><span class="p">]</span> <span class="o">=</span> \ + <span class="p">(</span><span class="n">vertices</span><span class="p">[</span><span class="n">object_index</span> <span class="o">*</span> <span class="n">sec</span><span class="p">:</span> <span class="n">object_index</span> <span class="o">*</span> <span class="n">sec</span> <span class="o">+</span> <span class="n">sec</span><span class="p">]</span> <span class="o">-</span> + <span class="n">centers</span><span class="p">[</span><span class="n">object_index</span><span class="p">])</span> <span class="o">+</span> <span class="n">new_pos</span> + +<span class="n">centers</span><span class="p">[</span><span class="n">object_index</span><span class="p">]</span> <span class="o">=</span> <span class="n">new_pos</span> +</pre></div> +</div> +</section> +</section> +<section id="what-is-coming-up-next-week"> +<h2>What is coming up next week?</h2> +<p>Currently, I am yet to figure out the orientation problem. Once I figure that out I will be ready to implement simulations without any major issues. I am also tasked with creating a wrecking ball simulation and a quadruped robot simulation.</p> +</section> +<section id="did-you-get-stuck-anywhere"> +<h2>Did you get stuck anywhere?</h2> +<p>I did face some problems while rotating objects. My mentors suggested me to implement it via rotation matrix. I still haven’t figured out the orientation problem, which I plan to work on next. Apart from these I did not face any major issues.</p> +<p><code class="docutils literal notranslate"><span class="pre">Thank</span> <span class="pre">you</span> <span class="pre">for</span> <span class="pre">reading,</span> <span class="pre">see</span> <span class="pre">you</span> <span class="pre">next</span> <span class="pre">week!!</span></code></p> +</section> +</section> + + + Hello and welcome to my 6th weekly check-in. The first evaluation period officially ends and I am very excited to move on to the second coding period. I will be sharing my progress with handling specific object’s properties among various multiple objects rendered by a single actor. I am mainly focusing on making it easier to translate, rotate and reposition a particular object, so that I can use them to render physics simulations more efficiently. The official repository of my sub-org, FURY can always be found here. + + 2020-07-05T00:00:00-04:00 + + + https://fury.gl/posts/2020/2020-06-28-week-5-soham.html + May the Force be with you!! + 2020-06-28T00:00:00-04:00 + + Soham Biswas + + <section id="may-the-force-be-with-you"> + +<p>Hello and welcome to my 5th weekly check-in, I will be sharing my progress of pyBullet Physics Engine Integration with FURY. The official repository of my sub-org, FURY can always be found <a class="reference external" href="https://github.com/fury-gl/fury/">here</a>.</p> +<section id="what-did-you-do-this-week"> +<h2>What did you do this week?</h2> +<p>Last week due to the <code class="docutils literal notranslate"><span class="pre">vtkTextActor</span></code> sizing issue I was not able to continue my work with <code class="docutils literal notranslate"><span class="pre">ComboBox2D</span></code> UI element. Thus, I decided to work on the “Physics Engine Integration” part of my project. It took me quite a while to understand the terminology of various methods and algorithms used for detection and physics simulation. Nevertheless, I was able to create a couple of rigid body examples to showcase the integration procedure. For physics calculations we used pyBullet and for rendering we used FURY. In other words, pyBullet will handle the backend part of the simulation and FURY will handle the frontend. I have documented the entire integration process <a class="reference external" href="https://docs.google.com/document/d/1XJcG1TL5ZRJZDyi8V76leYZt_maxGp0kOB7OZIxKsTA/edit?usp=sharing">here</a> in detail.</p> +<section id="ball-collision-simulation"> +<h3>Ball Collision Simulation:</h3> +<img alt="https://user-images.githubusercontent.com/29832615/85949638-988e5b80-b975-11ea-85ba-16c1f78dec89.gif" src="https://user-images.githubusercontent.com/29832615/85949638-988e5b80-b975-11ea-85ba-16c1f78dec89.gif" /> +<p>For the first example, I created a simple collision between two balls in which two spheres were created both in FURY and pyBullet world and then both the worlds are connected by syncing the position and orientation of the said bodies. Timer callback is created to update the positions and to simulate Physics for each step.</p> +</section> +<section id="brick-wall-simulation"> +<h3>Brick Wall Simulation:</h3> +<img alt="https://raw.githubusercontent.com/Nibba2018/testing-fury/master/2020-06-26_21-15-47.gif" src="https://raw.githubusercontent.com/Nibba2018/testing-fury/master/2020-06-26_21-15-47.gif" /> +<p>For the second example I tried to increase the complexity of the simulations by increasing the number of dynamic objects. Here a brick-wall is created using 100 bricks and then a ball is thrown at it. The rest of it is simulated. The same concepts from the first example is used to render the second one. Timer callback is created to update position of all the objects and to simulate Physics for each step.</p> +</section> +</section> +<section id="what-is-coming-up-next-week"> +<h2>What is coming up next week?</h2> +<p>In the above examples I used a separate actor for each object which is highly un-optimized. Thus, my mentor suggested me to render all the bricks using a single actor, so that the simulation is more optimized. I am not very confident in changing the position and orientation of different objects rendered by a single actor. Therefore, I will have to research a bit more about it. Apart from that I will also try to work on Constraint based simulation examples if possible.</p> +</section> +<section id="did-you-get-stuck-anywhere"> +<h2>Did you get stuck anywhere?</h2> +<p>The pyBullet documentation isn’t well written for cross rendering, hence it was a bit of a challenge for me to implement the integration. I also faced a problem regarding the offset of actors between the FURY world and pyBullet world. Both use different coordinate systems for rendering and simulation because of which I had a constant offset between the objects during simulations. I was able to fix it by converting one coordinate system to the other. Apart from this I did not have any major issues.</p> +<p><code class="docutils literal notranslate"><span class="pre">Thank</span> <span class="pre">you</span> <span class="pre">for</span> <span class="pre">reading,</span> <span class="pre">see</span> <span class="pre">you</span> <span class="pre">next</span> <span class="pre">week!!</span></code></p> +</section> +</section> + + + Hello and welcome to my 5th weekly check-in, I will be sharing my progress of pyBullet Physics Engine Integration with FURY. The official repository of my sub-org, FURY can always be found here. + + 2020-06-28T00:00:00-04:00 + + diff --git a/v0.10.x/blog/author/tania-castillo.html b/v0.10.x/blog/author/tania-castillo.html new file mode 100644 index 000000000..d36f67e1c --- /dev/null +++ b/v0.10.x/blog/author/tania-castillo.html @@ -0,0 +1,1460 @@ + + + + + + + Posts by Tania Castillo — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +
+

+ + Posts by + + Tania Castillo + +

+ + +
+

+ Week 12 : Experimenting with ODFs implementation +

+
    +
  • + + + 24 August 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Tania Castillo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

There were different issues I needed to address for the ODF implementation. Even though I could not solve any of them completely, I did check each of the issues and made some progress. All the work in progress is being recorded in the following branch SH-for-ODF-impl, which when ready will be associated with a well-structured PR.

+

+ +

Read more ...

+
+
+ +
+

+ Google Summer of Code Final Work Product +

+
    +
  • + + + 24 August 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Tania Castillo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Name: Tania Castillo

+

+ +

Read more ...

+
+
+ +
+

+ Week 11 : Adjusting ODF implementation and looking for solutions on issues found +

+
    +
  • + + + 16 August 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Tania Castillo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

I continued to experiment with the ODF glyph implementation. Thanks to one of my mentors I figured out how to get the missing data corresponding to the SH coefficients \(a^l_m\) part of the function \(f(\theta, \phi)\) described here. I also was told to make sure to implement the correct SH basis since there are different definitions from the literature, I have to focus now in the one proposed by Descoteaux, described in this paper, which is labeled in dipy as descoteaux07. To do this I had to make a small adjustment to the base implementation that I took as a reference, from which I obtained a first result using SH of order 4.

+

+ +

Read more ...

+
+
+ +
+

+ Week 10 : Start of SH implementation experiments +

+
    +
  • + + + 08 August 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Tania Castillo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

I started formally working on SH implementation. I was told to start first doing a simple program where I can modify in real-time the order \(l\) and degree \(m\), parameters corresponding to the Spherical Harmonics function \(Y^m_l(\theta,\phi)=\), based on previous work. That is just one part of the final ODF calculation, but here is what a first experimental script looks like.

+

+ +

Read more ...

+
+
+ +
+

+ Week 9: Tutorial done and polishing DTI uncertainty +

+
    +
  • + + + 31 July 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Tania Castillo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

I addressed the comments from the tutorial of PR #818 related to how to display specific visualizations I wanted to make. I was suggested to use ShowManager to handle the zoom of the scene and also to use GridUI to display several actors at the same time for a visual quality comparison of the tensors. Below are some images generated for the tutorial that is almost done.

+

+ +

Read more ...

+
+
+ +
+

+ Week 8: Working on Ellipsoid Tutorial and exploring SH +

+
    +
  • + + + 25 July 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Tania Castillo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

I mainly worked on the ellipsoid actor tutorial, as PR #791 is finally merged, so I was able to complete the tutorial by adding my implementation. In addition, during the weekly meeting, I received a good overview of the next issue I will be working on, which is using raymarching SDFs to display spherical harmonics (SH) for visualizing ODF glyphs for DTI. I got several ideas and resources which I can start experimenting with, such as Shadertoy and some base implementations from other FURY contributors. The main drawback when creating these objects is the amount of data required to create them, because depending on the SH order, the number of parameters that the function receives may vary, also unlike the tensors, which are represented only with a 3x3 matrix, here we could have more than 9 values associated with a single glyph, so passing the information from python to the shaders is not so trivial, besides requiring more resources as there is more information that needs to be processed. Some ideas I received were using matrixes instead of vectors, using templating, or even using texture to pass the data. I started to explore these options further, as well as to review in more detail the existing implementations of SH with raymarching, in order to understand them better.

+

+ +

Read more ...

+
+
+ +
+

+ Week 7: Adjustments on the Uncertainty Cones visualization +

+
    +
  • + + + 17 July 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Tania Castillo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

I was told to refactor some parts of the uncertainty PR, since I was relying too much on dipy functions which is not good because it makes maintenance more difficult as dipy requires FURY for some functionalities. So I did some adjustments on the uncertainty function parameters and the corresponding tests, hopefully I managed to get with the most appropriate definition but I need to receive a first feedback to see how much I have to adjust the implementation. As I had to delete some relevant code lines inside the uncertainty calculation which consisted of preprocessing the data in order to define the necessary variables for the uncertainty formula, I was also suggested to make a tutorial of this new feature, so I can explain in detail how to obtain and adjust the necessary information, before passing it to the actor, and in general how and what is the purpose of this new function.

+

+ +

Read more ...

+
+
+ +
+

+ Week 6: First draft of the Ellipsoid tutorial +

+
    +
  • + + + 10 July 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Tania Castillo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

#PR 818: Tutorial on using ellipsoid actor to visualize tensor ellipsoids for DTI

+

+ +

Read more ...

+
+
+ +
+

+ Week 5: Preparing the data for the Ellipsoid tutorial +

+
    +
  • + + + 03 July 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Tania Castillo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

During the weekly meeting with my mentors, there was a small discussion over the naming of the actor and its usage. On the one hand, although the purpose of the actor is to visualize diffusion tensor ellipsoids, the idea is that it can also be used for any other type of visualization that requires the use of ellipsoids, so in the end, we decided to keep the name ellipsoid as it is more generic. On the other hand, as there is already an actor made for the purpose of tensor visualization, namely tensor_slicer, it might not be obvious how and why one would use this new ellipsoid actor for this purpose, thus it was proposed to make a tutorial that can clarify this. The main difference between both actors relies on the quality and the amount of data that can be displayed, so the idea is to show the difference between both alternatives so the user can choose which one to use depending on their needs. To prepare the tutorial the first step was to add the data I will use on fury-data so I can then fetch and load the datasets I need to work on the tutorial.

+

+ +

Read more ...

+
+
+ +
+

+ Week 4: First draft of the DTI uncertainty visualization +

+
    +
  • + + + 27 June 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Tania Castillo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

#PR 810: DTI uncertainty visualization

+

+ +

Read more ...

+
+
+ +
+

+ Week 3: Working on uncertainty and details of the first PR +

+
    +
  • + + + 19 June 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Tania Castillo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

I made some adjustments to the ellipsoid actor definition, now called tensor. This was something discussed in the weekly meeting as the coming changes are related to this actor, the idea now is to have a tensor actor that allows choosing between displaying the tensor ellipsoids or the uncertainty cones (later on). I also worked on the uncertainty calculation, and the cone SDF for the visualization, so I plan to do a WIP PR next to start getting feedback on this new addition.

+

+ +

Read more ...

+
+
+ +
+

+ Week 2: Making adjustments to the Ellipsoid Actor +

+
    +
  • + + + 12 June 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Tania Castillo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

I made some minor adjustments to the last PR I submitted. Last time it was a draft since I was waiting for the weekly meeting to know how to proceed, but now it is ready. I am waiting for the review so I can make the necessary corrections and adjustments to merge this first PR soon.

+

+ +

Read more ...

+
+
+ +
+

+ Week 1: Ellipsoid actor implemented with SDF +

+
    +
  • + + + 05 June 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Tania Castillo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

PR #791: Ellipsoid actor implemented with SDF

+

+ +

Read more ...

+
+
+ +
+

+ Week 0: Community Bounding Period +

+
    +
  • + + + 02 June 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Tania Castillo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hello everyone, my name is Tania Castillo, I am close to finishing my degree in Computer Science and I think this is a great opportunity to put my learning and skills into practice. I will be working with FURY on improving the visualization of DTI tensors and HARDI ODFs glyphs by using well-known techniques in computer graphics.

+

+ +

Read more ...

+
+
+ + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/blog/author/tania-castillo/atom.xml b/v0.10.x/blog/author/tania-castillo/atom.xml new file mode 100644 index 000000000..052f22fbc --- /dev/null +++ b/v0.10.x/blog/author/tania-castillo/atom.xml @@ -0,0 +1,486 @@ + + + https://fury.gl/ + Blog - Posts by Tania Castillo + 2024-02-29T15:43:57.561356+00:00 + + + ABlog + + https://fury.gl/posts/2023/2023-08-24-week-12-tvcastillod.html + Week 12 : Experimenting with ODFs implementation + 2023-08-24T00:00:00-04:00 + + Tania Castillo + + <section id="week-12-experimenting-with-odfs-implementation"> + +<section id="what-did-i-do-this-week"> +<h2>What did I do this week?</h2> +<p>There were different issues I needed to address for the ODF implementation. Even though I could not solve any of them completely, I did check each of the issues and made some progress. All the work in progress is being recorded in the following branch <a class="reference external" href="https://github.com/tvcastillod/fury/tree/SH-for-ODF-impl">SH-for-ODF-impl</a>, which when ready will be associated with a well-structured PR.</p> +<p>First, about the scaling, I was suggested to check Generalized Fractional Anisotropy <strong>gfa</strong> metric to adjust the scaling depending on the shape of the ODF glyph, i.e., the less the <strong>gfa</strong> the more sphere-shaped and smaller, so I had to associate a greater scaling for those. However, this did not work very well as I was unable to define an appropriate scale relation that would give an equitable result for each glyph. For this reason, I opted to use peak values which are extracted from the ODFs, setting the scales as 1/peak_value*0.4 and I got a more uniformly sized glyph without the need of setting it manually. That is a temporal solution as I would like to see better why this happens and if possible do the adjustment inside the shader instead of a precalculation.</p> +<p>Second, for the direction, I made a small adjustment to the spherical coordinates which affected the direction of the ODF glyph. As you can see below,</p> +<img alt="https://user-images.githubusercontent.com/31288525/263122770-b9ee19d2-d82b-4d7f-a5bb-1cbbf5907049.png" class="align-center" src="https://user-images.githubusercontent.com/31288525/263122770-b9ee19d2-d82b-4d7f-a5bb-1cbbf5907049.png" style="width: 400px;" /> +<p>All the glyphs are aligned over the y-axis but not over the z-axis, to correct this I precalculated the main direction of each glyph using peaks and passed it to the shader as a <em>vec3</em>, then used <em>vec2vecrotmat</em> to align the main axis vector of the ODF to the required direction vector, the only problem with this is that not all the glyps are equally aligned to the axis, i.e., the first 3 glyphs are aligned with the x-axis but the last one is aligned with the y-axis, so the final rotation gives a different result for that one.</p> +<img alt="https://user-images.githubusercontent.com/31288525/263122752-b2aa696f-62a5-4b09-b8dd-0cb1ec49431c.png" class="align-center" src="https://user-images.githubusercontent.com/31288525/263122752-b2aa696f-62a5-4b09-b8dd-0cb1ec49431c.png" style="width: 400px;" /> +<p>As with the first small adjustment of the coordinates the direction was partially correct, I need to double check the theta, phi and r definitions to see if I can get the right direction without the need of the additional data of direction. Also, there might be a way to get the specific rotation angles associated to each individual glyph from the data associated with the ODFs.</p> +<p>Third, about passing the coefficients data through textures, I understand better now how to pass textures to the shaders but I still have problems understanding how to retrieve the data inside the shader. I used <a class="reference external" href="https://github.com/fury-gl/fury/blob/master/docs/experimental/viz_shader_texture.py">this base implementation</a>, suggested by one of my mentors, to store the data as a <a class="reference external" href="http://www.khronos.org/opengl/wiki/Cubemap_Texture#:~:text=A%20Cubemap%20Texture%20is%20a,the%20value%20to%20be%20accessed.">texture cubemap</a>, “a texture, where each mipmap level consists of six 2D images which must be square. The 6 images represent the faces of a cube”. I had 4x15 coefficients and inside the function, a grid of RGB colors is made so then it can be mapped as a texture. To check if was passing the data correctly, I used the same value, .5, for all the textures, so then I could pick a random texel get a specific color (gray), and pass it as <em>fragOutput0</em> to see if the value was correct. However, it didn’t appear to work correctly as I couldn’t get the expected color. To get the specific color I used <a class="reference external" href="https://registry.khronos.org/OpenGL-Refpages/gl4/html/texture.xhtml">texture(sampler, P)</a> which samples texels from the texture bound to sampler at texture coordinate P. Now, what I still need to figure out is which should be the corresponding texture coordinate. I have tried with random coordinates, as they are supposed to correspond to a point on the cube and since the information I have encoded in the texture is all the same, I assumed that I would get the expected result for any set of values. It might be a problem with the data normalization, or maybe there is something failing on the texture definition, but I need to review it in more detail to see where is the problem.</p> +<p>Lastly, about the colormapping, I created the texture based on a generic colormap from <a class="reference external" href="https://matplotlib.org/stable/tutorials/colors/colormaps.html">matplotlib</a>. I was able to give some color to the glyph but it does not match correctly its shape. Some adjustment must be done regarding the texels, as the colormap is mapped on a cube, but I need it to fit the shape of the glyph correctly.</p> +<img alt="https://user-images.githubusercontent.com/31288525/263122760-7d1fff5e-7787-473c-8053-ea69f3009fb4.png" class="align-center" src="https://user-images.githubusercontent.com/31288525/263122760-7d1fff5e-7787-473c-8053-ea69f3009fb4.png" style="width: 250px;" /> +</section> +<section id="what-is-coming-up-next"> +<h2>What is coming up next?</h2> +<p>I will continue to explore more on how to handle textures so I can solve the issues related to the coefficient data and colormapping. Also, take a deeper look at the SH implementation and check what is the information needed to adjust the main direction of the ODF correctly.</p> +</section> +<section id="did-i-get-stuck-anywhere"> +<h2>Did I get stuck anywhere?</h2> +<p>As I mentioned I had some drawbacks in understanding the use of textures and how to retrieve the data inside the shaders. This is a topic that might take some time to manage properly but if I can master it and understand it better, it is a tool that can be useful later. Additionally, there are details of the SH implementation that I still need to understand and explore better in order to make sure I get exactly the same result as the current <em>odf_slicer</em> implementation.</p> +</section> +</section> + + + There were different issues I needed to address for the ODF implementation. Even though I could not solve any of them completely, I did check each of the issues and made some progress. All the work in progress is being recorded in the following branch SH-for-ODF-impl, which when ready will be associated with a well-structured PR. + + 2023-08-24T00:00:00-04:00 + + + https://fury.gl/posts/2023/2023-08-24-final-report-tvcastillod.html + Google Summer of Code Final Work Product + 2023-08-24T00:00:00-04:00 + + Tania Castillo + + <a class="reference external image-reference" href="https://summerofcode.withgoogle.com/programs/2023/projects/ymwnLwtT"><img alt="https://developers.google.com/open-source/gsoc/resources/downloads/GSoC-logo-horizontal.svg" class="align-center" height="50" src="https://developers.google.com/open-source/gsoc/resources/downloads/GSoC-logo-horizontal.svg" /></a> +<a class="reference external image-reference" href="https://summerofcode.withgoogle.com/programs/2023/organizations/python-software-foundation"><img alt="https://www.python.org/static/community_logos/python-logo.png" src="https://www.python.org/static/community_logos/python-logo.png" style="width: 40%;" /></a> +<a class="reference external image-reference" href="https://fury.gl/latest/index.html"><img alt="https://python-gsoc.org/logos/FURY.png" src="https://python-gsoc.org/logos/FURY.png" style="width: 25%;" /></a> +<section id="google-summer-of-code-final-work-product"> + +<ul class="simple"> +<li><p><strong>Name:</strong> Tania Castillo</p></li> +<li><p><strong>Organisation:</strong> Python Software Foundation</p></li> +<li><p><strong>Sub-Organisation:</strong> FURY</p></li> +<li><p><strong>Project:</strong> <a class="reference external" href="https://github.com/fury-gl/fury/wiki/Google-Summer-of-Code-2023-(GSOC2023)#project-3-sdf-based-uncertainty-representation-for-dmri-glyphs">SDF-based uncertainty representation for dMRI glyphs</a></p></li> +</ul> +<section id="abstract"> +<h2>Abstract</h2> +<p>Diffusion Magnetic Resonance Imaging (dMRI) is a non-invasive imaging technique used by neuroscientists to measure the diffusion of water molecules in biological tissue. The directional information is reconstructed using either a Diffusion Tensor Imaging (DTI) or High Angular Resolution Diffusion Imaging (HARDI) based model, which is graphically represented as tensors and Orientation Distribution Functions (ODF). Traditional rendering engines discretize Tensor and ODF surfaces using triangles or quadrilateral polygons, making their visual quality depending on the number of polygons used to build the 3D mesh, which might compromise real-time display performance. This project proposes a methodological approach to further improve the visualization of DTI tensors and HARDI ODFs glyphs by using well-established techniques in the field of computer graphics, such as geometry amplification, billboarding, signed distance functions (SDFs), and ray marching.</p> +</section> +<section id="proposed-objectives"> +<h2>Proposed Objectives</h2> +<ul class="simple"> +<li><p>Implement a parallelized version of computer-generated billboards using geometry shaders for amplification.</p></li> +<li><p>Model the mathematical functions that express the geometry of ellipsoid glyphs and implement them using Ray Marching techniques.</p></li> +<li><p>Model the mathematical functions that express the geometry of ODF glyphs and implement them using Ray Marching techniques.</p></li> +<li><p>Use SDF properties and techniques to represent the uncertainty of dMRI reconstruction models.</p></li> +</ul> +</section> +<section id="objectives-completed"> +<h2>Objectives Completed</h2> +<section id="ellipsoid-actor-implemented-with-sdf"> +<h3>Ellipsoid actor implemented with SDF</h3> +<p>A first approach for tensor glyph generation has been made, using ray marching and SDF applied to a box. The current implementation (<code class="docutils literal notranslate"><span class="pre">tensor_slicer</span></code>) requires a sphere with a specific number of vertices to be deformed. Based on this model, a sphere with more vertices is needed to get a higher resolution. Because the ray marching technique does not use polygonal meshes, it is possible to define perfectly smooth surfaces and still obtain a fast rendering.</p> +<p>Details of the implementation:</p> +<ul class="simple"> +<li><p><em>Vertex shader pre-calculations</em>: Some minor calculations are done in the vertex shader. One, corresponding to the eigenvalues constraining and min-max normalization, are to avoid incorrect visualizations when the difference between the eigenvalues is too large. And the other is related to the tensor matrix calculation given by the diffusion tensor definition <span class="math notranslate nohighlight">\(T = R^{−1}\Lambda R\)</span>, where <span class="math notranslate nohighlight">\(R\)</span> is a rotation matrix that transforms the standard basis onto the eigenvector basis, and <span class="math notranslate nohighlight">\(\Lambda\)</span> is the diagonal matrix of eigenvalues <a class="footnote-reference brackets" href="#id10" id="id1" role="doc-noteref"><span class="fn-bracket">[</span>4<span class="fn-bracket">]</span></a>.</p></li> +<li><p><em>Ellipsoid SDF definition</em>: The definition of the SDF is done in the fragment shader inside the <code class="docutils literal notranslate"><span class="pre">map</span></code> function, which is used later for the ray marching algorithm and the normals calculation. We define the SDF more simply by transforming a sphere into an ellipsoid, considering that the SDF of a sphere is easily computed and the definition of a tensor gives us a linear transformation of a given geometry. Also, as scaling is not a rigid body transformation, we multiply the final result by a factor to compensate for the difference, which gave us the SDF of the ellipsoid defined as <code class="docutils literal notranslate"><span class="pre">sdSphere(tensorMatrix</span> <span class="pre">*</span> <span class="pre">(position</span> <span class="pre">-</span> <span class="pre">centerMCVSOutput),</span> <span class="pre">scaleVSOutput*0.48)</span> <span class="pre">*</span> <span class="pre">scFactor</span></code>.</p></li> +<li><p><em>Ray marching algorithm and lighting</em>: For the ray marching algorithm, a small value of 20 was taken as the maximum distance since we apply the technique to each individual object and not all at the same time. Additionally, we set the convergence precision to 0.001. We use the central differences method to compute the normals necessary for the scene’s illumination, besides the Blinn-Phong lighting technique, which is high-quality and computationally cheap.</p></li> +<li><p><em>Visualization example</em>: Below is a detailed visualization of the ellipsoids created from this new implementation.</p></li> +</ul> +<img alt="https://user-images.githubusercontent.com/31288525/244503195-a626718f-4a13-4275-a2b7-6773823e553c.png" class="align-center" src="https://user-images.githubusercontent.com/31288525/244503195-a626718f-4a13-4275-a2b7-6773823e553c.png" style="width: 376px;" /> +<p>This implementation does show a better quality in the displayed glyphs, and supports the display of a large amount of data, as seen in the image below. For this reason, a tutorial was made to justify in more detail the value of this new implementation. Below are some images generated for the tutorial.</p> +<img alt="https://user-images.githubusercontent.com/31288525/260906510-d422e7b4-3ba3-4de6-bfd0-09c04bec8876.png" class="align-center" src="https://user-images.githubusercontent.com/31288525/260906510-d422e7b4-3ba3-4de6-bfd0-09c04bec8876.png" style="width: 600px;" /> +<p><em>Pull Requests:</em></p> +<ul class="simple"> +<li><p><strong>Ellipsoid actor implemented with SDF (Merged)</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/791">fury-gl/fury#791</a></p></li> +<li><p><strong>Tutorial on using ellipsoid actor to visualize tensor ellipsoids for DTI (Merged)</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/818">fury-gl/fury#818</a></p></li> +</ul> +<p><strong>Future work:</strong> In line with one of the initial objectives, it is expected to implement billboards later on to improve the performance, i.e., higher frame rate and less memory usage for the tensor ellipsoid creation. In addition to looking for ways to optimize the naive ray marching algorithm and the definition of SDFs.</p> +</section> +</section> +<section id="objectives-in-progress"> +<h2>Objectives in Progress</h2> +<section id="dti-uncertainty-visualization"> +<h3>DTI uncertainty visualization</h3> +<p>The DTI visualization pipeline is fairly complex, as a level of uncertainty arises, which, if visualized, helps to assess the model’s accuracy. This measure is not currently implemented, and even though there are several methods to calculate and visualize the uncertainty in the DTI model, because of its simplicity and visual representation, we considered Matrix Perturbation Analysis (MPA) proposed by Basser <a class="footnote-reference brackets" href="#id7" id="id2" role="doc-noteref"><span class="fn-bracket">[</span>1<span class="fn-bracket">]</span></a>. This measurement is visualized as double cones representing the variance of the main direction of diffusion, for which the ray marching technique was also used to create these objects.</p> +<p>Details of the implementation:</p> +<ul class="simple"> +<li><p><em>Source of uncertainty</em>: The method of MPA arises from the susceptibility of DTI to dMRI noise present in diffusion-weighted images (DWIs), and also because the model is inherently statistical, making the tensor estimation and other derived quantities to be random variables <a class="footnote-reference brackets" href="#id7" id="id3" role="doc-noteref"><span class="fn-bracket">[</span>1<span class="fn-bracket">]</span></a>. For this reason, this method focus on the premise that image noise produces a random perturbation in the diffusion tensor estimation, and therefore in the calculation of eigenvalues and eigenvectors, particularly in the first eigenvector associated with the main diffusion direction.</p></li> +<li><p><em>Mathematical equation</em>: The description of the perturbation of the principal eigenvector is given by math formula where <span class="math notranslate nohighlight">\(\Delta D\)</span> corresponds to the estimated perturbation matrix of <span class="math notranslate nohighlight">\(D\)</span> given by the diagonal elements of the covariance matrix <span class="math notranslate nohighlight">\(\Sigma_{\alpha} \approx (B^T\Sigma^{−1}_{e}B)^{−1}\)</span>, where <span class="math notranslate nohighlight">\(\Sigma_{e}\)</span> is the covariance matrix of the error e, defined as a diagonal matrix made with the diagonal elements of <span class="math notranslate nohighlight">\((\Sigma^{−1}_{e}) = ⟨S(b)⟩^2 / \sigma^{2}_{\eta}\)</span>. Then, to get the angle <span class="math notranslate nohighlight">\(\theta\)</span> between the perturbed principal eigenvector of <span class="math notranslate nohighlight">\(D\)</span>, <span class="math notranslate nohighlight">\(\varepsilon_1 + \Delta\varepsilon_1\)</span>, and the estimated eigenvector <span class="math notranslate nohighlight">\(\varepsilon_1\)</span>, it can be approximated by <span class="math notranslate nohighlight">\(\theta = \tan^{−1}( \| \Delta\varepsilon_1 \|)\)</span> <a class="footnote-reference brackets" href="#id8" id="id4" role="doc-noteref"><span class="fn-bracket">[</span>2<span class="fn-bracket">]</span></a>. Taking into account the above, we define the function <code class="docutils literal notranslate"><span class="pre">main_dir_uncertainty(evals,</span> <span class="pre">evecs,</span> <span class="pre">signal,</span> <span class="pre">sigma,</span> <span class="pre">b_matrix)</span></code> that calculates the uncertainty of the eigenvector associated to the main direction of diffusion.</p></li> +<li><p><em>Double cone SDF definition</em>: The final SDF is composed by the union of 2 separately cones using the definition taken from this list of <a class="reference external" href="https://iquilezles.org/articles/distfunctions/#:~:text=Cone%20%2D%20exact,sign(s)%3B%0A%7D">distance functions</a>, in this way we have the SDF for the double cone defined as <code class="docutils literal notranslate"><span class="pre">opUnion(sdCone(p,a,h),</span> <span class="pre">sdCone(-p,a,h))</span> <span class="pre">*</span> <span class="pre">scaleVSOutput</span></code></p></li> +<li><p><em>Visualization example</em>: Below is a demo of how this new feature is intended to be used, an image of diffusion tensor ellipsoids and their associated uncertainty cones.</p></li> +</ul> +<img alt="https://user-images.githubusercontent.com/31288525/254747296-09a8674e-bfc0-4b3f-820f-8a1b1ad8c5c9.png" class="align-center" src="https://user-images.githubusercontent.com/31288525/254747296-09a8674e-bfc0-4b3f-820f-8a1b1ad8c5c9.png" style="width: 610px;" /> +<p>The implementation is almost complete, but as it is a new addition that includes mathematical calculations and for which there is no direct reference for comparison, it requires a more detail review before it can be incorporated.</p> +<p><em>Pull Request:</em></p> +<ul class="simple"> +<li><p><strong>DTI uncertainty visualization (Under Review)</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/810">fury-gl/fury#810</a></p></li> +</ul> +<p><strong>Future work:</strong> A tutorial will be made explaining in more detail how to calculate the parameters needed for the uncertainty cones using <strong>dipy</strong> functions, specifically: <a class="reference external" href="https://github.com/dipy/dipy/blob/321e06722ef42b5add3a7f570f6422845177eafa/dipy/denoise/noise_estimate.py#L272">estimate_sigma</a> for the noise variance calculation, <a class="reference external" href="https://github.com/dipy/dipy/blob/321e06722ef42b5add3a7f570f6422845177eafa/dipy/reconst/dti.py#L2112">design_matrix</a> to get the b-matrix, and <a class="reference external" href="https://github.com/dipy/dipy/blob/321e06722ef42b5add3a7f570f6422845177eafa/dipy/reconst/dti.py#L639">tensor_prediction</a> for the signal estimation. Additionally, when the ODF implementation is complete, uncertainty for this other reconstruction model is expected to be added, using semitransparent glyphs representing the mean directional information proposed by Tournier <a class="footnote-reference brackets" href="#id9" id="id5" role="doc-noteref"><span class="fn-bracket">[</span>3<span class="fn-bracket">]</span></a>.</p> +</section> +<section id="odf-actor-implemented-with-sdf"> +<h3>ODF actor implemented with SDF</h3> +<p>HARDI-based techniques require more images than DTI, however, they model the diffusion directions as probability distribution functions (PDFs), and the fitted values are returned as orientation distribution functions (ODFs). ODFs are more diffusion sensitive than the diffusion tensor and, therefore, can determine the structure of multi-directional voxels very common in the white matter regions of the brain <a class="footnote-reference brackets" href="#id9" id="id6" role="doc-noteref"><span class="fn-bracket">[</span>3<span class="fn-bracket">]</span></a>. The current actor to display this kind of glyphs is the <code class="docutils literal notranslate"><span class="pre">odf_slicer</span></code> which, given an array of spherical harmonics (SH) coefficients renders a grid of ODFs, which are created from a sphere with a specific number of vertices that fit the data.</p> +<p>For the application of this model using the same SDF ray marching techniques, we need the data of the SH coefficients, which are used to calculate the orientation distribution function (ODF) described <a class="reference external" href="https://dipy.org/documentation/1.7.0/theory/sh_basis/">here</a>. Different SH bases can be used, but for this first approach we focus on <code class="docutils literal notranslate"><span class="pre">descoteaux07</span></code> (as labeled in dipy). After performing the necessary calculations, we obtain an approximate result of the current implementation of FURY, as seen below.</p> +<img alt="https://user-images.githubusercontent.com/31288525/260909561-fd90033c-018a-465b-bd16-3586bb31ca36.png" class="align-center" src="https://user-images.githubusercontent.com/31288525/260909561-fd90033c-018a-465b-bd16-3586bb31ca36.png" style="width: 580px;" /> +<p>With a first implementation we start to solve some issues related to direction, color, and data handling, to obtain exactly the same results as the current implementation.</p> +<p>Details on the issues:</p> +<ul class="simple"> +<li><p><em>The direction and the scaling</em>: When the shape of the ODF is more sphere-like, the size of the glyph is smaller, so for the moment it needs to be adjusted manually, but the idea is to find a relationship between the coefficients and the final object size so it can be automatically scaled. Additionally, as seen in the image, the direction does not match. To fix this, an adjustment in the calculation of the spherical coordinates can be made, or pass the direction information directly.</p></li> +<li><p><em>Pass the coefficients data efficiently</em>: I’m currently creating one actor per glyph since I’m using a <em>uniform</em> array to pass the coefficients, but the idea is to pass all the data simultaneously. The first idea is to encode the coefficients data through a texture and retrieve them in the fragment shader.</p></li> +<li><p><em>The colormapping and the lighting</em>: As these objects present curvatures with quite a bit of detail in some cases, this requires more specific lighting work, in addition to having now not only one color but a color map. This can also be done with texture, but it is necessary to see in more detail how to adjust the texture to the glyph’s shape.</p></li> +</ul> +<p>More details on current progress can be seen in blogpost of <a class="reference external" href="https://fury.gl/latest/posts/2023/2023-08-16-week-11-tvcastillod.html">week 11</a> and <a class="reference external" href="https://fury.gl/latest/posts/2023/2023-08-24-week-12-tvcastillod.html">week 12</a>.</p> +<p><em>Working branch:</em></p> +<ul class="simple"> +<li><p><strong>ODF implementation (Under Development)</strong> +<a class="github reference external" href="https://github.com/tvcastillod/fury/tree/SH-for-ODF-impl">tvcastillod/fury</a></p></li> +</ul> +</section> +</section> +<section id="gsoc-weekly-blogs"> +<h2>GSoC Weekly Blogs</h2> +<ul class="simple"> +<li><p>My blog posts can be found on the <a class="reference external" href="https://fury.gl/latest/blog/author/tania-castillo.html">FURY website</a> and the <a class="reference external" href="https://blogs.python-gsoc.org/en/tvcastillods-blog/">Python GSoC blog</a>.</p></li> +</ul> +</section> +<section id="timeline"> +<h2>Timeline</h2> +<table class="table"> +<thead> +<tr class="row-odd"><th class="head"><p>Date</p></th> +<th class="head"><p>Description</p></th> +<th class="head"><p>Blog Post Link</p></th> +</tr> +</thead> +<tbody> +<tr class="row-even"><td><p>Week 0(02-06-2022)</p></td> +<td><p>Community Bounding Period</p></td> +<td><p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-06-02-week-0-tvcastillod.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/tvcastillods-blog/weekly-check-in-0-2">Python</a></p></td> +</tr> +<tr class="row-odd"><td><p>Week 1(05-06-2022)</p></td> +<td><p>Ellipsoid actor implemented with SDF</p></td> +<td><p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-06-05-week-1-tvcastillod.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/tvcastillods-blog/weekly-check-in-1-23">Python</a></p></td> +</tr> +<tr class="row-even"><td><p>Week 2(12-06-2022)</p></td> +<td><p>Making adjustments to the Ellipsoid Actor</p></td> +<td><p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-06-12-week-2-tvcastillod.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/tvcastillods-blog/weekly-check-in-2-18">Python</a></p></td> +</tr> +<tr class="row-odd"><td><p>Week 3(19-06-2022)</p></td> +<td><p>Working on uncertainty and details of the first PR</p></td> +<td><p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-06-19-week-3-tvcastillod.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/tvcastillods-blog/weekly-check-in-3-27">Python</a></p></td> +</tr> +<tr class="row-even"><td><p>Week 4(27-06-2022)</p></td> +<td><p>First draft of the DTI uncertainty visualization</p></td> +<td><p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-06-27-week-4-tvcastillod.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/tvcastillods-blog/weekly-check-in-4-24">Python</a></p></td> +</tr> +<tr class="row-odd"><td><p>Week 5(03-07-2022)</p></td> +<td><p>Preparing the data for the Ellipsoid tutorial</p></td> +<td><p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-07-03-week-5-tvcastillod.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/tvcastillods-blog/weekly-check-in-5-27">Python</a></p></td> +</tr> +<tr class="row-even"><td><p>Week 6(10-07-2022)</p></td> +<td><p>First draft of the Ellipsoid tutorial</p></td> +<td><p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-07-10-week-6-tvcastillod.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/tvcastillods-blog/weekly-check-in-6-26">Python</a></p></td> +</tr> +<tr class="row-odd"><td><p>Week 7(17-07-2022)</p></td> +<td><p>Adjustments on the Uncertainty Cones visualization</p></td> +<td><p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-07-17-week-7-tvcastillod.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/tvcastillods-blog/weekly-check-in-7-26">Python</a></p></td> +</tr> +<tr class="row-even"><td><p>Week 8(25-07-2022)</p></td> +<td><p>Working on Ellipsoid Tutorial and exploring SH</p></td> +<td><p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-07-25-week-8-tvcastillod.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/tvcastillods-blog/weekly-check-in-8-17">Python</a></p></td> +</tr> +<tr class="row-odd"><td><p>Week 9(31-07-2022)</p></td> +<td><p>Tutorial done and polishing DTI uncertainty</p></td> +<td><p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-07-31-week-9-tvcastillod.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/tvcastillods-blog/weekly-check-in-9-22">Python</a></p></td> +</tr> +<tr class="row-even"><td><p>Week 10(08-08-2022)</p></td> +<td><p>Start of SH implementation experiments</p></td> +<td><p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-08-08-week-10-tvcastillod.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/tvcastillods-blog/weekly-check-in-10-16">Python</a></p></td> +</tr> +<tr class="row-odd"><td><p>Week 11(16-08-2022)</p></td> +<td><p>Adjusting ODF implementation and looking for solutions on issues found</p></td> +<td><p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-08-16-week-11-tvcastillod.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/tvcastillods-blog/weekly-check-in-11-17">Python</a></p></td> +</tr> +<tr class="row-even"><td><p>Week 12(24-08-2022)</p></td> +<td><p>Experimenting with ODFs implementation</p></td> +<td><p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-08-24-week-12-tvcastillod.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/tvcastillods-blog/weekly-check-in-12-9">Python</a></p></td> +</tr> +</tbody> +</table> +</section> +<section id="references"> +<h2>References</h2> +<aside class="footnote-list brackets"> +<aside class="footnote brackets" id="id7" role="doc-footnote"> +<span class="label"><span class="fn-bracket">[</span>1<span class="fn-bracket">]</span></span> +<span class="backrefs">(<a role="doc-backlink" href="#id2">1</a>,<a role="doc-backlink" href="#id3">2</a>)</span> +<p>Basser, P. J. (1997). Quantifying errors in fiber direction and diffusion tensor field maps resulting from MR noise. In 5th Scientific Meeting of the ISMRM (Vol. 1740).</p> +</aside> +<aside class="footnote brackets" id="id8" role="doc-footnote"> +<span class="label"><span class="fn-bracket">[</span><a role="doc-backlink" href="#id4">2</a><span class="fn-bracket">]</span></span> +<p>Chang, L. C., Koay, C. G., Pierpaoli, C., &amp; Basser, P. J. (2007). Variance of estimated DTI‐derived parameters via first‐order perturbation methods. Magnetic Resonance in Medicine: An Official Journal of the International Society for Magnetic Resonance in Medicine, 57(1), 141-149.</p> +</aside> +<aside class="footnote brackets" id="id9" role="doc-footnote"> +<span class="label"><span class="fn-bracket">[</span>3<span class="fn-bracket">]</span></span> +<span class="backrefs">(<a role="doc-backlink" href="#id5">1</a>,<a role="doc-backlink" href="#id6">2</a>)</span> +<p>J-Donald Tournier, Fernando Calamante, David G Gadian, and Alan Connelly. Direct estimation of the fiber orientation density function from diffusion-weighted mri data using spherical deconvolution. Neuroimage, 23(3):1176–1185, 2004.</p> +</aside> +<aside class="footnote brackets" id="id10" role="doc-footnote"> +<span class="label"><span class="fn-bracket">[</span><a role="doc-backlink" href="#id1">4</a><span class="fn-bracket">]</span></span> +<p>Gordon Kindlmann. Superquadric tensor glyphs. In Proceedings of the Sixth Joint Eurographics-IEEE TCVG conference on Visualization, pages 147–154, 2004.</p> +</aside> +</aside> +</section> +</section> + + + Name: Tania Castillo + + 2023-08-24T00:00:00-04:00 + + + https://fury.gl/posts/2023/2023-08-16-week-11-tvcastillod.html + Week 11 : Adjusting ODF implementation and looking for solutions on issues found + 2023-08-16T00:00:00-04:00 + + Tania Castillo + + <section id="week-11-adjusting-odf-implementation-and-looking-for-solutions-on-issues-found"> + +<section id="what-did-i-do-this-week"> +<h2>What did I do this week?</h2> +<p>I continued to experiment with the ODF glyph implementation. Thanks to one of my mentors I figured out how to get the missing data corresponding to the SH coefficients <span class="math notranslate nohighlight">\(a^l_m\)</span> part of the function <span class="math notranslate nohighlight">\(f(\theta, \phi)\)</span> described <a class="reference external" href="https://dipy.org/documentation/1.7.0/theory/sh_basis/">here</a>. I also was told to make sure to implement the correct SH basis since there are different definitions from the literature, I have to focus now in the one proposed by Descoteaux, described in <a class="reference external" href="https://onlinelibrary.wiley.com/doi/10.1002/mrm.21277">this paper</a>, which is labeled in <em>dipy</em> as <em>descoteaux07</em>. To do this I had to make a small adjustment to the base implementation that I took as a reference, from which I obtained a first result using SH of order 4.</p> +<img alt="https://user-images.githubusercontent.com/31288525/260909561-fd90033c-018a-465b-bd16-3586bb31ca36.png" class="align-center" src="https://user-images.githubusercontent.com/31288525/260909561-fd90033c-018a-465b-bd16-3586bb31ca36.png" style="width: 600px;" /> +<p>It appears that the results on the shape are about the same, except for the direction, but there is still work to be done.</p> +</section> +<section id="what-is-coming-up-next"> +<h2>What is coming up next?</h2> +<p>For now, there are 3 things I will continue to work on:</p> +<ul> +<li><p>The color and lighting. As these objects present curvatures with quite a bit of detail in some cases, this is something that requires more specific lighting work, in addition to having now not only one color but a color map.</p></li> +<li><p>The scaling. This is something I still don’t know how to deal with. I had to adjust it manually for now, but the idea is to find a relationship between the coefficients and the final object size so it can be automatically scaled, or maybe there is a proper way to pre-process this data before passing it to the shaders to get the right result at once.</p></li> +<li><aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-16-week-11-tvcastillod.rst</span>, line 2); <em><a href="#id1">backlink</a></em></p> +<p>Duplicate explicit target name: “here”.</p> +</aside> +<p>How to pass the information of the coefficients efficiently. Right now I’m creating one actor per glyph since I’m using a uniform array to pass the coefficients, but the idea is to pass all the data at once. I found several ideas <a class="reference external" href="https://stackoverflow.com/questions/7954927/passing-a-list-of-values-to-fragment-shader">here</a> of how to pass a list of values to the fragment shader directly, I just need to explore deeper how this can be done on <strong>FURY</strong>, and see which option is most suitable.</p> +</li> +</ul> +</section> +<section id="did-i-get-stuck-anywhere"> +<h2>Did I get stuck anywhere?</h2> +<p>All the points mentioned above are things that I tried to fix, however, it is something that I need to look at in much more detail and that I know is going to take me some time to understand and test before I get to the expected result. I hope to get some ideas from my mentors and fellow GSoC contributors on how I can proceed to deal with each of the problems.</p> +</section> +</section> + + + I continued to experiment with the ODF glyph implementation. Thanks to one of my mentors I figured out how to get the missing data corresponding to the SH coefficients a^l_m part of the function f(\theta, \phi) described here. I also was told to make sure to implement the correct SH basis since there are different definitions from the literature, I have to focus now in the one proposed by Descoteaux, described in this paper, which is labeled in dipy as descoteaux07. To do this I had to make a small adjustment to the base implementation that I took as a reference, from which I obtained a first result using SH of order 4. + + 2023-08-16T00:00:00-04:00 + + + https://fury.gl/posts/2023/2023-08-08-week-10-tvcastillod.html + Week 10 : Start of SH implementation experiments + 2023-08-08T00:00:00-04:00 + + Tania Castillo + + <section id="week-10-start-of-sh-implementation-experiments"> + +<section id="what-did-i-do-this-week"> +<h2>What did I do this week?</h2> +<p>I started formally working on SH implementation. I was told to start first doing a simple program where I can modify in real-time the order <span class="math notranslate nohighlight">\(l\)</span> and degree <span class="math notranslate nohighlight">\(m\)</span>, parameters corresponding to the <a class="reference external" href="https://dipy.org/documentation/1.7.0/theory/sh_basis/">Spherical Harmonics function</a> <span class="math notranslate nohighlight">\(Y^m_l(\theta,\phi)=\)</span>, based on <a class="reference external" href="https://github.com/lenixlobo/fury/commit/2b7ce7a71fd422dc5a250d7b49e1eea2db9d3bce">previous work</a>. That is just one part of the final ODF calculation, but here is what a first experimental script looks like.</p> +<img alt="https://user-images.githubusercontent.com/31288525/260910073-10b0edd4-40e3-495c-85ad-79993aef3b19.png" class="align-center" src="https://user-images.githubusercontent.com/31288525/260910073-10b0edd4-40e3-495c-85ad-79993aef3b19.png" style="width: 600px;" /> +<p>I did it in order to make sure it was visually correct and also to understand better how those 2 parameters are related and need to be incorporated into the final calculation. There is one issue at first sight that needs to be addressed, and that is the scaling, since for SH with a degree near 0, the object gets out of bounds.</p> +</section> +<section id="what-is-coming-up-next"> +<h2>What is coming up next?</h2> +<p>I will keep polishing details from my current open PRs, hopefully, I will get another PR merged before the last GSoC week.</p> +</section> +<section id="did-i-get-stuck-anywhere"> +<h2>Did I get stuck anywhere?</h2> +<p>Not sure about how to use the current implementation I have to get similar visualizations made with <em>odf_slicer</em>, since the parameters that the function receive are different, so I need to take a deeper look and see where it might be the connection or if I should make some adjustments on the parameters.</p> +</section> +</section> + + + I started formally working on SH implementation. I was told to start first doing a simple program where I can modify in real-time the order l and degree m, parameters corresponding to the Spherical Harmonics function Y^m_l(\theta,\phi)=, based on previous work. That is just one part of the final ODF calculation, but here is what a first experimental script looks like. + + 2023-08-08T00:00:00-04:00 + + + https://fury.gl/posts/2023/2023-07-31-week-9-tvcastillod.html + Week 9: Tutorial done and polishing DTI uncertainty + 2023-07-31T00:00:00-04:00 + + Tania Castillo + + <section id="week-9-tutorial-done-and-polishing-dti-uncertainty"> + +<section id="what-did-i-do-this-week"> +<h2>What did I do this week?</h2> +<p>I addressed the comments from the tutorial of <a class="reference external" href="https://github.com/fury-gl/fury/pull/818">PR #818</a> related to how to display specific visualizations I wanted to make. I was suggested to use <em>ShowManager</em> to handle the zoom of the scene and also to use <em>GridUI</em> to display several actors at the same time for a visual quality comparison of the tensors. Below are some images generated for the tutorial that is almost done.</p> +<img alt="https://user-images.githubusercontent.com/31288525/260906510-d422e7b4-3ba3-4de6-bfd0-09c04bec8876.png" class="align-center" src="https://user-images.githubusercontent.com/31288525/260906510-d422e7b4-3ba3-4de6-bfd0-09c04bec8876.png" style="width: 600px;" /> +</section> +<section id="what-is-coming-up-next"> +<h2>What is coming up next?</h2> +<p>There are some issues with the tests of the uncertainty implementation, specifically a segmentation problem that has to be with the shaders, so I expect to correct the problem by next week.</p> +</section> +<section id="did-i-get-stuck-anywhere"> +<h2>Did I get stuck anywhere?</h2> +<p>I’m still thinking about how to approach the implementation of the spherical harmonics for ODF glyphs. Most of the implementations I have found are static so my task would be to try to parametrize the existing functions, so I can pass data from Python to the shaders properly so that I can obtain the same result as the current <em>odf_slicer</em>.</p> +</section> +</section> + + + I addressed the comments from the tutorial of PR #818 related to how to display specific visualizations I wanted to make. I was suggested to use ShowManager to handle the zoom of the scene and also to use GridUI to display several actors at the same time for a visual quality comparison of the tensors. Below are some images generated for the tutorial that is almost done. + + 2023-07-31T00:00:00-04:00 + + + https://fury.gl/posts/2023/2023-07-25-week-8-tvcastillod.html + Week 8: Working on Ellipsoid Tutorial and exploring SH + 2023-07-25T00:00:00-04:00 + + Tania Castillo + + <section id="week-8-working-on-ellipsoid-tutorial-and-exploring-sh"> + +<section id="what-did-i-do-this-week"> +<h2>What did I do this week?</h2> +<p>I mainly worked on the ellipsoid actor tutorial, as <a class="reference external" href="https://github.com/fury-gl/fury/pull/791">PR #791</a> is finally merged, so I was able to complete the tutorial by adding my implementation. In addition, during the weekly meeting, I received a good overview of the next issue I will be working on, which is using raymarching SDFs to display spherical harmonics (SH) for visualizing ODF glyphs for DTI. I got several ideas and resources which I can start experimenting with, such as <a class="reference external" href="https://www.shadertoy.com/results?query=Spherical+Harmonics">Shadertoy</a> and some base implementations from other FURY contributors. The main drawback when creating these objects is the amount of data required to create them, because depending on the SH order, the number of parameters that the function receives may vary, also unlike the tensors, which are represented only with a 3x3 matrix, here we could have more than 9 values associated with a single glyph, so passing the information from python to the shaders is not so trivial, besides requiring more resources as there is more information that needs to be processed. Some ideas I received were using matrixes instead of vectors, using templating, or even using texture to pass the data. I started to explore these options further, as well as to review in more detail the existing implementations of SH with raymarching, in order to understand them better.</p> +</section> +<section id="what-is-coming-up-next"> +<h2>What is coming up next?</h2> +<p>I currently have two PRs under review, so I will address the comments I receive and update them accordingly. I also will continue to explore and start working on the implementation of these objects so that I can start making adjustments and further discuss possible improvements to the implementation I will make.</p> +</section> +<section id="did-i-get-stuck-anywhere"> +<h2>Did I get stuck anywhere?</h2> +<p>Fortunately, I did not encounter any drawbacks this week.</p> +</section> +</section> + + + I mainly worked on the ellipsoid actor tutorial, as PR #791 is finally merged, so I was able to complete the tutorial by adding my implementation. In addition, during the weekly meeting, I received a good overview of the next issue I will be working on, which is using raymarching SDFs to display spherical harmonics (SH) for visualizing ODF glyphs for DTI. I got several ideas and resources which I can start experimenting with, such as Shadertoy and some base implementations from other FURY contributors. The main drawback when creating these objects is the amount of data required to create them, because depending on the SH order, the number of parameters that the function receives may vary, also unlike the tensors, which are represented only with a 3x3 matrix, here we could have more than 9 values associated with a single glyph, so passing the information from python to the shaders is not so trivial, besides requiring more resources as there is more information that needs to be processed. Some ideas I received were using matrixes instead of vectors, using templating, or even using texture to pass the data. I started to explore these options further, as well as to review in more detail the existing implementations of SH with raymarching, in order to understand them better. + + 2023-07-25T00:00:00-04:00 + + + https://fury.gl/posts/2023/2023-07-17-week-7-tvcastillod.html + Week 7: Adjustments on the Uncertainty Cones visualization + 2023-07-17T00:00:00-04:00 + + Tania Castillo + + <section id="week-7-adjustments-on-the-uncertainty-cones-visualization"> + +<section id="what-did-i-do-this-week"> +<h2>What did I do this week?</h2> +<p>I was told to refactor some parts of the uncertainty PR, since I was relying too much on <strong>dipy</strong> functions which is not good because it makes maintenance more difficult as <strong>dipy</strong> requires <strong>FURY</strong> for some functionalities. So I did some adjustments on the uncertainty function parameters and the corresponding tests, hopefully I managed to get with the most appropriate definition but I need to receive a first feedback to see how much I have to adjust the implementation. As I had to delete some relevant code lines inside the uncertainty calculation which consisted of preprocessing the data in order to define the necessary variables for the uncertainty formula, I was also suggested to make a tutorial of this new feature, so I can explain in detail how to obtain and adjust the necessary information, before passing it to the actor, and in general how and what is the purpose of this new function.</p> +<p>I also continued working on the ellipsoid tutorial, which I hope to finish this week so that I can ask for a first revision.</p> +</section> +<section id="what-is-coming-up-next"> +<h2>What is coming up next?</h2> +<p>I will finish defining some details of the tutorial so that it is ready for review, and now I will start working on the tutorial related to the uncertainty, while I receive feedback on the other PRs. Also, as preparation for the next step I will start exploring on how to address visualization of spherical harmonics for ODF glyphs visualization, I found that a previous GSoC participant at FURY started working on that and also did several work with raymarching and SDF (<span class="xref std std-doc">here is a summary of the work</span>), so I will take a deeper look on that to see if I can get something useful I can start with.</p> +</section> +<section id="did-i-get-stuck-anywhere"> +<h2>Did I get stuck anywhere?</h2> +<p>Not this week, but I foresee some problems with the uncertainty PR, we will see how it goes.</p> +</section> +</section> + + + I was told to refactor some parts of the uncertainty PR, since I was relying too much on dipy functions which is not good because it makes maintenance more difficult as dipy requires FURY for some functionalities. So I did some adjustments on the uncertainty function parameters and the corresponding tests, hopefully I managed to get with the most appropriate definition but I need to receive a first feedback to see how much I have to adjust the implementation. As I had to delete some relevant code lines inside the uncertainty calculation which consisted of preprocessing the data in order to define the necessary variables for the uncertainty formula, I was also suggested to make a tutorial of this new feature, so I can explain in detail how to obtain and adjust the necessary information, before passing it to the actor, and in general how and what is the purpose of this new function. + + 2023-07-17T00:00:00-04:00 + + + https://fury.gl/posts/2023/2023-07-10-week-6-tvcastillod.html + Week 6: First draft of the Ellipsoid tutorial + 2023-07-10T00:00:00-04:00 + + Tania Castillo + + <section id="week-6-first-draft-of-the-ellipsoid-tutorial"> + +<section id="what-did-i-do-this-week"> +<h2>What did I do this week?</h2> +<p><a class="reference external" href="https://github.com/fury-gl/fury/pull/818">#PR 818: Tutorial on using ellipsoid actor to visualize tensor ellipsoids for DTI</a></p> +<p>I created the PR for the tutorial that will show the use that can be made of the <em>ellipsoid</em> actor in the visualization of diffusion tensor ellipsoids. It is still in its most basic stage, but the structure that I have thought of for now consists of: displaying a slice using <em>tensor_slicer</em> with spheres of 100, 200, and 724 vertices, and using <em>ellipsoid</em> actor, and show a comparison of the visual quality of the tensor ellipsoids. Then, display a ROI using both actors and a whole brain using the <em>ellipsoid</em> actor, to show that this new actor gives the possibility to display more data.</p> +<p>I also submitted the <a class="reference external" href="https://github.com/fury-gl/fury/pull/810">uncertainty PR</a> for review, in order to start making the necessary corrections.</p> +</section> +<section id="what-is-coming-up-next"> +<h2>What is coming up next?</h2> +<p>I need <a class="reference external" href="https://github.com/fury-gl/fury/pull/791">#PR 791</a> to be merged first, but meanwhile, I will start working on the explanation of the tutorial, since I already have the code structure and the idea of what I want to illustrate. I will discuss further work with my mentors at the upcoming meeting, so I can organize myself better and plan how I’m going to address the pending parts of my project.</p> +</section> +<section id="did-i-get-stuck-anywhere"> +<h2>Did I get stuck anywhere?</h2> +<p>I found no major difficulties this week.</p> +</section> +</section> + + + #PR 818: Tutorial on using ellipsoid actor to visualize tensor ellipsoids for DTI + + 2023-07-10T00:00:00-04:00 + + + https://fury.gl/posts/2023/2023-07-03-week-5-tvcastillod.html + Week 5: Preparing the data for the Ellipsoid tutorial + 2023-07-03T00:00:00-04:00 + + Tania Castillo + + <section id="week-5-preparing-the-data-for-the-ellipsoid-tutorial"> + +<section id="what-did-i-do-this-week"> +<h2>What did I do this week?</h2> +<p>During the weekly meeting with my mentors, there was a small discussion over the naming of the actor and its usage. On the one hand, although the purpose of the actor is to visualize diffusion tensor ellipsoids, the idea is that it can also be used for any other type of visualization that requires the use of ellipsoids, so in the end, we decided to keep the name <em>ellipsoid</em> as it is more generic. On the other hand, as there is already an actor made for the purpose of tensor visualization, namely <a class="reference external" href="https://github.com/fury-gl/fury/blob/e595bad0246899d58d24121dcc291eb050721f9f/fury/actor.py#L1172">tensor_slicer</a>, it might not be obvious how and why one would use this new ellipsoid actor for this purpose, thus it was proposed to make a tutorial that can clarify this. The main difference between both actors relies on the quality and the amount of data that can be displayed, so the idea is to show the difference between both alternatives so the user can choose which one to use depending on their needs. To prepare the tutorial the first step was to <a class="reference external" href="https://github.com/fury-gl/fury-data/pull/12">add the data</a> I will use on <a class="reference external" href="https://github.com/fury-gl/fury-data">fury-data</a> so I can then fetch and load the datasets I need to work on the tutorial.</p> +</section> +<section id="what-is-coming-up-next"> +<h2>What is coming up next?</h2> +<p>I need <a class="reference external" href="https://github.com/fury-gl/fury/pull/791">#PR 791</a> to be reviewed by my GSoC fellows at FURY, so I will address their comments, and additionally make adjustments on <a class="reference external" href="https://github.com/fury-gl/fury/pull/810">#PR 810</a> based on the feedback I receive. I will also start working on the tutorial, the idea is to show the use that can be made of the ellipsoid actor in the visualization of diffusion tensor ellipsoids, compared to the <em>tensor_slicer</em> actor. I plan to create a WIP PR to start getting feedback on the general structure of the tutorial and the way everything will be explained.</p> +</section> +<section id="did-i-get-stuck-anywhere"> +<h2>Did I get stuck anywhere?</h2> +<p>I did not encounter any obstacles this week.</p> +</section> +</section> + + + During the weekly meeting with my mentors, there was a small discussion over the naming of the actor and its usage. On the one hand, although the purpose of the actor is to visualize diffusion tensor ellipsoids, the idea is that it can also be used for any other type of visualization that requires the use of ellipsoids, so in the end, we decided to keep the name ellipsoid as it is more generic. On the other hand, as there is already an actor made for the purpose of tensor visualization, namely tensor_slicer, it might not be obvious how and why one would use this new ellipsoid actor for this purpose, thus it was proposed to make a tutorial that can clarify this. The main difference between both actors relies on the quality and the amount of data that can be displayed, so the idea is to show the difference between both alternatives so the user can choose which one to use depending on their needs. To prepare the tutorial the first step was to add the data I will use on fury-data so I can then fetch and load the datasets I need to work on the tutorial. + + 2023-07-03T00:00:00-04:00 + + + https://fury.gl/posts/2023/2023-06-27-week-4-tvcastillod.html + Week 4: First draft of the DTI uncertainty visualization + 2023-06-27T00:00:00-04:00 + + Tania Castillo + + <section id="week-4-first-draft-of-the-dti-uncertainty-visualization"> + +<section id="what-did-i-do-this-week"> +<h2>What did I do this week?</h2> +<p><a class="reference external" href="https://github.com/fury-gl/fury/pull/810">#PR 810: DTI uncertainty visualization</a></p> +<p>I made a second PR with the implementation of DTI uncertainty calculation and visualization. Below is an image of diffusion tensor ellipsoids and their associated uncertainty cones.</p> +<img alt="https://user-images.githubusercontent.com/31288525/254747296-09a8674e-bfc0-4b3f-820f-8a1b1ad8c5c9.png" class="align-center" src="https://user-images.githubusercontent.com/31288525/254747296-09a8674e-bfc0-4b3f-820f-8a1b1ad8c5c9.png" style="width: 530px;" /> +<p>I had to use some <strong>dipy</strong> functions, specifically: <a class="reference external" href="https://github.com/dipy/dipy/blob/321e06722ef42b5add3a7f570f6422845177eafa/dipy/denoise/noise_estimate.py#L272">estimate_sigma</a> for the noise variance calculation, <a class="reference external" href="https://github.com/dipy/dipy/blob/321e06722ef42b5add3a7f570f6422845177eafa/dipy/reconst/dti.py#L2112">design_matrix</a> to get the b-matrix, and <a class="reference external" href="https://github.com/dipy/dipy/blob/321e06722ef42b5add3a7f570f6422845177eafa/dipy/reconst/dti.py#L639">tensor_prediction</a> for the signal estimation. The details of this calculations can be found <a class="reference external" href="https://onlinelibrary.wiley.com/doi/full/10.1002/mrm.21111">here</a>.</p> +</section> +<section id="what-is-coming-up-next"> +<h2>What is coming up next?</h2> +<p>I will continue working on the uncertainty PR which is still in its early stage, I’m going to make a couple of adjustments to the description of the parameters and the actor, and keep working on based on the feedback I receive. There are also minor details to be discussed with my mentors about the first PR, which I hope to finish refining.</p> +</section> +<section id="did-i-get-stuck-anywhere"> +<h2>Did I get stuck anywhere?</h2> +<p>It took me a while to make the PR because I had some problems with the uncertainty function definition. I tried to use the least amount of parameters for the function, since with data, bvals and bvecs it is possible to obtain the rest of the parameters needed to generate the cones, which led me to readjust some calculations from the base implementation I had, to keep everything working correctly.</p> +</section> +</section> + + + #PR 810: DTI uncertainty visualization + + 2023-06-27T00:00:00-04:00 + + diff --git a/v0.10.x/blog/category.html b/v0.10.x/blog/category.html new file mode 100644 index 000000000..41f1809eb --- /dev/null +++ b/v0.10.x/blog/category.html @@ -0,0 +1,2572 @@ + + + + + + + Categories — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + + +
+

+ Posts in + gsoc +

+ +
+

+ + 25 August 2023 + + - + Google Summer of Code Final Work Product +

+
+ +
+

+ + 24 August 2023 + + - + Week 12 : Experimenting with ODFs implementation +

+
+ +
+

+ + 24 August 2023 + + - + Google Summer of Code Final Work Product +

+
+ +
+

+ + 21 August 2023 + + - + Week 12: Now That is (almost) a Wrap! +

+
+ +
+

+ + 21 August 2023 + + - + Google Summer of Code Final Work Product +

+
+ +
+

+ + 19 August 2023 + + - + Week 12: FileDialog Quest Begins! +

+
+ +
+

+ + 16 August 2023 + + - + Week 11 : Adjusting ODF implementation and looking for solutions on issues found +

+
+ +
+

+ + 14 August 2023 + + - + Week 11: A Refactor is Sometimes Needed +

+
+ +
+

+ + 12 August 2023 + + - + Week 11: Bye Bye SpinBox +

+
+ +
+

+ + 08 August 2023 + + - + Week 10 : Start of SH implementation experiments +

+
+ +
+

+ + 07 August 2023 + + - + Week 10: Ready for Review! +

+
+ +
+

+ + 05 August 2023 + + - + Week 10: Its time for a Spin-Box! +

+
+ +
+

+ + 31 July 2023 + + - + Week 9: Tutorial done and polishing DTI uncertainty +

+
+ +
+

+ + 31 July 2023 + + - + Week 9: It is Polishing Time! +

+
+ +
+

+ + 29 July 2023 + + - + Week 9: TextBlock2D is Finally Merged! +

+
+ +
+

+ + 25 July 2023 + + - + Week 8: Working on Ellipsoid Tutorial and exploring SH +

+
+ +
+

+ + 24 July 2023 + + - + Week 8: The Birth of a Versatile API +

+
+ +
+

+ + 22 July 2023 + + - + Week 8: Another week with TextBlockUI +

+
+ +
+

+ + 17 July 2023 + + - + Week 7: Experimentation Done +

+
+ +
+

+ + 17 July 2023 + + - + Week 7: Adjustments on the Uncertainty Cones visualization +

+
+ +
+

+ + 15 July 2023 + + - + Week 7: Sowing the seeds for TreeUI +

+
+ +
+

+ + 10 July 2023 + + - + Week 6: Things are Starting to Build Up +

+
+ +
+

+ + 10 July 2023 + + - + Week 6: First draft of the Ellipsoid tutorial +

+
+ +
+

+ + 08 July 2023 + + - + Week 6: BoundingBox for TextBlock2D! +

+
+ +
+

+ + 03 July 2023 + + - + Week 5: Preparing the data for the Ellipsoid tutorial +

+
+ +
+

+ + 03 July 2023 + + - + Week 5: All Roads Lead to Rome +

+
+ +
+

+ + 01 July 2023 + + - + Week 5: Trying out PRs and Planning Ahead +

+
+ +
+

+ + 27 June 2023 + + - + Week 4: First draft of the DTI uncertainty visualization +

+
+ +
+

+ + 26 June 2023 + + - + Week 4: Nothing is Ever Lost +

+
+ +
+

+ + 24 June 2023 + + - + Week 4: Exam Preparations and Reviewing +

+
+ +
+

+ + 19 June 2023 + + - + Week 3: Working on uncertainty and details of the first PR +

+
+ +
+

+ + 19 June 2023 + + - + Week 3: Watch Your Expectations +

+
+ +
+

+ + 17 June 2023 + + - + Week 3: Resolving Combobox Icon Flaw and TextBox Justification +

+
+ +
+

+ + 12 June 2023 + + - + Week 2: The Importance of (good) Documentation +

+
+ +
+

+ + 12 June 2023 + + - + Week 2: Making adjustments to the Ellipsoid Actor +

+
+ +
+

+ + 11 June 2023 + + - + Week 2: Tackling Text Justification and Icon Flaw Issues +

+
+ +
+

+ + 05 June 2023 + + - + Week 1: Ellipsoid actor implemented with SDF +

+
+ +
+

+ + 05 June 2023 + + - + The FBO Saga - Week 1 +

+
+ +
+

+ + 03 June 2023 + + - + Week 1: Working with SpinBox and TextBox Enhancements +

+
+ +
+

+ + 02 June 2023 + + - + Week 0: Community Bounding Period +

+
+ +
+

+ + 02 June 2023 + + - + Week 0: Community Bounding Period +

+
+ +
+

+ + 29 May 2023 + + - + The Beginning of Everything - Week 0 +

+
+ +
+

+ + 01 February 2023 + + - + Contribute to FURY via Google Summer of Code 2023 +

+
+ +
+

+ + 29 January 2023 + + - + Google Summer of Code Final Work Product +

+
+ +
+

+ + 29 January 2023 + + - + Google Summer of Code Final Work Product +

+
+ +
+

+ + 24 January 2023 + + - + Google Summer of Code Final Work Product +

+
+ +
+

+ + 28 September 2022 + + - + Week 14: Keyframes animation is now a bit easier in FURY +

+
+ +
+

+ + 28 September 2022 + + - + Week 14 - Morphing is here! +

+
+ +
+

+ + 21 September 2022 + + - + Week 16 - Working with Rotations! +

+
+ +
+

+ + 20 September 2022 + + - + Week 13: Keyframes animation is now a bit easier in FURY +

+
+ +
+

+ + 15 September 2022 + + - + Week 13 - Multi-bone skeletal animation support +

+
+ +
+

+ + 14 September 2022 + + - + Week 15 - Highlighting DrawShapes +

+
+ +
+

+ + 08 September 2022 + + - + Week 12 - Adding skeleton as actors and fix global transformation +

+
+ +
+

+ + 07 September 2022 + + - + Week 14 - Updating DrawPanel architecture +

+
+ +
+

+ + 07 September 2022 + + - + Week 12: Adding new tutorials +

+
+ +
+

+ + 31 August 2022 + + - + Week 13 - Separating tests and fixing bugs +

+
+ +
+

+ + 31 August 2022 + + - + Week 11 - Multiple transformations support and adding tests +

+
+ +
+

+ + 30 August 2022 + + - + Week 11: Improving tutorials a little +

+
+ +
+

+ + 25 August 2022 + + - + Week 10 - Multi-node skinning support +

+
+ +
+

+ + 24 August 2022 + + - + Week 12 - Fixing translating issues and updating tests +

+
+ +
+

+ + 23 August 2022 + + - + Week 10: Supporting hierarchical animating +

+
+ +
+

+ + 17 August 2022 + + - + Week 9 - First working skeletal animation prototype +

+
+ +
+

+ + 17 August 2022 + + - + Week 11 - Creating a base for Freehand Drawing +

+
+ +
+

+ + 16 August 2022 + + - + Week 9: Animating primitives of the same actor +

+
+ +
+

+ + 10 August 2022 + + - + Week 8 - Fixing animation bugs +

+
+ +
+

+ + 10 August 2022 + + - + Week 10 - Understanding Codes and Playing with Animation +

+
+ +
+

+ + 09 August 2022 + + - + Week 8: Back to the shader-based version of the Timeline +

+
+ +
+

+ + 03 August 2022 + + - + Week 9 - Grouping and Transforming Shapes +

+
+ +
+

+ + 01 August 2022 + + - + Week 7: Billboard spheres and implementing interpolators using closures +

+
+ +
+

+ + 01 August 2022 + + - + Week 7 - Fixing bugs in animations +

+
+ +
+

+ + 27 July 2022 + + - + Week 8 - Working on the polyline feature +

+
+ +
+

+ + 25 July 2022 + + - + Week 6: Fixing the Timeline issues and equipping it with more features +

+
+ +
+

+ + 25 July 2022 + + - + Week 6 - Extracting the animation data +

+
+ +
+

+ + 20 July 2022 + + - + Week 7 - Working on Rotation PR and Trying Freehand Drawing +

+
+ +
+

+ + 19 July 2022 + + - + Week 5: Slerp implementation, documenting the Timeline, and adding unit tests +

+
+ +
+

+ + 19 July 2022 + + - + Week 5 - Creating PR for glTF exporter and fixing the loader +

+
+ +
+

+ + 13 July 2022 + + - + Week 6 - Supporting Rotation of the Shapes from the Center +

+
+ +
+

+ + 12 July 2022 + + - + Week 4 - Finalizing glTF loader +

+
+ +
+

+ + 11 July 2022 + + - + Week 4: Camera animation, interpolation in GLSL, and a single Timeline! +

+
+ +
+

+ + 06 July 2022 + + - + Week 5 - Working on new features +

+
+ +
+

+ + 04 July 2022 + + - + Week 3: Redesigning the API, Implementing cubic Bezier Interpolator, and making progress on the GPU side! +

+
+ +
+

+ + 04 July 2022 + + - + Week 3 - Fixing fetcher, adding tests and docs +

+
+ +
+

+ + 29 June 2022 + + - + Week 4 - Fixing the Clamping Issue +

+
+ +
+

+ + 29 June 2022 + + - + Week 2 - Improving Fetcher and Exporting glTF +

+
+ +
+

+ + 28 June 2022 + + - + Week 2: Implementing non-linear and color interpolators +

+
+ +
+

+ + 22 June 2022 + + - + Week 3 - Dealing with Problems +

+
+ +
+

+ + 20 June 2022 + + - + Week 1 - A Basic glTF Importer +

+
+ +
+

+ + 19 June 2022 + + - + Week 1: Implementing a basic Keyframe animation API +

+
+ +
+

+ + 15 June 2022 + + - + Week 2 - Improving DrawPanel UI +

+
+ +
+

+ + 08 June 2022 + + - + Week 1 - Laying the Foundation of DrawPanel UI +

+
+ +
+

+ + 25 May 2022 + + - + Pre-GSoC Journey +

+
+ +
+

+ + 24 May 2022 + + - + My Journey to GSoC 2022 +

+
+ +
+

+ + 23 May 2022 + + - + My journey till getting accepted into GSoC22 +

+
+ +
+

+ + 01 February 2022 + + - + Contribute to FURY via Google Summer of Code 2022 +

+
+ +
+

+ + 23 August 2021 + + - + Google Summer of Code Final Work Product +

+
+ +
+

+ + 23 August 2021 + + - + Google Summer of Code Final Work Product +

+
+ +
+

+ + 23 August 2021 + + - + Google Summer of Code 2021 - Final Report - Bruno Messias +

+
+ +
+

+ + 16 August 2021 + + - + Week #11: Removing the flickering effect +

+
+ +
+

+ + 16 August 2021 + + - + Week #11: Finalizing open Pull Requests +

+
+ +
+

+ + 16 August 2021 + + - + Tenth coding week! +

+
+ +
+

+ + 09 August 2021 + + - + Week#10: Accordion UI, Support for sprite sheet animations +

+
+ +
+

+ + 09 August 2021 + + - + Week #10: SDF Fonts +

+
+ +
+

+ + 09 August 2021 + + - + Ninth coding week! +

+
+ +
+

+ + 02 August 2021 + + - + Week #9: More Layouts! +

+
+ +
+

+ + 02 August 2021 + + - + Week #09: Sphinx custom summary +

+
+ +
+

+ + 02 August 2021 + + - + Eighth coding week! +

+
+ +
+

+ + 26 July 2021 + + - + Weekly Check-In #8 +

+
+ +
+

+ + 26 July 2021 + + - + Week #8: Code Cleanup, Finishing up open PRs, Continuing work on Tree2D +

+
+ +
+

+ + 26 July 2021 + + - + Seventh week of coding! +

+
+ +
+

+ + 19 July 2021 + + - + Weekly Check-In #7 +

+
+ +
+

+ + 19 July 2021 + + - + Week #7: Finalizing the stalling PRs, finishing up Tree2D UI. +

+
+ +
+

+ + 19 July 2021 + + - + Sixth week of coding! +

+
+ +
+

+ + 12 July 2021 + + - + Week #6: Bug fixes, Working on Tree2D UI +

+
+ +
+

+ + 12 July 2021 + + - + Network layout algorithms using IPC +

+
+ +
+

+ + 12 July 2021 + + - + Fifth week of coding! +

+
+ +
+

+ + 05 July 2021 + + - + Weekly Check-In #5 +

+
+ +
+

+ + 05 July 2021 + + - + Week #5: Rebasing all PRs w.r.t the UI restructuring, Tree2D, Bug Fixes +

+
+ +
+

+ + 05 July 2021 + + - + SOLID, monkey patching a python issue and network visualization through WebRTC +

+
+ +
+

+ + 05 July 2021 + + - + Fourth week of coding! +

+
+ +
+

+ + 28 June 2021 + + - + Week #4: Adding Tree UI to the UI module +

+
+ +
+

+ + 28 June 2021 + + - + Third week of coding! +

+
+ +
+

+ + 21 June 2021 + + - + Weekly Check-In #3 +

+
+ +
+

+ + 21 June 2021 + + - + Week #3: Adapting GridLayout to work with UI +

+
+ +
+

+ + 21 June 2021 + + - + Second week of coding! +

+
+ +
+

+ + 14 June 2021 + + - + First week of coding! +

+
+ +
+

+ + 13 June 2021 + + - + Week #2: Feature additions in UI and IO modules +

+
+ +
+

+ + 13 June 2021 + + - + A Stadia-like system for data visualization +

+
+ +
+

+ + 08 June 2021 + + - + Welcome to my GSoC Blog! +

+
+ +
+

+ + 08 June 2021 + + - + Weekly Check-In #1 +

+
+ +
+

+ + 08 June 2021 + + - + Week #1: Welcome to my weekly Blogs! +

+
+ +
+

+ + 09 March 2021 + + - + Google Summer of Code +

+
+ +
+

+ + 24 August 2020 + + - + Shader Showcase +

+
+ +
+

+ + 24 August 2020 + + - + Google Summer of Code Final Work Product +

+
+ +
+

+ + 24 August 2020 + + - + Google Summer of Code 2020 Final Work Product +

+
+ +
+

+ + 23 August 2020 + + - + Part of the Journey is the end unless its Open Source! +

+
+ +
+

+ + 17 August 2020 + + - + Outline Picker +

+
+ +
+

+ + 16 August 2020 + + - + Wrecking Ball Simulation, Scrollbars Update, Physics Tutorials. +

+
+ +
+

+ + 09 August 2020 + + - + More Shaders!! +

+
+ +
+

+ + 09 August 2020 + + - + Chain Simulation, Scrollbar Refactor, Tutorial Update. +

+
+ +
+

+ + 02 August 2020 + + - + Single Actor, Physics, Scrollbars. +

+
+ +
+

+ + 02 August 2020 + + - + More Shaders!! +

+
+ +
+

+ + 27 July 2020 + + - + Merging SDF primitives. +

+
+ +
+

+ + 26 July 2020 + + - + Tab UI, TabPanel2D, Tab UI Tutorial. +

+
+ +
+

+ + 20 July 2020 + + - + Improvements in SDF primitives. +

+
+ +
+

+ + 19 July 2020 + + - + ComboBox2D, TextBlock2D, Clipping Overflow. +

+
+ +
+

+ + 13 July 2020 + + - + Multiple SDF primitives. +

+
+ +
+

+ + 12 July 2020 + + - + Orientation, Sizing, Tab UI. +

+
+ +
+

+ + 05 July 2020 + + - + Translation, Reposition, Rotation. +

+
+ +
+

+ + 05 July 2020 + + - + Spherical harmonics, Continued. +

+
+ +
+

+ + 28 June 2020 + + - + Spherical harmonics +

+
+ +
+

+ + 28 June 2020 + + - + May the Force be with you!! +

+
+ +
+

+ + 21 June 2020 + + - + TextBlock2D Progress!! +

+
+ +
+

+ + 21 June 2020 + + - + Raymarching continued +

+
+ +
+

+ + 14 June 2020 + + - + Raymarching!! +

+
+ +
+

+ + 14 June 2020 + + - + ComboBox2D Progress!! +

+
+ +
+

+ + 07 June 2020 + + - + First week of coding!! +

+
+ +
+

+ + 07 June 2020 + + - + First week of coding!! +

+
+ +
+

+ + 30 May 2020 + + - + Welcome to my GSoC Blog!!! +

+
+ +
+

+ + 30 May 2020 + + - + Weekly Check-in #1 +

+
+ +
+

+ + 05 January 2020 + + - + Google Summer of Code +

+
+ +
+ + + +
+

+ Posts in + news +

+ +
+

+ + 19 June 2019 + + - + Success on Brain Art Competition using FURY +

+
+ +
+ + + +
+

+ Posts in + release +

+ +
+

+ + 15 April 2023 + + - + FURY 0.9.0 Released +

+
+ +
+

+ + 31 January 2022 + + - + FURY 0.8.0 Released +

+
+ +
+

+ + 03 August 2021 + + - + FURY 0.7.0 Released +

+
+ +
+

+ + 13 March 2021 + + - + FURY 0.7.0 Released +

+
+ +
+

+ + 18 August 2020 + + - + FURY 0.6.1 Released +

+
+ +
+

+ + 20 July 2020 + + - + FURY 0.6.0 Released +

+
+ +
+

+ + 09 April 2020 + + - + FURY 0.5.1 Released +

+
+ +
+

+ + 29 October 2019 + + - + FURY 0.4.0 Released +

+
+ +
+

+ + 02 August 2019 + + - + FURY 0.3.0 Released +

+
+ +
+

+ + 08 March 2019 + + - + FURY 0.2.0 Released +

+
+ +
+

+ + 26 November 2018 + + - + FURY 0.1.4 Released +

+
+ +
+

+ + 31 October 2018 + + - + FURY 0.1.3 Released +

+
+ +
+

+ + 21 September 2018 + + - + FURY 0.1.0 Released +

+
+ +
+ + + +
+ + + +
+ +
+
+
+ +
+ + + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/blog/category/gsoc.html b/v0.10.x/blog/category/gsoc.html new file mode 100644 index 000000000..27a1ab803 --- /dev/null +++ b/v0.10.x/blog/category/gsoc.html @@ -0,0 +1,11891 @@ + + + + + + + Posts in gsoc — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +
+

+ + Posts in + + gsoc + +

+ + +
+

+ Google Summer of Code Final Work Product +

+
    +
  • + + + 25 August 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Name: Praneeth Shetty

+

+ +

Read more ...

+
+
+ +
+

+ Week 12 : Experimenting with ODFs implementation +

+
    +
  • + + + 24 August 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Tania Castillo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

There were different issues I needed to address for the ODF implementation. Even though I could not solve any of them completely, I did check each of the issues and made some progress. All the work in progress is being recorded in the following branch SH-for-ODF-impl, which when ready will be associated with a well-structured PR.

+

+ +

Read more ...

+
+
+ +
+

+ Google Summer of Code Final Work Product +

+
    +
  • + + + 24 August 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Tania Castillo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Name: Tania Castillo

+

+ +

Read more ...

+
+
+ +
+

+ Week 12: Now That is (almost) a Wrap! +

+ +

Hello everyone, it’s time for another GSoC blogpost! Today, I am going to talk about some minor details I worked on last week on my +project.

+

+ +

Read more ...

+
+
+ +
+

+ Google Summer of Code Final Work Product +

+ +

Name: João Victor Dell Agli Floriano

+

+ +

Read more ...

+
+
+ +
+

+ Week 12: FileDialog Quest Begins! +

+
    +
  • + + + 19 August 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

During this week, I initiated my work on the FileDialog PR, which had been started by Soham. The initial version of the FileDialog can be found at #294. To start, I focused on rebasing the PR. Since this PR was based on an older version, there were some updates to the overall UI structure that needed to be addressed for compatibility. While handling this, I identified a set of issues that I documented in the current PR #832. These mainly revolved around:

+

+ +

Read more ...

+
+
+ +
+

+ Week 11 : Adjusting ODF implementation and looking for solutions on issues found +

+
    +
  • + + + 16 August 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Tania Castillo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

I continued to experiment with the ODF glyph implementation. Thanks to one of my mentors I figured out how to get the missing data corresponding to the SH coefficients \(a^l_m\) part of the function \(f(\theta, \phi)\) described here. I also was told to make sure to implement the correct SH basis since there are different definitions from the literature, I have to focus now in the one proposed by Descoteaux, described in this paper, which is labeled in dipy as descoteaux07. To do this I had to make a small adjustment to the base implementation that I took as a reference, from which I obtained a first result using SH of order 4.

+

+ +

Read more ...

+
+
+ +
+

+ Week 11: A Refactor is Sometimes Needed +

+ +

Hello everyone, it’s time for another weekly blogpost! Today I am going to share some updates on the API refactoring +I was working on with my mentors.

+

+ +

Read more ...

+
+
+ +
+

+ Week 11: Bye Bye SpinBox +

+
    +
  • + + + 12 August 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Building upon the progress of the previous week, a major milestone was reached with the merging of PR #830. This PR added essential “getters” and “setters” for the new features of TextBlock, making it easier to handle changes. This, in turn, facilitated the integration of SpinBoxUI with the updated TextBlock.

+

+ +

Read more ...

+
+
+ +
+

+ Week 10 : Start of SH implementation experiments +

+
    +
  • + + + 08 August 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Tania Castillo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

I started formally working on SH implementation. I was told to start first doing a simple program where I can modify in real-time the order \(l\) and degree \(m\), parameters corresponding to the Spherical Harmonics function \(Y^m_l(\theta,\phi)=\), based on previous work. That is just one part of the final ODF calculation, but here is what a first experimental script looks like.

+

+ +

Read more ...

+
+
+ +
+

+ Week 10: Ready for Review! +

+ +

Hello everyone, it’s time for another weekly blogpost!

+

+ +

Read more ...

+
+
+ +
+

+ Week 10: Its time for a Spin-Box! +

+
    +
  • + + + 05 August 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week, my focus shifted to the SpinBoxUI after wrapping up work on TextBlock2D. SpinBoxUI is a component that allows users to select a value by spinning through a range. To ensure a smooth transition, I made adjustments in SpinBoxUI to align it with the recent updates in TextBlock2D. To make things even clearer and more user-friendly, I initiated a continuous code improvement process. I introduced setters and getters that enable easier customization of TextBlock2D’s new features, such as auto_font_scale and dynamic_bbox. These tools simplify the process of adjusting these settings, and you can see the ongoing changes in pull request #830.

+

+ +

Read more ...

+
+
+ +
+

+ Week 9: Tutorial done and polishing DTI uncertainty +

+
    +
  • + + + 31 July 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Tania Castillo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

I addressed the comments from the tutorial of PR #818 related to how to display specific visualizations I wanted to make. I was suggested to use ShowManager to handle the zoom of the scene and also to use GridUI to display several actors at the same time for a visual quality comparison of the tensors. Below are some images generated for the tutorial that is almost done.

+

+ +

Read more ...

+
+
+ +
+

+ Week 9: It is Polishing Time! +

+ +

Hello everyone, it’s time for another weekly blogpost! Today, I am going to update you on my project’s latest changes.

+

+ +

Read more ...

+
+
+ +
+

+ Week 9: TextBlock2D is Finally Merged! +

+
    +
  • + + + 29 July 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Continuing from the previous week, it seemed like we were almost done with the TextBlock2D, but there remained a final task of addressing conflicting issues. Being a core part of the UI, TextBlock2D had a few compatibility problems with certain other UI elements.

+

+ +

Read more ...

+
+
+ +
+

+ Week 8: Working on Ellipsoid Tutorial and exploring SH +

+
    +
  • + + + 25 July 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Tania Castillo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

I mainly worked on the ellipsoid actor tutorial, as PR #791 is finally merged, so I was able to complete the tutorial by adding my implementation. In addition, during the weekly meeting, I received a good overview of the next issue I will be working on, which is using raymarching SDFs to display spherical harmonics (SH) for visualizing ODF glyphs for DTI. I got several ideas and resources which I can start experimenting with, such as Shadertoy and some base implementations from other FURY contributors. The main drawback when creating these objects is the amount of data required to create them, because depending on the SH order, the number of parameters that the function receives may vary, also unlike the tensors, which are represented only with a 3x3 matrix, here we could have more than 9 values associated with a single glyph, so passing the information from python to the shaders is not so trivial, besides requiring more resources as there is more information that needs to be processed. Some ideas I received were using matrixes instead of vectors, using templating, or even using texture to pass the data. I started to explore these options further, as well as to review in more detail the existing implementations of SH with raymarching, in order to understand them better.

+

+ +

Read more ...

+
+
+ +
+

+ Week 8: The Birth of a Versatile API +

+ +

Hello everyone, it’s time for another weekly blogpost! Today, I am going to tell you all about how is the KDE API development going, and +to show you the potential this holds for the future!

+

+ +

Read more ...

+
+
+ +
+

+ Week 8: Another week with TextBlockUI +

+
    +
  • + + + 22 July 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week, I delved deeper into the TextBlock2D Bounding Box PR to address the challenges with tests and offsetting issues. In a pair programming session with my mentor, we discovered that the offsetting background problem stemmed from the dynamic nature of the bounding box. The issue arose when the RingSlider2D component began with an initial text size larger than the current text, which changed as the value was adjusted between 0-100%. This resulted in problems with offsetting and shrinking the bounding box. To resolve this, we decided to make the dynamic bounding box an optional feature.

+

+ +

Read more ...

+
+
+ +
+

+ Week 7: Experimentation Done +

+ +

Hello everyone, welcome to another weekly blogpost! Let’s talk about the current status of my project (spoiler: it is beautiful).

+

+ +

Read more ...

+
+
+ +
+

+ Week 7: Adjustments on the Uncertainty Cones visualization +

+
    +
  • + + + 17 July 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Tania Castillo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

I was told to refactor some parts of the uncertainty PR, since I was relying too much on dipy functions which is not good because it makes maintenance more difficult as dipy requires FURY for some functionalities. So I did some adjustments on the uncertainty function parameters and the corresponding tests, hopefully I managed to get with the most appropriate definition but I need to receive a first feedback to see how much I have to adjust the implementation. As I had to delete some relevant code lines inside the uncertainty calculation which consisted of preprocessing the data in order to define the necessary variables for the uncertainty formula, I was also suggested to make a tutorial of this new feature, so I can explain in detail how to obtain and adjust the necessary information, before passing it to the actor, and in general how and what is the purpose of this new function.

+

+ +

Read more ...

+
+
+ +
+

+ Week 7: Sowing the seeds for TreeUI +

+
    +
  • + + + 15 July 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week, I focused on completing the TextBlock2D Bounding Box feature. However, the tests were failing due to automatic background resizing based on content and improper text actor alignment during setup. I encountered difficulties while positioning the text, which caused the text to appear offset and led to test failures.

+

+ +

Read more ...

+
+
+ +
+

+ Week 6: Things are Starting to Build Up +

+ +

Hello everyone, time for a other weekly blogpost! Today, I will show you my current progress on my project and latest activities.

+

+ +

Read more ...

+
+
+ +
+

+ Week 6: First draft of the Ellipsoid tutorial +

+
    +
  • + + + 10 July 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Tania Castillo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

#PR 818: Tutorial on using ellipsoid actor to visualize tensor ellipsoids for DTI

+

+ +

Read more ...

+
+
+ +
+

+ Week 6: BoundingBox for TextBlock2D! +

+
    +
  • + + + 08 July 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week, I worked on improving the TextBlock2D component in the UI system. I started from scratch to address alignment and scaling issues. When resizing the TextBlock2D, the text alignment and justification with the background rectangle were inconsistent. To resolve this, I introduced a new “boundingbox” property that calculates the text bounding box based on its content. Additionally, I separated the scaling mode from the resizing action with the new “auto_font_scale” property, enabling automatic font scaling according to the bounding box. This will provide better alignment, justified text, and smoother font scaling for the TextBlock2D component. Try it out at PR #803.

+

+ +

Read more ...

+
+
+ +
+

+ Week 5: Preparing the data for the Ellipsoid tutorial +

+
    +
  • + + + 03 July 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Tania Castillo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

During the weekly meeting with my mentors, there was a small discussion over the naming of the actor and its usage. On the one hand, although the purpose of the actor is to visualize diffusion tensor ellipsoids, the idea is that it can also be used for any other type of visualization that requires the use of ellipsoids, so in the end, we decided to keep the name ellipsoid as it is more generic. On the other hand, as there is already an actor made for the purpose of tensor visualization, namely tensor_slicer, it might not be obvious how and why one would use this new ellipsoid actor for this purpose, thus it was proposed to make a tutorial that can clarify this. The main difference between both actors relies on the quality and the amount of data that can be displayed, so the idea is to show the difference between both alternatives so the user can choose which one to use depending on their needs. To prepare the tutorial the first step was to add the data I will use on fury-data so I can then fetch and load the datasets I need to work on the tutorial.

+

+ +

Read more ...

+
+
+ +
+

+ Week 5: All Roads Lead to Rome +

+ +

Hello everyone, time for another weekly blogpost! Today, we will talk about taking different paths to reach your objective.

+

+ +

Read more ...

+
+
+ +
+

+ Week 5: Trying out PRs and Planning Ahead +

+
    +
  • + + + 01 July 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Due to ongoing exams, my productivity was limited this week. However, I managed to find some time to explore and review a few PRs submitted by contributors:

+

+ +

Read more ...

+
+
+ +
+

+ Week 4: First draft of the DTI uncertainty visualization +

+
    +
  • + + + 27 June 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Tania Castillo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

#PR 810: DTI uncertainty visualization

+

+ +

Read more ...

+
+
+ +
+

+ Week 4: Nothing is Ever Lost +

+ +

Welcome again to another weekly blogpost! Today, let’s talk about the importance of guidance throughout a project.

+

+ +

Read more ...

+
+
+ +
+

+ Week 4: Exam Preparations and Reviewing +

+
    +
  • + + + 24 June 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week, amidst end-semester exams, I managed to accomplish a few notable tasks. Let’s dive into the highlights:

+

+ +

Read more ...

+
+
+ +
+

+ Week 3: Working on uncertainty and details of the first PR +

+
    +
  • + + + 19 June 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Tania Castillo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

I made some adjustments to the ellipsoid actor definition, now called tensor. This was something discussed in the weekly meeting as the coming changes are related to this actor, the idea now is to have a tensor actor that allows choosing between displaying the tensor ellipsoids or the uncertainty cones (later on). I also worked on the uncertainty calculation, and the cone SDF for the visualization, so I plan to do a WIP PR next to start getting feedback on this new addition.

+

+ +

Read more ...

+
+
+ +
+

+ Week 3: Watch Your Expectations +

+ +

Hello everyone, it’s time for another weekly blogpost! This week, +I will talk about how you should watch your expectations when working with any project.

+

+ +

Read more ...

+
+
+ +
+

+ Week 3: Resolving Combobox Icon Flaw and TextBox Justification +

+
    +
  • + + + 17 June 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week, I tackled the ComboBox2D icon flaw, which was addressed using Pull Request (PR) #576. The problem arose when we added a ComboBox2D to the TabUI. The TabUI would propagate the set_visibility = true for all its child elements, causing the combobox to appear on the screen without the icon change. To fix this issue, PR #768 updated the set_visibility method of the UI class, ensuring that the icon change was applied correctly.

+

+ +

Read more ...

+
+
+ +
+

+ Week 2: The Importance of (good) Documentation +

+ +

Hello everybody, welcome to the week 2 of this project! I must admit I thought this would be simpler than it is currently being, but I forgot that when it comes to dealing with computer graphics’ applications, things never are. Below, some updates on what I have been up to for this past week.

+

+ +

Read more ...

+
+
+ +
+

+ Week 2: Making adjustments to the Ellipsoid Actor +

+
    +
  • + + + 12 June 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Tania Castillo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

I made some minor adjustments to the last PR I submitted. Last time it was a draft since I was waiting for the weekly meeting to know how to proceed, but now it is ready. I am waiting for the review so I can make the necessary corrections and adjustments to merge this first PR soon.

+

+ +

Read more ...

+
+
+ +
+

+ Week 2: Tackling Text Justification and Icon Flaw Issues +

+
    +
  • + + + 11 June 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week, I continued tweaking the text justification PR #790 and encountered a new issue when combining both justification and vertical_justification. The problem arose because the vertical_justification did not take into account the applied justification, resulting in unexpected behavior. I focused on resolving this issue by ensuring that both justifications work together correctly. Additionally, during the weekly meeting, we discussed the problem and decided to introduce new properties such as boundaries and padding to enhance the functionality of the text justification feature.

+

+ +

Read more ...

+
+
+ +
+

+ Week 1: Ellipsoid actor implemented with SDF +

+
    +
  • + + + 05 June 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Tania Castillo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

PR #791: Ellipsoid actor implemented with SDF

+

+ +

Read more ...

+
+
+ +
+

+ The FBO Saga - Week 1 +

+ +

As mentioned in the last week’s blogpost, the goal for that week was to investigate VTK’s Framebuffer Object framework. +An update on that is that indeed, VTK has one more low-level working FBO class that can be used inside FURY, however, +they come with some issues that I will explain further below.

+

+ +

Read more ...

+
+
+ +
+

+ Week 1: Working with SpinBox and TextBox Enhancements +

+
    +
  • + + + 03 June 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week, my focus was on reviewing pull requests (PRs) and issues related to the user interface (UI) of the project. I meticulously went through each PR and issue, identifying those specifically associated with UI improvements. To streamline the process, I categorized them accordingly under the UI category. One of the key tasks was PR #499, which involved the implementation of SpinBoxUI. After rebasing the PR, I identified an alignment issue with the textbox component.

+

+ +

Read more ...

+
+
+ +
+

+ Week 0: Community Bounding Period +

+
    +
  • + + + 02 June 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hello All!

+

+ +

Read more ...

+
+
+ +
+

+ Week 0: Community Bounding Period +

+
    +
  • + + + 02 June 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Tania Castillo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hello everyone, my name is Tania Castillo, I am close to finishing my degree in Computer Science and I think this is a great opportunity to put my learning and skills into practice. I will be working with FURY on improving the visualization of DTI tensors and HARDI ODFs glyphs by using well-known techniques in computer graphics.

+

+ +

Read more ...

+
+
+ +
+

+ The Beginning of Everything - Week 0 +

+ +

Hello everyone, welcome to the beginning of my journey through GSoC 2023! I would like to thank everyone involved for the opportunity provided, it is an honour to be working side by side with professionals and so many experienced people from around the world.

+

+ +

Read more ...

+
+
+ +
+

+ Contribute to FURY via Google Summer of Code 2023 +

+
    +
  • + + + 01 February 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Serge Koudoro + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

FURY is participating in the Google Summer of Code 2023 under the umbrella of the Python Software Foundation.

+

+ +

Read more ...

+
+
+ +
+

+ Google Summer of Code Final Work Product +

+
    +
  • + + + 29 January 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Mohamed Abouagour + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Name: Mohamed Abouagour

+

+ +

Read more ...

+
+
+ +
+

+ Google Summer of Code Final Work Product +

+
    +
  • + + + 29 January 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Shivam Anand + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Name: Shivam Anand

+

+ +

Read more ...

+
+
+ +
+

+ Google Summer of Code Final Work Product +

+
    +
  • + + + 24 January 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Name: Praneeth Shetty

+

+ +

Read more ...

+
+
+ +
+

+ Week 14: Keyframes animation is now a bit easier in FURY +

+
    +
  • + + + 28 September 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Mohamed Abouagour + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Separated the Timeline into a Timeline and an Animation. So, instead of having the Timeline do everything. It’s now more like doing animations in Blender and other 3D editing software where the timeline handles the playback of several animations #694.

+

+ +

Read more ...

+
+
+ +
+

+ Week 14 - Morphing is here! +

+
    +
  • + + + 28 September 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Shivam Anand + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week, I started with multiple actor support in skinning and managed to do it +successfully. Here’s the preview using the BrainStem model.

+

+ +

Read more ...

+
+
+ +
+

+ Week 16 - Working with Rotations! +

+
    +
  • + + + 21 September 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Last week my mentors noticed that each DrawShape has its individual rotation_slider which increases redundancy and complexity in setting its visibility on and off. Instead, they suggested moving the rotation_slider to DrawPanel and keeping a common slider for all the shapes.

+

+ +

Read more ...

+
+
+ +
+

+ Week 13: Keyframes animation is now a bit easier in FURY +

+
    +
  • + + + 20 September 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Mohamed Abouagour + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Added the ability to have the ShowManager stored inside the Timeline. That way the user does not have to update and render the animations because it will be done internally.

+

+ +

Read more ...

+
+
+ +
+

+ Week 13 - Multi-bone skeletal animation support +

+
    +
  • + + + 15 September 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Shivam Anand + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week I fixed all the issues with skeletal animations, and we got to see our first render of skeletal animation :).

+

+ +

Read more ...

+
+
+ +
+

+ Week 15 - Highlighting DrawShapes +

+
    +
  • + + + 14 September 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week I started with highlighting the shapes. As discussed earlier, I had two ways, but while implementing them, I found out both ways aren’t that good to continue with. +The first way in which we thought of creating the scaled shapes in the background had an issue with the stacking. The border(blue rectangle) and the shape(grey rectangle) both seem to look like different shapes just grouped together as shown below.

+

+ +

Read more ...

+
+
+ +
+

+ Week 12 - Adding skeleton as actors and fix global transformation +

+
    +
  • + + + 08 September 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Shivam Anand + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

I started this week by fixing the segmentation fault for the skinning test. I could not fix this as of now.

+

+ +

Read more ...

+
+
+ +
+

+ Week 14 - Updating DrawPanel architecture +

+
    +
  • + + + 07 September 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week I continued updating the DrawShape and DrawPanel.

+

+ +

Read more ...

+
+
+ +
+

+ Week 12: Adding new tutorials +

+
    +
  • + + + 07 September 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Mohamed Abouagour + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Restructured tutorials to be more readable and more focused on a specific topic.

+

+ +

Read more ...

+
+
+ +
+

+ Week 13 - Separating tests and fixing bugs +

+
    +
  • + + + 31 August 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week I managed to fix the translation issue in PR #653. This was happening because of the calculation error while repositioning the shapes. Now it works as intended.

+

+ +

Read more ...

+
+
+ +
+

+ Week 11 - Multiple transformations support and adding tests +

+
    +
  • + + + 31 August 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Shivam Anand + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

As decided last week, I added support for multiple animations at the same timestamp. But this didn’t solve the animation problems of RiggedSimple model.

+

+ +

Read more ...

+
+
+ +
+

+ Week 11: Improving tutorials a little +

+
    +
  • + + + 30 August 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Mohamed Abouagour + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Fixed some issues in the hierarchical order animation support PR that we discussed during last week’s meeting (mostly naming issues).

+

+ +

Read more ...

+
+
+ +
+

+ Week 10 - Multi-node skinning support +

+
    +
  • + + + 25 August 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Shivam Anand + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

As we figured out that the SimpleSkin model is not animated as intended. This week I started working with that model; +I figured out that we need to apply the InverseBindMatrix to each timer callback. I had a hard time figuring out what inverse bind matrix actually does. +Here’s a good blog that answers that.

+

+ +

Read more ...

+
+
+ +
+

+ Week 12 - Fixing translating issues and updating tests +

+
    +
  • + + + 24 August 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

I started with updating the tests for PR #623 as some of the tests weren’t covering all the aspects in the code. +Previously I was just creating the DrawShape and adding it to the scene but now I had to analyze the scene to see whether they were properly added or not.

+

+ +

Read more ...

+
+
+ +
+

+ Week 10: Supporting hierarchical animating +

+
    +
  • + + + 23 August 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Mohamed Abouagour + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Implemented hierarchical order support for animations using matrices in this PR.

+

+ +

Read more ...

+
+
+ +
+

+ Week 9 - First working skeletal animation prototype +

+
    +
  • + + + 17 August 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Shivam Anand + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week I had the first working example of skeletal animation ready. I was able to render the SimpleSkin model. Here’s a quick preview:

+

+ +

Read more ...

+
+
+ +
+

+ Week 11 - Creating a base for Freehand Drawing +

+
    +
  • + + + 17 August 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week I tried to imitate the working of vtkImageTracer. Previously, I had created a small prototype for freehand drawing by adding points at the mouse position (which you can check out here). As mentioned, there were some drawback of this method. +So to overcome these issues, I tried combining both methods. Considering points using the previous method and instead of adding points I tried creating lines between them which looks promising. Below you can see a demo.

+

+ +

Read more ...

+
+
+ +
+

+ Week 9: Animating primitives of the same actor +

+
    +
  • + + + 16 August 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Mohamed Abouagour + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Made two tutorials in this PR that show two approaches on how to animate primitives of the same FURY actor using the Timeline.

+

+ +

Read more ...

+
+
+ +
+

+ Week 8 - Fixing animation bugs +

+
    +
  • + + + 10 August 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Shivam Anand + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week I had to fix the transformation issue in glTF animation. As discussed in the last meeting, I disabled vertex transformation and applied the transformation after the actor was formed.

+

+ +

Read more ...

+
+
+ +
+

+ Week 10 - Understanding Codes and Playing with Animation +

+
    +
  • + + + 10 August 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

I started working on the PR #645 created last week and tested a few more corner cases such as What happens if the maximum value is exceeded?? What if we give a value less than the minimum value range?? +Most of these worked as intended.

+

+ +

Read more ...

+
+
+ +
+

+ Week 8: Back to the shader-based version of the Timeline +

+
    +
  • + + + 09 August 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Mohamed Abouagour + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

First, I made some modifications to the main animation PR. Then as Filipi requested, I integrated the vertex shader that I was implementing a few weeks ago to work with the new improved version of the Timeline.

+

+ +

Read more ...

+
+
+ +
+

+ Week 9 - Grouping and Transforming Shapes +

+
    +
  • + + + 03 August 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

I started this week by creating a quick PR #645 for the UI sliders. The sliders raised ZeroDivsionError when the min and max values were the same. To solve this, I handled the case where the value_range becomes zero and then manually set the handle position to zero.

+

+ +

Read more ...

+
+
+ +
+

+ Week 7: Billboard spheres and implementing interpolators using closures +

+
    +
  • + + + 01 August 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Mohamed Abouagour + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Restructured the keyframe animation interpolators using closures to be functions instead of classes #647. Now it is easier to implement new interpolators with the help of the functions existing in fury/animation/helpers.py. Also, now unit tests can be added for the latter functions.

+

+ +

Read more ...

+
+
+ +
+

+ Week 7 - Fixing bugs in animations +

+
    +
  • + + + 01 August 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Shivam Anand + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week I started with implementing scaling to the animation example.

+

+ +

Read more ...

+
+
+ +
+

+ Week 8 - Working on the polyline feature +

+
    +
  • + + + 27 July 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week I started working on the polyline feature. After a lot of investigating and trying out different things, I found a way to call the dragging event manually without any prior click event. VTK actually captures the mouse movement using the MouseMoveEvent. This event is then modified by FURY to only be called after the click event. So I added a new callback to track the mouse movement and set the current canvas as an active prop because it is required to capture the drag event happening on it.

+

+ +

Read more ...

+
+
+ +
+

+ Week 6: Fixing the Timeline issues and equipping it with more features +

+
    +
  • + + + 25 July 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Mohamed Abouagour + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Improved the PlaybackPanel by adding speed control and the ability to loop the animation. Also, fixed the lagging issue of play and pause buttons and composed them into a single play/pause button.

+

+ +

Read more ...

+
+
+ +
+

+ Week 6 - Extracting the animation data +

+
    +
  • + + + 25 July 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Shivam Anand + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week, it was all about reading docs and extracting the animation data from buffers.

+

+ +

Read more ...

+
+
+ +
+

+ Week 7 - Working on Rotation PR and Trying Freehand Drawing +

+
    +
  • + + + 20 July 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

I continued PR #623 and fixed the displacement of the shape from its original position when applying rotation. This was happening because most of the calculations resulted in float values, but as the pixel position were integers we had to explicitly convert these values into int. This conversion rounded off the values and as we call this function continuously, each time the round-off would happen, the shape would get displaced.

+

+ +

Read more ...

+
+
+ +
+

+ Week 5: Slerp implementation, documenting the Timeline, and adding unit tests +

+
    +
  • + + + 19 July 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Mohamed Abouagour + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Implemented Slerp (spherical linear interpolation) for rotation keyframes.

+

+ +

Read more ...

+
+
+ +
+

+ Week 5 - Creating PR for glTF exporter and fixing the loader +

+
    +
  • + + + 19 July 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Shivam Anand + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Finalised the glTF export PR #630., adding tutorial, docs, and tests for all functions.

+

+ +

Read more ...

+
+
+ +
+

+ Week 6 - Supporting Rotation of the Shapes from the Center +

+
    +
  • + + + 13 July 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week I started implementing a new feature to rotate the shapes from the center using RingSlider2D. I already had a rotate function that rotates the shape around its pivot vertex, so I updated it to support rotation from the center.

+

+ +

Read more ...

+
+
+ +
+

+ Week 4 - Finalizing glTF loader +

+
    +
  • + + + 12 July 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Shivam Anand + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week I had to travel back to my college since the summer vacations have ended. +I had a coding session with Serge this week, we modified the exporter function and looked at some bugs I faced.

+

+ +

Read more ...

+
+
+ +
+

+ Week 4: Camera animation, interpolation in GLSL, and a single Timeline! +

+
    +
  • + + + 11 July 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Mohamed Abouagour + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Managed to implement a single Timeline using the Container class. So, instead of having two classes: Timeline and CompositeTimeline, now the Timeline can have multiple Timeline objects and controls them as in the code below.

+

+ +

Read more ...

+
+
+ +
+

+ Week 5 - Working on new features +

+
    +
  • + + + 06 July 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week I tried to create a base for some upcoming new features. +The first thing I updated was the Properties panel which I prototyped in Week 3. +So previously, it was just displaying the properties but now after the update, it is able to modify the properties(such as color, position, and rotation) too. This was a quick change to test the callbacks.

+

+ +

Read more ...

+
+
+ +
+

+ Week 3: Redesigning the API, Implementing cubic Bezier Interpolator, and making progress on the GPU side! +

+
    +
  • + + + 04 July 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Mohamed Abouagour + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Redesigned the keyframe animations API to optimize having a lot of timelines by composing them into a parent Timeline called CompositeTimeline while maintaining playing individual timelines separately.

+

+ +

Read more ...

+
+
+ +
+

+ Week 3 - Fixing fetcher, adding tests and docs +

+
    +
  • + + + 04 July 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Shivam Anand + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

The first task for this week was to fix the glTF fetcher. We noticed that while running tests it reaches the API limit. So we decided to use a JSON file that contains the download URLs for all models.

+

+ +

Read more ...

+
+
+ +
+

+ Week 4 - Fixing the Clamping Issue +

+
    +
  • + + + 29 June 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Phew!! This week was a tedious week for me as parallelly my End-Sem exams also started. So as usual I started from where I left off last week, The Clamping Issue. As per the discussion with the mentors, we decided to use the AABB bounding box method to calculate the bounding box around the shape and then reposition or transform respectively, as now we had a fixed reference point. So after doing some calculations with the mouse positions and the bounding box points at last, I was able to clamp all the shapes successfully.

+

+ +

Read more ...

+
+
+ +
+

+ Week 2 - Improving Fetcher and Exporting glTF +

+
    +
  • + + + 29 June 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Shivam Anand + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week I worked primarily on the glTF fetcher and exporting scenes to a glTF file. I added tests and docstrings for all functions. I modified the fetch_gltf function to return the downloaded files. As we planned, the PR for the glTF fetcher was merged this week.

+

+ +

Read more ...

+
+
+ +
+

+ Week 2: Implementing non-linear and color interpolators +

+
    +
  • + + + 28 June 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Mohamed Abouagour + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Implemented some other general interpolators such as n-th degree spline and cubic spline interpolators. Also implemented HSV and LAB color interpolators.

+

+ +

Read more ...

+
+
+ +
+

+ Week 3 - Dealing with Problems +

+
    +
  • + + + 22 June 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week was full of researching, playing around with things, prototyping ideas, etc. +I started with last week’s clamping issue and managed to solve this issue while drawing shapes by clipping the mouse position according to canvas size, but it didn’t solve the problem with translating these shapes. I tried solving this using various approaches, but if one thing would get fixed, other things would raise a new error.

+

+ +

Read more ...

+
+
+ +
+

+ Week 1 - A Basic glTF Importer +

+
    +
  • + + + 20 June 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Shivam Anand + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

In the community bonding period I met with my mentor Serge Koudoro, along with other mentors in FURY and gsoc contributors. +We discussed about my project and set up project timeline on github projects section. As my project (glTF Integration) +and Keyframe animations were related so we discussed on that too.

+

+ +

Read more ...

+
+
+ +
+

+ Week 1: Implementing a basic Keyframe animation API +

+
    +
  • + + + 19 June 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Mohamed Abouagour + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

During the community bonding period, we had weekly meetings in which I got to know the mentors better and bonded with Shivam and Praneeth, my fellow contributors. +We talked about the importance of open-source contribution and discussed scientific visualization, how important it is and how it differs from game engines despite having some similarities. +We also discussed how important the code review is and how to do a proper code review.

+

+ +

Read more ...

+
+
+ +
+

+ Week 2 - Improving DrawPanel UI +

+
    +
  • + + + 15 June 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week I had to refactor and make my code cleaner along with some bug fixing, I started by adding tests and tutorials so that my changes could be tested by everyone. Then I separated the mode for selection so that it would be easy to select an individual element and work along with it. Once the selection mode was complete I started with the deletion of the elements.

+

+ +

Read more ...

+
+
+ +
+

+ Week 1 - Laying the Foundation of DrawPanel UI +

+
    +
  • + + + 08 June 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week we started with our first technical meeting in which the weekly tasks were assigned. So I had to start with some background or canvas and draw a line using mouse clicks.

+

+ +

Read more ...

+
+
+ +
+

+ Pre-GSoC Journey +

+
    +
  • + + + 25 May 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hello Guys!! I am Praneeth Shetty, currently pursuing Bachelor of Engineering in Computer Engineering, and here is my journey from where I started to the selection into GSoC22.

+

+ +

Read more ...

+
+
+ +
+

+ My Journey to GSoC 2022 +

+
    +
  • + + + 24 May 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Shivam Sahu + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hi! I’m Shivam, currently pursuing my bachelor’s (expected 2024) in Production and Industrial engineering from the Indian Institute of Technology (IIT) Roorkee.

+

+ +

Read more ...

+
+
+ +
+

+ My journey till getting accepted into GSoC22 +

+
    +
  • + + + 23 May 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Mohamed Abouagour + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

My name is Mohamed and I’m from Egypt. I am pursuing a Bachelor of Engineering in Computer Engineering and Automatic Control (expected: 2023), Tanta University, Egypt.

+

+ +

Read more ...

+
+
+ +
+

+ Contribute to FURY via Google Summer of Code 2022 +

+
    +
  • + + + 01 February 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Serge Koudoro + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

FURY is participating in the Google Summer of Code 2022 under the umbrella of the Python Software Foundation.

+

+ +

Read more ...

+
+
+ +
+

+ Google Summer of Code Final Work Product +

+
    +
  • + + + 23 August 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Antriksh Misri + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Name: Antriksh Misri

+

+ +

Read more ...

+
+
+ +
+

+ Google Summer of Code Final Work Product +

+
    +
  • + + + 23 August 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Sajag Swami + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Name: Sajag Swami

+

+ +

Read more ...

+
+
+ +
+

+ Google Summer of Code 2021 - Final Report - Bruno Messias +

+
    +
  • + + + 23 August 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Bruno Messias + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

We have changed some points of my project in the first meeting. +Specifically, we focused the efforts into developing a streaming system +using the WebRTC protocol that could be used in more generic scenarios +than just the network visualization. In addition to that, we have opted +to develop the network visualization for fury as a separated repository +and package available here. The +name Helios was selected for this new network visualization system based +on the Fury rendering pipeline.

+

+ +

Read more ...

+
+
+ +
+

+ Week #11: Removing the flickering effect +

+
    +
  • + + + 16 August 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Bruno Messias + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

PR fury-gl/fury#489:

+

+ +

Read more ...

+
+
+ +
+

+ Week #11: Finalizing open Pull Requests +

+
    +
  • + + + 16 August 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Antriksh Misri + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Below are the tasks that I worked on:

+

+ +

Read more ...

+
+
+ +
+

+ Tenth coding week! +

+
    +
  • + + + 16 August 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Sajag Swami + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Welcome to the eleventh weekly check-in. I’ll be sharing my progress for the tenth week of coding.

+

+ +

Read more ...

+
+
+ +
+

+ Week#10: Accordion UI, Support for sprite sheet animations +

+
    +
  • + + + 09 August 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Antriksh Misri + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Below are the tasks that I worked on:

+

+ +

Read more ...

+
+
+ +
+

+ Week #10: SDF Fonts +

+
    +
  • + + + 09 August 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Bruno Messias + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

PR fury-gl/helios#22 +: Helios Documentation +Improvements.

+

+ +

Read more ...

+
+
+ +
+

+ Ninth coding week! +

+
    +
  • + + + 09 August 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Sajag Swami + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Welcome to the tenth weekly check-in. I’ll be sharing my progress for the ninth week of coding.

+

+ +

Read more ...

+
+
+ +
+

+ Week #9: More Layouts! +

+
    +
  • + + + 02 August 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Antriksh Misri + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Below are the tasks that I worked on:

+

+ +

Read more ...

+
+
+ +
+

+ Week #09: Sphinx custom summary +

+
    +
  • + + + 02 August 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Bruno Messias + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

PR fury-gl/helios#22 +: Helios Documentation +Improvements. +I’ve spent some time studying sphinx in order to discover how I could create a +custom summary inside of a template module.

+

+ +

Read more ...

+
+
+ +
+

+ Eighth coding week! +

+
    +
  • + + + 02 August 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Sajag Swami + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Welcome to the ninth weekly check-in. I’ll be sharing my progress for the eighth week of coding.

+

+ +

Read more ...

+
+
+ +
+

+ Weekly Check-In #8 +

+
    +
  • + + + 26 July 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Bruno Messias + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

PR fury-gl/helios#18 (merged): Helios Documentation/ +I’ve been working on Helios documentation. Now it’s available +online at https://fury-gl.github.io/helios-website image1

+

+ +

Read more ...

+
+
+ +
+

+ Week #8: Code Cleanup, Finishing up open PRs, Continuing work on Tree2D +

+
    +
  • + + + 26 July 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Antriksh Misri + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week I had to work on the open PRs specifically work on the bugs that were pointed out in last week’s meeting. Along side the bugs I had to continue the work on Tree2D UI element. Below is the detailed description of what I worked on this week:

+

+ +

Read more ...

+
+
+ +
+

+ Seventh week of coding! +

+
    +
  • + + + 26 July 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Sajag Swami + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Welcome to the eighth weekly check-in. I’ll be sharing my progress for the seventh week of coding.

+

+ +

Read more ...

+
+
+ +
+

+ Weekly Check-In #7 +

+
    +
  • + + + 19 July 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Bruno Messias + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

PR fury-gl/helios#16 +(merged): Helios IPC +network layout support for MacOs

+

+ +

Read more ...

+
+
+ +
+

+ Week #7: Finalizing the stalling PRs, finishing up Tree2D UI. +

+
    +
  • + + + 19 July 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Antriksh Misri + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week I had limited tasks to do, mostly tasks related to existing PRs. Other than some minor fixes I had to implement some more things in Tree2D which included some minor UI fixes, some changes in tutorial, adding tests. Below is the detailed description of what I worked on this week:

+

+ +

Read more ...

+
+
+ +
+

+ Sixth week of coding! +

+
    +
  • + + + 19 July 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Sajag Swami + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Welcome to the seventh weekly check-in. I’ll be sharing my progress for the sixth week of coding.

+

+ +

Read more ...

+
+
+ +
+

+ Week #6: Bug fixes, Working on Tree2D UI +

+
    +
  • + + + 12 July 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Antriksh Misri + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week I had relatively few tasks and most of them were to fix some bugs/design flaws that were discussed in last week’s meeting. Other than that, I had to implement a few things in the Tree2D UI element that will be discussed in detail below. I also had to update some existing PRs in order to make things work well. Below are the list of things I worked on this week:

+

+ +

Read more ...

+
+
+ +
+

+ Network layout algorithms using IPC +

+
    +
  • + + + 12 July 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Bruno Messias + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hi all. In the past weeks, I’ve been focusing on developing Helios; the +network visualization library for FURY. I improved the visual aspects of +the network rendering as well as implemented the most relevant network +layout methods.

+

+ +

Read more ...

+
+
+ +
+

+ Fifth week of coding! +

+
    +
  • + + + 12 July 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Sajag Swami + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Welcome to the sixth weekly check-in. I’ll be sharing my progress for the fifth week of coding.

+

+ +

Read more ...

+
+
+ +
+

+ Weekly Check-In #5 +

+
    +
  • + + + 05 July 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Bruno Messias + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Before the 8c670c2 commit, for some versions of MacOs the +streaming system was falling in a silent bug. I’ve spent a lot of +time researching to found a cause for this. Fortunately, I could found +the cause and the solution. This troublesome MacOs was falling in a +silent bug because the SharedMemory Object was creating a memory +resource with at least 4086 bytes independent if I’ve requested less +than that. If we look into the MultiDimensionalBuffer Object +(stream/tools.py) before the 8c670c2 commit we can see that Object +has max_size parameter which needs to be updated if the SharedMemory +was created with a “wrong” size.

+

+ +

Read more ...

+
+
+ +
+

+ Week #5: Rebasing all PRs w.r.t the UI restructuring, Tree2D, Bug Fixes +

+
    +
  • + + + 05 July 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Antriksh Misri + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

The UI restructuring was finally merged this week. This means UI is now a submodule in itself and provides different UI elements based on their types which are, core, elements, containers and some helper methods/classes. So, this week my main tasks were to rebase and fix merge conflicts of my open PR’s. Other than that, I had to continue my work on Tree2D UI element and finish the remaining aspects of it. Also, I had to create an example demonstrating how to use the newly added UI element. Many use cases were discussed in the open meeting like, an image gallery which displays preview image on the title and when expanded reveals the full scale image. I am thinking of adding multiple examples for the Tree2D to brainstorm on its certain features. Also, I had this annoying bug in Panel2D which didn’t allow it to be resized from the bottom right corner. It was resizing from the top right corner. I had to address this bug as well. Below are the tasks in detail:

+

+ +

Read more ...

+
+
+ +
+

+ SOLID, monkey patching a python issue and network visualization through WebRTC +

+
    +
  • + + + 05 July 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Bruno Messias + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

These past two weeks I’ve spent most of my time in the Streaming System +PR and the Network Layout +PR . In this post I’ll +focus on the most relevant things I’ve made for those PRs.

+

+ +

Read more ...

+
+
+ +
+

+ Fourth week of coding! +

+
    +
  • + + + 05 July 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Sajag Swami + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Welcome to the fifth weekly check-in. I’ll be sharing my progress for the fourth week of coding.

+

+ +

Read more ...

+
+
+ +
+

+ Week #4: Adding Tree UI to the UI module +

+
    +
  • + + + 28 June 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Antriksh Misri + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week I had very few tasks to do, almost all of them revolved around UI elements and adding stuff to the UI module. Earlier, it was pointed out that due to some design issues, importing certain modules into others caused circular imports which led to importing the specific modules inside a class/method which is not the best approach. This will be resolved as soon as the PR that fixes this issue is reviewed/merged in the codebase. In the meantime, all the PR’s related to UI will be on hold, which is why this I had few tasks this week. The tasks are described below in detail:

+

+ +

Read more ...

+
+
+ +
+

+ Third week of coding! +

+
    +
  • + + + 28 June 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Sajag Swami + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Welcome to the fourth weekly check-in. I’ll be sharing my progress for the third week of coding.

+

+ +

Read more ...

+
+
+ +
+

+ Weekly Check-In #3 +

+
    +
  • + + + 21 June 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Bruno Messias + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

PR fury-gl/fury#422 +(merged): +Integrated the 3d impostor spheres with the marker actor.

+

+ +

Read more ...

+
+
+ +
+

+ Week #3: Adapting GridLayout to work with UI +

+
    +
  • + + + 21 June 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Antriksh Misri + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week my tasks revolved around layout and UI elements. The primary goal for this week was to adapt the GridLayout to work with different UI elements. Currently, GridLayout just supports vtk actors and not UI elements, my task was to modify the class to support UI elements. The other tasks for this week are described below in detail:

+

+ +

Read more ...

+
+
+ +
+

+ Second week of coding! +

+
    +
  • + + + 21 June 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Sajag Swami + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Welcome to the third weekly check-in. I’ll be sharing my progress for the second week of coding.

+

+ +

Read more ...

+
+
+ +
+

+ First week of coding! +

+
    +
  • + + + 14 June 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Sajag Swami + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Welcome to the second weekly check-in. I’ll be sharing my progress for the first week of coding.

+

+ +

Read more ...

+
+
+ +
+

+ Week #2: Feature additions in UI and IO modules +

+
    +
  • + + + 13 June 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Antriksh Misri + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week I had to work on 3 PRs as well as some documentation. I really enjoyed this week’s work as the tasks were really interesting. The aim for these PRs were to actually add a couple of features in the UI as well as the IO module, which includes, adding support for border in Panel2D, adding support for network/URL images in load_image method in IO module, adding resizing Panel2D from bottom right corner, completing the document with layout solutions provided by Unity/Unreal engine. Below are the PRs that I worked on:

+

+ +

Read more ...

+
+
+ +
+

+ A Stadia-like system for data visualization +

+
    +
  • + + + 13 June 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Bruno Messias + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hi all! In this post I’ll talk about the PR +#437.

+

+ +

Read more ...

+
+
+ +
+

+ Welcome to my GSoC Blog! +

+
    +
  • + + + 08 June 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Sajag Swami + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hi all! +I’m Sajag Swami, a sophomore at Indian Institute of Technology, Roorkee. This summer, I will be working on adding a new functionality to FURY which shall enable users to +visualise various types of proteins via different representations like Richardson aka Ribbon diagrams and molecular surface diagrams. +As a part of my stretch goals, I’ll try to expand protein diagrams via other representations including:

+

+ +

Read more ...

+
+
+ +
+

+ Weekly Check-In #1 +

+
    +
  • + + + 08 June 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Bruno Messias + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hi everyone! My name is Bruno Messias currently I’m a Ph.D student at +USP/Brazil. In this summer I’ll develop new tools and features for +FURY-GL. Specifically, I’ll focus into developing a system for +collaborative visualization of large network layouts using FURY and VTK.

+

+ +

Read more ...

+
+
+ +
+

+ Week #1: Welcome to my weekly Blogs! +

+
    +
  • + + + 08 June 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Antriksh Misri + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hi everyone! I am Antriksh Misri. I am a Pre-Final year student at MIT Pune. This summer, I will be working on Layout Management under FURY’s UI module as my primary goal. This includes addition of different classes under Layout Management to provide different layouts/arrangements in which the UI elements can be arranged. As my stretch goals, I will be working on a couple of UI components for FURY’s UI module. These 2D and 3D components will be sci-fi like as seen in the movie “Guardians of The Galaxy”. My objective for the stretch goals would be to develop these UI components with their respective test and tutorials such that it adds on to the UI module of FURY and doesn’t hinder existing functionalities/performance.

+

+ +

Read more ...

+
+
+ +
+

+ Google Summer of Code +

+
    +
  • + + + 09 March 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Serge Koudoro + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

FURY is participating in the Google Summer of Code 2021 under the umbrella of the Python Software Foundation.

+

+ +

Read more ...

+
+
+ +
+

+ Shader Showcase +

+
    +
  • + + + 24 August 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Lenix Lobo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Make sure to check out Project FURY

+

+ +

Read more ...

+
+
+ +
+

+ Google Summer of Code Final Work Product +

+
    +
  • + + + 24 August 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Soham Biswas + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Name: Soham Biswas

+

+ +

Read more ...

+
+
+ +
+

+ Google Summer of Code 2020 Final Work Product +

+
    +
  • + + + 24 August 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Lenix Lobo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Name: Lenix Lobo

+

+ +

Read more ...

+
+
+ +
+

+ Part of the Journey is the end unless its Open Source! +

+
    +
  • + + + 23 August 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Soham Biswas + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hello and welcome to my final weekly check-in. Today officially marks the end of the coding period for GSoC 2020. I enjoyed every bit of it. This was a life-changing experience for me and now I observe and interpret everything from a different perspective altogether. I have grown into a better developer and a person since GSoC. I would like to thank all my mentors and especially Serge for his immense support and mentorship. I would love to contribute to fury even after GSoC is over but unfortunately my semester break is over so I won’t be as active as I was during the summer.

+

+ +

Read more ...

+
+
+ +
+

+ Outline Picker +

+
    +
  • + + + 17 August 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Lenix Lobo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Make sure to check out Project FURY

+

+ +

Read more ...

+
+
+ +
+

+ Wrecking Ball Simulation, Scrollbars Update, Physics Tutorials. +

+
    +
  • + + + 16 August 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Soham Biswas + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hello and welcome to my 12th weekly check-in. In this blog I will be discussing my progress with the wrecking ball simulation and my scrollbar separation work. Apart from this I have also finalized the physics simulation tutorials and have created a Pull Request to finally get it merged with the official repository. The official repository of my sub-org can be found here.

+

+ +

Read more ...

+
+
+ +
+

+ More Shaders!! +

+
    +
  • + + + 09 August 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Lenix Lobo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Make sure to check out Project FURY

+

+ +

Read more ...

+
+
+ +
+

+ Chain Simulation, Scrollbar Refactor, Tutorial Update. +

+
    +
  • + + + 09 August 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Soham Biswas + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hello and welcome to my 11th weekly check-in. In this blog I will be discussing my progress with multiple topics related to physics and ui components. I was actively working on a couple of things, specifically Joint simulations in pyBullet and scrollbar UI component. I also took up the responsibility to complete an incomplete Pull Request which was pending for quite a while. The official repository of my sub-org can be found here.

+

+ +

Read more ...

+
+
+ +
+

+ Single Actor, Physics, Scrollbars. +

+
    +
  • + + + 02 August 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Soham Biswas + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hello and welcome to my 10th weekly check-in. Second evaluation ended this week and now we move on to our 3rd and final coding period. In today’s check-in I will be sharing my progress with the single actor physics simulation that I facing some issues with and I will also be discussing my future plans regarding UI components. The official repository of my sub-org, FURY can always be found here.

+

+ +

Read more ...

+
+
+ +
+

+ More Shaders!! +

+
    +
  • + + + 02 August 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Lenix Lobo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Make sure to check out Project FURY

+

+ +

Read more ...

+
+
+ +
+

+ Merging SDF primitives. +

+
    +
  • + + + 27 July 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Lenix Lobo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Make sure to check out Project FURY

+

+ +

Read more ...

+
+
+ +
+

+ Tab UI, TabPanel2D, Tab UI Tutorial. +

+
    +
  • + + + 26 July 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Soham Biswas + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hello and welcome to my 9th weekly check-in. I will be sharing my progress with TabUI and its corresponding tutorial. The official repository of my sub-org, FURY can always be found here.

+

+ +

Read more ...

+
+
+ +
+

+ Improvements in SDF primitives. +

+
    +
  • + + + 20 July 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Lenix Lobo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Make sure to check out Project FURY

+

+ +

Read more ...

+
+
+ +
+

+ ComboBox2D, TextBlock2D, Clipping Overflow. +

+
    +
  • + + + 19 July 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Soham Biswas + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hello and welcome to my 8th weekly check-in. I will be sharing my progress with ComboBox2D and TextBlock2D UI components. After solving TextBlock2D sizing issue, I was finally able to complete the implementation of combo box. I also faced some problems while refactoring TextBlock2D. The official repository of my sub-org, FURY can always be found here.

+

+ +

Read more ...

+
+
+ +
+

+ Multiple SDF primitives. +

+
    +
  • + + + 13 July 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Lenix Lobo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Make sure to check out Project FURY

+

+ +

Read more ...

+
+
+ +
+

+ Orientation, Sizing, Tab UI. +

+
    +
  • + + + 12 July 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Soham Biswas + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hello and welcome to my 7th weekly check-in. I will be sharing my progress with single actor physics simulation and TextBlock2D sizing issue which was pending for quite a while now. I will also be sharing my thoughts regarding the TAB UI component. The official repository of my sub-org, FURY can always be found here.

+

+ +

Read more ...

+
+
+ +
+

+ Translation, Reposition, Rotation. +

+
    +
  • + + + 05 July 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Soham Biswas + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hello and welcome to my 6th weekly check-in. The first evaluation period officially ends and I am very excited to move on to the second coding period. I will be sharing my progress with handling specific object’s properties among various multiple objects rendered by a single actor. I am mainly focusing on making it easier to translate, rotate and reposition a particular object, so that I can use them to render physics simulations more efficiently. The official repository of my sub-org, FURY can always be found here.

+

+ +

Read more ...

+
+
+ +
+

+ Spherical harmonics, Continued. +

+
    +
  • + + + 05 July 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Lenix Lobo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Make sure to check out Project FURY

+

+ +

Read more ...

+
+
+ +
+

+ Spherical harmonics +

+
    +
  • + + + 28 June 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Lenix Lobo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Make sure to check out Project FURY

+

+ +

Read more ...

+
+
+ +
+

+ May the Force be with you!! +

+
    +
  • + + + 28 June 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Soham Biswas + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hello and welcome to my 5th weekly check-in, I will be sharing my progress of pyBullet Physics Engine Integration with FURY. The official repository of my sub-org, FURY can always be found here.

+

+ +

Read more ...

+
+
+ +
+

+ TextBlock2D Progress!! +

+
    +
  • + + + 21 June 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Soham Biswas + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hello and welcome to my 4th weekly check-in, I will be sharing my progress with TextBlock2D UI component. The official repository of my sub-org, FURY can always be found here.

+

+ +

Read more ...

+
+
+ +
+

+ Raymarching continued +

+
    +
  • + + + 21 June 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Lenix Lobo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Make sure to check out Project FURY

+

+ +

Read more ...

+
+
+ +
+

+ Raymarching!! +

+
    +
  • + + + 14 June 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Lenix Lobo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Make sure to check out Project FURY

+

+ +

Read more ...

+
+
+ +
+

+ ComboBox2D Progress!! +

+
    +
  • + + + 14 June 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Soham Biswas + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hello and welcome to my third weekly check-in, I will be sharing my progress with the project so far. In case you wondered, the sub-org that I am affiliated to is FURY. Make sure to check out the official repository here.

+

+ +

Read more ...

+
+
+ +
+

+ First week of coding!! +

+
    +
  • + + + 07 June 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Lenix Lobo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hey everyone! +This week : Geometry Shaders!

+

+ +

Read more ...

+
+
+ +
+

+ First week of coding!! +

+
    +
  • + + + 07 June 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Soham Biswas + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hello and welcome to my second weekly check-in, I will be sharing my progress for the first week of coding.

+

+ +

Read more ...

+
+
+ +
+

+ Welcome to my GSoC Blog!!! +

+
    +
  • + + + 30 May 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Soham Biswas + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hello Everyone, this is Soham Biswas currently in 2nd year pursuing my Bachelor’s(B.Tech) degree in Computer Science & Engineering from Institute of Engineering & Management, Kolkata. I have been selected for GSoC’ 20 at sub-org FURY under the umbrella organization of Python Software Foundation. I will be working on building sci-fi-like 2D and 3D interfaces and provide physics engine integration under project titled “Create new UI widgets & Physics Engine Integration”.

+

+ +

Read more ...

+
+
+ +
+

+ Weekly Check-in #1 +

+
    +
  • + + + 30 May 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Lenix Lobo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hey everyone! +This is my blog for this summer’s GSoC @ PSF +I am Lenix Lobo, an undergraduate student from India, and this summer I will be working with project Fury under the umbrella of the Python Software foundation. I will be working on improving the current shader framework.

+

+ +

Read more ...

+
+
+ +
+

+ Google Summer of Code +

+
    +
  • + + + 05 January 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Serge Koudoro + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

FURY is participating in the Google Summer of Code 2020 under the umbrella of the Python Software Foundation.

+

+ +

Read more ...

+
+
+ + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/blog/category/gsoc/atom.xml b/v0.10.x/blog/category/gsoc/atom.xml new file mode 100644 index 000000000..33a56620d --- /dev/null +++ b/v0.10.x/blog/category/gsoc/atom.xml @@ -0,0 +1,1229 @@ + + + https://fury.gl/ + Blog - Posts in gsoc + 2024-02-29T15:43:57.597871+00:00 + + + ABlog + + https://fury.gl/posts/2023/2023-08-25-final-report-praneeth.html + Google Summer of Code Final Work Product + 2023-08-25T00:00:00-04:00 + + Praneeth Shetty + + <a class="reference external image-reference" href="https://summerofcode.withgoogle.com/programs/2023/projects/BqfBWfwS"><img alt="https://developers.google.com/open-source/gsoc/resources/downloads/GSoC-logo-horizontal.svg" class="align-center" height="50" src="https://developers.google.com/open-source/gsoc/resources/downloads/GSoC-logo-horizontal.svg" /></a> +<a class="reference external image-reference" href="https://summerofcode.withgoogle.com/programs/2023/organizations/python-software-foundation"><img alt="https://www.python.org/static/community_logos/python-logo.png" src="https://www.python.org/static/community_logos/python-logo.png" style="width: 40%;" /></a> +<a class="reference external image-reference" href="https://fury.gl/latest/index.html"><img alt="https://python-gsoc.org/logos/FURY.png" src="https://python-gsoc.org/logos/FURY.png" style="width: 25%;" /></a> +<section id="google-summer-of-code-final-work-product"> + +<ul class="simple"> +<li><p><strong>Name:</strong> Praneeth Shetty</p></li> +<li><p><strong>Organisation:</strong> Python Software Foundation</p></li> +<li><p><strong>Sub-Organisation:</strong> FURY</p></li> +<li><p><strong>Project:</strong> <a class="reference external" href="https://github.com/fury-gl/fury/wiki/Google-Summer-of-Code-2023-(GSOC2023)#project-5-update-user-interface-widget--explore-new-ui-framework">FURY - Update user interface widget + Explore new UI Framework</a></p></li> +</ul> +<section id="proposed-objectives"> +<h2>Proposed Objectives</h2> +<ul class="simple"> +<li><p>SpinBoxUI</p></li> +<li><p>Scrollbar as Independent Element</p></li> +<li><p>FileDialog</p></li> +<li><p>TreeUI</p></li> +<li><p>AccordionUI</p></li> +<li><p>ColorPickerUI</p></li> +<li><dl class="simple"> +<dt>Stretch Goals:</dt><dd><ul> +<li><p>Exploring new UI Framework</p></li> +<li><p>Implementing Borders for UI elements</p></li> +</ul> +</dd> +</dl> +</li> +</ul> +</section> +<section id="objectives-completed"> +<h2>Objectives Completed</h2> +<ul> +<li><dl> +<dt><strong>SpinBoxUI:</strong></dt><dd><p>The <code class="docutils literal notranslate"><span class="pre">SpinBoxUI</span></code> element is essential for user interfaces as it allows users to pick a numeric value from a set range. While we had an active pull request (PR) to add this element, updates in the main code caused conflicts and required further changes for added features. At one point, we noticed that text alignment wasn’t centered properly within the box due to a flaw. To fix this, we began a PR to adjust the alignment, but it turned into a larger refactoring of the <code class="docutils literal notranslate"><span class="pre">TextBlock2D</span></code>, a core component connected to various parts. This was a complex task that needed careful handling. After sorting out the <code class="docutils literal notranslate"><span class="pre">TextBlock2D</span></code>, we returned to the <code class="docutils literal notranslate"><span class="pre">SpinBoxUI</span></code> and made a few tweaks. Once we were confident with the changes, the PR was successfully merged after thorough review and testing.</p> +<p><strong>Pull Requests:</strong></p> +</dd> +</dl> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 50)</p> +<p>Definition list ends without a blank line; unexpected unindent.</p> +</aside> +<ul> +<li><p><strong>SpinBoxUI (Merged)</strong> - <a class="github reference external" href="https://github.com/fury-gl/fury/pull/499">fury-gl/fury#499</a></p> +<blockquote> +<div><img alt="SpinBoxUI" class="align-center" src="https://user-images.githubusercontent.com/64432063/263165327-c0b19cdc-9ebd-433a-8ff1-99e706a76508.gif" style="height: 500px;" /> +</div></blockquote> +</li> +</ul> +</li> +<li><dl> +<dt><strong>`TextBlock2D` Refactoring:</strong></dt><dd><p>This was a significant aspect of the GSoC period and occupied a substantial portion of the timeline. The process began when we observed misaligned text in the <code class="docutils literal notranslate"><span class="pre">SpinBoxUI</span></code>, as previously discussed. The root cause of the alignment issue was the mispositioning of the text actor concerning the background actor. The text actor’s independent repositioning based on justification conflicted with the static position of the background actor, leading to the alignment problem.</p> +<p>To address this, the initial focus was on resolving the justification issue. However, as the work progressed, we recognized that solely adjusting justification would not suffice. The alignment was inherently linked to the UI’s size, which was currently retrieved only when a valid scene was present. This approach lacked scalability and efficiency, as it constrained size retrieval to scene availability.</p> +<p>To overcome these challenges, we devised a solution involving the creation of a bounding box around the <code class="docutils literal notranslate"><span class="pre">TextBlock2D</span></code>. This bounding box would encapsulate the size information, enabling proper text alignment. This endeavor spanned several weeks of development, culminating in a finalized solution that underwent rigorous testing before being merged.</p> +<p>As a result of this refactoring effort, the <code class="docutils literal notranslate"><span class="pre">TextBlock2D</span></code> now offers three distinct modes:</p> +<ol class="arabic simple"> +<li><p><strong>Fully Static Background:</strong> This mode requires background setup during initialization.</p></li> +<li><p><strong>Dynamic Background:</strong> The background dynamically scales based on the text content.</p></li> +<li><p><strong>Auto Font Scale Mode:</strong> The font within the background box automatically scales to fill the available space.</p></li> +</ol> +<p>An issue has been identified with <code class="docutils literal notranslate"><span class="pre">TextBlock2D</span></code> where its text actor aligns with the top boundary of the background actor, especially noticeable with letters like “g,” “y,” and “j”. These letters extend beyond the baseline of standard alphabets, causing the text box to shift upwards.</p> +<p>However, resolving this matter is complex. Adjusting the text’s position might lead to it touching the bottom boundary, especially in font scale mode, resulting in unexpected positioning and transformations. To address this, the plan is to defer discussions about this matter until after GSoC, allowing for thorough consideration and solutions.</p> +<p>For more detailed insights into the individual steps and nuances of this process, you can refer to the comprehensive weekly blog post provided below. It delves into the entire journey of this <code class="docutils literal notranslate"><span class="pre">TextBlock2D</span></code> refactoring effort.</p> +<p><strong>Pull Requests:</strong></p> +</dd> +</dl> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 79)</p> +<p>Definition list ends without a blank line; unexpected unindent.</p> +</aside> +<ul> +<li><p><strong>Fixing Justification Issue - 1st Draft (Closed)</strong> - <a class="github reference external" href="https://github.com/fury-gl/fury/pull/790">fury-gl/fury#790</a></p></li> +<li><p><strong>Adding BoundingBox and fixing Justificaiton (Merged)</strong> - <a class="github reference external" href="https://github.com/fury-gl/fury/pull/803">fury-gl/fury#803</a></p></li> +<li><p><strong>Adding getters and setter for properties (Merged)</strong> - <a class="github reference external" href="https://github.com/fury-gl/fury/pull/830">fury-gl/fury#830</a></p></li> +<li><p><strong>Text Offset PR (Closed)</strong> - <a class="github reference external" href="https://github.com/fury-gl/fury/pull/837">fury-gl/fury#837</a></p> +<img alt="TextBlock2D Feature Demo" class="align-center" src="https://user-images.githubusercontent.com/64432063/258603191-d540105a-0612-450e-8ae3-ca8aa87916e6.gif" style="height: 500px;" /> +<img alt="TextBlock2D All Justification" class="align-center" src="https://github-production-user-asset-6210df.s3.amazonaws.com/64432063/254652569-94212105-7259-48da-8fdc-41ee987bda84.png" style="height: 500px;" /> +</li> +</ul> +</li> +<li><dl> +<dt><strong>ScrollbarUI as Independent Element:</strong></dt><dd><p>We initially planned to make the scrollbar independent based on PR <a class="reference external" href="https://github.com/fury-gl/fury/pull/16">#16</a>. The main goal was to avoid redundancy by not rewriting the scrollbar code for each element that requires it, such as the <code class="docutils literal notranslate"><span class="pre">FileMenu2D</span></code>. However, upon further analysis, we realized that elements like the <code class="docutils literal notranslate"><span class="pre">FileMenu2D</span></code> and others utilize the <code class="docutils literal notranslate"><span class="pre">Listbox2D</span></code>, which already includes an integrated scrollbar. We also examined other UI libraries and found that they also have independent scrollbars but lack a proper use case. Typically, display containers like <code class="docutils literal notranslate"><span class="pre">Listbox2D</span></code> are directly used instead of utilizing an independent scrollbar.</p> +<p>Based on these findings, we have decided to close all related issues and pull requests for now. If the need arises in the future, we can revisit this topic.</p> +<p><strong>Topic:</strong> - <a class="github reference external" href="https://github.com/fury-gl/fury/discussions/816">fury-gl/fury#816</a></p> +</dd> +</dl> +</li> +</ul> +</section> +<section id="other-objectives"> +<h2>Other Objectives</h2> +<ul> +<li><dl> +<dt><strong>Reviewing &amp; Merging:</strong></dt><dd><p>In this phase, my focus was not on specific coding but rather on facilitating the completion of ongoing PRs. Here are two instances where I played a role:</p> +<ol class="arabic simple"> +<li><p><strong>CardUI PR:</strong> +I assisted with the <code class="docutils literal notranslate"><span class="pre">CardUI</span></code> PR by aiding in the rebase process and reviewing the changes. The CardUI is a simple UI element consisting of an image and a description, designed to function like a flash card. I worked closely with my mentor to ensure a smooth rebase and review process.</p></li> +<li><p><strong>ComboBox Issue:</strong> +There was an issue with the <code class="docutils literal notranslate"><span class="pre">ComboBox2D</span></code> functionality, where adding it to a <code class="docutils literal notranslate"><span class="pre">TabUI</span></code> caused all elements to open simultaneously, which shouldn’t be the case. I tested various PRs addressing this problem and identified a suitable solution. I then helped the lead in reviewing the PR that fixed the issue, which was successfully merged.</p></li> +</ol> +<p><strong>Pull Requests:</strong></p> +</dd> +</dl> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 116)</p> +<p>Definition list ends without a blank line; unexpected unindent.</p> +</aside> +<ul> +<li><p><strong>CardUI (Merged)</strong> - <a class="github reference external" href="https://github.com/fury-gl/fury/pull/398">fury-gl/fury#398</a></p></li> +<li><p><strong>ComboBox Flaw (Merged)</strong> - <a class="github reference external" href="https://github.com/fury-gl/fury/pull/768">fury-gl/fury#768</a></p> +<img alt="CardUI" class="align-center" src="https://user-images.githubusercontent.com/54466356/112532305-b090ef80-8dce-11eb-90a0-8d06eed55993.png" style="height: 500px;" /> +</li> +</ul> +</li> +<li><dl> +<dt><strong>Updating Broken Website Links:</strong></dt><dd><p>I addressed an issue with malfunctioning links in the Scientific Section of the website. The problem emerged from alterations introduced in PR <a class="reference external" href="https://github.com/fury-gl/fury/pull/769">#769</a>. These changes consolidated demos and examples into a unified “auto_examples” folder, and a toml file was utilized to retrieve this data and construct examples. However, this led to challenges with the paths employed in website generation. My responsibility was to rectify these links, ensuring they accurately direct users to the intended content.</p> +<p><strong>Pull Requests:</strong></p> +</dd> +</dl> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 130)</p> +<p>Definition list ends without a blank line; unexpected unindent.</p> +</aside> +<ul class="simple"> +<li><p><strong>Updating Broken Links (Merged)</strong> - <a class="github reference external" href="https://github.com/fury-gl/fury/pull/820">fury-gl/fury#820</a></p></li> +</ul> +</li> +</ul> +</section> +<section id="objectives-in-progress"> +<h2>Objectives in Progress</h2> +<ul> +<li><dl> +<dt><strong>FileDialogUI:</strong></dt><dd><p>An existing <code class="docutils literal notranslate"><span class="pre">FileDialog</span></code> PR by Soham (<a class="reference external" href="https://github.com/fury-gl/fury/pull/294">#294</a>) was worked upon. The primary task was to rebase the PR to match the current UI structure, resolving compatibility concerns with the older base. In PR <a class="reference external" href="https://github.com/fury-gl/fury/pull/832">#832</a>, we detailed issues encompassing resizing <code class="docutils literal notranslate"><span class="pre">FileDialog</span></code> and components, addressing text overflow, fixing <code class="docutils literal notranslate"><span class="pre">ZeroDivisionError</span></code>, and correcting <code class="docutils literal notranslate"><span class="pre">ListBox2D</span></code> item positioning. The PR is complete with comprehensive testing and documentation. Presently, it’s undergoing review, and upon approval, it will be prepared for integration.</p> +<p><strong>Pull Requests:</strong></p> +</dd> +</dl> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 140)</p> +<p>Definition list ends without a blank line; unexpected unindent.</p> +</aside> +<ul> +<li><p><strong>Soham’s FileDialog (Closed)</strong> - <a class="github reference external" href="https://github.com/fury-gl/fury/pull/294">fury-gl/fury#294</a></p></li> +<li><p><strong>FileDialogUI (Under Review)</strong> - <a class="github reference external" href="https://github.com/fury-gl/fury/pull/832">fury-gl/fury#832</a></p> +<img alt="FileDialogUI" class="align-center" src="https://user-images.githubusercontent.com/64432063/263189092-6b0891d5-f0ef-4185-8b17-c7104f1a7d60.gif" style="height: 500px;" /> +</li> +</ul> +</li> +<li><dl> +<dt><strong>TreeUI:</strong></dt><dd><p>Continuing Antriksh’s initial PR for <code class="docutils literal notranslate"><span class="pre">TreeUI</span></code> posed some challenges. Antriksh had set the foundation, and I picked up from there. The main issue was with the visibility of TreeUI due to updates in the <code class="docutils literal notranslate"><span class="pre">set_visibility</span></code> method of <code class="docutils literal notranslate"><span class="pre">Panel2D</span></code>. These updates affected how <code class="docutils literal notranslate"><span class="pre">TreeUI</span></code> was displayed, and after investigating the actors involved, it was clear that the visibility features had changed. This took some time to figure out, and I had a helpful pair programming session with my mentor, Serge, to narrow down the problem. Now, I’ve updated the code to address this issue. However, I’m still a bit cautious about potential future problems. The PR is now ready for review.</p> +<p><strong>Pull Requests:</strong></p> +</dd> +</dl> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 154)</p> +<p>Definition list ends without a blank line; unexpected unindent.</p> +</aside> +<ul> +<li><p><strong>TreeUI (In Progress)</strong> - <a class="github reference external" href="https://github.com/fury-gl/fury/pull/821">fury-gl/fury#821</a></p> +<img alt="TreeUI" class="align-center" src="https://user-images.githubusercontent.com/64432063/263237308-70e77ba0-1ce8-449e-a79c-d5e0fbb58b45.gif" style="height: 500px;" /> +</li> +</ul> +</li> +</ul> +</section> +<section id="gsoc-weekly-blogs"> +<h2>GSoC Weekly Blogs</h2> +<ul class="simple"> +<li><p>My blog posts can be found at <a class="reference external" href="https://fury.gl/latest/blog/author/praneeth-shetty.html">FURY website</a> +and <a class="reference external" href="https://blogs.python-gsoc.org/en/ganimtron_10s-blog-copy-2/">Python GSoC blog</a>.</p></li> +</ul> +</section> +<section id="timeline"> +<h2>Timeline</h2> +<table class="table"> +<colgroup> +<col style="width: 40.0%" /> +<col style="width: 40.0%" /> +<col style="width: 20.0%" /> +</colgroup> +<thead> +<tr class="row-odd"><th class="head"><p>Date</p></th> +<th class="head"><p>Description</p></th> +<th class="head"><p>Blog Post Link</p></th> +</tr> +</thead> +<tbody> +<tr class="row-even"><td><p>Week 0 (27-05-2023)</p></td> +<td><p>Community Bounding Period</p></td> +<td><p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-06-02-week-0-praneeth.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/ganimtron_10s-blog-copy-2/gsoc-2023-community-bonding-period/">Python</a></p></td> +</tr> +<tr class="row-odd"><td><p>Week 1 (03-06-2023)</p></td> +<td><p>Working with SpinBox and TextBox Enhancements</p></td> +<td><aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id5">backlink</a></em></p> +<p>Duplicate explicit target name: “fury”.</p> +</aside> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id6">backlink</a></em></p> +<p>Duplicate explicit target name: “python”.</p> +</aside> +<p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-06-03-week-1-praneeth.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/ganimtron_10s-blog-copy-2/week-1-working-with-spinbox-and-textbox-enhancements/">Python</a></p> +</td> +</tr> +<tr class="row-even"><td><p>Week 2 (10-06-2023)</p></td> +<td><p>Tackling Text Justification and Icon Flaw Issues</p></td> +<td><aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id7">backlink</a></em></p> +<p>Duplicate explicit target name: “fury”.</p> +</aside> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id8">backlink</a></em></p> +<p>Duplicate explicit target name: “python”.</p> +</aside> +<p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-06-11-week-2-praneeth.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/ganimtron_10s-blog-copy-2/week-2-tackling-text-justification-and-icon-flaw-issues/">Python</a></p> +</td> +</tr> +<tr class="row-odd"><td><p>Week 3 (17-06-2023)</p></td> +<td><p>Resolving Combobox Icon Flaw and TextBox Justification</p></td> +<td><aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id9">backlink</a></em></p> +<p>Duplicate explicit target name: “fury”.</p> +</aside> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id10">backlink</a></em></p> +<p>Duplicate explicit target name: “python”.</p> +</aside> +<p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-06-17-week-3-praneeth.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/ganimtron_10s-blog-copy-2/week-3-resolving-combobox-icon-flaw-and-textbox-justification/">Python</a></p> +</td> +</tr> +<tr class="row-even"><td><p>Week 4 (24-06-2023)</p></td> +<td><p>Exam Preparations and Reviewing</p></td> +<td><aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id11">backlink</a></em></p> +<p>Duplicate explicit target name: “fury”.</p> +</aside> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id12">backlink</a></em></p> +<p>Duplicate explicit target name: “python”.</p> +</aside> +<p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-06-24-week-4-praneeth.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/ganimtron_10s-blog-copy-2/week-4-exam-preparations-and-reviewing/">Python</a></p> +</td> +</tr> +<tr class="row-odd"><td><p>Week 5 (01-07-2023)</p></td> +<td><p>Trying out PRs and Planning Ahead</p></td> +<td><aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id13">backlink</a></em></p> +<p>Duplicate explicit target name: “fury”.</p> +</aside> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id14">backlink</a></em></p> +<p>Duplicate explicit target name: “python”.</p> +</aside> +<p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-07-01-week-5-praneeth.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/ganimtron_10s-blog-copy-2/week-5-testing-out-prs-and-planning-ahead/">Python</a></p> +</td> +</tr> +<tr class="row-even"><td><p>Week 6 (08-07-2023)</p></td> +<td><p>BoundingBox for TextBlock2D!</p></td> +<td><aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id15">backlink</a></em></p> +<p>Duplicate explicit target name: “fury”.</p> +</aside> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id16">backlink</a></em></p> +<p>Duplicate explicit target name: “python”.</p> +</aside> +<p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-07-08-week-6-praneeth.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/ganimtron_10s-blog-copy-2/week-6-boundingbox-for-textblock2d/">Python</a></p> +</td> +</tr> +<tr class="row-odd"><td><p>Week 7 (15-07-2023)</p></td> +<td><p>Sowing the seeds for TreeUI</p></td> +<td><aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id17">backlink</a></em></p> +<p>Duplicate explicit target name: “fury”.</p> +</aside> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id18">backlink</a></em></p> +<p>Duplicate explicit target name: “python”.</p> +</aside> +<p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-07-15-week-7-praneeth.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/ganimtron_10s-blog-copy-2/week-7-sowing-the-seeds-for-treeui/">Python</a></p> +</td> +</tr> +<tr class="row-even"><td><p>Week 8 (22-07-2023)</p></td> +<td><p>Another week with TextBlockUI</p></td> +<td><aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id19">backlink</a></em></p> +<p>Duplicate explicit target name: “fury”.</p> +</aside> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id20">backlink</a></em></p> +<p>Duplicate explicit target name: “python”.</p> +</aside> +<p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-07-22-week-8-praneeth.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/ganimtron_10s-blog-copy-2/week-8-another-week-with-textblockui/">Python</a></p> +</td> +</tr> +<tr class="row-odd"><td><p>Week 9 (29-07-2023)</p></td> +<td><p>TextBlock2D is Finally Merged!</p></td> +<td><aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id21">backlink</a></em></p> +<p>Duplicate explicit target name: “fury”.</p> +</aside> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id22">backlink</a></em></p> +<p>Duplicate explicit target name: “python”.</p> +</aside> +<p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-07-29-week-9-praneeth.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/ganimtron_10s-blog-copy-2/week-9-textblock2d-is-finally-merged/">Python</a></p> +</td> +</tr> +<tr class="row-even"><td><p>Week 10 (05-08-2023)</p></td> +<td><p>Its time for a Spin-Box!</p></td> +<td><aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id23">backlink</a></em></p> +<p>Duplicate explicit target name: “fury”.</p> +</aside> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id24">backlink</a></em></p> +<p>Duplicate explicit target name: “python”.</p> +</aside> +<p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-08-05-week-10-praneeth.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/ganimtron_10s-blog-copy-2/week-10-its-time-for-a-spin-box/">Python</a></p> +</td> +</tr> +<tr class="row-odd"><td><p>Week 11 (12-08-2023)</p></td> +<td><p>Bye Bye SpinBox</p></td> +<td><aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id25">backlink</a></em></p> +<p>Duplicate explicit target name: “fury”.</p> +</aside> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id26">backlink</a></em></p> +<p>Duplicate explicit target name: “python”.</p> +</aside> +<p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-08-12-week-11-praneeth.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/ganimtron_10s-blog-copy-2/week-11-bye-bye-spinbox/">Python</a></p> +</td> +</tr> +<tr class="row-even"><td><p>Week 12 (19-08-2023)</p></td> +<td><p>FileDialog Quest Begins!</p></td> +<td><aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id27">backlink</a></em></p> +<p>Duplicate explicit target name: “fury”.</p> +</aside> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id28">backlink</a></em></p> +<p>Duplicate explicit target name: “python”.</p> +</aside> +<p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-08-19-week-12-praneeth.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/ganimtron_10s-blog-copy-2/week-12-filedialog-quest-begins/">Python</a></p> +</td> +</tr> +</tbody> +</table> +</section> +</section> + + + Name: Praneeth Shetty + + 2023-08-25T00:00:00-04:00 + + + https://fury.gl/posts/2023/2023-08-24-week-12-tvcastillod.html + Week 12 : Experimenting with ODFs implementation + 2023-08-24T00:00:00-04:00 + + Tania Castillo + + <section id="week-12-experimenting-with-odfs-implementation"> + +<section id="what-did-i-do-this-week"> +<h2>What did I do this week?</h2> +<p>There were different issues I needed to address for the ODF implementation. Even though I could not solve any of them completely, I did check each of the issues and made some progress. All the work in progress is being recorded in the following branch <a class="reference external" href="https://github.com/tvcastillod/fury/tree/SH-for-ODF-impl">SH-for-ODF-impl</a>, which when ready will be associated with a well-structured PR.</p> +<p>First, about the scaling, I was suggested to check Generalized Fractional Anisotropy <strong>gfa</strong> metric to adjust the scaling depending on the shape of the ODF glyph, i.e., the less the <strong>gfa</strong> the more sphere-shaped and smaller, so I had to associate a greater scaling for those. However, this did not work very well as I was unable to define an appropriate scale relation that would give an equitable result for each glyph. For this reason, I opted to use peak values which are extracted from the ODFs, setting the scales as 1/peak_value*0.4 and I got a more uniformly sized glyph without the need of setting it manually. That is a temporal solution as I would like to see better why this happens and if possible do the adjustment inside the shader instead of a precalculation.</p> +<p>Second, for the direction, I made a small adjustment to the spherical coordinates which affected the direction of the ODF glyph. As you can see below,</p> +<img alt="https://user-images.githubusercontent.com/31288525/263122770-b9ee19d2-d82b-4d7f-a5bb-1cbbf5907049.png" class="align-center" src="https://user-images.githubusercontent.com/31288525/263122770-b9ee19d2-d82b-4d7f-a5bb-1cbbf5907049.png" style="width: 400px;" /> +<p>All the glyphs are aligned over the y-axis but not over the z-axis, to correct this I precalculated the main direction of each glyph using peaks and passed it to the shader as a <em>vec3</em>, then used <em>vec2vecrotmat</em> to align the main axis vector of the ODF to the required direction vector, the only problem with this is that not all the glyps are equally aligned to the axis, i.e., the first 3 glyphs are aligned with the x-axis but the last one is aligned with the y-axis, so the final rotation gives a different result for that one.</p> +<img alt="https://user-images.githubusercontent.com/31288525/263122752-b2aa696f-62a5-4b09-b8dd-0cb1ec49431c.png" class="align-center" src="https://user-images.githubusercontent.com/31288525/263122752-b2aa696f-62a5-4b09-b8dd-0cb1ec49431c.png" style="width: 400px;" /> +<p>As with the first small adjustment of the coordinates the direction was partially correct, I need to double check the theta, phi and r definitions to see if I can get the right direction without the need of the additional data of direction. Also, there might be a way to get the specific rotation angles associated to each individual glyph from the data associated with the ODFs.</p> +<p>Third, about passing the coefficients data through textures, I understand better now how to pass textures to the shaders but I still have problems understanding how to retrieve the data inside the shader. I used <a class="reference external" href="https://github.com/fury-gl/fury/blob/master/docs/experimental/viz_shader_texture.py">this base implementation</a>, suggested by one of my mentors, to store the data as a <a class="reference external" href="http://www.khronos.org/opengl/wiki/Cubemap_Texture#:~:text=A%20Cubemap%20Texture%20is%20a,the%20value%20to%20be%20accessed.">texture cubemap</a>, “a texture, where each mipmap level consists of six 2D images which must be square. The 6 images represent the faces of a cube”. I had 4x15 coefficients and inside the function, a grid of RGB colors is made so then it can be mapped as a texture. To check if was passing the data correctly, I used the same value, .5, for all the textures, so then I could pick a random texel get a specific color (gray), and pass it as <em>fragOutput0</em> to see if the value was correct. However, it didn’t appear to work correctly as I couldn’t get the expected color. To get the specific color I used <a class="reference external" href="https://registry.khronos.org/OpenGL-Refpages/gl4/html/texture.xhtml">texture(sampler, P)</a> which samples texels from the texture bound to sampler at texture coordinate P. Now, what I still need to figure out is which should be the corresponding texture coordinate. I have tried with random coordinates, as they are supposed to correspond to a point on the cube and since the information I have encoded in the texture is all the same, I assumed that I would get the expected result for any set of values. It might be a problem with the data normalization, or maybe there is something failing on the texture definition, but I need to review it in more detail to see where is the problem.</p> +<p>Lastly, about the colormapping, I created the texture based on a generic colormap from <a class="reference external" href="https://matplotlib.org/stable/tutorials/colors/colormaps.html">matplotlib</a>. I was able to give some color to the glyph but it does not match correctly its shape. Some adjustment must be done regarding the texels, as the colormap is mapped on a cube, but I need it to fit the shape of the glyph correctly.</p> +<img alt="https://user-images.githubusercontent.com/31288525/263122760-7d1fff5e-7787-473c-8053-ea69f3009fb4.png" class="align-center" src="https://user-images.githubusercontent.com/31288525/263122760-7d1fff5e-7787-473c-8053-ea69f3009fb4.png" style="width: 250px;" /> +</section> +<section id="what-is-coming-up-next"> +<h2>What is coming up next?</h2> +<p>I will continue to explore more on how to handle textures so I can solve the issues related to the coefficient data and colormapping. Also, take a deeper look at the SH implementation and check what is the information needed to adjust the main direction of the ODF correctly.</p> +</section> +<section id="did-i-get-stuck-anywhere"> +<h2>Did I get stuck anywhere?</h2> +<p>As I mentioned I had some drawbacks in understanding the use of textures and how to retrieve the data inside the shaders. This is a topic that might take some time to manage properly but if I can master it and understand it better, it is a tool that can be useful later. Additionally, there are details of the SH implementation that I still need to understand and explore better in order to make sure I get exactly the same result as the current <em>odf_slicer</em> implementation.</p> +</section> +</section> + + + There were different issues I needed to address for the ODF implementation. Even though I could not solve any of them completely, I did check each of the issues and made some progress. All the work in progress is being recorded in the following branch SH-for-ODF-impl, which when ready will be associated with a well-structured PR. + + 2023-08-24T00:00:00-04:00 + + + https://fury.gl/posts/2023/2023-08-24-final-report-tvcastillod.html + Google Summer of Code Final Work Product + 2023-08-24T00:00:00-04:00 + + Tania Castillo + + <a class="reference external image-reference" href="https://summerofcode.withgoogle.com/programs/2023/projects/ymwnLwtT"><img alt="https://developers.google.com/open-source/gsoc/resources/downloads/GSoC-logo-horizontal.svg" class="align-center" height="50" src="https://developers.google.com/open-source/gsoc/resources/downloads/GSoC-logo-horizontal.svg" /></a> +<a class="reference external image-reference" href="https://summerofcode.withgoogle.com/programs/2023/organizations/python-software-foundation"><img alt="https://www.python.org/static/community_logos/python-logo.png" src="https://www.python.org/static/community_logos/python-logo.png" style="width: 40%;" /></a> +<a class="reference external image-reference" href="https://fury.gl/latest/index.html"><img alt="https://python-gsoc.org/logos/FURY.png" src="https://python-gsoc.org/logos/FURY.png" style="width: 25%;" /></a> +<section id="google-summer-of-code-final-work-product"> + +<ul class="simple"> +<li><p><strong>Name:</strong> Tania Castillo</p></li> +<li><p><strong>Organisation:</strong> Python Software Foundation</p></li> +<li><p><strong>Sub-Organisation:</strong> FURY</p></li> +<li><p><strong>Project:</strong> <a class="reference external" href="https://github.com/fury-gl/fury/wiki/Google-Summer-of-Code-2023-(GSOC2023)#project-3-sdf-based-uncertainty-representation-for-dmri-glyphs">SDF-based uncertainty representation for dMRI glyphs</a></p></li> +</ul> +<section id="abstract"> +<h2>Abstract</h2> +<p>Diffusion Magnetic Resonance Imaging (dMRI) is a non-invasive imaging technique used by neuroscientists to measure the diffusion of water molecules in biological tissue. The directional information is reconstructed using either a Diffusion Tensor Imaging (DTI) or High Angular Resolution Diffusion Imaging (HARDI) based model, which is graphically represented as tensors and Orientation Distribution Functions (ODF). Traditional rendering engines discretize Tensor and ODF surfaces using triangles or quadrilateral polygons, making their visual quality depending on the number of polygons used to build the 3D mesh, which might compromise real-time display performance. This project proposes a methodological approach to further improve the visualization of DTI tensors and HARDI ODFs glyphs by using well-established techniques in the field of computer graphics, such as geometry amplification, billboarding, signed distance functions (SDFs), and ray marching.</p> +</section> +<section id="proposed-objectives"> +<h2>Proposed Objectives</h2> +<ul class="simple"> +<li><p>Implement a parallelized version of computer-generated billboards using geometry shaders for amplification.</p></li> +<li><p>Model the mathematical functions that express the geometry of ellipsoid glyphs and implement them using Ray Marching techniques.</p></li> +<li><p>Model the mathematical functions that express the geometry of ODF glyphs and implement them using Ray Marching techniques.</p></li> +<li><p>Use SDF properties and techniques to represent the uncertainty of dMRI reconstruction models.</p></li> +</ul> +</section> +<section id="objectives-completed"> +<h2>Objectives Completed</h2> +<section id="ellipsoid-actor-implemented-with-sdf"> +<h3>Ellipsoid actor implemented with SDF</h3> +<p>A first approach for tensor glyph generation has been made, using ray marching and SDF applied to a box. The current implementation (<code class="docutils literal notranslate"><span class="pre">tensor_slicer</span></code>) requires a sphere with a specific number of vertices to be deformed. Based on this model, a sphere with more vertices is needed to get a higher resolution. Because the ray marching technique does not use polygonal meshes, it is possible to define perfectly smooth surfaces and still obtain a fast rendering.</p> +<p>Details of the implementation:</p> +<ul class="simple"> +<li><p><em>Vertex shader pre-calculations</em>: Some minor calculations are done in the vertex shader. One, corresponding to the eigenvalues constraining and min-max normalization, are to avoid incorrect visualizations when the difference between the eigenvalues is too large. And the other is related to the tensor matrix calculation given by the diffusion tensor definition <span class="math notranslate nohighlight">\(T = R^{−1}\Lambda R\)</span>, where <span class="math notranslate nohighlight">\(R\)</span> is a rotation matrix that transforms the standard basis onto the eigenvector basis, and <span class="math notranslate nohighlight">\(\Lambda\)</span> is the diagonal matrix of eigenvalues <a class="footnote-reference brackets" href="#id10" id="id1" role="doc-noteref"><span class="fn-bracket">[</span>4<span class="fn-bracket">]</span></a>.</p></li> +<li><p><em>Ellipsoid SDF definition</em>: The definition of the SDF is done in the fragment shader inside the <code class="docutils literal notranslate"><span class="pre">map</span></code> function, which is used later for the ray marching algorithm and the normals calculation. We define the SDF more simply by transforming a sphere into an ellipsoid, considering that the SDF of a sphere is easily computed and the definition of a tensor gives us a linear transformation of a given geometry. Also, as scaling is not a rigid body transformation, we multiply the final result by a factor to compensate for the difference, which gave us the SDF of the ellipsoid defined as <code class="docutils literal notranslate"><span class="pre">sdSphere(tensorMatrix</span> <span class="pre">*</span> <span class="pre">(position</span> <span class="pre">-</span> <span class="pre">centerMCVSOutput),</span> <span class="pre">scaleVSOutput*0.48)</span> <span class="pre">*</span> <span class="pre">scFactor</span></code>.</p></li> +<li><p><em>Ray marching algorithm and lighting</em>: For the ray marching algorithm, a small value of 20 was taken as the maximum distance since we apply the technique to each individual object and not all at the same time. Additionally, we set the convergence precision to 0.001. We use the central differences method to compute the normals necessary for the scene’s illumination, besides the Blinn-Phong lighting technique, which is high-quality and computationally cheap.</p></li> +<li><p><em>Visualization example</em>: Below is a detailed visualization of the ellipsoids created from this new implementation.</p></li> +</ul> +<img alt="https://user-images.githubusercontent.com/31288525/244503195-a626718f-4a13-4275-a2b7-6773823e553c.png" class="align-center" src="https://user-images.githubusercontent.com/31288525/244503195-a626718f-4a13-4275-a2b7-6773823e553c.png" style="width: 376px;" /> +<p>This implementation does show a better quality in the displayed glyphs, and supports the display of a large amount of data, as seen in the image below. For this reason, a tutorial was made to justify in more detail the value of this new implementation. Below are some images generated for the tutorial.</p> +<img alt="https://user-images.githubusercontent.com/31288525/260906510-d422e7b4-3ba3-4de6-bfd0-09c04bec8876.png" class="align-center" src="https://user-images.githubusercontent.com/31288525/260906510-d422e7b4-3ba3-4de6-bfd0-09c04bec8876.png" style="width: 600px;" /> +<p><em>Pull Requests:</em></p> +<ul class="simple"> +<li><p><strong>Ellipsoid actor implemented with SDF (Merged)</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/791">fury-gl/fury#791</a></p></li> +<li><p><strong>Tutorial on using ellipsoid actor to visualize tensor ellipsoids for DTI (Merged)</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/818">fury-gl/fury#818</a></p></li> +</ul> +<p><strong>Future work:</strong> In line with one of the initial objectives, it is expected to implement billboards later on to improve the performance, i.e., higher frame rate and less memory usage for the tensor ellipsoid creation. In addition to looking for ways to optimize the naive ray marching algorithm and the definition of SDFs.</p> +</section> +</section> +<section id="objectives-in-progress"> +<h2>Objectives in Progress</h2> +<section id="dti-uncertainty-visualization"> +<h3>DTI uncertainty visualization</h3> +<p>The DTI visualization pipeline is fairly complex, as a level of uncertainty arises, which, if visualized, helps to assess the model’s accuracy. This measure is not currently implemented, and even though there are several methods to calculate and visualize the uncertainty in the DTI model, because of its simplicity and visual representation, we considered Matrix Perturbation Analysis (MPA) proposed by Basser <a class="footnote-reference brackets" href="#id7" id="id2" role="doc-noteref"><span class="fn-bracket">[</span>1<span class="fn-bracket">]</span></a>. This measurement is visualized as double cones representing the variance of the main direction of diffusion, for which the ray marching technique was also used to create these objects.</p> +<p>Details of the implementation:</p> +<ul class="simple"> +<li><p><em>Source of uncertainty</em>: The method of MPA arises from the susceptibility of DTI to dMRI noise present in diffusion-weighted images (DWIs), and also because the model is inherently statistical, making the tensor estimation and other derived quantities to be random variables <a class="footnote-reference brackets" href="#id7" id="id3" role="doc-noteref"><span class="fn-bracket">[</span>1<span class="fn-bracket">]</span></a>. For this reason, this method focus on the premise that image noise produces a random perturbation in the diffusion tensor estimation, and therefore in the calculation of eigenvalues and eigenvectors, particularly in the first eigenvector associated with the main diffusion direction.</p></li> +<li><p><em>Mathematical equation</em>: The description of the perturbation of the principal eigenvector is given by math formula where <span class="math notranslate nohighlight">\(\Delta D\)</span> corresponds to the estimated perturbation matrix of <span class="math notranslate nohighlight">\(D\)</span> given by the diagonal elements of the covariance matrix <span class="math notranslate nohighlight">\(\Sigma_{\alpha} \approx (B^T\Sigma^{−1}_{e}B)^{−1}\)</span>, where <span class="math notranslate nohighlight">\(\Sigma_{e}\)</span> is the covariance matrix of the error e, defined as a diagonal matrix made with the diagonal elements of <span class="math notranslate nohighlight">\((\Sigma^{−1}_{e}) = ⟨S(b)⟩^2 / \sigma^{2}_{\eta}\)</span>. Then, to get the angle <span class="math notranslate nohighlight">\(\theta\)</span> between the perturbed principal eigenvector of <span class="math notranslate nohighlight">\(D\)</span>, <span class="math notranslate nohighlight">\(\varepsilon_1 + \Delta\varepsilon_1\)</span>, and the estimated eigenvector <span class="math notranslate nohighlight">\(\varepsilon_1\)</span>, it can be approximated by <span class="math notranslate nohighlight">\(\theta = \tan^{−1}( \| \Delta\varepsilon_1 \|)\)</span> <a class="footnote-reference brackets" href="#id8" id="id4" role="doc-noteref"><span class="fn-bracket">[</span>2<span class="fn-bracket">]</span></a>. Taking into account the above, we define the function <code class="docutils literal notranslate"><span class="pre">main_dir_uncertainty(evals,</span> <span class="pre">evecs,</span> <span class="pre">signal,</span> <span class="pre">sigma,</span> <span class="pre">b_matrix)</span></code> that calculates the uncertainty of the eigenvector associated to the main direction of diffusion.</p></li> +<li><p><em>Double cone SDF definition</em>: The final SDF is composed by the union of 2 separately cones using the definition taken from this list of <a class="reference external" href="https://iquilezles.org/articles/distfunctions/#:~:text=Cone%20%2D%20exact,sign(s)%3B%0A%7D">distance functions</a>, in this way we have the SDF for the double cone defined as <code class="docutils literal notranslate"><span class="pre">opUnion(sdCone(p,a,h),</span> <span class="pre">sdCone(-p,a,h))</span> <span class="pre">*</span> <span class="pre">scaleVSOutput</span></code></p></li> +<li><p><em>Visualization example</em>: Below is a demo of how this new feature is intended to be used, an image of diffusion tensor ellipsoids and their associated uncertainty cones.</p></li> +</ul> +<img alt="https://user-images.githubusercontent.com/31288525/254747296-09a8674e-bfc0-4b3f-820f-8a1b1ad8c5c9.png" class="align-center" src="https://user-images.githubusercontent.com/31288525/254747296-09a8674e-bfc0-4b3f-820f-8a1b1ad8c5c9.png" style="width: 610px;" /> +<p>The implementation is almost complete, but as it is a new addition that includes mathematical calculations and for which there is no direct reference for comparison, it requires a more detail review before it can be incorporated.</p> +<p><em>Pull Request:</em></p> +<ul class="simple"> +<li><p><strong>DTI uncertainty visualization (Under Review)</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/810">fury-gl/fury#810</a></p></li> +</ul> +<p><strong>Future work:</strong> A tutorial will be made explaining in more detail how to calculate the parameters needed for the uncertainty cones using <strong>dipy</strong> functions, specifically: <a class="reference external" href="https://github.com/dipy/dipy/blob/321e06722ef42b5add3a7f570f6422845177eafa/dipy/denoise/noise_estimate.py#L272">estimate_sigma</a> for the noise variance calculation, <a class="reference external" href="https://github.com/dipy/dipy/blob/321e06722ef42b5add3a7f570f6422845177eafa/dipy/reconst/dti.py#L2112">design_matrix</a> to get the b-matrix, and <a class="reference external" href="https://github.com/dipy/dipy/blob/321e06722ef42b5add3a7f570f6422845177eafa/dipy/reconst/dti.py#L639">tensor_prediction</a> for the signal estimation. Additionally, when the ODF implementation is complete, uncertainty for this other reconstruction model is expected to be added, using semitransparent glyphs representing the mean directional information proposed by Tournier <a class="footnote-reference brackets" href="#id9" id="id5" role="doc-noteref"><span class="fn-bracket">[</span>3<span class="fn-bracket">]</span></a>.</p> +</section> +<section id="odf-actor-implemented-with-sdf"> +<h3>ODF actor implemented with SDF</h3> +<p>HARDI-based techniques require more images than DTI, however, they model the diffusion directions as probability distribution functions (PDFs), and the fitted values are returned as orientation distribution functions (ODFs). ODFs are more diffusion sensitive than the diffusion tensor and, therefore, can determine the structure of multi-directional voxels very common in the white matter regions of the brain <a class="footnote-reference brackets" href="#id9" id="id6" role="doc-noteref"><span class="fn-bracket">[</span>3<span class="fn-bracket">]</span></a>. The current actor to display this kind of glyphs is the <code class="docutils literal notranslate"><span class="pre">odf_slicer</span></code> which, given an array of spherical harmonics (SH) coefficients renders a grid of ODFs, which are created from a sphere with a specific number of vertices that fit the data.</p> +<p>For the application of this model using the same SDF ray marching techniques, we need the data of the SH coefficients, which are used to calculate the orientation distribution function (ODF) described <a class="reference external" href="https://dipy.org/documentation/1.7.0/theory/sh_basis/">here</a>. Different SH bases can be used, but for this first approach we focus on <code class="docutils literal notranslate"><span class="pre">descoteaux07</span></code> (as labeled in dipy). After performing the necessary calculations, we obtain an approximate result of the current implementation of FURY, as seen below.</p> +<img alt="https://user-images.githubusercontent.com/31288525/260909561-fd90033c-018a-465b-bd16-3586bb31ca36.png" class="align-center" src="https://user-images.githubusercontent.com/31288525/260909561-fd90033c-018a-465b-bd16-3586bb31ca36.png" style="width: 580px;" /> +<p>With a first implementation we start to solve some issues related to direction, color, and data handling, to obtain exactly the same results as the current implementation.</p> +<p>Details on the issues:</p> +<ul class="simple"> +<li><p><em>The direction and the scaling</em>: When the shape of the ODF is more sphere-like, the size of the glyph is smaller, so for the moment it needs to be adjusted manually, but the idea is to find a relationship between the coefficients and the final object size so it can be automatically scaled. Additionally, as seen in the image, the direction does not match. To fix this, an adjustment in the calculation of the spherical coordinates can be made, or pass the direction information directly.</p></li> +<li><p><em>Pass the coefficients data efficiently</em>: I’m currently creating one actor per glyph since I’m using a <em>uniform</em> array to pass the coefficients, but the idea is to pass all the data simultaneously. The first idea is to encode the coefficients data through a texture and retrieve them in the fragment shader.</p></li> +<li><p><em>The colormapping and the lighting</em>: As these objects present curvatures with quite a bit of detail in some cases, this requires more specific lighting work, in addition to having now not only one color but a color map. This can also be done with texture, but it is necessary to see in more detail how to adjust the texture to the glyph’s shape.</p></li> +</ul> +<p>More details on current progress can be seen in blogpost of <a class="reference external" href="https://fury.gl/latest/posts/2023/2023-08-16-week-11-tvcastillod.html">week 11</a> and <a class="reference external" href="https://fury.gl/latest/posts/2023/2023-08-24-week-12-tvcastillod.html">week 12</a>.</p> +<p><em>Working branch:</em></p> +<ul class="simple"> +<li><p><strong>ODF implementation (Under Development)</strong> +<a class="github reference external" href="https://github.com/tvcastillod/fury/tree/SH-for-ODF-impl">tvcastillod/fury</a></p></li> +</ul> +</section> +</section> +<section id="gsoc-weekly-blogs"> +<h2>GSoC Weekly Blogs</h2> +<ul class="simple"> +<li><p>My blog posts can be found on the <a class="reference external" href="https://fury.gl/latest/blog/author/tania-castillo.html">FURY website</a> and the <a class="reference external" href="https://blogs.python-gsoc.org/en/tvcastillods-blog/">Python GSoC blog</a>.</p></li> +</ul> +</section> +<section id="timeline"> +<h2>Timeline</h2> +<table class="table"> +<thead> +<tr class="row-odd"><th class="head"><p>Date</p></th> +<th class="head"><p>Description</p></th> +<th class="head"><p>Blog Post Link</p></th> +</tr> +</thead> +<tbody> +<tr class="row-even"><td><p>Week 0(02-06-2022)</p></td> +<td><p>Community Bounding Period</p></td> +<td><p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-06-02-week-0-tvcastillod.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/tvcastillods-blog/weekly-check-in-0-2">Python</a></p></td> +</tr> +<tr class="row-odd"><td><p>Week 1(05-06-2022)</p></td> +<td><p>Ellipsoid actor implemented with SDF</p></td> +<td><p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-06-05-week-1-tvcastillod.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/tvcastillods-blog/weekly-check-in-1-23">Python</a></p></td> +</tr> +<tr class="row-even"><td><p>Week 2(12-06-2022)</p></td> +<td><p>Making adjustments to the Ellipsoid Actor</p></td> +<td><p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-06-12-week-2-tvcastillod.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/tvcastillods-blog/weekly-check-in-2-18">Python</a></p></td> +</tr> +<tr class="row-odd"><td><p>Week 3(19-06-2022)</p></td> +<td><p>Working on uncertainty and details of the first PR</p></td> +<td><p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-06-19-week-3-tvcastillod.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/tvcastillods-blog/weekly-check-in-3-27">Python</a></p></td> +</tr> +<tr class="row-even"><td><p>Week 4(27-06-2022)</p></td> +<td><p>First draft of the DTI uncertainty visualization</p></td> +<td><p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-06-27-week-4-tvcastillod.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/tvcastillods-blog/weekly-check-in-4-24">Python</a></p></td> +</tr> +<tr class="row-odd"><td><p>Week 5(03-07-2022)</p></td> +<td><p>Preparing the data for the Ellipsoid tutorial</p></td> +<td><p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-07-03-week-5-tvcastillod.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/tvcastillods-blog/weekly-check-in-5-27">Python</a></p></td> +</tr> +<tr class="row-even"><td><p>Week 6(10-07-2022)</p></td> +<td><p>First draft of the Ellipsoid tutorial</p></td> +<td><p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-07-10-week-6-tvcastillod.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/tvcastillods-blog/weekly-check-in-6-26">Python</a></p></td> +</tr> +<tr class="row-odd"><td><p>Week 7(17-07-2022)</p></td> +<td><p>Adjustments on the Uncertainty Cones visualization</p></td> +<td><p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-07-17-week-7-tvcastillod.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/tvcastillods-blog/weekly-check-in-7-26">Python</a></p></td> +</tr> +<tr class="row-even"><td><p>Week 8(25-07-2022)</p></td> +<td><p>Working on Ellipsoid Tutorial and exploring SH</p></td> +<td><p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-07-25-week-8-tvcastillod.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/tvcastillods-blog/weekly-check-in-8-17">Python</a></p></td> +</tr> +<tr class="row-odd"><td><p>Week 9(31-07-2022)</p></td> +<td><p>Tutorial done and polishing DTI uncertainty</p></td> +<td><p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-07-31-week-9-tvcastillod.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/tvcastillods-blog/weekly-check-in-9-22">Python</a></p></td> +</tr> +<tr class="row-even"><td><p>Week 10(08-08-2022)</p></td> +<td><p>Start of SH implementation experiments</p></td> +<td><p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-08-08-week-10-tvcastillod.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/tvcastillods-blog/weekly-check-in-10-16">Python</a></p></td> +</tr> +<tr class="row-odd"><td><p>Week 11(16-08-2022)</p></td> +<td><p>Adjusting ODF implementation and looking for solutions on issues found</p></td> +<td><p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-08-16-week-11-tvcastillod.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/tvcastillods-blog/weekly-check-in-11-17">Python</a></p></td> +</tr> +<tr class="row-even"><td><p>Week 12(24-08-2022)</p></td> +<td><p>Experimenting with ODFs implementation</p></td> +<td><p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-08-24-week-12-tvcastillod.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/tvcastillods-blog/weekly-check-in-12-9">Python</a></p></td> +</tr> +</tbody> +</table> +</section> +<section id="references"> +<h2>References</h2> +<aside class="footnote-list brackets"> +<aside class="footnote brackets" id="id7" role="doc-footnote"> +<span class="label"><span class="fn-bracket">[</span>1<span class="fn-bracket">]</span></span> +<span class="backrefs">(<a role="doc-backlink" href="#id2">1</a>,<a role="doc-backlink" href="#id3">2</a>)</span> +<p>Basser, P. J. (1997). Quantifying errors in fiber direction and diffusion tensor field maps resulting from MR noise. In 5th Scientific Meeting of the ISMRM (Vol. 1740).</p> +</aside> +<aside class="footnote brackets" id="id8" role="doc-footnote"> +<span class="label"><span class="fn-bracket">[</span><a role="doc-backlink" href="#id4">2</a><span class="fn-bracket">]</span></span> +<p>Chang, L. C., Koay, C. G., Pierpaoli, C., &amp; Basser, P. J. (2007). Variance of estimated DTI‐derived parameters via first‐order perturbation methods. Magnetic Resonance in Medicine: An Official Journal of the International Society for Magnetic Resonance in Medicine, 57(1), 141-149.</p> +</aside> +<aside class="footnote brackets" id="id9" role="doc-footnote"> +<span class="label"><span class="fn-bracket">[</span>3<span class="fn-bracket">]</span></span> +<span class="backrefs">(<a role="doc-backlink" href="#id5">1</a>,<a role="doc-backlink" href="#id6">2</a>)</span> +<p>J-Donald Tournier, Fernando Calamante, David G Gadian, and Alan Connelly. Direct estimation of the fiber orientation density function from diffusion-weighted mri data using spherical deconvolution. Neuroimage, 23(3):1176–1185, 2004.</p> +</aside> +<aside class="footnote brackets" id="id10" role="doc-footnote"> +<span class="label"><span class="fn-bracket">[</span><a role="doc-backlink" href="#id1">4</a><span class="fn-bracket">]</span></span> +<p>Gordon Kindlmann. Superquadric tensor glyphs. In Proceedings of the Sixth Joint Eurographics-IEEE TCVG conference on Visualization, pages 147–154, 2004.</p> +</aside> +</aside> +</section> +</section> + + + Name: Tania Castillo + + 2023-08-24T00:00:00-04:00 + + + https://fury.gl/posts/2023/2023-08-21-week-12-joaodellagli.html + Week 12: Now That is (almost) a Wrap! + 2023-08-21T00:00:00-04:00 + + João Victor Dell Agli Floriano + + <section id="week-12-now-that-is-almost-a-wrap"> + +<p>Hello everyone, it’s time for another GSoC blogpost! Today, I am going to talk about some minor details I worked on last week on my +project.</p> +<section id="last-week-s-effort"> +<h2>Last Week’s Effort</h2> +<p>After the API refactoring was done last week, I focused on addressing the reviews I would get from it. The first issues I addressed was related to +style, as there were some minor details my GSoC contributors pointed out that needed change. Also, I have addressed an issue I was having +with the <cite>typed hint</cite> of one of my functions. Filipi, my mentor, showed me there is a way to have more than one typed hint in the same parameter, +all I needed to do was to use the <cite>Union</cite> class from the <cite>typing</cite> module, as shown below:</p> +<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">Union</span> <span class="k">as</span> <span class="n">tUnion</span> +<span class="kn">from</span> <span class="nn">numpy</span> <span class="kn">import</span> <span class="n">ndarray</span> + +<span class="k">def</span> <span class="nf">function</span><span class="p">(</span><span class="n">variable</span> <span class="p">:</span> <span class="n">tUnion</span><span class="p">(</span><span class="nb">float</span><span class="p">,</span> <span class="n">np</span><span class="o">.</span><span class="n">ndarray</span><span class="p">)):</span> + <span class="k">pass</span> +</pre></div> +</div> +<p>Using that, I could set the typedhint of the <cite>bandwidth</cite> variable to <cite>float</cite> and <cite>np.ndarray</cite>.</p> +</section> +<section id="so-how-did-it-go"> +<h2>So how did it go?</h2> +<p>All went fine with no difficult at all, thankfully.</p> +</section> +<section id="the-next-steps"> +<h2>The Next Steps</h2> +<p>My next plans are, after having PR <a class="reference external" href="https://github.com/fury-gl/fury/pull/826">#826</a> merged, to work on the float encoding issue described in +<span class="xref std std-doc">this blogpost</span>. Also, I plan to tackle the UI idea once again, to see if I can finally give the user +a way to control the intensities of the distributions.</p> +<p>Wish me luck!</p> +</section> +</section> + + + Hello everyone, it’s time for another GSoC blogpost! Today, I am going to talk about some minor details I worked on last week on my +project. + + 2023-08-21T00:00:00-04:00 + + + https://fury.gl/posts/2023/2023-08-21-joaodellagli-final-report.html + Google Summer of Code Final Work Product + 2023-08-21T00:00:00-04:00 + + João Victor Dell Agli Floriano + + <a class="reference external image-reference" href="https://summerofcode.withgoogle.com/programs/2023/projects/ED0203De"><img alt="https://developers.google.com/open-source/gsoc/resources/downloads/GSoC-logo-horizontal.svg" height="40" src="https://developers.google.com/open-source/gsoc/resources/downloads/GSoC-logo-horizontal.svg" /></a> +<a class="reference external image-reference" href="https://summerofcode.withgoogle.com/programs/2023/organizations/python-software-foundation"><img alt="https://www.python.org/static/img/python-logo&#64;2x.png" src="https://www.python.org/static/img/python-logo&#64;2x.png" style="height: 40px;" /></a> +<a class="reference external image-reference" href="https://fury.gl/latest/index.html"><img alt="https://python-gsoc.org/logos/fury_logo.png" src="https://python-gsoc.org/logos/fury_logo.png" style="width: 40px;" /></a> +<section id="google-summer-of-code-final-work-product"> + +<ul class="simple"> +<li><p><strong>Name:</strong> João Victor Dell Agli Floriano</p></li> +<li><p><strong>Organisation:</strong> Python Software Foundation</p></li> +<li><p><strong>Sub-Organisation:</strong> FURY</p></li> +<li><p><strong>Project:</strong> <a class="reference external" href="https://github.com/fury-gl/fury/wiki/Google-Summer-of-Code-2023-(GSOC2023)#project-2-fast-3d-kernel-based-density-rendering-using-billboards">FURY - Project 2. Fast 3D kernel-based density rendering using billboards.</a></p></li> +</ul> +<section id="abstract"> +<h2>Abstract</h2> +<p>This project had the goal to implement 3D Kernel Density Estimation rendering to FURY. Kernel Density Estimation, or KDE, is a +statistical method that uses kernel smoothing for modeling and estimating the density distribution of a set of points defined +inside a given region. For its graphical implementation, it was used post-processing techniques such as offscreen rendering to +framebuffers and colormap post-processing as tools to achieve the desired results. This was completed with a functional basic KDE +rendering result, that relies on a solid and easy-to-use API, as well as some additional features.</p> +</section> +<section id="proposed-objectives"> +<h2>Proposed Objectives</h2> +<ul class="simple"> +<li><dl class="simple"> +<dt><strong>First Phase</strong><span class="classifier">Implement framebuffer usage in FURY</span></dt><dd><ul> +<li><p>Investigate the usage of float framebuffers inside FURY’s environment.</p></li> +<li><p>Implement a float framebuffer API.</p></li> +</ul> +</dd> +</dl> +</li> +<li><dl class="simple"> +<dt><strong>Second Phase</strong><span class="classifier">Shader-framebuffer integration</span></dt><dd><ul> +<li><p>Implement a shader that uses a colormap to render framebuffers.</p></li> +<li><p>Escalate this rendering for composing multiple framebuffers.</p></li> +</ul> +</dd> +</dl> +</li> +<li><dl class="simple"> +<dt><strong>Third Phase</strong><span class="classifier">KDE Calculations</span></dt><dd><ul> +<li><p>Investigate KDE calculation for point-cloud datasets.</p></li> +<li><p>Implement KDE calculation inside the framebuffer rendering shaders.</p></li> +<li><p>Test KDE for multiple datasets.</p></li> +</ul> +</dd> +</dl> +</li> +</ul> +</section> +<section id="objectives-completed"> +<h2>Objectives Completed</h2> +<ul> +<li><dl> +<dt><strong>Implement framebuffer usage in FURY</strong></dt><dd><p>The first phase, addressed from <em>May/29</em> to <em>July/07</em>, started with the investigation of +<a class="reference external" href="https://vtk.org/doc/nightly/html/classvtkOpenGLFramebufferObject.html#details">VTK’s Framebuffer Object</a>, a vital part of this project, to understand +how to use it properly.</p> +<p>Framebuffer Objects, abbreviated as FBOs, are the key to post-processing effects in OpenGL, as they are used to render things offscreen and save the resulting image to a texture +that will be later used to apply the desired post-processing effects within the object’s <a class="reference external" href="https://www.khronos.org/opengl/wiki/Fragment_Shader">fragment shader</a> +rendered to screen, in this case, a <a class="reference external" href="http://www.opengl-tutorial.org/intermediate-tutorials/billboards-particles/billboards/">billboard</a>. In the case of the +<a class="reference external" href="https://en.wikipedia.org/wiki/Kernel_density_estimation">Kernel Density Estimation</a> post-processing effect, we need a special kind of FBO, one that stores textures’ +values as floats, different from the standard 8-bit unsigned int storage. This is necessary because the KDE rendering involves rendering every KDE point calculation +to separate billboards, rendered to the same scene, which will have their intensities, divided by the number of points rendered, blended with +<a class="reference external" href="https://www.khronos.org/opengl/wiki/Blending">OpenGL Additive Blending</a>, and if a relative big number of points are rendered at the +same time, 32-bit float precision is needed to guarantee that small-intensity values will not be capped to zero, and disappear.</p> +<p>After a month going through VTK’s FBO documentation and weeks spent trying different approaches to this method, it would not work +properly, as some details seemed to be missing from the documentation, and asking the community haven’t solved the problem as well. +Reporting that to my mentors, which unsuccessfully tried themselves to make it work, they decided it was better if another path was taken, using +<a class="reference external" href="https://vtk.org/doc/nightly/html/classvtkWindowToImageFilter.html">VTK’s WindowToImageFilter</a> method as a workaround, described +in this <a class="reference external" href="https://fury.gl/latest/posts/2023/2023-07-03-week-5-joaodellagli.html">blogpost</a>. This method helped the development of +three new functions to FURY, <em>window_to_texture()</em>, <em>texture_to_actor()</em> and <em>colormap_to_texture()</em>, that allow the passing of +different kinds of textures to FURY’s actor’s shaders, the first one to capture a window and pass it as a texture to an actor, +the second one to pass an external texture to an actor, and the third one to specifically pass a colormap as a texture to an +actor. It is important to say that <em>WindowToImageFilter()</em> is not the ideal way to make it work, as this method does not seem to +support float textures. However, a workaround to that is currently being worked on, as I will describe later on.</p> +<p><em>Pull Requests:</em></p> +<ul class="simple"> +<li><p><strong>KDE Rendering Experimental Program (Needs major revision):</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/804">fury-gl/fury#804</a></p></li> +</ul> +<p>The result of this whole FBO and WindowToImageFilter experimentation is well documented in PR +<a class="reference external" href="https://github.com/fury-gl/fury/pull/804">#804</a> that implements an experimental version of a KDE rendering program. +The future of this PR, as discussed with my mentors, is to be better documented to be used as an example for developers on +how to develop features in FURY with the tools used, and it shall be done soon.</p> +</dd> +</dl> +</li> +<li><dl> +<dt><strong>Shader-framebuffer integration</strong></dt><dd><aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-21-joaodellagli-final-report.rst</span>, line 16); <em><a href="#id2">backlink</a></em></p> +<p>Duplicate explicit target name: “blogpost”.</p> +</aside> +<p>The second phase, which initially was thought of as “Implement a shader that uses a colormap to render framebuffers” and “Escalate this +rendering for composing multiple framebuffers” was actually a pretty simple phase that could be addressed in one week, <em>July/10</em> +to <em>July/17</em>, done at the same time as the third phase goal, documented in this +<a class="reference external" href="https://fury.gl/latest/posts/2023/2023-07-17-week-7-joaodellagli.html">blogpost</a>. As FURY already had a tool for generating and +using colormaps, they were simply connected to the shader part of the program as textures, with the functions explained above. +Below, is the result of the <em>matplotlib viridis</em> colormap passed to a simple gaussian KDE render:</p> +<img alt="Final 2D plot" class="align-center" src="https://raw.githubusercontent.com/JoaoDell/gsoc_assets/main/images/final_2d_plot.png" /> +<aside class="system-message"> +<p class="system-message-title">System Message: INFO/1 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-21-joaodellagli-final-report.rst</span>, line 16); <em><a href="#id3">backlink</a></em></p> +<p>Duplicate explicit target name: “#804”.</p> +</aside> +<p>That is also included in PR <a class="reference external" href="https://github.com/fury-gl/fury/pull/804">#804</a>. Having the 2D plot ready, some time was taken to +figure out how to enable a 3D render, that includes rotation and other movement around the set rendered, which was solved by +learning about the callback properties that exist inside <em>VTK</em>. Callbacks are ways to enable code execution inside the VTK rendering +loop, enclosed inside <em>vtkRenderWindowInteractor.start()</em>. If it is desired to add a piece of code that, for example, passes a time +variable to the fragment shader over time, a callback function can be declared:</p> +<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">fury</span> <span class="kn">import</span> <span class="n">window</span> +<span class="n">t</span> <span class="o">=</span> <span class="mi">0</span> +<span class="n">showm</span> <span class="o">=</span> <span class="n">window</span><span class="o">.</span><span class="n">ShowManager</span><span class="p">(</span><span class="o">...</span><span class="p">)</span> + +<span class="k">def</span> <span class="nf">callback_function</span><span class="p">:</span> + <span class="n">t</span> <span class="o">+=</span> <span class="mf">0.01</span> + <span class="n">pass_shader_uniforms_to_fs</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="s2">&quot;t&quot;</span><span class="p">)</span> + +<span class="n">showm</span><span class="o">.</span><span class="n">add_iren_callback</span><span class="p">(</span><span class="n">callback_function</span><span class="p">,</span> <span class="s2">&quot;RenderEvent&quot;</span><span class="p">)</span> +</pre></div> +</div> +<p>The piece of code above created a function that updates the time variable <em>t</em> in every <em>“RenderEvent”</em>, and passes it to the +fragment shader. With that property, the camera and some other parameters could be updated, which enabled 3D visualization, that +then, outputted the following result, using <em>matplotlib inferno</em> colormap:</p> +<img alt="3D Render gif" class="align-center" src="https://raw.githubusercontent.com/JoaoDell/gsoc_assets/main/images/3d_kde_gif.gif" /> +</dd> +</dl> +</li> +<li><dl> +<dt><strong>KDE Calculations</strong> (ongoing)</dt><dd><p>As said before, the second and third phases were done simultaneously, so after having a way to capture the window and use it as a +texture ready, the colormap ready, and an initial KDE render ready, all it was needed to do was to improve the KDE calculations. +As this <a class="reference external" href="https://en.wikipedia.org/wiki/Kernel_density_estimation">Wikipedia page</a> explains, a KDE calculation is to estimate an +abstract density around a set of points defined inside a given region with a kernel, that is a function that models the density +around a point based on its associated distribution <span class="math notranslate nohighlight">\(\sigma\)</span>.</p> +<p>A well-known kernel is, for example, the <strong>Gaussian Kernel</strong>, that says that the density around a point <span class="math notranslate nohighlight">\(p\)</span> with distribution +<span class="math notranslate nohighlight">\(\sigma\)</span> is defined as:</p> +<div class="math notranslate nohighlight"> +\[GK_{\textbf{p}, \sigma} (\textbf{x}) = e^{-\frac{1}{2}\frac{||\textbf{x} - \textbf{p}||^2}{\sigma^2}}\]</div> +<p>Using that kernel, we can calculate the KDE of a set of points <span class="math notranslate nohighlight">\(P\)</span> with associated distributions <span class="math notranslate nohighlight">\(S\)</span> calculating their individual +Gaussian distributions, summing them up and dividing them by the total number of points <span class="math notranslate nohighlight">\(n\)</span>:</p> +<div class="math notranslate nohighlight"> +\[KDE(A, S)=\frac{1}{n}\sum_{i = 0}^{n}GK(x, p_{i}, \sigma_{i})\]</div> +<p>So I dove into implementing all of that into the offscreen rendering part, and that is when the lack of a float framebuffer would +charge its cost. As it can be seen above, just calculating each point’s density isn’t the whole part, as I also need to divide +everyone by the total number of points <span class="math notranslate nohighlight">\(n\)</span>, and then sum them all. The problem is that, if the number of points its big enough, +the individual densities will be really low, and that would not be a problem for a 32-bit precision float framebuffer, but that is +<em>definitely</em> a problem for a 8-bit integer framebuffer, as small enough values will simply underflow and disappear. That issue is +currently under investigation, and some solutions have already being presented, as I will show in the <strong>Objectives in Progress</strong> +section.</p> +<p>Apart from that, after having the experimental program ready, I focused on modularizing it into a functional and simple API +(without the <span class="math notranslate nohighlight">\(n\)</span> division for now), and I could get a good set of results from that. The API I first developed implemented the +<em>EffectManager</em> class, responsible for managing all of the behind-the-scenes steps necessary for the kde render to work, +encapsulated inside the <em>ÈffectManager.kde()</em> method. It had the following look:</p> +<aside class="system-message"> +<p class="system-message-title">System Message: ERROR/3 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-21-joaodellagli-final-report.rst</span>, line 162)</p> +<p>Error in “code-block” directive: +maximum 1 argument(s) allowed, 9 supplied.</p> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="o">..</span> <span class="n">code</span><span class="o">-</span><span class="n">block</span><span class="p">::</span> <span class="n">python</span> + <span class="kn">from</span> <span class="nn">fury.effect_manager</span> <span class="kn">import</span> <span class="n">EffectManager</span> + <span class="kn">from</span> <span class="nn">fury</span> <span class="kn">import</span> <span class="n">window</span> + + <span class="n">showm</span> <span class="o">=</span> <span class="n">window</span><span class="o">.</span><span class="n">ShowManager</span><span class="p">(</span><span class="o">...</span><span class="p">)</span> + + <span class="c1"># KDE rendering setup</span> + <span class="n">em</span> <span class="o">=</span> <span class="n">EffectManager</span><span class="p">(</span><span class="n">showm</span><span class="p">)</span> + <span class="n">kde_actor</span> <span class="o">=</span> <span class="n">em</span><span class="o">.</span><span class="n">kde</span><span class="p">(</span><span class="o">...</span><span class="p">)</span> + <span class="c1"># End of KDE rendering setup</span> + + <span class="n">showmn</span><span class="o">.</span><span class="n">scene</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">kde_actor</span><span class="p">)</span> + + <span class="n">showm</span><span class="o">.</span><span class="n">start</span><span class="p">()</span> +</pre></div> +</div> +</aside> +<p>Those straightforward instructions, that hid several lines of code and setup, could manage to output the following result:</p> +<img alt="API 3D KDE plot" class="align-center" src="https://raw.githubusercontent.com/JoaoDell/gsoc_assets/main/images/fianl_3d_plot.png" /> +<p>And this was not the only feature I had implemented for this API, as the use of <em>WindowToImageFilter</em> method opened doors for a +whole new world for FURY: The world of post-processing effects. With this features setup, I managed to implement a <em>gaussian blur</em> +effect, a <em>grayscale</em> effect and a <em>Laplacian</em> effect for calculating “borders”:</p> +<img alt="Gaussian Blur effect" class="align-center" src="https://raw.githubusercontent.com/JoaoDell/gsoc_assets/main/images/gaussian_blur.png" /> +<img alt="Grayscale effect" class="align-center" src="https://raw.githubusercontent.com/JoaoDell/gsoc_assets/main/images/grayscale.png" /> +<img alt="Laplacian effect" class="align-center" src="https://raw.githubusercontent.com/JoaoDell/gsoc_assets/main/images/laplacian1.gif" /> +<p>As this wasn’t the initial goal of the project and I still had several issues to deal with, I have decided to leave these features as a +future addition.</p> +<p>Talking with my mentors, we realized that the first KDE API, even though simple, could lead to bad usage from users, as the +<em>em.kde()</em> method, that outputted a <em>FURY actor</em>, had dependencies different from any other object of its kind, making it a new +class of actors, which could lead to confusion and bad handling. After some pair programming sessions, they instructed me to take +a similar, but different road from what I was doing, turning the kde actor into a new class, the <em>KDE</em> class. This class would +have almost the same set of instructions present in the prior method, but it would break them in a way it would only be completely +set up after being passed to the <em>EffectManager</em> via its add function. Below, how the refactoring handles it:</p> +<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">fury.effects</span> <span class="kn">import</span> <span class="n">EffectManager</span><span class="p">,</span> <span class="n">KDE</span> +<span class="kn">from</span> <span class="nn">fury</span> <span class="kn">import</span> <span class="n">window</span> + +<span class="n">showm</span> <span class="o">=</span> <span class="n">window</span><span class="o">.</span><span class="n">ShowManager</span><span class="p">(</span><span class="o">...</span><span class="p">)</span> + +<span class="c1"># KDE rendering setup</span> +<span class="n">em</span> <span class="o">=</span> <span class="n">EffectManager</span><span class="p">(</span><span class="n">showm</span><span class="p">)</span> +<span class="n">kde_effect</span> <span class="o">=</span> <span class="n">KDE</span><span class="p">(</span><span class="o">...</span><span class="p">)</span> +<span class="n">em</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">kde_effect</span><span class="p">)</span> +<span class="c1"># End of KDE rendering setup</span> + +<span class="n">showm</span><span class="o">.</span><span class="n">start</span><span class="p">()</span> +</pre></div> +</div> +<p>Which outputted the same results as shown above. It may have cost some simplicity as we are now one line farther from having it +working, but it is more explicit in telling the user this is not just a normal actor.</p> +<p>Another detail I worked on was the kernel variety. The Gaussian Kernel isn’t the only one available to model density distributions, +there are several others that can do that job, as it can be seen in this <a class="reference external" href="https://scikit-learn.org/stable/modules/density.html">scikit-learn piece of documentation</a> +and this <a class="reference external" href="https://en.wikipedia.org/wiki/Kernel_(statistics)">Wikipedia page on kernels</a>. Based on the scikit-learn KDE +implementation, I worked on implementing the following kernels inside our API, that can be chosen as a parameter when calling the +<em>KDE</em> class:</p> +<ul class="simple"> +<li><p>Cosine</p></li> +<li><p>Epanechnikov</p></li> +<li><p>Exponential</p></li> +<li><p>Gaussian</p></li> +<li><p>Linear</p></li> +<li><p>Tophat</p></li> +</ul> +<p>Below, the comparison between them using the same set of points and bandwidths:</p> +<img alt="Comparison between the six implemented kernels" class="align-center" src="https://raw.githubusercontent.com/JoaoDell/gsoc_assets/main/images/kernels.png" /> +<p><em>Pull Requests</em>:</p> +<ul class="simple"> +<li><p><strong>First Stage of the KDE Rendering API (will be merged soon)</strong>: <a class="github reference external" href="https://github.com/fury-gl/fury/pull/826">fury-gl/fury#826</a></p></li> +</ul> +<p>All of this work culminated in PR <a class="reference external" href="https://github.com/fury-gl/fury/pull/826/">#826</a>, that proposes to add the first stage of +this API (there are some details yet to be completed, like the <span class="math notranslate nohighlight">\(n\)</span> division) to FURY. This PR added the described API, and also +proposed some minor changes to some already existing FURY functions related to callbacks, changes necessary for this and other +future applications that would use it to work. It also added the six kernels described, and a simple documented example on how +to use this feature.</p> +</dd> +</dl> +</li> +</ul> +</section> +<section id="other-objectives"> +<h2>Other Objectives</h2> +<ul class="simple"> +<li><dl class="simple"> +<dt><strong>Stretch Goals</strong><span class="classifier">SDE Implementation, Network/Graph visualization using SDE/KDE, Tutorials</span></dt><dd><ul> +<li><p>Investigate SDE calculation for surface datasets.</p></li> +<li><p>Implement SDE calculation inside the framebuffer rendering shaders.</p></li> +<li><p>Test SDE for multiple datasets.</p></li> +<li><p>Develop comprehensive tutorials that explain SDE concepts and FURY API usage.</p></li> +<li><p>Create practical, scenario-based tutorials using real datasets and/or simulations.</p></li> +</ul> +</dd> +</dl> +</li> +</ul> +</section> +<section id="objectives-in-progress"> +<h2>Objectives in Progress</h2> +<ul> +<li><dl> +<dt><strong>KDE Calculations</strong> (ongoing)</dt><dd><p>The KDE rendering, even though almost complete, have the $n$ division, an important step, missing, as this normalization allows colormaps +to cover the whole range o values rendered. The lack of a float FBO made a big difference in the project, as the search for a functional implementation of it not only delayed the project, but it is vital for +the correct calculations to work.</p> +<p>For the last part, a workaround thought was to try an approach I later figured out is an old one, as it can be check in +<a class="reference external" href="https://developer.nvidia.com/gpugems/gpugems/part-ii-lighting-and-shadows/chapter-12-omnidirectional-shadow-mapping">GPU Gems 12.3.3 section</a>: +If I need 32-bit float precision and I got 4 8-bit integer precision available, why not trying to pack this float into this RGBA +texture? I have first tried to do one myself, but it didn’t work for some reason, so I tried <a class="reference external" href="https://aras-p.info/blog/2009/07/30/encoding-floats-to-rgba-the-final/">Aras Pranckevičius</a> +implementation, that does the following:</p> +<div class="highlight-GLSL notranslate"><div class="highlight"><pre><span></span><span class="kt">vec4</span><span class="w"> </span><span class="n">float_to_rgba</span><span class="p">(</span><span class="kt">float</span><span class="w"> </span><span class="n">value</span><span class="p">)</span><span class="w"> </span><span class="p">{</span> +<span class="w"> </span><span class="kt">vec4</span><span class="w"> </span><span class="n">bitEnc</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="kt">vec4</span><span class="p">(</span><span class="mf">1.</span><span class="p">,</span><span class="mf">256.</span><span class="p">,</span><span class="mf">65536.0</span><span class="p">,</span><span class="mf">16777216.0</span><span class="p">);</span> +<span class="w"> </span><span class="kt">vec4</span><span class="w"> </span><span class="n">enc</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">bitEnc</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">value</span><span class="p">;</span> +<span class="w"> </span><span class="n">enc</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">fract</span><span class="p">(</span><span class="n">enc</span><span class="p">);</span> +<span class="w"> </span><span class="n">enc</span><span class="w"> </span><span class="o">-=</span><span class="w"> </span><span class="n">enc</span><span class="p">.</span><span class="n">yzww</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="kt">vec2</span><span class="p">(</span><span class="mf">1.</span><span class="o">/</span><span class="mf">255.</span><span class="p">,</span><span class="w"> </span><span class="mf">0.</span><span class="p">).</span><span class="n">xxxy</span><span class="p">;</span> +<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="n">enc</span><span class="p">;</span> +<span class="p">}</span> +</pre></div> +</div> +<p>That initially worked, but for some reason I am still trying to understand, it is resulting in a really noisy texture:</p> +<img alt="Noisy KDE render" class="align-center" src="https://raw.githubusercontent.com/JoaoDell/gsoc_assets/main/images/noisy%20kde.png" /> +<p>One way to try to mitigate that while is to pass this by a gaussian blur filter, to try to smooth out the result:</p> +<img alt="Blurred result" class="align-center" src="https://raw.githubusercontent.com/JoaoDell/gsoc_assets/main/images/blurred_kde.png" /> +<p>But it is not an ideal solution as well, as it may lead to distortions in the actual density values, depending on the application of +the KDE. Now, my goal is to first find the root of the noise problem, and then, if that does not work, try to make the gaussian filter +work.</p> +<p>Another detail that would be a good addition to the API is UI controls. Filipi, one of my mentors, told me it would be a good feature +if the user could control the intensities of the bandwidths for a better structural visualization of the render, and knowing FURY already +have a good set of <a class="reference external" href="https://fury.gl/latest/auto_examples/index.html#user-interface-elements">UI elements</a>, I just needed to integrate +that into my program via callbacks. I tried implementing an intensity slider. However, for some reason, it is making the program crash +randomly, for reasons I still don’t know, so that is another issue under investigation. Below, we show a first version of that feature, +which was working before the crashes:</p> +<img alt="Slider for bandwidths" class="align-center" src="https://raw.githubusercontent.com/JoaoDell/gsoc_assets/main/images/slider.gif" /> +<p><em>Pull Requests</em></p> +<ul class="simple"> +<li><p><strong>UI intensity slider for the KDE rendering API (draft)</strong>: <a class="github reference external" href="https://github.com/fury-gl/fury/pull/849">fury-gl/fury#849</a></p></li> +<li><p><strong>Post-processing effects for FURY Effects API (draft)</strong>: <a class="github reference external" href="https://github.com/fury-gl/fury/pull/850">fury-gl/fury#850</a></p></li> +</ul> +</dd> +</dl> +</li> +</ul> +</section> +<section id="gsoc-weekly-blogs"> +<h2>GSoC Weekly Blogs</h2> +<ul class="simple"> +<li><p>My blog posts can be found at <a class="reference external" href="https://fury.gl/latest/blog/author/joao-victor-dell-agli-floriano.html">FURY website</a> and <a class="reference external" href="https://blogs.python-gsoc.org/en/joaodellaglis-blog/">Python GSoC blog</a>.</p></li> +</ul> +</section> +<section id="timeline"> +<h2>Timeline</h2> +<aside class="system-message"> +<p class="system-message-title">System Message: ERROR/3 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-21-joaodellagli-final-report.rst</span>, line 332)</p> +<p>Malformed table.</p> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>+---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Date | Description | Blog Post Link | ++=====================+====================================================+===========================================================================================================================================================================================================+ +| Week 0 (29-05-2023) | The Beginning of Everything | `FURY &lt;https://fury.gl/latest/posts/2023/2023-05-29-week-0-joaodellagli.html&gt;`__ - `Python &lt;https://blogs.python-gsoc.org/en/joaodellaglis-blog/the-beggining-of-everything-week-0/&gt;`__ | ++---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 1 (05-06-2022) | The FBO Saga | `FURY &lt;https://fury.gl/latest/posts/2023/2023-06-05-week-1-joaodellagli.html&gt;`__ - `Python &lt;https://blogs.python-gsoc.org/en/joaodellaglis-blog/the-fbo-saga-week-1/&gt;`__ | ++---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 2 (12-06-2022) | The Importance of (good) Documentation | `FURY &lt;https://fury.gl/latest/posts/2023/2023-06-12-week-2-joaodellagli.html&gt;`__ - `Python &lt;https://blogs.python-gsoc.org/en/joaodellaglis-blog/the-importance-of-good-documentation-week-2/&gt;`__ | ++---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 3 (19-06-2022) | Watch Your Expectations | `FURY &lt;https://fury.gl/latest/posts/2023/2023-06-19-week-3-joaodellagli.html&gt;`__ - `Python &lt;https://blogs.python-gsoc.org/en/joaodellaglis-blog/week-3-watch-your-expectations/&gt;`__ | ++---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 4 (26-06-2022) | Nothing is Ever Lost | `FURY &lt;https://fury.gl/latest/posts/2023/2023-06-26-week-4-joaodellagli.html&gt;`__ - `Python &lt;https://blogs.python-gsoc.org/en/joaodellaglis-blog/week-4-nothing-is-ever-lost/&gt;`__ | ++---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 5 (03-07-2022) | All Roads Lead to Rome | `FURY &lt;https://fury.gl/latest/posts/2023/2023-07-03-week-5-joaodellagli.html&gt;`__ - `Python &lt;https://blogs.python-gsoc.org/en/joaodellaglis-blog/week-5-all-roads-lead-to-rome/&gt;`__ | ++---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 6 (10-07-2022) | Things are Starting to Build Up | `FURY &lt;https://fury.gl/latest/posts/2023/2023-07-10-week-6-joaodellagli.html&gt;`__ - `Python &lt;https://blogs.python-gsoc.org/en/joaodellaglis-blog/week-6-things-are-starting-to-build-up/&gt;`__ | ++---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 7 (17-07-2022) | Experimentation Done | `FURY &lt;https://fury.gl/latest/posts/2023/2023-07-17-week-7-joaodellagli.html&gt;`__ - `Python &lt;https://blogs.python-gsoc.org/en/joaodellaglis-blog/week-7-experimentation-done/&gt;`__ | ++---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 8 (24-07-2022) | The Birth of a Versatile API | `FURY &lt;https://fury.gl/latest/posts/2023/2023-07-24-week-8-joaodellagli.html&gt;`__ - `Python &lt;https://blogs.python-gsoc.org/en/joaodellaglis-blog/week-8-the-birth-of-a-versatile-api/&gt;`__ | ++---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 9 (31-07-2022) | It is Polishing Time! | `FURY &lt;https://fury.gl/latest/posts/2023/2023-07-31-week-9-joaodellagli.html&gt;`__ - `Python &lt;https://blogs.python-gsoc.org/en/joaodellaglis-blog/week-9-it-is-polishing-time/&gt;`__ | ++---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 10 (07-08-2022)| Ready for Review! | `FURY &lt;https://fury.gl/latest/posts/2023/2023-08-07-week-10-joaodellagli.html&gt;`__ - `Python &lt;https://blogs.python-gsoc.org/en/joaodellaglis-blog/ready-for-review/&gt;`__ | ++---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 11 (14-08-2022)| A Refactor is Sometimes Needed | `FURY &lt;https://fury.gl/latest/posts/2023/2023-08-14-week-11-joaodellagli.html&gt;`__ - `Python &lt;https://blogs.python-gsoc.org/en/joaodellaglis-blog/a-refactor-is-sometimes-needed/&gt;`__ | ++---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 12 (21-08-2022)| Now That is (almost) a Wrap! | `FURY &lt;https://fury.gl/latest/posts/2023/2023-08-21-week-12-joaodellagli.html&gt;`__ - `Python &lt;https://blogs.python-gsoc.org/en/joaodellaglis-blog/week-12-now-that-is-almost-a-wrap/&gt;`__ | ++---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +</pre></div> +</div> +</aside> +</section> +</section> + + + Name: João Victor Dell Agli Floriano + + 2023-08-21T00:00:00-04:00 + + + https://fury.gl/posts/2023/2023-08-19-week-12-praneeth.html + Week 12: FileDialog Quest Begins! + 2023-08-19T00:00:00-04:00 + + Praneeth Shetty + + <section id="week-12-filedialog-quest-begins"> + +<section id="what-did-you-do-this-week"> +<h2>What did you do this week?</h2> +<p>During this week, I initiated my work on the <code class="docutils literal notranslate"><span class="pre">FileDialog</span></code> PR, which had been started by Soham. The initial version of the <code class="docutils literal notranslate"><span class="pre">FileDialog</span></code> can be found at <a class="reference external" href="https://github.com/fury-gl/fury/pull/294">#294</a>. To start, I focused on rebasing the PR. Since this PR was based on an older version, there were some updates to the overall UI structure that needed to be addressed for compatibility. While handling this, I identified a set of issues that I documented in the current PR <a class="reference external" href="https://github.com/fury-gl/fury/pull/832">#832</a>. These mainly revolved around:</p> +<ol class="arabic simple"> +<li><p>Resizing <code class="docutils literal notranslate"><span class="pre">FileDialog</span></code> and related components.</p></li> +<li><p>Rectifying the text overflow problem.</p></li> +<li><p>Dealing with a <code class="docutils literal notranslate"><span class="pre">ZeroDivisionError</span></code>.</p></li> +<li><p>Fixing the positioning of items in the <code class="docutils literal notranslate"><span class="pre">ListBox2D</span></code>.</p></li> +</ol> +<p>I systematically approached each of these challenges:</p> +<p><strong>Resizing FileMenu and Related Components:</strong> This was a fairly complex task since it involved intricate dependencies, such as the <code class="docutils literal notranslate"><span class="pre">FileDialog</span></code> relying on the <code class="docutils literal notranslate"><span class="pre">FileMenu</span></code>, which, in turn, was dependent on <code class="docutils literal notranslate"><span class="pre">ListBox2D</span></code> and <code class="docutils literal notranslate"><span class="pre">Panel2D</span></code> resizing. To make the process manageable, I decided to progress incrementally in a separate PR a bit later.</p> +<p><strong>Text Overflow Issue:</strong> The problem with text overflow was rooted in our previous approach, which involved executing these actions only when the <code class="docutils literal notranslate"><span class="pre">TextBlock2D</span></code> had a scene property. Although this approach suited the previous version of <code class="docutils literal notranslate"><span class="pre">TextBlock2D</span></code>, the recent refactoring led to the removal of this property. The scene was previously utilized to determine the text actor’s size. However, we had new methodologies to calculate these sizes, which are detailed in <a class="reference external" href="https://github.com/fury-gl/fury/pull/803">#803</a>.</p> +<img alt="Text Overflow Before" class="align-center" src="https://github.com/fury-gl/fury/assets/64432063/b001f9d3-a5e8-45ad-8605-85df595b5654" /> +<img alt="Text Overflow After" class="align-center" src="https://github.com/fury-gl/fury/assets/64432063/d3c9c3a3-e601-45ab-8975-2b1e98acf1d3" /> +<p><strong>Addressing ZeroDivisionError:</strong> The <code class="docutils literal notranslate"><span class="pre">ZeroDivisionError</span></code> emerged when the total number of values was the same as the number of slots. The issue lay in the separation of these values for calculating the scrollbar’s height parameter. Unfortunately, this calculation error occurred when this would return us zero while updating the scrollbar. To counter this, I implemented a conditional check to ascertain whether the value is zero or not.</p> +<p><strong>Correcting ``ListBox2D`` Item Positioning:</strong> Another challenge I encountered related to the improper positioning of <code class="docutils literal notranslate"><span class="pre">ListBox2D</span></code> item’s background. When a slot was not visible, its background was resized to zero, and visibility was set to off. Consequently, during the calculation of updated positions, the height was considered zero, leading to mispositioning. I resolved this by refraining from resizing and solely toggling visibility, achieving the desired result.</p> +<img alt="ListBox2D mispositioning Before" class="align-center" src="https://github.com/fury-gl/fury/assets/64432063/e2805934-b037-47fd-872c-0b284b298d3c" /> +<img alt="Fixed ListBox2D mispositioning" class="align-center" src="https://github.com/fury-gl/fury/assets/64432063/3bc1aabb-bb79-4e26-817d-a2a2ddd20ea3" /> +</section> +<section id="did-you-get-stuck-anywhere"> +<h2>Did you get stuck anywhere?</h2> +<p>Among the challenges I faced, one notable instance involved addressing the visibility issue in <code class="docutils literal notranslate"><span class="pre">TreeUI</span></code>. Despite my attempts at various solutions, none yielded the desired outcome. The <code class="docutils literal notranslate"><span class="pre">TreeUI</span></code> exhibited either full visibility or no visibility at all. In this situation, I sought guidance from my mentor to find a viable solution.</p> +</section> +<section id="what-is-coming-up-next"> +<h2>What is coming up next?</h2> +<p>The <code class="docutils literal notranslate"><span class="pre">FileDialog</span></code> implementation is nearly finalized, and my plan is to work on any review, feedback or suggestions that might arise. Following this, I will shift my attention towards addressing the <code class="docutils literal notranslate"><span class="pre">TreeUI</span></code>.</p> +</section> +</section> + + + During this week, I initiated my work on the FileDialog PR, which had been started by Soham. The initial version of the FileDialog can be found at #294. To start, I focused on rebasing the PR. Since this PR was based on an older version, there were some updates to the overall UI structure that needed to be addressed for compatibility. While handling this, I identified a set of issues that I documented in the current PR #832. These mainly revolved around: + + 2023-08-19T00:00:00-04:00 + + + https://fury.gl/posts/2023/2023-08-16-week-11-tvcastillod.html + Week 11 : Adjusting ODF implementation and looking for solutions on issues found + 2023-08-16T00:00:00-04:00 + + Tania Castillo + + <section id="week-11-adjusting-odf-implementation-and-looking-for-solutions-on-issues-found"> + +<section id="what-did-i-do-this-week"> +<h2>What did I do this week?</h2> +<p>I continued to experiment with the ODF glyph implementation. Thanks to one of my mentors I figured out how to get the missing data corresponding to the SH coefficients <span class="math notranslate nohighlight">\(a^l_m\)</span> part of the function <span class="math notranslate nohighlight">\(f(\theta, \phi)\)</span> described <a class="reference external" href="https://dipy.org/documentation/1.7.0/theory/sh_basis/">here</a>. I also was told to make sure to implement the correct SH basis since there are different definitions from the literature, I have to focus now in the one proposed by Descoteaux, described in <a class="reference external" href="https://onlinelibrary.wiley.com/doi/10.1002/mrm.21277">this paper</a>, which is labeled in <em>dipy</em> as <em>descoteaux07</em>. To do this I had to make a small adjustment to the base implementation that I took as a reference, from which I obtained a first result using SH of order 4.</p> +<img alt="https://user-images.githubusercontent.com/31288525/260909561-fd90033c-018a-465b-bd16-3586bb31ca36.png" class="align-center" src="https://user-images.githubusercontent.com/31288525/260909561-fd90033c-018a-465b-bd16-3586bb31ca36.png" style="width: 600px;" /> +<p>It appears that the results on the shape are about the same, except for the direction, but there is still work to be done.</p> +</section> +<section id="what-is-coming-up-next"> +<h2>What is coming up next?</h2> +<p>For now, there are 3 things I will continue to work on:</p> +<ul> +<li><p>The color and lighting. As these objects present curvatures with quite a bit of detail in some cases, this is something that requires more specific lighting work, in addition to having now not only one color but a color map.</p></li> +<li><p>The scaling. This is something I still don’t know how to deal with. I had to adjust it manually for now, but the idea is to find a relationship between the coefficients and the final object size so it can be automatically scaled, or maybe there is a proper way to pre-process this data before passing it to the shaders to get the right result at once.</p></li> +<li><aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-16-week-11-tvcastillod.rst</span>, line 2); <em><a href="#id1">backlink</a></em></p> +<p>Duplicate explicit target name: “here”.</p> +</aside> +<p>How to pass the information of the coefficients efficiently. Right now I’m creating one actor per glyph since I’m using a uniform array to pass the coefficients, but the idea is to pass all the data at once. I found several ideas <a class="reference external" href="https://stackoverflow.com/questions/7954927/passing-a-list-of-values-to-fragment-shader">here</a> of how to pass a list of values to the fragment shader directly, I just need to explore deeper how this can be done on <strong>FURY</strong>, and see which option is most suitable.</p> +</li> +</ul> +</section> +<section id="did-i-get-stuck-anywhere"> +<h2>Did I get stuck anywhere?</h2> +<p>All the points mentioned above are things that I tried to fix, however, it is something that I need to look at in much more detail and that I know is going to take me some time to understand and test before I get to the expected result. I hope to get some ideas from my mentors and fellow GSoC contributors on how I can proceed to deal with each of the problems.</p> +</section> +</section> + + + I continued to experiment with the ODF glyph implementation. Thanks to one of my mentors I figured out how to get the missing data corresponding to the SH coefficients a^l_m part of the function f(\theta, \phi) described here. I also was told to make sure to implement the correct SH basis since there are different definitions from the literature, I have to focus now in the one proposed by Descoteaux, described in this paper, which is labeled in dipy as descoteaux07. To do this I had to make a small adjustment to the base implementation that I took as a reference, from which I obtained a first result using SH of order 4. + + 2023-08-16T00:00:00-04:00 + + + https://fury.gl/posts/2023/2023-08-14-week-11-joaodellagli.html + Week 11: A Refactor is Sometimes Needed + 2023-08-14T00:00:00-04:00 + + João Victor Dell Agli Floriano + + <section id="week-11-a-refactor-is-sometimes-needed"> + +<p>Hello everyone, it’s time for another weekly blogpost! Today I am going to share some updates on the API refactoring +I was working on with my mentors.</p> +<section id="last-week-s-effort"> +<h2>Last Week’s Effort</h2> +<p>As I shared with you <span class="xref std std-doc">last week</span>, the first draft of my API was finally ready for review, as +I finished tweaking some remaining details missing. I was tasked with finding a good example of the usage of the tools we proposed, +and I started to do that, however after testing it with some examples, I figured out some significant bugs were to be fixed. Also, +after some reviews and hints from some of my mentors and other GSoC contributors, we realised that some refactoring should be done, +mainly focused on avoiding bad API usage from the user.</p> +</section> +<section id="so-how-did-it-go"> +<h2>So how did it go?</h2> +<p>Initially, I thought only one bug was the source of the issues the rendering presented, but it turned out to be two, which I will +explain further.</p> +<p>The first bug was related to scaling and misalignment of the KDE render. The render of the points being post-processed was not only +with sizes different from the original set size, but it was also misaligned, making it appear in positions different from the points’ +original ones. After some time spent, I figured out the bug was related to the texture coordinates I was using. Before, this is how +my fragment shader looked:</p> +<div class="highlight-C notranslate"><div class="highlight"><pre><span></span><span class="n">vec2</span><span class="w"> </span><span class="n">res_factor</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">vec2</span><span class="p">(</span><span class="n">res</span><span class="p">.</span><span class="n">y</span><span class="o">/</span><span class="n">res</span><span class="p">.</span><span class="n">x</span><span class="p">,</span><span class="w"> </span><span class="mf">1.0</span><span class="p">);</span> +<span class="n">vec2</span><span class="w"> </span><span class="n">tex_coords</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">res_factor</span><span class="o">*</span><span class="n">normalizedVertexMCVSOutput</span><span class="p">.</span><span class="n">xy</span><span class="o">*</span><span class="mf">0.5</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mf">0.5</span><span class="p">;</span> +<span class="kt">float</span><span class="w"> </span><span class="n">intensity</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">texture</span><span class="p">(</span><span class="n">screenTexture</span><span class="p">,</span><span class="w"> </span><span class="n">tex_coords</span><span class="p">).</span><span class="n">r</span><span class="p">;</span> +</pre></div> +</div> +<p>It turns out using this texture coordinates for <em>this case</em> was not the best choice, as even though it matches the fragment positions, +the idea here was to render the offscreen window, which has the same size as the onscreen one, to the billboard actor. With that in mind, +I realised the best choice was using texture coordinates that matched the whole screen positions, coordinates that were derived from the +<code class="docutils literal notranslate"><span class="pre">gl_FragCoord.xy</span></code>, being the division of that by the resolution of the screen, for normalization. Below, the change made:</p> +<div class="highlight-C notranslate"><div class="highlight"><pre><span></span><span class="n">vec2</span><span class="w"> </span><span class="n">tex_coords</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">gl_FragCoord</span><span class="p">.</span><span class="n">xy</span><span class="o">/</span><span class="n">res</span><span class="p">;</span> +<span class="kt">float</span><span class="w"> </span><span class="n">intensity</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">texture</span><span class="p">(</span><span class="n">screenTexture</span><span class="p">,</span><span class="w"> </span><span class="n">tex_coords</span><span class="p">).</span><span class="n">r</span><span class="p">;</span> +</pre></div> +</div> +<p>This change worked initially, although with some problems, that later revealed the resolution of the offscreen window needed to be +updated inside the callback function as well. Fixing that, it was perfectly aligned and scaled!</p> +<p>The second bug was related with the handling of the bandwidth, former sigma parameter. I realised I wasn’t dealing properly with the option of the user passing only +one single bandwidth value being passed, so when trying that, only the first point was being rendered. I also fixed that and it worked, +so cheers!</p> +<p>As I previously said, the bugs were not the only details I spent my time on last week. Being reviewed, the API design, even +though simple, showed itself vulnerable to bad usage from the user side, requiring some changes. The changes suggested by mentors were, +to, basically, take the <code class="docutils literal notranslate"><span class="pre">kde</span></code> method out of the <code class="docutils literal notranslate"><span class="pre">EffectManager</span></code> class, and create a new class from it inside an <code class="docutils literal notranslate"><span class="pre">effects</span></code> module, +like it was a special effects class. With this change, the KDE setup would go from:</p> +<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">em</span> <span class="o">=</span> <span class="n">EffectManager</span><span class="p">(</span><span class="n">show_manager</span><span class="p">)</span> + +<span class="n">kde_actor</span> <span class="o">=</span> <span class="n">em</span><span class="o">.</span><span class="n">kde</span><span class="p">(</span><span class="o">...</span><span class="p">)</span> + +<span class="n">show_manager</span><span class="o">.</span><span class="n">scene</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">kde_actor</span><span class="p">)</span> +</pre></div> +</div> +<p>To:</p> +<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">em</span> <span class="o">=</span> <span class="n">EffectManager</span><span class="p">(</span><span class="n">show_manager</span><span class="p">)</span> + +<span class="n">kde_effect</span> <span class="o">=</span> <span class="n">KDE</span><span class="p">(</span><span class="o">...</span><span class="p">)</span> + +<span class="n">em</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">kde_effect</span><span class="p">)</span> +</pre></div> +</div> +<p>Not a gain in line shortening, however, a gain in security, as preventing users from misusing the kde_actor. Something worth noting is +that I learned how to use the <code class="docutils literal notranslate"><span class="pre">functools.partial</span></code> function, that allowed me to partially call the callback function with only some +parameters passed.</p> +</section> +<section id="this-week-s-goals"> +<h2>This Week’s Goals</h2> +<p>Having that refactoring made, now I am awaiting for a second review so we could finally wrap it up and merge the first stage of this API. +With that being done, I will write the final report and wrap this all up.</p> +<p>Let’s get to work!</p> +</section> +</section> + + + Hello everyone, it’s time for another weekly blogpost! Today I am going to share some updates on the API refactoring +I was working on with my mentors. + + 2023-08-14T00:00:00-04:00 + + + https://fury.gl/posts/2023/2023-08-12-week-11-praneeth.html + Week 11: Bye Bye SpinBox + 2023-08-12T00:00:00-04:00 + + Praneeth Shetty + + <section id="week-11-bye-bye-spinbox"> + +<section id="what-did-you-do-this-week"> +<h2>What did you do this week?</h2> +<p>Building upon the progress of the previous week, a major milestone was reached with the merging of PR <a class="reference external" href="https://github.com/fury-gl/fury/pull/830">#830</a>. This PR added essential “getters” and “setters” for the new features of <code class="docutils literal notranslate"><span class="pre">TextBlock</span></code>, making it easier to handle changes. This, in turn, facilitated the integration of <code class="docutils literal notranslate"><span class="pre">SpinBoxUI</span></code> with the updated <code class="docutils literal notranslate"><span class="pre">TextBlock</span></code>.</p> +<p>However, while working on <code class="docutils literal notranslate"><span class="pre">SpinBoxUI</span></code>, a critical issue emerged. As <code class="docutils literal notranslate"><span class="pre">SpinBoxUI</span></code> allows users to input characters and symbols into an editable textbox, it posed a risk of program crashes due to invalid inputs. To counter this, I introduced a validation check to ensure that the input was a valid number. If valid, the input was converted; otherwise, it reverted to the previous value. After thorough testing and review, PR <a class="reference external" href="https://github.com/fury-gl/fury/pull/499">#499</a> was successfully merged.</p> +<img alt="SpinBoxUI" class="align-center" src="https://user-images.githubusercontent.com/64432063/261409747-511e535b-185c-4e70-aaa8-5296c93e5344.gif" style="width: 500px;" /> +<p>Meanwhile, a concern with the textbox’s behavior was identified when <code class="docutils literal notranslate"><span class="pre">SpinBoxUI</span></code> was scaled to a larger size. Specifically, the text occasionally touched the top or bottom boundary, creating an overflow appearance. Although initial solutions were attempted, the complexity of the issue required further consideration. This issue has been documented in more detail in Issue <a class="reference external" href="https://github.com/fury-gl/fury/pull/838">#838</a>, where it is marked as a low-priority item.</p> +<figure class="align-center"> +<img alt="TextBlock2D text positioning issue" src="https://user-images.githubusercontent.com/64432063/133194003-53e2dac6-31e0-444e-b7f1-a9e71545f560.jpeg" /> +</figure> +</section> +<section id="did-you-get-stuck-anywhere"> +<h2>Did you get stuck anywhere?</h2> +<p>The challenge of the week centered around addressing the textbox’s overflow behavior in <code class="docutils literal notranslate"><span class="pre">SpinBoxUI</span></code>.</p> +</section> +<section id="what-is-coming-up-next"> +<h2>What is coming up next?</h2> +<p>Looking ahead, the focus remains on refining the FileDialog component, as the significant progress with <code class="docutils literal notranslate"><span class="pre">TextBlock</span></code> and <code class="docutils literal notranslate"><span class="pre">SpinBoxUI</span></code> prepares us to shift attention to other aspects of development.</p> +</section> +</section> + + + Building upon the progress of the previous week, a major milestone was reached with the merging of PR #830. This PR added essential “getters” and “setters” for the new features of TextBlock, making it easier to handle changes. This, in turn, facilitated the integration of SpinBoxUI with the updated TextBlock. + + 2023-08-12T00:00:00-04:00 + + + https://fury.gl/posts/2023/2023-08-08-week-10-tvcastillod.html + Week 10 : Start of SH implementation experiments + 2023-08-08T00:00:00-04:00 + + Tania Castillo + + <section id="week-10-start-of-sh-implementation-experiments"> + +<section id="what-did-i-do-this-week"> +<h2>What did I do this week?</h2> +<p>I started formally working on SH implementation. I was told to start first doing a simple program where I can modify in real-time the order <span class="math notranslate nohighlight">\(l\)</span> and degree <span class="math notranslate nohighlight">\(m\)</span>, parameters corresponding to the <a class="reference external" href="https://dipy.org/documentation/1.7.0/theory/sh_basis/">Spherical Harmonics function</a> <span class="math notranslate nohighlight">\(Y^m_l(\theta,\phi)=\)</span>, based on <a class="reference external" href="https://github.com/lenixlobo/fury/commit/2b7ce7a71fd422dc5a250d7b49e1eea2db9d3bce">previous work</a>. That is just one part of the final ODF calculation, but here is what a first experimental script looks like.</p> +<img alt="https://user-images.githubusercontent.com/31288525/260910073-10b0edd4-40e3-495c-85ad-79993aef3b19.png" class="align-center" src="https://user-images.githubusercontent.com/31288525/260910073-10b0edd4-40e3-495c-85ad-79993aef3b19.png" style="width: 600px;" /> +<p>I did it in order to make sure it was visually correct and also to understand better how those 2 parameters are related and need to be incorporated into the final calculation. There is one issue at first sight that needs to be addressed, and that is the scaling, since for SH with a degree near 0, the object gets out of bounds.</p> +</section> +<section id="what-is-coming-up-next"> +<h2>What is coming up next?</h2> +<p>I will keep polishing details from my current open PRs, hopefully, I will get another PR merged before the last GSoC week.</p> +</section> +<section id="did-i-get-stuck-anywhere"> +<h2>Did I get stuck anywhere?</h2> +<p>Not sure about how to use the current implementation I have to get similar visualizations made with <em>odf_slicer</em>, since the parameters that the function receive are different, so I need to take a deeper look and see where it might be the connection or if I should make some adjustments on the parameters.</p> +</section> +</section> + + + I started formally working on SH implementation. I was told to start first doing a simple program where I can modify in real-time the order l and degree m, parameters corresponding to the Spherical Harmonics function Y^m_l(\theta,\phi)=, based on previous work. That is just one part of the final ODF calculation, but here is what a first experimental script looks like. + + 2023-08-08T00:00:00-04:00 + + diff --git a/v0.10.x/blog/category/news.html b/v0.10.x/blog/category/news.html new file mode 100644 index 000000000..ad073acec --- /dev/null +++ b/v0.10.x/blog/category/news.html @@ -0,0 +1,537 @@ + + + + + + + Posts in news — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + + + + + +
+ +
+
+
+ +
+ + + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/blog/category/news/atom.xml b/v0.10.x/blog/category/news/atom.xml new file mode 100644 index 000000000..31f7a2089 --- /dev/null +++ b/v0.10.x/blog/category/news/atom.xml @@ -0,0 +1,28 @@ + + + https://fury.gl/ + Blog - Posts in news + 2024-02-29T15:43:57.636652+00:00 + + + ABlog + + https://fury.gl/posts/2019/2019-06-19-brain-art.html + Success on Brain Art Competition using FURY + 2019-06-19T00:00:00-04:00 + + Serge Koudoro + + <section id="success-on-brain-art-competition-using-fury"> + +<p>Congratulations to <a class="reference external" href="https://github.com/dmreagan">David</a> who won the <a class="reference external" href="https://www.neurobureau.org/galleries/brain-art-competition-2019-2/">OHBM BrainArt (MELPOMENE category)</a> by using DIPY and FURY!!!</p> +<p>As you can see below, really beautiful streamlines effect created during shader experiment/fail!</p> +<img alt="Brain Streamlines Shader Experiment" class="align-center" src="https://fury.gl/_images/Melpomene_Brain-Streamlines-shader-experiment_by_David-Reagan.jpg" /> +</section> + + + Congratulations to David who won the OHBM BrainArt (MELPOMENE category) by using DIPY and FURY!!! + + 2019-06-19T00:00:00-04:00 + + diff --git a/v0.10.x/blog/category/release.html b/v0.10.x/blog/category/release.html new file mode 100644 index 000000000..fe8d10c95 --- /dev/null +++ b/v0.10.x/blog/category/release.html @@ -0,0 +1,1402 @@ + + + + + + + Posts in release — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +
+

+ + Posts in + + release + +

+ + +
+

+ FURY 0.9.0 Released +

+
    +
  • + + + 15 April 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Serge Koudoro + + + +
  • + + + + +
  • + + + Category: + + + + + release + + + +
  • + + +
  • + + + + Tag: + + + + + fury + + + +
  • + + +
    +
+

The FURY project is happy to announce the release of FURY 0.9.0! +FURY is a free and open source software library for scientific visualization and 3D animations.

+

+ +

Read more ...

+
+
+ +
+

+ FURY 0.8.0 Released +

+
    +
  • + + + 31 January 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Serge Koudoro + + + +
  • + + + + +
  • + + + Category: + + + + + release + + + +
  • + + +
  • + + + + Tag: + + + + + fury + + + +
  • + + +
    +
+

The FURY project is happy to announce the release of FURY 0.8.0! +FURY is a free and open source software library for scientific visualization and 3D animations.

+

+ +

Read more ...

+
+
+ +
+

+ FURY 0.7.0 Released +

+
    +
  • + + + 03 August 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Serge Koudoro + + + +
  • + + + + +
  • + + + Category: + + + + + release + + + +
  • + + +
  • + + + + Tag: + + + + + fury + + + +
  • + + +
    +
+

The FURY project is happy to announce the release of FURY 0.7.1! +FURY is a free and open source software library for scientific visualization and 3D animations.

+

+ +

Read more ...

+
+
+ +
+

+ FURY 0.7.0 Released +

+
    +
  • + + + 13 March 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Serge Koudoro + + + +
  • + + + + +
  • + + + Category: + + + + + release + + + +
  • + + +
  • + + + + Tag: + + + + + fury + + + +
  • + + +
    +
+

The FURY project is happy to announce the release of FURY 0.7.0! +FURY is a free and open source software library for scientific visualization and 3D animations.

+

+ +

Read more ...

+
+
+ +
+

+ FURY 0.6.1 Released +

+
    +
  • + + + 18 August 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Serge Koudoro + + + +
  • + + + + +
  • + + + Category: + + + + + release + + + +
  • + + +
  • + + + + Tag: + + + + + fury + + + +
  • + + +
    +
+

The FURY project is happy to announce the release of FURY 0.6.1! +FURY is a free and open source software library for scientific visualization and 3D animations.

+

+ +

Read more ...

+
+
+ +
+

+ FURY 0.6.0 Released +

+
    +
  • + + + 20 July 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Serge Koudoro + + + +
  • + + + + +
  • + + + Category: + + + + + release + + + +
  • + + +
  • + + + + Tag: + + + + + fury + + + +
  • + + +
    +
+

The FURY project is happy to announce the release of FURY 0.6.0! +FURY is a free and open source software library for scientific visualization and 3D animations.

+

+ +

Read more ...

+
+
+ +
+

+ FURY 0.5.1 Released +

+
    +
  • + + + 09 April 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Serge Koudoro + + + +
  • + + + + +
  • + + + Category: + + + + + release + + + +
  • + + +
  • + + + + Tag: + + + + + fury + + + +
  • + + +
    +
+

The FURY project is happy to announce the release of FURY 0.5.1! +FURY is a free and open source software library for scientific visualization and 3D animations.

+

+ +

Read more ...

+
+
+ +
+

+ FURY 0.4.0 Released +

+
    +
  • + + + 29 October 2019 + +
  • +
    + + +
  • + + + Author: + + + + + Serge Koudoro + + + +
  • + + + + +
  • + + + Category: + + + + + release + + + +
  • + + +
  • + + + + Tag: + + + + + fury + + + +
  • + + +
    +
+

The FURY project is happy to announce the release of FURY 0.4.0! +FURY is a free and open source software library for scientific visualization and 3D animations.

+

+ +

Read more ...

+
+
+ +
+

+ FURY 0.3.0 Released +

+
    +
  • + + + 02 August 2019 + +
  • +
    + + +
  • + + + Author: + + + + + Serge Koudoro + + + +
  • + + + + +
  • + + + Category: + + + + + release + + + +
  • + + +
  • + + + + Tag: + + + + + fury + + + +
  • + + +
    +
+

The FURY project is happy to announce the release of FURY 0.3.0! +FURY is a free and open source software library for scientific visualization and 3D animations.

+

+ +

Read more ...

+
+
+ +
+

+ FURY 0.2.0 Released +

+
    +
  • + + + 08 March 2019 + +
  • +
    + + +
  • + + + Author: + + + + + Serge Koudoro + + + +
  • + + + + +
  • + + + Category: + + + + + release + + + +
  • + + +
  • + + + + Tag: + + + + + fury + + + +
  • + + +
    +
+

The FURY project is happy to announce the release of FURY 0.2.0! +FURY is a free and open source software library for scientific visualization and 3D animations.

+

+ +

Read more ...

+
+
+ +
+

+ FURY 0.1.4 Released +

+
    +
  • + + + 26 November 2018 + +
  • +
    + + +
  • + + + Author: + + + + + Serge Koudoro + + + +
  • + + + + +
  • + + + Category: + + + + + release + + + +
  • + + +
  • + + + + Tag: + + + + + fury + + + +
  • + + +
    +
+

The FURY project is happy to announce the release of FURY 0.1.4! +FURY is a free and open source software library for scientific visualization and 3D animations.

+

+ +

Read more ...

+
+
+ +
+

+ FURY 0.1.3 Released +

+
    +
  • + + + 31 October 2018 + +
  • +
    + + +
  • + + + Author: + + + + + Serge Koudoro + + + +
  • + + + + +
  • + + + Category: + + + + + release + + + +
  • + + +
  • + + + + Tag: + + + + + fury + + + +
  • + + +
    +
+

The FURY project is happy to announce the release of FURY 0.1.3! +FURY is a free and open source software library for scientific visualization and 3D animations.

+

+ +

Read more ...

+
+
+ +
+

+ FURY 0.1.0 Released +

+
    +
  • + + + 21 September 2018 + +
  • +
    + + +
  • + + + Author: + + + + + Serge Koudoro + + + +
  • + + + + +
  • + + + Category: + + + + + release + + + +
  • + + +
  • + + + + Tag: + + + + + fury + + + +
  • + + +
    +
+

The FURY project is happy to announce the release of FURY 0.1.0! +FURY is a free and open source software library for scientific visualization and 3D animations.

+

+ +

Read more ...

+
+
+ + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/blog/category/release/atom.xml b/v0.10.x/blog/category/release/atom.xml new file mode 100644 index 000000000..1e81ed83c --- /dev/null +++ b/v0.10.x/blog/category/release/atom.xml @@ -0,0 +1,639 @@ + + + https://fury.gl/ + Blog - Posts in release + 2024-02-29T15:43:57.637485+00:00 + + + ABlog + + https://fury.gl/posts/2023/2023-04-14-release-announcement.html + FURY 0.9.0 Released + 2023-04-15T00:00:00-04:00 + + Serge Koudoro + + <section id="fury-0-9-0-released"> + +<p>The FURY project is happy to announce the release of FURY 0.9.0! +FURY is a free and open source software library for scientific visualization and 3D animations.</p> +<p>You can show your support by <a class="reference external" href="https://github.com/fury-gl/fury/stargazers">adding a star</a> on FURY github project.</p> +<p>This Release is mainly a maintenance release. The <strong>major highlights</strong> of this release are:</p> +<ul class="simple"> +<li><p>New Streaming System added.</p></li> +<li><p>Large improvement of Signed Distance Functions actors (SDF).</p></li> +<li><p>Continuous Integration (CI) platform updated. Migrate Windows CI from Azure to Github Actions</p></li> +<li><p>Migration from setuptools to hatching. versioning system updated also.</p></li> +<li><p>New module fury.animation added.</p></li> +<li><p>New module fury.gltf added. Module to support glTF 2.0.</p></li> +<li><p>Multiple tutorials added and updated.</p></li> +<li><p>Documentation updated.</p></li> +<li><p>Website updated.</p></li> +</ul> +<div class="admonition note"> +<p class="admonition-title">Note</p> +<p>The complete release notes are available <a class="reference internal" href="../../release_notes/releasev0.9.0.html#releasev0-9-0"><span class="std std-ref">here</span></a></p> +</div> +<p><strong>To upgrade or install FURY</strong></p> +<p>Run the following command in your terminal:</p> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">pip</span> <span class="n">install</span> <span class="o">--</span><span class="n">upgrade</span> <span class="n">fury</span> +</pre></div> +</div> +<p>or:</p> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">conda</span> <span class="n">install</span> <span class="o">-</span><span class="n">c</span> <span class="n">conda</span><span class="o">-</span><span class="n">forge</span> <span class="n">fury</span> +</pre></div> +</div> +<p><strong>Questions or suggestions?</strong></p> +<p>For any questions go to <a class="reference external" href="http://fury.gl">http://fury.gl</a>, or send an e-mail to <a class="reference external" href="mailto:fury&#37;&#52;&#48;python&#46;org">fury<span>&#64;</span>python<span>&#46;</span>org</a> +We can also join our <a class="reference external" href="https://discord.gg/6btFPPj">discord community</a></p> +<p>We would like to thanks to <a class="reference internal" href="../../community.html#community"><span class="std std-ref">all contributors</span></a> for this release:</p> +<ul class="simple"> +<li><p>Anand Shivam</p></li> +<li><p>Antriksh Misri</p></li> +<li><p>Bruno Messias</p></li> +<li><p>Dwij Raj Hari</p></li> +<li><p>Eleftherios Garyfallidis</p></li> +<li><p>Filipi Nascimento Silva</p></li> +<li><p>Francois Rheault</p></li> +<li><p>Frank Cerasoli</p></li> +<li><p>Javier Guaje</p></li> +<li><p>Johny Daras</p></li> +<li><p>Mohamed Agour</p></li> +<li><p>Nasim Anousheh</p></li> +<li><p>Praneeth Shetty</p></li> +<li><p>Rohit Kharsan</p></li> +<li><p>Sara Hamza</p></li> +<li><p>Serge Koudoro</p></li> +<li><p>Siddharth Gautam</p></li> +<li><p>Soham Biswas</p></li> +<li><p>Sreekar Chigurupati</p></li> +<li><p>Tania Castillo</p></li> +<li><p>Zhiwen Shi</p></li> +<li><p>maharshigor</p></li> +<li><p>sailesh</p></li> +<li><p>sparshg</p></li> +</ul> +<p>On behalf of the <a class="reference internal" href="../../community.html#community"><span class="std std-ref">FURY developers</span></a>,</p> +<p>Serge K.</p> +</section> + + + The FURY project is happy to announce the release of FURY 0.9.0! +FURY is a free and open source software library for scientific visualization and 3D animations. + + 2023-04-15T00:00:00-04:00 + + + https://fury.gl/posts/2022/2022-01-31-release-announcement.html + FURY 0.8.0 Released + 2022-01-31T00:00:00-05:00 + + Serge Koudoro + + <section id="fury-0-8-0-released"> + +<p>The FURY project is happy to announce the release of FURY 0.8.0! +FURY is a free and open source software library for scientific visualization and 3D animations.</p> +<p>You can show your support by <a class="reference external" href="https://github.com/fury-gl/fury/stargazers">adding a star</a> on FURY github project.</p> +<p>This Release is mainly a maintenance release. The <strong>major highlights</strong> of this release are:</p> +<ul class="simple"> +<li><p>New Physically Based Rendering (PBR) added. It includes anisotropic rotation and index of refraction among other material properties.</p></li> +<li><p>New Principled BRDF shader unique to FURY added. BRDF stands for bidirectional reflectance distribution function.</p></li> +<li><p>VTK 9.1.0 defined as minimum version.</p></li> +<li><p>Continuous Integration (CI) platform updated.</p></li> +<li><p>New actors added (Rhombicuboctahedron, Pentagonal Prism).</p></li> +<li><p>New UI layouts added (Vertical and Horizontal).</p></li> +<li><p>New module fury.molecular added.</p></li> +<li><p>New module fury.lib added. Module improved loading speed.</p></li> +<li><p>Demos added and updated.</p></li> +<li><p>Documentation updated.</p></li> +</ul> +<div class="admonition note"> +<p class="admonition-title">Note</p> +<p>The complete release notes are available <a class="reference internal" href="../../release_notes/releasev0.8.0.html#releasev0-8-0"><span class="std std-ref">here</span></a></p> +</div> +<p><strong>To upgrade or install FURY</strong></p> +<p>Run the following command in your terminal:</p> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">pip</span> <span class="n">install</span> <span class="o">--</span><span class="n">upgrade</span> <span class="n">fury</span> +</pre></div> +</div> +<p>or:</p> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">conda</span> <span class="n">install</span> <span class="o">-</span><span class="n">c</span> <span class="n">conda</span><span class="o">-</span><span class="n">forge</span> <span class="n">fury</span> +</pre></div> +</div> +<p><strong>Questions or suggestions?</strong></p> +<p>For any questions go to <a class="reference external" href="http://fury.gl">http://fury.gl</a>, or send an e-mail to <a class="reference external" href="mailto:fury&#37;&#52;&#48;python&#46;org">fury<span>&#64;</span>python<span>&#46;</span>org</a> +We can also join our <a class="reference external" href="https://discord.gg/6btFPPj">discord community</a></p> +<p>We would like to thanks to <a class="reference internal" href="../../community.html#community"><span class="std std-ref">all contributors</span></a> for this release:</p> +<ul class="simple"> +<li><p>Anand Shivam</p></li> +<li><p>Antriksh Misri</p></li> +<li><p>Bruno Messias</p></li> +<li><p>Eleftherios Garyfallidis</p></li> +<li><p>Javier Guaje</p></li> +<li><p>Marc-Alexandre Côté</p></li> +<li><p>Meha Bhalodiya</p></li> +<li><p>Praneeth Shetty</p></li> +<li><p>PrayasJ</p></li> +<li><p>Sajag Swami</p></li> +<li><p>Serge Koudoro</p></li> +<li><p>Shivam Anand</p></li> +</ul> +<p>On behalf of the <a class="reference internal" href="../../community.html#community"><span class="std std-ref">FURY developers</span></a>,</p> +<p>Serge K.</p> +</section> + + + The FURY project is happy to announce the release of FURY 0.8.0! +FURY is a free and open source software library for scientific visualization and 3D animations. + + 2022-01-31T00:00:00-05:00 + + + https://fury.gl/posts/2021/2021-08-03-release-announcement.html + FURY 0.7.0 Released + 2021-08-03T00:00:00-04:00 + + Serge Koudoro + + <section id="fury-0-7-0-released"> + +<p>The FURY project is happy to announce the release of FURY 0.7.1! +FURY is a free and open source software library for scientific visualization and 3D animations.</p> +<p>You can show your support by <a class="reference external" href="https://github.com/fury-gl/fury/stargazers">adding a star</a> on FURY github project.</p> +<p>This Release is mainly a maintenance release. The <strong>major highlights</strong> of this release are:</p> +<ul class="simple"> +<li><p>FURY paper added.</p></li> +<li><p>Fast selection of multiple objects added.</p></li> +<li><p>UI refactored.</p></li> +<li><p>Tests coverage increased.</p></li> +<li><p>New actor (Marker) added.</p></li> +<li><p>New primitive (Triangular Prism) added.</p></li> +<li><p>Demos added and updated.</p></li> +<li><p>Large Documentation Update.</p></li> +</ul> +<div class="admonition note"> +<p class="admonition-title">Note</p> +<p>The complete release notes are available <a class="reference internal" href="../../release_notes/releasev0.7.1.html#releasev0-7-1"><span class="std std-ref">here</span></a></p> +</div> +<p><strong>To upgrade or install FURY</strong></p> +<p>Run the following command in your terminal:</p> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">pip</span> <span class="n">install</span> <span class="o">--</span><span class="n">upgrade</span> <span class="n">fury</span> +</pre></div> +</div> +<p>or:</p> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">conda</span> <span class="n">install</span> <span class="o">-</span><span class="n">c</span> <span class="n">conda</span><span class="o">-</span><span class="n">forge</span> <span class="n">fury</span> +</pre></div> +</div> +<p><strong>Questions or suggestions?</strong></p> +<p>For any questions go to <a class="reference external" href="http://fury.gl">http://fury.gl</a>, or send an e-mail to <a class="reference external" href="mailto:fury&#37;&#52;&#48;python&#46;org">fury<span>&#64;</span>python<span>&#46;</span>org</a> +We can also join our <a class="reference external" href="https://discord.gg/6btFPPj">discord community</a></p> +<p>We would like to thanks to <a class="reference internal" href="../../community.html#community"><span class="std std-ref">all contributors</span></a> for this release:</p> +<ul class="simple"> +<li><p>Amit Chaudhari</p></li> +<li><p>Antriksh Misri</p></li> +<li><p>Bruno Messias</p></li> +<li><p>Daniel S. Katz</p></li> +<li><p>Eleftherios Garyfallidis</p></li> +<li><p>Gurdit Siyan</p></li> +<li><p>Javier Guaje</p></li> +<li><p>Jhalak Gupta</p></li> +<li><p>LoopThrough-i-j</p></li> +<li><p>MIHIR</p></li> +<li><p>Praneeth Shetty</p></li> +<li><p>Sajag Swami</p></li> +<li><p>Serge Koudoro</p></li> +<li><p>Hariharan Ayappane</p></li> +</ul> +<p>On behalf of the <a class="reference internal" href="../../community.html#community"><span class="std std-ref">FURY developers</span></a>,</p> +<p>Serge K.</p> +</section> + + + The FURY project is happy to announce the release of FURY 0.7.1! +FURY is a free and open source software library for scientific visualization and 3D animations. + + 2021-08-03T00:00:00-04:00 + + + https://fury.gl/posts/2021/2021-03-13-release-announcement.html + FURY 0.7.0 Released + 2021-03-13T00:00:00-05:00 + + Serge Koudoro + + <section id="fury-0-7-0-released"> + +<p>The FURY project is happy to announce the release of FURY 0.7.0! +FURY is a free and open source software library for scientific visualization and 3D animations.</p> +<p>You can show your support by <a class="reference external" href="https://github.com/fury-gl/fury/stargazers">adding a star</a> on FURY github project.</p> +<p>This Release is mainly a maintenance release. The <strong>major highlights</strong> of this release are:</p> +<ul class="simple"> +<li><p>New SDF actors added.</p></li> +<li><p>Materials module added.</p></li> +<li><p>ODF slicer actor performance improved.</p></li> +<li><p>New primitive (Cylinder) added.</p></li> +<li><p>Compatibility with VTK 9 added.</p></li> +<li><p>Five new demos added.</p></li> +<li><p>Large Documentation Update.</p></li> +<li><p>Migration from Travis to Github Action.</p></li> +</ul> +<div class="admonition note"> +<p class="admonition-title">Note</p> +<p>The complete release notes are available <a class="reference internal" href="../../release_notes/releasev0.7.0.html#releasev0-7-0"><span class="std std-ref">here</span></a></p> +</div> +<p><strong>To upgrade or install FURY</strong></p> +<p>Run the following command in your terminal:</p> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">pip</span> <span class="n">install</span> <span class="o">--</span><span class="n">upgrade</span> <span class="n">fury</span> +</pre></div> +</div> +<p>or:</p> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">conda</span> <span class="n">install</span> <span class="o">-</span><span class="n">c</span> <span class="n">conda</span><span class="o">-</span><span class="n">forge</span> <span class="n">fury</span> +</pre></div> +</div> +<p><strong>Questions or suggestions?</strong></p> +<p>For any questions go to <a class="reference external" href="http://fury.gl">http://fury.gl</a>, or send an e-mail to <a class="reference external" href="mailto:fury&#37;&#52;&#48;python&#46;org">fury<span>&#64;</span>python<span>&#46;</span>org</a> +We can also join our <a class="reference external" href="https://discord.gg/6btFPPj">discord community</a></p> +<p>We would like to thanks to <a class="reference internal" href="../../community.html#community"><span class="std std-ref">all contributors</span></a> for this release:</p> +<ul class="simple"> +<li><p>Eleftherios Garyfallidis</p></li> +<li><p>Serge Koudoro</p></li> +<li><p>Charles Poirier</p></li> +<li><p>Javier Guaje</p></li> +<li><p>Soham Biswas</p></li> +<li><p>Sajag Swami</p></li> +<li><p>Lenix Lobo</p></li> +<li><p>Pietro Astolfi</p></li> +<li><p>Sanjay Marreddi</p></li> +<li><p>Tushar</p></li> +<li><p>ganimtron-10</p></li> +<li><p>haran2001</p></li> +<li><p>Aju100</p></li> +<li><p>Aman Soni</p></li> +</ul> +<p>On behalf of the <a class="reference internal" href="../../community.html#community"><span class="std std-ref">FURY developers</span></a>,</p> +<p>Serge K.</p> +</section> + + + The FURY project is happy to announce the release of FURY 0.7.0! +FURY is a free and open source software library for scientific visualization and 3D animations. + + 2021-03-13T00:00:00-05:00 + + + https://fury.gl/posts/2020/2020-08-18-release-announcement.html + FURY 0.6.1 Released + 2020-08-18T00:00:00-04:00 + + Serge Koudoro + + <section id="fury-0-6-1-released"> + +<p>The FURY project is happy to announce the release of FURY 0.6.1! +FURY is a free and open source software library for scientific visualization and 3D animations.</p> +<p>You can show your support by <a class="reference external" href="https://github.com/fury-gl/fury/stargazers">adding a star</a> on FURY github project.</p> +<p>This Release is mainly a maintenance release. The <strong>major highlights</strong> of this release are:</p> +<ul class="simple"> +<li><p>Added Shaders Manager.</p></li> +<li><p>Standardized colors across API.</p></li> +<li><p>Added a new UI Tab.</p></li> +<li><p>Added Physics Engine Tutorial.</p></li> +<li><p>Large documentation update, examples and tutorials (4 new).</p></li> +<li><p>Increased tests coverage and code quality.</p></li> +</ul> +<div class="admonition note"> +<p class="admonition-title">Note</p> +<p>The complete release notes are available <a class="reference internal" href="../../release_notes/releasev0.6.1.html#releasev0-6-1"><span class="std std-ref">here</span></a></p> +</div> +<p><strong>To upgrade or install FURY</strong></p> +<p>Run the following command in your terminal:</p> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">pip</span> <span class="n">install</span> <span class="o">--</span><span class="n">upgrade</span> <span class="n">fury</span> +</pre></div> +</div> +<p>or:</p> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">conda</span> <span class="n">install</span> <span class="o">-</span><span class="n">c</span> <span class="n">conda</span><span class="o">-</span><span class="n">forge</span> <span class="n">fury</span> +</pre></div> +</div> +<p><strong>Questions or suggestions?</strong></p> +<p>For any questions go to <a class="reference external" href="http://fury.gl">http://fury.gl</a>, or send an e-mail to <a class="reference external" href="mailto:fury&#37;&#52;&#48;python&#46;org">fury<span>&#64;</span>python<span>&#46;</span>org</a> +We can also join our <a class="reference external" href="https://discord.gg/6btFPPj">discord community</a></p> +<p>We would like to thanks to <a class="reference internal" href="../../community.html#community"><span class="std std-ref">all contributors</span></a> for this release:</p> +<ul class="simple"> +<li><p>Eleftherios Garyfallidis</p></li> +<li><p>Javier Guaje</p></li> +<li><p>Lenix Lobo</p></li> +<li><p>Melina Raglin</p></li> +<li><p>Nasim Anousheh</p></li> +<li><p>Serge Koudoro</p></li> +<li><p>Soham Biswas</p></li> +<li><p>Vivek Choudhary</p></li> +</ul> +<p>On behalf of the <a class="reference internal" href="../../community.html#community"><span class="std std-ref">FURY developers</span></a>,</p> +<p>Serge K.</p> +</section> + + + The FURY project is happy to announce the release of FURY 0.6.1! +FURY is a free and open source software library for scientific visualization and 3D animations. + + 2020-08-18T00:00:00-04:00 + + + https://fury.gl/posts/2020/2020-07-20-release-announcement.html + FURY 0.6.0 Released + 2020-07-20T00:00:00-04:00 + + Serge Koudoro + + <section id="fury-0-6-0-released"> + +<p>The FURY project is happy to announce the release of FURY 0.6.0! +FURY is a free and open source software library for scientific visualization and 3D animations.</p> +<p>You can show your support by <a class="reference external" href="https://github.com/fury-gl/fury/stargazers">adding a star</a> on FURY github project.</p> +<p>The <strong>major highlights</strong> of this release are:</p> +<ul class="simple"> +<li><p>Added new features: Picking and double-click callback.</p></li> +<li><p>Added Signed Distance Field actor.</p></li> +<li><p>Added a new UI ComboBox.</p></li> +<li><p>Added multiples primitives (Rhombocuboctahedron, …).</p></li> +<li><p>Huge improvement of multiple UIs and actors.</p></li> +<li><p>Fixed Compatibility with VTK9.</p></li> +<li><p>Large documentation update, examples and tutorials (5 new).</p></li> +<li><p>Added a blog system.</p></li> +<li><p>Increased tests coverage and code quality.</p></li> +</ul> +<div class="admonition note"> +<p class="admonition-title">Note</p> +<p>The complete release notes are available <a class="reference internal" href="../../release_notes/releasev0.6.0.html#releasev0-6-0"><span class="std std-ref">here</span></a></p> +</div> +<p><strong>To upgrade or install FURY</strong></p> +<p>Run the following command in your terminal:</p> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">pip</span> <span class="n">install</span> <span class="o">--</span><span class="n">upgrade</span> <span class="n">fury</span> +</pre></div> +</div> +<p>or:</p> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">conda</span> <span class="n">install</span> <span class="o">-</span><span class="n">c</span> <span class="n">conda</span><span class="o">-</span><span class="n">forge</span> <span class="n">fury</span> +</pre></div> +</div> +<p><strong>Questions or suggestions?</strong></p> +<p>For any questions go to <a class="reference external" href="http://fury.gl">http://fury.gl</a>, or send an e-mail to <a class="reference external" href="mailto:fury&#37;&#52;&#48;python&#46;org">fury<span>&#64;</span>python<span>&#46;</span>org</a> +We can also join our <a class="reference external" href="https://discord.gg/6btFPPj">discord community</a></p> +<p>We would like to thanks to <a class="reference internal" href="../../community.html#community"><span class="std std-ref">all contributors</span></a> for this release:</p> +<ul class="simple"> +<li><p>Eleftherios Garyfallidis</p></li> +<li><p>Liam Donohue</p></li> +<li><p>Marc-Alexandre Côté</p></li> +<li><p>Melina Raglin</p></li> +<li><p>Naman Bansal</p></li> +<li><p>Serge Koudoro</p></li> +<li><p>Soham Biswas</p></li> +<li><p>Tushar</p></li> +<li><p>Lenix Lobo</p></li> +</ul> +<p>On behalf of the <a class="reference internal" href="../../community.html#community"><span class="std std-ref">FURY developers</span></a>,</p> +<p>Serge K.</p> +</section> + + + The FURY project is happy to announce the release of FURY 0.6.0! +FURY is a free and open source software library for scientific visualization and 3D animations. + + 2020-07-20T00:00:00-04:00 + + + https://fury.gl/posts/2020/2020-04-09-release-announcement.html + FURY 0.5.1 Released + 2020-04-09T00:00:00-04:00 + + Serge Koudoro + + <section id="fury-0-5-1-released"> + +<p>The FURY project is happy to announce the release of FURY 0.5.1! +FURY is a free and open source software library for scientific visualization and 3D animations.</p> +<p>You can show your support by <a class="reference external" href="https://github.com/fury-gl/fury/stargazers">adding a star</a> on FURY github project.</p> +<p>The <strong>major highlights</strong> of this release are:</p> +<ul class="simple"> +<li><p>Remove python 2 compatibility</p></li> +<li><p>Added texture management</p></li> +<li><p>Added multiples primitives.</p></li> +<li><p>Added multiples actors (contour_from_label, billboard…)</p></li> +<li><p>Huge improvement of multiple UI (RangeSlider, …)</p></li> +<li><p>Improved security (from md5 to sha256)</p></li> +<li><p>Large documentation update, examples and tutorials</p></li> +<li><p>Increased tests coverage and code quality</p></li> +</ul> +<div class="admonition note"> +<p class="admonition-title">Note</p> +<p>The complete release notes are available <a class="reference internal" href="../../release_notes/releasev0.5.1.html#releasev0-5-1"><span class="std std-ref">here</span></a></p> +</div> +<p><strong>To upgrade or install FURY</strong></p> +<p>Run the following command in your terminal:</p> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">pip</span> <span class="n">install</span> <span class="o">--</span><span class="n">upgrade</span> <span class="n">fury</span> +</pre></div> +</div> +<p>or:</p> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">conda</span> <span class="n">install</span> <span class="o">-</span><span class="n">c</span> <span class="n">conda</span><span class="o">-</span><span class="n">forge</span> <span class="n">fury</span> +</pre></div> +</div> +<p><strong>Questions or suggestions?</strong></p> +<p>For any questions go to <a class="reference external" href="http://fury.gl">http://fury.gl</a>, or send an e-mail to <a class="reference external" href="mailto:fury&#37;&#52;&#48;python&#46;org">fury<span>&#64;</span>python<span>&#46;</span>org</a> +We can also join our <a class="reference external" href="https://discord.gg/6btFPPj">discord community</a></p> +<p>We would like to thanks to <a class="reference internal" href="../../community.html#community"><span class="std std-ref">all contributors</span></a> for this release:</p> +<ul class="simple"> +<li><p>ChenCheng0630</p></li> +<li><p>Devanshu Modi</p></li> +<li><p>Eleftherios Garyfallidis</p></li> +<li><p>Etienne St-Onge</p></li> +<li><p>Filipi Nascimento Silva</p></li> +<li><p>Gottipati Gautam</p></li> +<li><p>Javier Guaje</p></li> +<li><p>Jon Haitz Legarreta Gorroño</p></li> +<li><p>Liam Donohue</p></li> +<li><p>Marc-Alexandre Côté</p></li> +<li><p>Marssis</p></li> +<li><p>Naman Bansal</p></li> +<li><p>Nasim</p></li> +<li><p>Saransh Jain</p></li> +<li><p>Serge Koudoro</p></li> +<li><p>Shreyas Bhujbal</p></li> +<li><p>Soham Biswas</p></li> +<li><p>Vivek Choudhary</p></li> +<li><p>ibrahimAnis</p></li> +<li><p>lenixlobo</p></li> +</ul> +<p>On behalf of the <a class="reference internal" href="../../community.html#community"><span class="std std-ref">FURY developers</span></a>,</p> +<p>Serge K.</p> +</section> + + + The FURY project is happy to announce the release of FURY 0.5.1! +FURY is a free and open source software library for scientific visualization and 3D animations. + + 2020-04-09T00:00:00-04:00 + + + https://fury.gl/posts/2019/2019-10-29-release-announcement.html + FURY 0.4.0 Released + 2019-10-29T00:00:00-04:00 + + Serge Koudoro + + <section id="fury-0-4-0-released"> + +<p>The FURY project is happy to announce the release of FURY 0.4.0! +FURY is a free and open source software library for scientific visualization and 3D animations.</p> +<p>You can show your support by <a class="reference external" href="https://github.com/fury-gl/fury/stargazers">adding a star</a> on FURY github project.</p> +<p>The <strong>major highlights</strong> of this release are:</p> +<ul class="simple"> +<li><p>Enable Anti aliasing and frame rate features</p></li> +<li><p>Add multiples actors (arrow, box, …)</p></li> +<li><p>Glyph extensions</p></li> +<li><p>Remove Nose dependency</p></li> +<li><p>Replace Appveyor by Azure pipeline for Windows</p></li> +<li><p>Update Documentation, examples and tutorials</p></li> +<li><p>Increase tests coverage and code quality</p></li> +</ul> +<div class="admonition note"> +<p class="admonition-title">Note</p> +<p>The complete release notes are <a class="reference internal" href="../../release_notes/releasev0.4.0.html#releasev0-4-0"><span class="std std-ref">available here</span></a></p> +</div> +<p><strong>To upgrade or install FURY</strong></p> +<p>Run the following command in your terminal:</p> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">pip</span> <span class="n">install</span> <span class="o">--</span><span class="n">upgrade</span> <span class="n">fury</span> +</pre></div> +</div> +<p>or:</p> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">conda</span> <span class="n">install</span> <span class="o">-</span><span class="n">c</span> <span class="n">conda</span><span class="o">-</span><span class="n">forge</span> <span class="n">fury</span> +</pre></div> +</div> +<p><strong>Questions or suggestions?</strong></p> +<p>For any questions go to <a class="reference external" href="http://fury.gl">http://fury.gl</a>, or send an e-mail to <a class="reference external" href="mailto:fury&#37;&#52;&#48;python&#46;org">fury<span>&#64;</span>python<span>&#46;</span>org</a> +We can also join our <a class="reference external" href="https://discord.gg/6btFPPj">discord community</a></p> +<p>We would like to thanks to <a class="reference internal" href="../../community.html#community"><span class="std std-ref">all contributors</span></a> for this release:</p> +<ul class="simple"> +<li><p>Eleftherios Garyfallidis</p></li> +<li><p>Etienne St-Onge</p></li> +<li><p>Javier Guaje</p></li> +<li><p>Serge Koudoro</p></li> +</ul> +<p>On behalf of the <a class="reference internal" href="../../community.html#community"><span class="std std-ref">FURY developers</span></a>,</p> +<p>Serge K.</p> +</section> + + + The FURY project is happy to announce the release of FURY 0.4.0! +FURY is a free and open source software library for scientific visualization and 3D animations. + + 2019-10-29T00:00:00-04:00 + + + https://fury.gl/posts/2019/2019-08-02-release-announcement.html + FURY 0.3.0 Released + 2019-08-02T00:00:00-04:00 + + Serge Koudoro + + <section id="fury-0-3-0-released"> + +<p>The FURY project is happy to announce the release of FURY 0.3.0! +FURY is a free and open source software library for scientific visualization and 3D animations.</p> +<p>You can show your support by <a class="reference external" href="https://github.com/fury-gl/fury/stargazers">adding a star</a> on FURY github project.</p> +<p>The <strong>major highlights</strong> of this release are:</p> +<ul class="simple"> +<li><p>Add cone actor and update odf actor</p></li> +<li><p>Add Appveyor CI and update MacOS CI</p></li> +<li><p>Update Documentation, examples and tutorials</p></li> +<li><p>Increase tests coverage and code quality</p></li> +</ul> +<div class="admonition note"> +<p class="admonition-title">Note</p> +<p>The complete release notes are <a class="reference internal" href="../../release_notes/releasev0.3.0.html#releasev0-3-0"><span class="std std-ref">available here</span></a></p> +</div> +<p><strong>To upgrade or install FURY</strong></p> +<p>Run the following command in your terminal:</p> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">pip</span> <span class="n">install</span> <span class="o">--</span><span class="n">upgrade</span> <span class="n">fury</span> +</pre></div> +</div> +<p>or:</p> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">conda</span> <span class="n">install</span> <span class="o">-</span><span class="n">c</span> <span class="n">conda</span><span class="o">-</span><span class="n">forge</span> <span class="n">fury</span> +</pre></div> +</div> +<p><strong>Questions or suggestions?</strong></p> +<p>For any questions go to <a class="reference external" href="http://fury.gl">http://fury.gl</a>, or send an e-mail to <a class="reference external" href="mailto:fury&#37;&#52;&#48;python&#46;org">fury<span>&#64;</span>python<span>&#46;</span>org</a> +We can also join our <a class="reference external" href="https://discord.gg/6btFPPj">discord community</a></p> +<p>We would like to thanks to <a class="reference internal" href="../../community.html#community"><span class="std std-ref">all contributors</span></a> for this release:</p> +<ul class="simple"> +<li><p>Ariel Rokem</p></li> +<li><p>Eleftherios Garyfallidis</p></li> +<li><p>Guillaume Favelier</p></li> +<li><p>Kevin Sitek</p></li> +<li><p>Prashil</p></li> +<li><p>Scott Trinkle</p></li> +<li><p>Serge Koudoro</p></li> +</ul> +<p>On behalf of the <a class="reference internal" href="../../community.html#community"><span class="std std-ref">FURY developers</span></a>,</p> +<p>Serge K.</p> +</section> + + + The FURY project is happy to announce the release of FURY 0.3.0! +FURY is a free and open source software library for scientific visualization and 3D animations. + + 2019-08-02T00:00:00-04:00 + + + https://fury.gl/posts/2019/2019-03-08-release-announcement.html + FURY 0.2.0 Released + 2019-03-08T00:00:00-05:00 + + Serge Koudoro + + <section id="fury-0-2-0-released"> + +<p>The FURY project is happy to announce the release of FURY 0.2.0! +FURY is a free and open source software library for scientific visualization and 3D animations.</p> +<p>You can show your support by <a class="reference external" href="https://github.com/fury-gl/fury/stargazers">adding a star</a> on FURY github project.</p> +<p>The <strong>major highlights</strong> of this release are:</p> +<ul class="simple"> +<li><p>Replace <code class="docutils literal notranslate"><span class="pre">fury.window.Renderer</span></code> by <code class="docutils literal notranslate"><span class="pre">fury.window.Scene</span></code></p></li> +<li><p>Add stereo support</p></li> +<li><p>Add GridUI object</p></li> +<li><p>Increase tests coverage and code quality</p></li> +</ul> +<div class="admonition note"> +<p class="admonition-title">Note</p> +<p>The complete release notes are <a class="reference internal" href="../../release_notes/releasev0.2.0.html#releasev0-2-0"><span class="std std-ref">available here</span></a></p> +</div> +<p><strong>To upgrade or install FURY</strong></p> +<p>Run the following command in your terminal:</p> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">pip</span> <span class="n">install</span> <span class="o">--</span><span class="n">upgrade</span> <span class="n">fury</span> +</pre></div> +</div> +<p>or:</p> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">conda</span> <span class="n">install</span> <span class="o">-</span><span class="n">c</span> <span class="n">conda</span><span class="o">-</span><span class="n">forge</span> <span class="n">fury</span> +</pre></div> +</div> +<p><strong>Questions or suggestions?</strong></p> +<p>For any questions go to <a class="reference external" href="http://fury.gl">http://fury.gl</a>, or send an e-mail to <a class="reference external" href="mailto:fury&#37;&#52;&#48;python&#46;org">fury<span>&#64;</span>python<span>&#46;</span>org</a> +We can also join our <a class="reference external" href="https://discord.gg/6btFPPj">discord community</a></p> +<p>We would like to thanks to <a class="reference internal" href="../../community.html#community"><span class="std std-ref">all contributors</span></a> for this release:</p> +<ul class="simple"> +<li><p>David Reagan</p></li> +<li><p>Eleftherios Garyfallidis</p></li> +<li><p>Jon Haitz Legarreta Gorroño</p></li> +<li><p>Marc-Alexandre Côté</p></li> +<li><p>Serge Koudoro</p></li> +</ul> +<p>On behalf of the <a class="reference internal" href="../../community.html#community"><span class="std std-ref">FURY developers</span></a>,</p> +<p>Serge K.</p> +</section> + + + The FURY project is happy to announce the release of FURY 0.2.0! +FURY is a free and open source software library for scientific visualization and 3D animations. + + 2019-03-08T00:00:00-05:00 + + diff --git a/v0.10.x/blog/drafts.html b/v0.10.x/blog/drafts.html new file mode 100644 index 000000000..d6d813dc5 --- /dev/null +++ b/v0.10.x/blog/drafts.html @@ -0,0 +1,466 @@ + + + + + + + Drafts — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +
+

+ + + + Drafts + +

+ + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/blog/tag.html b/v0.10.x/blog/tag.html new file mode 100644 index 000000000..507dcb3a6 --- /dev/null +++ b/v0.10.x/blog/tag.html @@ -0,0 +1,2572 @@ + + + + + + + Tags — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + + +
+

+ Posts tagged + fury +

+ +
+

+ + 15 April 2023 + + - + FURY 0.9.0 Released +

+
+ +
+

+ + 31 January 2022 + + - + FURY 0.8.0 Released +

+
+ +
+

+ + 03 August 2021 + + - + FURY 0.7.0 Released +

+
+ +
+

+ + 13 March 2021 + + - + FURY 0.7.0 Released +

+
+ +
+

+ + 18 August 2020 + + - + FURY 0.6.1 Released +

+
+ +
+

+ + 20 July 2020 + + - + FURY 0.6.0 Released +

+
+ +
+

+ + 09 April 2020 + + - + FURY 0.5.1 Released +

+
+ +
+

+ + 29 October 2019 + + - + FURY 0.4.0 Released +

+
+ +
+

+ + 02 August 2019 + + - + FURY 0.3.0 Released +

+
+ +
+

+ + 08 March 2019 + + - + FURY 0.2.0 Released +

+
+ +
+

+ + 26 November 2018 + + - + FURY 0.1.4 Released +

+
+ +
+

+ + 31 October 2018 + + - + FURY 0.1.3 Released +

+
+ +
+

+ + 21 September 2018 + + - + FURY 0.1.0 Released +

+
+ +
+ + + +
+

+ Posts tagged + google +

+ +
+

+ + 25 August 2023 + + - + Google Summer of Code Final Work Product +

+
+ +
+

+ + 24 August 2023 + + - + Week 12 : Experimenting with ODFs implementation +

+
+ +
+

+ + 24 August 2023 + + - + Google Summer of Code Final Work Product +

+
+ +
+

+ + 21 August 2023 + + - + Week 12: Now That is (almost) a Wrap! +

+
+ +
+

+ + 21 August 2023 + + - + Google Summer of Code Final Work Product +

+
+ +
+

+ + 19 August 2023 + + - + Week 12: FileDialog Quest Begins! +

+
+ +
+

+ + 16 August 2023 + + - + Week 11 : Adjusting ODF implementation and looking for solutions on issues found +

+
+ +
+

+ + 14 August 2023 + + - + Week 11: A Refactor is Sometimes Needed +

+
+ +
+

+ + 12 August 2023 + + - + Week 11: Bye Bye SpinBox +

+
+ +
+

+ + 08 August 2023 + + - + Week 10 : Start of SH implementation experiments +

+
+ +
+

+ + 07 August 2023 + + - + Week 10: Ready for Review! +

+
+ +
+

+ + 05 August 2023 + + - + Week 10: Its time for a Spin-Box! +

+
+ +
+

+ + 31 July 2023 + + - + Week 9: Tutorial done and polishing DTI uncertainty +

+
+ +
+

+ + 31 July 2023 + + - + Week 9: It is Polishing Time! +

+
+ +
+

+ + 29 July 2023 + + - + Week 9: TextBlock2D is Finally Merged! +

+
+ +
+

+ + 25 July 2023 + + - + Week 8: Working on Ellipsoid Tutorial and exploring SH +

+
+ +
+

+ + 24 July 2023 + + - + Week 8: The Birth of a Versatile API +

+
+ +
+

+ + 22 July 2023 + + - + Week 8: Another week with TextBlockUI +

+
+ +
+

+ + 17 July 2023 + + - + Week 7: Experimentation Done +

+
+ +
+

+ + 17 July 2023 + + - + Week 7: Adjustments on the Uncertainty Cones visualization +

+
+ +
+

+ + 15 July 2023 + + - + Week 7: Sowing the seeds for TreeUI +

+
+ +
+

+ + 10 July 2023 + + - + Week 6: Things are Starting to Build Up +

+
+ +
+

+ + 10 July 2023 + + - + Week 6: First draft of the Ellipsoid tutorial +

+
+ +
+

+ + 08 July 2023 + + - + Week 6: BoundingBox for TextBlock2D! +

+
+ +
+

+ + 03 July 2023 + + - + Week 5: Preparing the data for the Ellipsoid tutorial +

+
+ +
+

+ + 03 July 2023 + + - + Week 5: All Roads Lead to Rome +

+
+ +
+

+ + 01 July 2023 + + - + Week 5: Trying out PRs and Planning Ahead +

+
+ +
+

+ + 27 June 2023 + + - + Week 4: First draft of the DTI uncertainty visualization +

+
+ +
+

+ + 26 June 2023 + + - + Week 4: Nothing is Ever Lost +

+
+ +
+

+ + 24 June 2023 + + - + Week 4: Exam Preparations and Reviewing +

+
+ +
+

+ + 19 June 2023 + + - + Week 3: Working on uncertainty and details of the first PR +

+
+ +
+

+ + 19 June 2023 + + - + Week 3: Watch Your Expectations +

+
+ +
+

+ + 17 June 2023 + + - + Week 3: Resolving Combobox Icon Flaw and TextBox Justification +

+
+ +
+

+ + 12 June 2023 + + - + Week 2: The Importance of (good) Documentation +

+
+ +
+

+ + 12 June 2023 + + - + Week 2: Making adjustments to the Ellipsoid Actor +

+
+ +
+

+ + 11 June 2023 + + - + Week 2: Tackling Text Justification and Icon Flaw Issues +

+
+ +
+

+ + 05 June 2023 + + - + Week 1: Ellipsoid actor implemented with SDF +

+
+ +
+

+ + 05 June 2023 + + - + The FBO Saga - Week 1 +

+
+ +
+

+ + 03 June 2023 + + - + Week 1: Working with SpinBox and TextBox Enhancements +

+
+ +
+

+ + 02 June 2023 + + - + Week 0: Community Bounding Period +

+
+ +
+

+ + 02 June 2023 + + - + Week 0: Community Bounding Period +

+
+ +
+

+ + 29 May 2023 + + - + The Beginning of Everything - Week 0 +

+
+ +
+

+ + 01 February 2023 + + - + Contribute to FURY via Google Summer of Code 2023 +

+
+ +
+

+ + 29 January 2023 + + - + Google Summer of Code Final Work Product +

+
+ +
+

+ + 29 January 2023 + + - + Google Summer of Code Final Work Product +

+
+ +
+

+ + 24 January 2023 + + - + Google Summer of Code Final Work Product +

+
+ +
+

+ + 28 September 2022 + + - + Week 14: Keyframes animation is now a bit easier in FURY +

+
+ +
+

+ + 28 September 2022 + + - + Week 14 - Morphing is here! +

+
+ +
+

+ + 21 September 2022 + + - + Week 16 - Working with Rotations! +

+
+ +
+

+ + 20 September 2022 + + - + Week 13: Keyframes animation is now a bit easier in FURY +

+
+ +
+

+ + 15 September 2022 + + - + Week 13 - Multi-bone skeletal animation support +

+
+ +
+

+ + 14 September 2022 + + - + Week 15 - Highlighting DrawShapes +

+
+ +
+

+ + 08 September 2022 + + - + Week 12 - Adding skeleton as actors and fix global transformation +

+
+ +
+

+ + 07 September 2022 + + - + Week 14 - Updating DrawPanel architecture +

+
+ +
+

+ + 07 September 2022 + + - + Week 12: Adding new tutorials +

+
+ +
+

+ + 31 August 2022 + + - + Week 13 - Separating tests and fixing bugs +

+
+ +
+

+ + 31 August 2022 + + - + Week 11 - Multiple transformations support and adding tests +

+
+ +
+

+ + 30 August 2022 + + - + Week 11: Improving tutorials a little +

+
+ +
+

+ + 25 August 2022 + + - + Week 10 - Multi-node skinning support +

+
+ +
+

+ + 24 August 2022 + + - + Week 12 - Fixing translating issues and updating tests +

+
+ +
+

+ + 23 August 2022 + + - + Week 10: Supporting hierarchical animating +

+
+ +
+

+ + 17 August 2022 + + - + Week 9 - First working skeletal animation prototype +

+
+ +
+

+ + 17 August 2022 + + - + Week 11 - Creating a base for Freehand Drawing +

+
+ +
+

+ + 16 August 2022 + + - + Week 9: Animating primitives of the same actor +

+
+ +
+

+ + 10 August 2022 + + - + Week 8 - Fixing animation bugs +

+
+ +
+

+ + 10 August 2022 + + - + Week 10 - Understanding Codes and Playing with Animation +

+
+ +
+

+ + 09 August 2022 + + - + Week 8: Back to the shader-based version of the Timeline +

+
+ +
+

+ + 03 August 2022 + + - + Week 9 - Grouping and Transforming Shapes +

+
+ +
+

+ + 01 August 2022 + + - + Week 7: Billboard spheres and implementing interpolators using closures +

+
+ +
+

+ + 01 August 2022 + + - + Week 7 - Fixing bugs in animations +

+
+ +
+

+ + 27 July 2022 + + - + Week 8 - Working on the polyline feature +

+
+ +
+

+ + 25 July 2022 + + - + Week 6: Fixing the Timeline issues and equipping it with more features +

+
+ +
+

+ + 25 July 2022 + + - + Week 6 - Extracting the animation data +

+
+ +
+

+ + 20 July 2022 + + - + Week 7 - Working on Rotation PR and Trying Freehand Drawing +

+
+ +
+

+ + 19 July 2022 + + - + Week 5: Slerp implementation, documenting the Timeline, and adding unit tests +

+
+ +
+

+ + 19 July 2022 + + - + Week 5 - Creating PR for glTF exporter and fixing the loader +

+
+ +
+

+ + 13 July 2022 + + - + Week 6 - Supporting Rotation of the Shapes from the Center +

+
+ +
+

+ + 12 July 2022 + + - + Week 4 - Finalizing glTF loader +

+
+ +
+

+ + 11 July 2022 + + - + Week 4: Camera animation, interpolation in GLSL, and a single Timeline! +

+
+ +
+

+ + 06 July 2022 + + - + Week 5 - Working on new features +

+
+ +
+

+ + 04 July 2022 + + - + Week 3: Redesigning the API, Implementing cubic Bezier Interpolator, and making progress on the GPU side! +

+
+ +
+

+ + 04 July 2022 + + - + Week 3 - Fixing fetcher, adding tests and docs +

+
+ +
+

+ + 29 June 2022 + + - + Week 4 - Fixing the Clamping Issue +

+
+ +
+

+ + 29 June 2022 + + - + Week 2 - Improving Fetcher and Exporting glTF +

+
+ +
+

+ + 28 June 2022 + + - + Week 2: Implementing non-linear and color interpolators +

+
+ +
+

+ + 22 June 2022 + + - + Week 3 - Dealing with Problems +

+
+ +
+

+ + 20 June 2022 + + - + Week 1 - A Basic glTF Importer +

+
+ +
+

+ + 19 June 2022 + + - + Week 1: Implementing a basic Keyframe animation API +

+
+ +
+

+ + 15 June 2022 + + - + Week 2 - Improving DrawPanel UI +

+
+ +
+

+ + 08 June 2022 + + - + Week 1 - Laying the Foundation of DrawPanel UI +

+
+ +
+

+ + 25 May 2022 + + - + Pre-GSoC Journey +

+
+ +
+

+ + 24 May 2022 + + - + My Journey to GSoC 2022 +

+
+ +
+

+ + 23 May 2022 + + - + My journey till getting accepted into GSoC22 +

+
+ +
+

+ + 01 February 2022 + + - + Contribute to FURY via Google Summer of Code 2022 +

+
+ +
+

+ + 23 August 2021 + + - + Google Summer of Code Final Work Product +

+
+ +
+

+ + 23 August 2021 + + - + Google Summer of Code Final Work Product +

+
+ +
+

+ + 23 August 2021 + + - + Google Summer of Code 2021 - Final Report - Bruno Messias +

+
+ +
+

+ + 16 August 2021 + + - + Week #11: Removing the flickering effect +

+
+ +
+

+ + 16 August 2021 + + - + Week #11: Finalizing open Pull Requests +

+
+ +
+

+ + 16 August 2021 + + - + Tenth coding week! +

+
+ +
+

+ + 09 August 2021 + + - + Week#10: Accordion UI, Support for sprite sheet animations +

+
+ +
+

+ + 09 August 2021 + + - + Week #10: SDF Fonts +

+
+ +
+

+ + 09 August 2021 + + - + Ninth coding week! +

+
+ +
+

+ + 02 August 2021 + + - + Week #9: More Layouts! +

+
+ +
+

+ + 02 August 2021 + + - + Week #09: Sphinx custom summary +

+
+ +
+

+ + 02 August 2021 + + - + Eighth coding week! +

+
+ +
+

+ + 26 July 2021 + + - + Weekly Check-In #8 +

+
+ +
+

+ + 26 July 2021 + + - + Week #8: Code Cleanup, Finishing up open PRs, Continuing work on Tree2D +

+
+ +
+

+ + 26 July 2021 + + - + Seventh week of coding! +

+
+ +
+

+ + 19 July 2021 + + - + Weekly Check-In #7 +

+
+ +
+

+ + 19 July 2021 + + - + Week #7: Finalizing the stalling PRs, finishing up Tree2D UI. +

+
+ +
+

+ + 19 July 2021 + + - + Sixth week of coding! +

+
+ +
+

+ + 12 July 2021 + + - + Week #6: Bug fixes, Working on Tree2D UI +

+
+ +
+

+ + 12 July 2021 + + - + Network layout algorithms using IPC +

+
+ +
+

+ + 12 July 2021 + + - + Fifth week of coding! +

+
+ +
+

+ + 05 July 2021 + + - + Weekly Check-In #5 +

+
+ +
+

+ + 05 July 2021 + + - + Week #5: Rebasing all PRs w.r.t the UI restructuring, Tree2D, Bug Fixes +

+
+ +
+

+ + 05 July 2021 + + - + SOLID, monkey patching a python issue and network visualization through WebRTC +

+
+ +
+

+ + 05 July 2021 + + - + Fourth week of coding! +

+
+ +
+

+ + 28 June 2021 + + - + Week #4: Adding Tree UI to the UI module +

+
+ +
+

+ + 28 June 2021 + + - + Third week of coding! +

+
+ +
+

+ + 21 June 2021 + + - + Weekly Check-In #3 +

+
+ +
+

+ + 21 June 2021 + + - + Week #3: Adapting GridLayout to work with UI +

+
+ +
+

+ + 21 June 2021 + + - + Second week of coding! +

+
+ +
+

+ + 14 June 2021 + + - + First week of coding! +

+
+ +
+

+ + 13 June 2021 + + - + Week #2: Feature additions in UI and IO modules +

+
+ +
+

+ + 13 June 2021 + + - + A Stadia-like system for data visualization +

+
+ +
+

+ + 08 June 2021 + + - + Welcome to my GSoC Blog! +

+
+ +
+

+ + 08 June 2021 + + - + Weekly Check-In #1 +

+
+ +
+

+ + 08 June 2021 + + - + Week #1: Welcome to my weekly Blogs! +

+
+ +
+

+ + 09 March 2021 + + - + Google Summer of Code +

+
+ +
+

+ + 24 August 2020 + + - + Shader Showcase +

+
+ +
+

+ + 24 August 2020 + + - + Google Summer of Code Final Work Product +

+
+ +
+

+ + 24 August 2020 + + - + Google Summer of Code 2020 Final Work Product +

+
+ +
+

+ + 23 August 2020 + + - + Part of the Journey is the end unless its Open Source! +

+
+ +
+

+ + 17 August 2020 + + - + Outline Picker +

+
+ +
+

+ + 16 August 2020 + + - + Wrecking Ball Simulation, Scrollbars Update, Physics Tutorials. +

+
+ +
+

+ + 09 August 2020 + + - + More Shaders!! +

+
+ +
+

+ + 09 August 2020 + + - + Chain Simulation, Scrollbar Refactor, Tutorial Update. +

+
+ +
+

+ + 02 August 2020 + + - + Single Actor, Physics, Scrollbars. +

+
+ +
+

+ + 02 August 2020 + + - + More Shaders!! +

+
+ +
+

+ + 27 July 2020 + + - + Merging SDF primitives. +

+
+ +
+

+ + 26 July 2020 + + - + Tab UI, TabPanel2D, Tab UI Tutorial. +

+
+ +
+

+ + 20 July 2020 + + - + Improvements in SDF primitives. +

+
+ +
+

+ + 19 July 2020 + + - + ComboBox2D, TextBlock2D, Clipping Overflow. +

+
+ +
+

+ + 13 July 2020 + + - + Multiple SDF primitives. +

+
+ +
+

+ + 12 July 2020 + + - + Orientation, Sizing, Tab UI. +

+
+ +
+

+ + 05 July 2020 + + - + Translation, Reposition, Rotation. +

+
+ +
+

+ + 05 July 2020 + + - + Spherical harmonics, Continued. +

+
+ +
+

+ + 28 June 2020 + + - + Spherical harmonics +

+
+ +
+

+ + 28 June 2020 + + - + May the Force be with you!! +

+
+ +
+

+ + 21 June 2020 + + - + TextBlock2D Progress!! +

+
+ +
+

+ + 21 June 2020 + + - + Raymarching continued +

+
+ +
+

+ + 14 June 2020 + + - + Raymarching!! +

+
+ +
+

+ + 14 June 2020 + + - + ComboBox2D Progress!! +

+
+ +
+

+ + 07 June 2020 + + - + First week of coding!! +

+
+ +
+

+ + 07 June 2020 + + - + First week of coding!! +

+
+ +
+

+ + 30 May 2020 + + - + Welcome to my GSoC Blog!!! +

+
+ +
+

+ + 30 May 2020 + + - + Weekly Check-in #1 +

+
+ +
+

+ + 05 January 2020 + + - + Google Summer of Code +

+
+ +
+ + + +
+

+ Posts tagged + shader +

+ +
+

+ + 19 June 2019 + + - + Success on Brain Art Competition using FURY +

+
+ +
+ + + +
+ + + +
+ +
+
+
+ +
+ + + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/blog/tag/fury.html b/v0.10.x/blog/tag/fury.html new file mode 100644 index 000000000..ae4646c97 --- /dev/null +++ b/v0.10.x/blog/tag/fury.html @@ -0,0 +1,1402 @@ + + + + + + + Posts tagged fury — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +
+

+ + Posts tagged + + fury + +

+ + +
+

+ FURY 0.9.0 Released +

+
    +
  • + + + 15 April 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Serge Koudoro + + + +
  • + + + + +
  • + + + Category: + + + + + release + + + +
  • + + +
  • + + + + Tag: + + + + + fury + + + +
  • + + +
    +
+

The FURY project is happy to announce the release of FURY 0.9.0! +FURY is a free and open source software library for scientific visualization and 3D animations.

+

+ +

Read more ...

+
+
+ +
+

+ FURY 0.8.0 Released +

+
    +
  • + + + 31 January 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Serge Koudoro + + + +
  • + + + + +
  • + + + Category: + + + + + release + + + +
  • + + +
  • + + + + Tag: + + + + + fury + + + +
  • + + +
    +
+

The FURY project is happy to announce the release of FURY 0.8.0! +FURY is a free and open source software library for scientific visualization and 3D animations.

+

+ +

Read more ...

+
+
+ +
+

+ FURY 0.7.0 Released +

+
    +
  • + + + 03 August 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Serge Koudoro + + + +
  • + + + + +
  • + + + Category: + + + + + release + + + +
  • + + +
  • + + + + Tag: + + + + + fury + + + +
  • + + +
    +
+

The FURY project is happy to announce the release of FURY 0.7.1! +FURY is a free and open source software library for scientific visualization and 3D animations.

+

+ +

Read more ...

+
+
+ +
+

+ FURY 0.7.0 Released +

+
    +
  • + + + 13 March 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Serge Koudoro + + + +
  • + + + + +
  • + + + Category: + + + + + release + + + +
  • + + +
  • + + + + Tag: + + + + + fury + + + +
  • + + +
    +
+

The FURY project is happy to announce the release of FURY 0.7.0! +FURY is a free and open source software library for scientific visualization and 3D animations.

+

+ +

Read more ...

+
+
+ +
+

+ FURY 0.6.1 Released +

+
    +
  • + + + 18 August 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Serge Koudoro + + + +
  • + + + + +
  • + + + Category: + + + + + release + + + +
  • + + +
  • + + + + Tag: + + + + + fury + + + +
  • + + +
    +
+

The FURY project is happy to announce the release of FURY 0.6.1! +FURY is a free and open source software library for scientific visualization and 3D animations.

+

+ +

Read more ...

+
+
+ +
+

+ FURY 0.6.0 Released +

+
    +
  • + + + 20 July 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Serge Koudoro + + + +
  • + + + + +
  • + + + Category: + + + + + release + + + +
  • + + +
  • + + + + Tag: + + + + + fury + + + +
  • + + +
    +
+

The FURY project is happy to announce the release of FURY 0.6.0! +FURY is a free and open source software library for scientific visualization and 3D animations.

+

+ +

Read more ...

+
+
+ +
+

+ FURY 0.5.1 Released +

+
    +
  • + + + 09 April 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Serge Koudoro + + + +
  • + + + + +
  • + + + Category: + + + + + release + + + +
  • + + +
  • + + + + Tag: + + + + + fury + + + +
  • + + +
    +
+

The FURY project is happy to announce the release of FURY 0.5.1! +FURY is a free and open source software library for scientific visualization and 3D animations.

+

+ +

Read more ...

+
+
+ +
+

+ FURY 0.4.0 Released +

+
    +
  • + + + 29 October 2019 + +
  • +
    + + +
  • + + + Author: + + + + + Serge Koudoro + + + +
  • + + + + +
  • + + + Category: + + + + + release + + + +
  • + + +
  • + + + + Tag: + + + + + fury + + + +
  • + + +
    +
+

The FURY project is happy to announce the release of FURY 0.4.0! +FURY is a free and open source software library for scientific visualization and 3D animations.

+

+ +

Read more ...

+
+
+ +
+

+ FURY 0.3.0 Released +

+
    +
  • + + + 02 August 2019 + +
  • +
    + + +
  • + + + Author: + + + + + Serge Koudoro + + + +
  • + + + + +
  • + + + Category: + + + + + release + + + +
  • + + +
  • + + + + Tag: + + + + + fury + + + +
  • + + +
    +
+

The FURY project is happy to announce the release of FURY 0.3.0! +FURY is a free and open source software library for scientific visualization and 3D animations.

+

+ +

Read more ...

+
+
+ +
+

+ FURY 0.2.0 Released +

+
    +
  • + + + 08 March 2019 + +
  • +
    + + +
  • + + + Author: + + + + + Serge Koudoro + + + +
  • + + + + +
  • + + + Category: + + + + + release + + + +
  • + + +
  • + + + + Tag: + + + + + fury + + + +
  • + + +
    +
+

The FURY project is happy to announce the release of FURY 0.2.0! +FURY is a free and open source software library for scientific visualization and 3D animations.

+

+ +

Read more ...

+
+
+ +
+

+ FURY 0.1.4 Released +

+
    +
  • + + + 26 November 2018 + +
  • +
    + + +
  • + + + Author: + + + + + Serge Koudoro + + + +
  • + + + + +
  • + + + Category: + + + + + release + + + +
  • + + +
  • + + + + Tag: + + + + + fury + + + +
  • + + +
    +
+

The FURY project is happy to announce the release of FURY 0.1.4! +FURY is a free and open source software library for scientific visualization and 3D animations.

+

+ +

Read more ...

+
+
+ +
+

+ FURY 0.1.3 Released +

+
    +
  • + + + 31 October 2018 + +
  • +
    + + +
  • + + + Author: + + + + + Serge Koudoro + + + +
  • + + + + +
  • + + + Category: + + + + + release + + + +
  • + + +
  • + + + + Tag: + + + + + fury + + + +
  • + + +
    +
+

The FURY project is happy to announce the release of FURY 0.1.3! +FURY is a free and open source software library for scientific visualization and 3D animations.

+

+ +

Read more ...

+
+
+ +
+

+ FURY 0.1.0 Released +

+
    +
  • + + + 21 September 2018 + +
  • +
    + + +
  • + + + Author: + + + + + Serge Koudoro + + + +
  • + + + + +
  • + + + Category: + + + + + release + + + +
  • + + +
  • + + + + Tag: + + + + + fury + + + +
  • + + +
    +
+

The FURY project is happy to announce the release of FURY 0.1.0! +FURY is a free and open source software library for scientific visualization and 3D animations.

+

+ +

Read more ...

+
+
+ + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/blog/tag/fury/atom.xml b/v0.10.x/blog/tag/fury/atom.xml new file mode 100644 index 000000000..ef913eee3 --- /dev/null +++ b/v0.10.x/blog/tag/fury/atom.xml @@ -0,0 +1,639 @@ + + + https://fury.gl/ + Blog - Posts tagged fury + 2024-02-29T15:43:57.772368+00:00 + + + ABlog + + https://fury.gl/posts/2023/2023-04-14-release-announcement.html + FURY 0.9.0 Released + 2023-04-15T00:00:00-04:00 + + Serge Koudoro + + <section id="fury-0-9-0-released"> + +<p>The FURY project is happy to announce the release of FURY 0.9.0! +FURY is a free and open source software library for scientific visualization and 3D animations.</p> +<p>You can show your support by <a class="reference external" href="https://github.com/fury-gl/fury/stargazers">adding a star</a> on FURY github project.</p> +<p>This Release is mainly a maintenance release. The <strong>major highlights</strong> of this release are:</p> +<ul class="simple"> +<li><p>New Streaming System added.</p></li> +<li><p>Large improvement of Signed Distance Functions actors (SDF).</p></li> +<li><p>Continuous Integration (CI) platform updated. Migrate Windows CI from Azure to Github Actions</p></li> +<li><p>Migration from setuptools to hatching. versioning system updated also.</p></li> +<li><p>New module fury.animation added.</p></li> +<li><p>New module fury.gltf added. Module to support glTF 2.0.</p></li> +<li><p>Multiple tutorials added and updated.</p></li> +<li><p>Documentation updated.</p></li> +<li><p>Website updated.</p></li> +</ul> +<div class="admonition note"> +<p class="admonition-title">Note</p> +<p>The complete release notes are available <a class="reference internal" href="../../release_notes/releasev0.9.0.html#releasev0-9-0"><span class="std std-ref">here</span></a></p> +</div> +<p><strong>To upgrade or install FURY</strong></p> +<p>Run the following command in your terminal:</p> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">pip</span> <span class="n">install</span> <span class="o">--</span><span class="n">upgrade</span> <span class="n">fury</span> +</pre></div> +</div> +<p>or:</p> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">conda</span> <span class="n">install</span> <span class="o">-</span><span class="n">c</span> <span class="n">conda</span><span class="o">-</span><span class="n">forge</span> <span class="n">fury</span> +</pre></div> +</div> +<p><strong>Questions or suggestions?</strong></p> +<p>For any questions go to <a class="reference external" href="http://fury.gl">http://fury.gl</a>, or send an e-mail to <a class="reference external" href="mailto:fury&#37;&#52;&#48;python&#46;org">fury<span>&#64;</span>python<span>&#46;</span>org</a> +We can also join our <a class="reference external" href="https://discord.gg/6btFPPj">discord community</a></p> +<p>We would like to thanks to <a class="reference internal" href="../../community.html#community"><span class="std std-ref">all contributors</span></a> for this release:</p> +<ul class="simple"> +<li><p>Anand Shivam</p></li> +<li><p>Antriksh Misri</p></li> +<li><p>Bruno Messias</p></li> +<li><p>Dwij Raj Hari</p></li> +<li><p>Eleftherios Garyfallidis</p></li> +<li><p>Filipi Nascimento Silva</p></li> +<li><p>Francois Rheault</p></li> +<li><p>Frank Cerasoli</p></li> +<li><p>Javier Guaje</p></li> +<li><p>Johny Daras</p></li> +<li><p>Mohamed Agour</p></li> +<li><p>Nasim Anousheh</p></li> +<li><p>Praneeth Shetty</p></li> +<li><p>Rohit Kharsan</p></li> +<li><p>Sara Hamza</p></li> +<li><p>Serge Koudoro</p></li> +<li><p>Siddharth Gautam</p></li> +<li><p>Soham Biswas</p></li> +<li><p>Sreekar Chigurupati</p></li> +<li><p>Tania Castillo</p></li> +<li><p>Zhiwen Shi</p></li> +<li><p>maharshigor</p></li> +<li><p>sailesh</p></li> +<li><p>sparshg</p></li> +</ul> +<p>On behalf of the <a class="reference internal" href="../../community.html#community"><span class="std std-ref">FURY developers</span></a>,</p> +<p>Serge K.</p> +</section> + + + The FURY project is happy to announce the release of FURY 0.9.0! +FURY is a free and open source software library for scientific visualization and 3D animations. + + 2023-04-15T00:00:00-04:00 + + + https://fury.gl/posts/2022/2022-01-31-release-announcement.html + FURY 0.8.0 Released + 2022-01-31T00:00:00-05:00 + + Serge Koudoro + + <section id="fury-0-8-0-released"> + +<p>The FURY project is happy to announce the release of FURY 0.8.0! +FURY is a free and open source software library for scientific visualization and 3D animations.</p> +<p>You can show your support by <a class="reference external" href="https://github.com/fury-gl/fury/stargazers">adding a star</a> on FURY github project.</p> +<p>This Release is mainly a maintenance release. The <strong>major highlights</strong> of this release are:</p> +<ul class="simple"> +<li><p>New Physically Based Rendering (PBR) added. It includes anisotropic rotation and index of refraction among other material properties.</p></li> +<li><p>New Principled BRDF shader unique to FURY added. BRDF stands for bidirectional reflectance distribution function.</p></li> +<li><p>VTK 9.1.0 defined as minimum version.</p></li> +<li><p>Continuous Integration (CI) platform updated.</p></li> +<li><p>New actors added (Rhombicuboctahedron, Pentagonal Prism).</p></li> +<li><p>New UI layouts added (Vertical and Horizontal).</p></li> +<li><p>New module fury.molecular added.</p></li> +<li><p>New module fury.lib added. Module improved loading speed.</p></li> +<li><p>Demos added and updated.</p></li> +<li><p>Documentation updated.</p></li> +</ul> +<div class="admonition note"> +<p class="admonition-title">Note</p> +<p>The complete release notes are available <a class="reference internal" href="../../release_notes/releasev0.8.0.html#releasev0-8-0"><span class="std std-ref">here</span></a></p> +</div> +<p><strong>To upgrade or install FURY</strong></p> +<p>Run the following command in your terminal:</p> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">pip</span> <span class="n">install</span> <span class="o">--</span><span class="n">upgrade</span> <span class="n">fury</span> +</pre></div> +</div> +<p>or:</p> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">conda</span> <span class="n">install</span> <span class="o">-</span><span class="n">c</span> <span class="n">conda</span><span class="o">-</span><span class="n">forge</span> <span class="n">fury</span> +</pre></div> +</div> +<p><strong>Questions or suggestions?</strong></p> +<p>For any questions go to <a class="reference external" href="http://fury.gl">http://fury.gl</a>, or send an e-mail to <a class="reference external" href="mailto:fury&#37;&#52;&#48;python&#46;org">fury<span>&#64;</span>python<span>&#46;</span>org</a> +We can also join our <a class="reference external" href="https://discord.gg/6btFPPj">discord community</a></p> +<p>We would like to thanks to <a class="reference internal" href="../../community.html#community"><span class="std std-ref">all contributors</span></a> for this release:</p> +<ul class="simple"> +<li><p>Anand Shivam</p></li> +<li><p>Antriksh Misri</p></li> +<li><p>Bruno Messias</p></li> +<li><p>Eleftherios Garyfallidis</p></li> +<li><p>Javier Guaje</p></li> +<li><p>Marc-Alexandre Côté</p></li> +<li><p>Meha Bhalodiya</p></li> +<li><p>Praneeth Shetty</p></li> +<li><p>PrayasJ</p></li> +<li><p>Sajag Swami</p></li> +<li><p>Serge Koudoro</p></li> +<li><p>Shivam Anand</p></li> +</ul> +<p>On behalf of the <a class="reference internal" href="../../community.html#community"><span class="std std-ref">FURY developers</span></a>,</p> +<p>Serge K.</p> +</section> + + + The FURY project is happy to announce the release of FURY 0.8.0! +FURY is a free and open source software library for scientific visualization and 3D animations. + + 2022-01-31T00:00:00-05:00 + + + https://fury.gl/posts/2021/2021-08-03-release-announcement.html + FURY 0.7.0 Released + 2021-08-03T00:00:00-04:00 + + Serge Koudoro + + <section id="fury-0-7-0-released"> + +<p>The FURY project is happy to announce the release of FURY 0.7.1! +FURY is a free and open source software library for scientific visualization and 3D animations.</p> +<p>You can show your support by <a class="reference external" href="https://github.com/fury-gl/fury/stargazers">adding a star</a> on FURY github project.</p> +<p>This Release is mainly a maintenance release. The <strong>major highlights</strong> of this release are:</p> +<ul class="simple"> +<li><p>FURY paper added.</p></li> +<li><p>Fast selection of multiple objects added.</p></li> +<li><p>UI refactored.</p></li> +<li><p>Tests coverage increased.</p></li> +<li><p>New actor (Marker) added.</p></li> +<li><p>New primitive (Triangular Prism) added.</p></li> +<li><p>Demos added and updated.</p></li> +<li><p>Large Documentation Update.</p></li> +</ul> +<div class="admonition note"> +<p class="admonition-title">Note</p> +<p>The complete release notes are available <a class="reference internal" href="../../release_notes/releasev0.7.1.html#releasev0-7-1"><span class="std std-ref">here</span></a></p> +</div> +<p><strong>To upgrade or install FURY</strong></p> +<p>Run the following command in your terminal:</p> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">pip</span> <span class="n">install</span> <span class="o">--</span><span class="n">upgrade</span> <span class="n">fury</span> +</pre></div> +</div> +<p>or:</p> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">conda</span> <span class="n">install</span> <span class="o">-</span><span class="n">c</span> <span class="n">conda</span><span class="o">-</span><span class="n">forge</span> <span class="n">fury</span> +</pre></div> +</div> +<p><strong>Questions or suggestions?</strong></p> +<p>For any questions go to <a class="reference external" href="http://fury.gl">http://fury.gl</a>, or send an e-mail to <a class="reference external" href="mailto:fury&#37;&#52;&#48;python&#46;org">fury<span>&#64;</span>python<span>&#46;</span>org</a> +We can also join our <a class="reference external" href="https://discord.gg/6btFPPj">discord community</a></p> +<p>We would like to thanks to <a class="reference internal" href="../../community.html#community"><span class="std std-ref">all contributors</span></a> for this release:</p> +<ul class="simple"> +<li><p>Amit Chaudhari</p></li> +<li><p>Antriksh Misri</p></li> +<li><p>Bruno Messias</p></li> +<li><p>Daniel S. Katz</p></li> +<li><p>Eleftherios Garyfallidis</p></li> +<li><p>Gurdit Siyan</p></li> +<li><p>Javier Guaje</p></li> +<li><p>Jhalak Gupta</p></li> +<li><p>LoopThrough-i-j</p></li> +<li><p>MIHIR</p></li> +<li><p>Praneeth Shetty</p></li> +<li><p>Sajag Swami</p></li> +<li><p>Serge Koudoro</p></li> +<li><p>Hariharan Ayappane</p></li> +</ul> +<p>On behalf of the <a class="reference internal" href="../../community.html#community"><span class="std std-ref">FURY developers</span></a>,</p> +<p>Serge K.</p> +</section> + + + The FURY project is happy to announce the release of FURY 0.7.1! +FURY is a free and open source software library for scientific visualization and 3D animations. + + 2021-08-03T00:00:00-04:00 + + + https://fury.gl/posts/2021/2021-03-13-release-announcement.html + FURY 0.7.0 Released + 2021-03-13T00:00:00-05:00 + + Serge Koudoro + + <section id="fury-0-7-0-released"> + +<p>The FURY project is happy to announce the release of FURY 0.7.0! +FURY is a free and open source software library for scientific visualization and 3D animations.</p> +<p>You can show your support by <a class="reference external" href="https://github.com/fury-gl/fury/stargazers">adding a star</a> on FURY github project.</p> +<p>This Release is mainly a maintenance release. The <strong>major highlights</strong> of this release are:</p> +<ul class="simple"> +<li><p>New SDF actors added.</p></li> +<li><p>Materials module added.</p></li> +<li><p>ODF slicer actor performance improved.</p></li> +<li><p>New primitive (Cylinder) added.</p></li> +<li><p>Compatibility with VTK 9 added.</p></li> +<li><p>Five new demos added.</p></li> +<li><p>Large Documentation Update.</p></li> +<li><p>Migration from Travis to Github Action.</p></li> +</ul> +<div class="admonition note"> +<p class="admonition-title">Note</p> +<p>The complete release notes are available <a class="reference internal" href="../../release_notes/releasev0.7.0.html#releasev0-7-0"><span class="std std-ref">here</span></a></p> +</div> +<p><strong>To upgrade or install FURY</strong></p> +<p>Run the following command in your terminal:</p> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">pip</span> <span class="n">install</span> <span class="o">--</span><span class="n">upgrade</span> <span class="n">fury</span> +</pre></div> +</div> +<p>or:</p> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">conda</span> <span class="n">install</span> <span class="o">-</span><span class="n">c</span> <span class="n">conda</span><span class="o">-</span><span class="n">forge</span> <span class="n">fury</span> +</pre></div> +</div> +<p><strong>Questions or suggestions?</strong></p> +<p>For any questions go to <a class="reference external" href="http://fury.gl">http://fury.gl</a>, or send an e-mail to <a class="reference external" href="mailto:fury&#37;&#52;&#48;python&#46;org">fury<span>&#64;</span>python<span>&#46;</span>org</a> +We can also join our <a class="reference external" href="https://discord.gg/6btFPPj">discord community</a></p> +<p>We would like to thanks to <a class="reference internal" href="../../community.html#community"><span class="std std-ref">all contributors</span></a> for this release:</p> +<ul class="simple"> +<li><p>Eleftherios Garyfallidis</p></li> +<li><p>Serge Koudoro</p></li> +<li><p>Charles Poirier</p></li> +<li><p>Javier Guaje</p></li> +<li><p>Soham Biswas</p></li> +<li><p>Sajag Swami</p></li> +<li><p>Lenix Lobo</p></li> +<li><p>Pietro Astolfi</p></li> +<li><p>Sanjay Marreddi</p></li> +<li><p>Tushar</p></li> +<li><p>ganimtron-10</p></li> +<li><p>haran2001</p></li> +<li><p>Aju100</p></li> +<li><p>Aman Soni</p></li> +</ul> +<p>On behalf of the <a class="reference internal" href="../../community.html#community"><span class="std std-ref">FURY developers</span></a>,</p> +<p>Serge K.</p> +</section> + + + The FURY project is happy to announce the release of FURY 0.7.0! +FURY is a free and open source software library for scientific visualization and 3D animations. + + 2021-03-13T00:00:00-05:00 + + + https://fury.gl/posts/2020/2020-08-18-release-announcement.html + FURY 0.6.1 Released + 2020-08-18T00:00:00-04:00 + + Serge Koudoro + + <section id="fury-0-6-1-released"> + +<p>The FURY project is happy to announce the release of FURY 0.6.1! +FURY is a free and open source software library for scientific visualization and 3D animations.</p> +<p>You can show your support by <a class="reference external" href="https://github.com/fury-gl/fury/stargazers">adding a star</a> on FURY github project.</p> +<p>This Release is mainly a maintenance release. The <strong>major highlights</strong> of this release are:</p> +<ul class="simple"> +<li><p>Added Shaders Manager.</p></li> +<li><p>Standardized colors across API.</p></li> +<li><p>Added a new UI Tab.</p></li> +<li><p>Added Physics Engine Tutorial.</p></li> +<li><p>Large documentation update, examples and tutorials (4 new).</p></li> +<li><p>Increased tests coverage and code quality.</p></li> +</ul> +<div class="admonition note"> +<p class="admonition-title">Note</p> +<p>The complete release notes are available <a class="reference internal" href="../../release_notes/releasev0.6.1.html#releasev0-6-1"><span class="std std-ref">here</span></a></p> +</div> +<p><strong>To upgrade or install FURY</strong></p> +<p>Run the following command in your terminal:</p> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">pip</span> <span class="n">install</span> <span class="o">--</span><span class="n">upgrade</span> <span class="n">fury</span> +</pre></div> +</div> +<p>or:</p> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">conda</span> <span class="n">install</span> <span class="o">-</span><span class="n">c</span> <span class="n">conda</span><span class="o">-</span><span class="n">forge</span> <span class="n">fury</span> +</pre></div> +</div> +<p><strong>Questions or suggestions?</strong></p> +<p>For any questions go to <a class="reference external" href="http://fury.gl">http://fury.gl</a>, or send an e-mail to <a class="reference external" href="mailto:fury&#37;&#52;&#48;python&#46;org">fury<span>&#64;</span>python<span>&#46;</span>org</a> +We can also join our <a class="reference external" href="https://discord.gg/6btFPPj">discord community</a></p> +<p>We would like to thanks to <a class="reference internal" href="../../community.html#community"><span class="std std-ref">all contributors</span></a> for this release:</p> +<ul class="simple"> +<li><p>Eleftherios Garyfallidis</p></li> +<li><p>Javier Guaje</p></li> +<li><p>Lenix Lobo</p></li> +<li><p>Melina Raglin</p></li> +<li><p>Nasim Anousheh</p></li> +<li><p>Serge Koudoro</p></li> +<li><p>Soham Biswas</p></li> +<li><p>Vivek Choudhary</p></li> +</ul> +<p>On behalf of the <a class="reference internal" href="../../community.html#community"><span class="std std-ref">FURY developers</span></a>,</p> +<p>Serge K.</p> +</section> + + + The FURY project is happy to announce the release of FURY 0.6.1! +FURY is a free and open source software library for scientific visualization and 3D animations. + + 2020-08-18T00:00:00-04:00 + + + https://fury.gl/posts/2020/2020-07-20-release-announcement.html + FURY 0.6.0 Released + 2020-07-20T00:00:00-04:00 + + Serge Koudoro + + <section id="fury-0-6-0-released"> + +<p>The FURY project is happy to announce the release of FURY 0.6.0! +FURY is a free and open source software library for scientific visualization and 3D animations.</p> +<p>You can show your support by <a class="reference external" href="https://github.com/fury-gl/fury/stargazers">adding a star</a> on FURY github project.</p> +<p>The <strong>major highlights</strong> of this release are:</p> +<ul class="simple"> +<li><p>Added new features: Picking and double-click callback.</p></li> +<li><p>Added Signed Distance Field actor.</p></li> +<li><p>Added a new UI ComboBox.</p></li> +<li><p>Added multiples primitives (Rhombocuboctahedron, …).</p></li> +<li><p>Huge improvement of multiple UIs and actors.</p></li> +<li><p>Fixed Compatibility with VTK9.</p></li> +<li><p>Large documentation update, examples and tutorials (5 new).</p></li> +<li><p>Added a blog system.</p></li> +<li><p>Increased tests coverage and code quality.</p></li> +</ul> +<div class="admonition note"> +<p class="admonition-title">Note</p> +<p>The complete release notes are available <a class="reference internal" href="../../release_notes/releasev0.6.0.html#releasev0-6-0"><span class="std std-ref">here</span></a></p> +</div> +<p><strong>To upgrade or install FURY</strong></p> +<p>Run the following command in your terminal:</p> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">pip</span> <span class="n">install</span> <span class="o">--</span><span class="n">upgrade</span> <span class="n">fury</span> +</pre></div> +</div> +<p>or:</p> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">conda</span> <span class="n">install</span> <span class="o">-</span><span class="n">c</span> <span class="n">conda</span><span class="o">-</span><span class="n">forge</span> <span class="n">fury</span> +</pre></div> +</div> +<p><strong>Questions or suggestions?</strong></p> +<p>For any questions go to <a class="reference external" href="http://fury.gl">http://fury.gl</a>, or send an e-mail to <a class="reference external" href="mailto:fury&#37;&#52;&#48;python&#46;org">fury<span>&#64;</span>python<span>&#46;</span>org</a> +We can also join our <a class="reference external" href="https://discord.gg/6btFPPj">discord community</a></p> +<p>We would like to thanks to <a class="reference internal" href="../../community.html#community"><span class="std std-ref">all contributors</span></a> for this release:</p> +<ul class="simple"> +<li><p>Eleftherios Garyfallidis</p></li> +<li><p>Liam Donohue</p></li> +<li><p>Marc-Alexandre Côté</p></li> +<li><p>Melina Raglin</p></li> +<li><p>Naman Bansal</p></li> +<li><p>Serge Koudoro</p></li> +<li><p>Soham Biswas</p></li> +<li><p>Tushar</p></li> +<li><p>Lenix Lobo</p></li> +</ul> +<p>On behalf of the <a class="reference internal" href="../../community.html#community"><span class="std std-ref">FURY developers</span></a>,</p> +<p>Serge K.</p> +</section> + + + The FURY project is happy to announce the release of FURY 0.6.0! +FURY is a free and open source software library for scientific visualization and 3D animations. + + 2020-07-20T00:00:00-04:00 + + + https://fury.gl/posts/2020/2020-04-09-release-announcement.html + FURY 0.5.1 Released + 2020-04-09T00:00:00-04:00 + + Serge Koudoro + + <section id="fury-0-5-1-released"> + +<p>The FURY project is happy to announce the release of FURY 0.5.1! +FURY is a free and open source software library for scientific visualization and 3D animations.</p> +<p>You can show your support by <a class="reference external" href="https://github.com/fury-gl/fury/stargazers">adding a star</a> on FURY github project.</p> +<p>The <strong>major highlights</strong> of this release are:</p> +<ul class="simple"> +<li><p>Remove python 2 compatibility</p></li> +<li><p>Added texture management</p></li> +<li><p>Added multiples primitives.</p></li> +<li><p>Added multiples actors (contour_from_label, billboard…)</p></li> +<li><p>Huge improvement of multiple UI (RangeSlider, …)</p></li> +<li><p>Improved security (from md5 to sha256)</p></li> +<li><p>Large documentation update, examples and tutorials</p></li> +<li><p>Increased tests coverage and code quality</p></li> +</ul> +<div class="admonition note"> +<p class="admonition-title">Note</p> +<p>The complete release notes are available <a class="reference internal" href="../../release_notes/releasev0.5.1.html#releasev0-5-1"><span class="std std-ref">here</span></a></p> +</div> +<p><strong>To upgrade or install FURY</strong></p> +<p>Run the following command in your terminal:</p> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">pip</span> <span class="n">install</span> <span class="o">--</span><span class="n">upgrade</span> <span class="n">fury</span> +</pre></div> +</div> +<p>or:</p> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">conda</span> <span class="n">install</span> <span class="o">-</span><span class="n">c</span> <span class="n">conda</span><span class="o">-</span><span class="n">forge</span> <span class="n">fury</span> +</pre></div> +</div> +<p><strong>Questions or suggestions?</strong></p> +<p>For any questions go to <a class="reference external" href="http://fury.gl">http://fury.gl</a>, or send an e-mail to <a class="reference external" href="mailto:fury&#37;&#52;&#48;python&#46;org">fury<span>&#64;</span>python<span>&#46;</span>org</a> +We can also join our <a class="reference external" href="https://discord.gg/6btFPPj">discord community</a></p> +<p>We would like to thanks to <a class="reference internal" href="../../community.html#community"><span class="std std-ref">all contributors</span></a> for this release:</p> +<ul class="simple"> +<li><p>ChenCheng0630</p></li> +<li><p>Devanshu Modi</p></li> +<li><p>Eleftherios Garyfallidis</p></li> +<li><p>Etienne St-Onge</p></li> +<li><p>Filipi Nascimento Silva</p></li> +<li><p>Gottipati Gautam</p></li> +<li><p>Javier Guaje</p></li> +<li><p>Jon Haitz Legarreta Gorroño</p></li> +<li><p>Liam Donohue</p></li> +<li><p>Marc-Alexandre Côté</p></li> +<li><p>Marssis</p></li> +<li><p>Naman Bansal</p></li> +<li><p>Nasim</p></li> +<li><p>Saransh Jain</p></li> +<li><p>Serge Koudoro</p></li> +<li><p>Shreyas Bhujbal</p></li> +<li><p>Soham Biswas</p></li> +<li><p>Vivek Choudhary</p></li> +<li><p>ibrahimAnis</p></li> +<li><p>lenixlobo</p></li> +</ul> +<p>On behalf of the <a class="reference internal" href="../../community.html#community"><span class="std std-ref">FURY developers</span></a>,</p> +<p>Serge K.</p> +</section> + + + The FURY project is happy to announce the release of FURY 0.5.1! +FURY is a free and open source software library for scientific visualization and 3D animations. + + 2020-04-09T00:00:00-04:00 + + + https://fury.gl/posts/2019/2019-10-29-release-announcement.html + FURY 0.4.0 Released + 2019-10-29T00:00:00-04:00 + + Serge Koudoro + + <section id="fury-0-4-0-released"> + +<p>The FURY project is happy to announce the release of FURY 0.4.0! +FURY is a free and open source software library for scientific visualization and 3D animations.</p> +<p>You can show your support by <a class="reference external" href="https://github.com/fury-gl/fury/stargazers">adding a star</a> on FURY github project.</p> +<p>The <strong>major highlights</strong> of this release are:</p> +<ul class="simple"> +<li><p>Enable Anti aliasing and frame rate features</p></li> +<li><p>Add multiples actors (arrow, box, …)</p></li> +<li><p>Glyph extensions</p></li> +<li><p>Remove Nose dependency</p></li> +<li><p>Replace Appveyor by Azure pipeline for Windows</p></li> +<li><p>Update Documentation, examples and tutorials</p></li> +<li><p>Increase tests coverage and code quality</p></li> +</ul> +<div class="admonition note"> +<p class="admonition-title">Note</p> +<p>The complete release notes are <a class="reference internal" href="../../release_notes/releasev0.4.0.html#releasev0-4-0"><span class="std std-ref">available here</span></a></p> +</div> +<p><strong>To upgrade or install FURY</strong></p> +<p>Run the following command in your terminal:</p> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">pip</span> <span class="n">install</span> <span class="o">--</span><span class="n">upgrade</span> <span class="n">fury</span> +</pre></div> +</div> +<p>or:</p> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">conda</span> <span class="n">install</span> <span class="o">-</span><span class="n">c</span> <span class="n">conda</span><span class="o">-</span><span class="n">forge</span> <span class="n">fury</span> +</pre></div> +</div> +<p><strong>Questions or suggestions?</strong></p> +<p>For any questions go to <a class="reference external" href="http://fury.gl">http://fury.gl</a>, or send an e-mail to <a class="reference external" href="mailto:fury&#37;&#52;&#48;python&#46;org">fury<span>&#64;</span>python<span>&#46;</span>org</a> +We can also join our <a class="reference external" href="https://discord.gg/6btFPPj">discord community</a></p> +<p>We would like to thanks to <a class="reference internal" href="../../community.html#community"><span class="std std-ref">all contributors</span></a> for this release:</p> +<ul class="simple"> +<li><p>Eleftherios Garyfallidis</p></li> +<li><p>Etienne St-Onge</p></li> +<li><p>Javier Guaje</p></li> +<li><p>Serge Koudoro</p></li> +</ul> +<p>On behalf of the <a class="reference internal" href="../../community.html#community"><span class="std std-ref">FURY developers</span></a>,</p> +<p>Serge K.</p> +</section> + + + The FURY project is happy to announce the release of FURY 0.4.0! +FURY is a free and open source software library for scientific visualization and 3D animations. + + 2019-10-29T00:00:00-04:00 + + + https://fury.gl/posts/2019/2019-08-02-release-announcement.html + FURY 0.3.0 Released + 2019-08-02T00:00:00-04:00 + + Serge Koudoro + + <section id="fury-0-3-0-released"> + +<p>The FURY project is happy to announce the release of FURY 0.3.0! +FURY is a free and open source software library for scientific visualization and 3D animations.</p> +<p>You can show your support by <a class="reference external" href="https://github.com/fury-gl/fury/stargazers">adding a star</a> on FURY github project.</p> +<p>The <strong>major highlights</strong> of this release are:</p> +<ul class="simple"> +<li><p>Add cone actor and update odf actor</p></li> +<li><p>Add Appveyor CI and update MacOS CI</p></li> +<li><p>Update Documentation, examples and tutorials</p></li> +<li><p>Increase tests coverage and code quality</p></li> +</ul> +<div class="admonition note"> +<p class="admonition-title">Note</p> +<p>The complete release notes are <a class="reference internal" href="../../release_notes/releasev0.3.0.html#releasev0-3-0"><span class="std std-ref">available here</span></a></p> +</div> +<p><strong>To upgrade or install FURY</strong></p> +<p>Run the following command in your terminal:</p> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">pip</span> <span class="n">install</span> <span class="o">--</span><span class="n">upgrade</span> <span class="n">fury</span> +</pre></div> +</div> +<p>or:</p> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">conda</span> <span class="n">install</span> <span class="o">-</span><span class="n">c</span> <span class="n">conda</span><span class="o">-</span><span class="n">forge</span> <span class="n">fury</span> +</pre></div> +</div> +<p><strong>Questions or suggestions?</strong></p> +<p>For any questions go to <a class="reference external" href="http://fury.gl">http://fury.gl</a>, or send an e-mail to <a class="reference external" href="mailto:fury&#37;&#52;&#48;python&#46;org">fury<span>&#64;</span>python<span>&#46;</span>org</a> +We can also join our <a class="reference external" href="https://discord.gg/6btFPPj">discord community</a></p> +<p>We would like to thanks to <a class="reference internal" href="../../community.html#community"><span class="std std-ref">all contributors</span></a> for this release:</p> +<ul class="simple"> +<li><p>Ariel Rokem</p></li> +<li><p>Eleftherios Garyfallidis</p></li> +<li><p>Guillaume Favelier</p></li> +<li><p>Kevin Sitek</p></li> +<li><p>Prashil</p></li> +<li><p>Scott Trinkle</p></li> +<li><p>Serge Koudoro</p></li> +</ul> +<p>On behalf of the <a class="reference internal" href="../../community.html#community"><span class="std std-ref">FURY developers</span></a>,</p> +<p>Serge K.</p> +</section> + + + The FURY project is happy to announce the release of FURY 0.3.0! +FURY is a free and open source software library for scientific visualization and 3D animations. + + 2019-08-02T00:00:00-04:00 + + + https://fury.gl/posts/2019/2019-03-08-release-announcement.html + FURY 0.2.0 Released + 2019-03-08T00:00:00-05:00 + + Serge Koudoro + + <section id="fury-0-2-0-released"> + +<p>The FURY project is happy to announce the release of FURY 0.2.0! +FURY is a free and open source software library for scientific visualization and 3D animations.</p> +<p>You can show your support by <a class="reference external" href="https://github.com/fury-gl/fury/stargazers">adding a star</a> on FURY github project.</p> +<p>The <strong>major highlights</strong> of this release are:</p> +<ul class="simple"> +<li><p>Replace <code class="docutils literal notranslate"><span class="pre">fury.window.Renderer</span></code> by <code class="docutils literal notranslate"><span class="pre">fury.window.Scene</span></code></p></li> +<li><p>Add stereo support</p></li> +<li><p>Add GridUI object</p></li> +<li><p>Increase tests coverage and code quality</p></li> +</ul> +<div class="admonition note"> +<p class="admonition-title">Note</p> +<p>The complete release notes are <a class="reference internal" href="../../release_notes/releasev0.2.0.html#releasev0-2-0"><span class="std std-ref">available here</span></a></p> +</div> +<p><strong>To upgrade or install FURY</strong></p> +<p>Run the following command in your terminal:</p> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">pip</span> <span class="n">install</span> <span class="o">--</span><span class="n">upgrade</span> <span class="n">fury</span> +</pre></div> +</div> +<p>or:</p> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">conda</span> <span class="n">install</span> <span class="o">-</span><span class="n">c</span> <span class="n">conda</span><span class="o">-</span><span class="n">forge</span> <span class="n">fury</span> +</pre></div> +</div> +<p><strong>Questions or suggestions?</strong></p> +<p>For any questions go to <a class="reference external" href="http://fury.gl">http://fury.gl</a>, or send an e-mail to <a class="reference external" href="mailto:fury&#37;&#52;&#48;python&#46;org">fury<span>&#64;</span>python<span>&#46;</span>org</a> +We can also join our <a class="reference external" href="https://discord.gg/6btFPPj">discord community</a></p> +<p>We would like to thanks to <a class="reference internal" href="../../community.html#community"><span class="std std-ref">all contributors</span></a> for this release:</p> +<ul class="simple"> +<li><p>David Reagan</p></li> +<li><p>Eleftherios Garyfallidis</p></li> +<li><p>Jon Haitz Legarreta Gorroño</p></li> +<li><p>Marc-Alexandre Côté</p></li> +<li><p>Serge Koudoro</p></li> +</ul> +<p>On behalf of the <a class="reference internal" href="../../community.html#community"><span class="std std-ref">FURY developers</span></a>,</p> +<p>Serge K.</p> +</section> + + + The FURY project is happy to announce the release of FURY 0.2.0! +FURY is a free and open source software library for scientific visualization and 3D animations. + + 2019-03-08T00:00:00-05:00 + + diff --git a/v0.10.x/blog/tag/google.html b/v0.10.x/blog/tag/google.html new file mode 100644 index 000000000..af73965e0 --- /dev/null +++ b/v0.10.x/blog/tag/google.html @@ -0,0 +1,11891 @@ + + + + + + + Posts tagged google — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +
+

+ + Posts tagged + + google + +

+ + +
+

+ Google Summer of Code Final Work Product +

+
    +
  • + + + 25 August 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Name: Praneeth Shetty

+

+ +

Read more ...

+
+
+ +
+

+ Week 12 : Experimenting with ODFs implementation +

+
    +
  • + + + 24 August 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Tania Castillo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

There were different issues I needed to address for the ODF implementation. Even though I could not solve any of them completely, I did check each of the issues and made some progress. All the work in progress is being recorded in the following branch SH-for-ODF-impl, which when ready will be associated with a well-structured PR.

+

+ +

Read more ...

+
+
+ +
+

+ Google Summer of Code Final Work Product +

+
    +
  • + + + 24 August 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Tania Castillo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Name: Tania Castillo

+

+ +

Read more ...

+
+
+ +
+

+ Week 12: Now That is (almost) a Wrap! +

+ +

Hello everyone, it’s time for another GSoC blogpost! Today, I am going to talk about some minor details I worked on last week on my +project.

+

+ +

Read more ...

+
+
+ +
+

+ Google Summer of Code Final Work Product +

+ +

Name: João Victor Dell Agli Floriano

+

+ +

Read more ...

+
+
+ +
+

+ Week 12: FileDialog Quest Begins! +

+
    +
  • + + + 19 August 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

During this week, I initiated my work on the FileDialog PR, which had been started by Soham. The initial version of the FileDialog can be found at #294. To start, I focused on rebasing the PR. Since this PR was based on an older version, there were some updates to the overall UI structure that needed to be addressed for compatibility. While handling this, I identified a set of issues that I documented in the current PR #832. These mainly revolved around:

+

+ +

Read more ...

+
+
+ +
+

+ Week 11 : Adjusting ODF implementation and looking for solutions on issues found +

+
    +
  • + + + 16 August 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Tania Castillo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

I continued to experiment with the ODF glyph implementation. Thanks to one of my mentors I figured out how to get the missing data corresponding to the SH coefficients \(a^l_m\) part of the function \(f(\theta, \phi)\) described here. I also was told to make sure to implement the correct SH basis since there are different definitions from the literature, I have to focus now in the one proposed by Descoteaux, described in this paper, which is labeled in dipy as descoteaux07. To do this I had to make a small adjustment to the base implementation that I took as a reference, from which I obtained a first result using SH of order 4.

+

+ +

Read more ...

+
+
+ +
+

+ Week 11: A Refactor is Sometimes Needed +

+ +

Hello everyone, it’s time for another weekly blogpost! Today I am going to share some updates on the API refactoring +I was working on with my mentors.

+

+ +

Read more ...

+
+
+ +
+

+ Week 11: Bye Bye SpinBox +

+
    +
  • + + + 12 August 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Building upon the progress of the previous week, a major milestone was reached with the merging of PR #830. This PR added essential “getters” and “setters” for the new features of TextBlock, making it easier to handle changes. This, in turn, facilitated the integration of SpinBoxUI with the updated TextBlock.

+

+ +

Read more ...

+
+
+ +
+

+ Week 10 : Start of SH implementation experiments +

+
    +
  • + + + 08 August 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Tania Castillo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

I started formally working on SH implementation. I was told to start first doing a simple program where I can modify in real-time the order \(l\) and degree \(m\), parameters corresponding to the Spherical Harmonics function \(Y^m_l(\theta,\phi)=\), based on previous work. That is just one part of the final ODF calculation, but here is what a first experimental script looks like.

+

+ +

Read more ...

+
+
+ +
+

+ Week 10: Ready for Review! +

+ +

Hello everyone, it’s time for another weekly blogpost!

+

+ +

Read more ...

+
+
+ +
+

+ Week 10: Its time for a Spin-Box! +

+
    +
  • + + + 05 August 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week, my focus shifted to the SpinBoxUI after wrapping up work on TextBlock2D. SpinBoxUI is a component that allows users to select a value by spinning through a range. To ensure a smooth transition, I made adjustments in SpinBoxUI to align it with the recent updates in TextBlock2D. To make things even clearer and more user-friendly, I initiated a continuous code improvement process. I introduced setters and getters that enable easier customization of TextBlock2D’s new features, such as auto_font_scale and dynamic_bbox. These tools simplify the process of adjusting these settings, and you can see the ongoing changes in pull request #830.

+

+ +

Read more ...

+
+
+ +
+

+ Week 9: Tutorial done and polishing DTI uncertainty +

+
    +
  • + + + 31 July 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Tania Castillo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

I addressed the comments from the tutorial of PR #818 related to how to display specific visualizations I wanted to make. I was suggested to use ShowManager to handle the zoom of the scene and also to use GridUI to display several actors at the same time for a visual quality comparison of the tensors. Below are some images generated for the tutorial that is almost done.

+

+ +

Read more ...

+
+
+ +
+

+ Week 9: It is Polishing Time! +

+ +

Hello everyone, it’s time for another weekly blogpost! Today, I am going to update you on my project’s latest changes.

+

+ +

Read more ...

+
+
+ +
+

+ Week 9: TextBlock2D is Finally Merged! +

+
    +
  • + + + 29 July 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Continuing from the previous week, it seemed like we were almost done with the TextBlock2D, but there remained a final task of addressing conflicting issues. Being a core part of the UI, TextBlock2D had a few compatibility problems with certain other UI elements.

+

+ +

Read more ...

+
+
+ +
+

+ Week 8: Working on Ellipsoid Tutorial and exploring SH +

+
    +
  • + + + 25 July 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Tania Castillo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

I mainly worked on the ellipsoid actor tutorial, as PR #791 is finally merged, so I was able to complete the tutorial by adding my implementation. In addition, during the weekly meeting, I received a good overview of the next issue I will be working on, which is using raymarching SDFs to display spherical harmonics (SH) for visualizing ODF glyphs for DTI. I got several ideas and resources which I can start experimenting with, such as Shadertoy and some base implementations from other FURY contributors. The main drawback when creating these objects is the amount of data required to create them, because depending on the SH order, the number of parameters that the function receives may vary, also unlike the tensors, which are represented only with a 3x3 matrix, here we could have more than 9 values associated with a single glyph, so passing the information from python to the shaders is not so trivial, besides requiring more resources as there is more information that needs to be processed. Some ideas I received were using matrixes instead of vectors, using templating, or even using texture to pass the data. I started to explore these options further, as well as to review in more detail the existing implementations of SH with raymarching, in order to understand them better.

+

+ +

Read more ...

+
+
+ +
+

+ Week 8: The Birth of a Versatile API +

+ +

Hello everyone, it’s time for another weekly blogpost! Today, I am going to tell you all about how is the KDE API development going, and +to show you the potential this holds for the future!

+

+ +

Read more ...

+
+
+ +
+

+ Week 8: Another week with TextBlockUI +

+
    +
  • + + + 22 July 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week, I delved deeper into the TextBlock2D Bounding Box PR to address the challenges with tests and offsetting issues. In a pair programming session with my mentor, we discovered that the offsetting background problem stemmed from the dynamic nature of the bounding box. The issue arose when the RingSlider2D component began with an initial text size larger than the current text, which changed as the value was adjusted between 0-100%. This resulted in problems with offsetting and shrinking the bounding box. To resolve this, we decided to make the dynamic bounding box an optional feature.

+

+ +

Read more ...

+
+
+ +
+

+ Week 7: Experimentation Done +

+ +

Hello everyone, welcome to another weekly blogpost! Let’s talk about the current status of my project (spoiler: it is beautiful).

+

+ +

Read more ...

+
+
+ +
+

+ Week 7: Adjustments on the Uncertainty Cones visualization +

+
    +
  • + + + 17 July 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Tania Castillo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

I was told to refactor some parts of the uncertainty PR, since I was relying too much on dipy functions which is not good because it makes maintenance more difficult as dipy requires FURY for some functionalities. So I did some adjustments on the uncertainty function parameters and the corresponding tests, hopefully I managed to get with the most appropriate definition but I need to receive a first feedback to see how much I have to adjust the implementation. As I had to delete some relevant code lines inside the uncertainty calculation which consisted of preprocessing the data in order to define the necessary variables for the uncertainty formula, I was also suggested to make a tutorial of this new feature, so I can explain in detail how to obtain and adjust the necessary information, before passing it to the actor, and in general how and what is the purpose of this new function.

+

+ +

Read more ...

+
+
+ +
+

+ Week 7: Sowing the seeds for TreeUI +

+
    +
  • + + + 15 July 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week, I focused on completing the TextBlock2D Bounding Box feature. However, the tests were failing due to automatic background resizing based on content and improper text actor alignment during setup. I encountered difficulties while positioning the text, which caused the text to appear offset and led to test failures.

+

+ +

Read more ...

+
+
+ +
+

+ Week 6: Things are Starting to Build Up +

+ +

Hello everyone, time for a other weekly blogpost! Today, I will show you my current progress on my project and latest activities.

+

+ +

Read more ...

+
+
+ +
+

+ Week 6: First draft of the Ellipsoid tutorial +

+
    +
  • + + + 10 July 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Tania Castillo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

#PR 818: Tutorial on using ellipsoid actor to visualize tensor ellipsoids for DTI

+

+ +

Read more ...

+
+
+ +
+

+ Week 6: BoundingBox for TextBlock2D! +

+
    +
  • + + + 08 July 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week, I worked on improving the TextBlock2D component in the UI system. I started from scratch to address alignment and scaling issues. When resizing the TextBlock2D, the text alignment and justification with the background rectangle were inconsistent. To resolve this, I introduced a new “boundingbox” property that calculates the text bounding box based on its content. Additionally, I separated the scaling mode from the resizing action with the new “auto_font_scale” property, enabling automatic font scaling according to the bounding box. This will provide better alignment, justified text, and smoother font scaling for the TextBlock2D component. Try it out at PR #803.

+

+ +

Read more ...

+
+
+ +
+

+ Week 5: Preparing the data for the Ellipsoid tutorial +

+
    +
  • + + + 03 July 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Tania Castillo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

During the weekly meeting with my mentors, there was a small discussion over the naming of the actor and its usage. On the one hand, although the purpose of the actor is to visualize diffusion tensor ellipsoids, the idea is that it can also be used for any other type of visualization that requires the use of ellipsoids, so in the end, we decided to keep the name ellipsoid as it is more generic. On the other hand, as there is already an actor made for the purpose of tensor visualization, namely tensor_slicer, it might not be obvious how and why one would use this new ellipsoid actor for this purpose, thus it was proposed to make a tutorial that can clarify this. The main difference between both actors relies on the quality and the amount of data that can be displayed, so the idea is to show the difference between both alternatives so the user can choose which one to use depending on their needs. To prepare the tutorial the first step was to add the data I will use on fury-data so I can then fetch and load the datasets I need to work on the tutorial.

+

+ +

Read more ...

+
+
+ +
+

+ Week 5: All Roads Lead to Rome +

+ +

Hello everyone, time for another weekly blogpost! Today, we will talk about taking different paths to reach your objective.

+

+ +

Read more ...

+
+
+ +
+

+ Week 5: Trying out PRs and Planning Ahead +

+
    +
  • + + + 01 July 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Due to ongoing exams, my productivity was limited this week. However, I managed to find some time to explore and review a few PRs submitted by contributors:

+

+ +

Read more ...

+
+
+ +
+

+ Week 4: First draft of the DTI uncertainty visualization +

+
    +
  • + + + 27 June 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Tania Castillo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

#PR 810: DTI uncertainty visualization

+

+ +

Read more ...

+
+
+ +
+

+ Week 4: Nothing is Ever Lost +

+ +

Welcome again to another weekly blogpost! Today, let’s talk about the importance of guidance throughout a project.

+

+ +

Read more ...

+
+
+ +
+

+ Week 4: Exam Preparations and Reviewing +

+
    +
  • + + + 24 June 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week, amidst end-semester exams, I managed to accomplish a few notable tasks. Let’s dive into the highlights:

+

+ +

Read more ...

+
+
+ +
+

+ Week 3: Working on uncertainty and details of the first PR +

+
    +
  • + + + 19 June 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Tania Castillo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

I made some adjustments to the ellipsoid actor definition, now called tensor. This was something discussed in the weekly meeting as the coming changes are related to this actor, the idea now is to have a tensor actor that allows choosing between displaying the tensor ellipsoids or the uncertainty cones (later on). I also worked on the uncertainty calculation, and the cone SDF for the visualization, so I plan to do a WIP PR next to start getting feedback on this new addition.

+

+ +

Read more ...

+
+
+ +
+

+ Week 3: Watch Your Expectations +

+ +

Hello everyone, it’s time for another weekly blogpost! This week, +I will talk about how you should watch your expectations when working with any project.

+

+ +

Read more ...

+
+
+ +
+

+ Week 3: Resolving Combobox Icon Flaw and TextBox Justification +

+
    +
  • + + + 17 June 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week, I tackled the ComboBox2D icon flaw, which was addressed using Pull Request (PR) #576. The problem arose when we added a ComboBox2D to the TabUI. The TabUI would propagate the set_visibility = true for all its child elements, causing the combobox to appear on the screen without the icon change. To fix this issue, PR #768 updated the set_visibility method of the UI class, ensuring that the icon change was applied correctly.

+

+ +

Read more ...

+
+
+ +
+

+ Week 2: The Importance of (good) Documentation +

+ +

Hello everybody, welcome to the week 2 of this project! I must admit I thought this would be simpler than it is currently being, but I forgot that when it comes to dealing with computer graphics’ applications, things never are. Below, some updates on what I have been up to for this past week.

+

+ +

Read more ...

+
+
+ +
+

+ Week 2: Making adjustments to the Ellipsoid Actor +

+
    +
  • + + + 12 June 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Tania Castillo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

I made some minor adjustments to the last PR I submitted. Last time it was a draft since I was waiting for the weekly meeting to know how to proceed, but now it is ready. I am waiting for the review so I can make the necessary corrections and adjustments to merge this first PR soon.

+

+ +

Read more ...

+
+
+ +
+

+ Week 2: Tackling Text Justification and Icon Flaw Issues +

+
    +
  • + + + 11 June 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week, I continued tweaking the text justification PR #790 and encountered a new issue when combining both justification and vertical_justification. The problem arose because the vertical_justification did not take into account the applied justification, resulting in unexpected behavior. I focused on resolving this issue by ensuring that both justifications work together correctly. Additionally, during the weekly meeting, we discussed the problem and decided to introduce new properties such as boundaries and padding to enhance the functionality of the text justification feature.

+

+ +

Read more ...

+
+
+ +
+

+ Week 1: Ellipsoid actor implemented with SDF +

+
    +
  • + + + 05 June 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Tania Castillo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

PR #791: Ellipsoid actor implemented with SDF

+

+ +

Read more ...

+
+
+ +
+

+ The FBO Saga - Week 1 +

+ +

As mentioned in the last week’s blogpost, the goal for that week was to investigate VTK’s Framebuffer Object framework. +An update on that is that indeed, VTK has one more low-level working FBO class that can be used inside FURY, however, +they come with some issues that I will explain further below.

+

+ +

Read more ...

+
+
+ +
+

+ Week 1: Working with SpinBox and TextBox Enhancements +

+
    +
  • + + + 03 June 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week, my focus was on reviewing pull requests (PRs) and issues related to the user interface (UI) of the project. I meticulously went through each PR and issue, identifying those specifically associated with UI improvements. To streamline the process, I categorized them accordingly under the UI category. One of the key tasks was PR #499, which involved the implementation of SpinBoxUI. After rebasing the PR, I identified an alignment issue with the textbox component.

+

+ +

Read more ...

+
+
+ +
+

+ Week 0: Community Bounding Period +

+
    +
  • + + + 02 June 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hello All!

+

+ +

Read more ...

+
+
+ +
+

+ Week 0: Community Bounding Period +

+
    +
  • + + + 02 June 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Tania Castillo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hello everyone, my name is Tania Castillo, I am close to finishing my degree in Computer Science and I think this is a great opportunity to put my learning and skills into practice. I will be working with FURY on improving the visualization of DTI tensors and HARDI ODFs glyphs by using well-known techniques in computer graphics.

+

+ +

Read more ...

+
+
+ +
+

+ The Beginning of Everything - Week 0 +

+ +

Hello everyone, welcome to the beginning of my journey through GSoC 2023! I would like to thank everyone involved for the opportunity provided, it is an honour to be working side by side with professionals and so many experienced people from around the world.

+

+ +

Read more ...

+
+
+ +
+

+ Contribute to FURY via Google Summer of Code 2023 +

+
    +
  • + + + 01 February 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Serge Koudoro + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

FURY is participating in the Google Summer of Code 2023 under the umbrella of the Python Software Foundation.

+

+ +

Read more ...

+
+
+ +
+

+ Google Summer of Code Final Work Product +

+
    +
  • + + + 29 January 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Mohamed Abouagour + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Name: Mohamed Abouagour

+

+ +

Read more ...

+
+
+ +
+

+ Google Summer of Code Final Work Product +

+
    +
  • + + + 29 January 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Shivam Anand + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Name: Shivam Anand

+

+ +

Read more ...

+
+
+ +
+

+ Google Summer of Code Final Work Product +

+
    +
  • + + + 24 January 2023 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Name: Praneeth Shetty

+

+ +

Read more ...

+
+
+ +
+

+ Week 14: Keyframes animation is now a bit easier in FURY +

+
    +
  • + + + 28 September 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Mohamed Abouagour + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Separated the Timeline into a Timeline and an Animation. So, instead of having the Timeline do everything. It’s now more like doing animations in Blender and other 3D editing software where the timeline handles the playback of several animations #694.

+

+ +

Read more ...

+
+
+ +
+

+ Week 14 - Morphing is here! +

+
    +
  • + + + 28 September 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Shivam Anand + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week, I started with multiple actor support in skinning and managed to do it +successfully. Here’s the preview using the BrainStem model.

+

+ +

Read more ...

+
+
+ +
+

+ Week 16 - Working with Rotations! +

+
    +
  • + + + 21 September 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Last week my mentors noticed that each DrawShape has its individual rotation_slider which increases redundancy and complexity in setting its visibility on and off. Instead, they suggested moving the rotation_slider to DrawPanel and keeping a common slider for all the shapes.

+

+ +

Read more ...

+
+
+ +
+

+ Week 13: Keyframes animation is now a bit easier in FURY +

+
    +
  • + + + 20 September 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Mohamed Abouagour + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Added the ability to have the ShowManager stored inside the Timeline. That way the user does not have to update and render the animations because it will be done internally.

+

+ +

Read more ...

+
+
+ +
+

+ Week 13 - Multi-bone skeletal animation support +

+
    +
  • + + + 15 September 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Shivam Anand + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week I fixed all the issues with skeletal animations, and we got to see our first render of skeletal animation :).

+

+ +

Read more ...

+
+
+ +
+

+ Week 15 - Highlighting DrawShapes +

+
    +
  • + + + 14 September 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week I started with highlighting the shapes. As discussed earlier, I had two ways, but while implementing them, I found out both ways aren’t that good to continue with. +The first way in which we thought of creating the scaled shapes in the background had an issue with the stacking. The border(blue rectangle) and the shape(grey rectangle) both seem to look like different shapes just grouped together as shown below.

+

+ +

Read more ...

+
+
+ +
+

+ Week 12 - Adding skeleton as actors and fix global transformation +

+
    +
  • + + + 08 September 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Shivam Anand + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

I started this week by fixing the segmentation fault for the skinning test. I could not fix this as of now.

+

+ +

Read more ...

+
+
+ +
+

+ Week 14 - Updating DrawPanel architecture +

+
    +
  • + + + 07 September 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week I continued updating the DrawShape and DrawPanel.

+

+ +

Read more ...

+
+
+ +
+

+ Week 12: Adding new tutorials +

+
    +
  • + + + 07 September 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Mohamed Abouagour + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Restructured tutorials to be more readable and more focused on a specific topic.

+

+ +

Read more ...

+
+
+ +
+

+ Week 13 - Separating tests and fixing bugs +

+
    +
  • + + + 31 August 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week I managed to fix the translation issue in PR #653. This was happening because of the calculation error while repositioning the shapes. Now it works as intended.

+

+ +

Read more ...

+
+
+ +
+

+ Week 11 - Multiple transformations support and adding tests +

+
    +
  • + + + 31 August 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Shivam Anand + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

As decided last week, I added support for multiple animations at the same timestamp. But this didn’t solve the animation problems of RiggedSimple model.

+

+ +

Read more ...

+
+
+ +
+

+ Week 11: Improving tutorials a little +

+
    +
  • + + + 30 August 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Mohamed Abouagour + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Fixed some issues in the hierarchical order animation support PR that we discussed during last week’s meeting (mostly naming issues).

+

+ +

Read more ...

+
+
+ +
+

+ Week 10 - Multi-node skinning support +

+
    +
  • + + + 25 August 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Shivam Anand + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

As we figured out that the SimpleSkin model is not animated as intended. This week I started working with that model; +I figured out that we need to apply the InverseBindMatrix to each timer callback. I had a hard time figuring out what inverse bind matrix actually does. +Here’s a good blog that answers that.

+

+ +

Read more ...

+
+
+ +
+

+ Week 12 - Fixing translating issues and updating tests +

+
    +
  • + + + 24 August 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

I started with updating the tests for PR #623 as some of the tests weren’t covering all the aspects in the code. +Previously I was just creating the DrawShape and adding it to the scene but now I had to analyze the scene to see whether they were properly added or not.

+

+ +

Read more ...

+
+
+ +
+

+ Week 10: Supporting hierarchical animating +

+
    +
  • + + + 23 August 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Mohamed Abouagour + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Implemented hierarchical order support for animations using matrices in this PR.

+

+ +

Read more ...

+
+
+ +
+

+ Week 9 - First working skeletal animation prototype +

+
    +
  • + + + 17 August 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Shivam Anand + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week I had the first working example of skeletal animation ready. I was able to render the SimpleSkin model. Here’s a quick preview:

+

+ +

Read more ...

+
+
+ +
+

+ Week 11 - Creating a base for Freehand Drawing +

+
    +
  • + + + 17 August 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week I tried to imitate the working of vtkImageTracer. Previously, I had created a small prototype for freehand drawing by adding points at the mouse position (which you can check out here). As mentioned, there were some drawback of this method. +So to overcome these issues, I tried combining both methods. Considering points using the previous method and instead of adding points I tried creating lines between them which looks promising. Below you can see a demo.

+

+ +

Read more ...

+
+
+ +
+

+ Week 9: Animating primitives of the same actor +

+
    +
  • + + + 16 August 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Mohamed Abouagour + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Made two tutorials in this PR that show two approaches on how to animate primitives of the same FURY actor using the Timeline.

+

+ +

Read more ...

+
+
+ +
+

+ Week 8 - Fixing animation bugs +

+
    +
  • + + + 10 August 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Shivam Anand + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week I had to fix the transformation issue in glTF animation. As discussed in the last meeting, I disabled vertex transformation and applied the transformation after the actor was formed.

+

+ +

Read more ...

+
+
+ +
+

+ Week 10 - Understanding Codes and Playing with Animation +

+
    +
  • + + + 10 August 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

I started working on the PR #645 created last week and tested a few more corner cases such as What happens if the maximum value is exceeded?? What if we give a value less than the minimum value range?? +Most of these worked as intended.

+

+ +

Read more ...

+
+
+ +
+

+ Week 8: Back to the shader-based version of the Timeline +

+
    +
  • + + + 09 August 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Mohamed Abouagour + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

First, I made some modifications to the main animation PR. Then as Filipi requested, I integrated the vertex shader that I was implementing a few weeks ago to work with the new improved version of the Timeline.

+

+ +

Read more ...

+
+
+ +
+

+ Week 9 - Grouping and Transforming Shapes +

+
    +
  • + + + 03 August 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

I started this week by creating a quick PR #645 for the UI sliders. The sliders raised ZeroDivsionError when the min and max values were the same. To solve this, I handled the case where the value_range becomes zero and then manually set the handle position to zero.

+

+ +

Read more ...

+
+
+ +
+

+ Week 7: Billboard spheres and implementing interpolators using closures +

+
    +
  • + + + 01 August 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Mohamed Abouagour + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Restructured the keyframe animation interpolators using closures to be functions instead of classes #647. Now it is easier to implement new interpolators with the help of the functions existing in fury/animation/helpers.py. Also, now unit tests can be added for the latter functions.

+

+ +

Read more ...

+
+
+ +
+

+ Week 7 - Fixing bugs in animations +

+
    +
  • + + + 01 August 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Shivam Anand + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week I started with implementing scaling to the animation example.

+

+ +

Read more ...

+
+
+ +
+

+ Week 8 - Working on the polyline feature +

+
    +
  • + + + 27 July 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week I started working on the polyline feature. After a lot of investigating and trying out different things, I found a way to call the dragging event manually without any prior click event. VTK actually captures the mouse movement using the MouseMoveEvent. This event is then modified by FURY to only be called after the click event. So I added a new callback to track the mouse movement and set the current canvas as an active prop because it is required to capture the drag event happening on it.

+

+ +

Read more ...

+
+
+ +
+

+ Week 6: Fixing the Timeline issues and equipping it with more features +

+
    +
  • + + + 25 July 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Mohamed Abouagour + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Improved the PlaybackPanel by adding speed control and the ability to loop the animation. Also, fixed the lagging issue of play and pause buttons and composed them into a single play/pause button.

+

+ +

Read more ...

+
+
+ +
+

+ Week 6 - Extracting the animation data +

+
    +
  • + + + 25 July 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Shivam Anand + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week, it was all about reading docs and extracting the animation data from buffers.

+

+ +

Read more ...

+
+
+ +
+

+ Week 7 - Working on Rotation PR and Trying Freehand Drawing +

+
    +
  • + + + 20 July 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

I continued PR #623 and fixed the displacement of the shape from its original position when applying rotation. This was happening because most of the calculations resulted in float values, but as the pixel position were integers we had to explicitly convert these values into int. This conversion rounded off the values and as we call this function continuously, each time the round-off would happen, the shape would get displaced.

+

+ +

Read more ...

+
+
+ +
+

+ Week 5: Slerp implementation, documenting the Timeline, and adding unit tests +

+
    +
  • + + + 19 July 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Mohamed Abouagour + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Implemented Slerp (spherical linear interpolation) for rotation keyframes.

+

+ +

Read more ...

+
+
+ +
+

+ Week 5 - Creating PR for glTF exporter and fixing the loader +

+
    +
  • + + + 19 July 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Shivam Anand + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Finalised the glTF export PR #630., adding tutorial, docs, and tests for all functions.

+

+ +

Read more ...

+
+
+ +
+

+ Week 6 - Supporting Rotation of the Shapes from the Center +

+
    +
  • + + + 13 July 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week I started implementing a new feature to rotate the shapes from the center using RingSlider2D. I already had a rotate function that rotates the shape around its pivot vertex, so I updated it to support rotation from the center.

+

+ +

Read more ...

+
+
+ +
+

+ Week 4 - Finalizing glTF loader +

+
    +
  • + + + 12 July 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Shivam Anand + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week I had to travel back to my college since the summer vacations have ended. +I had a coding session with Serge this week, we modified the exporter function and looked at some bugs I faced.

+

+ +

Read more ...

+
+
+ +
+

+ Week 4: Camera animation, interpolation in GLSL, and a single Timeline! +

+
    +
  • + + + 11 July 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Mohamed Abouagour + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Managed to implement a single Timeline using the Container class. So, instead of having two classes: Timeline and CompositeTimeline, now the Timeline can have multiple Timeline objects and controls them as in the code below.

+

+ +

Read more ...

+
+
+ +
+

+ Week 5 - Working on new features +

+
    +
  • + + + 06 July 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week I tried to create a base for some upcoming new features. +The first thing I updated was the Properties panel which I prototyped in Week 3. +So previously, it was just displaying the properties but now after the update, it is able to modify the properties(such as color, position, and rotation) too. This was a quick change to test the callbacks.

+

+ +

Read more ...

+
+
+ +
+

+ Week 3: Redesigning the API, Implementing cubic Bezier Interpolator, and making progress on the GPU side! +

+
    +
  • + + + 04 July 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Mohamed Abouagour + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Redesigned the keyframe animations API to optimize having a lot of timelines by composing them into a parent Timeline called CompositeTimeline while maintaining playing individual timelines separately.

+

+ +

Read more ...

+
+
+ +
+

+ Week 3 - Fixing fetcher, adding tests and docs +

+
    +
  • + + + 04 July 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Shivam Anand + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

The first task for this week was to fix the glTF fetcher. We noticed that while running tests it reaches the API limit. So we decided to use a JSON file that contains the download URLs for all models.

+

+ +

Read more ...

+
+
+ +
+

+ Week 4 - Fixing the Clamping Issue +

+
    +
  • + + + 29 June 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Phew!! This week was a tedious week for me as parallelly my End-Sem exams also started. So as usual I started from where I left off last week, The Clamping Issue. As per the discussion with the mentors, we decided to use the AABB bounding box method to calculate the bounding box around the shape and then reposition or transform respectively, as now we had a fixed reference point. So after doing some calculations with the mouse positions and the bounding box points at last, I was able to clamp all the shapes successfully.

+

+ +

Read more ...

+
+
+ +
+

+ Week 2 - Improving Fetcher and Exporting glTF +

+
    +
  • + + + 29 June 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Shivam Anand + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week I worked primarily on the glTF fetcher and exporting scenes to a glTF file. I added tests and docstrings for all functions. I modified the fetch_gltf function to return the downloaded files. As we planned, the PR for the glTF fetcher was merged this week.

+

+ +

Read more ...

+
+
+ +
+

+ Week 2: Implementing non-linear and color interpolators +

+
    +
  • + + + 28 June 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Mohamed Abouagour + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Implemented some other general interpolators such as n-th degree spline and cubic spline interpolators. Also implemented HSV and LAB color interpolators.

+

+ +

Read more ...

+
+
+ +
+

+ Week 3 - Dealing with Problems +

+
    +
  • + + + 22 June 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week was full of researching, playing around with things, prototyping ideas, etc. +I started with last week’s clamping issue and managed to solve this issue while drawing shapes by clipping the mouse position according to canvas size, but it didn’t solve the problem with translating these shapes. I tried solving this using various approaches, but if one thing would get fixed, other things would raise a new error.

+

+ +

Read more ...

+
+
+ +
+

+ Week 1 - A Basic glTF Importer +

+
    +
  • + + + 20 June 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Shivam Anand + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

In the community bonding period I met with my mentor Serge Koudoro, along with other mentors in FURY and gsoc contributors. +We discussed about my project and set up project timeline on github projects section. As my project (glTF Integration) +and Keyframe animations were related so we discussed on that too.

+

+ +

Read more ...

+
+
+ +
+

+ Week 1: Implementing a basic Keyframe animation API +

+
    +
  • + + + 19 June 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Mohamed Abouagour + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

During the community bonding period, we had weekly meetings in which I got to know the mentors better and bonded with Shivam and Praneeth, my fellow contributors. +We talked about the importance of open-source contribution and discussed scientific visualization, how important it is and how it differs from game engines despite having some similarities. +We also discussed how important the code review is and how to do a proper code review.

+

+ +

Read more ...

+
+
+ +
+

+ Week 2 - Improving DrawPanel UI +

+
    +
  • + + + 15 June 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week I had to refactor and make my code cleaner along with some bug fixing, I started by adding tests and tutorials so that my changes could be tested by everyone. Then I separated the mode for selection so that it would be easy to select an individual element and work along with it. Once the selection mode was complete I started with the deletion of the elements.

+

+ +

Read more ...

+
+
+ +
+

+ Week 1 - Laying the Foundation of DrawPanel UI +

+
    +
  • + + + 08 June 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week we started with our first technical meeting in which the weekly tasks were assigned. So I had to start with some background or canvas and draw a line using mouse clicks.

+

+ +

Read more ...

+
+
+ +
+

+ Pre-GSoC Journey +

+
    +
  • + + + 25 May 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Praneeth Shetty + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hello Guys!! I am Praneeth Shetty, currently pursuing Bachelor of Engineering in Computer Engineering, and here is my journey from where I started to the selection into GSoC22.

+

+ +

Read more ...

+
+
+ +
+

+ My Journey to GSoC 2022 +

+
    +
  • + + + 24 May 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Shivam Sahu + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hi! I’m Shivam, currently pursuing my bachelor’s (expected 2024) in Production and Industrial engineering from the Indian Institute of Technology (IIT) Roorkee.

+

+ +

Read more ...

+
+
+ +
+

+ My journey till getting accepted into GSoC22 +

+
    +
  • + + + 23 May 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Mohamed Abouagour + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

My name is Mohamed and I’m from Egypt. I am pursuing a Bachelor of Engineering in Computer Engineering and Automatic Control (expected: 2023), Tanta University, Egypt.

+

+ +

Read more ...

+
+
+ +
+

+ Contribute to FURY via Google Summer of Code 2022 +

+
    +
  • + + + 01 February 2022 + +
  • +
    + + +
  • + + + Author: + + + + + Serge Koudoro + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

FURY is participating in the Google Summer of Code 2022 under the umbrella of the Python Software Foundation.

+

+ +

Read more ...

+
+
+ +
+

+ Google Summer of Code Final Work Product +

+
    +
  • + + + 23 August 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Antriksh Misri + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Name: Antriksh Misri

+

+ +

Read more ...

+
+
+ +
+

+ Google Summer of Code Final Work Product +

+
    +
  • + + + 23 August 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Sajag Swami + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Name: Sajag Swami

+

+ +

Read more ...

+
+
+ +
+

+ Google Summer of Code 2021 - Final Report - Bruno Messias +

+
    +
  • + + + 23 August 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Bruno Messias + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

We have changed some points of my project in the first meeting. +Specifically, we focused the efforts into developing a streaming system +using the WebRTC protocol that could be used in more generic scenarios +than just the network visualization. In addition to that, we have opted +to develop the network visualization for fury as a separated repository +and package available here. The +name Helios was selected for this new network visualization system based +on the Fury rendering pipeline.

+

+ +

Read more ...

+
+
+ +
+

+ Week #11: Removing the flickering effect +

+
    +
  • + + + 16 August 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Bruno Messias + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

PR fury-gl/fury#489:

+

+ +

Read more ...

+
+
+ +
+

+ Week #11: Finalizing open Pull Requests +

+
    +
  • + + + 16 August 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Antriksh Misri + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Below are the tasks that I worked on:

+

+ +

Read more ...

+
+
+ +
+

+ Tenth coding week! +

+
    +
  • + + + 16 August 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Sajag Swami + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Welcome to the eleventh weekly check-in. I’ll be sharing my progress for the tenth week of coding.

+

+ +

Read more ...

+
+
+ +
+

+ Week#10: Accordion UI, Support for sprite sheet animations +

+
    +
  • + + + 09 August 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Antriksh Misri + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Below are the tasks that I worked on:

+

+ +

Read more ...

+
+
+ +
+

+ Week #10: SDF Fonts +

+
    +
  • + + + 09 August 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Bruno Messias + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

PR fury-gl/helios#22 +: Helios Documentation +Improvements.

+

+ +

Read more ...

+
+
+ +
+

+ Ninth coding week! +

+
    +
  • + + + 09 August 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Sajag Swami + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Welcome to the tenth weekly check-in. I’ll be sharing my progress for the ninth week of coding.

+

+ +

Read more ...

+
+
+ +
+

+ Week #9: More Layouts! +

+
    +
  • + + + 02 August 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Antriksh Misri + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Below are the tasks that I worked on:

+

+ +

Read more ...

+
+
+ +
+

+ Week #09: Sphinx custom summary +

+
    +
  • + + + 02 August 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Bruno Messias + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

PR fury-gl/helios#22 +: Helios Documentation +Improvements. +I’ve spent some time studying sphinx in order to discover how I could create a +custom summary inside of a template module.

+

+ +

Read more ...

+
+
+ +
+

+ Eighth coding week! +

+
    +
  • + + + 02 August 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Sajag Swami + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Welcome to the ninth weekly check-in. I’ll be sharing my progress for the eighth week of coding.

+

+ +

Read more ...

+
+
+ +
+

+ Weekly Check-In #8 +

+
    +
  • + + + 26 July 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Bruno Messias + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

PR fury-gl/helios#18 (merged): Helios Documentation/ +I’ve been working on Helios documentation. Now it’s available +online at https://fury-gl.github.io/helios-website image1

+

+ +

Read more ...

+
+
+ +
+

+ Week #8: Code Cleanup, Finishing up open PRs, Continuing work on Tree2D +

+
    +
  • + + + 26 July 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Antriksh Misri + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week I had to work on the open PRs specifically work on the bugs that were pointed out in last week’s meeting. Along side the bugs I had to continue the work on Tree2D UI element. Below is the detailed description of what I worked on this week:

+

+ +

Read more ...

+
+
+ +
+

+ Seventh week of coding! +

+
    +
  • + + + 26 July 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Sajag Swami + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Welcome to the eighth weekly check-in. I’ll be sharing my progress for the seventh week of coding.

+

+ +

Read more ...

+
+
+ +
+

+ Weekly Check-In #7 +

+
    +
  • + + + 19 July 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Bruno Messias + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

PR fury-gl/helios#16 +(merged): Helios IPC +network layout support for MacOs

+

+ +

Read more ...

+
+
+ +
+

+ Week #7: Finalizing the stalling PRs, finishing up Tree2D UI. +

+
    +
  • + + + 19 July 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Antriksh Misri + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week I had limited tasks to do, mostly tasks related to existing PRs. Other than some minor fixes I had to implement some more things in Tree2D which included some minor UI fixes, some changes in tutorial, adding tests. Below is the detailed description of what I worked on this week:

+

+ +

Read more ...

+
+
+ +
+

+ Sixth week of coding! +

+
    +
  • + + + 19 July 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Sajag Swami + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Welcome to the seventh weekly check-in. I’ll be sharing my progress for the sixth week of coding.

+

+ +

Read more ...

+
+
+ +
+

+ Week #6: Bug fixes, Working on Tree2D UI +

+
    +
  • + + + 12 July 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Antriksh Misri + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week I had relatively few tasks and most of them were to fix some bugs/design flaws that were discussed in last week’s meeting. Other than that, I had to implement a few things in the Tree2D UI element that will be discussed in detail below. I also had to update some existing PRs in order to make things work well. Below are the list of things I worked on this week:

+

+ +

Read more ...

+
+
+ +
+

+ Network layout algorithms using IPC +

+
    +
  • + + + 12 July 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Bruno Messias + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hi all. In the past weeks, I’ve been focusing on developing Helios; the +network visualization library for FURY. I improved the visual aspects of +the network rendering as well as implemented the most relevant network +layout methods.

+

+ +

Read more ...

+
+
+ +
+

+ Fifth week of coding! +

+
    +
  • + + + 12 July 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Sajag Swami + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Welcome to the sixth weekly check-in. I’ll be sharing my progress for the fifth week of coding.

+

+ +

Read more ...

+
+
+ +
+

+ Weekly Check-In #5 +

+
    +
  • + + + 05 July 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Bruno Messias + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Before the 8c670c2 commit, for some versions of MacOs the +streaming system was falling in a silent bug. I’ve spent a lot of +time researching to found a cause for this. Fortunately, I could found +the cause and the solution. This troublesome MacOs was falling in a +silent bug because the SharedMemory Object was creating a memory +resource with at least 4086 bytes independent if I’ve requested less +than that. If we look into the MultiDimensionalBuffer Object +(stream/tools.py) before the 8c670c2 commit we can see that Object +has max_size parameter which needs to be updated if the SharedMemory +was created with a “wrong” size.

+

+ +

Read more ...

+
+
+ +
+

+ Week #5: Rebasing all PRs w.r.t the UI restructuring, Tree2D, Bug Fixes +

+
    +
  • + + + 05 July 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Antriksh Misri + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

The UI restructuring was finally merged this week. This means UI is now a submodule in itself and provides different UI elements based on their types which are, core, elements, containers and some helper methods/classes. So, this week my main tasks were to rebase and fix merge conflicts of my open PR’s. Other than that, I had to continue my work on Tree2D UI element and finish the remaining aspects of it. Also, I had to create an example demonstrating how to use the newly added UI element. Many use cases were discussed in the open meeting like, an image gallery which displays preview image on the title and when expanded reveals the full scale image. I am thinking of adding multiple examples for the Tree2D to brainstorm on its certain features. Also, I had this annoying bug in Panel2D which didn’t allow it to be resized from the bottom right corner. It was resizing from the top right corner. I had to address this bug as well. Below are the tasks in detail:

+

+ +

Read more ...

+
+
+ +
+

+ SOLID, monkey patching a python issue and network visualization through WebRTC +

+
    +
  • + + + 05 July 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Bruno Messias + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

These past two weeks I’ve spent most of my time in the Streaming System +PR and the Network Layout +PR . In this post I’ll +focus on the most relevant things I’ve made for those PRs.

+

+ +

Read more ...

+
+
+ +
+

+ Fourth week of coding! +

+
    +
  • + + + 05 July 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Sajag Swami + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Welcome to the fifth weekly check-in. I’ll be sharing my progress for the fourth week of coding.

+

+ +

Read more ...

+
+
+ +
+

+ Week #4: Adding Tree UI to the UI module +

+
    +
  • + + + 28 June 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Antriksh Misri + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week I had very few tasks to do, almost all of them revolved around UI elements and adding stuff to the UI module. Earlier, it was pointed out that due to some design issues, importing certain modules into others caused circular imports which led to importing the specific modules inside a class/method which is not the best approach. This will be resolved as soon as the PR that fixes this issue is reviewed/merged in the codebase. In the meantime, all the PR’s related to UI will be on hold, which is why this I had few tasks this week. The tasks are described below in detail:

+

+ +

Read more ...

+
+
+ +
+

+ Third week of coding! +

+
    +
  • + + + 28 June 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Sajag Swami + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Welcome to the fourth weekly check-in. I’ll be sharing my progress for the third week of coding.

+

+ +

Read more ...

+
+
+ +
+

+ Weekly Check-In #3 +

+
    +
  • + + + 21 June 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Bruno Messias + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

PR fury-gl/fury#422 +(merged): +Integrated the 3d impostor spheres with the marker actor.

+

+ +

Read more ...

+
+
+ +
+

+ Week #3: Adapting GridLayout to work with UI +

+
    +
  • + + + 21 June 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Antriksh Misri + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week my tasks revolved around layout and UI elements. The primary goal for this week was to adapt the GridLayout to work with different UI elements. Currently, GridLayout just supports vtk actors and not UI elements, my task was to modify the class to support UI elements. The other tasks for this week are described below in detail:

+

+ +

Read more ...

+
+
+ +
+

+ Second week of coding! +

+
    +
  • + + + 21 June 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Sajag Swami + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Welcome to the third weekly check-in. I’ll be sharing my progress for the second week of coding.

+

+ +

Read more ...

+
+
+ +
+

+ First week of coding! +

+
    +
  • + + + 14 June 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Sajag Swami + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Welcome to the second weekly check-in. I’ll be sharing my progress for the first week of coding.

+

+ +

Read more ...

+
+
+ +
+

+ Week #2: Feature additions in UI and IO modules +

+
    +
  • + + + 13 June 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Antriksh Misri + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

This week I had to work on 3 PRs as well as some documentation. I really enjoyed this week’s work as the tasks were really interesting. The aim for these PRs were to actually add a couple of features in the UI as well as the IO module, which includes, adding support for border in Panel2D, adding support for network/URL images in load_image method in IO module, adding resizing Panel2D from bottom right corner, completing the document with layout solutions provided by Unity/Unreal engine. Below are the PRs that I worked on:

+

+ +

Read more ...

+
+
+ +
+

+ A Stadia-like system for data visualization +

+
    +
  • + + + 13 June 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Bruno Messias + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hi all! In this post I’ll talk about the PR +#437.

+

+ +

Read more ...

+
+
+ +
+

+ Welcome to my GSoC Blog! +

+
    +
  • + + + 08 June 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Sajag Swami + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hi all! +I’m Sajag Swami, a sophomore at Indian Institute of Technology, Roorkee. This summer, I will be working on adding a new functionality to FURY which shall enable users to +visualise various types of proteins via different representations like Richardson aka Ribbon diagrams and molecular surface diagrams. +As a part of my stretch goals, I’ll try to expand protein diagrams via other representations including:

+

+ +

Read more ...

+
+
+ +
+

+ Weekly Check-In #1 +

+
    +
  • + + + 08 June 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Bruno Messias + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hi everyone! My name is Bruno Messias currently I’m a Ph.D student at +USP/Brazil. In this summer I’ll develop new tools and features for +FURY-GL. Specifically, I’ll focus into developing a system for +collaborative visualization of large network layouts using FURY and VTK.

+

+ +

Read more ...

+
+
+ +
+

+ Week #1: Welcome to my weekly Blogs! +

+
    +
  • + + + 08 June 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Antriksh Misri + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hi everyone! I am Antriksh Misri. I am a Pre-Final year student at MIT Pune. This summer, I will be working on Layout Management under FURY’s UI module as my primary goal. This includes addition of different classes under Layout Management to provide different layouts/arrangements in which the UI elements can be arranged. As my stretch goals, I will be working on a couple of UI components for FURY’s UI module. These 2D and 3D components will be sci-fi like as seen in the movie “Guardians of The Galaxy”. My objective for the stretch goals would be to develop these UI components with their respective test and tutorials such that it adds on to the UI module of FURY and doesn’t hinder existing functionalities/performance.

+

+ +

Read more ...

+
+
+ +
+

+ Google Summer of Code +

+
    +
  • + + + 09 March 2021 + +
  • +
    + + +
  • + + + Author: + + + + + Serge Koudoro + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

FURY is participating in the Google Summer of Code 2021 under the umbrella of the Python Software Foundation.

+

+ +

Read more ...

+
+
+ +
+

+ Shader Showcase +

+
    +
  • + + + 24 August 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Lenix Lobo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Make sure to check out Project FURY

+

+ +

Read more ...

+
+
+ +
+

+ Google Summer of Code Final Work Product +

+
    +
  • + + + 24 August 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Soham Biswas + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Name: Soham Biswas

+

+ +

Read more ...

+
+
+ +
+

+ Google Summer of Code 2020 Final Work Product +

+
    +
  • + + + 24 August 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Lenix Lobo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Name: Lenix Lobo

+

+ +

Read more ...

+
+
+ +
+

+ Part of the Journey is the end unless its Open Source! +

+
    +
  • + + + 23 August 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Soham Biswas + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hello and welcome to my final weekly check-in. Today officially marks the end of the coding period for GSoC 2020. I enjoyed every bit of it. This was a life-changing experience for me and now I observe and interpret everything from a different perspective altogether. I have grown into a better developer and a person since GSoC. I would like to thank all my mentors and especially Serge for his immense support and mentorship. I would love to contribute to fury even after GSoC is over but unfortunately my semester break is over so I won’t be as active as I was during the summer.

+

+ +

Read more ...

+
+
+ +
+

+ Outline Picker +

+
    +
  • + + + 17 August 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Lenix Lobo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Make sure to check out Project FURY

+

+ +

Read more ...

+
+
+ +
+

+ Wrecking Ball Simulation, Scrollbars Update, Physics Tutorials. +

+
    +
  • + + + 16 August 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Soham Biswas + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hello and welcome to my 12th weekly check-in. In this blog I will be discussing my progress with the wrecking ball simulation and my scrollbar separation work. Apart from this I have also finalized the physics simulation tutorials and have created a Pull Request to finally get it merged with the official repository. The official repository of my sub-org can be found here.

+

+ +

Read more ...

+
+
+ +
+

+ More Shaders!! +

+
    +
  • + + + 09 August 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Lenix Lobo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Make sure to check out Project FURY

+

+ +

Read more ...

+
+
+ +
+

+ Chain Simulation, Scrollbar Refactor, Tutorial Update. +

+
    +
  • + + + 09 August 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Soham Biswas + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hello and welcome to my 11th weekly check-in. In this blog I will be discussing my progress with multiple topics related to physics and ui components. I was actively working on a couple of things, specifically Joint simulations in pyBullet and scrollbar UI component. I also took up the responsibility to complete an incomplete Pull Request which was pending for quite a while. The official repository of my sub-org can be found here.

+

+ +

Read more ...

+
+
+ +
+

+ Single Actor, Physics, Scrollbars. +

+
    +
  • + + + 02 August 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Soham Biswas + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hello and welcome to my 10th weekly check-in. Second evaluation ended this week and now we move on to our 3rd and final coding period. In today’s check-in I will be sharing my progress with the single actor physics simulation that I facing some issues with and I will also be discussing my future plans regarding UI components. The official repository of my sub-org, FURY can always be found here.

+

+ +

Read more ...

+
+
+ +
+

+ More Shaders!! +

+
    +
  • + + + 02 August 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Lenix Lobo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Make sure to check out Project FURY

+

+ +

Read more ...

+
+
+ +
+

+ Merging SDF primitives. +

+
    +
  • + + + 27 July 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Lenix Lobo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Make sure to check out Project FURY

+

+ +

Read more ...

+
+
+ +
+

+ Tab UI, TabPanel2D, Tab UI Tutorial. +

+
    +
  • + + + 26 July 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Soham Biswas + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hello and welcome to my 9th weekly check-in. I will be sharing my progress with TabUI and its corresponding tutorial. The official repository of my sub-org, FURY can always be found here.

+

+ +

Read more ...

+
+
+ +
+

+ Improvements in SDF primitives. +

+
    +
  • + + + 20 July 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Lenix Lobo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Make sure to check out Project FURY

+

+ +

Read more ...

+
+
+ +
+

+ ComboBox2D, TextBlock2D, Clipping Overflow. +

+
    +
  • + + + 19 July 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Soham Biswas + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hello and welcome to my 8th weekly check-in. I will be sharing my progress with ComboBox2D and TextBlock2D UI components. After solving TextBlock2D sizing issue, I was finally able to complete the implementation of combo box. I also faced some problems while refactoring TextBlock2D. The official repository of my sub-org, FURY can always be found here.

+

+ +

Read more ...

+
+
+ +
+

+ Multiple SDF primitives. +

+
    +
  • + + + 13 July 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Lenix Lobo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Make sure to check out Project FURY

+

+ +

Read more ...

+
+
+ +
+

+ Orientation, Sizing, Tab UI. +

+
    +
  • + + + 12 July 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Soham Biswas + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hello and welcome to my 7th weekly check-in. I will be sharing my progress with single actor physics simulation and TextBlock2D sizing issue which was pending for quite a while now. I will also be sharing my thoughts regarding the TAB UI component. The official repository of my sub-org, FURY can always be found here.

+

+ +

Read more ...

+
+
+ +
+

+ Translation, Reposition, Rotation. +

+
    +
  • + + + 05 July 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Soham Biswas + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hello and welcome to my 6th weekly check-in. The first evaluation period officially ends and I am very excited to move on to the second coding period. I will be sharing my progress with handling specific object’s properties among various multiple objects rendered by a single actor. I am mainly focusing on making it easier to translate, rotate and reposition a particular object, so that I can use them to render physics simulations more efficiently. The official repository of my sub-org, FURY can always be found here.

+

+ +

Read more ...

+
+
+ +
+

+ Spherical harmonics, Continued. +

+
    +
  • + + + 05 July 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Lenix Lobo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Make sure to check out Project FURY

+

+ +

Read more ...

+
+
+ +
+

+ Spherical harmonics +

+
    +
  • + + + 28 June 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Lenix Lobo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Make sure to check out Project FURY

+

+ +

Read more ...

+
+
+ +
+

+ May the Force be with you!! +

+
    +
  • + + + 28 June 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Soham Biswas + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hello and welcome to my 5th weekly check-in, I will be sharing my progress of pyBullet Physics Engine Integration with FURY. The official repository of my sub-org, FURY can always be found here.

+

+ +

Read more ...

+
+
+ +
+

+ TextBlock2D Progress!! +

+
    +
  • + + + 21 June 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Soham Biswas + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hello and welcome to my 4th weekly check-in, I will be sharing my progress with TextBlock2D UI component. The official repository of my sub-org, FURY can always be found here.

+

+ +

Read more ...

+
+
+ +
+

+ Raymarching continued +

+
    +
  • + + + 21 June 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Lenix Lobo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Make sure to check out Project FURY

+

+ +

Read more ...

+
+
+ +
+

+ Raymarching!! +

+
    +
  • + + + 14 June 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Lenix Lobo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Make sure to check out Project FURY

+

+ +

Read more ...

+
+
+ +
+

+ ComboBox2D Progress!! +

+
    +
  • + + + 14 June 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Soham Biswas + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hello and welcome to my third weekly check-in, I will be sharing my progress with the project so far. In case you wondered, the sub-org that I am affiliated to is FURY. Make sure to check out the official repository here.

+

+ +

Read more ...

+
+
+ +
+

+ First week of coding!! +

+
    +
  • + + + 07 June 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Lenix Lobo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hey everyone! +This week : Geometry Shaders!

+

+ +

Read more ...

+
+
+ +
+

+ First week of coding!! +

+
    +
  • + + + 07 June 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Soham Biswas + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hello and welcome to my second weekly check-in, I will be sharing my progress for the first week of coding.

+

+ +

Read more ...

+
+
+ +
+

+ Welcome to my GSoC Blog!!! +

+
    +
  • + + + 30 May 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Soham Biswas + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hello Everyone, this is Soham Biswas currently in 2nd year pursuing my Bachelor’s(B.Tech) degree in Computer Science & Engineering from Institute of Engineering & Management, Kolkata. I have been selected for GSoC’ 20 at sub-org FURY under the umbrella organization of Python Software Foundation. I will be working on building sci-fi-like 2D and 3D interfaces and provide physics engine integration under project titled “Create new UI widgets & Physics Engine Integration”.

+

+ +

Read more ...

+
+
+ +
+

+ Weekly Check-in #1 +

+
    +
  • + + + 30 May 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Lenix Lobo + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

Hey everyone! +This is my blog for this summer’s GSoC @ PSF +I am Lenix Lobo, an undergraduate student from India, and this summer I will be working with project Fury under the umbrella of the Python Software foundation. I will be working on improving the current shader framework.

+

+ +

Read more ...

+
+
+ +
+

+ Google Summer of Code +

+
    +
  • + + + 05 January 2020 + +
  • +
    + + +
  • + + + Author: + + + + + Serge Koudoro + + + +
  • + + + + +
  • + + + Category: + + + + + gsoc + + + +
  • + + +
  • + + + + Tag: + + + + + google + + + +
  • + + +
    +
+

FURY is participating in the Google Summer of Code 2020 under the umbrella of the Python Software Foundation.

+

+ +

Read more ...

+
+
+ + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/blog/tag/google/atom.xml b/v0.10.x/blog/tag/google/atom.xml new file mode 100644 index 000000000..8b431adaf --- /dev/null +++ b/v0.10.x/blog/tag/google/atom.xml @@ -0,0 +1,1229 @@ + + + https://fury.gl/ + Blog - Posts tagged google + 2024-02-29T15:43:57.796218+00:00 + + + ABlog + + https://fury.gl/posts/2023/2023-08-25-final-report-praneeth.html + Google Summer of Code Final Work Product + 2023-08-25T00:00:00-04:00 + + Praneeth Shetty + + <a class="reference external image-reference" href="https://summerofcode.withgoogle.com/programs/2023/projects/BqfBWfwS"><img alt="https://developers.google.com/open-source/gsoc/resources/downloads/GSoC-logo-horizontal.svg" class="align-center" height="50" src="https://developers.google.com/open-source/gsoc/resources/downloads/GSoC-logo-horizontal.svg" /></a> +<a class="reference external image-reference" href="https://summerofcode.withgoogle.com/programs/2023/organizations/python-software-foundation"><img alt="https://www.python.org/static/community_logos/python-logo.png" src="https://www.python.org/static/community_logos/python-logo.png" style="width: 40%;" /></a> +<a class="reference external image-reference" href="https://fury.gl/latest/index.html"><img alt="https://python-gsoc.org/logos/FURY.png" src="https://python-gsoc.org/logos/FURY.png" style="width: 25%;" /></a> +<section id="google-summer-of-code-final-work-product"> + +<ul class="simple"> +<li><p><strong>Name:</strong> Praneeth Shetty</p></li> +<li><p><strong>Organisation:</strong> Python Software Foundation</p></li> +<li><p><strong>Sub-Organisation:</strong> FURY</p></li> +<li><p><strong>Project:</strong> <a class="reference external" href="https://github.com/fury-gl/fury/wiki/Google-Summer-of-Code-2023-(GSOC2023)#project-5-update-user-interface-widget--explore-new-ui-framework">FURY - Update user interface widget + Explore new UI Framework</a></p></li> +</ul> +<section id="proposed-objectives"> +<h2>Proposed Objectives</h2> +<ul class="simple"> +<li><p>SpinBoxUI</p></li> +<li><p>Scrollbar as Independent Element</p></li> +<li><p>FileDialog</p></li> +<li><p>TreeUI</p></li> +<li><p>AccordionUI</p></li> +<li><p>ColorPickerUI</p></li> +<li><dl class="simple"> +<dt>Stretch Goals:</dt><dd><ul> +<li><p>Exploring new UI Framework</p></li> +<li><p>Implementing Borders for UI elements</p></li> +</ul> +</dd> +</dl> +</li> +</ul> +</section> +<section id="objectives-completed"> +<h2>Objectives Completed</h2> +<ul> +<li><dl> +<dt><strong>SpinBoxUI:</strong></dt><dd><p>The <code class="docutils literal notranslate"><span class="pre">SpinBoxUI</span></code> element is essential for user interfaces as it allows users to pick a numeric value from a set range. While we had an active pull request (PR) to add this element, updates in the main code caused conflicts and required further changes for added features. At one point, we noticed that text alignment wasn’t centered properly within the box due to a flaw. To fix this, we began a PR to adjust the alignment, but it turned into a larger refactoring of the <code class="docutils literal notranslate"><span class="pre">TextBlock2D</span></code>, a core component connected to various parts. This was a complex task that needed careful handling. After sorting out the <code class="docutils literal notranslate"><span class="pre">TextBlock2D</span></code>, we returned to the <code class="docutils literal notranslate"><span class="pre">SpinBoxUI</span></code> and made a few tweaks. Once we were confident with the changes, the PR was successfully merged after thorough review and testing.</p> +<p><strong>Pull Requests:</strong></p> +</dd> +</dl> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 50)</p> +<p>Definition list ends without a blank line; unexpected unindent.</p> +</aside> +<ul> +<li><p><strong>SpinBoxUI (Merged)</strong> - <a class="github reference external" href="https://github.com/fury-gl/fury/pull/499">fury-gl/fury#499</a></p> +<blockquote> +<div><img alt="SpinBoxUI" class="align-center" src="https://user-images.githubusercontent.com/64432063/263165327-c0b19cdc-9ebd-433a-8ff1-99e706a76508.gif" style="height: 500px;" /> +</div></blockquote> +</li> +</ul> +</li> +<li><dl> +<dt><strong>`TextBlock2D` Refactoring:</strong></dt><dd><p>This was a significant aspect of the GSoC period and occupied a substantial portion of the timeline. The process began when we observed misaligned text in the <code class="docutils literal notranslate"><span class="pre">SpinBoxUI</span></code>, as previously discussed. The root cause of the alignment issue was the mispositioning of the text actor concerning the background actor. The text actor’s independent repositioning based on justification conflicted with the static position of the background actor, leading to the alignment problem.</p> +<p>To address this, the initial focus was on resolving the justification issue. However, as the work progressed, we recognized that solely adjusting justification would not suffice. The alignment was inherently linked to the UI’s size, which was currently retrieved only when a valid scene was present. This approach lacked scalability and efficiency, as it constrained size retrieval to scene availability.</p> +<p>To overcome these challenges, we devised a solution involving the creation of a bounding box around the <code class="docutils literal notranslate"><span class="pre">TextBlock2D</span></code>. This bounding box would encapsulate the size information, enabling proper text alignment. This endeavor spanned several weeks of development, culminating in a finalized solution that underwent rigorous testing before being merged.</p> +<p>As a result of this refactoring effort, the <code class="docutils literal notranslate"><span class="pre">TextBlock2D</span></code> now offers three distinct modes:</p> +<ol class="arabic simple"> +<li><p><strong>Fully Static Background:</strong> This mode requires background setup during initialization.</p></li> +<li><p><strong>Dynamic Background:</strong> The background dynamically scales based on the text content.</p></li> +<li><p><strong>Auto Font Scale Mode:</strong> The font within the background box automatically scales to fill the available space.</p></li> +</ol> +<p>An issue has been identified with <code class="docutils literal notranslate"><span class="pre">TextBlock2D</span></code> where its text actor aligns with the top boundary of the background actor, especially noticeable with letters like “g,” “y,” and “j”. These letters extend beyond the baseline of standard alphabets, causing the text box to shift upwards.</p> +<p>However, resolving this matter is complex. Adjusting the text’s position might lead to it touching the bottom boundary, especially in font scale mode, resulting in unexpected positioning and transformations. To address this, the plan is to defer discussions about this matter until after GSoC, allowing for thorough consideration and solutions.</p> +<p>For more detailed insights into the individual steps and nuances of this process, you can refer to the comprehensive weekly blog post provided below. It delves into the entire journey of this <code class="docutils literal notranslate"><span class="pre">TextBlock2D</span></code> refactoring effort.</p> +<p><strong>Pull Requests:</strong></p> +</dd> +</dl> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 79)</p> +<p>Definition list ends without a blank line; unexpected unindent.</p> +</aside> +<ul> +<li><p><strong>Fixing Justification Issue - 1st Draft (Closed)</strong> - <a class="github reference external" href="https://github.com/fury-gl/fury/pull/790">fury-gl/fury#790</a></p></li> +<li><p><strong>Adding BoundingBox and fixing Justificaiton (Merged)</strong> - <a class="github reference external" href="https://github.com/fury-gl/fury/pull/803">fury-gl/fury#803</a></p></li> +<li><p><strong>Adding getters and setter for properties (Merged)</strong> - <a class="github reference external" href="https://github.com/fury-gl/fury/pull/830">fury-gl/fury#830</a></p></li> +<li><p><strong>Text Offset PR (Closed)</strong> - <a class="github reference external" href="https://github.com/fury-gl/fury/pull/837">fury-gl/fury#837</a></p> +<img alt="TextBlock2D Feature Demo" class="align-center" src="https://user-images.githubusercontent.com/64432063/258603191-d540105a-0612-450e-8ae3-ca8aa87916e6.gif" style="height: 500px;" /> +<img alt="TextBlock2D All Justification" class="align-center" src="https://github-production-user-asset-6210df.s3.amazonaws.com/64432063/254652569-94212105-7259-48da-8fdc-41ee987bda84.png" style="height: 500px;" /> +</li> +</ul> +</li> +<li><dl> +<dt><strong>ScrollbarUI as Independent Element:</strong></dt><dd><p>We initially planned to make the scrollbar independent based on PR <a class="reference external" href="https://github.com/fury-gl/fury/pull/16">#16</a>. The main goal was to avoid redundancy by not rewriting the scrollbar code for each element that requires it, such as the <code class="docutils literal notranslate"><span class="pre">FileMenu2D</span></code>. However, upon further analysis, we realized that elements like the <code class="docutils literal notranslate"><span class="pre">FileMenu2D</span></code> and others utilize the <code class="docutils literal notranslate"><span class="pre">Listbox2D</span></code>, which already includes an integrated scrollbar. We also examined other UI libraries and found that they also have independent scrollbars but lack a proper use case. Typically, display containers like <code class="docutils literal notranslate"><span class="pre">Listbox2D</span></code> are directly used instead of utilizing an independent scrollbar.</p> +<p>Based on these findings, we have decided to close all related issues and pull requests for now. If the need arises in the future, we can revisit this topic.</p> +<p><strong>Topic:</strong> - <a class="github reference external" href="https://github.com/fury-gl/fury/discussions/816">fury-gl/fury#816</a></p> +</dd> +</dl> +</li> +</ul> +</section> +<section id="other-objectives"> +<h2>Other Objectives</h2> +<ul> +<li><dl> +<dt><strong>Reviewing &amp; Merging:</strong></dt><dd><p>In this phase, my focus was not on specific coding but rather on facilitating the completion of ongoing PRs. Here are two instances where I played a role:</p> +<ol class="arabic simple"> +<li><p><strong>CardUI PR:</strong> +I assisted with the <code class="docutils literal notranslate"><span class="pre">CardUI</span></code> PR by aiding in the rebase process and reviewing the changes. The CardUI is a simple UI element consisting of an image and a description, designed to function like a flash card. I worked closely with my mentor to ensure a smooth rebase and review process.</p></li> +<li><p><strong>ComboBox Issue:</strong> +There was an issue with the <code class="docutils literal notranslate"><span class="pre">ComboBox2D</span></code> functionality, where adding it to a <code class="docutils literal notranslate"><span class="pre">TabUI</span></code> caused all elements to open simultaneously, which shouldn’t be the case. I tested various PRs addressing this problem and identified a suitable solution. I then helped the lead in reviewing the PR that fixed the issue, which was successfully merged.</p></li> +</ol> +<p><strong>Pull Requests:</strong></p> +</dd> +</dl> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 116)</p> +<p>Definition list ends without a blank line; unexpected unindent.</p> +</aside> +<ul> +<li><p><strong>CardUI (Merged)</strong> - <a class="github reference external" href="https://github.com/fury-gl/fury/pull/398">fury-gl/fury#398</a></p></li> +<li><p><strong>ComboBox Flaw (Merged)</strong> - <a class="github reference external" href="https://github.com/fury-gl/fury/pull/768">fury-gl/fury#768</a></p> +<img alt="CardUI" class="align-center" src="https://user-images.githubusercontent.com/54466356/112532305-b090ef80-8dce-11eb-90a0-8d06eed55993.png" style="height: 500px;" /> +</li> +</ul> +</li> +<li><dl> +<dt><strong>Updating Broken Website Links:</strong></dt><dd><p>I addressed an issue with malfunctioning links in the Scientific Section of the website. The problem emerged from alterations introduced in PR <a class="reference external" href="https://github.com/fury-gl/fury/pull/769">#769</a>. These changes consolidated demos and examples into a unified “auto_examples” folder, and a toml file was utilized to retrieve this data and construct examples. However, this led to challenges with the paths employed in website generation. My responsibility was to rectify these links, ensuring they accurately direct users to the intended content.</p> +<p><strong>Pull Requests:</strong></p> +</dd> +</dl> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 130)</p> +<p>Definition list ends without a blank line; unexpected unindent.</p> +</aside> +<ul class="simple"> +<li><p><strong>Updating Broken Links (Merged)</strong> - <a class="github reference external" href="https://github.com/fury-gl/fury/pull/820">fury-gl/fury#820</a></p></li> +</ul> +</li> +</ul> +</section> +<section id="objectives-in-progress"> +<h2>Objectives in Progress</h2> +<ul> +<li><dl> +<dt><strong>FileDialogUI:</strong></dt><dd><p>An existing <code class="docutils literal notranslate"><span class="pre">FileDialog</span></code> PR by Soham (<a class="reference external" href="https://github.com/fury-gl/fury/pull/294">#294</a>) was worked upon. The primary task was to rebase the PR to match the current UI structure, resolving compatibility concerns with the older base. In PR <a class="reference external" href="https://github.com/fury-gl/fury/pull/832">#832</a>, we detailed issues encompassing resizing <code class="docutils literal notranslate"><span class="pre">FileDialog</span></code> and components, addressing text overflow, fixing <code class="docutils literal notranslate"><span class="pre">ZeroDivisionError</span></code>, and correcting <code class="docutils literal notranslate"><span class="pre">ListBox2D</span></code> item positioning. The PR is complete with comprehensive testing and documentation. Presently, it’s undergoing review, and upon approval, it will be prepared for integration.</p> +<p><strong>Pull Requests:</strong></p> +</dd> +</dl> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 140)</p> +<p>Definition list ends without a blank line; unexpected unindent.</p> +</aside> +<ul> +<li><p><strong>Soham’s FileDialog (Closed)</strong> - <a class="github reference external" href="https://github.com/fury-gl/fury/pull/294">fury-gl/fury#294</a></p></li> +<li><p><strong>FileDialogUI (Under Review)</strong> - <a class="github reference external" href="https://github.com/fury-gl/fury/pull/832">fury-gl/fury#832</a></p> +<img alt="FileDialogUI" class="align-center" src="https://user-images.githubusercontent.com/64432063/263189092-6b0891d5-f0ef-4185-8b17-c7104f1a7d60.gif" style="height: 500px;" /> +</li> +</ul> +</li> +<li><dl> +<dt><strong>TreeUI:</strong></dt><dd><p>Continuing Antriksh’s initial PR for <code class="docutils literal notranslate"><span class="pre">TreeUI</span></code> posed some challenges. Antriksh had set the foundation, and I picked up from there. The main issue was with the visibility of TreeUI due to updates in the <code class="docutils literal notranslate"><span class="pre">set_visibility</span></code> method of <code class="docutils literal notranslate"><span class="pre">Panel2D</span></code>. These updates affected how <code class="docutils literal notranslate"><span class="pre">TreeUI</span></code> was displayed, and after investigating the actors involved, it was clear that the visibility features had changed. This took some time to figure out, and I had a helpful pair programming session with my mentor, Serge, to narrow down the problem. Now, I’ve updated the code to address this issue. However, I’m still a bit cautious about potential future problems. The PR is now ready for review.</p> +<p><strong>Pull Requests:</strong></p> +</dd> +</dl> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 154)</p> +<p>Definition list ends without a blank line; unexpected unindent.</p> +</aside> +<ul> +<li><p><strong>TreeUI (In Progress)</strong> - <a class="github reference external" href="https://github.com/fury-gl/fury/pull/821">fury-gl/fury#821</a></p> +<img alt="TreeUI" class="align-center" src="https://user-images.githubusercontent.com/64432063/263237308-70e77ba0-1ce8-449e-a79c-d5e0fbb58b45.gif" style="height: 500px;" /> +</li> +</ul> +</li> +</ul> +</section> +<section id="gsoc-weekly-blogs"> +<h2>GSoC Weekly Blogs</h2> +<ul class="simple"> +<li><p>My blog posts can be found at <a class="reference external" href="https://fury.gl/latest/blog/author/praneeth-shetty.html">FURY website</a> +and <a class="reference external" href="https://blogs.python-gsoc.org/en/ganimtron_10s-blog-copy-2/">Python GSoC blog</a>.</p></li> +</ul> +</section> +<section id="timeline"> +<h2>Timeline</h2> +<table class="table"> +<colgroup> +<col style="width: 40.0%" /> +<col style="width: 40.0%" /> +<col style="width: 20.0%" /> +</colgroup> +<thead> +<tr class="row-odd"><th class="head"><p>Date</p></th> +<th class="head"><p>Description</p></th> +<th class="head"><p>Blog Post Link</p></th> +</tr> +</thead> +<tbody> +<tr class="row-even"><td><p>Week 0 (27-05-2023)</p></td> +<td><p>Community Bounding Period</p></td> +<td><p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-06-02-week-0-praneeth.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/ganimtron_10s-blog-copy-2/gsoc-2023-community-bonding-period/">Python</a></p></td> +</tr> +<tr class="row-odd"><td><p>Week 1 (03-06-2023)</p></td> +<td><p>Working with SpinBox and TextBox Enhancements</p></td> +<td><aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id5">backlink</a></em></p> +<p>Duplicate explicit target name: “fury”.</p> +</aside> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id6">backlink</a></em></p> +<p>Duplicate explicit target name: “python”.</p> +</aside> +<p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-06-03-week-1-praneeth.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/ganimtron_10s-blog-copy-2/week-1-working-with-spinbox-and-textbox-enhancements/">Python</a></p> +</td> +</tr> +<tr class="row-even"><td><p>Week 2 (10-06-2023)</p></td> +<td><p>Tackling Text Justification and Icon Flaw Issues</p></td> +<td><aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id7">backlink</a></em></p> +<p>Duplicate explicit target name: “fury”.</p> +</aside> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id8">backlink</a></em></p> +<p>Duplicate explicit target name: “python”.</p> +</aside> +<p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-06-11-week-2-praneeth.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/ganimtron_10s-blog-copy-2/week-2-tackling-text-justification-and-icon-flaw-issues/">Python</a></p> +</td> +</tr> +<tr class="row-odd"><td><p>Week 3 (17-06-2023)</p></td> +<td><p>Resolving Combobox Icon Flaw and TextBox Justification</p></td> +<td><aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id9">backlink</a></em></p> +<p>Duplicate explicit target name: “fury”.</p> +</aside> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id10">backlink</a></em></p> +<p>Duplicate explicit target name: “python”.</p> +</aside> +<p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-06-17-week-3-praneeth.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/ganimtron_10s-blog-copy-2/week-3-resolving-combobox-icon-flaw-and-textbox-justification/">Python</a></p> +</td> +</tr> +<tr class="row-even"><td><p>Week 4 (24-06-2023)</p></td> +<td><p>Exam Preparations and Reviewing</p></td> +<td><aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id11">backlink</a></em></p> +<p>Duplicate explicit target name: “fury”.</p> +</aside> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id12">backlink</a></em></p> +<p>Duplicate explicit target name: “python”.</p> +</aside> +<p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-06-24-week-4-praneeth.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/ganimtron_10s-blog-copy-2/week-4-exam-preparations-and-reviewing/">Python</a></p> +</td> +</tr> +<tr class="row-odd"><td><p>Week 5 (01-07-2023)</p></td> +<td><p>Trying out PRs and Planning Ahead</p></td> +<td><aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id13">backlink</a></em></p> +<p>Duplicate explicit target name: “fury”.</p> +</aside> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id14">backlink</a></em></p> +<p>Duplicate explicit target name: “python”.</p> +</aside> +<p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-07-01-week-5-praneeth.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/ganimtron_10s-blog-copy-2/week-5-testing-out-prs-and-planning-ahead/">Python</a></p> +</td> +</tr> +<tr class="row-even"><td><p>Week 6 (08-07-2023)</p></td> +<td><p>BoundingBox for TextBlock2D!</p></td> +<td><aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id15">backlink</a></em></p> +<p>Duplicate explicit target name: “fury”.</p> +</aside> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id16">backlink</a></em></p> +<p>Duplicate explicit target name: “python”.</p> +</aside> +<p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-07-08-week-6-praneeth.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/ganimtron_10s-blog-copy-2/week-6-boundingbox-for-textblock2d/">Python</a></p> +</td> +</tr> +<tr class="row-odd"><td><p>Week 7 (15-07-2023)</p></td> +<td><p>Sowing the seeds for TreeUI</p></td> +<td><aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id17">backlink</a></em></p> +<p>Duplicate explicit target name: “fury”.</p> +</aside> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id18">backlink</a></em></p> +<p>Duplicate explicit target name: “python”.</p> +</aside> +<p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-07-15-week-7-praneeth.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/ganimtron_10s-blog-copy-2/week-7-sowing-the-seeds-for-treeui/">Python</a></p> +</td> +</tr> +<tr class="row-even"><td><p>Week 8 (22-07-2023)</p></td> +<td><p>Another week with TextBlockUI</p></td> +<td><aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id19">backlink</a></em></p> +<p>Duplicate explicit target name: “fury”.</p> +</aside> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id20">backlink</a></em></p> +<p>Duplicate explicit target name: “python”.</p> +</aside> +<p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-07-22-week-8-praneeth.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/ganimtron_10s-blog-copy-2/week-8-another-week-with-textblockui/">Python</a></p> +</td> +</tr> +<tr class="row-odd"><td><p>Week 9 (29-07-2023)</p></td> +<td><p>TextBlock2D is Finally Merged!</p></td> +<td><aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id21">backlink</a></em></p> +<p>Duplicate explicit target name: “fury”.</p> +</aside> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id22">backlink</a></em></p> +<p>Duplicate explicit target name: “python”.</p> +</aside> +<p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-07-29-week-9-praneeth.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/ganimtron_10s-blog-copy-2/week-9-textblock2d-is-finally-merged/">Python</a></p> +</td> +</tr> +<tr class="row-even"><td><p>Week 10 (05-08-2023)</p></td> +<td><p>Its time for a Spin-Box!</p></td> +<td><aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id23">backlink</a></em></p> +<p>Duplicate explicit target name: “fury”.</p> +</aside> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id24">backlink</a></em></p> +<p>Duplicate explicit target name: “python”.</p> +</aside> +<p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-08-05-week-10-praneeth.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/ganimtron_10s-blog-copy-2/week-10-its-time-for-a-spin-box/">Python</a></p> +</td> +</tr> +<tr class="row-odd"><td><p>Week 11 (12-08-2023)</p></td> +<td><p>Bye Bye SpinBox</p></td> +<td><aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id25">backlink</a></em></p> +<p>Duplicate explicit target name: “fury”.</p> +</aside> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id26">backlink</a></em></p> +<p>Duplicate explicit target name: “python”.</p> +</aside> +<p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-08-12-week-11-praneeth.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/ganimtron_10s-blog-copy-2/week-11-bye-bye-spinbox/">Python</a></p> +</td> +</tr> +<tr class="row-even"><td><p>Week 12 (19-08-2023)</p></td> +<td><p>FileDialog Quest Begins!</p></td> +<td><aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id27">backlink</a></em></p> +<p>Duplicate explicit target name: “fury”.</p> +</aside> +<aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-25-final-report-praneeth.rst</span>, line 15); <em><a href="#id28">backlink</a></em></p> +<p>Duplicate explicit target name: “python”.</p> +</aside> +<p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-08-19-week-12-praneeth.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/ganimtron_10s-blog-copy-2/week-12-filedialog-quest-begins/">Python</a></p> +</td> +</tr> +</tbody> +</table> +</section> +</section> + + + Name: Praneeth Shetty + + 2023-08-25T00:00:00-04:00 + + + https://fury.gl/posts/2023/2023-08-24-week-12-tvcastillod.html + Week 12 : Experimenting with ODFs implementation + 2023-08-24T00:00:00-04:00 + + Tania Castillo + + <section id="week-12-experimenting-with-odfs-implementation"> + +<section id="what-did-i-do-this-week"> +<h2>What did I do this week?</h2> +<p>There were different issues I needed to address for the ODF implementation. Even though I could not solve any of them completely, I did check each of the issues and made some progress. All the work in progress is being recorded in the following branch <a class="reference external" href="https://github.com/tvcastillod/fury/tree/SH-for-ODF-impl">SH-for-ODF-impl</a>, which when ready will be associated with a well-structured PR.</p> +<p>First, about the scaling, I was suggested to check Generalized Fractional Anisotropy <strong>gfa</strong> metric to adjust the scaling depending on the shape of the ODF glyph, i.e., the less the <strong>gfa</strong> the more sphere-shaped and smaller, so I had to associate a greater scaling for those. However, this did not work very well as I was unable to define an appropriate scale relation that would give an equitable result for each glyph. For this reason, I opted to use peak values which are extracted from the ODFs, setting the scales as 1/peak_value*0.4 and I got a more uniformly sized glyph without the need of setting it manually. That is a temporal solution as I would like to see better why this happens and if possible do the adjustment inside the shader instead of a precalculation.</p> +<p>Second, for the direction, I made a small adjustment to the spherical coordinates which affected the direction of the ODF glyph. As you can see below,</p> +<img alt="https://user-images.githubusercontent.com/31288525/263122770-b9ee19d2-d82b-4d7f-a5bb-1cbbf5907049.png" class="align-center" src="https://user-images.githubusercontent.com/31288525/263122770-b9ee19d2-d82b-4d7f-a5bb-1cbbf5907049.png" style="width: 400px;" /> +<p>All the glyphs are aligned over the y-axis but not over the z-axis, to correct this I precalculated the main direction of each glyph using peaks and passed it to the shader as a <em>vec3</em>, then used <em>vec2vecrotmat</em> to align the main axis vector of the ODF to the required direction vector, the only problem with this is that not all the glyps are equally aligned to the axis, i.e., the first 3 glyphs are aligned with the x-axis but the last one is aligned with the y-axis, so the final rotation gives a different result for that one.</p> +<img alt="https://user-images.githubusercontent.com/31288525/263122752-b2aa696f-62a5-4b09-b8dd-0cb1ec49431c.png" class="align-center" src="https://user-images.githubusercontent.com/31288525/263122752-b2aa696f-62a5-4b09-b8dd-0cb1ec49431c.png" style="width: 400px;" /> +<p>As with the first small adjustment of the coordinates the direction was partially correct, I need to double check the theta, phi and r definitions to see if I can get the right direction without the need of the additional data of direction. Also, there might be a way to get the specific rotation angles associated to each individual glyph from the data associated with the ODFs.</p> +<p>Third, about passing the coefficients data through textures, I understand better now how to pass textures to the shaders but I still have problems understanding how to retrieve the data inside the shader. I used <a class="reference external" href="https://github.com/fury-gl/fury/blob/master/docs/experimental/viz_shader_texture.py">this base implementation</a>, suggested by one of my mentors, to store the data as a <a class="reference external" href="http://www.khronos.org/opengl/wiki/Cubemap_Texture#:~:text=A%20Cubemap%20Texture%20is%20a,the%20value%20to%20be%20accessed.">texture cubemap</a>, “a texture, where each mipmap level consists of six 2D images which must be square. The 6 images represent the faces of a cube”. I had 4x15 coefficients and inside the function, a grid of RGB colors is made so then it can be mapped as a texture. To check if was passing the data correctly, I used the same value, .5, for all the textures, so then I could pick a random texel get a specific color (gray), and pass it as <em>fragOutput0</em> to see if the value was correct. However, it didn’t appear to work correctly as I couldn’t get the expected color. To get the specific color I used <a class="reference external" href="https://registry.khronos.org/OpenGL-Refpages/gl4/html/texture.xhtml">texture(sampler, P)</a> which samples texels from the texture bound to sampler at texture coordinate P. Now, what I still need to figure out is which should be the corresponding texture coordinate. I have tried with random coordinates, as they are supposed to correspond to a point on the cube and since the information I have encoded in the texture is all the same, I assumed that I would get the expected result for any set of values. It might be a problem with the data normalization, or maybe there is something failing on the texture definition, but I need to review it in more detail to see where is the problem.</p> +<p>Lastly, about the colormapping, I created the texture based on a generic colormap from <a class="reference external" href="https://matplotlib.org/stable/tutorials/colors/colormaps.html">matplotlib</a>. I was able to give some color to the glyph but it does not match correctly its shape. Some adjustment must be done regarding the texels, as the colormap is mapped on a cube, but I need it to fit the shape of the glyph correctly.</p> +<img alt="https://user-images.githubusercontent.com/31288525/263122760-7d1fff5e-7787-473c-8053-ea69f3009fb4.png" class="align-center" src="https://user-images.githubusercontent.com/31288525/263122760-7d1fff5e-7787-473c-8053-ea69f3009fb4.png" style="width: 250px;" /> +</section> +<section id="what-is-coming-up-next"> +<h2>What is coming up next?</h2> +<p>I will continue to explore more on how to handle textures so I can solve the issues related to the coefficient data and colormapping. Also, take a deeper look at the SH implementation and check what is the information needed to adjust the main direction of the ODF correctly.</p> +</section> +<section id="did-i-get-stuck-anywhere"> +<h2>Did I get stuck anywhere?</h2> +<p>As I mentioned I had some drawbacks in understanding the use of textures and how to retrieve the data inside the shaders. This is a topic that might take some time to manage properly but if I can master it and understand it better, it is a tool that can be useful later. Additionally, there are details of the SH implementation that I still need to understand and explore better in order to make sure I get exactly the same result as the current <em>odf_slicer</em> implementation.</p> +</section> +</section> + + + There were different issues I needed to address for the ODF implementation. Even though I could not solve any of them completely, I did check each of the issues and made some progress. All the work in progress is being recorded in the following branch SH-for-ODF-impl, which when ready will be associated with a well-structured PR. + + 2023-08-24T00:00:00-04:00 + + + https://fury.gl/posts/2023/2023-08-24-final-report-tvcastillod.html + Google Summer of Code Final Work Product + 2023-08-24T00:00:00-04:00 + + Tania Castillo + + <a class="reference external image-reference" href="https://summerofcode.withgoogle.com/programs/2023/projects/ymwnLwtT"><img alt="https://developers.google.com/open-source/gsoc/resources/downloads/GSoC-logo-horizontal.svg" class="align-center" height="50" src="https://developers.google.com/open-source/gsoc/resources/downloads/GSoC-logo-horizontal.svg" /></a> +<a class="reference external image-reference" href="https://summerofcode.withgoogle.com/programs/2023/organizations/python-software-foundation"><img alt="https://www.python.org/static/community_logos/python-logo.png" src="https://www.python.org/static/community_logos/python-logo.png" style="width: 40%;" /></a> +<a class="reference external image-reference" href="https://fury.gl/latest/index.html"><img alt="https://python-gsoc.org/logos/FURY.png" src="https://python-gsoc.org/logos/FURY.png" style="width: 25%;" /></a> +<section id="google-summer-of-code-final-work-product"> + +<ul class="simple"> +<li><p><strong>Name:</strong> Tania Castillo</p></li> +<li><p><strong>Organisation:</strong> Python Software Foundation</p></li> +<li><p><strong>Sub-Organisation:</strong> FURY</p></li> +<li><p><strong>Project:</strong> <a class="reference external" href="https://github.com/fury-gl/fury/wiki/Google-Summer-of-Code-2023-(GSOC2023)#project-3-sdf-based-uncertainty-representation-for-dmri-glyphs">SDF-based uncertainty representation for dMRI glyphs</a></p></li> +</ul> +<section id="abstract"> +<h2>Abstract</h2> +<p>Diffusion Magnetic Resonance Imaging (dMRI) is a non-invasive imaging technique used by neuroscientists to measure the diffusion of water molecules in biological tissue. The directional information is reconstructed using either a Diffusion Tensor Imaging (DTI) or High Angular Resolution Diffusion Imaging (HARDI) based model, which is graphically represented as tensors and Orientation Distribution Functions (ODF). Traditional rendering engines discretize Tensor and ODF surfaces using triangles or quadrilateral polygons, making their visual quality depending on the number of polygons used to build the 3D mesh, which might compromise real-time display performance. This project proposes a methodological approach to further improve the visualization of DTI tensors and HARDI ODFs glyphs by using well-established techniques in the field of computer graphics, such as geometry amplification, billboarding, signed distance functions (SDFs), and ray marching.</p> +</section> +<section id="proposed-objectives"> +<h2>Proposed Objectives</h2> +<ul class="simple"> +<li><p>Implement a parallelized version of computer-generated billboards using geometry shaders for amplification.</p></li> +<li><p>Model the mathematical functions that express the geometry of ellipsoid glyphs and implement them using Ray Marching techniques.</p></li> +<li><p>Model the mathematical functions that express the geometry of ODF glyphs and implement them using Ray Marching techniques.</p></li> +<li><p>Use SDF properties and techniques to represent the uncertainty of dMRI reconstruction models.</p></li> +</ul> +</section> +<section id="objectives-completed"> +<h2>Objectives Completed</h2> +<section id="ellipsoid-actor-implemented-with-sdf"> +<h3>Ellipsoid actor implemented with SDF</h3> +<p>A first approach for tensor glyph generation has been made, using ray marching and SDF applied to a box. The current implementation (<code class="docutils literal notranslate"><span class="pre">tensor_slicer</span></code>) requires a sphere with a specific number of vertices to be deformed. Based on this model, a sphere with more vertices is needed to get a higher resolution. Because the ray marching technique does not use polygonal meshes, it is possible to define perfectly smooth surfaces and still obtain a fast rendering.</p> +<p>Details of the implementation:</p> +<ul class="simple"> +<li><p><em>Vertex shader pre-calculations</em>: Some minor calculations are done in the vertex shader. One, corresponding to the eigenvalues constraining and min-max normalization, are to avoid incorrect visualizations when the difference between the eigenvalues is too large. And the other is related to the tensor matrix calculation given by the diffusion tensor definition <span class="math notranslate nohighlight">\(T = R^{−1}\Lambda R\)</span>, where <span class="math notranslate nohighlight">\(R\)</span> is a rotation matrix that transforms the standard basis onto the eigenvector basis, and <span class="math notranslate nohighlight">\(\Lambda\)</span> is the diagonal matrix of eigenvalues <a class="footnote-reference brackets" href="#id10" id="id1" role="doc-noteref"><span class="fn-bracket">[</span>4<span class="fn-bracket">]</span></a>.</p></li> +<li><p><em>Ellipsoid SDF definition</em>: The definition of the SDF is done in the fragment shader inside the <code class="docutils literal notranslate"><span class="pre">map</span></code> function, which is used later for the ray marching algorithm and the normals calculation. We define the SDF more simply by transforming a sphere into an ellipsoid, considering that the SDF of a sphere is easily computed and the definition of a tensor gives us a linear transformation of a given geometry. Also, as scaling is not a rigid body transformation, we multiply the final result by a factor to compensate for the difference, which gave us the SDF of the ellipsoid defined as <code class="docutils literal notranslate"><span class="pre">sdSphere(tensorMatrix</span> <span class="pre">*</span> <span class="pre">(position</span> <span class="pre">-</span> <span class="pre">centerMCVSOutput),</span> <span class="pre">scaleVSOutput*0.48)</span> <span class="pre">*</span> <span class="pre">scFactor</span></code>.</p></li> +<li><p><em>Ray marching algorithm and lighting</em>: For the ray marching algorithm, a small value of 20 was taken as the maximum distance since we apply the technique to each individual object and not all at the same time. Additionally, we set the convergence precision to 0.001. We use the central differences method to compute the normals necessary for the scene’s illumination, besides the Blinn-Phong lighting technique, which is high-quality and computationally cheap.</p></li> +<li><p><em>Visualization example</em>: Below is a detailed visualization of the ellipsoids created from this new implementation.</p></li> +</ul> +<img alt="https://user-images.githubusercontent.com/31288525/244503195-a626718f-4a13-4275-a2b7-6773823e553c.png" class="align-center" src="https://user-images.githubusercontent.com/31288525/244503195-a626718f-4a13-4275-a2b7-6773823e553c.png" style="width: 376px;" /> +<p>This implementation does show a better quality in the displayed glyphs, and supports the display of a large amount of data, as seen in the image below. For this reason, a tutorial was made to justify in more detail the value of this new implementation. Below are some images generated for the tutorial.</p> +<img alt="https://user-images.githubusercontent.com/31288525/260906510-d422e7b4-3ba3-4de6-bfd0-09c04bec8876.png" class="align-center" src="https://user-images.githubusercontent.com/31288525/260906510-d422e7b4-3ba3-4de6-bfd0-09c04bec8876.png" style="width: 600px;" /> +<p><em>Pull Requests:</em></p> +<ul class="simple"> +<li><p><strong>Ellipsoid actor implemented with SDF (Merged)</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/791">fury-gl/fury#791</a></p></li> +<li><p><strong>Tutorial on using ellipsoid actor to visualize tensor ellipsoids for DTI (Merged)</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/818">fury-gl/fury#818</a></p></li> +</ul> +<p><strong>Future work:</strong> In line with one of the initial objectives, it is expected to implement billboards later on to improve the performance, i.e., higher frame rate and less memory usage for the tensor ellipsoid creation. In addition to looking for ways to optimize the naive ray marching algorithm and the definition of SDFs.</p> +</section> +</section> +<section id="objectives-in-progress"> +<h2>Objectives in Progress</h2> +<section id="dti-uncertainty-visualization"> +<h3>DTI uncertainty visualization</h3> +<p>The DTI visualization pipeline is fairly complex, as a level of uncertainty arises, which, if visualized, helps to assess the model’s accuracy. This measure is not currently implemented, and even though there are several methods to calculate and visualize the uncertainty in the DTI model, because of its simplicity and visual representation, we considered Matrix Perturbation Analysis (MPA) proposed by Basser <a class="footnote-reference brackets" href="#id7" id="id2" role="doc-noteref"><span class="fn-bracket">[</span>1<span class="fn-bracket">]</span></a>. This measurement is visualized as double cones representing the variance of the main direction of diffusion, for which the ray marching technique was also used to create these objects.</p> +<p>Details of the implementation:</p> +<ul class="simple"> +<li><p><em>Source of uncertainty</em>: The method of MPA arises from the susceptibility of DTI to dMRI noise present in diffusion-weighted images (DWIs), and also because the model is inherently statistical, making the tensor estimation and other derived quantities to be random variables <a class="footnote-reference brackets" href="#id7" id="id3" role="doc-noteref"><span class="fn-bracket">[</span>1<span class="fn-bracket">]</span></a>. For this reason, this method focus on the premise that image noise produces a random perturbation in the diffusion tensor estimation, and therefore in the calculation of eigenvalues and eigenvectors, particularly in the first eigenvector associated with the main diffusion direction.</p></li> +<li><p><em>Mathematical equation</em>: The description of the perturbation of the principal eigenvector is given by math formula where <span class="math notranslate nohighlight">\(\Delta D\)</span> corresponds to the estimated perturbation matrix of <span class="math notranslate nohighlight">\(D\)</span> given by the diagonal elements of the covariance matrix <span class="math notranslate nohighlight">\(\Sigma_{\alpha} \approx (B^T\Sigma^{−1}_{e}B)^{−1}\)</span>, where <span class="math notranslate nohighlight">\(\Sigma_{e}\)</span> is the covariance matrix of the error e, defined as a diagonal matrix made with the diagonal elements of <span class="math notranslate nohighlight">\((\Sigma^{−1}_{e}) = ⟨S(b)⟩^2 / \sigma^{2}_{\eta}\)</span>. Then, to get the angle <span class="math notranslate nohighlight">\(\theta\)</span> between the perturbed principal eigenvector of <span class="math notranslate nohighlight">\(D\)</span>, <span class="math notranslate nohighlight">\(\varepsilon_1 + \Delta\varepsilon_1\)</span>, and the estimated eigenvector <span class="math notranslate nohighlight">\(\varepsilon_1\)</span>, it can be approximated by <span class="math notranslate nohighlight">\(\theta = \tan^{−1}( \| \Delta\varepsilon_1 \|)\)</span> <a class="footnote-reference brackets" href="#id8" id="id4" role="doc-noteref"><span class="fn-bracket">[</span>2<span class="fn-bracket">]</span></a>. Taking into account the above, we define the function <code class="docutils literal notranslate"><span class="pre">main_dir_uncertainty(evals,</span> <span class="pre">evecs,</span> <span class="pre">signal,</span> <span class="pre">sigma,</span> <span class="pre">b_matrix)</span></code> that calculates the uncertainty of the eigenvector associated to the main direction of diffusion.</p></li> +<li><p><em>Double cone SDF definition</em>: The final SDF is composed by the union of 2 separately cones using the definition taken from this list of <a class="reference external" href="https://iquilezles.org/articles/distfunctions/#:~:text=Cone%20%2D%20exact,sign(s)%3B%0A%7D">distance functions</a>, in this way we have the SDF for the double cone defined as <code class="docutils literal notranslate"><span class="pre">opUnion(sdCone(p,a,h),</span> <span class="pre">sdCone(-p,a,h))</span> <span class="pre">*</span> <span class="pre">scaleVSOutput</span></code></p></li> +<li><p><em>Visualization example</em>: Below is a demo of how this new feature is intended to be used, an image of diffusion tensor ellipsoids and their associated uncertainty cones.</p></li> +</ul> +<img alt="https://user-images.githubusercontent.com/31288525/254747296-09a8674e-bfc0-4b3f-820f-8a1b1ad8c5c9.png" class="align-center" src="https://user-images.githubusercontent.com/31288525/254747296-09a8674e-bfc0-4b3f-820f-8a1b1ad8c5c9.png" style="width: 610px;" /> +<p>The implementation is almost complete, but as it is a new addition that includes mathematical calculations and for which there is no direct reference for comparison, it requires a more detail review before it can be incorporated.</p> +<p><em>Pull Request:</em></p> +<ul class="simple"> +<li><p><strong>DTI uncertainty visualization (Under Review)</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/810">fury-gl/fury#810</a></p></li> +</ul> +<p><strong>Future work:</strong> A tutorial will be made explaining in more detail how to calculate the parameters needed for the uncertainty cones using <strong>dipy</strong> functions, specifically: <a class="reference external" href="https://github.com/dipy/dipy/blob/321e06722ef42b5add3a7f570f6422845177eafa/dipy/denoise/noise_estimate.py#L272">estimate_sigma</a> for the noise variance calculation, <a class="reference external" href="https://github.com/dipy/dipy/blob/321e06722ef42b5add3a7f570f6422845177eafa/dipy/reconst/dti.py#L2112">design_matrix</a> to get the b-matrix, and <a class="reference external" href="https://github.com/dipy/dipy/blob/321e06722ef42b5add3a7f570f6422845177eafa/dipy/reconst/dti.py#L639">tensor_prediction</a> for the signal estimation. Additionally, when the ODF implementation is complete, uncertainty for this other reconstruction model is expected to be added, using semitransparent glyphs representing the mean directional information proposed by Tournier <a class="footnote-reference brackets" href="#id9" id="id5" role="doc-noteref"><span class="fn-bracket">[</span>3<span class="fn-bracket">]</span></a>.</p> +</section> +<section id="odf-actor-implemented-with-sdf"> +<h3>ODF actor implemented with SDF</h3> +<p>HARDI-based techniques require more images than DTI, however, they model the diffusion directions as probability distribution functions (PDFs), and the fitted values are returned as orientation distribution functions (ODFs). ODFs are more diffusion sensitive than the diffusion tensor and, therefore, can determine the structure of multi-directional voxels very common in the white matter regions of the brain <a class="footnote-reference brackets" href="#id9" id="id6" role="doc-noteref"><span class="fn-bracket">[</span>3<span class="fn-bracket">]</span></a>. The current actor to display this kind of glyphs is the <code class="docutils literal notranslate"><span class="pre">odf_slicer</span></code> which, given an array of spherical harmonics (SH) coefficients renders a grid of ODFs, which are created from a sphere with a specific number of vertices that fit the data.</p> +<p>For the application of this model using the same SDF ray marching techniques, we need the data of the SH coefficients, which are used to calculate the orientation distribution function (ODF) described <a class="reference external" href="https://dipy.org/documentation/1.7.0/theory/sh_basis/">here</a>. Different SH bases can be used, but for this first approach we focus on <code class="docutils literal notranslate"><span class="pre">descoteaux07</span></code> (as labeled in dipy). After performing the necessary calculations, we obtain an approximate result of the current implementation of FURY, as seen below.</p> +<img alt="https://user-images.githubusercontent.com/31288525/260909561-fd90033c-018a-465b-bd16-3586bb31ca36.png" class="align-center" src="https://user-images.githubusercontent.com/31288525/260909561-fd90033c-018a-465b-bd16-3586bb31ca36.png" style="width: 580px;" /> +<p>With a first implementation we start to solve some issues related to direction, color, and data handling, to obtain exactly the same results as the current implementation.</p> +<p>Details on the issues:</p> +<ul class="simple"> +<li><p><em>The direction and the scaling</em>: When the shape of the ODF is more sphere-like, the size of the glyph is smaller, so for the moment it needs to be adjusted manually, but the idea is to find a relationship between the coefficients and the final object size so it can be automatically scaled. Additionally, as seen in the image, the direction does not match. To fix this, an adjustment in the calculation of the spherical coordinates can be made, or pass the direction information directly.</p></li> +<li><p><em>Pass the coefficients data efficiently</em>: I’m currently creating one actor per glyph since I’m using a <em>uniform</em> array to pass the coefficients, but the idea is to pass all the data simultaneously. The first idea is to encode the coefficients data through a texture and retrieve them in the fragment shader.</p></li> +<li><p><em>The colormapping and the lighting</em>: As these objects present curvatures with quite a bit of detail in some cases, this requires more specific lighting work, in addition to having now not only one color but a color map. This can also be done with texture, but it is necessary to see in more detail how to adjust the texture to the glyph’s shape.</p></li> +</ul> +<p>More details on current progress can be seen in blogpost of <a class="reference external" href="https://fury.gl/latest/posts/2023/2023-08-16-week-11-tvcastillod.html">week 11</a> and <a class="reference external" href="https://fury.gl/latest/posts/2023/2023-08-24-week-12-tvcastillod.html">week 12</a>.</p> +<p><em>Working branch:</em></p> +<ul class="simple"> +<li><p><strong>ODF implementation (Under Development)</strong> +<a class="github reference external" href="https://github.com/tvcastillod/fury/tree/SH-for-ODF-impl">tvcastillod/fury</a></p></li> +</ul> +</section> +</section> +<section id="gsoc-weekly-blogs"> +<h2>GSoC Weekly Blogs</h2> +<ul class="simple"> +<li><p>My blog posts can be found on the <a class="reference external" href="https://fury.gl/latest/blog/author/tania-castillo.html">FURY website</a> and the <a class="reference external" href="https://blogs.python-gsoc.org/en/tvcastillods-blog/">Python GSoC blog</a>.</p></li> +</ul> +</section> +<section id="timeline"> +<h2>Timeline</h2> +<table class="table"> +<thead> +<tr class="row-odd"><th class="head"><p>Date</p></th> +<th class="head"><p>Description</p></th> +<th class="head"><p>Blog Post Link</p></th> +</tr> +</thead> +<tbody> +<tr class="row-even"><td><p>Week 0(02-06-2022)</p></td> +<td><p>Community Bounding Period</p></td> +<td><p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-06-02-week-0-tvcastillod.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/tvcastillods-blog/weekly-check-in-0-2">Python</a></p></td> +</tr> +<tr class="row-odd"><td><p>Week 1(05-06-2022)</p></td> +<td><p>Ellipsoid actor implemented with SDF</p></td> +<td><p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-06-05-week-1-tvcastillod.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/tvcastillods-blog/weekly-check-in-1-23">Python</a></p></td> +</tr> +<tr class="row-even"><td><p>Week 2(12-06-2022)</p></td> +<td><p>Making adjustments to the Ellipsoid Actor</p></td> +<td><p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-06-12-week-2-tvcastillod.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/tvcastillods-blog/weekly-check-in-2-18">Python</a></p></td> +</tr> +<tr class="row-odd"><td><p>Week 3(19-06-2022)</p></td> +<td><p>Working on uncertainty and details of the first PR</p></td> +<td><p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-06-19-week-3-tvcastillod.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/tvcastillods-blog/weekly-check-in-3-27">Python</a></p></td> +</tr> +<tr class="row-even"><td><p>Week 4(27-06-2022)</p></td> +<td><p>First draft of the DTI uncertainty visualization</p></td> +<td><p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-06-27-week-4-tvcastillod.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/tvcastillods-blog/weekly-check-in-4-24">Python</a></p></td> +</tr> +<tr class="row-odd"><td><p>Week 5(03-07-2022)</p></td> +<td><p>Preparing the data for the Ellipsoid tutorial</p></td> +<td><p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-07-03-week-5-tvcastillod.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/tvcastillods-blog/weekly-check-in-5-27">Python</a></p></td> +</tr> +<tr class="row-even"><td><p>Week 6(10-07-2022)</p></td> +<td><p>First draft of the Ellipsoid tutorial</p></td> +<td><p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-07-10-week-6-tvcastillod.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/tvcastillods-blog/weekly-check-in-6-26">Python</a></p></td> +</tr> +<tr class="row-odd"><td><p>Week 7(17-07-2022)</p></td> +<td><p>Adjustments on the Uncertainty Cones visualization</p></td> +<td><p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-07-17-week-7-tvcastillod.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/tvcastillods-blog/weekly-check-in-7-26">Python</a></p></td> +</tr> +<tr class="row-even"><td><p>Week 8(25-07-2022)</p></td> +<td><p>Working on Ellipsoid Tutorial and exploring SH</p></td> +<td><p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-07-25-week-8-tvcastillod.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/tvcastillods-blog/weekly-check-in-8-17">Python</a></p></td> +</tr> +<tr class="row-odd"><td><p>Week 9(31-07-2022)</p></td> +<td><p>Tutorial done and polishing DTI uncertainty</p></td> +<td><p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-07-31-week-9-tvcastillod.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/tvcastillods-blog/weekly-check-in-9-22">Python</a></p></td> +</tr> +<tr class="row-even"><td><p>Week 10(08-08-2022)</p></td> +<td><p>Start of SH implementation experiments</p></td> +<td><p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-08-08-week-10-tvcastillod.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/tvcastillods-blog/weekly-check-in-10-16">Python</a></p></td> +</tr> +<tr class="row-odd"><td><p>Week 11(16-08-2022)</p></td> +<td><p>Adjusting ODF implementation and looking for solutions on issues found</p></td> +<td><p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-08-16-week-11-tvcastillod.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/tvcastillods-blog/weekly-check-in-11-17">Python</a></p></td> +</tr> +<tr class="row-even"><td><p>Week 12(24-08-2022)</p></td> +<td><p>Experimenting with ODFs implementation</p></td> +<td><p><a class="reference external" href="https://fury.gl/latest/posts/2023/2023-08-24-week-12-tvcastillod.html">FURY</a> - <a class="reference external" href="https://blogs.python-gsoc.org/en/tvcastillods-blog/weekly-check-in-12-9">Python</a></p></td> +</tr> +</tbody> +</table> +</section> +<section id="references"> +<h2>References</h2> +<aside class="footnote-list brackets"> +<aside class="footnote brackets" id="id7" role="doc-footnote"> +<span class="label"><span class="fn-bracket">[</span>1<span class="fn-bracket">]</span></span> +<span class="backrefs">(<a role="doc-backlink" href="#id2">1</a>,<a role="doc-backlink" href="#id3">2</a>)</span> +<p>Basser, P. J. (1997). Quantifying errors in fiber direction and diffusion tensor field maps resulting from MR noise. In 5th Scientific Meeting of the ISMRM (Vol. 1740).</p> +</aside> +<aside class="footnote brackets" id="id8" role="doc-footnote"> +<span class="label"><span class="fn-bracket">[</span><a role="doc-backlink" href="#id4">2</a><span class="fn-bracket">]</span></span> +<p>Chang, L. C., Koay, C. G., Pierpaoli, C., &amp; Basser, P. J. (2007). Variance of estimated DTI‐derived parameters via first‐order perturbation methods. Magnetic Resonance in Medicine: An Official Journal of the International Society for Magnetic Resonance in Medicine, 57(1), 141-149.</p> +</aside> +<aside class="footnote brackets" id="id9" role="doc-footnote"> +<span class="label"><span class="fn-bracket">[</span>3<span class="fn-bracket">]</span></span> +<span class="backrefs">(<a role="doc-backlink" href="#id5">1</a>,<a role="doc-backlink" href="#id6">2</a>)</span> +<p>J-Donald Tournier, Fernando Calamante, David G Gadian, and Alan Connelly. Direct estimation of the fiber orientation density function from diffusion-weighted mri data using spherical deconvolution. Neuroimage, 23(3):1176–1185, 2004.</p> +</aside> +<aside class="footnote brackets" id="id10" role="doc-footnote"> +<span class="label"><span class="fn-bracket">[</span><a role="doc-backlink" href="#id1">4</a><span class="fn-bracket">]</span></span> +<p>Gordon Kindlmann. Superquadric tensor glyphs. In Proceedings of the Sixth Joint Eurographics-IEEE TCVG conference on Visualization, pages 147–154, 2004.</p> +</aside> +</aside> +</section> +</section> + + + Name: Tania Castillo + + 2023-08-24T00:00:00-04:00 + + + https://fury.gl/posts/2023/2023-08-21-week-12-joaodellagli.html + Week 12: Now That is (almost) a Wrap! + 2023-08-21T00:00:00-04:00 + + João Victor Dell Agli Floriano + + <section id="week-12-now-that-is-almost-a-wrap"> + +<p>Hello everyone, it’s time for another GSoC blogpost! Today, I am going to talk about some minor details I worked on last week on my +project.</p> +<section id="last-week-s-effort"> +<h2>Last Week’s Effort</h2> +<p>After the API refactoring was done last week, I focused on addressing the reviews I would get from it. The first issues I addressed was related to +style, as there were some minor details my GSoC contributors pointed out that needed change. Also, I have addressed an issue I was having +with the <cite>typed hint</cite> of one of my functions. Filipi, my mentor, showed me there is a way to have more than one typed hint in the same parameter, +all I needed to do was to use the <cite>Union</cite> class from the <cite>typing</cite> module, as shown below:</p> +<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">Union</span> <span class="k">as</span> <span class="n">tUnion</span> +<span class="kn">from</span> <span class="nn">numpy</span> <span class="kn">import</span> <span class="n">ndarray</span> + +<span class="k">def</span> <span class="nf">function</span><span class="p">(</span><span class="n">variable</span> <span class="p">:</span> <span class="n">tUnion</span><span class="p">(</span><span class="nb">float</span><span class="p">,</span> <span class="n">np</span><span class="o">.</span><span class="n">ndarray</span><span class="p">)):</span> + <span class="k">pass</span> +</pre></div> +</div> +<p>Using that, I could set the typedhint of the <cite>bandwidth</cite> variable to <cite>float</cite> and <cite>np.ndarray</cite>.</p> +</section> +<section id="so-how-did-it-go"> +<h2>So how did it go?</h2> +<p>All went fine with no difficult at all, thankfully.</p> +</section> +<section id="the-next-steps"> +<h2>The Next Steps</h2> +<p>My next plans are, after having PR <a class="reference external" href="https://github.com/fury-gl/fury/pull/826">#826</a> merged, to work on the float encoding issue described in +<span class="xref std std-doc">this blogpost</span>. Also, I plan to tackle the UI idea once again, to see if I can finally give the user +a way to control the intensities of the distributions.</p> +<p>Wish me luck!</p> +</section> +</section> + + + Hello everyone, it’s time for another GSoC blogpost! Today, I am going to talk about some minor details I worked on last week on my +project. + + 2023-08-21T00:00:00-04:00 + + + https://fury.gl/posts/2023/2023-08-21-joaodellagli-final-report.html + Google Summer of Code Final Work Product + 2023-08-21T00:00:00-04:00 + + João Victor Dell Agli Floriano + + <a class="reference external image-reference" href="https://summerofcode.withgoogle.com/programs/2023/projects/ED0203De"><img alt="https://developers.google.com/open-source/gsoc/resources/downloads/GSoC-logo-horizontal.svg" height="40" src="https://developers.google.com/open-source/gsoc/resources/downloads/GSoC-logo-horizontal.svg" /></a> +<a class="reference external image-reference" href="https://summerofcode.withgoogle.com/programs/2023/organizations/python-software-foundation"><img alt="https://www.python.org/static/img/python-logo&#64;2x.png" src="https://www.python.org/static/img/python-logo&#64;2x.png" style="height: 40px;" /></a> +<a class="reference external image-reference" href="https://fury.gl/latest/index.html"><img alt="https://python-gsoc.org/logos/fury_logo.png" src="https://python-gsoc.org/logos/fury_logo.png" style="width: 40px;" /></a> +<section id="google-summer-of-code-final-work-product"> + +<ul class="simple"> +<li><p><strong>Name:</strong> João Victor Dell Agli Floriano</p></li> +<li><p><strong>Organisation:</strong> Python Software Foundation</p></li> +<li><p><strong>Sub-Organisation:</strong> FURY</p></li> +<li><p><strong>Project:</strong> <a class="reference external" href="https://github.com/fury-gl/fury/wiki/Google-Summer-of-Code-2023-(GSOC2023)#project-2-fast-3d-kernel-based-density-rendering-using-billboards">FURY - Project 2. Fast 3D kernel-based density rendering using billboards.</a></p></li> +</ul> +<section id="abstract"> +<h2>Abstract</h2> +<p>This project had the goal to implement 3D Kernel Density Estimation rendering to FURY. Kernel Density Estimation, or KDE, is a +statistical method that uses kernel smoothing for modeling and estimating the density distribution of a set of points defined +inside a given region. For its graphical implementation, it was used post-processing techniques such as offscreen rendering to +framebuffers and colormap post-processing as tools to achieve the desired results. This was completed with a functional basic KDE +rendering result, that relies on a solid and easy-to-use API, as well as some additional features.</p> +</section> +<section id="proposed-objectives"> +<h2>Proposed Objectives</h2> +<ul class="simple"> +<li><dl class="simple"> +<dt><strong>First Phase</strong><span class="classifier">Implement framebuffer usage in FURY</span></dt><dd><ul> +<li><p>Investigate the usage of float framebuffers inside FURY’s environment.</p></li> +<li><p>Implement a float framebuffer API.</p></li> +</ul> +</dd> +</dl> +</li> +<li><dl class="simple"> +<dt><strong>Second Phase</strong><span class="classifier">Shader-framebuffer integration</span></dt><dd><ul> +<li><p>Implement a shader that uses a colormap to render framebuffers.</p></li> +<li><p>Escalate this rendering for composing multiple framebuffers.</p></li> +</ul> +</dd> +</dl> +</li> +<li><dl class="simple"> +<dt><strong>Third Phase</strong><span class="classifier">KDE Calculations</span></dt><dd><ul> +<li><p>Investigate KDE calculation for point-cloud datasets.</p></li> +<li><p>Implement KDE calculation inside the framebuffer rendering shaders.</p></li> +<li><p>Test KDE for multiple datasets.</p></li> +</ul> +</dd> +</dl> +</li> +</ul> +</section> +<section id="objectives-completed"> +<h2>Objectives Completed</h2> +<ul> +<li><dl> +<dt><strong>Implement framebuffer usage in FURY</strong></dt><dd><p>The first phase, addressed from <em>May/29</em> to <em>July/07</em>, started with the investigation of +<a class="reference external" href="https://vtk.org/doc/nightly/html/classvtkOpenGLFramebufferObject.html#details">VTK’s Framebuffer Object</a>, a vital part of this project, to understand +how to use it properly.</p> +<p>Framebuffer Objects, abbreviated as FBOs, are the key to post-processing effects in OpenGL, as they are used to render things offscreen and save the resulting image to a texture +that will be later used to apply the desired post-processing effects within the object’s <a class="reference external" href="https://www.khronos.org/opengl/wiki/Fragment_Shader">fragment shader</a> +rendered to screen, in this case, a <a class="reference external" href="http://www.opengl-tutorial.org/intermediate-tutorials/billboards-particles/billboards/">billboard</a>. In the case of the +<a class="reference external" href="https://en.wikipedia.org/wiki/Kernel_density_estimation">Kernel Density Estimation</a> post-processing effect, we need a special kind of FBO, one that stores textures’ +values as floats, different from the standard 8-bit unsigned int storage. This is necessary because the KDE rendering involves rendering every KDE point calculation +to separate billboards, rendered to the same scene, which will have their intensities, divided by the number of points rendered, blended with +<a class="reference external" href="https://www.khronos.org/opengl/wiki/Blending">OpenGL Additive Blending</a>, and if a relative big number of points are rendered at the +same time, 32-bit float precision is needed to guarantee that small-intensity values will not be capped to zero, and disappear.</p> +<p>After a month going through VTK’s FBO documentation and weeks spent trying different approaches to this method, it would not work +properly, as some details seemed to be missing from the documentation, and asking the community haven’t solved the problem as well. +Reporting that to my mentors, which unsuccessfully tried themselves to make it work, they decided it was better if another path was taken, using +<a class="reference external" href="https://vtk.org/doc/nightly/html/classvtkWindowToImageFilter.html">VTK’s WindowToImageFilter</a> method as a workaround, described +in this <a class="reference external" href="https://fury.gl/latest/posts/2023/2023-07-03-week-5-joaodellagli.html">blogpost</a>. This method helped the development of +three new functions to FURY, <em>window_to_texture()</em>, <em>texture_to_actor()</em> and <em>colormap_to_texture()</em>, that allow the passing of +different kinds of textures to FURY’s actor’s shaders, the first one to capture a window and pass it as a texture to an actor, +the second one to pass an external texture to an actor, and the third one to specifically pass a colormap as a texture to an +actor. It is important to say that <em>WindowToImageFilter()</em> is not the ideal way to make it work, as this method does not seem to +support float textures. However, a workaround to that is currently being worked on, as I will describe later on.</p> +<p><em>Pull Requests:</em></p> +<ul class="simple"> +<li><p><strong>KDE Rendering Experimental Program (Needs major revision):</strong> <a class="github reference external" href="https://github.com/fury-gl/fury/pull/804">fury-gl/fury#804</a></p></li> +</ul> +<p>The result of this whole FBO and WindowToImageFilter experimentation is well documented in PR +<a class="reference external" href="https://github.com/fury-gl/fury/pull/804">#804</a> that implements an experimental version of a KDE rendering program. +The future of this PR, as discussed with my mentors, is to be better documented to be used as an example for developers on +how to develop features in FURY with the tools used, and it shall be done soon.</p> +</dd> +</dl> +</li> +<li><dl> +<dt><strong>Shader-framebuffer integration</strong></dt><dd><aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-21-joaodellagli-final-report.rst</span>, line 16); <em><a href="#id2">backlink</a></em></p> +<p>Duplicate explicit target name: “blogpost”.</p> +</aside> +<p>The second phase, which initially was thought of as “Implement a shader that uses a colormap to render framebuffers” and “Escalate this +rendering for composing multiple framebuffers” was actually a pretty simple phase that could be addressed in one week, <em>July/10</em> +to <em>July/17</em>, done at the same time as the third phase goal, documented in this +<a class="reference external" href="https://fury.gl/latest/posts/2023/2023-07-17-week-7-joaodellagli.html">blogpost</a>. As FURY already had a tool for generating and +using colormaps, they were simply connected to the shader part of the program as textures, with the functions explained above. +Below, is the result of the <em>matplotlib viridis</em> colormap passed to a simple gaussian KDE render:</p> +<img alt="Final 2D plot" class="align-center" src="https://raw.githubusercontent.com/JoaoDell/gsoc_assets/main/images/final_2d_plot.png" /> +<aside class="system-message"> +<p class="system-message-title">System Message: INFO/1 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-21-joaodellagli-final-report.rst</span>, line 16); <em><a href="#id3">backlink</a></em></p> +<p>Duplicate explicit target name: “#804”.</p> +</aside> +<p>That is also included in PR <a class="reference external" href="https://github.com/fury-gl/fury/pull/804">#804</a>. Having the 2D plot ready, some time was taken to +figure out how to enable a 3D render, that includes rotation and other movement around the set rendered, which was solved by +learning about the callback properties that exist inside <em>VTK</em>. Callbacks are ways to enable code execution inside the VTK rendering +loop, enclosed inside <em>vtkRenderWindowInteractor.start()</em>. If it is desired to add a piece of code that, for example, passes a time +variable to the fragment shader over time, a callback function can be declared:</p> +<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">fury</span> <span class="kn">import</span> <span class="n">window</span> +<span class="n">t</span> <span class="o">=</span> <span class="mi">0</span> +<span class="n">showm</span> <span class="o">=</span> <span class="n">window</span><span class="o">.</span><span class="n">ShowManager</span><span class="p">(</span><span class="o">...</span><span class="p">)</span> + +<span class="k">def</span> <span class="nf">callback_function</span><span class="p">:</span> + <span class="n">t</span> <span class="o">+=</span> <span class="mf">0.01</span> + <span class="n">pass_shader_uniforms_to_fs</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="s2">&quot;t&quot;</span><span class="p">)</span> + +<span class="n">showm</span><span class="o">.</span><span class="n">add_iren_callback</span><span class="p">(</span><span class="n">callback_function</span><span class="p">,</span> <span class="s2">&quot;RenderEvent&quot;</span><span class="p">)</span> +</pre></div> +</div> +<p>The piece of code above created a function that updates the time variable <em>t</em> in every <em>“RenderEvent”</em>, and passes it to the +fragment shader. With that property, the camera and some other parameters could be updated, which enabled 3D visualization, that +then, outputted the following result, using <em>matplotlib inferno</em> colormap:</p> +<img alt="3D Render gif" class="align-center" src="https://raw.githubusercontent.com/JoaoDell/gsoc_assets/main/images/3d_kde_gif.gif" /> +</dd> +</dl> +</li> +<li><dl> +<dt><strong>KDE Calculations</strong> (ongoing)</dt><dd><p>As said before, the second and third phases were done simultaneously, so after having a way to capture the window and use it as a +texture ready, the colormap ready, and an initial KDE render ready, all it was needed to do was to improve the KDE calculations. +As this <a class="reference external" href="https://en.wikipedia.org/wiki/Kernel_density_estimation">Wikipedia page</a> explains, a KDE calculation is to estimate an +abstract density around a set of points defined inside a given region with a kernel, that is a function that models the density +around a point based on its associated distribution <span class="math notranslate nohighlight">\(\sigma\)</span>.</p> +<p>A well-known kernel is, for example, the <strong>Gaussian Kernel</strong>, that says that the density around a point <span class="math notranslate nohighlight">\(p\)</span> with distribution +<span class="math notranslate nohighlight">\(\sigma\)</span> is defined as:</p> +<div class="math notranslate nohighlight"> +\[GK_{\textbf{p}, \sigma} (\textbf{x}) = e^{-\frac{1}{2}\frac{||\textbf{x} - \textbf{p}||^2}{\sigma^2}}\]</div> +<p>Using that kernel, we can calculate the KDE of a set of points <span class="math notranslate nohighlight">\(P\)</span> with associated distributions <span class="math notranslate nohighlight">\(S\)</span> calculating their individual +Gaussian distributions, summing them up and dividing them by the total number of points <span class="math notranslate nohighlight">\(n\)</span>:</p> +<div class="math notranslate nohighlight"> +\[KDE(A, S)=\frac{1}{n}\sum_{i = 0}^{n}GK(x, p_{i}, \sigma_{i})\]</div> +<p>So I dove into implementing all of that into the offscreen rendering part, and that is when the lack of a float framebuffer would +charge its cost. As it can be seen above, just calculating each point’s density isn’t the whole part, as I also need to divide +everyone by the total number of points <span class="math notranslate nohighlight">\(n\)</span>, and then sum them all. The problem is that, if the number of points its big enough, +the individual densities will be really low, and that would not be a problem for a 32-bit precision float framebuffer, but that is +<em>definitely</em> a problem for a 8-bit integer framebuffer, as small enough values will simply underflow and disappear. That issue is +currently under investigation, and some solutions have already being presented, as I will show in the <strong>Objectives in Progress</strong> +section.</p> +<p>Apart from that, after having the experimental program ready, I focused on modularizing it into a functional and simple API +(without the <span class="math notranslate nohighlight">\(n\)</span> division for now), and I could get a good set of results from that. The API I first developed implemented the +<em>EffectManager</em> class, responsible for managing all of the behind-the-scenes steps necessary for the kde render to work, +encapsulated inside the <em>ÈffectManager.kde()</em> method. It had the following look:</p> +<aside class="system-message"> +<p class="system-message-title">System Message: ERROR/3 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-21-joaodellagli-final-report.rst</span>, line 162)</p> +<p>Error in “code-block” directive: +maximum 1 argument(s) allowed, 9 supplied.</p> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="o">..</span> <span class="n">code</span><span class="o">-</span><span class="n">block</span><span class="p">::</span> <span class="n">python</span> + <span class="kn">from</span> <span class="nn">fury.effect_manager</span> <span class="kn">import</span> <span class="n">EffectManager</span> + <span class="kn">from</span> <span class="nn">fury</span> <span class="kn">import</span> <span class="n">window</span> + + <span class="n">showm</span> <span class="o">=</span> <span class="n">window</span><span class="o">.</span><span class="n">ShowManager</span><span class="p">(</span><span class="o">...</span><span class="p">)</span> + + <span class="c1"># KDE rendering setup</span> + <span class="n">em</span> <span class="o">=</span> <span class="n">EffectManager</span><span class="p">(</span><span class="n">showm</span><span class="p">)</span> + <span class="n">kde_actor</span> <span class="o">=</span> <span class="n">em</span><span class="o">.</span><span class="n">kde</span><span class="p">(</span><span class="o">...</span><span class="p">)</span> + <span class="c1"># End of KDE rendering setup</span> + + <span class="n">showmn</span><span class="o">.</span><span class="n">scene</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">kde_actor</span><span class="p">)</span> + + <span class="n">showm</span><span class="o">.</span><span class="n">start</span><span class="p">()</span> +</pre></div> +</div> +</aside> +<p>Those straightforward instructions, that hid several lines of code and setup, could manage to output the following result:</p> +<img alt="API 3D KDE plot" class="align-center" src="https://raw.githubusercontent.com/JoaoDell/gsoc_assets/main/images/fianl_3d_plot.png" /> +<p>And this was not the only feature I had implemented for this API, as the use of <em>WindowToImageFilter</em> method opened doors for a +whole new world for FURY: The world of post-processing effects. With this features setup, I managed to implement a <em>gaussian blur</em> +effect, a <em>grayscale</em> effect and a <em>Laplacian</em> effect for calculating “borders”:</p> +<img alt="Gaussian Blur effect" class="align-center" src="https://raw.githubusercontent.com/JoaoDell/gsoc_assets/main/images/gaussian_blur.png" /> +<img alt="Grayscale effect" class="align-center" src="https://raw.githubusercontent.com/JoaoDell/gsoc_assets/main/images/grayscale.png" /> +<img alt="Laplacian effect" class="align-center" src="https://raw.githubusercontent.com/JoaoDell/gsoc_assets/main/images/laplacian1.gif" /> +<p>As this wasn’t the initial goal of the project and I still had several issues to deal with, I have decided to leave these features as a +future addition.</p> +<p>Talking with my mentors, we realized that the first KDE API, even though simple, could lead to bad usage from users, as the +<em>em.kde()</em> method, that outputted a <em>FURY actor</em>, had dependencies different from any other object of its kind, making it a new +class of actors, which could lead to confusion and bad handling. After some pair programming sessions, they instructed me to take +a similar, but different road from what I was doing, turning the kde actor into a new class, the <em>KDE</em> class. This class would +have almost the same set of instructions present in the prior method, but it would break them in a way it would only be completely +set up after being passed to the <em>EffectManager</em> via its add function. Below, how the refactoring handles it:</p> +<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">fury.effects</span> <span class="kn">import</span> <span class="n">EffectManager</span><span class="p">,</span> <span class="n">KDE</span> +<span class="kn">from</span> <span class="nn">fury</span> <span class="kn">import</span> <span class="n">window</span> + +<span class="n">showm</span> <span class="o">=</span> <span class="n">window</span><span class="o">.</span><span class="n">ShowManager</span><span class="p">(</span><span class="o">...</span><span class="p">)</span> + +<span class="c1"># KDE rendering setup</span> +<span class="n">em</span> <span class="o">=</span> <span class="n">EffectManager</span><span class="p">(</span><span class="n">showm</span><span class="p">)</span> +<span class="n">kde_effect</span> <span class="o">=</span> <span class="n">KDE</span><span class="p">(</span><span class="o">...</span><span class="p">)</span> +<span class="n">em</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">kde_effect</span><span class="p">)</span> +<span class="c1"># End of KDE rendering setup</span> + +<span class="n">showm</span><span class="o">.</span><span class="n">start</span><span class="p">()</span> +</pre></div> +</div> +<p>Which outputted the same results as shown above. It may have cost some simplicity as we are now one line farther from having it +working, but it is more explicit in telling the user this is not just a normal actor.</p> +<p>Another detail I worked on was the kernel variety. The Gaussian Kernel isn’t the only one available to model density distributions, +there are several others that can do that job, as it can be seen in this <a class="reference external" href="https://scikit-learn.org/stable/modules/density.html">scikit-learn piece of documentation</a> +and this <a class="reference external" href="https://en.wikipedia.org/wiki/Kernel_(statistics)">Wikipedia page on kernels</a>. Based on the scikit-learn KDE +implementation, I worked on implementing the following kernels inside our API, that can be chosen as a parameter when calling the +<em>KDE</em> class:</p> +<ul class="simple"> +<li><p>Cosine</p></li> +<li><p>Epanechnikov</p></li> +<li><p>Exponential</p></li> +<li><p>Gaussian</p></li> +<li><p>Linear</p></li> +<li><p>Tophat</p></li> +</ul> +<p>Below, the comparison between them using the same set of points and bandwidths:</p> +<img alt="Comparison between the six implemented kernels" class="align-center" src="https://raw.githubusercontent.com/JoaoDell/gsoc_assets/main/images/kernels.png" /> +<p><em>Pull Requests</em>:</p> +<ul class="simple"> +<li><p><strong>First Stage of the KDE Rendering API (will be merged soon)</strong>: <a class="github reference external" href="https://github.com/fury-gl/fury/pull/826">fury-gl/fury#826</a></p></li> +</ul> +<p>All of this work culminated in PR <a class="reference external" href="https://github.com/fury-gl/fury/pull/826/">#826</a>, that proposes to add the first stage of +this API (there are some details yet to be completed, like the <span class="math notranslate nohighlight">\(n\)</span> division) to FURY. This PR added the described API, and also +proposed some minor changes to some already existing FURY functions related to callbacks, changes necessary for this and other +future applications that would use it to work. It also added the six kernels described, and a simple documented example on how +to use this feature.</p> +</dd> +</dl> +</li> +</ul> +</section> +<section id="other-objectives"> +<h2>Other Objectives</h2> +<ul class="simple"> +<li><dl class="simple"> +<dt><strong>Stretch Goals</strong><span class="classifier">SDE Implementation, Network/Graph visualization using SDE/KDE, Tutorials</span></dt><dd><ul> +<li><p>Investigate SDE calculation for surface datasets.</p></li> +<li><p>Implement SDE calculation inside the framebuffer rendering shaders.</p></li> +<li><p>Test SDE for multiple datasets.</p></li> +<li><p>Develop comprehensive tutorials that explain SDE concepts and FURY API usage.</p></li> +<li><p>Create practical, scenario-based tutorials using real datasets and/or simulations.</p></li> +</ul> +</dd> +</dl> +</li> +</ul> +</section> +<section id="objectives-in-progress"> +<h2>Objectives in Progress</h2> +<ul> +<li><dl> +<dt><strong>KDE Calculations</strong> (ongoing)</dt><dd><p>The KDE rendering, even though almost complete, have the $n$ division, an important step, missing, as this normalization allows colormaps +to cover the whole range o values rendered. The lack of a float FBO made a big difference in the project, as the search for a functional implementation of it not only delayed the project, but it is vital for +the correct calculations to work.</p> +<p>For the last part, a workaround thought was to try an approach I later figured out is an old one, as it can be check in +<a class="reference external" href="https://developer.nvidia.com/gpugems/gpugems/part-ii-lighting-and-shadows/chapter-12-omnidirectional-shadow-mapping">GPU Gems 12.3.3 section</a>: +If I need 32-bit float precision and I got 4 8-bit integer precision available, why not trying to pack this float into this RGBA +texture? I have first tried to do one myself, but it didn’t work for some reason, so I tried <a class="reference external" href="https://aras-p.info/blog/2009/07/30/encoding-floats-to-rgba-the-final/">Aras Pranckevičius</a> +implementation, that does the following:</p> +<div class="highlight-GLSL notranslate"><div class="highlight"><pre><span></span><span class="kt">vec4</span><span class="w"> </span><span class="n">float_to_rgba</span><span class="p">(</span><span class="kt">float</span><span class="w"> </span><span class="n">value</span><span class="p">)</span><span class="w"> </span><span class="p">{</span> +<span class="w"> </span><span class="kt">vec4</span><span class="w"> </span><span class="n">bitEnc</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="kt">vec4</span><span class="p">(</span><span class="mf">1.</span><span class="p">,</span><span class="mf">256.</span><span class="p">,</span><span class="mf">65536.0</span><span class="p">,</span><span class="mf">16777216.0</span><span class="p">);</span> +<span class="w"> </span><span class="kt">vec4</span><span class="w"> </span><span class="n">enc</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">bitEnc</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">value</span><span class="p">;</span> +<span class="w"> </span><span class="n">enc</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">fract</span><span class="p">(</span><span class="n">enc</span><span class="p">);</span> +<span class="w"> </span><span class="n">enc</span><span class="w"> </span><span class="o">-=</span><span class="w"> </span><span class="n">enc</span><span class="p">.</span><span class="n">yzww</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="kt">vec2</span><span class="p">(</span><span class="mf">1.</span><span class="o">/</span><span class="mf">255.</span><span class="p">,</span><span class="w"> </span><span class="mf">0.</span><span class="p">).</span><span class="n">xxxy</span><span class="p">;</span> +<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="n">enc</span><span class="p">;</span> +<span class="p">}</span> +</pre></div> +</div> +<p>That initially worked, but for some reason I am still trying to understand, it is resulting in a really noisy texture:</p> +<img alt="Noisy KDE render" class="align-center" src="https://raw.githubusercontent.com/JoaoDell/gsoc_assets/main/images/noisy%20kde.png" /> +<p>One way to try to mitigate that while is to pass this by a gaussian blur filter, to try to smooth out the result:</p> +<img alt="Blurred result" class="align-center" src="https://raw.githubusercontent.com/JoaoDell/gsoc_assets/main/images/blurred_kde.png" /> +<p>But it is not an ideal solution as well, as it may lead to distortions in the actual density values, depending on the application of +the KDE. Now, my goal is to first find the root of the noise problem, and then, if that does not work, try to make the gaussian filter +work.</p> +<p>Another detail that would be a good addition to the API is UI controls. Filipi, one of my mentors, told me it would be a good feature +if the user could control the intensities of the bandwidths for a better structural visualization of the render, and knowing FURY already +have a good set of <a class="reference external" href="https://fury.gl/latest/auto_examples/index.html#user-interface-elements">UI elements</a>, I just needed to integrate +that into my program via callbacks. I tried implementing an intensity slider. However, for some reason, it is making the program crash +randomly, for reasons I still don’t know, so that is another issue under investigation. Below, we show a first version of that feature, +which was working before the crashes:</p> +<img alt="Slider for bandwidths" class="align-center" src="https://raw.githubusercontent.com/JoaoDell/gsoc_assets/main/images/slider.gif" /> +<p><em>Pull Requests</em></p> +<ul class="simple"> +<li><p><strong>UI intensity slider for the KDE rendering API (draft)</strong>: <a class="github reference external" href="https://github.com/fury-gl/fury/pull/849">fury-gl/fury#849</a></p></li> +<li><p><strong>Post-processing effects for FURY Effects API (draft)</strong>: <a class="github reference external" href="https://github.com/fury-gl/fury/pull/850">fury-gl/fury#850</a></p></li> +</ul> +</dd> +</dl> +</li> +</ul> +</section> +<section id="gsoc-weekly-blogs"> +<h2>GSoC Weekly Blogs</h2> +<ul class="simple"> +<li><p>My blog posts can be found at <a class="reference external" href="https://fury.gl/latest/blog/author/joao-victor-dell-agli-floriano.html">FURY website</a> and <a class="reference external" href="https://blogs.python-gsoc.org/en/joaodellaglis-blog/">Python GSoC blog</a>.</p></li> +</ul> +</section> +<section id="timeline"> +<h2>Timeline</h2> +<aside class="system-message"> +<p class="system-message-title">System Message: ERROR/3 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-21-joaodellagli-final-report.rst</span>, line 332)</p> +<p>Malformed table.</p> +<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>+---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Date | Description | Blog Post Link | ++=====================+====================================================+===========================================================================================================================================================================================================+ +| Week 0 (29-05-2023) | The Beginning of Everything | `FURY &lt;https://fury.gl/latest/posts/2023/2023-05-29-week-0-joaodellagli.html&gt;`__ - `Python &lt;https://blogs.python-gsoc.org/en/joaodellaglis-blog/the-beggining-of-everything-week-0/&gt;`__ | ++---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 1 (05-06-2022) | The FBO Saga | `FURY &lt;https://fury.gl/latest/posts/2023/2023-06-05-week-1-joaodellagli.html&gt;`__ - `Python &lt;https://blogs.python-gsoc.org/en/joaodellaglis-blog/the-fbo-saga-week-1/&gt;`__ | ++---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 2 (12-06-2022) | The Importance of (good) Documentation | `FURY &lt;https://fury.gl/latest/posts/2023/2023-06-12-week-2-joaodellagli.html&gt;`__ - `Python &lt;https://blogs.python-gsoc.org/en/joaodellaglis-blog/the-importance-of-good-documentation-week-2/&gt;`__ | ++---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 3 (19-06-2022) | Watch Your Expectations | `FURY &lt;https://fury.gl/latest/posts/2023/2023-06-19-week-3-joaodellagli.html&gt;`__ - `Python &lt;https://blogs.python-gsoc.org/en/joaodellaglis-blog/week-3-watch-your-expectations/&gt;`__ | ++---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 4 (26-06-2022) | Nothing is Ever Lost | `FURY &lt;https://fury.gl/latest/posts/2023/2023-06-26-week-4-joaodellagli.html&gt;`__ - `Python &lt;https://blogs.python-gsoc.org/en/joaodellaglis-blog/week-4-nothing-is-ever-lost/&gt;`__ | ++---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 5 (03-07-2022) | All Roads Lead to Rome | `FURY &lt;https://fury.gl/latest/posts/2023/2023-07-03-week-5-joaodellagli.html&gt;`__ - `Python &lt;https://blogs.python-gsoc.org/en/joaodellaglis-blog/week-5-all-roads-lead-to-rome/&gt;`__ | ++---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 6 (10-07-2022) | Things are Starting to Build Up | `FURY &lt;https://fury.gl/latest/posts/2023/2023-07-10-week-6-joaodellagli.html&gt;`__ - `Python &lt;https://blogs.python-gsoc.org/en/joaodellaglis-blog/week-6-things-are-starting-to-build-up/&gt;`__ | ++---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 7 (17-07-2022) | Experimentation Done | `FURY &lt;https://fury.gl/latest/posts/2023/2023-07-17-week-7-joaodellagli.html&gt;`__ - `Python &lt;https://blogs.python-gsoc.org/en/joaodellaglis-blog/week-7-experimentation-done/&gt;`__ | ++---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 8 (24-07-2022) | The Birth of a Versatile API | `FURY &lt;https://fury.gl/latest/posts/2023/2023-07-24-week-8-joaodellagli.html&gt;`__ - `Python &lt;https://blogs.python-gsoc.org/en/joaodellaglis-blog/week-8-the-birth-of-a-versatile-api/&gt;`__ | ++---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 9 (31-07-2022) | It is Polishing Time! | `FURY &lt;https://fury.gl/latest/posts/2023/2023-07-31-week-9-joaodellagli.html&gt;`__ - `Python &lt;https://blogs.python-gsoc.org/en/joaodellaglis-blog/week-9-it-is-polishing-time/&gt;`__ | ++---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 10 (07-08-2022)| Ready for Review! | `FURY &lt;https://fury.gl/latest/posts/2023/2023-08-07-week-10-joaodellagli.html&gt;`__ - `Python &lt;https://blogs.python-gsoc.org/en/joaodellaglis-blog/ready-for-review/&gt;`__ | ++---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 11 (14-08-2022)| A Refactor is Sometimes Needed | `FURY &lt;https://fury.gl/latest/posts/2023/2023-08-14-week-11-joaodellagli.html&gt;`__ - `Python &lt;https://blogs.python-gsoc.org/en/joaodellaglis-blog/a-refactor-is-sometimes-needed/&gt;`__ | ++---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Week 12 (21-08-2022)| Now That is (almost) a Wrap! | `FURY &lt;https://fury.gl/latest/posts/2023/2023-08-21-week-12-joaodellagli.html&gt;`__ - `Python &lt;https://blogs.python-gsoc.org/en/joaodellaglis-blog/week-12-now-that-is-almost-a-wrap/&gt;`__ | ++---------------------+----------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +</pre></div> +</div> +</aside> +</section> +</section> + + + Name: João Victor Dell Agli Floriano + + 2023-08-21T00:00:00-04:00 + + + https://fury.gl/posts/2023/2023-08-19-week-12-praneeth.html + Week 12: FileDialog Quest Begins! + 2023-08-19T00:00:00-04:00 + + Praneeth Shetty + + <section id="week-12-filedialog-quest-begins"> + +<section id="what-did-you-do-this-week"> +<h2>What did you do this week?</h2> +<p>During this week, I initiated my work on the <code class="docutils literal notranslate"><span class="pre">FileDialog</span></code> PR, which had been started by Soham. The initial version of the <code class="docutils literal notranslate"><span class="pre">FileDialog</span></code> can be found at <a class="reference external" href="https://github.com/fury-gl/fury/pull/294">#294</a>. To start, I focused on rebasing the PR. Since this PR was based on an older version, there were some updates to the overall UI structure that needed to be addressed for compatibility. While handling this, I identified a set of issues that I documented in the current PR <a class="reference external" href="https://github.com/fury-gl/fury/pull/832">#832</a>. These mainly revolved around:</p> +<ol class="arabic simple"> +<li><p>Resizing <code class="docutils literal notranslate"><span class="pre">FileDialog</span></code> and related components.</p></li> +<li><p>Rectifying the text overflow problem.</p></li> +<li><p>Dealing with a <code class="docutils literal notranslate"><span class="pre">ZeroDivisionError</span></code>.</p></li> +<li><p>Fixing the positioning of items in the <code class="docutils literal notranslate"><span class="pre">ListBox2D</span></code>.</p></li> +</ol> +<p>I systematically approached each of these challenges:</p> +<p><strong>Resizing FileMenu and Related Components:</strong> This was a fairly complex task since it involved intricate dependencies, such as the <code class="docutils literal notranslate"><span class="pre">FileDialog</span></code> relying on the <code class="docutils literal notranslate"><span class="pre">FileMenu</span></code>, which, in turn, was dependent on <code class="docutils literal notranslate"><span class="pre">ListBox2D</span></code> and <code class="docutils literal notranslate"><span class="pre">Panel2D</span></code> resizing. To make the process manageable, I decided to progress incrementally in a separate PR a bit later.</p> +<p><strong>Text Overflow Issue:</strong> The problem with text overflow was rooted in our previous approach, which involved executing these actions only when the <code class="docutils literal notranslate"><span class="pre">TextBlock2D</span></code> had a scene property. Although this approach suited the previous version of <code class="docutils literal notranslate"><span class="pre">TextBlock2D</span></code>, the recent refactoring led to the removal of this property. The scene was previously utilized to determine the text actor’s size. However, we had new methodologies to calculate these sizes, which are detailed in <a class="reference external" href="https://github.com/fury-gl/fury/pull/803">#803</a>.</p> +<img alt="Text Overflow Before" class="align-center" src="https://github.com/fury-gl/fury/assets/64432063/b001f9d3-a5e8-45ad-8605-85df595b5654" /> +<img alt="Text Overflow After" class="align-center" src="https://github.com/fury-gl/fury/assets/64432063/d3c9c3a3-e601-45ab-8975-2b1e98acf1d3" /> +<p><strong>Addressing ZeroDivisionError:</strong> The <code class="docutils literal notranslate"><span class="pre">ZeroDivisionError</span></code> emerged when the total number of values was the same as the number of slots. The issue lay in the separation of these values for calculating the scrollbar’s height parameter. Unfortunately, this calculation error occurred when this would return us zero while updating the scrollbar. To counter this, I implemented a conditional check to ascertain whether the value is zero or not.</p> +<p><strong>Correcting ``ListBox2D`` Item Positioning:</strong> Another challenge I encountered related to the improper positioning of <code class="docutils literal notranslate"><span class="pre">ListBox2D</span></code> item’s background. When a slot was not visible, its background was resized to zero, and visibility was set to off. Consequently, during the calculation of updated positions, the height was considered zero, leading to mispositioning. I resolved this by refraining from resizing and solely toggling visibility, achieving the desired result.</p> +<img alt="ListBox2D mispositioning Before" class="align-center" src="https://github.com/fury-gl/fury/assets/64432063/e2805934-b037-47fd-872c-0b284b298d3c" /> +<img alt="Fixed ListBox2D mispositioning" class="align-center" src="https://github.com/fury-gl/fury/assets/64432063/3bc1aabb-bb79-4e26-817d-a2a2ddd20ea3" /> +</section> +<section id="did-you-get-stuck-anywhere"> +<h2>Did you get stuck anywhere?</h2> +<p>Among the challenges I faced, one notable instance involved addressing the visibility issue in <code class="docutils literal notranslate"><span class="pre">TreeUI</span></code>. Despite my attempts at various solutions, none yielded the desired outcome. The <code class="docutils literal notranslate"><span class="pre">TreeUI</span></code> exhibited either full visibility or no visibility at all. In this situation, I sought guidance from my mentor to find a viable solution.</p> +</section> +<section id="what-is-coming-up-next"> +<h2>What is coming up next?</h2> +<p>The <code class="docutils literal notranslate"><span class="pre">FileDialog</span></code> implementation is nearly finalized, and my plan is to work on any review, feedback or suggestions that might arise. Following this, I will shift my attention towards addressing the <code class="docutils literal notranslate"><span class="pre">TreeUI</span></code>.</p> +</section> +</section> + + + During this week, I initiated my work on the FileDialog PR, which had been started by Soham. The initial version of the FileDialog can be found at #294. To start, I focused on rebasing the PR. Since this PR was based on an older version, there were some updates to the overall UI structure that needed to be addressed for compatibility. While handling this, I identified a set of issues that I documented in the current PR #832. These mainly revolved around: + + 2023-08-19T00:00:00-04:00 + + + https://fury.gl/posts/2023/2023-08-16-week-11-tvcastillod.html + Week 11 : Adjusting ODF implementation and looking for solutions on issues found + 2023-08-16T00:00:00-04:00 + + Tania Castillo + + <section id="week-11-adjusting-odf-implementation-and-looking-for-solutions-on-issues-found"> + +<section id="what-did-i-do-this-week"> +<h2>What did I do this week?</h2> +<p>I continued to experiment with the ODF glyph implementation. Thanks to one of my mentors I figured out how to get the missing data corresponding to the SH coefficients <span class="math notranslate nohighlight">\(a^l_m\)</span> part of the function <span class="math notranslate nohighlight">\(f(\theta, \phi)\)</span> described <a class="reference external" href="https://dipy.org/documentation/1.7.0/theory/sh_basis/">here</a>. I also was told to make sure to implement the correct SH basis since there are different definitions from the literature, I have to focus now in the one proposed by Descoteaux, described in <a class="reference external" href="https://onlinelibrary.wiley.com/doi/10.1002/mrm.21277">this paper</a>, which is labeled in <em>dipy</em> as <em>descoteaux07</em>. To do this I had to make a small adjustment to the base implementation that I took as a reference, from which I obtained a first result using SH of order 4.</p> +<img alt="https://user-images.githubusercontent.com/31288525/260909561-fd90033c-018a-465b-bd16-3586bb31ca36.png" class="align-center" src="https://user-images.githubusercontent.com/31288525/260909561-fd90033c-018a-465b-bd16-3586bb31ca36.png" style="width: 600px;" /> +<p>It appears that the results on the shape are about the same, except for the direction, but there is still work to be done.</p> +</section> +<section id="what-is-coming-up-next"> +<h2>What is coming up next?</h2> +<p>For now, there are 3 things I will continue to work on:</p> +<ul> +<li><p>The color and lighting. As these objects present curvatures with quite a bit of detail in some cases, this is something that requires more specific lighting work, in addition to having now not only one color but a color map.</p></li> +<li><p>The scaling. This is something I still don’t know how to deal with. I had to adjust it manually for now, but the idea is to find a relationship between the coefficients and the final object size so it can be automatically scaled, or maybe there is a proper way to pre-process this data before passing it to the shaders to get the right result at once.</p></li> +<li><aside class="system-message"> +<p class="system-message-title">System Message: WARNING/2 (<span class="docutils literal">/Users/skoudoro/devel/fury/docs/source/posts/2023/2023-08-16-week-11-tvcastillod.rst</span>, line 2); <em><a href="#id1">backlink</a></em></p> +<p>Duplicate explicit target name: “here”.</p> +</aside> +<p>How to pass the information of the coefficients efficiently. Right now I’m creating one actor per glyph since I’m using a uniform array to pass the coefficients, but the idea is to pass all the data at once. I found several ideas <a class="reference external" href="https://stackoverflow.com/questions/7954927/passing-a-list-of-values-to-fragment-shader">here</a> of how to pass a list of values to the fragment shader directly, I just need to explore deeper how this can be done on <strong>FURY</strong>, and see which option is most suitable.</p> +</li> +</ul> +</section> +<section id="did-i-get-stuck-anywhere"> +<h2>Did I get stuck anywhere?</h2> +<p>All the points mentioned above are things that I tried to fix, however, it is something that I need to look at in much more detail and that I know is going to take me some time to understand and test before I get to the expected result. I hope to get some ideas from my mentors and fellow GSoC contributors on how I can proceed to deal with each of the problems.</p> +</section> +</section> + + + I continued to experiment with the ODF glyph implementation. Thanks to one of my mentors I figured out how to get the missing data corresponding to the SH coefficients a^l_m part of the function f(\theta, \phi) described here. I also was told to make sure to implement the correct SH basis since there are different definitions from the literature, I have to focus now in the one proposed by Descoteaux, described in this paper, which is labeled in dipy as descoteaux07. To do this I had to make a small adjustment to the base implementation that I took as a reference, from which I obtained a first result using SH of order 4. + + 2023-08-16T00:00:00-04:00 + + + https://fury.gl/posts/2023/2023-08-14-week-11-joaodellagli.html + Week 11: A Refactor is Sometimes Needed + 2023-08-14T00:00:00-04:00 + + João Victor Dell Agli Floriano + + <section id="week-11-a-refactor-is-sometimes-needed"> + +<p>Hello everyone, it’s time for another weekly blogpost! Today I am going to share some updates on the API refactoring +I was working on with my mentors.</p> +<section id="last-week-s-effort"> +<h2>Last Week’s Effort</h2> +<p>As I shared with you <span class="xref std std-doc">last week</span>, the first draft of my API was finally ready for review, as +I finished tweaking some remaining details missing. I was tasked with finding a good example of the usage of the tools we proposed, +and I started to do that, however after testing it with some examples, I figured out some significant bugs were to be fixed. Also, +after some reviews and hints from some of my mentors and other GSoC contributors, we realised that some refactoring should be done, +mainly focused on avoiding bad API usage from the user.</p> +</section> +<section id="so-how-did-it-go"> +<h2>So how did it go?</h2> +<p>Initially, I thought only one bug was the source of the issues the rendering presented, but it turned out to be two, which I will +explain further.</p> +<p>The first bug was related to scaling and misalignment of the KDE render. The render of the points being post-processed was not only +with sizes different from the original set size, but it was also misaligned, making it appear in positions different from the points’ +original ones. After some time spent, I figured out the bug was related to the texture coordinates I was using. Before, this is how +my fragment shader looked:</p> +<div class="highlight-C notranslate"><div class="highlight"><pre><span></span><span class="n">vec2</span><span class="w"> </span><span class="n">res_factor</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">vec2</span><span class="p">(</span><span class="n">res</span><span class="p">.</span><span class="n">y</span><span class="o">/</span><span class="n">res</span><span class="p">.</span><span class="n">x</span><span class="p">,</span><span class="w"> </span><span class="mf">1.0</span><span class="p">);</span> +<span class="n">vec2</span><span class="w"> </span><span class="n">tex_coords</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">res_factor</span><span class="o">*</span><span class="n">normalizedVertexMCVSOutput</span><span class="p">.</span><span class="n">xy</span><span class="o">*</span><span class="mf">0.5</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mf">0.5</span><span class="p">;</span> +<span class="kt">float</span><span class="w"> </span><span class="n">intensity</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">texture</span><span class="p">(</span><span class="n">screenTexture</span><span class="p">,</span><span class="w"> </span><span class="n">tex_coords</span><span class="p">).</span><span class="n">r</span><span class="p">;</span> +</pre></div> +</div> +<p>It turns out using this texture coordinates for <em>this case</em> was not the best choice, as even though it matches the fragment positions, +the idea here was to render the offscreen window, which has the same size as the onscreen one, to the billboard actor. With that in mind, +I realised the best choice was using texture coordinates that matched the whole screen positions, coordinates that were derived from the +<code class="docutils literal notranslate"><span class="pre">gl_FragCoord.xy</span></code>, being the division of that by the resolution of the screen, for normalization. Below, the change made:</p> +<div class="highlight-C notranslate"><div class="highlight"><pre><span></span><span class="n">vec2</span><span class="w"> </span><span class="n">tex_coords</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">gl_FragCoord</span><span class="p">.</span><span class="n">xy</span><span class="o">/</span><span class="n">res</span><span class="p">;</span> +<span class="kt">float</span><span class="w"> </span><span class="n">intensity</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">texture</span><span class="p">(</span><span class="n">screenTexture</span><span class="p">,</span><span class="w"> </span><span class="n">tex_coords</span><span class="p">).</span><span class="n">r</span><span class="p">;</span> +</pre></div> +</div> +<p>This change worked initially, although with some problems, that later revealed the resolution of the offscreen window needed to be +updated inside the callback function as well. Fixing that, it was perfectly aligned and scaled!</p> +<p>The second bug was related with the handling of the bandwidth, former sigma parameter. I realised I wasn’t dealing properly with the option of the user passing only +one single bandwidth value being passed, so when trying that, only the first point was being rendered. I also fixed that and it worked, +so cheers!</p> +<p>As I previously said, the bugs were not the only details I spent my time on last week. Being reviewed, the API design, even +though simple, showed itself vulnerable to bad usage from the user side, requiring some changes. The changes suggested by mentors were, +to, basically, take the <code class="docutils literal notranslate"><span class="pre">kde</span></code> method out of the <code class="docutils literal notranslate"><span class="pre">EffectManager</span></code> class, and create a new class from it inside an <code class="docutils literal notranslate"><span class="pre">effects</span></code> module, +like it was a special effects class. With this change, the KDE setup would go from:</p> +<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">em</span> <span class="o">=</span> <span class="n">EffectManager</span><span class="p">(</span><span class="n">show_manager</span><span class="p">)</span> + +<span class="n">kde_actor</span> <span class="o">=</span> <span class="n">em</span><span class="o">.</span><span class="n">kde</span><span class="p">(</span><span class="o">...</span><span class="p">)</span> + +<span class="n">show_manager</span><span class="o">.</span><span class="n">scene</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">kde_actor</span><span class="p">)</span> +</pre></div> +</div> +<p>To:</p> +<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">em</span> <span class="o">=</span> <span class="n">EffectManager</span><span class="p">(</span><span class="n">show_manager</span><span class="p">)</span> + +<span class="n">kde_effect</span> <span class="o">=</span> <span class="n">KDE</span><span class="p">(</span><span class="o">...</span><span class="p">)</span> + +<span class="n">em</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">kde_effect</span><span class="p">)</span> +</pre></div> +</div> +<p>Not a gain in line shortening, however, a gain in security, as preventing users from misusing the kde_actor. Something worth noting is +that I learned how to use the <code class="docutils literal notranslate"><span class="pre">functools.partial</span></code> function, that allowed me to partially call the callback function with only some +parameters passed.</p> +</section> +<section id="this-week-s-goals"> +<h2>This Week’s Goals</h2> +<p>Having that refactoring made, now I am awaiting for a second review so we could finally wrap it up and merge the first stage of this API. +With that being done, I will write the final report and wrap this all up.</p> +<p>Let’s get to work!</p> +</section> +</section> + + + Hello everyone, it’s time for another weekly blogpost! Today I am going to share some updates on the API refactoring +I was working on with my mentors. + + 2023-08-14T00:00:00-04:00 + + + https://fury.gl/posts/2023/2023-08-12-week-11-praneeth.html + Week 11: Bye Bye SpinBox + 2023-08-12T00:00:00-04:00 + + Praneeth Shetty + + <section id="week-11-bye-bye-spinbox"> + +<section id="what-did-you-do-this-week"> +<h2>What did you do this week?</h2> +<p>Building upon the progress of the previous week, a major milestone was reached with the merging of PR <a class="reference external" href="https://github.com/fury-gl/fury/pull/830">#830</a>. This PR added essential “getters” and “setters” for the new features of <code class="docutils literal notranslate"><span class="pre">TextBlock</span></code>, making it easier to handle changes. This, in turn, facilitated the integration of <code class="docutils literal notranslate"><span class="pre">SpinBoxUI</span></code> with the updated <code class="docutils literal notranslate"><span class="pre">TextBlock</span></code>.</p> +<p>However, while working on <code class="docutils literal notranslate"><span class="pre">SpinBoxUI</span></code>, a critical issue emerged. As <code class="docutils literal notranslate"><span class="pre">SpinBoxUI</span></code> allows users to input characters and symbols into an editable textbox, it posed a risk of program crashes due to invalid inputs. To counter this, I introduced a validation check to ensure that the input was a valid number. If valid, the input was converted; otherwise, it reverted to the previous value. After thorough testing and review, PR <a class="reference external" href="https://github.com/fury-gl/fury/pull/499">#499</a> was successfully merged.</p> +<img alt="SpinBoxUI" class="align-center" src="https://user-images.githubusercontent.com/64432063/261409747-511e535b-185c-4e70-aaa8-5296c93e5344.gif" style="width: 500px;" /> +<p>Meanwhile, a concern with the textbox’s behavior was identified when <code class="docutils literal notranslate"><span class="pre">SpinBoxUI</span></code> was scaled to a larger size. Specifically, the text occasionally touched the top or bottom boundary, creating an overflow appearance. Although initial solutions were attempted, the complexity of the issue required further consideration. This issue has been documented in more detail in Issue <a class="reference external" href="https://github.com/fury-gl/fury/pull/838">#838</a>, where it is marked as a low-priority item.</p> +<figure class="align-center"> +<img alt="TextBlock2D text positioning issue" src="https://user-images.githubusercontent.com/64432063/133194003-53e2dac6-31e0-444e-b7f1-a9e71545f560.jpeg" /> +</figure> +</section> +<section id="did-you-get-stuck-anywhere"> +<h2>Did you get stuck anywhere?</h2> +<p>The challenge of the week centered around addressing the textbox’s overflow behavior in <code class="docutils literal notranslate"><span class="pre">SpinBoxUI</span></code>.</p> +</section> +<section id="what-is-coming-up-next"> +<h2>What is coming up next?</h2> +<p>Looking ahead, the focus remains on refining the FileDialog component, as the significant progress with <code class="docutils literal notranslate"><span class="pre">TextBlock</span></code> and <code class="docutils literal notranslate"><span class="pre">SpinBoxUI</span></code> prepares us to shift attention to other aspects of development.</p> +</section> +</section> + + + Building upon the progress of the previous week, a major milestone was reached with the merging of PR #830. This PR added essential “getters” and “setters” for the new features of TextBlock, making it easier to handle changes. This, in turn, facilitated the integration of SpinBoxUI with the updated TextBlock. + + 2023-08-12T00:00:00-04:00 + + + https://fury.gl/posts/2023/2023-08-08-week-10-tvcastillod.html + Week 10 : Start of SH implementation experiments + 2023-08-08T00:00:00-04:00 + + Tania Castillo + + <section id="week-10-start-of-sh-implementation-experiments"> + +<section id="what-did-i-do-this-week"> +<h2>What did I do this week?</h2> +<p>I started formally working on SH implementation. I was told to start first doing a simple program where I can modify in real-time the order <span class="math notranslate nohighlight">\(l\)</span> and degree <span class="math notranslate nohighlight">\(m\)</span>, parameters corresponding to the <a class="reference external" href="https://dipy.org/documentation/1.7.0/theory/sh_basis/">Spherical Harmonics function</a> <span class="math notranslate nohighlight">\(Y^m_l(\theta,\phi)=\)</span>, based on <a class="reference external" href="https://github.com/lenixlobo/fury/commit/2b7ce7a71fd422dc5a250d7b49e1eea2db9d3bce">previous work</a>. That is just one part of the final ODF calculation, but here is what a first experimental script looks like.</p> +<img alt="https://user-images.githubusercontent.com/31288525/260910073-10b0edd4-40e3-495c-85ad-79993aef3b19.png" class="align-center" src="https://user-images.githubusercontent.com/31288525/260910073-10b0edd4-40e3-495c-85ad-79993aef3b19.png" style="width: 600px;" /> +<p>I did it in order to make sure it was visually correct and also to understand better how those 2 parameters are related and need to be incorporated into the final calculation. There is one issue at first sight that needs to be addressed, and that is the scaling, since for SH with a degree near 0, the object gets out of bounds.</p> +</section> +<section id="what-is-coming-up-next"> +<h2>What is coming up next?</h2> +<p>I will keep polishing details from my current open PRs, hopefully, I will get another PR merged before the last GSoC week.</p> +</section> +<section id="did-i-get-stuck-anywhere"> +<h2>Did I get stuck anywhere?</h2> +<p>Not sure about how to use the current implementation I have to get similar visualizations made with <em>odf_slicer</em>, since the parameters that the function receive are different, so I need to take a deeper look and see where it might be the connection or if I should make some adjustments on the parameters.</p> +</section> +</section> + + + I started formally working on SH implementation. I was told to start first doing a simple program where I can modify in real-time the order l and degree m, parameters corresponding to the Spherical Harmonics function Y^m_l(\theta,\phi)=, based on previous work. That is just one part of the final ODF calculation, but here is what a first experimental script looks like. + + 2023-08-08T00:00:00-04:00 + + diff --git a/v0.10.x/blog/tag/shader.html b/v0.10.x/blog/tag/shader.html new file mode 100644 index 000000000..38fbf1ff6 --- /dev/null +++ b/v0.10.x/blog/tag/shader.html @@ -0,0 +1,537 @@ + + + + + + + Posts tagged shader — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + + + + + +
+ +
+
+
+ +
+ + + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/blog/tag/shader/atom.xml b/v0.10.x/blog/tag/shader/atom.xml new file mode 100644 index 000000000..ad3f02451 --- /dev/null +++ b/v0.10.x/blog/tag/shader/atom.xml @@ -0,0 +1,28 @@ + + + https://fury.gl/ + Blog - Posts tagged shader + 2024-02-29T15:43:57.833923+00:00 + + + ABlog + + https://fury.gl/posts/2019/2019-06-19-brain-art.html + Success on Brain Art Competition using FURY + 2019-06-19T00:00:00-04:00 + + Serge Koudoro + + <section id="success-on-brain-art-competition-using-fury"> + +<p>Congratulations to <a class="reference external" href="https://github.com/dmreagan">David</a> who won the <a class="reference external" href="https://www.neurobureau.org/galleries/brain-art-competition-2019-2/">OHBM BrainArt (MELPOMENE category)</a> by using DIPY and FURY!!!</p> +<p>As you can see below, really beautiful streamlines effect created during shader experiment/fail!</p> +<img alt="Brain Streamlines Shader Experiment" class="align-center" src="https://fury.gl/_images/Melpomene_Brain-Streamlines-shader-experiment_by_David-Reagan.jpg" /> +</section> + + + Congratulations to David who won the OHBM BrainArt (MELPOMENE category) by using DIPY and FURY!!! + + 2019-06-19T00:00:00-04:00 + + diff --git a/v0.10.x/community.html b/v0.10.x/community.html new file mode 100644 index 000000000..f94d15ca8 --- /dev/null +++ b/v0.10.x/community.html @@ -0,0 +1,558 @@ + + + + + + + + Community — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Community#

+
+

Join Us!#

+
+
+

Contributors#

+
+
+
+
+
+
+ +
+ Stars + +
+
+
+
+
+ +
+ 157 Forks + +
+
+
+
+
+ +
+ 0 Contributors + +
+
+
+
+
+ +
+ 0 Commits + +
+
+
+
+ +
+
+
+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ +
+ On this page +
+ +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/fury-pybullet.html b/v0.10.x/fury-pybullet.html new file mode 100644 index 000000000..7d0dd6472 --- /dev/null +++ b/v0.10.x/fury-pybullet.html @@ -0,0 +1,1192 @@ + + + + + + + + FURY - pyBullet Integration Guide — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

FURY - pyBullet Integration Guide#

+ +
+
Official docs:
+
+
+
+

Note

+

All elements are in SI units.

+
+
+

Simple Rigid Body Dynamics#

+
+

Necessary Imports#

+

The following imports are necessary for physics simulations:

+ + + + + + + + + + + + + + + + + + + + +

Imports

Usage

Numpy

Creation of arrays and conversion of radians to degrees.

FURY

Window and Actor API is used to visualize the simulation.

pyBullet

Physics simulation.

Itertools

The Counter iterator for keeping track of simulation steps.

+
import numpy as np
+from fury import window, actor
+import itertools
+import pybullet as p
+
+
+
+
+

Connection Mode#

+

“After importing the PyBullet module, the first thing to do is ‘connecting’ to the physics simulation. PyBullet is designed around a client-server driven API, with a client sending commands and a physics server returning the status. PyBullet has some built-in physics servers: DIRECT and GUI.”

+

In our case we use DIRECT connection as the visualization will be handled by FURY.

+
client = p.connect(p.DIRECT)
+
+
+
+

Note

+

Keeping track of physics client ID is optional unless multiple physics clients are used. In order to observe the same simulation in pybullet, replace p.DIRECT with p.GUI.

+
+
+
+

Disconnection#

+

PyBullet Physics client can be shutdown by the following command:

+
p.disconnect()
+
+
+
+
+

Setting Gravity#

+

Global Scene() gravity can be set using the following command:

+
# Gravity vector.
+gravity_x = 0
+gravity_y = 0
+gravity_z = -10
+p.setGravity(gravity_x, gravity_y, gravity_z)
+
+
+
+
+

Creating Objects#

+

The following criterion must be fulfilled in order to create an object which is in sync with both FURY and pyBullet:

+ + + + + + + + + + + + +

Object Actor

The actor which will be rendered by FURY

Collision Shape

The shape used by pybullet for collision simulations. +Optional if collision simulation is not required.

Multi-Body

The object that will be tracked by pybullet for general simulations.

+

The following is a snippet for creating a spherical ball of radius = 0.3

+
###### Creating BALL
+# Ball actor
+ball_actor = actor.sphere(centers = np.array([[0, 0, 0]]),
+                          colors=np.array([1,0,0]),
+                          radii=0.3)
+
+# Collision shape for the ball.
+ball_coll = p.createCollisionShape(p.GEOM_SPHERE,
+                                   radius=0.3)
+
+# Creating a Multibody which will be tracked by pybullet.
+ball = p.createMultiBody(baseMass=3,
+                         baseCollisionShapeIndex=ball_coll,
+                         basePosition=[2, 0, 1.5],
+                         baseOrientation=[ 0, 0, 0, 1 ])
+
+
+
+

Warning

+

Centers for the actor must be set to (0, 0, 0) or else the simulation will be offset by that particular value.

+
+
+
+

Changing Object Dynamics#

+

Object dynamics such as mass, lateral_friction, damping, inertial_pos, inertial_orn, restitution, rolling friction etc can be changed. The following snippet shows how to change the lateral_friction and coeff of restitution of the same ball:

+
p.changeDynamics(ball, -1, lateralFriction=0.3, restitution=0.5)
+
+
+
+

Note

+

The second parameter is linkIndex which is for bodies having multiple links or joints. Passing -1 means applying changes to the base object.

+
+
+
+

Adding objects to the scene#

+

Objects can be added simply by adding their respective actors to the scene.

+
scene = window.Scene()
+scene.add(ball_actor)
+
+
+
+
+

Application of Force/Torque#

+

External force or torque to a body can be applied using applyExternalForce and applyExternalTorque. For e.g

+
p.applyExternalForce(ball, -1,
+                     forceObj=[-2000, 0, 0],
+                     posObj=ball_pos,
+                     flags=p.WORLD_FRAME)
+
+
+

Here, the first argument refers to the object, the second one refers to the link, forceObj = force vector, posObj = Position Vector of the application of force. [Not applicable for applyExternalTorque].

+
p.applyExternalTorque(ball, -1,
+                     forceObj=[-2000, 0, 0],
+                     flags=p.WORLD_FRAME)
+
+
+
+
+

Enabling collision#

+

By default, collision detection is enabled between different dynamic moving bodies. The following snippet can be used to enable/disable collision explicitly between a pair of objects.

+
enableCol = 1
+p.setCollisionFilterPair(ball, brick, -1, -1, enableCol)
+
+
+

Here, we enable the collision between a ball and a brick object.

+
+
+

Creation of Show Manager#

+

A window.ShowManager and itertools.count instance must be created before defining the timer callback function and setting it to initialize.

+
# Create a show manager.
+showm = window.ShowManager(scene,
+                        size=(900, 768), reset_camera=False,
+                        order_transparent=True)
+showm.initialize()
+# Counter iterator for tracking simulation steps.
+counter = itertools.count()
+
+
+
+
+

Syncing properties of actors#

+

The position and orientation of the actors in FURY can be updated by the values generated in pybullet during simulation. The following snippet updates all required parameters.

+
# Get the position and orientation of the ball.
+ball_pos, ball_orn = p.getBasePositionAndOrientation(ball)
+
+# Set position and orientation of the ball.
+ball_actor.SetPosition(*ball_pos)
+orn_deg = np.degrees(p.getEulerFromQuaternion(ball_orn))
+ball_actor.SetOrientation(*orn_deg)
+
+
+

ball and ball_actor can be replaced by the appropriate object and actor.

+
+
+

Creation of Timer Callback#

+

To simulate physics we need to call p.stepSimulation() in order to simulate a single step of physics simulation. Therefore, in order to update actors and simulate steps at each interval, we need to create a timer callback. At this point one can perform any operation that they feel like during each step of the simulation. This is also the appropriate section for the user to define all syncing activities required by the actors and render the scene accordingly. The following can be an example snippet:

+
# Counter iterator for tracking simulation steps.
+counter = itertools.count()
+
+# Variable for tracking applied force.
+apply_force = True
+
+# Create a timer callback which will execute at each step of simulation.
+def timer_callback(_obj, _event):
+    global apply_force
+    cnt = next(counter)
+    showm.render()
+    # Get the position and orientation of the ball.
+    ball_pos, ball_orn = p.getBasePositionAndOrientation(ball)
+
+    # Apply force for 5 times for the first step of simulation.
+    if apply_force:
+        # Apply the force.
+        p.applyExternalForce(ball, -1,
+                              forceObj=[-2000, 0, 0],
+                              posObj=ball_pos,
+                              flags=p.WORLD_FRAME)
+        apply_force = False
+
+    # Set position and orientation of the ball.
+    ball_actor.SetPosition(*ball_pos)
+    orn_deg = np.degrees(p.getEulerFromQuaternion(ball_orn))
+    ball_actor.SetOrientation(*orn_deg)
+    ball_actor.RotateWXYZ(*ball_orn)
+
+    # Simulate a step.
+    p.stepSimulation()
+
+    # Exit after 2000 steps of simulation.
+    if cnt == 2000:
+        showm.exit()
+
+# Add the timer callback to showmanager.
+# Increasing the duration value will slow down the simulation.
+showm.add_timer_callback(True, 10, timer_callback)
+
+
+
+
+

Initiating the simulation#

+

Once everything is set up, one can execute showm.start() to start the simulation.

+
+
+

Rendering multiple objects by a single actor#

+

Rendering multiple similar objects by a single actor is possible by manually updating the vertices of the individual objects. The said procedure will be demonstrated with the help of the brick wall simulation example where each brick is rendered by a single actor. +Firstly, we need to define the following parameters:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Variable

Shape

Description

nb_objects

1, 1

Number of objects to be rendered

object_centers

nb_objects, 3

To keep track of the centers in the xyz coordinate system. [x, y, z]

object_directions

nb_objects, 3

Array to track directions.

object_orientations

nb_objects, 4

Array to track orientations in quaternions. [x, y, z, w]

object_colors

nb_bricks, 3

Array to track colors.

object_collision

1, 1

Collision shape of the objects.

+
+

Warning

+

object_directions & object_orientations must be updated together or else orientation of objects in both the worlds may not be in sync.

+
+

Once we are ready with the above variables and array, we can proceed further to render the objects both in the FURY and pybullet world:

+
+

Rendering objects in FURY#

+

To render objects in the FURY world we simply call the respective actors. For this example we call actor.box for rendering the bricks:

+
brick_actor_single = actor.box(centers=brick_centers,
+                            directions=brick_directions,
+                            scales=brick_sizes,
+                            colors=brick_colors)
+
+scene.add(brick_actor_single)
+
+
+
+
+

Render Pybullet Objects#

+

Now to render pybullet objects we simply create a list of multibodies:

+
bricks[i] = p.createMultiBody(baseMass=0.5,
+                              baseCollisionShapeIndex=brick_coll,
+                              basePosition=center_pos,
+                              baseOrientation=brick_orn)
+
+
+
+
+

Syncing objects#

+

Now in order to calculate and the vertices we execute the following snippet:

+
vertices = utils.vertices_from_actor(brick_actor_single)
+num_vertices = vertices.shape[0]
+num_objects = brick_centers.shape[0]
+sec = int(num_vertices / num_objects)
+
+
+ + + + + + + + + + + + + + + + + +

Vertices

Array storing vertices of all the objects.

num_vertices

Number of vertices required to render the objects.

num_objects

Number of objects rendered

sec

Number of vertices required to render a single object.

+

Now the pybullet and FURY objects can be synced together by the following snippet:

+
def sync_brick(object_index, multibody):
+  pos, orn = p.getBasePositionAndOrientation(multibody)
+
+  rot_mat = np.reshape(
+      p.getMatrixFromQuaternion(
+          p.getDifferenceQuaternion(orn, brick_orns[object_index])),
+      (3, 3))
+
+  vertices[object_index * sec: object_index * sec + sec] = \
+      (vertices[object_index * sec: object_index * sec + sec] -
+      brick_centers[object_index])@rot_mat + pos
+
+  brick_centers[object_index] = pos
+  brick_orns[object_index] = orn
+
+
+

In order to Sync correctly, we do the following:

+
    +
  1. First we get the current position and orientation of the objects in the pybullet world with the help of p.getBasePositionAndOrientation.

  2. +
  3. Then we calculate the difference between two quaternions using p.getDifferenceFromQuarternion.

  4. +
  5. The said difference is then passed to p.getMatrixFromQuaternion to calculate the rotation matrix.

  6. +
  7. Now the method returns a tuple of size 9. Therefore we finally need to reshape the said tuple into a 3x3 matrix with the help of np.reshape.

  8. +
  9. Next, we slice the necessary part of the vertices which render our desired object.

  10. +
  11. Then we bring it back to the origin by subtracting their centers.

  12. +
  13. After that we perform matrix multiplication of the rotation matrix and the vertices to orient the object.

  14. +
  15. After orientation we bring the object to its new position.

  16. +
  17. Finally we update the centers and the orientation of the object.

  18. +
+

Lastly, we call this function in our timer callback to sync the objects correctly.

+
+

Note

+

VTK has an in-built method to handle gimbal locks therefore using actor.SetOrientation may lead to unwanted spinning simulations each time a gimbal lock is experienced. Hence, it is always advisable to use vertices and its corresponding rotation matrix to set the orientation.

+
+
+
+
+

Rendering Joints#

+https://raw.githubusercontent.com/fury-gl/fury-communication-assets/main/physics_joints.png +

A simulated robot as described in a URDF file has a base, and optionally links connected by joints. Each joint connects one parent link to a child link. At the root of the hierarchy there is a single root parent that we call base. The base can be either fully fixed, 0 degrees of freedom, or fully free, with 6 degrees of freedom. Since each link is connected to a parent with a single joint, the number of joints is equal to the number of links. Regular links have link indices in the range [0..getNumJoints()] Since the base is not a regular ‘link’, we use the convention of -1 as its link index. We use the convention that joint frames are expressed relative to the parent center of mass inertial frame, which is aligned with the principal axis of inertia. To know more how joints are implemented in pybullet refer the official docs.

+

We can create and sync joints in pybullet and FURY by following a few simple steps:

+

Firstly, in order to create objects with multiple joints we need to keep track of the following parameters:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Vertices

Shape

Description

nb_links

1,1

Number of links to be rendered.

link_masses

nb_links

Masses of the links.

linkCollisionShapeIndices

nb_links

Array tracking the collision shape IDs.

linkVisualShapeIndices

nb_links

Optional as we won’t be using +pybullet’s GUI render.

linkPositions

nb_links, 3

Position of the links in [x, y, z].

linkOrientations

nb_links, 4

Orientation of the links in +[x, y, z, w].

linkInertialFramePositions

nb_links, 3

Position of the inertial frame of the +links.

linkInertialFrameOrns

nb_links, 4

Orientation of the inertial frame of +the links.

indices

nb_link

Link ID each corresponding link is +supposed to attach at.

jointTypes

nb_link

The type of joint between the links. +Multiple joint types are available.

axis

nb_links, 3

The axis at which each link is supposed +to rotate.

linkDirections

nb_links, 3

Direction vector required to render +links in FURY.

+

Extra Arrays such as linkHeights, linkRadii etc may be required based on the link shape. +Base link is rendered separately, hence the above parameters should not contain information about the base link.

+

Now separately create definitions for the base link using the following parameters. Once we are ready with the required link parameters and definition, we can create a multibody to be rendered in the pybullet world. We can do so using p.createMultiBody. Here’s a snippet:

+
rope = p.createMultiBody(base_mass,
+                         base_shape,
+                         visualShapeId,
+                         basePosition,
+                         baseOrientation,
+                         linkMasses=link_Masses,
+                        linkCollisionShapeIndices=linkCollisionShapeIndices,
+                         linkVisualShapeIndices=linkVisualShapeIndices,
+                         linkPositions=linkPositions,
+                         linkOrientations=linkOrientations,
+                        linkInertialFramePositions=linkInertialFramePositions,
+                          linkInertialFrameOrientations=linkInertialFrameOrns,
+                         linkParentIndices=indices,
+                         linkJointTypes=jointTypes,
+                         linkJointAxis=axis)
+
+
+

Once we are done with the multibody we can create the actor to render the links:

+
rope_actor = actor.cylinder(centers=linkPositions,
+                      directions=linkDirections,
+                      colors=np.random.rand(n_links, 3),
+                      radius=radii,
+                      heights=link_heights, capped=True)
+
+
+

We can sync the joints using the following code snippet:

+
def sync_joints(actor_list, multibody):
+  for joint in range(p.getNumJoints(multibody)):
+      pos, orn = p.getLinkState(multibody, joint)[4:6]
+
+      rot_mat = np.reshape(
+              p.getMatrixFromQuaternion(
+              p.getDifferenceQuaternion(orn, linkOrientations[joint])),
+              (3, 3))
+
+      vertices[joint * sec: joint * sec + sec] =\
+              (vertices[joint * sec: joint * sec + sec] -
+              linkPositions[joint])@rot_mat + pos
+
+      linkPositions[joint] = pos
+      linkOrientations[joint] = orn
+
+
+

Here, we determine the total number of joints using p.getNumJoints and run a loop to iterate through all the joints present within the object. Once we get access to a particular joint we use the p.getLinkState to get various information about a particular joint. Within the list of information we have access to positions and orientation of the joints at index 4 and 5. So we perform the query to get the position and orientation of the joints. After that the process of translation and rotation are the same as shown here.

+
+
+
+
+

Examples#

+
+

Brick Wall Simulation#

+https://raw.githubusercontent.com/fury-gl/fury-communication-assets/main/physics_bricks_multi_actor.gif +

The code for the above simulation can be found here.

+
+
+

Ball Collision Simulation#

+https://raw.githubusercontent.com/fury-gl/fury-communication-assets/main/physics_collision.gif +

The code for the above simulation can be found here.

+
+
+

Brick Wall Simulation(Single Actor)#

+https://raw.githubusercontent.com/fury-gl/fury-communication-assets/main/physics_bricks_fast.gif +

The code for the above simulation can be found here.

+
+
+

Chain Simulation#

+https://raw.githubusercontent.com/fury-gl/fury-communication-assets/main/physics_chain.gif +

The code for the above simulation can be found here.

+
+
+

Wrecking Ball Simulation#

+https://raw.githubusercontent.com/fury-gl/fury-communication-assets/main/physics_wrecking_ball.gif +

The code for the above simulation can be found here.

+
+
+

Domino Simulation#

+https://raw.githubusercontent.com/fury-gl/fury-communication-assets/main/physics_domino.gif +

The code for the above simulation can be found here.

+
+
+
+ +
+ + +
+ +
+ + + + + +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/genindex.html b/v0.10.x/genindex.html new file mode 100644 index 000000000..cf297d6bd --- /dev/null +++ b/v0.10.x/genindex.html @@ -0,0 +1,3622 @@ + + + + + + + Index — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +

Index

+ +
+ _ + | A + | B + | C + | D + | E + | F + | G + | H + | I + | J + | K + | L + | M + | N + | O + | P + | R + | S + | T + | U + | V + | W + | X + | Y + | Z + +
+

_

+ + + +
+ +

A

+ + + +
+ +

B

+ + + +
+ +

C

+ + + +
+ +

D

+ + + +
+ +

E

+ + + +
+ +

F

+ + + +
+ +

G

+ + + +
+ +

H

+ + + +
+ +

I

+ + + +
+ +

J

+ + + +
+ +

K

+ + + +
+ +

L

+ + + +
+ +

M

+ + + +
+ +

N

+ + + +
+ +

O

+ + + +
+ +

P

+ + + +
+ +

R

+ + + +
+ +

S

+ + + +
+ +

T

+ + + +
+ +

U

+ + + +
+ +

V

+ + + +
+ +

W

+ + + +
+ +

X

+ + + +
+ +

Y

+ + + +
+ +

Z

+ + + +
+ + + +
+ + + +
+ +
+
+
+ +
+ + + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/getting_started.html b/v0.10.x/getting_started.html new file mode 100644 index 000000000..bf3d7186d --- /dev/null +++ b/v0.10.x/getting_started.html @@ -0,0 +1,554 @@ + + + + + + + + Getting Started — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Getting Started#

+

Start by importing FURY.

+
import numpy as np
+from fury import window, actor, ui, io, utils
+
+
+

To import a model, use io.load_polydata(). Currently supported formats include OBJ, VTK, FIB, PLY, STL and XML.

+

Here we are going to use suzanne model used by Blender. You can find more detail about what is suzanne model here.

+

We can download the model by

+
from fury.data import fetch_viz_models
+fetch_viz_models()
+
+
+

The models will be downloaded in ~/.fury/models directory.

+

If you store the return value to models, you can find the detailed information about models in the dictionary. The directory of the suzanne model will be in models[1].

+
models = fetch_viz_models()
+print(models[1])
+
+
+

To get the path of suzanne

+
import os
+path_suzanne = os.path.join(models[1], 'suzanne.obj')
+print(path_suzanne)
+
+
+

Now we can include the suzanne model used by Blender:

+
suzanne = io.load_polydata(path_suzanne)
+suzanne = utils.get_polymapper_from_polydata(suzanne)
+suzanne = utils.get_actor_from_polymapper(suzanne)
+
+
+

Set the opacity of the model:

+
suzanne.GetProperty().SetOpacity(0.5)
+
+
+

Let’s create some random variables for the cylinder parameters

+
centers = np.random.rand(2, 3)
+directions = np.random.rand(2, 3)
+heights = np.random.rand(2)
+colors = np.random.rand(2, 3)
+
+
+

Now, we create a cylinder:

+
cylinders = actor.cylinder(centers, directions, colors, heights=heights)
+
+
+

Anything that has to be rendered needs to be added to the scene so let’s create a Scene():

+
scene = window.Scene()
+
+
+

We set the window scene variables e.g. (width, height):

+
showm = window.ShowManager(scene, size=(1024,720), reset_camera=False)
+showm.initialize()
+
+
+

We add a text block to add some information:

+
tb = ui.TextBlock2D(position=(450, 550), font_size=23)
+tb.message = "Hello Fury"
+
+
+

The function Scene.add() is used to add the created objects to the scene to be rendered:

+
scene.add(suzanne)
+scene.add(cylinders)
+scene.add(tb)
+
+
+

Start the rendering of the scene:

+
showm.start()
+
+
+suzanne fury +
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/index.html b/v0.10.x/index.html new file mode 100644 index 000000000..300ab2e05 --- /dev/null +++ b/v0.10.x/index.html @@ -0,0 +1,836 @@ + + + + + + + + + FURY + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ +

fury

+
+
+ +
+ A free and open-source software library for Scientific Visualization and 3D animations. Learn how to use the rendering equation + \begin{equation} + L_o\left( x, \omega_o\right) = L_e\left( x, \omega_o\right) + \int_{\Omega} L_i\left( x, \omega_i\right) f_r\left(\omega_i, x, \omega_o\right) \left(\omega_i\cdot n\right) d\omega_i + \end{equation} + and other powerful techniques to create the most advanced effects and give new life to your data. +
+ + + + +
+
+
+
+
+ + + + + + + + + + + + + +
+ +
+
+
+
+ +
    +
  • +
    +
    +
    +
    + +

    Engineering

    +
    + + Engineering + +
    +
    +
    + +

    Physics

    +
    + + Physics + +
    +
    +
    + +

    Chemistry

    +
    + + Chemistry + +
    +
    +
    + +

    Astronomy

    +
    + + Chemistry + +
    +
    +
    + +

    Aerospace

    +
    + + Aerospace + +
    +
    +
    + +

    Biology

    +
    + + Biology + +
    +
    +
    + +

    Data Science

    +
    + + Data Science + +
    +
    +
    + +

    Network Science

    +
    + + Network Science + +
    +
    +
    + +

    Mathematics

    +
    + + Mathematics + +
    +
    +
    +
    +
    +
    + +
    +
    +
    + +

    Engineering

    +
    +

    FURY is a powerful tool for engineers and visualisation experts. It allows them to create high-quality visualisations quickly and easily, without the need for extensive programming knowledge. Its functional programming paradigm and support for large data sets make it an ideal tool for visualising complex systems and data, such as those used in engineering and scientific research. +

    + + + View More + + + +
    +
    +
    +
    + +
    +
    +
    + +

    Physics

    +
    + +

    FURY's ability to create stunning visualisations of complex physical phenomena. For example, FURY can be used to create detailed visualisations of fluid dynamics, such as the flow of water or gas. It can also be used to visualise the motion of particles in a simulation. +

    + + + View More + + + +
    +
    +
    +
    + +
    + +
    +
    + +

    Chemistry

    +
    +

    FURY can be used to create detailed visualisations of the structure of molecules, including their bonding and interactions. It can also be used to visualise the motion of atoms and molecules in a simulation, such as the motion of atoms and molecules in a material. +

    + + + View More + + + +
    +
    +
    +
    + +
    + +
    +
    + +

    Astronomy

    +
    +

    FURY can be used to create detailed visualisations of the structure of galaxies, including the distribution of stars, gas, and dust. It can also be used to visualise the motion of celestial bodies in a simulation, such as the motion of stars and planets in a solar system. +

    + + + View More + + + +
    +
    +
    +
    + +
    + +
    +
    + +

    Aerospace

    +
    +

    FURY can easily create 3D visualizations of aerodynamic simulations, which can help engineers understand the performance of an aircraft in different flight conditions. This can be done by importing the simulation data into FURY and then using the library's built-in functions to create 3D models of the aircraft, along with visualizations of the airflow patterns and other important parameters. +

    + + + View More + + + +
    +
    +
    +
    + +
    + +
    +
    + +

    Biology

    +
    +

    With FURY, researchers can create detailed models of cells and organelles, such as the mitochondria, ribosomes, and endoplasmic reticulum. This allows for a more in-depth understanding of the structure and function of these important cellular components. +

    + + + View More + + + +
    +
    +
    +
    + +
    + +
    +
    + +

    Data Science

    +
    +

    One of the key features of FURY is its ability to handle large amounts of data. This makes it perfect for data scientists who need to work with large datasets, as well as for visualizers who need to create interactive and engaging visualizations. +

    + + + View More + + + +
    +
    +
    +
    + +
    + +
    +
    + +

    Network Science

    +
    +

    One of the key features of FURY is its ability to handle large and complex networks. It can handle millions of nodes and edges, and can display the network in a variety of different ways, including node-link diagrams, matrix plots, and force-directed layouts. This allows users to explore their networks in a variety of different ways, and to find the best way to visualize their data. +

    + + + View More + + + +
    +
    +
    +
    + +
    + +
    +
    + +

    Mathematics

    +
    +

    FURY allows users to easily visualise complex mathematical data in a way that is easy to understand. For example, a mathematician studying a complex equation could use FURY to create a 3D plot of the equation's solutions, which would make it much easier to understand the behaviour of the equation. +

    + + + View More + + + +
    +
    +
    +
  • +
  • +
    With FURY, it becomes simple to produce multiple physics animations with ease.
    +
    +
    +
    + physics domino + +
    +
    + physics bricks + +
    +
    + physic collision + +
    +
    + brownian motion + +
    +
    + Em wave + +
    +
    + Helical path + +
    +
    +
    +
  • +
  • +
    +

    Some Molecular Dynamics applications using FURY.

    +
    +
    +
    +
    +
    + fullrene Modellin +
    +
    + Molecular Ribbon +
    +
    + Molecular Surface +
    +
    +
    +
  • +
  • +
    +

    Built with FURY: Neuroscience application examples

    +
    +
    +
    +
    +
    + Brain bundle +
    +
    + Brain bundle +
    +
    + Brain bundle +
    +
    + Brain bundle +
    +
    + Brain bundle +
    +
    + Brain bundle +
    +
    +
    +
    +
  • +
  • +
    +
    +

    +

    Releases
    +
    FURY is a Python library available for scientific + visualization. The library is available via PyPi or Anaconda package system
    +

    +
    +
    +

    +

    Free
    +
    FURY is totally free and it will be always free
    +

    +
    +
    +

    +

    Community
    +
    Join FURY family here and share your knowledge
    +

    +
    +
    +

    +

    Easy to Use
    +
    FURY is designed to be really easy to use
    +

    +
    +
    +
  • +
+
+
+
+ + + + + + + + +
+
+

+ Compatibility +

+
+
+
+
+ +
+
+
+
+ +
+
+
+
+ +
+
+
+
+ +
+
+
+
+
+
+ +
+
+
+
+ +
+
+
+
+ +
+
+
+
+
+ +
+

+ Our Sponsors +

+
+ + + +
+ +
+

+ Cite Us! +

+
+

Eleftherios Garyfallidis, Serge Koudoro, Javier Guaje, Marc-Alex Côté, Soham Biswas, David Reagan, Nasim + Anousheh, Filipi Silva, Geoffrey Fox, and FURY Contributors + FURY: advanced scientific visualization +

+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/installation.html b/v0.10.x/installation.html new file mode 100644 index 000000000..bcdb8a217 --- /dev/null +++ b/v0.10.x/installation.html @@ -0,0 +1,731 @@ + + + + + + + + Installation — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ + +
+ + +
+
+ +
+ +
+ + +
+ +
+

Installation#

+

FURY supports Python 3.5+. You can currently still use Python 2.7 but it will soon stop being supported as the Python 2.7 end of life is on December 31st 2019.

+
+

Dependencies#

+

The mandatory dependencies are:

+
    +
  • numpy >= 1.7.1

  • +
  • vtk >= 8.1.0

  • +
  • scipy >= 0.9

  • +
  • aiohttp

  • +
  • pygltflib

  • +
+

The optional dependencies are:

+
    +
  • matplotlib >= 2.0.0

  • +
  • dipy >= 0.16.0

  • +
+
+
+

Installation with PyPi#

+

In a terminal, issue the following command

+
pip install fury
+
+
+
+
+

Installation with Conda#

+

Our conda package is on the Conda-Forge channel. You will need to run the following command

+
conda install -c conda-forge fury
+
+
+
+
+

Installation via Source#

+

Step 1. Get the latest source by cloning this repo

+
git clone https://github.com/fury-gl/fury.git
+
+
+

Step 2. Install requirements

+
pip install -r requirements/default.txt
+
+
+

Step 3. Install fury via

+
pip install .
+
+
+

or

+
pip install -e .
+
+
+

Step 4: Enjoy!

+
+
+

Test the Installation#

+

You can check your installation via this command

+
python -c "from fury import get_info; print(get_info())"
+
+
+

This command will give you important information about FURY’s installation. The next step will be to run a tutorial.

+
+
+

Running the Tests#

+

Let’s install all required packages for the running the test

+
pip install -r requirements/default.txt
+pip install -r requirements/test.txt
+
+
+

There are two ways to run FURY tests:

+
    +
  • From the command line. You need to be on the FURY package folder

  • +
+
pytest -svv fury
+
+
+
    +
  • To run a specific test file

  • +
+
pytest -svv fury/tests/test_actor.py
+
+
+
    +
  • To run a specific test directory

  • +
+
pytest -svv fury/tests
+
+
+
    +
  • To run a specific test function

  • +
+
pytest -svv -k "test_my_function_name"
+
+
+
+
+

Running the Tests Offscreen#

+

FURY is based on VTK which uses OpenGL for all its rendering. For a headless rendering, we recommend to install and use Xvfb software on linux or OSX. +Since Xvfb will require an X server (we also recommend to install XQuartz package on OSX). After Xvfb is installed you have 2 options to run FURY tests:

+
    +
  • First option

  • +
+
export DISPLAY=:0
+Xvfb :0 -screen 1920x1080x24 > /dev/null 2>1 &
+pytest -svv fury
+
+
+
    +
  • Second option

  • +
+
export DISPLAY=:0
+xvfb-run --server-args="-screen 0 1920x1080x24" pytest -svv fury
+
+
+
+
+

Populating our Documentation#

+
+

Folder Structure#

+

Let’s start by showcasing the docs folder structure:

+
+
fury
+
├── docs
+
│ ├── build
+
│ ├── make.bat
+
│ ├── Makefile
+
│ ├── Readme.md
+
│ ├── upload_to_gh-pages.py
+
│ ├── examples
+
│ ├── experimental
+
│ └── source
+
├── requirements.txt
+
├── fury
+
│ ├── actor.py
+
│ ├── …
+
+
│── …
+

+

+
+

In our docs folder structure above:

+
    +
  • source is the folder that contains all *.rst files.

  • +
  • examples is the directory where we have all python scripts that describe how to use the library.

  • +
  • experimental directory contains experimental Python scripts. The goal is to keep a trace of experimental work.

  • +
+
+
+

Building the documentation#

+

Step 1. Install all required packages for the documentation generation

+
pip install -U -r requirements/default.txt
+pip install -U -r requirements/optional.txt
+pip install -U -r requirements/docs.txt
+
+
+

Step 2. Go to the docs folder and run the following command to generate it (Linux and macOS)

+
make -C . clean && make -C . html
+
+
+

To generate the documentation without running the examples

+
make -C . clean && make -C . html-no-examples
+
+
+

or under Windows

+
make clean
+make html
+
+
+

To generate the documentation without running the examples under Windows

+
make clean
+make html-no-examples
+
+
+

Step 3. Congratulations! the build folder has been generated! Go to build/html and open with browser index.html to see your generated documentation.

+
+
+
+ +
+ + +
+ +
+ + + + + +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/introduction.html b/v0.10.x/introduction.html new file mode 100644 index 000000000..2c17d049d --- /dev/null +++ b/v0.10.x/introduction.html @@ -0,0 +1,598 @@ + + + + + + + + About — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

About#

+
+

Overview#

+

Free Unified Rendering in pYthon is a Python package that provides a minimalistic but powerful API that enables advanced scientific visualization and 3D animations for scientific research.

+

FURY is a community-driven, open-source, and high-performance scientific visualization library that harnesses the graphics processing unit (GPU) for improved speed, precise interactivity, and visual clarity.

+
+
+

Statement of Need#

+

FURY was created to address the growing necessity of high-performance 3D scientific visualization in an easy-to-use API fully compatible with the Pythonic ecosystem. To achieve this FURY takes ideas from CGI (Computer-Generated Imagery) and game engines to then be deployed for usage in everyday research practices.

+
+
+

Mission Statement#

+

The purpose of FURY is to make it easier to perform advanced visualizations and animations without compromising performance. We aim to build software that is:

+
    +
  • clearly written

  • +
  • clearly explained

  • +
  • a good fit for the underlying ideas

  • +
  • a natural home for collaboration

  • +
+

We hope that, if we fail to do this, you will let us know and we will try and make it better. An easy way to access the FURY development team is either through our Discord live chat room or in GitHub.

+
+
+

Features#

+
    +
  • Physically based and Cinematic Rendering.

  • +
  • Ray Tracing and Signed Distance Functionality.

  • +
  • Includes multiple physics and collision engines.

  • +
  • Pythonic API easy to use with Numpy and Jupyter.

  • +
  • Multiplatform. With wheels available for Linux, Mac and Windows.

  • +
  • Super easy to install. Just write: pip install fury.

  • +
  • Provides integrated user interfaces.

  • +
  • Easy to create multithreaded animations.

  • +
  • Contains a series of shaders including a Principled BRDF and BTDF.

  • +
  • Enables LaTeX fonts in 3D.

  • +
  • Supports a series of 3D file formats including (.Obj and .glTF) and 2D file formats such as PNG.

  • +
+
+
+

Architecture#

+FURY Architecture +
+
+

License#

+

FURY is distributed under the BSD 3 License

+
+
+

Credits#

+

Go to Community page to see who have been involved in the development of FURY.

+
+
+

Bug reports and support#

+

Please report any issues via fury-gl/fury#issues. All types of issues are welcome including bug reports, documentation typos, feature requests and so on.

+
+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/objects.inv b/v0.10.x/objects.inv new file mode 100644 index 000000000..64e117076 Binary files /dev/null and b/v0.10.x/objects.inv differ diff --git a/v0.10.x/posts/2018/2018-09-21-release-announcement.html b/v0.10.x/posts/2018/2018-09-21-release-announcement.html new file mode 100644 index 000000000..95ffc0c18 --- /dev/null +++ b/v0.10.x/posts/2018/2018-09-21-release-announcement.html @@ -0,0 +1,522 @@ + + + + + + + + FURY 0.1.0 Released — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

FURY 0.1.0 Released#

+

The FURY project is happy to announce the release of FURY 0.1.0! +FURY is a free and open source software library for scientific visualization and 3D animations.

+

You can show your support by adding a star on FURY github project.

+

The major highlights of this release are:

+

This initial release is a split from DIPY. It contains:

+
    +
  • from dipy.viz.actors to fury.actors

  • +
  • from dipy.viz.window to fury.window

  • +
  • from dipy.viz.ui to fury.ui

  • +
  • from dipy.viz.widget to fury.widget

  • +
  • from dipy.viz.interactor to fury.interactor

  • +
  • from dipy.viz.colormap to fury.colormap

  • +
  • from dipy.viz.utils to fury.utils

  • +
+
+

Note

+

The complete release notes are available here

+
+

To upgrade or install FURY

+

Run the following command in your terminal:

+
pip install --upgrade fury
+
+
+

or:

+
conda install -c conda-forge fury
+
+
+

Questions or suggestions?

+

For any questions go to http://fury.gl, or send an e-mail to fury@python.org +We can also join our discord community

+

On behalf of the FURY developers,

+

Serge K.

+
+ +
+ + + + +
+ + + +   + + + + Next: + + + FURY 0.1.3 Released + + + + +
+ + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2018/2018-10-31-release-announcement.html b/v0.10.x/posts/2018/2018-10-31-release-announcement.html new file mode 100644 index 000000000..c68f67284 --- /dev/null +++ b/v0.10.x/posts/2018/2018-10-31-release-announcement.html @@ -0,0 +1,525 @@ + + + + + + + + FURY 0.1.3 Released — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

FURY 0.1.3 Released#

+

The FURY project is happy to announce the release of FURY 0.1.3! +FURY is a free and open source software library for scientific visualization and 3D animations.

+

You can show your support by adding a star on FURY github project.

+

The major highlights of this release are:

+

This is a maintenance release

+
    +
  • Update setup.py

  • +
  • Remove dependence on requirements.txt

  • +
+
+

Note

+

The complete release notes are available here

+
+

To upgrade or install FURY

+

Run the following command in your terminal:

+
pip install --upgrade fury
+
+
+

or:

+
conda install -c conda-forge fury
+
+
+

Questions or suggestions?

+

For any questions go to http://fury.gl, or send an e-mail to fury@python.org +We can also join our discord community

+

On behalf of the FURY developers,

+

Serge K.

+
+ +
+ + + + +
+ + + + Previous: + + + + FURY 0.1.0 Released + + + +   + + + + Next: + + + FURY 0.1.4 Released + + + + +
+ + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2018/2018-11-26-release-announcement.html b/v0.10.x/posts/2018/2018-11-26-release-announcement.html new file mode 100644 index 000000000..e87af17ed --- /dev/null +++ b/v0.10.x/posts/2018/2018-11-26-release-announcement.html @@ -0,0 +1,525 @@ + + + + + + + + FURY 0.1.4 Released — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

FURY 0.1.4 Released#

+

The FURY project is happy to announce the release of FURY 0.1.4! +FURY is a free and open source software library for scientific visualization and 3D animations.

+

You can show your support by adding a star on FURY github project.

+

The major highlights of this release are:

+

This is a maintenance release

+
    +
  • Add vtk.utils.color on window package

  • +
  • Update Readme, codecov, travis…

  • +
+
+

Note

+

The complete release notes are available here

+
+

To upgrade or install FURY

+

Run the following command in your terminal:

+
pip install --upgrade fury
+
+
+

or:

+
conda install -c conda-forge fury
+
+
+

Questions or suggestions?

+

For any questions go to http://fury.gl, or send an e-mail to fury@python.org +We can also join our discord community

+

On behalf of the FURY developers,

+

Serge K.

+
+ +
+ + + + +
+ + + + Previous: + + + + FURY 0.1.3 Released + + + +   + + + + Next: + + + FURY 0.2.0 Released + + + + +
+ + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2019/2019-03-08-release-announcement.html b/v0.10.x/posts/2019/2019-03-08-release-announcement.html new file mode 100644 index 000000000..3d7ea2b8f --- /dev/null +++ b/v0.10.x/posts/2019/2019-03-08-release-announcement.html @@ -0,0 +1,534 @@ + + + + + + + + FURY 0.2.0 Released — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

FURY 0.2.0 Released#

+

The FURY project is happy to announce the release of FURY 0.2.0! +FURY is a free and open source software library for scientific visualization and 3D animations.

+

You can show your support by adding a star on FURY github project.

+

The major highlights of this release are:

+
    +
  • Replace fury.window.Renderer by fury.window.Scene

  • +
  • Add stereo support

  • +
  • Add GridUI object

  • +
  • Increase tests coverage and code quality

  • +
+
+

Note

+

The complete release notes are available here

+
+

To upgrade or install FURY

+

Run the following command in your terminal:

+
pip install --upgrade fury
+
+
+

or:

+
conda install -c conda-forge fury
+
+
+

Questions or suggestions?

+

For any questions go to http://fury.gl, or send an e-mail to fury@python.org +We can also join our discord community

+

We would like to thanks to all contributors for this release:

+
    +
  • David Reagan

  • +
  • Eleftherios Garyfallidis

  • +
  • Jon Haitz Legarreta Gorroño

  • +
  • Marc-Alexandre Côté

  • +
  • Serge Koudoro

  • +
+

On behalf of the FURY developers,

+

Serge K.

+
+ +
+ + + + +
+ + + + Previous: + + + + FURY 0.1.4 Released + + + +   + + + + Next: + + + Success on Brain Art Competition using FURY + + + + +
+ + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2019/2019-06-19-brain-art.html b/v0.10.x/posts/2019/2019-06-19-brain-art.html new file mode 100644 index 000000000..ff9d0aa28 --- /dev/null +++ b/v0.10.x/posts/2019/2019-06-19-brain-art.html @@ -0,0 +1,501 @@ + + + + + + + + Success on Brain Art Competition using FURY — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + + + + + +
+ +
+
+
+ +
+ + + +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2019/2019-08-02-release-announcement.html b/v0.10.x/posts/2019/2019-08-02-release-announcement.html new file mode 100644 index 000000000..cb0463abe --- /dev/null +++ b/v0.10.x/posts/2019/2019-08-02-release-announcement.html @@ -0,0 +1,536 @@ + + + + + + + + FURY 0.3.0 Released — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

FURY 0.3.0 Released#

+

The FURY project is happy to announce the release of FURY 0.3.0! +FURY is a free and open source software library for scientific visualization and 3D animations.

+

You can show your support by adding a star on FURY github project.

+

The major highlights of this release are:

+
    +
  • Add cone actor and update odf actor

  • +
  • Add Appveyor CI and update MacOS CI

  • +
  • Update Documentation, examples and tutorials

  • +
  • Increase tests coverage and code quality

  • +
+
+

Note

+

The complete release notes are available here

+
+

To upgrade or install FURY

+

Run the following command in your terminal:

+
pip install --upgrade fury
+
+
+

or:

+
conda install -c conda-forge fury
+
+
+

Questions or suggestions?

+

For any questions go to http://fury.gl, or send an e-mail to fury@python.org +We can also join our discord community

+

We would like to thanks to all contributors for this release:

+
    +
  • Ariel Rokem

  • +
  • Eleftherios Garyfallidis

  • +
  • Guillaume Favelier

  • +
  • Kevin Sitek

  • +
  • Prashil

  • +
  • Scott Trinkle

  • +
  • Serge Koudoro

  • +
+

On behalf of the FURY developers,

+

Serge K.

+
+ +
+ + + + +
+ + + + Previous: + + + + Success on Brain Art Competition using FURY + + + +   + + + + Next: + + + FURY 0.4.0 Released + + + + +
+ + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2019/2019-10-29-release-announcement.html b/v0.10.x/posts/2019/2019-10-29-release-announcement.html new file mode 100644 index 000000000..b7800a66f --- /dev/null +++ b/v0.10.x/posts/2019/2019-10-29-release-announcement.html @@ -0,0 +1,536 @@ + + + + + + + + FURY 0.4.0 Released — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

FURY 0.4.0 Released#

+

The FURY project is happy to announce the release of FURY 0.4.0! +FURY is a free and open source software library for scientific visualization and 3D animations.

+

You can show your support by adding a star on FURY github project.

+

The major highlights of this release are:

+
    +
  • Enable Anti aliasing and frame rate features

  • +
  • Add multiples actors (arrow, box, …)

  • +
  • Glyph extensions

  • +
  • Remove Nose dependency

  • +
  • Replace Appveyor by Azure pipeline for Windows

  • +
  • Update Documentation, examples and tutorials

  • +
  • Increase tests coverage and code quality

  • +
+
+

Note

+

The complete release notes are available here

+
+

To upgrade or install FURY

+

Run the following command in your terminal:

+
pip install --upgrade fury
+
+
+

or:

+
conda install -c conda-forge fury
+
+
+

Questions or suggestions?

+

For any questions go to http://fury.gl, or send an e-mail to fury@python.org +We can also join our discord community

+

We would like to thanks to all contributors for this release:

+
    +
  • Eleftherios Garyfallidis

  • +
  • Etienne St-Onge

  • +
  • Javier Guaje

  • +
  • Serge Koudoro

  • +
+

On behalf of the FURY developers,

+

Serge K.

+
+ +
+ + + + +
+ + + + Previous: + + + + FURY 0.3.0 Released + + + +   + + + + Next: + + + Google Summer of Code + + + + +
+ + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2020/2020-01-05-gsoc.html b/v0.10.x/posts/2020/2020-01-05-gsoc.html new file mode 100644 index 000000000..03efb66cd --- /dev/null +++ b/v0.10.x/posts/2020/2020-01-05-gsoc.html @@ -0,0 +1,504 @@ + + + + + + + + Google Summer of Code — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Google Summer of Code#

+

FURY is participating in the Google Summer of Code 2020 under the umbrella of the Python Software Foundation.

+

FURY is a free and open source software library for scientific visualization and 3D animations. FURY contains many tools for visualizing a series of scientific data including graph and imaging data.

+

A list of project ideas and application info is on our GitHub Wiki.

+

If you are interested in talking to us about projects, applications join us to our discord community or drop us a line on our mailing list.

+

Be part of our community and Enjoy your summer of code!

+

Serge K.

+
+ +
+ + + + +
+ + + + Previous: + + + + FURY 0.4.0 Released + + + +   + + + + Next: + + + FURY 0.5.1 Released + + + + +
+ + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2020/2020-04-09-release-announcement.html b/v0.10.x/posts/2020/2020-04-09-release-announcement.html new file mode 100644 index 000000000..8df5621d9 --- /dev/null +++ b/v0.10.x/posts/2020/2020-04-09-release-announcement.html @@ -0,0 +1,553 @@ + + + + + + + + FURY 0.5.1 Released — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

FURY 0.5.1 Released#

+

The FURY project is happy to announce the release of FURY 0.5.1! +FURY is a free and open source software library for scientific visualization and 3D animations.

+

You can show your support by adding a star on FURY github project.

+

The major highlights of this release are:

+
    +
  • Remove python 2 compatibility

  • +
  • Added texture management

  • +
  • Added multiples primitives.

  • +
  • Added multiples actors (contour_from_label, billboard…)

  • +
  • Huge improvement of multiple UI (RangeSlider, …)

  • +
  • Improved security (from md5 to sha256)

  • +
  • Large documentation update, examples and tutorials

  • +
  • Increased tests coverage and code quality

  • +
+
+

Note

+

The complete release notes are available here

+
+

To upgrade or install FURY

+

Run the following command in your terminal:

+
pip install --upgrade fury
+
+
+

or:

+
conda install -c conda-forge fury
+
+
+

Questions or suggestions?

+

For any questions go to http://fury.gl, or send an e-mail to fury@python.org +We can also join our discord community

+

We would like to thanks to all contributors for this release:

+
    +
  • ChenCheng0630

  • +
  • Devanshu Modi

  • +
  • Eleftherios Garyfallidis

  • +
  • Etienne St-Onge

  • +
  • Filipi Nascimento Silva

  • +
  • Gottipati Gautam

  • +
  • Javier Guaje

  • +
  • Jon Haitz Legarreta Gorroño

  • +
  • Liam Donohue

  • +
  • Marc-Alexandre Côté

  • +
  • Marssis

  • +
  • Naman Bansal

  • +
  • Nasim

  • +
  • Saransh Jain

  • +
  • Serge Koudoro

  • +
  • Shreyas Bhujbal

  • +
  • Soham Biswas

  • +
  • Vivek Choudhary

  • +
  • ibrahimAnis

  • +
  • lenixlobo

  • +
+

On behalf of the FURY developers,

+

Serge K.

+
+ +
+ + + + +
+ + + + Previous: + + + + Google Summer of Code + + + +   + + + + Next: + + + Weekly Check-in #1 + + + + +
+ + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2020/2020-05-30-week-1-lenix.html b/v0.10.x/posts/2020/2020-05-30-week-1-lenix.html new file mode 100644 index 000000000..3f0e24d3c --- /dev/null +++ b/v0.10.x/posts/2020/2020-05-30-week-1-lenix.html @@ -0,0 +1,540 @@ + + + + + + + + Weekly Check-in #1 — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Weekly Check-in #1#

+
+

Welcome to my GSoC Blog!!!#

+

Hey everyone! +This is my blog for this summer’s GSoC @ PSF +I am Lenix Lobo, an undergraduate student from India, and this summer I will be working with project Fury under the umbrella of the Python Software foundation. I will be working on improving the current shader framework.

+
+
+

What did you do during the Community Bonding Period?#

+

Since most of the places including my university are closed due to the pandemic outbreak, I decided to get a head start and start with the project early. During the community bonding period, I had video conference meetings with my mentors scheduled every week on Wednesday. During these meetings i interacted with the mentors to have a coherent understanding of how the project design and implementation will be managed over the course of the entire period.

+

Since my project involves a lot of theoretical understanding of concepts such as ray marching, I spent the period going through the theory of each topic.This week also involved going through the documentation for shaders used in VTK.

+
+
+

What is coming up next week?#

+

The next task assigned to me is to go through the theory of geometry shaders and to create a example using the same.

+
+
+ +
+ + + + +
+ + + + Previous: + + + + FURY 0.5.1 Released + + + +   + + + + Next: + + + Welcome to my GSoC Blog!!! + + + + +
+ + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2020/2020-05-30-week-1-soham.html b/v0.10.x/posts/2020/2020-05-30-week-1-soham.html new file mode 100644 index 000000000..8f47db8b3 --- /dev/null +++ b/v0.10.x/posts/2020/2020-05-30-week-1-soham.html @@ -0,0 +1,532 @@ + + + + + + + + Welcome to my GSoC Blog!!! — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Welcome to my GSoC Blog!!!#

+

Hello Everyone, this is Soham Biswas currently in 2nd year pursuing my Bachelor’s(B.Tech) degree in Computer Science & Engineering from Institute of Engineering & Management, Kolkata. I have been selected for GSoC’ 20 at sub-org FURY under the umbrella organization of Python Software Foundation. I will be working on building sci-fi-like 2D and 3D interfaces and provide physics engine integration under project titled “Create new UI widgets & Physics Engine Integration”.

+
+

What did you do during the Community Bonding Period?#

+

Due to the pandemic outbreak and the country wide lockdown in India, many places including my university were closed and therefore I decided to get a head start and start with the project early. During the community bonding period, we had video conference meetings with our mentors and the project’s core team. We interacted with each other and discussed the implementation details and their respective deadlines for the entire event period. We will be having such meetings every week on Wednesday in order to update ourselves about the progress of our respective tasks.

+

I completed the remaining Pull Requests that I had pending before the GSoC students announcement. I also reviewed other issues and pull requests to make sure everything remains up-to-date.

+
+
+

What is coming up next week?#

+

Currently, I am focusing on building the ComboBox2D UI element. I will try to get the skeleton model, required sub-components and their respective default callbacks done by next week.

+

While working with my previous PR related to Double Click callbacks, I faced an issue where I was unable to create and implement User Events properly in VTK. Thankfully, my mentors helped me out I was able to implement double click callbacks for all three mouse buttons successfully.

+

See you next week, cheers!!

+
+
+ +
+ + + + +
+ + + + Previous: + + + + Weekly Check-in #1 + + + +   + + + + Next: + + + First week of coding!! + + + + +
+ + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2020/2020-06-07-week-2-lenix.html b/v0.10.x/posts/2020/2020-06-07-week-2-lenix.html new file mode 100644 index 000000000..82824bd14 --- /dev/null +++ b/v0.10.x/posts/2020/2020-06-07-week-2-lenix.html @@ -0,0 +1,543 @@ + + + + + + + + First week of coding!! — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

First week of coding!!#

+

Hey everyone! +This week : Geometry Shaders!

+
+

What did you do this week?#

+

To get a better understanding of the working of the shader pipeline, the mentors assigned me a challenging task of implementing a Dynamic Texture. The basic idea is to create a ‘volumetric’ texture by stacking layer of textures. Such an example is an ideal use case for a geometry shader. Since i had not much prior experience with Geometry shaders before, i spent the initial days going through existing implementations of similar ideas in OpenGL/DirectX. +After working on the code, the final image rendered is given below.

+https://raw.githubusercontent.com/lenixlobo/fury-outputs/master/blog-week-2.png +

I created a PR for the fur texture which is available here

+
+
+

What is coming up next week?#

+

The current PR has some minor bugs which need to be fixed. The next step would be to review the code and find the solutions for the bugs. Also we are looking into ideas on optimization for faster rendering time.

+

The next week will be spent looking into ray marching algorithms and adding them to the current code base as possible alternatives for FURY Actor primitives.

+
+
+

Did you get stuck anywhere?#

+

Nothing major.

+
+
+ +
+ + + + +
+ + + + Previous: + + + + Welcome to my GSoC Blog!!! + + + +   + + + + Next: + + + First week of coding!! + + + + +
+ + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2020/2020-06-07-week-2-soham.html b/v0.10.x/posts/2020/2020-06-07-week-2-soham.html new file mode 100644 index 000000000..9d2eb411b --- /dev/null +++ b/v0.10.x/posts/2020/2020-06-07-week-2-soham.html @@ -0,0 +1,541 @@ + + + + + + + + First week of coding!! — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

First week of coding!!#

+

Hello and welcome to my second weekly check-in, I will be sharing my progress for the first week of coding.

+
+

What did you do this week?#

+

This week my objective was to create the skeleton model for ComboBox2D UI element along with its required sub-components and their respective default callbacks. So far, I have successfully been able to implement them. Apart from some issues that I was facing regarding the sizing and position of the sub-components.

+
+
+

What is coming up next week?#

+

Next week, my main focus will be on fixing the sizing issue and I will also be working on respective default and specialized class methods required by the component and its sub-components for proper functioning. I will also create tests for the same.

+
+
+

Did you get stuck anywhere?#

+

The main problem that I faced while coding the UI element was regarding the sizing and positioning of the sub-components. The sub-components appeared flipped and the TextBlock2D element had no option to resize based on a particular width & height definition.

+https://user-images.githubusercontent.com/29832615/82089691-b713fc80-9711-11ea-8d72-efaeaac1044c.png +

As you can see, the ComboBox UI element doesn’t look the way its supposed to. Along with this issue the scrollbars callback doesn’t work either. Hopefully, I will be able to get these issues fixed by next week.

+

Thank you for reading, see you next week!!

+
+
+ +
+ + + + +
+ + + + Previous: + + + + First week of coding!! + + + +   + + + + Next: + + + ComboBox2D Progress!! + + + + +
+ + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2020/2020-06-14-week-3-lenix.html b/v0.10.x/posts/2020/2020-06-14-week-3-lenix.html new file mode 100644 index 000000000..88eca9943 --- /dev/null +++ b/v0.10.x/posts/2020/2020-06-14-week-3-lenix.html @@ -0,0 +1,543 @@ + + + + + + + + Raymarching!! — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Raymarching!!#

+

Make sure to check out Project FURY

+

Hey ! +This week, Raymarching!

+
+

What did you do this week?#

+

This was an exciting week as i got to learn and implement the ray marching algorithm in the FURY repo. In the weekly meeting, the mentors suggested adding support for SDF modelled actors as an alternative to the existing FURY actors. After going through a few implementations of ray marching in GLSL, i proceeded with the implementation in VTK. After being able to render a torus , the next logical step was to add support for multiple actors in the same window. The below render shows support for multiple SDF actors :

+https://raw.githubusercontent.com/lenixlobo/fury-outputs/master/blog-week-3.gif +

The code for the above render is available at the branch

+
+
+

What is coming up next week?#

+

In the above output, there is some deformation in some of the cubes, The next step is to get rid of this deformation . +Also i will be working on adding lighting within the shaders for a slightly more realistic experience.

+
+
+

Did you get stuck anywhere?#

+

Going through and understanding theVTK documentation was quite a challenging task, however whenever i was confused the doubts were immediately cleared by the mentors

+
+
+ +
+ + + + +
+ + + + Previous: + + + + ComboBox2D Progress!! + + + +   + + + + Next: + + + Raymarching continued + + + + +
+ + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2020/2020-06-14-week-3-soham.html b/v0.10.x/posts/2020/2020-06-14-week-3-soham.html new file mode 100644 index 000000000..57b44a648 --- /dev/null +++ b/v0.10.x/posts/2020/2020-06-14-week-3-soham.html @@ -0,0 +1,540 @@ + + + + + + + + ComboBox2D Progress!! — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

ComboBox2D Progress!!#

+

Hello and welcome to my third weekly check-in, I will be sharing my progress with the project so far. In case you wondered, the sub-org that I am affiliated to is FURY. Make sure to check out the official repository here.

+
+

What did you do this week?#

+

This week my objective was to work on the sizing and positioning issue regarding the sub-components of the ComboBox2D UI element. After countless debugging sessions and my mentor’s support, I was successfully able to fix the issue. I also developed helpful methods and callbacks for this element to allow users to interact with them in a user friendly manner. I also wrote tests for the same. So far the said progress can be summarized via this gif:

+https://user-images.githubusercontent.com/29832615/84592637-cc8d5b00-ae64-11ea-9ff3-c1ce2095f7f2.gif +
+
+

What is coming up next week?#

+

Unfortunately, one of the sub-components TextBlock2D, didn’t have a resizing feature that I could make use of for this new UI component. Thus, I need to add that feature on a different PR. This feature will also be required while building other UI elements therefore adding this feature is currently my top priority. There’s also a bug regarding the scrollbar that needs to be fixed. The scrollbar overshoots the specified combobox area after new items are appended to the combobox’s list of items during runtime. Hopefully I will be able to get them done by next week.

+
+
+

Did you get stuck anywhere?#

+

I was really confused with the coordinate system of Panel2D that was the main reason why components were misplaced. I also faced some issues regarding the scrollbar callback as it wasn’t scrolling the elements properly, the items were stuck in place. So far I was able to fix them. Apart from these, I didn’t face any major issues.

+

Thank you for reading, see you next week!!

+
+
+ +
+ + + + +
+ + + + Previous: + + + + First week of coding!! + + + +   + + + + Next: + + + Raymarching!! + + + + +
+ + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2020/2020-06-21-week-4-lenix.html b/v0.10.x/posts/2020/2020-06-21-week-4-lenix.html new file mode 100644 index 000000000..241fa748f --- /dev/null +++ b/v0.10.x/posts/2020/2020-06-21-week-4-lenix.html @@ -0,0 +1,546 @@ + + + + + + + + Raymarching continued — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Raymarching continued#

+

Make sure to check out Project FURY

+

Hey ! +Raymarching continued

+
+

What did you do this week?#

+

As you read in my last blog post, while the SDF primitives were working , there was slight deformation in the render. So the main focus for this week was working on solving the deformation bug. Initially the suspect was possibly the coordinate space in which the ray marching algorithm was being computed, however after testing multiple combination of transformations the issue wasn’t solved. To avoid getting stuck too long on a single bug, I decided to simultaneously work on any alternatives to the current approach. So i started working on the 2nd approach. The idea was to render multiple primitives in a single cube rather than one SDF per cube. This turned out to be highly beneficial as while implementing this , i realized what was causing the deformation .

+

I have added the GIFs for both the renders below. I also worked on a lambertian lighting model to create a more realistic render.

+

Multiple Primitives within a single cube:

+https://raw.githubusercontent.com/lenixlobo/fury-outputs/master/blog-week-4a.gif +

Solved deformation with added lambertian Lighting:

+https://raw.githubusercontent.com/lenixlobo/fury-outputs/master/blog-week-4b.gif +

The code for the above render is available at the branch

+
+
+

What is coming up next week?#

+

The next task assigned is to add support for spherical harmonics as primitives.

+
+
+

Did you get stuck anywhere?#

+

I was stuck on the deformation issue for most of the week, but was eventually able to solve that.

+
+
+ +
+ + + + +
+ + + + Previous: + + + + Raymarching!! + + + +   + + + + Next: + + + TextBlock2D Progress!! + + + + +
+ + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2020/2020-06-21-week-4-soham.html b/v0.10.x/posts/2020/2020-06-21-week-4-soham.html new file mode 100644 index 000000000..2c3571323 --- /dev/null +++ b/v0.10.x/posts/2020/2020-06-21-week-4-soham.html @@ -0,0 +1,548 @@ + + + + + + + + TextBlock2D Progress!! — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

TextBlock2D Progress!!#

+

Hello and welcome to my 4th weekly check-in, I will be sharing my progress with TextBlock2D UI component. The official repository of my sub-org, FURY can always be found here.

+
+

What did you do this week?#

+

This week my objective was to work on the TextBlock2D resizing feature and also work on the scrollbar bug in ComboBox2D UI component. The TextBlock2D component makes use of vtkTextActor and its methods available in VTK for handling all Text related properties such as font size, color, background color etc. Now, going through the official docs I figured out that the there were three different scaling modes for the said actor:

+
    +
  • TEXT_SCALE_MODE_NONE

  • +
  • TEXT_SCALE_MODE_PROP

  • +
  • TEXT_SCALE_MODE_VIEWPORT

  • +
+

The first scaling mode was currently implemented in FURY’s TextBlock2D code base. This was done mainly because the only way for the user to create a text block was by providing the font size as parameter. We couldn’t use the third option as the FURY API tries to maintain abstraction by not exposing vtkViewport parameter. Now in order to allow size as a parameter I had to use the second scaling option which is TEXT_SCALE_MODE_PROP. With this mode one can set the Position2 parameter to the desired value of height and width. But the problem is I cannot use this for the combobox element as the background size will be inconsistent with respect to font size and text length.

+https://user-images.githubusercontent.com/29832615/85226809-12af6500-b3f7-11ea-8a75-7e86d40701d1.png +https://user-images.githubusercontent.com/29832615/85226812-14792880-b3f7-11ea-8edd-1df25382a48f.png +

Therefore, as a solution we agreed to add a separate Rectangle2D UI component as the background for Text Block along with vtkTextActor. With this implementation one can easily manipulate the background irrespective of the text properties. But this had another issue, the user now had 2 different ways of initializing a TextBlock2D. Therefore, when the user uses size a constructor parameter, then everything works in sync, but the same is not true for the font size parameter. This is mainly because we do not have a specific way of determining the size of the actor based on font size. My mentors have agreed to look into this problem and advised me to focus on something else instead.

+
+
+

What is coming up next week?#

+

Next week I am planning to start with Physics engine integration of FURY with pyBullet. My main focus would be to create simple simulations first before initiating the integration process. If the size issue is solved before I move into Physics engine then I would complete the ComboBox UI and start with Tab UI instead. I have also fixed the scrollbar bug.

+
+
+

Did you get stuck anywhere?#

+

The main problem that I faced so far was regarding the variable background size of the Text Block component. Also the GetPosition2 method of vtkTextActor would always return the same value irrespective of the font size parameter passed as a constructor argument. Therefore, it was not possible for me to determine the actual size or bounding box of the said text actor.

+

Thank you for reading, see you next week!!

+
+
+ +
+ + + + +
+ + + + Previous: + + + + Raymarching continued + + + +   + + + + Next: + + + May the Force be with you!! + + + + +
+ + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2020/2020-06-28-week-5-lenix.html b/v0.10.x/posts/2020/2020-06-28-week-5-lenix.html new file mode 100644 index 000000000..04e0b30c8 --- /dev/null +++ b/v0.10.x/posts/2020/2020-06-28-week-5-lenix.html @@ -0,0 +1,543 @@ + + + + + + + + Spherical harmonics — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Spherical harmonics#

+

Make sure to check out Project FURY

+

Hey ! +This week, Spherical harmonics!

+
+

What did you do this week?#

+

The main task for the week was to include an implementation of spherical harmonics (upto the order of 4) as a FURY actor. This was the initial milestone to be achieved to work towards the support of using spherical harmonics as an visualization technique. I have added the GIFs for both the renders below. I also worked on a occlusion based lighting model.

+

Spherical harmonics for different values of order and degree:

+https://raw.githubusercontent.com/lenixlobo/fury-outputs/master/blog-week-5a.gif +https://raw.githubusercontent.com/lenixlobo/fury-outputs/master/blog-week-5b.gif +
+
+

What is coming up next week?#

+

The next task to add support for the user to be able to render different spherical harmonics by passing arguments

+
+
+

Did you get stuck anywhere?#

+

Spherical harmonics involve a lot of complicated math behind the hood. So the initial days were spent understanding the math .I was confused while working on the implementation but eventually got it working.

+
+
+ +
+ + + + +
+ + + + Previous: + + + + May the Force be with you!! + + + +   + + + + Next: + + + Spherical harmonics, Continued. + + + + +
+ + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2020/2020-06-28-week-5-soham.html b/v0.10.x/posts/2020/2020-06-28-week-5-soham.html new file mode 100644 index 000000000..4022b57b5 --- /dev/null +++ b/v0.10.x/posts/2020/2020-06-28-week-5-soham.html @@ -0,0 +1,561 @@ + + + + + + + + May the Force be with you!! — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

May the Force be with you!!#

+

Hello and welcome to my 5th weekly check-in, I will be sharing my progress of pyBullet Physics Engine Integration with FURY. The official repository of my sub-org, FURY can always be found here.

+
+

What did you do this week?#

+

Last week due to the vtkTextActor sizing issue I was not able to continue my work with ComboBox2D UI element. Thus, I decided to work on the “Physics Engine Integration” part of my project. It took me quite a while to understand the terminology of various methods and algorithms used for detection and physics simulation. Nevertheless, I was able to create a couple of rigid body examples to showcase the integration procedure. For physics calculations we used pyBullet and for rendering we used FURY. In other words, pyBullet will handle the backend part of the simulation and FURY will handle the frontend. I have documented the entire integration process here in detail.

+
+

Ball Collision Simulation:#

+https://user-images.githubusercontent.com/29832615/85949638-988e5b80-b975-11ea-85ba-16c1f78dec89.gif +

For the first example, I created a simple collision between two balls in which two spheres were created both in FURY and pyBullet world and then both the worlds are connected by syncing the position and orientation of the said bodies. Timer callback is created to update the positions and to simulate Physics for each step.

+
+
+

Brick Wall Simulation:#

+https://raw.githubusercontent.com/Nibba2018/testing-fury/master/2020-06-26_21-15-47.gif +

For the second example I tried to increase the complexity of the simulations by increasing the number of dynamic objects. Here a brick-wall is created using 100 bricks and then a ball is thrown at it. The rest of it is simulated. The same concepts from the first example is used to render the second one. Timer callback is created to update position of all the objects and to simulate Physics for each step.

+
+
+
+

What is coming up next week?#

+

In the above examples I used a separate actor for each object which is highly un-optimized. Thus, my mentor suggested me to render all the bricks using a single actor, so that the simulation is more optimized. I am not very confident in changing the position and orientation of different objects rendered by a single actor. Therefore, I will have to research a bit more about it. Apart from that I will also try to work on Constraint based simulation examples if possible.

+
+
+

Did you get stuck anywhere?#

+

The pyBullet documentation isn’t well written for cross rendering, hence it was a bit of a challenge for me to implement the integration. I also faced a problem regarding the offset of actors between the FURY world and pyBullet world. Both use different coordinate systems for rendering and simulation because of which I had a constant offset between the objects during simulations. I was able to fix it by converting one coordinate system to the other. Apart from this I did not have any major issues.

+

Thank you for reading, see you next week!!

+
+
+ +
+ + + + +
+ + + + Previous: + + + + TextBlock2D Progress!! + + + +   + + + + Next: + + + Spherical harmonics + + + + +
+ + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2020/2020-07-05-week-6-lenix.html b/v0.10.x/posts/2020/2020-07-05-week-6-lenix.html new file mode 100644 index 000000000..2409188f9 --- /dev/null +++ b/v0.10.x/posts/2020/2020-07-05-week-6-lenix.html @@ -0,0 +1,544 @@ + + + + + + + + Spherical harmonics, Continued. — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Spherical harmonics, Continued.#

+

Make sure to check out Project FURY

+

Hey ! +Spherical harmonics, Continued!

+
+

What did you do this week?#

+

Last week I added a basic implementation of Spherical harmonics based actors. However, the implementation was quite restricted and we needed to add support for more accurate generation of spherical harmonics. So the task assigned this week was to implement the spherical harmonics function within the shader rather than passing variables as uniforms. This was quite an challenging task as it involved understanding of mathematical formulae and implementing them using existing GLSL functions. +The output of the implementation is shown below :

+https://raw.githubusercontent.com/lenixlobo/fury-outputs/master/blog-week-6.gif +

While , i was able to complete the task the frame rate for the generated output was quite lower than expected. +The code for the above render is available at the branch

+
+
+

What is coming up next week?#

+

The next task is to discuss possible performance improvements with the mentors and also look into alternative ideas to add spherical harmonics as actors in FURY.

+
+
+

Did you get stuck anywhere?#

+

Spherical harmonics involve a lot of complicated math behind the hood as a result the generated output has a very poor frame rate. Currently, we are looking into improving this.

+
+
+ +
+ + + + +
+ + + + Previous: + + + + Spherical harmonics + + + +   + + + + Next: + + + Translation, Reposition, Rotation. + + + + +
+ + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2020/2020-07-05-week-6-soham.html b/v0.10.x/posts/2020/2020-07-05-week-6-soham.html new file mode 100644 index 000000000..2dd68cd01 --- /dev/null +++ b/v0.10.x/posts/2020/2020-07-05-week-6-soham.html @@ -0,0 +1,606 @@ + + + + + + + + Translation, Reposition, Rotation. — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Translation, Reposition, Rotation.#

+

Hello and welcome to my 6th weekly check-in. The first evaluation period officially ends and I am very excited to move on to the second coding period. I will be sharing my progress with handling specific object’s properties among various multiple objects rendered by a single actor. I am mainly focusing on making it easier to translate, rotate and reposition a particular object, so that I can use them to render physics simulations more efficiently. The official repository of my sub-org, FURY can always be found here.

+
+

What did you do this week?#

+

Last week I worked on physics simulations rendered in FURY with the help of pyBullet. Now the simulations were highly un-optimized, specially the brick wall simulation as each brick was rendered by its own actor. In other words, 1 brick = 1 actor. Now my objective was to render all the bricks using a single actor, but before jumping into the simulation I had to figure out how to modify specific properties of an individual object. Thanks to my mentor’s PR, I was able to experiment my implementations quickly.

+
+

Translation:#

+https://user-images.githubusercontent.com/29832615/86536066-5085b080-bf02-11ea-9bcd-9e555adc2ca1.gif +

The algorithm behind translation is to first identify the vertices of the object, then bring the vertices to the origin by subtracting their centers and then adding the displacement vector. The said operation can be achieved by the following snippet:

+
# Update vertices positions
+vertices[object_index * sec: object_index * sec + sec] = \
+    (vertices[object_index * sec: object_index * sec + sec] - centers[object_index]) + transln_vector​
+
+
+
+
+

Rotation:#

+https://user-images.githubusercontent.com/29832615/86536065-4fed1a00-bf02-11ea-815d-f7f297165c53.gif +

The algorithm behind rotation is to first calculate the difference between the vertices and the center of the object. Once we get the resultant matrix, we matrix multiply it with the rotation matrix and then we further add the centers back to it so that we preserve the position of the object. Rotation matrix can be defined as:

+https://wikimedia.org/api/rest_v1/media/math/render/svg/242deb7010fd504134a6cacab3d0ef4ce02e7613 +

where gamma, beta and alpha corresponds to the angle of rotation along Z-axis, Y-axis and X-axis.

+
def get_R(gamma, beta, alpha):
+    """ Returns rotational matrix.
+    """
+    r = [
+        [np.cos(alpha)*np.cos(beta), np.cos(alpha)*np.sin(beta)*np.sin(gamma) - np.sin(alpha)*np.cos(gamma),
+        np.cos(alpha)*np.sin(beta)*np.cos(gamma) + np.sin(alpha)*np.sin(gamma)],
+        [np.sin(alpha)*np.cos(beta), np.sin(alpha)*np.sin(beta)*np.sin(gamma) + np.cos(alpha)*np.cos(gamma),
+        np.sin(alpha)*np.sin(beta)*np.cos(gamma) - np.cos(alpha)*np.sin(gamma)],
+        [-np.sin(beta), np.cos(beta)*np.sin(gamma), np.cos(beta)*np.cos(gamma)]
+    ]
+    r = np.array(r)
+    return r
+
+vertices[object_index * sec: object_index * sec + sec] = \
+    (vertices[object_index * sec: object_index * sec + sec] -
+    centers[object_index])@get_R(0, np.pi/4, np.pi/4) + centers[object_index]
+
+
+
+
+

Reposition:#

+https://user-images.githubusercontent.com/29832615/86536063-4ebbed00-bf02-11ea-8592-a695d7b91426.gif +

Repositioning is similar to that of translation, except in this case, while repositioning we update centers with the new position value.

+
new_pos = np.array([1, 2, 3])
+
+# Update vertices positions
+vertices[object_index * sec: object_index * sec + sec] = \
+    (vertices[object_index * sec: object_index * sec + sec] -
+    centers[object_index]) + new_pos
+
+centers[object_index] = new_pos
+
+
+
+
+
+

What is coming up next week?#

+

Currently, I am yet to figure out the orientation problem. Once I figure that out I will be ready to implement simulations without any major issues. I am also tasked with creating a wrecking ball simulation and a quadruped robot simulation.

+
+
+

Did you get stuck anywhere?#

+

I did face some problems while rotating objects. My mentors suggested me to implement it via rotation matrix. I still haven’t figured out the orientation problem, which I plan to work on next. Apart from these I did not face any major issues.

+

Thank you for reading, see you next week!!

+
+
+ +
+ + + + +
+ + + + Previous: + + + + Spherical harmonics, Continued. + + + +   + + + + Next: + + + Orientation, Sizing, Tab UI. + + + + +
+ + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2020/2020-07-12-week-7-soham.html b/v0.10.x/posts/2020/2020-07-12-week-7-soham.html new file mode 100644 index 000000000..e74754407 --- /dev/null +++ b/v0.10.x/posts/2020/2020-07-12-week-7-soham.html @@ -0,0 +1,541 @@ + + + + + + + + Orientation, Sizing, Tab UI. — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Orientation, Sizing, Tab UI.#

+

Hello and welcome to my 7th weekly check-in. I will be sharing my progress with single actor physics simulation and TextBlock2D sizing issue which was pending for quite a while now. I will also be sharing my thoughts regarding the TAB UI component. The official repository of my sub-org, FURY can always be found here.

+
+

What did you do this week?#

+

This week I was working with the orientation problem I mentioned in my previous check-in. I did have some problems regarding it, but thanks to my mentor I was able to figure it out and implement it with the help of scipy’s Quaternion to Rotation Matrix method. After understanding the orientation implementation, I spent some time regarding the design of the TAB UI component. I expect the design to be something similar as follows:

+https://user-images.githubusercontent.com/29832615/87254337-906b0b80-c49f-11ea-93f3-3af0f2d8de10.png +

Fortunately, we have good news this week. The TextBlock2D sizing issue that we were facing for quite a while has now been fixed. We simply have to keep track of the scene parameter in the _add_to_scene method of each UI component. This scene parameter inherits vtkViewport, hence it allows us to determine the necessary details about the environment of the 3D objects.

+
+
+

What is coming up next week?#

+

As the sizing issue regarding TextBlock2D has been fixed, I am very much eager to finish the remaining work left. ComboBox2D and TextBlock2D were left incomplete because of the issue. Therefore, my main objective next week would be to finish them first. Once I am done with it, I will move on to Tab UI. If not, I will continue with the physics simulation.

+
+
+

Did you get stuck anywhere?#

+

Apart from the orientation and sizing problem, I did not face any major issues.

+

Thank you for reading, see you next week!!

+
+
+ +
+ + + + +
+ + + + Previous: + + + + Translation, Reposition, Rotation. + + + +   + + + + Next: + + + Multiple SDF primitives. + + + + +
+ + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2020/2020-07-13-week-7-lenix.html b/v0.10.x/posts/2020/2020-07-13-week-7-lenix.html new file mode 100644 index 000000000..ece7701c5 --- /dev/null +++ b/v0.10.x/posts/2020/2020-07-13-week-7-lenix.html @@ -0,0 +1,542 @@ + + + + + + + + Multiple SDF primitives. — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Multiple SDF primitives.#

+

Make sure to check out Project FURY

+

Hey Everyone! +This week, multiple SDF primitives.

+
+

What did you do this week?#

+

The objective of this week was to understand the capabilities of the multiple SDF primitives within the same cube project. To get a clearer understanding of what we can achieve with this approach, i added support for real time rotating primitives. The output of 2 cubes with rotating SDFs is shown below.

+https://raw.githubusercontent.com/lenixlobo/fury-outputs/master/blog-week-7.gif +

The code for the above render is available at the branch

+
+
+

What is coming up next week?#

+

The task for next week is to implement features in the SDF actor and also to fix minor bugs within the shaders. Once everything is done as planned, the PR will be merged for users to access the features.

+
+
+

Did you get stuck anywhere?#

+

No issues this week

+
+
+ +
+ + + + + + + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2020/2020-07-19-week-8-soham.html b/v0.10.x/posts/2020/2020-07-19-week-8-soham.html new file mode 100644 index 000000000..c6492680a --- /dev/null +++ b/v0.10.x/posts/2020/2020-07-19-week-8-soham.html @@ -0,0 +1,547 @@ + + + + + + + + ComboBox2D, TextBlock2D, Clipping Overflow. — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

ComboBox2D, TextBlock2D, Clipping Overflow.#

+

Hello and welcome to my 8th weekly check-in. I will be sharing my progress with ComboBox2D and TextBlock2D UI components. After solving TextBlock2D sizing issue, I was finally able to complete the implementation of combo box. I also faced some problems while refactoring TextBlock2D. The official repository of my sub-org, FURY can always be found here.

+
+

What did you do this week?#

+

This week I finished the implementation of TextBlock2D and ComboBox2D. I also added necessary tests and tutorials to aid the implementation. It still needs some color design, which will be decided later on. Here’s an overview of the tutorial:

+https://user-images.githubusercontent.com/29832615/87884567-a8f19d80-ca2c-11ea-8fd2-e7e37b30602f.gif +

Its a simple tutorial where I change the color of the label based on the option selected on the combo box.

+

Now while refactoring TextBlock2D, I noticed that the Text Overflow workaround on ListBox2D broke and started acting weird. This was mainly because the size implementation was changed and the code that I wrote a few months back wasn’t relevant anymore. So I removed the previous code and had to re-implement the same. I later found out that I would be needing such an implementation for most of my UI components so I decided to create a separate method for clipping overflowing texts.

+

I had to figure out a specific algorithm to achieve this as the height and width of each characters were different and the combined width of multiple characters were not equal to the sum of their widths. I decided to go for a binary search implementation as it was faster compared to a simple linear checking algorithm. The said algorithm works as expected and is more effective compared to its previous implementation. I tweaked the previous combo box example to showcase this algorithm.

+https://user-images.githubusercontent.com/29832615/87884568-aabb6100-ca2c-11ea-9ab8-b05bdb8b0631.gif +

The extremely long text is now clipped correctly.

+
+
+

What is coming up next week?#

+

Next week, I have a couple of things to work on. Firstly, the single actor wall brick simulation is yet to be completed. Once I am done with that I will continue working on Tab UI and try to finish its skeletal implementation.

+
+
+

Did you get stuck anywhere?#

+

I did get stuck regarding the previous implementation of Text Overflow in ListBox2D. Before the current implementation it looked something like this:

+https://user-images.githubusercontent.com/29832615/87430848-6b8fa900-c603-11ea-87b8-327f6e7f2ee0.png +

Apart from that, I did not face any major issues.

+

Thank you for reading, see you next week!!

+
+
+ +
+ + + + +
+ + + + Previous: + + + + Multiple SDF primitives. + + + +   + + + + Next: + + + FURY 0.6.0 Released + + + + +
+ + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2020/2020-07-20-release-announcement.html b/v0.10.x/posts/2020/2020-07-20-release-announcement.html new file mode 100644 index 000000000..b587203d8 --- /dev/null +++ b/v0.10.x/posts/2020/2020-07-20-release-announcement.html @@ -0,0 +1,543 @@ + + + + + + + + FURY 0.6.0 Released — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

FURY 0.6.0 Released#

+

The FURY project is happy to announce the release of FURY 0.6.0! +FURY is a free and open source software library for scientific visualization and 3D animations.

+

You can show your support by adding a star on FURY github project.

+

The major highlights of this release are:

+
    +
  • Added new features: Picking and double-click callback.

  • +
  • Added Signed Distance Field actor.

  • +
  • Added a new UI ComboBox.

  • +
  • Added multiples primitives (Rhombocuboctahedron, …).

  • +
  • Huge improvement of multiple UIs and actors.

  • +
  • Fixed Compatibility with VTK9.

  • +
  • Large documentation update, examples and tutorials (5 new).

  • +
  • Added a blog system.

  • +
  • Increased tests coverage and code quality.

  • +
+
+

Note

+

The complete release notes are available here

+
+

To upgrade or install FURY

+

Run the following command in your terminal:

+
pip install --upgrade fury
+
+
+

or:

+
conda install -c conda-forge fury
+
+
+

Questions or suggestions?

+

For any questions go to http://fury.gl, or send an e-mail to fury@python.org +We can also join our discord community

+

We would like to thanks to all contributors for this release:

+
    +
  • Eleftherios Garyfallidis

  • +
  • Liam Donohue

  • +
  • Marc-Alexandre Côté

  • +
  • Melina Raglin

  • +
  • Naman Bansal

  • +
  • Serge Koudoro

  • +
  • Soham Biswas

  • +
  • Tushar

  • +
  • Lenix Lobo

  • +
+

On behalf of the FURY developers,

+

Serge K.

+
+ +
+ + + + + + + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2020/2020-07-20-week-8-lenix.html b/v0.10.x/posts/2020/2020-07-20-week-8-lenix.html new file mode 100644 index 000000000..dedb26122 --- /dev/null +++ b/v0.10.x/posts/2020/2020-07-20-week-8-lenix.html @@ -0,0 +1,545 @@ + + + + + + + + Improvements in SDF primitives. — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Improvements in SDF primitives.#

+

Make sure to check out Project FURY

+

Hey Everyone! +This week, Improvements in SDF primitives.

+
+

What did you do this week?#

+

Over the past few weeks i have been working on adding SDF based actors in FURY. The task for this week was to complete the remaining features such as support for scaling and rotation based on user direction for the actors. The main objective is to complete the SDF actor and make it ready to merge into the FURY codebase. Below are the outputs after added the improvements to the SDF primitives.

+

Scaling:

+https://raw.githubusercontent.com/lenixlobo/fury-outputs/master/blog-week-8b.gif +

Rotation based on passed directions:

+https://raw.githubusercontent.com/lenixlobo/fury-outputs/master/blog-week-8a.gif +

The code for the above render is available at the branch

+
+
+

What is coming up next week?#

+

Since the features are almost done the task for next week is clean the code and test for bugs. And then to eventually merge the sdf_actor into the fury codebase.

+
+
+

Did you get stuck anywhere?#

+

No major issues this week.

+
+
+ +
+ + + + +
+ + + + Previous: + + + + FURY 0.6.0 Released + + + +   + + + + Next: + + + Tab UI, TabPanel2D, Tab UI Tutorial. + + + + +
+ + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2020/2020-07-26-week-9-soham.html b/v0.10.x/posts/2020/2020-07-26-week-9-soham.html new file mode 100644 index 000000000..fcf415d4a --- /dev/null +++ b/v0.10.x/posts/2020/2020-07-26-week-9-soham.html @@ -0,0 +1,549 @@ + + + + + + + + Tab UI, TabPanel2D, Tab UI Tutorial. — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Tab UI, TabPanel2D, Tab UI Tutorial.#

+

Hello and welcome to my 9th weekly check-in. I will be sharing my progress with TabUI and its corresponding tutorial. The official repository of my sub-org, FURY can always be found here.

+
+

What did you do this week?#

+

This week I finished the basic implementation of TabUI. Apart from that I was also able to finish the tutorial which showcases different features of this said UI. With the help of this UI one can have multiple panels containing different UI elements within them. The basic implementation can be demonstrated as follows:

+https://user-images.githubusercontent.com/29832615/88484746-87456880-cf8e-11ea-9e96-9cba111b90d3.gif +

After finishing with the basic implementation I moved on to create its tutorial. For that, I decided to combine 3 of the existing UI tutorials to be rendered with the help of Tab UI. I implemented the following in individual tabs:

+
    +
  • Controlling a cube with the help of LineSlider2D and RingSlider2D.

  • +
  • Using a CheckBox to render a cylinder or a sphere or both.

  • +
  • Using ComboBox to set the color of a label.

  • +
+

The above tutorial can be demonstrated as follows:

+https://user-images.githubusercontent.com/29832615/88481324-6a9e3600-cf78-11ea-8c5b-e26bf158388a.gif +
+
+

What is coming up next week?#

+

Next week I will continue working on the Physics engine integration. Previously we were facing a problem regarding the uncontrollable spinning of objects rendered by a single actor. There must be an issue with mismatching axes alignment of FURY and pyBullet. The spinning problem is as following:

+https://user-images.githubusercontent.com/29832615/88485303-87476780-cf92-11ea-850c-cc63e1376ef8.gif +
+
+

Did you get stuck anywhere?#

+

I did get stuck with the collapsing functionality of Tab UI and the uncontrollable spinning of the bricks in the Physics simulation. Apart from that I did not face any major issues.

+

Thank you for reading, see you next week!!

+
+
+ +
+ + + + +
+ + + + Previous: + + + + Improvements in SDF primitives. + + + +   + + + + Next: + + + Merging SDF primitives. + + + + +
+ + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2020/2020-07-27-week-9-lenix.html b/v0.10.x/posts/2020/2020-07-27-week-9-lenix.html new file mode 100644 index 000000000..3a7772049 --- /dev/null +++ b/v0.10.x/posts/2020/2020-07-27-week-9-lenix.html @@ -0,0 +1,546 @@ + + + + + + + + Merging SDF primitives. — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Merging SDF primitives.#

+

Make sure to check out Project FURY

+

Hey Everyone! +This week, Merging SDF primitives.

+
+

What did you do this week?#

+

Since GSoC started I have been working on adding support for raymarching based SDF actors as primitives in the FURY codebase. This week with the release of FURY 0.6.0 , the task assigned to me was to complete the remaining parts of the SDF actor including tests and tutorial. THe SDF actor is now part of the FURY actor and can be accessed using sdf_actor. +Currently we support , ellipsoids, spheres and torus as primitive options. As expected, SDF based actors have shown tremendous performance improvements over traditional polygon based actor.

+

Despite using 100,000 torus the FPS is higher than 60 :

+https://raw.githubusercontent.com/lenixlobo/fury-outputs/master/blog-week-9.gif +

10,000 actors :

+https://raw.githubusercontent.com/lenixlobo/fury-outputs/master/blog-week-9b.gif +

I also made a tutorial for new users to get started here

+
+
+

What is coming up next week?#

+

Now that the SDF actor is merged , the next step is to focus on spherical harmonics and i will also be working on creating shader visualization to showcase the features of FURY

+
+
+

Did you get stuck anywhere?#

+

This week involved a lot of work , including making tests, tutorial and looking for bugs but everything went smoothly .

+
+
+ +
+ + + + +
+ + + + Previous: + + + + Tab UI, TabPanel2D, Tab UI Tutorial. + + + +   + + + + Next: + + + More Shaders!! + + + + +
+ + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2020/2020-08-02-week-10-lenix.html b/v0.10.x/posts/2020/2020-08-02-week-10-lenix.html new file mode 100644 index 000000000..9b706462a --- /dev/null +++ b/v0.10.x/posts/2020/2020-08-02-week-10-lenix.html @@ -0,0 +1,544 @@ + + + + + + + + More Shaders!! — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

More Shaders!!#

+

Make sure to check out Project FURY

+

Hey ! +This week, More Shaders!

+
+

What did you do this week?#

+

After merging the SDF actor last week , the mentors and I decided to work on another project idea which was discussed prior to GSoC . So the next step assigned to me was to look into the current shader framework and create immersive visualizations using shaders. Being interested in volumetric rendering I looked into volumetric cloud rendering algorithms and created a basic shader-based render in FURY.

+

The output for the same is given below:

+https://raw.githubusercontent.com/lenixlobo/fury-outputs/master/blog-week-10a.gif +https://raw.githubusercontent.com/lenixlobo/fury-outputs/master/blog-week-10b.gif +

The shader demos are available here

+
+
+

What is coming up next week?#

+

The main focus now is to discuss and work on shader demos which an demonstrate the capabilities of FURY

+
+
+

Did you get stuck anywhere?#

+

No issues were faced this week

+
+
+ +
+ + + + +
+ + + + Previous: + + + + Merging SDF primitives. + + + +   + + + + Next: + + + Single Actor, Physics, Scrollbars. + + + + +
+ + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2020/2020-08-02-week-10-soham.html b/v0.10.x/posts/2020/2020-08-02-week-10-soham.html new file mode 100644 index 000000000..d8e8c9ae1 --- /dev/null +++ b/v0.10.x/posts/2020/2020-08-02-week-10-soham.html @@ -0,0 +1,560 @@ + + + + + + + + Single Actor, Physics, Scrollbars. — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Single Actor, Physics, Scrollbars.#

+

Hello and welcome to my 10th weekly check-in. Second evaluation ended this week and now we move on to our 3rd and final coding period. In today’s check-in I will be sharing my progress with the single actor physics simulation that I facing some issues with and I will also be discussing my future plans regarding UI components. The official repository of my sub-org, FURY can always be found here.

+
+

What did you do this week?#

+

This week I was able to figure out the uncontrollable spinning problem that I was facing while rendering physics simulations. Specifically the simulation where a brick wall was rendered by a single actor. The spinning problem was as follows:

+https://user-images.githubusercontent.com/29832615/88485303-87476780-cf92-11ea-850c-cc63e1376ef8.gif +

Here’s how the fixed simulation looks like:

+https://user-images.githubusercontent.com/29832615/89126963-946ed400-d507-11ea-93cd-aad3a9f59ab0.gif +

I was facing this particular issue because I was directly syncing the orientation of the objects in pyBullet world to the objects in the Fury world. So I decided to apply the change in orientation instead and it worked. In order to achieve this I had to keep track of the bricks’ orientation at each step of the simulation, sync the change and then update the tracked orientation. Thankfully, pybullet had convenient tools to achieve this. Here’s a snippet on how to update individual objects rendered by a single actor:

+
def sync_brick(object_index, multibody):
+    pos, orn = p.getBasePositionAndOrientation(multibody)
+
+    rot_mat = np.reshape(
+        p.getMatrixFromQuaternion(
+            p.getDifferenceQuaternion(orn, brick_orns[object_index])),
+        (3, 3))
+
+    vertices[object_index * sec: object_index * sec + sec] = \
+        (vertices[object_index * sec: object_index * sec + sec] -
+        brick_centers[object_index])@rot_mat + pos
+
+    brick_centers[object_index] = pos
+    brick_orns[object_index] = orn
+
+
+

All the necessary information is updated here.

+
+
+

What is coming up next week?#

+

Currently, the scrollbars are native to ListBox2D only. We are planning to separate scrollbars from ListBox2D to create a standalone UI component. This was in progress previously but was later discontinued, so I was given the responsibility to complete it. After this we plan to improve File Dialog capabilities later on.

+
+
+

Did you get stuck anywhere?#

+

I did not face any major issues but it took me some time to understand and evaluate the existing discontinued PR regarding scrollbar separation.

+

Thank you for reading, see you next week!!

+
+
+ +
+ + + + + + + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2020/2020-08-09-week-11-lenix.html b/v0.10.x/posts/2020/2020-08-09-week-11-lenix.html new file mode 100644 index 000000000..dfaf76734 --- /dev/null +++ b/v0.10.x/posts/2020/2020-08-09-week-11-lenix.html @@ -0,0 +1,545 @@ + + + + + + + + More Shaders!! — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

More Shaders!!#

+

Make sure to check out Project FURY

+

Hey ! +This week, More Shaders!

+
+

What did you do this week?#

+

The task assigned for this week was to explore more shader techniques which could be implemented using FURY and which would demonstrate the capability of FURY shader system. So i decided to work on implementing shading examples such as Gooch shading and reflection shader using textures.

+

Below are the outputs of the techniques i worked on :

+https://raw.githubusercontent.com/lenixlobo/fury-outputs/master/blog-week-11a.gif +https://raw.githubusercontent.com/lenixlobo/fury-outputs/master/blog-week-11b.gif +https://raw.githubusercontent.com/lenixlobo/fury-outputs/master/blog-week-11c.gif +

The shader demos are available here

+
+
+

What is coming up next week?#

+

The next week will involve working on more such demos which can demonstrate the capabilities of FURY

+
+
+

Did you get stuck anywhere?#

+

No issues were faced this week

+
+
+ + + +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2020/2020-08-09-week-11-soham.html b/v0.10.x/posts/2020/2020-08-09-week-11-soham.html new file mode 100644 index 000000000..cedf33ed7 --- /dev/null +++ b/v0.10.x/posts/2020/2020-08-09-week-11-soham.html @@ -0,0 +1,548 @@ + + + + + + + + Chain Simulation, Scrollbar Refactor, Tutorial Update. — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Chain Simulation, Scrollbar Refactor, Tutorial Update.#

+

Hello and welcome to my 11th weekly check-in. In this blog I will be discussing my progress with multiple topics related to physics and ui components. I was actively working on a couple of things, specifically Joint simulations in pyBullet and scrollbar UI component. I also took up the responsibility to complete an incomplete Pull Request which was pending for quite a while. The official repository of my sub-org can be found here.

+
+

What did you do this week?#

+

The first thing that I did this week was to figure out joint simulations in pybullet. Due to lack of proper documentation I was not aware that Joints are kept stiff by default, hence I had no idea what was wrong with my simulations. Thankfully, while I was browsing pybullet forums, I found this post regarding rope simulations when I realized that I had to explicitly set the friction force to prevent stiffness among the Joints. Keeping this point in mind I was able to simulate the following Chain of hexagonal prisms:

+https://user-images.githubusercontent.com/29832615/89737601-b7613100-da8f-11ea-947f-a96c66caefae.gif +

This week I was mainly supposed to work on refactoring scrollbars as a standalone component. I have made some progress for now. I am able to render the scrollbars properly, with proper size, orientation and color but I am having some issues regarding its scrolling callbacks. I need to look further into it. Here’s a brief glimpse:

+https://user-images.githubusercontent.com/29832615/89738159-28a2e300-da94-11ea-9167-e825f82edf98.png +

This particular PR by a fellow contributor was pending for quite a while, so I decided to look into it and complete it. The objective of the PR was to add examples for the CheckBox and RadioButton UI components, but the problem was that the objects were not rendered using FURY API in the tutorial, so I decided to complete that. It was already a well made tutorial. I only had to replace the appropriate functions with FURY’s API calls.

+

The CheckBox tutorial:

+https://user-images.githubusercontent.com/29832615/89438967-20326b80-d767-11ea-8f47-e7711e900c9f.gif +

There’s still some internal issues while updating the colors of the cube which is currently being worked on by my mentors.

+

The RadioButton tutorial:

+https://user-images.githubusercontent.com/29832615/89438999-2e808780-d767-11ea-8b08-2a36a05294bc.gif +
+
+

What is coming up next week?#

+

Next week I will continue working on the scrollbar component and try to fix the issues that I am having with its callbacks. I will also try to work on the wrecking ball simulation.

+
+
+

Did you get stuck anywhere?#

+

Apart from the scrollbar callbacks and stiff joints, I did not face any major issues.

+

Thank you for reading, see you next week!!

+
+
+ +
+ + + + +
+ + + + Previous: + + + + Single Actor, Physics, Scrollbars. + + + +   + + + + Next: + + + More Shaders!! + + + + +
+ + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2020/2020-08-16-week-12-soham.html b/v0.10.x/posts/2020/2020-08-16-week-12-soham.html new file mode 100644 index 000000000..ed06437f6 --- /dev/null +++ b/v0.10.x/posts/2020/2020-08-16-week-12-soham.html @@ -0,0 +1,550 @@ + + + + + + + + Wrecking Ball Simulation, Scrollbars Update, Physics Tutorials. — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Wrecking Ball Simulation, Scrollbars Update, Physics Tutorials.#

+

Hello and welcome to my 12th weekly check-in. In this blog I will be discussing my progress with the wrecking ball simulation and my scrollbar separation work. Apart from this I have also finalized the physics simulation tutorials and have created a Pull Request to finally get it merged with the official repository. The official repository of my sub-org can be found here.

+
+

What did you do this week?#

+

This week I was mainly focusing on the wrecking ball simulation. This simulation is basically the combination of chain simulation and brick wall simulation. A sphere attached to a chain smashes a “NxNxN” brick wall. The simulation is as follows:

+https://user-images.githubusercontent.com/29832615/90336291-84232280-dff8-11ea-869b-21a99b203c31.gif +

There’s a rendering bug with the cylinders because of which the chain segments look weird. My mentors confirmed that this bug originated from VTK’s cylinder source method and they are currently working on it to fix it. The simulation will render correctly once that bug is fixed.

+

Regarding the scrollbar separation task, I was able to fix those callback issues that I was facing. The mouse callbacks on the scrollbar now work correctly:

+https://user-images.githubusercontent.com/29832615/90337280-1af2dd80-dfff-11ea-94c4-508121307583.gif +

I have also created a pull request to add the following physics simulations with proper documentation to the main repository:

+
    +
  • Brick Wall Simulation

  • +
  • Ball Collision Simulation

  • +
  • Chain Simulation

  • +
  • Wrecking Ball Simulation

  • +
+
+
+

What is coming up next week?#

+

Currently I am a bit confused with the implementation of scrollbars with UI components. I had a meeting with my mentor and he decided to help me out with this. So most probably I will be working with the scrollbar component and its implementation. Next week will also be the final week for GSoC 2020 before the evaluations start so I would work on getting the final documentation and formalities ready.

+
+
+

Did you get stuck anywhere?#

+

Apart from the scrollbar implementation idea, I did not face any major issues.

+

Thank you for reading, see you next week!!

+
+
+ +
+ + + + +
+ + + + Previous: + + + + More Shaders!! + + + +   + + + + Next: + + + Outline Picker + + + + +
+ + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2020/2020-08-17-week-12-lenix.html b/v0.10.x/posts/2020/2020-08-17-week-12-lenix.html new file mode 100644 index 000000000..5efdc8ef3 --- /dev/null +++ b/v0.10.x/posts/2020/2020-08-17-week-12-lenix.html @@ -0,0 +1,543 @@ + + + + + + + + Outline Picker — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Outline Picker#

+

Make sure to check out Project FURY

+

Hey ! +This week, Picking Outline!

+
+

What did you do this week?#

+

We needed a Outline feature in FURY to indicate which model we choose in the scene. So the task assigned was to find options to achieve this. There were two ways to do this, 1. Using shader and 2. Using Vtk PolyData Silhouette. Despite trying multiple implementation methods the shader approach was not working . I also tried using VTKs inbuilt function , but there is a bug when i use some models. When i choose a model, it renders outline for every polygon , which is not what we want to achieve. The bug is shown below:

+

Below are the outputs of the techniques i worked on :

+https://raw.githubusercontent.com/lenixlobo/fury-outputs/master/blog-week-12.gif +

The shader demos are available here

+
+
+

What is coming up next week?#

+

With the end of GSoC approaching soon, the next task is to create a PR which can help new users to test different shaders using UI to get started.

+
+
+

Did you get stuck anywhere?#

+

I still was not able to figure out how we can achieve the outline effect. Am currently looking into other approaches we could use

+
+
+ +
+ + + + + + + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2020/2020-08-18-release-announcement.html b/v0.10.x/posts/2020/2020-08-18-release-announcement.html new file mode 100644 index 000000000..60add9c39 --- /dev/null +++ b/v0.10.x/posts/2020/2020-08-18-release-announcement.html @@ -0,0 +1,539 @@ + + + + + + + + FURY 0.6.1 Released — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

FURY 0.6.1 Released#

+

The FURY project is happy to announce the release of FURY 0.6.1! +FURY is a free and open source software library for scientific visualization and 3D animations.

+

You can show your support by adding a star on FURY github project.

+

This Release is mainly a maintenance release. The major highlights of this release are:

+
    +
  • Added Shaders Manager.

  • +
  • Standardized colors across API.

  • +
  • Added a new UI Tab.

  • +
  • Added Physics Engine Tutorial.

  • +
  • Large documentation update, examples and tutorials (4 new).

  • +
  • Increased tests coverage and code quality.

  • +
+
+

Note

+

The complete release notes are available here

+
+

To upgrade or install FURY

+

Run the following command in your terminal:

+
pip install --upgrade fury
+
+
+

or:

+
conda install -c conda-forge fury
+
+
+

Questions or suggestions?

+

For any questions go to http://fury.gl, or send an e-mail to fury@python.org +We can also join our discord community

+

We would like to thanks to all contributors for this release:

+
    +
  • Eleftherios Garyfallidis

  • +
  • Javier Guaje

  • +
  • Lenix Lobo

  • +
  • Melina Raglin

  • +
  • Nasim Anousheh

  • +
  • Serge Koudoro

  • +
  • Soham Biswas

  • +
  • Vivek Choudhary

  • +
+

On behalf of the FURY developers,

+

Serge K.

+
+ +
+ + + + + + + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2020/2020-08-23-week-13-soham.html b/v0.10.x/posts/2020/2020-08-23-week-13-soham.html new file mode 100644 index 000000000..5e9b778c7 --- /dev/null +++ b/v0.10.x/posts/2020/2020-08-23-week-13-soham.html @@ -0,0 +1,560 @@ + + + + + + + + Part of the Journey is the end unless its Open Source! — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Part of the Journey is the end unless its Open Source!#

+

Hello and welcome to my final weekly check-in. Today officially marks the end of the coding period for GSoC 2020. I enjoyed every bit of it. This was a life-changing experience for me and now I observe and interpret everything from a different perspective altogether. I have grown into a better developer and a person since GSoC. I would like to thank all my mentors and especially Serge for his immense support and mentorship. I would love to contribute to fury even after GSoC is over but unfortunately my semester break is over so I won’t be as active as I was during the summer.

+

Now, regarding work I will be sharing my progress with the File Dialog UI component. The official repository of my sub-org can be found here.

+
+

What did you do this week?#

+

This week I worked on the File Dialog UI component. Fury previously had a FileMenu component which could browse through the file system but we needed a dialog like implementation for it so that its easier for the users to read and write files during runtime. I tried implementing a simple design for it. It specifically has two modes, one for saving files and the other for writing files. The implementation can be demonstrated as follows:

+
+

Open Dialog:#

+https://user-images.githubusercontent.com/29832615/90978632-df12c780-e56c-11ea-8517-6243ea06bdd2.gif +
+
+

Save Dialog:#

+https://user-images.githubusercontent.com/29832615/90978638-eafe8980-e56c-11ea-835a-3a82ccee2973.gif +
+
+
+

What is coming up next week?#

+

Next week I will start with my final GSoC documentation and code submission. I will also try to implement the tests and tutorials for File Dialog or any further changes requested by my mentors. If I am not able to finish it within the next week, I will get it done after GSoC.

+
+
+

Did you get stuck anywhere?#

+

I did not face any major issues this week.

+

Thank you all for your love and support. ❤️😄

+
+
+ +
+ + + + + + + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2020/2020-08-24-final-work-lenix.html b/v0.10.x/posts/2020/2020-08-24-final-work-lenix.html new file mode 100644 index 000000000..65a9d429e --- /dev/null +++ b/v0.10.x/posts/2020/2020-08-24-final-work-lenix.html @@ -0,0 +1,685 @@ + + + + + + + + Google Summer of Code 2020 Final Work Product — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +https://developers.google.com/open-source/gsoc/resources/downloads/GSoC-logo-horizontal.svg +https://www.python.org/static/community_logos/python-logo.png +https://python-gsoc.org/logos/FURY.png +
+

Google Summer of Code 2020 Final Work Product#

+ +
+

Introduction#

+

The current shader framework for FURY is based on VTK and lacks documentation to get started which can be overwhelming for new users. The objective of this project is to enable users to be easily able to understand and use the shader framework to render stunning visual representations of data. The project involves programming vertex and fragment shaders to generate effects for more immersive visualization.

+
+
+

Proposed Objectives#

+

Adding SDF actor to the API

+

This actor uses raymarching to model actors using SDF. The method provides several actors including ellipsoid, sphere and torus. +Shader demos

+
+

Use the FURY shader system to create and visualize different shading algorithms. Implementations include SphereMap, Toon, Gooch and Vertex Noise

+
+
+
+

Unsubmitted Functionalities#

+

Spherical Harmonics using Shaders.

+

The spherical harmonics algorithm is used to generate spherical surfaces using biases and coefficients computed. The general approach to achieve this is computationally expensive. The idea proposed was to leverage the GPU hardware using shaders to provide a faster more efficient alternative to the current implementations. The second month of the coding period was devoted to the same task but unfortunately, the observed performance was quite unsatisfactory than the expected performance. Moreover, the output shape of the geometry was distorted. It was then decided to continue the work after the GSoC period and prioritize the task at hand.

+

The Work in Progress can be accessed here. lenixlobo/fury

+

Dynamic Texture using Geometry Shader

+

Geometry Shaders provide a lot of flexibility to users to create custom geometry behaviors such as instancing. The idea was to create a dynamic Fur/Hair effect on top of a FURY actor. Unfortunately due to missing documentation on VTK geometry shaders and lack of resources, the project was not completed during the GSoC period. However, I will continue to try to solve the issue.

+

The source code for the current progress can be accessed here. lenixlobo/fury

+
+
+

Objectives Completed#

+

SDF based Actor

+
+

The objective here was to provide an alternative approach to users to use SDF modeled actors in the scene. This actor is modeled using the raymarching algorithm which provides much better performance than conventional polygon-based actors. Currently, the shapes supported include ellipsoid, sphere and torus

+

Pull Requests: +SDF Actor method: fury-gl/fury#250

+
+

Multiple SDF Actor

+
+

The objective was to create a method through which multiple SDF primitives are rendered within a single cube. This task helped us explore the limitations of the shader system and also benchmarking the performance.

+

Pull Requests: +MultiSDF Shader: fury-gl/fury

+
+

Shader Demos

+
+

The task here was to create a pull request showcasing the capabilities of the FURY shader system and to also provide examples or new users to get started with integrating custom shaders into the scenes.

+

Pull Requests: +Shader Demos: fury-gl/fury#296

+
+
+
+

Other Objectives#

+ +
+
+

Timeline#

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Date

Description

Blog Link

Week 1(30-05-2020)

Welcome to my GSoC Blog!

Weekly Check-in #1

Week 2(07-06-2020)

Geometry Shaders!

Weekly Check-in #2

Week 3(14-06-2020)

Ray Marching!

Weekly Check-in #3

Week 4(21-06-2020)

RayMarching Continued

Weekly Check-in #4

Week 5(28-06-2020)

Spherical Harmonics

Weekly Check-in #5

Week 6(05-07-2020)

Spherical Harmonics Continued

Weekly Check-in #6

Week 7(12-07-2020)

Multiple SDF Primitives

Weekly Check-in #7

Week 8(19-07-2020)

Improvements in SDF primitives

Weekly Check-in #8

Week 9(26-07-2020)

Merging SDF Actor and Benchmarks!

Weekly Check-in #9

Week 10(02-08-2020)

More Shaders

Weekly Check-in #10

Week 11(08-08-2020)

Even More Shaders

Weekly Check-in #11

Week 12(16-08-2020)

Picking Outline

Weekly Check-in #12

Week 13(23-08-2020)

Final Week

Weekly Check-in #13

+

Detailed weekly tasks and work done can be found +here.

+
+
+ + + +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2020/2020-08-24-final-work-soham.html b/v0.10.x/posts/2020/2020-08-24-final-work-soham.html new file mode 100644 index 000000000..7753666d0 --- /dev/null +++ b/v0.10.x/posts/2020/2020-08-24-final-work-soham.html @@ -0,0 +1,793 @@ + + + + + + + + Google Summer of Code Final Work Product — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +https://developers.google.com/open-source/gsoc/resources/downloads/GSoC-logo-horizontal.svg +https://www.python.org/static/community_logos/python-logo.png +https://python-gsoc.org/logos/FURY.png +
+

Google Summer of Code Final Work Product#

+ +
+

Proposed Objectives#

+
    +
  • ComboBox

  • +
  • Tab UI

  • +
  • File Dialog Improvements

  • +
+
+
+

Modified Objectives#

+
    +
  • Combobox

  • +
  • Tab UI

  • +
  • File Dialog Improvements

  • +
  • Double Click Callback

  • +
  • TextBlock2D Improvements

  • +
  • Scrollbars as a Standalone Component

  • +
  • Physics Engine Integration

  • +
+
+
+

Objectives Completed#

+
    +
  • ComboBox2D UI Component

    +

    A combobox is a commonly used graphical user interface widget. +Traditionally, it is a combination of a drop-down list or list box and a +single-line textbox, allowing the user to select a value from the list. +The term “combo box” is sometimes used to mean “drop-down list”. +Respective components, tests and tutorials were created.

    +

    Pull Requests:

    + +
  • +
  • Tab UI Component

    +

    In interface design, a tabbed document interface or Tab is a graphical +control element that allows multiple documents or panels to be contained +within a single window, using tabs as a navigational widget for +switching between sets of documents. Respective components, tests and +tutorials were created.

    +

    Pull Requests:

    + +
  • +
  • Double Click Callback

    +

    Double click callbacks aren’t implemented in VTK by default so they need +to be implemented manually. With my mentor’s help I was able to +implement double click callbacks for all the three mouse buttons +successfully.

    +

    Pull Requests:

    + +
  • +
  • TextBlock2D Improvements

    +

    The previous implementation of TextBlock2D was lacking a few +features such as size arguments and text overflow. There was no specific +way to create Texts occupying a said height or width area. Apart from +that UI components like ListBoxItem2D, FileMenu2D etc had an +issue where text would overflow from their specified width. In order to +tackle these problems, a modification was done to TextBlock2D to +accept size as an argument and a new method was added to clip +overflowing text based on a specified width and to replace the +overflowing characters with ....

    +

    Pull Requests:

    + +
  • +
  • Physics Engine Integration

    +

    Optional support for Physics engine integration of Pybullet was added to +Fury. Pybullet’s engine was used for the simulations and FURY was used +for rendering the said simulations. Exhaustive examples were added to +demonstrate various types of physics simulations possible using pybullet +and fury. The said examples are as follows:

    +
      +
    • Brick Wall Simulation

      +
        +
      • Explains how to render and simulate external forces, objects and +gravity.

      • +
      +
    • +
    • Ball Collision Simulation

      +
        +
      • Explains how collisions work and how to detect said collisions.

      • +
      +
    • +
    • Chain Simulation

      +
        +
      • Explains how to render and simulate joints.

      • +
      +
    • +
    • Wrecking Ball Simulation

      +
        +
      • A more complicated simulation that combines concepts explained by +the other examples.

      • +
      +
    • +
    +

    Apart from that, a document was created to explain the integration +process between pybullet and fury in detail.

    +

    Pull Requests:

    + +
  • +
+
+
+

Objectives in Progress#

+
    +
  • Scrollbars as a standalone component

    +

    The previous implementation of scrollbars were hard coded into +ListBox2D. Therefore, it was not possible to use scrollbars with any +other UI component. Apart from that, scrollbars in terms of design were +limited. Creating a horizontal scrollbar was not possible. The objective +of this PR is to make scrollbars separate so that other UI elements can +also make use of it.

    +

    Currently, the skeletal and design aspects of the scrollbars are +implemented but the combination of scrollbars with other UI components +are still in progress.

    +

    Pull Requests:

    + +
  • +
  • File Dialog Improvements

    +

    Currently, we have access to FileMenu2D which allows us to navigate +through the filesystem but it does not provide a user friendly Dialog to +read and write files in Fury. Hence the idea is to create a file dialog +which can easily open or save file at runtime. As of now, Open and +Save operations are implemented. Corresponding tests and tutorials +are in progress.

    +

    Pull Requests:

    + +
  • +
+
+
+

Other Objectives#

+
    +
  • Radio Checkbox Tutorial using FURY API

    +

    The objects for Radio button and Checkbox tutorial were rendered using +VTK’s method by a fellow contributor so I decided to replace them with +native FURY API. The methods were rewritten keeping the previous commits +intact.

    +

    Pull Requests:

    + +
  • +
  • GSoC weekly Blogs

    +

    Weekly blogs were added for FURY’s Website.

    +

    Pull Requests:

    + +
  • +
+
+
+

Timeline#

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Date

Description

Blog Link

Week 1(30-05-2020)

Welcome to my GSoC Blog!!

Weekly Check-in #1

Week 2(07-06-2020)

First Week of Coding!!

Weekly Check-in #2

Week 3(14-06-2020)

ComboBox2D Progress!!

Weekly Check-in #3

Week 4(21-06-2020)

TextBlock2D Progress!!

Weekly Check-in #4

Week 5(28-06-2020)

May the Force be with you!!

Weekly Check-in #5

Week 6(05-07-2020)

Translation, Reposition, Rotation.

Weekly Check-in #6

Week 7(12-07-2020)

Orientation, Sizing, Tab UI.

Weekly Check-in #7

Week 8(19-07-2020)

ComboBox2D, TextBlock2D, ClippingOverflow.

Weekly Check-in #8

Week 9(26-07-2020)

Tab UI, TabPanel2D, Tab UI Tutorial.

Weekly Check-in #9

Week 10(02-08-2020)

Single Actor, Physics, Scrollbars.

Weekly Check-in #10

Week 11(09-08-2020)

Chain Simulation, Scrollbar Refactor,Tutorial Update.

Weekly Check-in #11

Week 12(16-08-2020)

Wrecking Ball Simulation, ScrollbarsUpdate, Physics Tutorials.

Weekly Check-in #12

Week 13(23-08-2020)

Part of the Journey is the end unless itsOpen Source!

Weekly Check-in #13

+

Detailed weekly tasks and work done can be found +here.

+
+
+ +
+ + + + +
+ + + + Previous: + + + + Google Summer of Code 2020 Final Work Product + + + +   + + + + Next: + + + Shader Showcase + + + + +
+ + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2020/2020-08-24-week-13-lenix.html b/v0.10.x/posts/2020/2020-08-24-week-13-lenix.html new file mode 100644 index 000000000..80c371d11 --- /dev/null +++ b/v0.10.x/posts/2020/2020-08-24-week-13-lenix.html @@ -0,0 +1,545 @@ + + + + + + + + Shader Showcase — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Shader Showcase#

+

Make sure to check out Project FURY

+

Hey Everyone! +Today marked the official end of the coding period for Google Summer of Code 2020. On this day I would like to take the opportunity to thank all my mentors and Soham who have shown immense support during this time and helped me grow not only to be a better programmer but also to be a better team member. While the GSoC period ends, I will try my best to be active and contribute to the project and help it grow. +Cheers!

+
+

What did you do this week?#

+

This being the final week of GSoC , my task was to create a PR which showcases not only the shader capabilities of the project but also to create a example which integrates both the UI and shader system of project FURY. This example can help new users to get familiar with both the UI and shaders. +Apart from this i also worked on a Toon Shader.

+

The output for the above task is given below :

+https://raw.githubusercontent.com/lenixlobo/fury-outputs/master/blog-week-13.gif +

The shader demos are available here

+
+
+

What is coming up next week?#

+

The next week I will work on the final GSoC documentation which explains what I worked on throughout the GSoC period. In case of any changes are requested by the mentors I will also try to implement them.

+
+
+

Did you get stuck anywhere?#

+

With the help of Soham and the mentors this week went smoothly.

+
+
+ +
+ + + + +
+ + + + Previous: + + + + Google Summer of Code Final Work Product + + + +   + + + + Next: + + + Google Summer of Code + + + + +
+ + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2021/2021-03-09-gsoc.html b/v0.10.x/posts/2021/2021-03-09-gsoc.html new file mode 100644 index 000000000..19d5d386e --- /dev/null +++ b/v0.10.x/posts/2021/2021-03-09-gsoc.html @@ -0,0 +1,504 @@ + + + + + + + + Google Summer of Code — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Google Summer of Code#

+

FURY is participating in the Google Summer of Code 2021 under the umbrella of the Python Software Foundation.

+

FURY is a free and open source software library for scientific visualization and 3D animations. FURY contains many tools for visualizing a series of scientific data including graph and imaging data.

+

A list of project ideas and application info is on our GitHub Wiki.

+

If you are interested in talking to us about projects, applications join us to our discord community or drop us a line on our mailing list.

+

Be part of our community and Enjoy your summer of code!

+

Serge K.

+
+ +
+ + + + +
+ + + + Previous: + + + + Shader Showcase + + + +   + + + + Next: + + + FURY 0.7.0 Released + + + + +
+ + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2021/2021-03-13-release-announcement.html b/v0.10.x/posts/2021/2021-03-13-release-announcement.html new file mode 100644 index 000000000..987172067 --- /dev/null +++ b/v0.10.x/posts/2021/2021-03-13-release-announcement.html @@ -0,0 +1,547 @@ + + + + + + + + FURY 0.7.0 Released — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

FURY 0.7.0 Released#

+

The FURY project is happy to announce the release of FURY 0.7.0! +FURY is a free and open source software library for scientific visualization and 3D animations.

+

You can show your support by adding a star on FURY github project.

+

This Release is mainly a maintenance release. The major highlights of this release are:

+
    +
  • New SDF actors added.

  • +
  • Materials module added.

  • +
  • ODF slicer actor performance improved.

  • +
  • New primitive (Cylinder) added.

  • +
  • Compatibility with VTK 9 added.

  • +
  • Five new demos added.

  • +
  • Large Documentation Update.

  • +
  • Migration from Travis to Github Action.

  • +
+
+

Note

+

The complete release notes are available here

+
+

To upgrade or install FURY

+

Run the following command in your terminal:

+
pip install --upgrade fury
+
+
+

or:

+
conda install -c conda-forge fury
+
+
+

Questions or suggestions?

+

For any questions go to http://fury.gl, or send an e-mail to fury@python.org +We can also join our discord community

+

We would like to thanks to all contributors for this release:

+
    +
  • Eleftherios Garyfallidis

  • +
  • Serge Koudoro

  • +
  • Charles Poirier

  • +
  • Javier Guaje

  • +
  • Soham Biswas

  • +
  • Sajag Swami

  • +
  • Lenix Lobo

  • +
  • Pietro Astolfi

  • +
  • Sanjay Marreddi

  • +
  • Tushar

  • +
  • ganimtron-10

  • +
  • haran2001

  • +
  • Aju100

  • +
  • Aman Soni

  • +
+

On behalf of the FURY developers,

+

Serge K.

+
+ +
+ + + + +
+ + + + Previous: + + + + Google Summer of Code + + + +   + + + + Next: + + + Week #1: Welcome to my weekly Blogs! + + + + +
+ + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2021/2021-06-08-gsoc-devmessias-1.html b/v0.10.x/posts/2021/2021-06-08-gsoc-devmessias-1.html new file mode 100644 index 000000000..9fab0d84f --- /dev/null +++ b/v0.10.x/posts/2021/2021-06-08-gsoc-devmessias-1.html @@ -0,0 +1,560 @@ + + + + + + + + Weekly Check-In #1 — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Weekly Check-In #1#

+

Hi everyone! My name is Bruno Messias currently I’m a Ph.D student at +USP/Brazil. In this summer I’ll develop new tools and features for +FURY-GL. Specifically, I’ll focus into developing a system for +collaborative visualization of large network layouts using FURY and VTK.

+
+

What did I do this week?#

+

In my first meeting the mentors explained the rules and the code of +conduct inside the FURY organization. We also made some modifications in +the timeline and discussed the next steps of my project. I started +coding during the community bonding period. The next paragraph shows my +contributions in the past weeks

+
    +
  • A FURY/VTK webrtc stream system proposal: to the second part of my +GSoC project I need to have a efficiently and easy to use streaming +system to send the graph visualizations across the Internet. In +addition, I also need this to my Ph.D. Therefore, I’ve been working a +lot in this PR. This PR it’s also help me to achieve the first part +of my project. Because I don’t have a computer with good specs in my +house and I need to access a external computer to test the examples +for large graphs.

  • +
  • Minor improvements into the shader markers PR and fine tuning +open-gl state PR.

  • +
+
+
+

Did I get stuck anywhere?#

+

I’ve been stuck into a performance issue (copying the opengl framebuffer +to a python rawarray) which caused a lot of lag in the webrtc streamer. +Fortunately, I discovered that I’ve been using rawarrays in the wrong +way. My commit solved this performance issue.

+
+
+

What is coming up next?#

+

In this week I’ll focus on finish the #432 and #422 pull-requests.

+
+
+ +
+ + + + +
+ + + + Previous: + + + + Week #1: Welcome to my weekly Blogs! + + + +   + + + + Next: + + + Welcome to my GSoC Blog! + + + + +
+ + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2021/2021-06-08-week-1-antriksh.html b/v0.10.x/posts/2021/2021-06-08-week-1-antriksh.html new file mode 100644 index 000000000..46cf9aa0d --- /dev/null +++ b/v0.10.x/posts/2021/2021-06-08-week-1-antriksh.html @@ -0,0 +1,544 @@ + + + + + + + + Week #1: Welcome to my weekly Blogs! — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Week #1: Welcome to my weekly Blogs!#

+

Hi everyone! I am Antriksh Misri. I am a Pre-Final year student at MIT Pune. This summer, I will be working on Layout Management under FURY’s UI module as my primary goal. This includes addition of different classes under Layout Management to provide different layouts/arrangements in which the UI elements can be arranged. As my stretch goals, I will be working on a couple of UI components for FURY’s UI module. These 2D and 3D components will be sci-fi like as seen in the movie “Guardians of The Galaxy”. My objective for the stretch goals would be to develop these UI components with their respective test and tutorials such that it adds on to the UI module of FURY and doesn’t hinder existing functionalities/performance.

+
+

What did I do this week?#

+

During the community bonding period I got to know the mentors as well as other participants. We had an introductory meeting, in which the rules and code of conduct was explained. Also, my proposal was reviewed and modified slightly. Initially, I had to develop UI elements as my primary goal and I had to work on layout management as my stretch goals but the tasks were switched. Now I have to work on Layout Management as my primary task and develop UI in the stretch goals period. I also started coding before hand to actually make use of this free period. I worked on different PR’s which are described below:-

+ +
+
+

Did I get stuck anywhere?#

+

I got stuck at Panel resizing feature. I couldn’t figure out how to propagate the window invoked events to a specific actor. Fortunately, the mentors helped me to solve this problem by using partial from functools.

+
+
+

What is coming up next?#

+

The next tasks will be decided in this week’s open meeting with the mentors.

+

See you guys next week!

+
+
+ +
+ + + + +
+ + + + Previous: + + + + FURY 0.7.0 Released + + + +   + + + + Next: + + + Weekly Check-In #1 + + + + +
+ + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2021/2021-06-08-week-1-sajag.html b/v0.10.x/posts/2021/2021-06-08-week-1-sajag.html new file mode 100644 index 000000000..c29ff9ccb --- /dev/null +++ b/v0.10.x/posts/2021/2021-06-08-week-1-sajag.html @@ -0,0 +1,553 @@ + + + + + + + + Welcome to my GSoC Blog! — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Welcome to my GSoC Blog!#

+

Hi all! +I’m Sajag Swami, a sophomore at Indian Institute of Technology, Roorkee. This summer, I will be working on adding a new functionality to FURY which shall enable users to +visualise various types of proteins via different representations like Richardson aka Ribbon diagrams and molecular surface diagrams. +As a part of my stretch goals, I’ll try to expand protein diagrams via other representations including:

+
    +
  1. Stick

  2. +
  3. Ball and stick

  4. +
  5. Wire

  6. +
  7. Pipes and Planks

  8. +
  9. Sphere

  10. +
+
+

What did you do during the Community Bonding Period?#

+

I had weekly meetings with my mentors and other core team members. In the first meeting I got acquainted with the team members and learnt about the organisation and its goal/vision. +In the later meetings we discussed about various representations of proteins and how to go about implementing them in FURY. +We discussed about various libraries which can be used to parse PDB and PDBx files. +I made a document for the same to list pros and cons of using each library. +I worked upon my previous PR too during the community bonding period and fixed its docstring syntax.

+

As my college ended early courtesy covid, I had extra time during which I experimented and learnt more about PDB and PDBx files - the details they contain and how to parse them. +A small backbone visualisation of 1mb0 protein made on FURY by extracting coordinate data of its alpha carbons:

+
+https://github.com/SunTzunami/gsoc2021_blog_data/blob/master/visuals/week1_backbone.png?raw=true +
+
+
+

What is coming up next week?#

+

I have two major goals for the next week:

+
    +
  1. Make an actor for the space filling model of the proteins and make PR for the same which will also include the unit tests and a small tutorial for the users.

  2. +
  3. Try to understand the documentation of vtkProteinRibbonFilter which will prove beneficial in generating Ribbon diagrams.

  4. +
+

Au Revoir!

+
+
+ +
+ + + + +
+ + + + Previous: + + + + Weekly Check-In #1 + + + +   + + + + Next: + + + A Stadia-like system for data visualization + + + + +
+ + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2021/2021-06-12-gsoc-devmessias-2.html b/v0.10.x/posts/2021/2021-06-12-gsoc-devmessias-2.html new file mode 100644 index 000000000..b94be6241 --- /dev/null +++ b/v0.10.x/posts/2021/2021-06-12-gsoc-devmessias-2.html @@ -0,0 +1,660 @@ + + + + + + + + A Stadia-like system for data visualization — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

A Stadia-like system for data visualization#

+

Hi all! In this post I’ll talk about the PR +#437.

+

There are several reasons to have a streaming system for data +visualization. Because I’m doing a PhD in a developing country I always +need to think of the cheapest way to use the computational resources +available. For example, with the GPUs prices increasing, it’s necessary +to share a machine with a GPU with different users in different +locations. Therefore, to convince my Brazilian friends to use FURY I +need to code thinking inside of the (a) low-budget scenario.

+

To construct the streaming system for my project I’m thinking about the +following properties and behaviors:

+
    +
  1. I want to avoid blocking the code execution in the main thread (where +the vtk/fury instance resides).

  2. +
  3. The streaming should work inside of a low bandwidth environment.

  4. +
  5. I need an easy way to share the rendering result. For example, using +the free version of ngrok.

  6. +
+

To achieve the property 1. we need to circumvent the GIL problem. +Using the threading module alone it’s not good enough because we can’t +use the python-threading for parallel CPU computation. In addition, to +achieve a better organization it’s better to define the server system as +an uncoupled module. Therefore, I believe that multiprocessing-lib in +python will fit very well for our proposes.

+

For the streaming system to work smoothly in a low-bandwidth scenario we +need to choose the protocol wisely. In the recent years the WebRTC +protocol has been used in a myriad of applications like google hangouts +and Google Stadia aiming low latency behavior. Therefore, I choose the +webrtc as my first protocol to be available in the streaming system +proposal.

+

To achieve the third property, we must be economical in adding +requirements and dependencies.

+

Currently, the system has some issues, but it’s already working. You can +see some tutorials about how to use this streaming system +here. +After running one of these examples you can easily share the results and +interact with other users. For example, using the ngrok For example, +using the ngrok

+
./ngrok http 8000
+
+
+
+

+
+
+

How does it works?#

+

The image below it’s a simple representation of the streaming system.

+

image1

+

As you can see, the streaming system is made up of different processes +that share some memory blocks with each other. One of the hardest part +of this PR was to code this sharing between different objects like VTK, +numpy and the webserver. I’ll discuss next some of technical issues that +I had to learn/circumvent.

+
+

Sharing data between process#

+

We want to avoid any kind of unnecessary duplication of data or +expensive copy/write actions. We can achieve this economy of +computational resources using the multiprocessing module from python.

+
+

multiprocessing RawArray#

+
+
The +RawArray +from multiprocessing allows to share resources between different +processes. However, there are some tricks to get a better performance +when we are dealing with RawArray’s. For example, take a look at my +PR in a older +stage. +In this older stage my streaming system was working well. However, one +of my mentors (Filipi Nascimento) saw a huge latency for +high-resolutions examples. My first thought was that latency was +caused by the GPU-CPU copy from the opengl context. However, I +discovered that I’ve been using RawArray’s wrong in my entire life!
+
See for example this line of code +fury/stream/client.py#L101 +The code below shows how I’ve been updating the raw arrays
+
+
raw_arr_buffer[:] = new_data
+
+
+

This works fine for small and medium sized arrays, but for large ones it +takes a large amount of time, more than GPU-CPU copy. The explanation +for this bad performance is available here : Demystifying sharedctypes +performance. +The solution which gives a stupendous performance improvement is quite +simple. RawArrays implements the buffer protocol. Therefore, we just +need to use the memoryview:

+
memview(arr_buffer)[:] = new_data
+
+
+

The memview is really good, but there it’s a little issue when we are +dealing with uint8 RawArrays. The following code will cause an exception:

+
memview(arr_buffer_uint8)[:] = new_data_uint8
+
+
+

There is a solution for uint8 rawarrays using just memview and cast +methods. However, numpy comes to rescue and offers a simple and a +generic solution. You just need to convert the rawarray to a np +representation in the following way:

+
arr_uint8_repr = np.ctypeslib.as_array(arr_buffer_uint8)
+arr_uint8_repr[:] = new_data_uint8
+
+
+

You can navigate to my repository in this specific commit +position +and test the streaming examples to see how this little modification +improves the performance.

+
+
+
+

Multiprocessing inside of different Operating Systems#

+

Serge Koudoro, who is one of my mentors, has pointed out an issue of the +streaming system running in MacOs. I don’t know many things about MacOs, +and as pointed out by Filipi the way that MacOs deals with +multiprocessing is very different than the Linux approach. Although we +solved the issue discovered by Serge, I need to be more careful to +assume that different operating systems will behave in the same way. If +you want to know more,I recommend that you read this post Python: +Forking vs +Spawm. +And it’s also important to read the official documentation from python. +It can save you a lot of time. Take a look what the +official python documentation says about the multiprocessing method

+

image2 Source:https://docs.python.org/3/library/multiprocessing.html

+
+
+
+ +
+ + + + + + + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2021/2021-06-13-week-2-antriksh.html b/v0.10.x/posts/2021/2021-06-13-week-2-antriksh.html new file mode 100644 index 000000000..f41d6a488 --- /dev/null +++ b/v0.10.x/posts/2021/2021-06-13-week-2-antriksh.html @@ -0,0 +1,544 @@ + + + + + + + + Week #2: Feature additions in UI and IO modules — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Week #2: Feature additions in UI and IO modules#

+
+

What did I do this week?#

+

This week I had to work on 3 PRs as well as some documentation. I really enjoyed this week’s work as the tasks were really interesting. The aim for these PRs were to actually add a couple of features in the UI as well as the IO module, which includes, adding support for border in Panel2D, adding support for network/URL images in load_image method in IO module, adding resizing Panel2D from bottom right corner, completing the document with layout solutions provided by Unity/Unreal engine. Below are the PRs that I worked on:

+
    +
  • Added support for URL image in load_image : The load_image of IO module didn’t support network /URL images, so I made this PR to add support for the same.

  • +
  • Added support for border in Panel2D : This PR was made in association with the Card2D PR. This PR adds support for border in Panel2D. The borders are individually customizable just like in CSS. This PR needs a little tweaking in terms of getters/setters. The same support needs to be added in Rectangle2D.

  • +
  • Complete the document with layout solutions provided by Unity/Unreal engine : Completed the document with layout solutions provided by Unity/Unreal Engine.

  • +
  • Behind the scenes I also worked on a Watcher class for the UI elements. The purpose of the watcher would be to monitor the UI elements for any changes after they have been added to the scene. A PR should be up by 2-3 days.

  • +
+
+
+

Did I get stuck anywhere?#

+

I had a minor issue with the tests for the IO module. When running the tests for IO module using pytest 5.0.0 resulted in Window fatal error, this was a sideeffect of pytest 5.0.0 wherein support for faulthandler was added. This error was suppressed by using certain flags while running the tests.

+
+
+

What is coming up next?#

+

Next week I would probably work on adapting the GridLayout with UI elements, some other tasks that will be decided in the next meeting.

+

See you guys next week!

+
+
+ +
+ + + + + + + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2021/2021-06-14-week-2-sajag.html b/v0.10.x/posts/2021/2021-06-14-week-2-sajag.html new file mode 100644 index 000000000..296ada0a1 --- /dev/null +++ b/v0.10.x/posts/2021/2021-06-14-week-2-sajag.html @@ -0,0 +1,560 @@ + + + + + + + + First week of coding! — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

First week of coding!#

+

Welcome to the second weekly check-in. I’ll be sharing my progress for the first week of coding.

+
+

What did you do this week?#

+

I implemented the space filling model for proteins and created a PR for the same. Preview:

+
+https://user-images.githubusercontent.com/65067354/121518963-b92cb580-ca0e-11eb-8232-3512edc04670.png +
+

(protein rendered: 3pgk)#

+
+
+

The PR has:

+
    +
  1. Actor for space_filling_model.

  2. +
  3. Two examples where I show how to visualize the proteins:

    +
      +
    1. In example 1, I parse a PDBx file myself and extract the atomic info essential for constructing the model which is then used by the actor to visualize it.

    2. +
    3. In example 2, I parse a PDB file by using Biopython module and extract the atomic info essential for constructing the model which is then used by the actor to visualize it.

    4. +
    +
  4. +
+

I created a basic test for the actor which needs to be improved. I’ll discuss how to improve the test with the mentors.

+
+
+

What is coming up next week?#

+

I have two major goals for the next week:

+
    +
  1. Make an actor for the space filling model of the proteins and make PR for the same which will also include the unit tests and a small tutorial for the users.

  2. +
  3. Try to understand the documentation of vtkProteinRibbonFilter which will prove beneficial in generating Ribbon diagrams.

  4. +
+
+
+

Did you get stuck anywhere?#

+

I tried to create a class in python which inherits from a vtk class called vtkMoleculeReaderBase but was unsuccessful in this endeavour. I’ll try to find a workaround.

+

Au Revoir!

+
+
+ +
+ + + + + + + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2021/2021-06-21-gsoc-devmessias-3.html b/v0.10.x/posts/2021/2021-06-21-gsoc-devmessias-3.html new file mode 100644 index 000000000..4325ea684 --- /dev/null +++ b/v0.10.x/posts/2021/2021-06-21-gsoc-devmessias-3.html @@ -0,0 +1,597 @@ + + + + + + + + Weekly Check-In #3 — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Weekly Check-In #3#

+
+

What did you do this week?#

+ +
+
+

Did I get stuck anywhere?#

+
+

A python-core issue#

+

I’ve spent some hours trying to discover this issue. But now it’s solved +through the commit +devmessias/fury/commit/071dab85

+

The SharedMemory +from python>=3.8 offers a new a way to share memory resources between +unrelated process. One of the advantages of using the SharedMemory +instead of the RawArray from multiprocessing is that the SharedMemory +allows to share memory blocks without those processes be related with a +fork or spawm method. The SharedMemory behavior allowed to achieve our +jupyter integration and simplifies the use of the streaming +system. +However, I saw a issue in the shared memory implementation.

+

Let’s see the following scenario:

+
1-Process A creates a shared memory X
+2-Process A creates a subprocess B using popen (shell=False)
+3-Process B reads X
+4-Process B closes X
+5-Process A kills B
+4-Process A closes  X
+5-Process A unlink() the shared memory resource X
+
+
+

The above scenario should work flawless. Calling unlink() in X is the right way as +discussed in the python official documentation. However, there is a open +issue related the unlink method

+ +

Fortunately, I could use a +monkey-patching solution to fix +that meanwhile we wait to the python-core team to fix the +resource_tracker (38119) issue.

+
+
+
+

What is coming up next?#

+

I’m planning to work in the +fury-gl/fury#432 and +fury-gl/helios#1.

+
+
+ +
+ + + + + + + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2021/2021-06-21-week-3-antriksh.html b/v0.10.x/posts/2021/2021-06-21-week-3-antriksh.html new file mode 100644 index 000000000..01ae3ca67 --- /dev/null +++ b/v0.10.x/posts/2021/2021-06-21-week-3-antriksh.html @@ -0,0 +1,548 @@ + + + + + + + + Week #3: Adapting GridLayout to work with UI — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Week #3: Adapting GridLayout to work with UI#

+
+

What did I do this week?#

+

This week my tasks revolved around layout and UI elements. The primary goal for this week was to adapt the GridLayout to work with different UI elements. Currently, GridLayout just supports vtk actors and not UI elements, my task was to modify the class to support UI elements. The other tasks for this week are described below in detail:

+
    +
  • Adapt GridLayout to support UI elements : This was the main task for the week and the aim for this was to actually modify GridLayout to support UI elements. This was not possible before because GridLayout only supported vtk actors (because of certain methods only being provided by vtk actors). I modified the main class itself along with some utility functions. The problem that I faced during this was circular imports. Currently, the structure of FURY doesn’t allow certain modules to be imported into other modules because of circular imports. A way to get around this was to actually import the modules inside the methods but this is not ideal always. This will be fixed in the future PRs where the UI module will be redesigned. I also added support for grid position offsetting, which basically means that the position of the UI elements that are placed in the Grid can be offset by a global offset passed in the constructor of GridLayout class. Below is an example showing the current state of GridLayout with different UI elements. I also created a brief example to demonstrate how to use GridLayout of different cellshapes with UI elements link to which is here.

    +
    +
    https://i.imgur.com/EX2cN1i.png +
    +
  • +
  • Reviewed the FileDialog2D PR : This PR added support for FileDialog2D in the UI module. The PR needed to be reviewed in order to merge it as soon as other required PRs were merged. One of the mentors already reviewed the PR briefly my job was to review the PR for any remaining bugs.

  • +
  • Study #422 PR to understand contours around the drawn markers : In my previous week’s tasks I created a PR to add support for borders in Panel2D. The borders were individually customizable just like in CSS which meant 4 Rectangle2D objects were needed to represent border in each direction. This is not ideal for a scenario where a lot of Panel2D are present in the scene as it can be performance taxing. A possible solution for this was to actually look how this was implemented in the #422. This PR allowed drawing millions of markers in one call that too from the GPU. Interestingly, each marker had a contour surrounding it which is exactly what we needed for Panel2D. This is something that can be considered in the future for border implementation in other complex UI elements.

  • +
  • I also continued my work on the watcher class that I mentioned in the previous week’s blog. The work for this is almost done and just needs some tests implemented, which should be done soon.

  • +
+
+
+

Did I get stuck anywhere?#

+

Fortunately, I did not get stuck this week.

+
+
+

What is coming up next?#

+

Next week I would probably continue to work on GridLayout and possibly other layouts as well, other tasks will be decided in the next meeting.

+

See you guys next week!

+
+
+ +
+ + + + +
+ + + + Previous: + + + + Second week of coding! + + + +   + + + + Next: + + + Weekly Check-In #3 + + + + +
+ + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2021/2021-06-21-week-3-sajag.html b/v0.10.x/posts/2021/2021-06-21-week-3-sajag.html new file mode 100644 index 000000000..37dcb1e29 --- /dev/null +++ b/v0.10.x/posts/2021/2021-06-21-week-3-sajag.html @@ -0,0 +1,565 @@ + + + + + + + + Second week of coding! — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Second week of coding!#

+

Welcome to the third weekly check-in. I’ll be sharing my progress for the second week of coding.

+
+

What did you do this week?#

+

I created an example to demonstrate how one can render multiple bonds (double and triple). This required me to write an algorithm to detect bonding. +I used this blog as a reference and made a few tweaks of my own to detect the presence of double/triple bonds from interatomic distances. +The math involved in generating the coordinates of bonds was quite intriguing. Preview:

+
+
+https://user-images.githubusercontent.com/65067354/122672109-7d040c80-d1e7-11eb-815d-1d07fe47bbc4.png +
+

molecules rendered: Ethane, Ethene, Ethyne (from left to right)#

+
+
+
+

In addition to this, I tried understanding the codebase of vtkMolecule, vtkSimpleBondPerceiver, vtkMoleculeMapper, vtkPeriodicTable and was able to render bond-stick models and stick models using it. +This will be of great help although it’s rather slow in rendering large molecules (using shaders to improve its speed will be crucial if it’s to be utilised).

+
+
+https://github.com/SunTzunami/gsoc2021_blog_data/blob/master/visuals/week2_wire_rep.png?raw=true +
+

Stick representation using vtkMoleculeMapper#

+
+
+
+https://raw.githubusercontent.com/SunTzunami/gsoc2021_blog_data/master/visuals/week2_bs_rep.png +
+

Ball and Stick representation using vtkMoleculeMapper#

+
+
+
+
+
+

What is coming up next week?#

+

Try to see if the above models can be implemented using shaders. Try implementing the ribbon model using the vtkProteinRibbonFilter. The rest will be decided in the meeting with the mentors.

+
+
+

Did you get stuck anywhere?#

+

Predicting bonds had been a problem since the past few weeks, it was resolved to a large extent by vtkSimpleBondPerceiver (the only limitation of vtkSimpleBondPerceiver being its inability to predict multiple bonds).

+

Au Revoir!

+
+
+ +
+ + + + + + + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2021/2021-06-28-gsoc-devmessias-4.html b/v0.10.x/posts/2021/2021-06-28-gsoc-devmessias-4.html new file mode 100644 index 000000000..fd775a841 --- /dev/null +++ b/v0.10.x/posts/2021/2021-06-28-gsoc-devmessias-4.html @@ -0,0 +1,807 @@ + + + + + + + + SOLID, monkey patching a python issue and network visualization through WebRTC — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

SOLID, monkey patching a python issue and network visualization through WebRTC#

+

These past two weeks I’ve spent most of my time in the Streaming System +PR and the Network Layout +PR . In this post I’ll +focus on the most relevant things I’ve made for those PRs.

+
+

Streaming System#

+

Pull +request : fury-gl/fury/pull/437.

+
+

Code Refactoring#

+
+

Abstract class and SOLID#

+

The past weeks I’ve spent some time refactoring the code to see what +I’ve done let’ s take a look into this +fury/blob/b1e985…/fury/stream/client.py#L20, +the FuryStreamClient Object before the refactoring.

+

The code is a mess. To see why this code is not good according to SOLID +principles let’s just list all the responsibilities of FuryStreamClient:

+
    +
  • Creates a RawArray or SharedMemory to store the n-buffers

  • +
  • Creates a RawArray or SharedMemory to store the information about +each buffer

  • +
  • Cleanup the shared memory resources if the SharedMemory was used

  • +
  • Write the vtk buffer into the shared memory resource

  • +
  • Creates the vtk callbacks to update the vtk-buffer

  • +
+

That’s a lot and those responsibilities are not even related to each +other. How can we be more SOLID[1]? An obvious solution is to create a +specific object to deal with the shared memory resources. But it’s not +good enough because we still have a poor generalization since this new +object still needs to deal with different memory management systems: +rawarray or shared memory (maybe sockets in the future). Fortunately, we +can use the python Abstract Classes[2] to organize the code.

+

To use the ABC from python I first listed all the behaviors that should +be mandatory in the new abstract class. If we are using SharedMemory or +RawArrays we need first to create the memory resource in a proper way. +Therefore, the GenericImageBufferManager must have a abstract method +create_mem_resource. Now take a look into the ImageBufferManager inside +of +stream/server/server.py, +sometimes it is necessary to load the memory resource in a proper way. +Because of that, the GenericImageBufferManager needs to have a +load_mem_resource abstract method. Finally, each type of +ImageBufferManager should have a different cleanup method. The code +below presents the sketch of the abstract class

+
from abc import ABC, abstractmethod
+
+GenericImageBufferManager(ABC):
+    def __init__(
+            self, max_window_size=None, num_buffers=2, use_shared_mem=False):
+         ...
+    @abstractmethod
+    def load_mem_resource(self):
+        pass
+    @abstractmethod
+    def create_mem_resource(self):
+        pass
+    @abstractmethod
+    def cleanup(self):
+        pass
+
+
+

Now we can look for those behaviors inside of FuryStreamClient.py and +ImageBufferManger.py that does not depend if we are using the +SharedMemory or RawArrays. These behaviors should be methods inside of +the new GenericImageBufferManager.

+
# code at: https://github.com/devmessias/fury/blob/440a39d427822096679ba384c7d1d9a362dab061/fury/stream/tools.py#L491
+
+class GenericImageBufferManager(ABC):
+    def __init__(
+            self, max_window_size=None, num_buffers=2, use_shared_mem=False)
+        self.max_window_size = max_window_size
+        self.num_buffers = num_buffers
+        self.info_buffer_size = num_buffers*2 + 2
+        self._use_shared_mem = use_shared_mem
+         # omitted code
+    @property
+    def next_buffer_index(self):
+        index = int((self.info_buffer_repr[1]+1) % self.num_buffers)
+        return index
+    @property
+    def buffer_index(self):
+        index = int(self.info_buffer_repr[1])
+        return index
+    def write_into(self, w, h, np_arr):
+        buffer_size = buffer_size = int(h*w)
+        next_buffer_index = self.next_buffer_index
+         # omitted code
+
+    def get_current_frame(self):
+        if not self._use_shared_mem:
+        # omitted code
+        return self.width, self.height, self.image_buffer_repr
+
+    def get_jpeg(self):
+        width, height, image = self.get_current_frame()
+        if self._use_shared_mem:
+        # omitted code
+        return image_encoded.tobytes()
+
+    async def async_get_jpeg(self, ms=33):
+       # omitted code
+    @abstractmethod
+    def load_mem_resource(self):
+        pass
+
+    @abstractmethod
+    def create_mem_resource(self):
+        pass
+
+    @abstractmethod
+    def cleanup(self):
+        Pass
+
+
+

With the +GenericImageBufferManager +the +RawArrayImageBufferManager +and +SharedMemImageBufferManager +is now implemented with less duplication of code (DRY principle). This +makes the code more readable and easier to find bugs. In addition, later +we can implement other memory management systems in the streaming system +without modifying the behavior of FuryStreamClient or the code inside of +server.py.

+

I’ve also applied the same SOLID principles to improve the CircularQueue +object. Although the CircularQueue and FuryStreamInteraction were not +violating the S from SOLID, the head-tail buffer from the CircularQueue +must have a way to lock the write/read if the memory resource is busy. +Meanwhile the +multiprocessing.Arrays +already has a context which allows lock (.get_lock()) SharedMemory +doesn’t[2]. The use of abstract class allowed me to deal with those +peculiarities. commit +358402e

+
+
+

Using namedtuples to grant immutability and to avoid silent bugs#

+

The circular queue and the user interaction are implemented in the +streaming system using numbers to identify the type of event (mouse +click, mouse weel, …) and where to store the specific values +associated with the event , for example if the ctrl key is pressed or +not. Therefore, those numbers appear in different files and locations: +tests/test_stream.py, stream/client.py, steam/server/app_async.py. This +can be problematic because a typo can create a silent bug. One +possibility to mitigate this is to use a python dictionary to store the +constant values, for example

+
EVENT_IDS = {
+     "mouse_move" : 2, "mouse_weel": 1, #...
+}
+
+
+

But this solution has another issue, anywhere in the code we can change +the values of EVENT_IDS and this will produce a new silent bug. To avoid +this I chose to use +namedtuples +to create an immutable object which holds all the constant values +associated with the user interactions. +stream/constants.py

+

The namedtuple has several advantages when compared to dictionaries for +this specific situation. In addition, it has a better performance. A +good tutorial about namedtuples it’s available here +https://realpython.com/python-namedtuple/

+
+
+
+

Testing#

+

My mentors asked me to write tests for this PR. Therefore, this past +week I’ve implemented the most important tests for the streaming system: +/fury/tests/test_stream.py

+
+
+

Most relevant bugs#

+

As I discussed in my third +week +check-in there is an open issue related to SharedMemory in python. +This”bug” happens in the streaming system through the following scenario

+
1-Process A creates a shared memory X
+2-Process A creates a subprocess B using popen (shell=False)
+3-Process B reads X
+4-Process B closes X
+5-Process A kills B
+4-Process A closes  X
+5-Process A unlink() the shared memory resource
+
+
+

In python, this scenario translates to

+
from multiprocessing import shared_memory as sh
+import time
+import subprocess
+import sys
+
+shm_a = sh.SharedMemory(create=True, size=10000)
+command_string = f"from multiprocessing import shared_memory as sh;import time;shm_b = sh.SharedMemory('{shm_a.name}');shm_b.close();"
+time.sleep(2)
+p = subprocess.Popen(
+    [sys.executable, '-c', command_string],
+    stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=False)
+p.wait()
+print("\nSTDOUT")
+print("=======\n")
+print(p.stdout.read())
+print("\nSTDERR")
+print("=======\n")
+print(p.stderr.read())
+print("========\n")
+time.sleep(2)
+shm_a.close()
+shm_a.unlink()
+
+
+

Fortunately, I could use a monkey-patching[3] solution to fix that; +meanwhile we’re waiting for the python-core team to fix the +resource_tracker (38119) issue [4].

+
+
+
+

Network Layout (Helios-FURY)#

+

Pull +requestfury-gl/helios/pull/1

+

Finally, the first version of FURY network layout is working as you can +see in the video below.

+

In addition, this already can be used with the streaming system allowing +user interactions across the internet with WebRTC protocol.

+

One of the issues that I had to solve to achieve the result presented in +the video above was to find a way to update the positions of the vtk +objects without blocking the main thread and at the same time allowing +the vtk events calls. My solution was to define an interval timer using +the python threading module: +/fury/stream/tools.py#L776, +/fury/stream/client.py#L112 +/fury/stream/client.py#L296

+
+
+

Refs:#

+ +
+
+ + + +
+ + + +
+ +
+
+
+ +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2021/2021-06-28-week-4-antriksh.html b/v0.10.x/posts/2021/2021-06-28-week-4-antriksh.html new file mode 100644 index 000000000..3cc26d4ff --- /dev/null +++ b/v0.10.x/posts/2021/2021-06-28-week-4-antriksh.html @@ -0,0 +1,553 @@ + + + + + + + + Week #4: Adding Tree UI to the UI module — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Week #4: Adding Tree UI to the UI module#

+
+

What did I do this week?#

+

This week I had very few tasks to do, almost all of them revolved around UI elements and adding stuff to the UI module. Earlier, it was pointed out that due to some design issues, importing certain modules into others caused circular imports which led to importing the specific modules inside a class/method which is not the best approach. This will be resolved as soon as the PR that fixes this issue is reviewed/merged in the codebase. In the meantime, all the PR’s related to UI will be on hold, which is why this I had few tasks this week. The tasks are described below in detail:

+
    +
  • Addition of watcher class in UI :This is finally done, as described in the previous blogs this was something that was on hold for a long time. Primarily, due to other tasks I couldn’t work on this but this week due to less tasks I was able to complete the watcher class and create a PR. This PR adds support for a watcher class in the UI elements. The purpose of this class is to monitor a particular attribute from the UI element after it has been added to the scene. If the attribute changes in the real time, a user defined callback is triggered and the scene is force rendered. Currently, if any attribute of the UI element changes after it is added to the scene it does not get updated accordingly. The only way to update the UI element would be to add a custom user hook that will be triggered when a particular event that can change the attribute is invoked. This is highly ambiguous as some unmonitored event can easily change many attributes of the UI element. Also it would be really hard to add user hooks for so many events. The watcher class does this automatically, it monitors the attribute for changes and if the attribute changes, a user defined callback is triggered. If this is something that is required in the UI module, then in the future a good addition would be to monitor the UI element instance as a whole instead of a single attribute .

  • +
  • Addition of Tree UI in the UI module : Another task for this week was to work on either Tree UI or the Accordion UI. I chose to work on Tree UI as it is very interesting to implement and the logic for Tree is almost similar to that of an Accordion. So far, I have managed to implement TreeNode2D. The Tree UI contains several nodes and each node can have its own sub-nodes/children. Also, each node has an expand/collapse button which can be used to chow/hide the underlying children. The Tree UI would take some sort of data structure that contains nodes/sub-nodes and convert each node to TreeNode2D and add all the processed node to the main Panel. So far this the result I have achieved:

    +
    +
    https://i.imgur.com/WIMWsrp.png +https://i.imgur.com/u33D7Qi.png +
    +
  • +
  • Resize Panel2D on window resizing : This PR adds support for resizing Panel2D on WindowResizeEvent. This means that the Panle2D resizes itself with respect to the changed window size. It also retains its maximum possible size and does not overflow. Also, this PR adds support for resizing the Panel2D for the bottom right corner. A placeholder button is placed at the bottom right corner of the Panel2D and when it is dragged by the placeholder the Panel2D resize accordingly. Below is an example:

    +
    +
    https://i.imgur.com/87PN7TQ.gif +
    +
  • +
  • Also, I did some testing of GridLayout when placed inside a resizable Panel2D. This will need to be worked on before advancing any further. Currently the elements present in the Panel2D do not resize properly w.r.t the changed panel size. Hopefully, this will be fixed in the future PRs.

  • +
+
+
+

Did I get stuck anywhere?#

+

Fortunately, I did not get stuck this week.

+
+
+

What is coming up next?#

+

The tasks for the next week will be decided in this weeks meeting.

+

See you guys next week!

+
+
+ +
+ + + + +
+ + + + Previous: + + + + Third week of coding! + + + +   + + + + Next: + + + Fourth week of coding! + + + + +
+ + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2021/2021-06-28-week-4-sajag.html b/v0.10.x/posts/2021/2021-06-28-week-4-sajag.html new file mode 100644 index 000000000..9d313820d --- /dev/null +++ b/v0.10.x/posts/2021/2021-06-28-week-4-sajag.html @@ -0,0 +1,560 @@ + + + + + + + + Third week of coding! — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Third week of coding!#

+

Welcome to the fourth weekly check-in. I’ll be sharing my progress for the third week of coding.

+
+

What did you do this week?#

+

I made a document with code snippets and visuals to show how one can use +some vtk classes in python for molecular visualization. Classes of +interest:

+
    +
  • vtkMolecule (store atomic information about the molecule).

  • +
  • vtkSimpleBondPerceiver (calculate bonding info for a vtkMolecule).

  • +
  • vtkMoleculeMapper (mapper to draw vtkMolecule object).

  • +
  • vtkPeriodicTable (stores chemical data sourced from the Blue Obelisk +Data).

  • +
+

Link to the document: Molecular_viz_vtk. In addition to the +document, I read some research papers recommended by my mentors to +understand some other (and potentially better) methods of ribbon +visualization. Tried to implement vtkProteinRibbonFilter usage without +using vtkPDBReader but was unsuccessful in this endeavor.

+
+
+

What is coming up next week?#

+

Three goals for next week:

+
    +
  1. Implement vtkProteinRibbonFilter usage without using vtkPDBReader.

  2. +
  3. Make a class for vtkMolecule which can store molecular data and pass +it on to different function for rendering purposes.

  4. +
  5. Read papers on surface model.

  6. +
+
+
+

Did you get stuck anywhere?#

+

Implementing vtkProteinRibbonFilter usage via vtkPolyData without using +vtkPDBReader has confounded me for some time now.

+

Au Revoir!

+
+
+ +
+ + + + +
+ + + + Previous: + + + + Weekly Check-In #3 + + + +   + + + + Next: + + + Week #4: Adding Tree UI to the UI module + + + + +
+ + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2021/2021-07-05-gsoc-devmessias-5.html b/v0.10.x/posts/2021/2021-07-05-gsoc-devmessias-5.html new file mode 100644 index 000000000..fca9b2e66 --- /dev/null +++ b/v0.10.x/posts/2021/2021-07-05-gsoc-devmessias-5.html @@ -0,0 +1,586 @@ + + + + + + + + Weekly Check-In #5 — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Weekly Check-In #5#

+
+

What did you do this week?#

+
+

fury-gl/fury PR#437: WebRTC streaming system for FURY#

+
    +
  • Before the 8c670c2 commit, for some versions of MacOs the +streaming system was falling in a silent bug. I’ve spent a lot of +time researching to found a cause for this. Fortunately, I could found +the cause and the solution. This troublesome MacOs was falling in a +silent bug because the SharedMemory Object was creating a memory +resource with at least 4086 bytes independent if I’ve requested less +than that. If we look into the MultiDimensionalBuffer Object +(stream/tools.py) before the 8c670c2 commit we can see that Object +has max_size parameter which needs to be updated if the SharedMemory +was created with a “wrong” size.

  • +
+
+
+

fury-gl/helios PR 1: Network Layout and SuperActors#

+

In the past week I’ve made a lot of improvements in this PR, from +performance improvements to visual effects. Below are the list of the +tasks related with this PR:

+
    +
  • Code refactoring.

  • +
  • Visual improvements: Using the UniformTools from my pull request +#424 now is possible to control all the visual characteristics at +runtime.

  • +
  • 2D Layout: Meanwhile 3d network representations are very usefully +for exploring a dataset is hard to convince a group of network +scientists to use a visualization system which doesn’t allow 2d +representations. Because of that I started to coding the 2d behavior +in the network visualization system.

  • +
  • Minimum Distortion Embeddings examples: I’ve created some examples +which shows how integrate pymde (Python Minimum Distortion +Embeddings) with fury/helios. The image below shows the result of +this integration: a “perfect” graph embedding

  • +
+https://user-images.githubusercontent.com/6979335/124524052-da937e00-ddcf-11eb-83ca-9b58ca692c2e.png +
+
+
+

What is coming up next week?#

+

I’ll probably focus on the heliosPR#1. Specifically, writing tests +and improving the minimum distortion embedding layout.

+
+
+

Did you get stuck anywhere?#

+

I did not get stuck this week.

+
+
+ + + +
+ + + +
+ +
+
+
+ +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2021/2021-07-05-week-5-antriksh.html b/v0.10.x/posts/2021/2021-07-05-week-5-antriksh.html new file mode 100644 index 000000000..957368e25 --- /dev/null +++ b/v0.10.x/posts/2021/2021-07-05-week-5-antriksh.html @@ -0,0 +1,547 @@ + + + + + + + + Week #5: Rebasing all PRs w.r.t the UI restructuring, Tree2D, Bug Fixes — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Week #5: Rebasing all PRs w.r.t the UI restructuring, Tree2D, Bug Fixes#

+
+

What did I do this week?#

+

The UI restructuring was finally merged this week. This means UI is now a submodule in itself and provides different UI elements based on their types which are, core, elements, containers and some helper methods/classes. So, this week my main tasks were to rebase and fix merge conflicts of my open PR’s. Other than that, I had to continue my work on Tree2D UI element and finish the remaining aspects of it. Also, I had to create an example demonstrating how to use the newly added UI element. Many use cases were discussed in the open meeting like, an image gallery which displays preview image on the title and when expanded reveals the full scale image. I am thinking of adding multiple examples for the Tree2D to brainstorm on its certain features. Also, I had this annoying bug in Panel2D which didn’t allow it to be resized from the bottom right corner. It was resizing from the top right corner. I had to address this bug as well. Below are the tasks in detail:

+
    +
  • Rebasing all PRs w.r.t the UI restructuring: As discussed in the earlier blogs, due to circular imports and large size of the UI module, a bit of restructuring was required. This week the PR that converts the UI into a sub module was finally merged. This meant I had to fix all the merge conflicts and rebase all UI related PR’s. So, I rebased all the UI related PR’s and fixed the merge conflicts. Currently, there are still some PR’s that need some attention as still some of the imports are circular in nature. This means if the issue is correct then some more restructuring is required, which will be hopefully done in the near future.

  • +
  • Continuing the work on Tree2D : This week I continued my work on Tree2D, TreeNode2D. I had to fix/add multiple features on both the classes but my priority was to fix the looks of the UI element as well as make it easier for the user to manipulate the UI element. The first thing that I fixed was node offsetting, when a node is collapsed and expanded the nodes below the current node should also offset. Previously, only the child nodes within the same parents were offset and not the nodes/parent beyond that. With some minor adjusting, now the nodes are offset recursively and all child/parent nodes below the current nodes are offset. Secondly, before only a node could be added to a node which meant it wasn’t any easy way to add any other UI element to a node but with some updates/fixes any UI element can be added to a node. Also, the Tree2D lacked some properties/methods to easily manipulate it. So, i added some properties/methods that allow to easily/efficiently manipulate individual node inside the Tree2D. Below is the current state of the Tree2D. In the below tree, two panels are added to a child node after the tree has been initialized. Also, the coordinated of the child elements are totally fluid i.e they can be placed anywhere inside the content panel by passing normalized or absolute coordinates.

    +
    +
    https://i.imgur.com/rQQvLqs.png +
    +
  • +
  • Fixed Panel2D bottom corner resizing: Previously, the panel would not resize from the bottom left corner but it would resize from top right corner. I didn’t understand what was going wrong and was stuck on this for a long time. But I finally figured out the problem, I was calculating the Y-offset wrong as well as the panel resized from the top side instead of bottom. With some minor tweaking the bug was gone and the panel resizes correctly from the bottom right corner.

  • +
+
+
+

Did I get stuck anywhere?#

+

I got stuck on recording events for the updated panel UI element. The panel updates w.r.t the window size but I couldn’t figure out how to record the events invoked by the window. Unfortunately, I still haven’t figured out how this will be done. My guess is that I have to propagate the event first to the interactor and then to the UI element.

+
+
+

What is coming up next?#

+

I will probably finish up the GridLayout, Tree2D UI along side some other UI’s. This will be decided in the next meeting.

+

See you guys next week!

+
+
+ + + +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2021/2021-07-05-week-5-sajag.html b/v0.10.x/posts/2021/2021-07-05-week-5-sajag.html new file mode 100644 index 000000000..b3411f5b4 --- /dev/null +++ b/v0.10.x/posts/2021/2021-07-05-week-5-sajag.html @@ -0,0 +1,547 @@ + + + + + + + + Fourth week of coding! — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Fourth week of coding!#

+

Welcome to the fifth weekly check-in. I’ll be sharing my progress for the fourth week of coding.

+
+

What did you do this week?#

+

Created a PR for the molecular module. Enables the ability to create +three types of molecular representations:

+
    +
  1. Space-filling model aka calotte model and CPK model.

  2. +
  3. Stick model.

  4. +
  5. Ball and Stick model.

  6. +
+
+
+

What is coming up next week?#

+

Mentors suggested changes to be made to the molecular module which I +shall make. Other goals to be decided post mid-week meeting.

+
+
+

Did you get stuck anywhere?#

+

Sending protein data to ProteinRibbonFilter via a vtkPolyData has been +unsuccessful so far.

+

Au Revoir!

+
+
+ + + +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2021/2021-07-12-gsoc-devmessias-6.html b/v0.10.x/posts/2021/2021-07-12-gsoc-devmessias-6.html new file mode 100644 index 000000000..c6efb315d --- /dev/null +++ b/v0.10.x/posts/2021/2021-07-12-gsoc-devmessias-6.html @@ -0,0 +1,687 @@ + + + + + + + + Network layout algorithms using IPC — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Network layout algorithms using IPC#

+

Hi all. In the past weeks, I’ve been focusing on developing Helios; the +network visualization library for FURY. I improved the visual aspects of +the network rendering as well as implemented the most relevant network +layout methods.

+

In this post I will discuss the most challenging task that I faced to +implement those new network layout methods and how I solved it.

+
+

The problem: network layout algorithm implementations with a blocking behavior#

+

Case 1: Suppose that you need to monitor a hashtag and build a +social graph. You want to interact with the graph and at the same time +get insights about the structure of the user interactions. To get those +insights you can perform a node embedding using any kind of network +layout algorithm, such as force-directed or minimum distortion +embeddings.

+

Case 2: Suppose that you are modelling a network dynamic such as an +epidemic spreading or a Kuramoto model. In some of those network +dynamics a node can change the state and the edges related to the node +must be deleted. For example, in an epidemic model a node can represent +a person who died due to a disease. Consequently, the layout of the +network must be recomputed to give better insights.

+

In described cases if we want a better (UX) and at the same time a more +practical and insightful application of Helios layouts algorithms +shouldn’t block any kind of computation in the main thread.

+

In Helios we already have a lib written in C (with a python wrapper) +which performs the force-directed layout algorithm using separated +threads avoiding the GIL problem and consequently avoiding the blocking. +But and the other open-source network layout libs available on the +internet? Unfortunately, most of those libs have not been implemented +like Helios force-directed methods and consequently, if we want to +update the network layout the python interpreter will block the +computation and user interaction in your network visualization. How to +solve this problem?

+
+
+

Why is using the python threading is not a good solution?#

+

One solution to remove the blocking behavior of the network layout libs +like PyMDE is to use the threading module from python. However, remember +the GIL problem: only one thread can execute python code at once. +Therefore, this solution will be unfeasible for networks with more than +some hundreds of nodes or even less! Ok, then how to solve it well?

+
+
+

IPC using python#

+

As I said in my previous posts I’ve created a streaming system for data +visualization for FURY using webrtc. The streaming system is already +working and an important piece in this system was implemented using the +python SharedMemory from multiprocessing. We can get the same ideas from +the streaming system to remove the blocking behavior of the network +layout libs.

+

My solution to have PyMDE and CuGraph-ForceAtlas without blocking was to +break the network layout method into two different types of processes: A +and B. The list below describes the most important behaviors and +responsibilities for each process

+

Process A:

+
    +
  • Where the visualization (NetworkDraw) will happen

  • +
  • Create the shared memory resources: edges, weights, positions, info..

  • +
  • Check if the process B has updated the shared memory resource which +stores the positions using the timestamp stored in the info_buffer

  • +
  • Update the positions inside of NetworkDraw instance

  • +
+

Process B:

+
    +
  • Read the network information stored in the shared memory resources: +edges , weights, positions

  • +
  • Execute the network layout algorithm

  • +
  • Update the positions values inside of the shared memory resource

  • +
  • Update the timestamp inside of the shared memory resource

  • +
+

I used the timestamp information to avoid unnecessary updates in the +FURY/VTK window instance, which can consume a lot of computational +resources.

+
+

How have I implemented the code for A and B?#

+

Because we need to deal with a lot of different data and share them +between different processes I’ve created a set of tools to deal with +that, take a look for example in the ShmManagerMultiArrays +Object +, which makes the memory management less painful.

+

I’m breaking the layout method into two different processes. Thus I’ve +created two abstract objects to deal with any kind of network layout +algorithm which must be performed using inter-process-communication +(IPC). Those objects are: +NetworkLayoutIPCServerCalc +; used by processes of type B and +NetworkLayoutIPCRender +; which should be used by processes of type A.

+

I’ll not bore you with the details of the implementation. But let’s take +a look into some important points. As I’ve said saving the timestamp +after each step of the network layout algorithm. Take a look into the +method _check_and_sync from NetworkLayoutIPCRender +here. +Notice that the update happens only if the stored timestamp has been +changed. Also, look at this line +helios/layouts/mde.py#L180, +the IPC-PyMDE implementation This line writes a value 1 into the second +element of the info_buffer. This value is used to inform the process A +that everything worked well. I used that info for example in the tests +for the network layout method, see the link +helios/tests/test_mde_layouts.py#L43

+
+
+
+

Results#

+

Until now Helios has three network layout methods implemented: Force +Directed , Minimum Distortion Embeddings and Force Atlas 2. Here +docs/examples/viz_helios_mde.ipynb +you can get a jupyter notebook that I’ve a created showing how to use +MDE with IPC in Helios.

+

In the animation below we can see the result of the Helios-MDE +application into a network with a set of anchored nodes.

+

image1

+
+
+

Next steps#

+

I’ll probably focus on the Helios network visualization system. +Improving the documentation and testing the ForceAtlas2 in a computer +with cuda installed. See the list of opened +issues

+
+
+

Summary of most important pull-requests:#

+ +
+
+ +
+ + + + +
+ + + + Previous: + + + + Fifth week of coding! + + + +   + + + + Next: + + + Week #6: Bug fixes, Working on Tree2D UI + + + + +
+ + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2021/2021-07-12-week-6-antriksh.html b/v0.10.x/posts/2021/2021-07-12-week-6-antriksh.html new file mode 100644 index 000000000..f4ac240b1 --- /dev/null +++ b/v0.10.x/posts/2021/2021-07-12-week-6-antriksh.html @@ -0,0 +1,543 @@ + + + + + + + + Week #6: Bug fixes, Working on Tree2D UI — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Week #6: Bug fixes, Working on Tree2D UI#

+
+

What did I do this week?#

+

This week I had relatively few tasks and most of them were to fix some bugs/design flaws that were discussed in last week’s meeting. Other than that, I had to implement a few things in the Tree2D UI element that will be discussed in detail below. I also had to update some existing PRs in order to make things work well. Below are the list of things I worked on this week:

+
    +
  • Extracted Button2D class from elements to core : Button2D was placed in elements during the UI restructuring. The problem with that was that Button2D was needed in other UI elements outside UI elements present in elements in Panel2D. So, it was decided to create a rule that only the UI elements that do not depend on any other UI element are allowed to be placed in core UI elements. Button2D does not depend on any other UI element so it was extracted from elements to core.

  • +
  • Adapting GridLayout to work with UI elements : This was a PR that aimed to add support for UI elements to be placed in a grid fashion. the problem was that there still some circular imports even after UI restructuring, primarily because UI was being imported in the layout module that in turn indirectly imported some UI elements making them circularly dependent. To remove the circular imports, it was decided to determine the UI element by checking for a add_to_scene method attribute in the instance. I updated the existing PR to implement the same.

  • +
  • Continuing my work on Tree2D: The Tree2D lacked some important things related to design and visual aspect of it. Before, if the children of any node exceeded its height they would just overflow. To prevent this I came up with a few solutions two of which were to either add a scrollbar on the overflowing node or to simply auto resize the parent node. Currently, there is no global API for the scrollbar and it has to be manually setup in a UI element, this will be hopefully implemented in the near future probably using layout management. Till then the auto resizing has been implemented for the nodes. In future, an option for scrollbar will be added.

  • +
+
+
+

Did I get stuck anywhere?#

+

I am still stuck with adding tests for panel resizing PR. As it needs windows events to be recorded as well. I tried to propagate the event to the interactor first but that just lead to that particular event being registered multiple times. I will try to find a workaround for it.

+
+
+

What is coming up next?#

+

If the Tree2D gets merged by this week then I’ll probably work on other UI elements. Other tasks will be decided in the next meeting.

+

See you guys next week!

+
+
+ +
+ + + + +
+ + + + Previous: + + + + Network layout algorithms using IPC + + + +   + + + + Next: + + + Sixth week of coding! + + + + +
+ + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2021/2021-07-12-week-6-sajag.html b/v0.10.x/posts/2021/2021-07-12-week-6-sajag.html new file mode 100644 index 000000000..6b3a06a85 --- /dev/null +++ b/v0.10.x/posts/2021/2021-07-12-week-6-sajag.html @@ -0,0 +1,559 @@ + + + + + + + + Fifth week of coding! — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Fifth week of coding!#

+

Welcome to the sixth weekly check-in. I’ll be sharing my progress for the fifth week of coding.

+
+

What did you do this week?#

+
    +
  1. Generalised the vtkProteinRibbonFilter implementation.

  2. +
  3. Updated the molecular module based on suggestions of team members +and mentors (PR #452).

  4. +
  5. Updated wave function animation (PR #362).

  6. +
+
+
+https://user-images.githubusercontent.com/65067354/125155195-d4105800-e17b-11eb-9e6d-2b66ba7a8f6e.gif +
+

an animation#

+
+
+
+
+
+

What is coming up next week?#

+
    +
  1. Update molecular module based on team members’ suggestions and add +tests for the same.

  2. +
  3. Add protein ribbon implementation to the molecular module.

  4. +
  5. Begin working on molecular surface model.

  6. +
+
+
+

Did you get stuck anywhere?#

+

No! I was finally able to generalise the vtkProteinRibbonFilter implementation!! I’m +grateful to the mentors for keeping a meeting and for helping me debug +the code. I figured out most of the stuff courtesy the meeting.

+

Au Revoir!

+
+
+ +
+ + + + +
+ + + + Previous: + + + + Weekly Check-In #5 + + + +   + + + + Next: + + + Network layout algorithms using IPC + + + + +
+ + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2021/2021-07-19-gsoc-devmessias-7.html b/v0.10.x/posts/2021/2021-07-19-gsoc-devmessias-7.html new file mode 100644 index 000000000..1623d3301 --- /dev/null +++ b/v0.10.x/posts/2021/2021-07-19-gsoc-devmessias-7.html @@ -0,0 +1,558 @@ + + + + + + + + Weekly Check-In #7 — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Weekly Check-In #7#

+
+

What did I do this week?#

+
    +
  • PR fury-gl/helios#16 +(merged): Helios IPC +network layout support for MacOs

  • +
  • PR fury-gl/helios#17 +(merged): Smooth +animations for IPC network layout algorithms

    +

    Before this commit was not possible to record the positions to have a +smooth animations with IPCLayout approach. See the animation below

    +

    image1

    +

    After this PR now it’s possible to tell Helios to store the evolution +of the network positions using the record_positions parameter. This +parameter should be passed on the start method. Notice in the image +below how this gives to us a better visualization

    +

    image2

    +
  • +
  • PR fury-gl/helios#13 +(merged) Merged the +forceatlas2 cugraph layout algorithm

  • +
+
+
+

Did I get stuck anywhere?#

+

I did not get stuck this week.

+
+
+

What is coming up next?#

+

Probably, I’ll work more on Helios. Specifically I want to improve the +memory management system. It seems that some shared memory resources are +not been released when using the IPCLayout approach.

+
+
+ +
+ + + + + + + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2021/2021-07-19-week-7-antriksh.html b/v0.10.x/posts/2021/2021-07-19-week-7-antriksh.html new file mode 100644 index 000000000..53b6c9435 --- /dev/null +++ b/v0.10.x/posts/2021/2021-07-19-week-7-antriksh.html @@ -0,0 +1,536 @@ + + + + + + + + Week #7: Finalizing the stalling PRs, finishing up Tree2D UI. — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Week #7: Finalizing the stalling PRs, finishing up Tree2D UI.#

+
+

What did I do this week?#

+

This week I had limited tasks to do, mostly tasks related to existing PRs. Other than some minor fixes I had to implement some more things in Tree2D which included some minor UI fixes, some changes in tutorial, adding tests. Below is the detailed description of what I worked on this week:

+
    +
  • Tests, tutorial changes, UI fixes for Tree2D : The Tree2D lacked some things like proper UI resizing, relative indentation, tests for the UI class. These were added with this PR. Currently, the indentation, resizing needs some improvement, which will be fixed after feedback from this week’s meeting. Also, tests for Tree2D, TreeNode2D were added as well.

  • +
  • Updating Panel2D tests, re-recording the events : This PR is almost done with just some tests blocking the PR. The tests were added this week, but tests for some callbacks that are associated with window event are still not added. This is because there is no way to count the WindowResizeEvent without actually using the API of the window provided by the OS. This can become very complicated very soon so, these tests may be added in the future.

  • +
  • Fixing the failing CI’s for #443 : The CI was failing on this PR and needed some fixing which was done this week. This PR still needs some refactoring before the all CI’s pass. This will hopefully be fixed before this week’s meeting.

  • +
  • Addressing all comments regarding #442 : Previously, it was pointed out that the some code can be extracted into a function and can be reused in other methods. So, this week the extracted method was updated to reuse even more code and now almost no code is repeated.

  • +
  • Adding has_border flag in Panel2D : Adding a has_border flag in Panel2D: Previously, to create the borders 4 Rectangle2D’s were used and they were created every time even when border_width was set to 0. This would take a lot of wasted system resources. To fix this, a flag is added in the the constructor which is by default set to False. If false, the borders are not initialized and the resources are saved.

  • +
+
+
+

Did I get stuck anywhere?#

+

Fortunately, this week I didn’t get stuck anywhere.

+

See you guys next week!

+
+
+ +
+ + + + +
+ + + + Previous: + + + + Sixth week of coding! + + + +   + + + + Next: + + + Weekly Check-In #7 + + + + +
+ + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ +
+ +
+ On this page +
+ +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2021/2021-07-19-week-7-sajag.html b/v0.10.x/posts/2021/2021-07-19-week-7-sajag.html new file mode 100644 index 000000000..94755e4df --- /dev/null +++ b/v0.10.x/posts/2021/2021-07-19-week-7-sajag.html @@ -0,0 +1,567 @@ + + + + + + + + Sixth week of coding! — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Sixth week of coding!#

+

Welcome to the seventh weekly check-in. I’ll be sharing my progress for the sixth week of coding.

+
+

What did you do this week?#

+
    +
  1. Updated Molecular module: made it more pythonic, implemented +ribbon actor, added support to pass numpy arrays (earlier, atomic +data could only be added by using the add_atom).

  2. +
  3. Created PR #462 to:

    +
      +
    • Update the helical motion animation to use a single line actor, +added textblocks to display velocity of the particle.

      +

      image1

      +
    • +
    • For brownian motion animation, I removed rotation(azimuth) and box +actor, added textblock to display the number of particles and to +show the simulation steps.

      +

      image2

      +
    • +
    +
  4. +
  5. Updated surface animation (used gridUI, added multiple animations).

    +

    image3

    +
  6. +
  7. Created a topic on vtk discourse forum to query about gaps in +bonds (tried resolving it by manipulating vtkProperties: +BackfaceCulling, FrontfaceCulling but was unsuccessful).

  8. +
  9. Read about molecular surface (theory behind it).

  10. +
+
+
+

What is coming up next week?#

+
    +
  1. Update molecular module by adding tests, ribbon actor.

  2. +
  3. Try to implement molecular surface representation.

  4. +
  5. Interactivity of the molecules.

  6. +
+
+
+

Did you get stuck anywhere?#

+

I didn’t get stuck anywhere this week.

+

Au Revoir!

+
+
+ + + +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2021/2021-07-26-gsoc-devmessias-8.html b/v0.10.x/posts/2021/2021-07-26-gsoc-devmessias-8.html new file mode 100644 index 000000000..a82824cb7 --- /dev/null +++ b/v0.10.x/posts/2021/2021-07-26-gsoc-devmessias-8.html @@ -0,0 +1,543 @@ + + + + + + + + Weekly Check-In #8 — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Weekly Check-In #8#

+
+

What did I do this week?#

+ +
+
+

Did I get stuck anywhere?#

+

I did not get stuck this week.

+
+
+

What is coming up next?#

+

I’ll discuss that with my mentors tomorrow.

+
+
+ +
+ + + + + + + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2021/2021-07-26-week-8-antriksh.html b/v0.10.x/posts/2021/2021-07-26-week-8-antriksh.html new file mode 100644 index 000000000..efd9d3077 --- /dev/null +++ b/v0.10.x/posts/2021/2021-07-26-week-8-antriksh.html @@ -0,0 +1,547 @@ + + + + + + + + Week #8: Code Cleanup, Finishing up open PRs, Continuing work on Tree2D — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Week #8: Code Cleanup, Finishing up open PRs, Continuing work on Tree2D#

+
+

What did I do this week?#

+

This week I had to work on the open PRs specifically work on the bugs that were pointed out in last week’s meeting. Along side the bugs I had to continue the work on Tree2D UI element. Below is the detailed description of what I worked on this week:

+
    +
  • Added new tutorial, code clean-up, bug fixes : The Tree2D had some issues with its resizing of child nodes. The size for the nodes was calculated automatically based on the vertical size occupied by its children but this could be problematic when working with sliders or UI elements that take up a lot of vertical size. To avoid this the children sizes are calculated relative to each other and the vertical size is calculated such that all children fit in perfectly. Besides this, a multiselection flag has been added that decides whether multiple child nodes can be selected or not.

  • +
  • Adding tests for corner resize callback : This PR is almost done as it was decided that WindowsResizeEvent will be ignored for now. Which leaves us with corner resizing, the callback for corner resizing didn’t have any tests so the recording was redone and tests for the corner resize callback was added.

  • +
  • Fixing the failing CI’s for #443 : The solution that ended up working was creating custom objects for testing of is_ui method. With this update there will be no circular dependencies and no failing CI’s.

  • +
  • Addressing all comments regarding #442 : In the last meeting, a bug was pointed out wherein the text wouldn’t wrap as expected. The reason for this was some minor calculation mistakes. The whole wrap_overflow method was redone and now everything works as expected. Hopefully, no bugs pop up during this week’s meeting.

  • +
  • Addressing some minor comments : This PR is almost done too, there were some minor changes that were required to be addressed before this could be merged. So, these comments were fixed and hopefully this will be merged soon.

  • +
  • Using different fonts using FreeType python API: A major thing that FURY needs right now is using different fonts on the fly. This is more complicated than it seems, in case of browser environment this is not a problem as browsers can support and render all fonts using various techniques. In case of a desktop environment, we need to generate the bitmap for the fonts and then use them in form of textures. For now I have created a small example that generates these bitmaps from a python API called freetype-py, the fonts are fetched from google fonts and then they are displayed as textures.

  • +
  • Starting working on Vertical Layout: As majority of PRs are almost done, I started working on Vertical Layout. This will be hihgly inspired from the Grid Layout with obvious differences. The same techniques are being used in the Tree2D so this shouldn’t be difficult to implement.

  • +
+
+
+

Did I get stuck anywhere?#

+

The failing CI’s for Grid Layout Pr needed some custom objects to remove circular dependencies. I couldn’t figure out where should these custom objects go but fortunaltely the mentors showed me a quick example of where it should go.

+
+
+

What is coming up next week?#

+

Next week I will continue my work on some other UI’s and the remaining Layouts.

+

See you guys next week!

+
+
+ +
+ + + + +
+ + + + Previous: + + + + Seventh week of coding! + + + +   + + + + Next: + + + Weekly Check-In #8 + + + + +
+ + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2021/2021-07-26-week-8-sajag.html b/v0.10.x/posts/2021/2021-07-26-week-8-sajag.html new file mode 100644 index 000000000..f136adb05 --- /dev/null +++ b/v0.10.x/posts/2021/2021-07-26-week-8-sajag.html @@ -0,0 +1,556 @@ + + + + + + + + Seventh week of coding! — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Seventh week of coding!#

+

Welcome to the eighth weekly check-in. I’ll be sharing my progress for the seventh week of coding.

+
+

What did you do this week?#

+
    +
  1. Updated PR #452:

    +
      +
    • Added ribbon actor to the molecular module.

    • +
    • Added tests for all functions in the molecular module.

    • +
    +
  2. +
  3. Updated PR #462: Addressed the reviews of team members and +mentors, added new features.

    +

    image1

    +
  4. +
  5. Updated PR #362: Addressed the feedbacks of team members and +mentors.

  6. +
+
+
+

What is coming up next week?#

+
    +
  1. Work more on molecular module, meeting with mentors and core team on +Thursday to optimize the module and merge PR #452.

  2. +
  3. Start working upon molecular surface model.

  4. +
+
+
+

Did you get stuck anywhere?#

+

No.

+

Au Revoir!

+
+
+ +
+ + + + + + + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2021/2021-08-02-gsoc-devmessias-9.html b/v0.10.x/posts/2021/2021-08-02-gsoc-devmessias-9.html new file mode 100644 index 000000000..640177508 --- /dev/null +++ b/v0.10.x/posts/2021/2021-08-02-gsoc-devmessias-9.html @@ -0,0 +1,577 @@ + + + + + + + + Week #09: Sphinx custom summary — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Week #09: Sphinx custom summary#

+
+

What did I do this week?#

+
+

FURY/Helios#

+
    +
  • PR fury-gl/helios#22 +: Helios Documentation +Improvements. +I’ve spent some time studying sphinx in order to discover how I could create a +custom summary inside of a template module.

  • +
+
+
+

FURY#

+

Added my GSoC blogs to the FURY blogs as requested by my mentors. +- PR fury-gl/fury#437:

+
+
    +
  • Docstrings improvements

  • +
  • Covered more tests

  • +
  • Covered tests using optional dependencies.

  • +
  • Aiortc now it’s not a mandatory dependency

  • +
  • improvements in memory management

  • +
+
+
    +
  • PR #432 Fixed some typos, improved the tests and docstrings

  • +
  • PR fury-gl/fury#474:

  • +
  • Helped to review and made some suggestions to the PR #474 made by @mehabhalodiya.

  • +
+
+
+
+

Did I get stuck anywhere?#

+

I did not get stuck this week.

+
+
+

What is coming up next?#

+

I’ll discuss that with my mentors tomorrow.

+
+
+ +
+ + + + +
+ + + + Previous: + + + + Eighth coding week! + + + +   + + + + Next: + + + Week #9: More Layouts! + + + + +
+ + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2021/2021-08-02-week-9-antriksh.html b/v0.10.x/posts/2021/2021-08-02-week-9-antriksh.html new file mode 100644 index 000000000..4da23619e --- /dev/null +++ b/v0.10.x/posts/2021/2021-08-02-week-9-antriksh.html @@ -0,0 +1,549 @@ + + + + + + + + Week #9: More Layouts! — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Week #9: More Layouts!#

+
+

What did I do this week?#

+

Below are the tasks that I worked on:

+ +
+
+

Did I get stuck anywhere?#

+

For now I am not stuck anywhere but I have yet to start my work on freetype this could pose some trouble.

+
+
+

What is coming up next week?#

+

Next week I will finish the remaining UI elements which includes Accordion2D, SpinBox2D.

+

See you guys next week!

+
+
+ +
+ + + + +
+ + + + Previous: + + + + Week #09: Sphinx custom summary + + + +   + + + + Next: + + + FURY 0.7.0 Released + + + + +
+ + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2021/2021-08-02-week-9-sajag.html b/v0.10.x/posts/2021/2021-08-02-week-9-sajag.html new file mode 100644 index 000000000..fa3eafd41 --- /dev/null +++ b/v0.10.x/posts/2021/2021-08-02-week-9-sajag.html @@ -0,0 +1,556 @@ + + + + + + + + Eighth coding week! — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Eighth coding week!#

+

Welcome to the ninth weekly check-in. I’ll be sharing my progress for the eighth week of coding.

+
+

What did you do this week?#

+
    +
  1. Updated PR #452: Had an extra meeting with the mentors in which we fine-tuned the molecular module and optimised the code to make it more pythonic.

  2. +
  3. I was able to generate vertices and triangles for Solvent Excluded Surfaces (SES) by using a bioconda package called msms. It’s based on this paper by Michel F. Sanner, Arthur J. Olson & Jean-Claude Spehner. The vertices and triangles were then sent to surface actor to generate a surface.

    +
    +
    +https://user-images.githubusercontent.com/65067354/128756004-553d1880-b6e1-4a43-99fa-5bd6a2ee70d4.png +
    +

    SES surface generated via msms and surface actor#

    +
    +
    +
    +
  4. +
  5. Added my GSoC blogs to the FURY blogs directory. (PR #475)

  6. +
+

Other goals will be decided in the meeting with mentors.

+
+
+

What is coming up next week?#

+
    +
  1. Research about recent papers having good (fast) algorithms to create the molecular surfaces.

  2. +
  3. Create tutorials to explain how to use molecular module.

  4. +
+
+
+

Did you get stuck anywhere?#

+

No.

+

Au Revoir!

+
+
+ +
+ + + + +
+ + + + Previous: + + + + Weekly Check-In #8 + + + +   + + + + Next: + + + Week #09: Sphinx custom summary + + + + +
+ + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2021/2021-08-03-release-announcement.html b/v0.10.x/posts/2021/2021-08-03-release-announcement.html new file mode 100644 index 000000000..69e2e2e0c --- /dev/null +++ b/v0.10.x/posts/2021/2021-08-03-release-announcement.html @@ -0,0 +1,547 @@ + + + + + + + + FURY 0.7.0 Released — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

FURY 0.7.0 Released#

+

The FURY project is happy to announce the release of FURY 0.7.1! +FURY is a free and open source software library for scientific visualization and 3D animations.

+

You can show your support by adding a star on FURY github project.

+

This Release is mainly a maintenance release. The major highlights of this release are:

+
    +
  • FURY paper added.

  • +
  • Fast selection of multiple objects added.

  • +
  • UI refactored.

  • +
  • Tests coverage increased.

  • +
  • New actor (Marker) added.

  • +
  • New primitive (Triangular Prism) added.

  • +
  • Demos added and updated.

  • +
  • Large Documentation Update.

  • +
+
+

Note

+

The complete release notes are available here

+
+

To upgrade or install FURY

+

Run the following command in your terminal:

+
pip install --upgrade fury
+
+
+

or:

+
conda install -c conda-forge fury
+
+
+

Questions or suggestions?

+

For any questions go to http://fury.gl, or send an e-mail to fury@python.org +We can also join our discord community

+

We would like to thanks to all contributors for this release:

+
    +
  • Amit Chaudhari

  • +
  • Antriksh Misri

  • +
  • Bruno Messias

  • +
  • Daniel S. Katz

  • +
  • Eleftherios Garyfallidis

  • +
  • Gurdit Siyan

  • +
  • Javier Guaje

  • +
  • Jhalak Gupta

  • +
  • LoopThrough-i-j

  • +
  • MIHIR

  • +
  • Praneeth Shetty

  • +
  • Sajag Swami

  • +
  • Serge Koudoro

  • +
  • Hariharan Ayappane

  • +
+

On behalf of the FURY developers,

+

Serge K.

+
+ +
+ + + + +
+ + + + Previous: + + + + Week #9: More Layouts! + + + +   + + + + Next: + + + Ninth coding week! + + + + +
+ + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2021/2021-08-09-week-10-antriksh.html b/v0.10.x/posts/2021/2021-08-09-week-10-antriksh.html new file mode 100644 index 000000000..8a5309f9b --- /dev/null +++ b/v0.10.x/posts/2021/2021-08-09-week-10-antriksh.html @@ -0,0 +1,552 @@ + + + + + + + + Week#10: Accordion UI, Support for sprite sheet animations — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Week#10: Accordion UI, Support for sprite sheet animations#

+
+

What did I do this week?#

+

Below are the tasks that I worked on:

+
    +
  • Added Accordion2D to UI sub-module : This PR adds the Accordion UI to the UI sub-module. This UI inherits from the Tree2D UI and can only be merged once the Tree2D UI is in. Here’s a screenshot for reference:

    +
    +
    https://i.imgur.com/klI4Tb5.png +
    +
  • +
  • Adding X, Y, Z Layouts : It was pointed out in last week’s meeting that in 3D space horizontal/vertical means nothing. Instead X, Y, Z are used, so, these three layouts were added on top of horizontal/vertical layouts. They also have functionality of changing the direction i.e. reverse the stacking order.

  • +
  • Added support of sprite sheet animation in Card2D : The image in Card2D was static in nature and wasn’t very interesting. So, to make things a bit interesting support for animated images were added. These animations are played from a sprite sheet or a texture atlas. A buffer of processed sprite chunks is maintained and with the help of a timer callback the image in the card is updated after a certain delay which is dependent of the frame rate. Below is the demonstration:

    +
    +
    https://i.imgur.com/DliSpf0.gif +
    +
  • +
  • Researching more about Freetype/Freetype-GL: Apart from coding stuff, i did some more research on custom font using freetype and freetype-gl. I found some examples that used the python bindings of the c++ library and displayed custom fonts that were transformable i.e. can be rotated by some angle. Hopefully I can create a working example by this weeks meeting.

  • +
+
+
+

Did I get stuck anywhere?#

+

No, I did not get stuck anywhere.

+
+
+

What is coming up next week?#

+

Next week I will finish up my remaining work. Which includes addressing all PR reviews and adding some more features.

+

See you guys next week!

+
+
+ +
+ + + + +
+ + + + Previous: + + + + Week #10: SDF Fonts + + + +   + + + + Next: + + + Tenth coding week! + + + + +
+ + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2021/2021-08-09-week-10-sajag.html b/v0.10.x/posts/2021/2021-08-09-week-10-sajag.html new file mode 100644 index 000000000..582ee68da --- /dev/null +++ b/v0.10.x/posts/2021/2021-08-09-week-10-sajag.html @@ -0,0 +1,561 @@ + + + + + + + + Ninth coding week! — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Ninth coding week!#

+

Welcome to the tenth weekly check-in. I’ll be sharing my progress for the ninth week of coding.

+
+

What did you do this week?#

+
    +
  1. Updated PR #452 :

    +
    +
      +
    • Made ribbon representation faster.

    • +
    • Added an actor to display bounding box around the molecule.

    • +
    +
    +
    +https://user-images.githubusercontent.com/65067354/128624529-03c026be-7f80-4792-b57e-eceeb1767ec2.png +
    +

    Bounding Box#

    +
    +
    +
    +
    +
  2. +
  3. Made a tutorial which showcases the abilities of molecular module (will create a PR after molecular module is merged).

  4. +
  5. I’m trying to implement a native implementation of molecular surfaces in FURY. Currently searching for recent research papers to find good algorithms to generate the molecular surfaces (the ones I’d collected in the research period were archaic and rather time consuming). The papers that I’ve read so far seem a tad bit intimidating as I’ve never done math related to this domain yet. Implementing them will be a good learning experience I reckon.

  6. +
+
+
+

What is coming up next week?#

+
    +
  1. Try to create a native implementation of molecular surface.

  2. +
  3. Small fixes to PR #362, PR #462.

  4. +
+
+
+

Did you get stuck anywhere?#

+

No.

+

Au Revoir!

+
+
+ +
+ + + + +
+ + + + Previous: + + + + FURY 0.7.0 Released + + + +   + + + + Next: + + + Week #10: SDF Fonts + + + + +
+ + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2021/2021-08-16-week-11-antriksh.html b/v0.10.x/posts/2021/2021-08-16-week-11-antriksh.html new file mode 100644 index 000000000..eaa20bf71 --- /dev/null +++ b/v0.10.x/posts/2021/2021-08-16-week-11-antriksh.html @@ -0,0 +1,544 @@ + + + + + + + + Week #11: Finalizing open Pull Requests — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Week #11: Finalizing open Pull Requests#

+
+

What did I do this week?#

+

Below are the tasks that I worked on:

+
    +
  • Created PR for sprite sheet animation : This PR adds support for playing animations from a sprite sheet. This feature will be used in Card2D to create a tutorial in which the card will show the animation in the image box. Previously, the utility functions for this were added directly inside the tutorial but now they are refactored to go in their respective modules.

  • +
  • Finalized the x, y, z layouts : The PR that adds these layouts needed some updates for it to work as intended. These changes were added and this PR is ready to go.

  • +
  • Resolved all conflicts in the GridLayout PR : As the Horizontal and Vertical layouts were merged this week the GridLayout PR had got some conflicts. These conflicts were resolved and the PR is almost ready.

  • +
  • Continuing the work on custom font rendering : In the last meeting, a few points were brought up. Firstly, to position each glyph to their respective location in the atlas a separate module is used which is freetype-gl. The python bindings for this module are not available which means either we have to write the bindings ourselves or the freetype team will be emailed about this and they will add bindings for that. On the other hand, I looked how latex is rendered in matplotlib. This is the Text class that is used to represent the string that is to be drawn and `This is the class that it inherits from.<https://github.com/matplotlib/matplotlib/blob/3a4fdea8d23207d67431973fe5df1811605c4132/lib/matplotlib/artist.py#L94>`_ Everything is handled internally in matplotlib, to draw the rasterized text this function is used. The text can be rendered in two ways, the first one is by using the default renderer and the second way is by using PathEffectRenderer that is used to add effects like outlines, anti-aliasing etc. It is a very rigid way of rendering text and is designed to be used internally.

  • +
+
+
+

Did I get stuck anywhere?#

+

No, I did not get stuck anywhere.

+
+
+

What is coming up next week?#

+

Hopefully everything is resolved by the end of this week and next week I will hopefully submit my final code in a gist format.

+

See you guys next week!

+
+
+ +
+ + + + +
+ + + + Previous: + + + + Tenth coding week! + + + +   + + + + Next: + + + Week #11: Removing the flickering effect + + + + +
+ + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2021/2021-08-16-week-11-sajag.html b/v0.10.x/posts/2021/2021-08-16-week-11-sajag.html new file mode 100644 index 000000000..d1288bff7 --- /dev/null +++ b/v0.10.x/posts/2021/2021-08-16-week-11-sajag.html @@ -0,0 +1,568 @@ + + + + + + + + Tenth coding week! — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Tenth coding week!#

+

Welcome to the eleventh weekly check-in. I’ll be sharing my progress for the tenth week of coding.

+
+

What did you do this week?#

+
    +
  1. Implemented this paper to generate Van der Waals surface and solvent-accessible surface (PR created: PR #492). It was a good learning experience because the first time I read the paper, I didn’t understand the underlying math, it all seemed alien to me. I had to read it many times, read about the algorithms used and understand the terminologies. I had a meeting with the mentors to understand a bit of the theory which proved to be quite fruitful as I understood how to go about making the space-filling model. This blog was helpful in understanding how to use vtkMarchingCubes with numpy arrays. One of the earliest SAS rendering looked like this (this implementation was not strictly according to the paper):

    +
    +
    +https://user-images.githubusercontent.com/65067354/129559593-baf201bf-720c-45f7-9269-3b31954efd5e.png +
    +

    Notice that it’s rather rough#

    +
    +
    +
    +

    Current implementation (this implementation was according to the paper):

    +
    +
    +https://user-images.githubusercontent.com/65067354/129560374-14180b22-14b2-449b-88a6-b3140226418d.png +
    +

    grid dimensions = 256 × 256 × 256, used smoothing algorithms recommended by vtk#

    +
    +
    +
    +
  2. +
+

I also understood how to go about rendering volumes. I think that the ability to render volumes with FURY will be a cool capability and I’ll discuss my implementation and request the mentors for feedback and ideas in the weekly meeting. Example of volume rendering:

+
+
+https://user-images.githubusercontent.com/65067354/129562606-50a9f0cf-e16d-4501-b0fa-a0038fda406b.png +
+

grid dimensions = 256 × 256 × 256#

+
+
+
+
+
+

What is coming up next week?#

+

I’ll try to get PR #452 merged. Documentation work to be done as GSoC coding period has come to an end.

+
+
+

Did you get stuck anywhere?#

+

No.

+

Au Revoir!

+
+
+ + + +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2021/2021-08-23-final-work-antriksh.html b/v0.10.x/posts/2021/2021-08-23-final-work-antriksh.html new file mode 100644 index 000000000..9805aaafa --- /dev/null +++ b/v0.10.x/posts/2021/2021-08-23-final-work-antriksh.html @@ -0,0 +1,733 @@ + + + + + + + + Google Summer of Code Final Work Product — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +https://developers.google.com/open-source/gsoc/resources/downloads/GSoC-logo-horizontal.svg +https://www.python.org/static/community_logos/python-logo.png +https://python-gsoc.org/logos/FURY.png +
+

Google Summer of Code Final Work Product#

+ +
+

Proposed Objectives#

+
    +
  • Add support for Layouts in UI elements

  • +
  • Add support for Horizontal Layout

  • +
  • Add support for Vertical Layout

  • +
  • Add support for Layout along X, Y, Z axes.

  • +
  • Stretch Goals:

    +
      +
    • Add Tree2D UI element to the UI sub-module

    • +
    • Add Accordion2D UI element to the UI sub-module

    • +
    • Add SpinBox2D UI element to the UI sub-module

    • +
    +
  • +
+
+
+

Objectives Completed#

+
    +
  • Add support for Horizontal Layout

    +

    Added support for Horizontal Layout in the layout module. This layout allows the user to stack actors in a horizontal fashion. Primarily, should be used for laying out UI elements as there is no meaning of horizontal/vertical in 3D space.

    +

    Pull Requests:

    + +
  • +
  • Add support for Vertical Layout

    +

    Added support for Vertical Layout in the layout module. This layout allows the user to stack actors in a vertical fashion. Primarily, should be used for laying out UI elements as there is no meaning of horizontal/vertical in 3D space.

    +

    Pull Requests:

    + +
  • +
  • Add support for Layout along X, Y, Z axes

    +

    Added support for Layout along x, y, z axes. Allows user to layout different actors along any given axes. Also it allows users to switch the stacking order by passing a axis+ or axis- to the constructor.

    +

    Pull Requests:

    + +
  • +
  • Add Tree2D UI element to the UI sub-module

    +

    Added Tree2D UI element to the UI sub-module. This allows user to visualize some data in a hierarchical fashion. Each node inside the tree can have N child nodes and the depth can be infinite. Each node can be clicked to trigger a user defined callback to perform some action. Tests and two demos were added for this UI element. Below is a screenshot for reference:

    +https://camo.githubusercontent.com/dd23b7c8503e4d01c80f2d9e84ee173e06c61eeb7c348c35aeadc75f722647ca/68747470733a2f2f692e696d6775722e636f6d2f4e49334873746c2e706e67 +

    Pull Requests:

    + +
  • +
  • Add Accordion2D UI element to the UI sub-module

    +

    Added Accordion2D to the UI sub-module. This Ui element allows users to visualize data in a tree with depth of one. Each node has a title and a content panel. The children for each node can be N if and only if the children are not nodes themselves. The child UIs can be placed inside the content panel by passing some coordinates, which can be absolute or normalized w.r.t the node content panel size. Tests and two demos were added for this UI element. Below is a screenshot for reference

    +https://camo.githubusercontent.com/9395d0ea572d7f253a051823f02496450c9f79d19ff0baf32841ec648b6f2860/68747470733a2f2f692e696d6775722e636f6d2f7854754f645a742e706e67 +

    Pull Requests:

    + +
  • +
+
+
+

Objectives in Progress#

+
    +
  • Add support for Layout in UI elements

    +

    Currently all the available layouts are only available for actors i.e. of type vtkActor2D. In order to add support for the layouts in UI elements there needs to be some tweaking in the base Layout class. Currently, the PR that adds these functionalities in stalling because of some circular imports. These will hopefully be fixed soon and as soon as the circular imports are fixed, the PR will be merged.

    +

    Pull Requests:

    + +
  • +
  • Method to process and load sprite sheets

    +

    This method adds support for loading and processing a sprite sheet. This will be very useful in playing animations from a n*m sprite sheet. This also has a flag to convert the processed chunks into vtkimageData which can be directly used to update the texture in some UI elements. The primary use of this method will in a tutorial for Card2D, wherein, the image panel of the card will play the animation directly from the sprite sheet.

    +

    Pull Requests:

    + +
  • +
+
+
+

Other Objectives#

+
    +
  • Add Card2D UI element to UI sub-module

    +

    Added Card2D UI element to the UI sub-module. A Card2D is generally divided into two parts i.e. the image content and the text content. This version of card has an image which can be fetched from a URL and the text content which is yet again divided into two parts i.e. the title and the body. The space distribution between the image and the text content is decided by a float between 0 and 1. A value of 0 means the image takes up no space and a value of 1 means the image consumes the whole space. Below is a demonstration:

    +https://camo.githubusercontent.com/a2e461352799b6490088de15ac041162d7bf8adf9c07485ea921b525fecd0a8e/68747470733a2f2f692e696d6775722e636f6d2f446c69537066302e676966 +

    Pull Requests:

    + +
  • +
  • Resize Panel2D with WindowResizeEvent or from corner placeholder

    +

    Currently, the size of the Panel2D is static and cannot be changed dynamically. The size is passed in during the initialization and cannot be changed easily at runtime. This PR adds support for resizing the Panel2D dynamically by adding a placeholder icon at the bottom right corner of the panel. This icon can be click and dragged on to change the size accordingly. Other than this, the panel also retains a specific size ratio when the window is resized. This means if the window is resized in any direction the panel adapts itself w.r.t the updated size. This is done by adding relevant observers for the WindowResizeEvent and binding the relevant callback to it. Below is a quick demonstration:

    +
    +
    https://camo.githubusercontent.com/3b1bf6a1b6522a6079055ff196551362fcf89a41b35ac4b32315ce02333e496d/68747470733a2f2f692e696d6775722e636f6d2f3837504e3754512e676966 +
    +

    Pull Requests:

    +
      +
    • Resize Panel2D with WindowResizeEvent or from corner placeholder: fury-gl/fury#446

    • +
    +
  • +
  • Added the watcher class to UI

    +

    This PR adds support for a watcher class in the UI elements. The purpose of this class is to monitor a particular attribute from the UI element after it has been added to the scene. If the attribute changes in the real time, a user defined callback is triggered and the scene is force rendered.

    +

    Pull Requests:

    + +
  • +
  • Added support for borders in Panel2D

    +

    The Panel2D previously, didn’t support any sort of effect, the main reason behind this is that, all UI elements are individual entities that are comprised of different actors. These are not the widgets provided by vtk and in order to have some effects provided by vtk shaders must be involved. This obviously makes the whole system very complicated. The border on the other hand uses 4 Rectangle2Ds to draw the 4 borders. This makes the whole process easier but makes the Panel2D very performance heavy as we are adding 5 actors to the scene. Future iterations will replace these rectangles by textures, that way we don’t compromise performance and we can have different patterns in the border. Below is a demonstration:

    +https://user-images.githubusercontent.com/54466356/121709989-bd340280-caf6-11eb-9b8a-81c65260d277.png +

    Pull Requests:

    + +
  • +
  • GSoC weekly Blogs

    +
    +

    Weekly blogs were added for FURY’s Website.

    +

    Pull Requests:

    + +
    +
  • +
+
+
+

Timeline#

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Date

Description

Blog Link

Week 1(08-06-2021)

Welcome to my weekly Blogs!

Weekly Check-in #1

Week 2(14-06-2021)

Feature additions in UI and IO modules

Weekly Check-in #2

Week 3(21-06-2021)

Adapting GridLayout to work with UI

Weekly Check-in #3

Week 4(28-06-2021)

Adding Tree UI to the UI module

Weekly Check-in #4

Week 5(05-07-2021)

Rebasing all PR’s w.r.t the UI restructuring, Tree2D, Bug Fixes

Weekly Check-in #5

Week 6(12-07-2021)

Bug fixes, Working on Tree2D UI

Weekly Check-in #6

Week 7(19-07-2021)

Finalizing the stalling PR’s, finishing up Tree2D UI.

Weekly Check-in #7

Week 8(26-07-2020)

Code Cleanup, Finishing up open PR’s, Continuing work on Tree2D.

Weekly Check-in #8

Week 9(02-08-2021)

More Layouts!

Weekly Check-in #9

Week 10(09-08-2021)

Accordion UI, Support for sprite sheet animations.

Weekly Check-in #10

Week 11(16-08-2021)

More tutorials for Accordion2D, Finalizing remaining PRs.

Weekly Check-in #11

+

Detailed weekly tasks and work done can be found +here.

+
+
+ + + +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2021/2021-08-23-final-work-sajag.html b/v0.10.x/posts/2021/2021-08-23-final-work-sajag.html new file mode 100644 index 000000000..71ab5ad35 --- /dev/null +++ b/v0.10.x/posts/2021/2021-08-23-final-work-sajag.html @@ -0,0 +1,735 @@ + + + + + + + + Google Summer of Code Final Work Product — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +https://developers.google.com/open-source/gsoc/resources/downloads/GSoC-logo-horizontal.svg +https://www.python.org/static/community_logos/python-logo.png +https://python-gsoc.org/logos/FURY.png +
+

Google Summer of Code Final Work Product#

+ +
+

Proposed Objectives#

+
    +
  • Ribbon Representation

  • +
  • Molecular Surface Representation

  • +
  • Stretch Goals:

    +
      +
    • Stick Representation

    • +
    • Ball and stick Representation

    • +
    • Wire Representation

    • +
    • Pipes and Planks Representation

    • +
    • Sphere Representation

    • +
    +
  • +
+
+
+

Objectives Completed#

+
    +
  • Ribbon Representation

    +

    Ribbon diagrams, also known as Richardson diagrams, +are 3D schematic representations of protein structure. Ribbon diagrams are +generated by interpolating a smooth curve through the polypeptide backbone. +α-helices are shown as coiled ribbons. β-strands as sheets, and non-repetitive +coils or loops as lines or thin strips. It was implemented by using +vtkProteinRibbonFilter. Generating a vtkPolyData of appropriate format +required by vtkProteinRibbonFilter was initially unclear due to lack of +examples. I was able to understand what kind of output the filter required +after a meeting with mentors. Tests were added and a demo was created.

    +

    Pull Requests:

    + +
  • +
  • Ball and Stick Representation

    +

    The ball-and-stick model is a molecular model of a chemical substance which +displays both the three-dimensional position of the atoms and the bonds between +them. The atoms are typically represented by spheres, connected by tubes which +represent the bonds. It was created by using vtkOpenGLMoleculeMapper. +Added vtkSimpleBondPerceiver for detection of bonds. Tests were added and a +demo was created.

    +

    Pull Requests:

    + +
  • +
  • Stick Representation

    +

    Stick model is a special case of Ball and Stick model where atomic radius of all +molecules is set equal to the radius of tubes used to create bonds. It was created +by using vtkOpenGLMoleculeMapper. Tests were added and a demo was created.

    +

    Pull Requests:

    + +
  • +
  • Sphere Representation

    +

    In chemistry, a space-filling model, also known as a calotte or sphere model, is a +type of three-dimensional (3D) molecular model where the atoms are represented by +spheres whose radii are proportional to the radii of the atoms. It was created by +using vtkOpenGLMoleculeMapper. Tests were added and a demo was created.

    +

    Pull Requests:

    + +
  • +
+
+
+

Objectives in Progress#

+
    +
  • Molecular Surfaces

    +

    There are three types of molecular surfaces:

    +
      +
    • Van der Waals

    • +
    • Solvent Accessible

    • +
    • Solvent Excluded

    • +
    +

    Currently the first two molecular surfaces i.e. Van der Waals and Solvent +Accessible are implemented. The code is based on the paper “Generating +Triangulated Macromolecular Surfaces by Euclidean Distance Transform” by +Dong Xu and Yang Zhang.

    +

    Pull Requests:

    + +
  • +
+
+
+

Other Objectives#

+
    +
  • 2D Animated Surfaces

    +

    This was a simple demonstration that animated Two-Dimensional (2D) functions using FURY. +Created a grid of x-y coordinates and mapped the heights (z-values) to the corresponding x, y +coordinates to generate the surfaces. Used colormaps to color the surfaces.

    +

    Pull Requests:

    + +
  • +
  • Updated miscellaneous animations

    +
      +
    • Updated the demo of helical motion to stop using multiple line actors as discussed in the meeting.

    • +
    • Updated the demo of brownian motion to make it more scientifically useful (removed unnecessary rotation of camera +during animation and box actor).

    • +
    • Display simulation data for brownian motion and helical motion animations (number of simulated steps for brownian +motion and velocity of the particle for helical motion).

    • +
    • Created utility functions to make the code understandable and used these in emwave, helical and brownian +animations.

    • +
    +

    Pull Requests:

    + +
  • +
  • GSoC weekly Blogs

    +
    +

    Weekly blogs were added for FURY’s Website.

    +

    Pull Requests:

    + +
    +
  • +
+
+
+

Timeline#

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Date

Description

Blog Link

Week 1(08-06-2021)

Welcome to my GSoC Blog!

Weekly Check-in #1

Week 2(14-06-2021)

First Week of coding: sphere model.

Weekly Check-in #2

Week 3(21-06-2021)

Bonding algorithms, Ball and Stick model progress.

Weekly Check-in #3

Week 4(28-06-2021)

VTK molecular visualization classes.

Weekly Check-in #4

Week 5(05-07-2021)

Genesis of molecular module.

Weekly Check-in #5

Week 6(12-07-2021)

Ribbon representation, updated molecular module (more pythonic)

Weekly Check-in #6

Week 7(19-07-2021)

More features to molecular, updated misc. animations.

Weekly Check-in #7

Week 8(26-07-2020)

Ribbon to molecular, tests for molecular, animated surfaces.

Weekly Check-in #8

Week 9(02-08-2021)

Optimized molecular with mentors, GSoC blogs to FURY docs.

Weekly Check-in #9

Week 10(09-08-2021)

Bounding box, molecular tutorial, molecular surfaces progress.

Weekly Check-in #10

Week 11(16-08-2021)

Molecular Surfaces (VDW, SAS) implementation.

Weekly Check-in #11

+

Detailed weekly tasks and work done can be found +here.

+
+
+ +
+ + + + +
+ + + + Previous: + + + + Google Summer of Code Final Work Product + + + +   + + + + Next: + + + FURY 0.8.0 Released + + + + +
+ + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2021/2021-08-23-gsoc-devmessias-final-report.html b/v0.10.x/posts/2021/2021-08-23-gsoc-devmessias-final-report.html new file mode 100644 index 000000000..cdae7dd60 --- /dev/null +++ b/v0.10.x/posts/2021/2021-08-23-gsoc-devmessias-final-report.html @@ -0,0 +1,898 @@ + + + + + + + + Google Summer of Code 2021 - Final Report - Bruno Messias — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Google Summer of Code 2021 - Final Report - Bruno Messias#

+
+

Abstract#

+

We have changed some points of my project in the first meeting. +Specifically, we focused the efforts into developing a streaming system +using the WebRTC protocol that could be used in more generic scenarios +than just the network visualization. In addition to that, we have opted +to develop the network visualization for fury as a separated repository +and package available here. The +name Helios was selected for this new network visualization system based +on the Fury rendering pipeline.

+
+
+

Proposed Objectives#

+
    +
  • Create a streaming system (stadia-like) for FURY

    +
      +
    • Should work in a low-bandwidth scenario

    • +
    • Should allow user interactions and collaboration across the +Internet using a web-browser

    • +
    +
  • +
  • Helios Network System objectives:

    +
      +
    • Implement the Force-Directed Algorithm with examples

    • +
    • Implement the ForceAtlas2 algorithm using cugraph with examples

    • +
    • Implement Minimum-Distortion Embeddings algorithm (PyMDE) and +examples

    • +
    • Non-blocking network algorithms computation avoiding the GIL using +the Shared Memory approach

    • +
    • Create the documentation and the actions for the CI

    • +
    +
  • +
  • Stretch Goals:

    +
      +
    • Create an actor in FURY to draw text efficiently using shaders

    • +
    • Add support to draw millions of nodes using FURY

    • +
    • Add support to control the opengl state on FURY

    • +
    +
  • +
+
+
+

Objectives Completed#

+
    +
  • Create a streaming system (stadia-like) for FURY

    +

    To construct the streaming system for my project we have opted to +follow three main properties and behaviors:

    +
      +
    1. avoid blocking the code execution in the main thread (where the +vtk/fury instance resides)

    2. +
    3. work inside of a low bandwidth environment

    4. +
    5. make it easy and cheap to share the rendering result. For example, +using the free version of ngrok

    6. +
    +

    To achieve the first property we need to circumvent the GIL and allow +python code to execute in parallel. Using the threading module alone +is not good enough to reach real parallelism as Python calls in the +same process can not execute concurrently. In addition to that, to +achieve better organization it is desirable to define the server +system as an uncoupled module from the rendering pipeline. Therefore, +I have chosen to employ the multiprocessing approach for that. The +second and third property can be only achieved choosing a suitable +protocol for transferring the rendered results to the client. We have +opted to implement two streaming protocols: the MJPEG and the WebRTC. +The latter is more suitable for low-bandwidth scenarios [1].

    +

    The image below shows a simple representation of the streaming +system.

    +
  • +
+
+ ... +
+ +The video below shows how our streaming system works smothly and can +be easily integrated inside of a Jupyter notebook.

Video: WebRTC Streaming + +Ngrok

+

Video: WebRTC Streaming + +Jupyter

+

Pull Requests: * fury-gl/fury#480

+
    +
  • 2D and 3D marker actor

    +

    This feature gave FURY the ability to efficiently draw millions of +markers and impostor 3D spheres. This feature was essential for the +development of Helios. This feature work with signed distance fields +(SDFs) you can get more information about how SDFs works here [4] .

    +

    The image below shows 1 million of markers rendered using an Intel +HD graphics 3000.

    +
  • +
+
+ +
    +
  • Fine-Tunning the OpenGl State

    +

    Sometimes users may need to have finer control on how OpenGL will +render the actors. This can be useful when they need to create +specialized visualization effects or to improve the performance.

    +

    In this PR I have worked in a feature that allows FURY to control the +OpenGL context created by VTK

    +

    Pull Request:

    + +
  • +
  • Helios Network Visualization Lib: Network Layout +Algorithms

    +

    Case 1: Suppose that you need to monitor a hashtag and build a +social graph. You want to interact with the graph and at the same +time get insights about the structure of the user interactions. To +get those insights you can perform a node embedding using any kind of +network layout algorithm, such as force-directed or minimum +distortion embeddings.

    +

    Case 2: Suppose that you are modelling a network dynamic such as +an epidemic spreading or a Kuramoto model. In some of those network +dynamics a node can change the state and the edges related to the +node must be deleted. For example, in an epidemic model a node can +represent a person who died due to a disease. Consequently, the +layout of the network must be recomputed to give better insights.

    +

    In the described cases, if we want a better (UX) and at the same time +a more practical and insightful application of Helios, the employed +layout algorithms should not block any kind of computation in the +main thread.

    +

    In Helios we already have a lib written in C (with a python wrapper) +which performs the force-directed layout algorithm using separated +threads avoiding the GIL problem and consequently avoiding blocking +the main thread. But what about the other open-source network layout +libs available on the internet? Unfortunately, most of those libs +have not been implemented like Helios force-directed methods and +consequently, if we want to update the network layout the Python +interpreter will block the computation and user interaction in your +network visualization.

    +

    My solution for having PyMDE and CuGraph-ForceAtlas not blocking the +main thread was to break the network layout method into two different +types of processes: A and B and communicate both process using the +Shared Memory approach. You can more information about this PR +through my following posts [2], [3].

    +
  • +
+

The image below show an example that I made and is available at +fury-gl/helios

+

image2 Pull Requests:

+ +

I’ve made several stuffs to give Helios a better visual aspects. One of +them was to give a smooth real-time network layout animations. Because +the layout computations happens into a different process that the +process responsible to render the network was necessary to record the +positions and communicate the state of layout between both process.

+

The GIF below shows how the network layout through IPC behaved before +these modification

+
+ +

below, you can see how after those modifications the visual aspect is +better.

+
+... +

Pull Requests:

+ +

Because Helios was an project that begins in my GSoC project It was +necessary to create the documentation, hosting and more. Now we have a +online documentation available at https://heliosnetwork.io/ although the +documentation still need some improvements.

+

The Helios Logo which was developed by +Filipi Nascimento.

+Helios Network Logo

Pull Requests:

+
    +
  • CI and pytests: fury-gl/helios#5, +fury-gl/helios#20

  • +
  • Helios Logo, Sphinx Gallery and API documentation +fury-gl/helios#18

  • +
  • Documentation improvements: +fury-gl/helios#8

  • +
  • Objectives in Progress

    +
  • +
  • Draw texts on FURY and Helios

    +

    This two PRs allows FURY and Helios to draw millions of characters in +VTK windows instance with low computational resources consumptions. I +still working on that, finishing the SDF font rendering which the +theory behinds was developed here [5].

    +

    Pull Requests:

    + +
  • +
  • GSoC weekly Blogs

    +

    Weekly blogs were added to the FURY Website.

    +

    Pull Requests:

    + +
  • +
+
+
+

Timeline#

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Date

Description

Blog Link

Week 1 +(08-06-2021)

Welcome to my weekly Blogs!

Weekly Check-in +#1

Week 2 +(14-06-2021)

Post #1: A Stadia-like +system for data +visualization

Weekly Check-in +# +2

Week 3 +(21-06-2021)

2d and 3d fake impostors +marker; fine-tunning +open-gl state; Shared +Memory support for the +streaming system; +first-version of helios: +the network visualization +lib for helios

Weekly Check-in +#3

Week 4 +(28-06-2020)

Post #2: SOLID, monkey +patching a python issue and +network layouts through +WebRTC

Weekly Check-in +#4

Week 5 +(05-07-2021)

Code refactoring; 2d +network layouts for Helios; +Implemented the Minimum +distortion embedding +algorithm using the IPC +approach

Weekly Check-in +#5

Week 6 +(12-07-2020)

Post #3: Network layout +algorithms using IPC

Weekly Check-in +#6

Week 7 +(19-07-2020)

Helios IPC network layout +algorithms support for +MacOs; Smooth animations +for IPC layouts; +ForceAtlas2 network layout +using cugraph/cuda

Weekly Check-in +#7

Week 8 +(26-07-2020)

Helios CI, Helios +documentation

Weekly Check-in +#8

Week 9 +(02-08-2020)

Helios documentation; +improved the examples and +documentation of the WebRTC +streaming system and made +some improvements in the +compatibility removing some +dependencies

Weekly Check-in +#9

Week 10 +(09-08-2020)

Helios documentation +improvements; found and +fixed a bug in fury w.r.t. +the time management system; +improved the memory +management system for the +network layout algorithms +using IPC

Weekly Check-in +#10

Week 11 +(16-08-2020)

Created a PR that allows +FURY to draw hundred of +thousands of characters +without any expensive GPU; +fixed the flickering effect +on the streaming system; +helios node labels feature; +finalizing remaining PRs

Weekly Check-in +#11

+

Detailed weekly tasks, progress and work done can be found +here.

+
+

References#

+

[1] ( Python GSoC - Post #1 - A Stadia-like system for data +visualization - demvessias s Blog, n.d.; +https://blogs.python-gsoc.org/en/demvessiass-blog/post-1-a-stadia-like-system-for-data-visualization/

+

[2] Python GSoC - Post #2: SOLID, monkey patching a python issue and +network layouts through WebRTC - demvessias s Blog, n.d.; +https://blogs.python-gsoc.org/en/demvessiass-blog/post-2-solid-monkey-patching-a-python-issue-and-network-layouts-through-webrtc/

+

[3] Python GSoC - Post #3: Network layout algorithms using IPC - +demvessias s Blog, +n.d.)https://blogs.python-gsoc.org/en/demvessiass-blog/post-3-network-layout-algorithms-using-ipc/

+

[4] Rougier, N.P., 2018. An open access book on Python, OpenGL and +Scientific Visualization [WWW Document]. An open access book on Python, +OpenGL and Scientific Visualization. URL +rougier/python-opengl (accessed 8.21.21).

+

[5] Green, C., 2007. Improved alpha-tested magnification for vector +textures and special effects, in: ACM SIGGRAPH 2007 Courses on - +SIGGRAPH ’07. Presented at the ACM SIGGRAPH 2007 courses, ACM Press, San +Diego, California, p. 9. https://doi.org/10.1145/1281500.1281665

+
+
+
+ +
+ + + + + + + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2021/2021-09-08-gsoc-devmessias-10.html b/v0.10.x/posts/2021/2021-09-08-gsoc-devmessias-10.html new file mode 100644 index 000000000..9b1a1f5fe --- /dev/null +++ b/v0.10.x/posts/2021/2021-09-08-gsoc-devmessias-10.html @@ -0,0 +1,580 @@ + + + + + + + + Week #10: SDF Fonts — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Week #10: SDF Fonts#

+
+

What did I do this week?#

+
+

FURY/Helios#

+ +
+
+

FURY#

+ +
+
+
+

Did I get stuck anywhere?#

+

I did not get stuck this week.

+
+
+

What is coming up next?#

+

I’ll discuss that with my mentors tomorrow.

+
+
+ +
+ + + + + + + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2021/2021-16-08-gsoc-devmessias-11.html b/v0.10.x/posts/2021/2021-16-08-gsoc-devmessias-11.html new file mode 100644 index 000000000..13fe3928d --- /dev/null +++ b/v0.10.x/posts/2021/2021-16-08-gsoc-devmessias-11.html @@ -0,0 +1,613 @@ + + + + + + + + Week #11: Removing the flickering effect — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Week #11: Removing the flickering effect#

+
+

What did I do this week?#

+
+

FURY#

+ +
+

This PR give to FURY three +pre-built texture maps using different fonts. However, is quite easy +to create new fonts to be used in a visualization.

+
+
+
It’s was quite hard to develop the shader code and find the correct +positions of the texture maps to be used in the shader. Because we +used the freetype-py to generate the texture and packing the glyps. +However, the lib has some examples with bugs. But fortunelly, now +everything is woking on FURY. I’ve also created two different examples +to show how this PR works.
+
+
+

The first example, viz_huge_amount_of_labels.py, shows that the user can +draw hundreds of thousands of characters.

+

image2

+

The second example, viz_billboad_labels.py, shows the different behaviors of the label actor. In addition, presents +to the user how to create a new texture atlas font to be used across different visualizations.

+
+
    +
  • PR fury-gl/fury#437:

    +
      +
    • +
      Fix: avoid multiple OpenGl context on windows using asyncio

      The streaming system must be generic, but opengl and vtk behaves in uniques ways in each Operating System. Thus, can be tricky +to have the same behavior acrros different OS. One hard stuff that we founded is that was not possible to use my +TimeIntervals objects (implemented with threading module) with vtk. The reason for this impossibility is because we can’t use +vtk in windows in different threads. But fortunely, moving from the threading (multithreading) to the asyncio approcach (concurrency) +have fixed this issue and now the streaming system is ready to be used anywhere.

      +
      +
      +
    • +
    • Flickering:

      +
      +

      Finally, I could found the cause of the flickering effect on the streaming system. +This flickering was appearing only when the streaming was created using the Widget object. +The cause seems to be a bug or a strange behavior from vtk. +Calling iren.MouseWheelForwardEvent() or iren.MouseWheelBackwardEvent() +inside of a thread without invoking the +Start method from a vtk instance produces a memory corruption. +Fortunately, I could fix this behavior and now the streaming system is +working without this glitch effect.

      +
      +
    • +
    +
  • +
+
+
+

FURY/Helios#

+ +

This uses the +PRfury-gl/fury#489: to +give the network label feature to helios. Is possible to draw node +labels, update the colors, change the positions at runtime. In addition, +when a network layout algorithm is running this will automatically +update the node labels positions to follow the nodes across the screen.

+

image1

+ +

This PR granted compatibility between IPC Layouts and Windows. Besides +that , now is quite easier to create new network layouts using inter +process communication

+
+
+
+

Did I get stuck anywhere?#

+

I did not get stuck this week.

+
+
+ + + +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2022/2022-01-31-release-announcement.html b/v0.10.x/posts/2022/2022-01-31-release-announcement.html new file mode 100644 index 000000000..0b3e7fa05 --- /dev/null +++ b/v0.10.x/posts/2022/2022-01-31-release-announcement.html @@ -0,0 +1,547 @@ + + + + + + + + FURY 0.8.0 Released — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

FURY 0.8.0 Released#

+

The FURY project is happy to announce the release of FURY 0.8.0! +FURY is a free and open source software library for scientific visualization and 3D animations.

+

You can show your support by adding a star on FURY github project.

+

This Release is mainly a maintenance release. The major highlights of this release are:

+
    +
  • New Physically Based Rendering (PBR) added. It includes anisotropic rotation and index of refraction among other material properties.

  • +
  • New Principled BRDF shader unique to FURY added. BRDF stands for bidirectional reflectance distribution function.

  • +
  • VTK 9.1.0 defined as minimum version.

  • +
  • Continuous Integration (CI) platform updated.

  • +
  • New actors added (Rhombicuboctahedron, Pentagonal Prism).

  • +
  • New UI layouts added (Vertical and Horizontal).

  • +
  • New module fury.molecular added.

  • +
  • New module fury.lib added. Module improved loading speed.

  • +
  • Demos added and updated.

  • +
  • Documentation updated.

  • +
+
+

Note

+

The complete release notes are available here

+
+

To upgrade or install FURY

+

Run the following command in your terminal:

+
pip install --upgrade fury
+
+
+

or:

+
conda install -c conda-forge fury
+
+
+

Questions or suggestions?

+

For any questions go to http://fury.gl, or send an e-mail to fury@python.org +We can also join our discord community

+

We would like to thanks to all contributors for this release:

+
    +
  • Anand Shivam

  • +
  • Antriksh Misri

  • +
  • Bruno Messias

  • +
  • Eleftherios Garyfallidis

  • +
  • Javier Guaje

  • +
  • Marc-Alexandre Côté

  • +
  • Meha Bhalodiya

  • +
  • Praneeth Shetty

  • +
  • PrayasJ

  • +
  • Sajag Swami

  • +
  • Serge Koudoro

  • +
  • Shivam Anand

  • +
+

On behalf of the FURY developers,

+

Serge K.

+
+ +
+ + + + + + + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2022/2022-02-01-gsoc.html b/v0.10.x/posts/2022/2022-02-01-gsoc.html new file mode 100644 index 000000000..855939ff5 --- /dev/null +++ b/v0.10.x/posts/2022/2022-02-01-gsoc.html @@ -0,0 +1,504 @@ + + + + + + + + Contribute to FURY via Google Summer of Code 2022 — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Contribute to FURY via Google Summer of Code 2022#

+

FURY is participating in the Google Summer of Code 2022 under the umbrella of the Python Software Foundation.

+

FURY is a free and open source software library for scientific visualization and 3D animations. FURY contains many tools for visualizing a series of scientific data including graph and imaging data.

+

A list of project ideas and application info is on our GitHub Wiki.

+

If you are interested in talking to us about projects, applications join us to our discord community or drop us a line on our mailing list.

+

Be part of our community and Enjoy your summer of code!

+

Serge K.

+
+ +
+ + + + +
+ + + + Previous: + + + + FURY 0.8.0 Released + + + +   + + + + Next: + + + My journey till getting accepted into GSoC22 + + + + +
+ + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2022/2022-05-23-first-post-mohamed.html b/v0.10.x/posts/2022/2022-05-23-first-post-mohamed.html new file mode 100644 index 000000000..1b1dfce2c --- /dev/null +++ b/v0.10.x/posts/2022/2022-05-23-first-post-mohamed.html @@ -0,0 +1,586 @@ + + + + + + + + My journey till getting accepted into GSoC22 — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

My journey till getting accepted into GSoC22#

+
+

A Little About Myself#

+

My name is Mohamed and I’m from Egypt. I am pursuing a Bachelor of Engineering in Computer Engineering and Automatic Control (expected: 2023), Tanta University, Egypt.

+

I’ve been around computers since 2008 when I had my first PC with 128MB RAM and ran on Windows XP (that’s almost all I could remember about it).

+

Around 2013, I had some questions about how games are made and how to make them myself! +There was no one to answer these questions for me.

+

My english wasn’t any good and the game development arabic community was very hard to find on the internet. But eventually, I came across a forum with some people speaking about some stuff such as game engines, 3D models, textures, animations, and a lot of fun stuff. That made sense back then and answered some of my questions. Then It was time to get involved with this amazing community. I was lucky enough to start with 3ds Max 2009 Edition, with that little view cube begging me to touch it. It was just love at first sight.

+

I learned enough to model a basic house with no interior or a low poly human face.

+

I was very curious about these game engines. Back then, the top three game engines available for the public were CryEngine 3, UDK, and Unity.

+

I was advised to use CryEngine 3 since it required no coding experience to use it. I started designing and texturing terrains and adding 3D models (I remember adding a pyramid and had a hard time scaling it down).

+
+
+

My first coding experience#

+

It started with C programming language, which I came across while taking Harvard’s CS50. I then used it in competitive programming as my primary language.

+

When I heard about OpenGL API for the first time from a senior and that it is being used to develop game engines, I started learning it along with GLSL.

+

And it finally hit me: It is all math!

+

I then started practicing pipelines, lighting models such as Blinn and Blinn-Phong models, cameras, texturing, fog, skybox, shadows, etc…

+
+
+

Developing a 3D game#

+

In the Graphics course, OpenGL was being taught to us using python and there was a course project!

+

I started preparing my notes and the shaders I wrote during that summer, only for the Professor to restrict us to use OpenGL v1.0 and only use PyOpenGL and Pygame.

+

So, no Numpy, no PyGLM, fixed pipelines, no custom shaders, and each vertex had to be sent individually to the GPU.

+

At first, I got disappointed, but while developing the game, I had a lot of optimization challenges that made me have fun figuring out how to still make the 3D game I’ve always wanted to make!

+

I searched on GitHub for similar projects to the one I’m trying to make and did not find any 3D FPS game using this version of OpenGL (at least not listed publicly).

+

I ended up implementing almost everything from scratch.

+

Real-world physics inspired the physics of the game. This means that I have collected data about walking speed, running speed, initial jumping velocity, and gravity. Even the sound Sound intensity is inversely proportional to the square of the distance between the source and the player.

+

I used Interpolation (bilinear interpolation) to interpolate the terrain’s height (y) at any given (x-z) coordinates so that entities can move on 64*64 pixels height map based terrain smoothly to reduce the number of triangles. I also implemented for this game an animation system that used obj sequence animations, then optimized it to load faster, and consume 95% less disk space compared to the non-optimized form.

+

Source code of the game: MummyIsland

+
+
+

My journey to GSoC22#

+

I first knew about GSoC from a friend last year. I then went through the organization’s list. There were a lot of familiar names that I recognized such as Anki, Godot, Blender.

+

Then I glanced at the Python software foundation. I had to go in and scroll through the sub-organizations only to come across FURY. The luminous horse got my attention. I felt the connection right away.

+

I went through the docs of both FURY and VTK.

+

I tried to contribute back then by adding the option to use the FXAA anti-aliasing algorithm for the window (I didn’t notice it has already been implemented as a method for the window).

+

So instead, I implemented the first mentioned shader in the GSoC 21’s project idea “Add new shader effects” (the fire shader) in GLSL using Gaussian noise.

+

The next step was to implement the shader to make it work with FURY actors but then I knew I’m having a mandatory training required by the University last summer. I was disappointed, and I decided to postpone until next year’s GSoC.

+

This year when the accepted organizations were announced, I didn’t bother to go through the list since I knew exactly which organization I’m going to apply for. So I just went directly to read the Ideas list for FURY.

+

The keyframe animation system was the perfect match! I have been around keyframes for half of my life to even guess the required features before I read them! I then started to contribute and one contribution led to the other one.

+

Code contributions:

+
    +
  1. fury-gl/fury#552

  2. +
  3. fury-gl/fury#555

  4. +
+
+
+

The day I got accepted#

+

I made it my mission for the day to keep watching the email for any changes. When It got 8:00 pm in the Cairo timezone, I didn’t see any changes. So I started searching for any news whatsoever and I couldn’t find any. +The GSoC dashboard doesn’t say anything (story of my life. I didn’t even get any promotions or spam mails that day). That’s when I gave up. But, something doesn’t feel right! Right? I went again to check the dashboard to find that my proposal got accepted. I couldn’t even believe it. I would better not jump to conclusions and wait for the official email before celebrating. Shortly after, I received the official email. It was a whole new feeling I had never experienced ever before! I reached a whole new level of happiness.

+
+
+ +
+ + + + + + + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2022/2022-05-24-my-journey-to-gsoc-2022-shivam.html b/v0.10.x/posts/2022/2022-05-24-my-journey-to-gsoc-2022-shivam.html new file mode 100644 index 000000000..86219fe5b --- /dev/null +++ b/v0.10.x/posts/2022/2022-05-24-my-journey-to-gsoc-2022-shivam.html @@ -0,0 +1,557 @@ + + + + + + + + My Journey to GSoC 2022 — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

My Journey to GSoC 2022#

+
+

About Myself#

+

Hi! I’m Shivam, currently pursuing my bachelor’s (expected 2024) in Production and Industrial engineering from the Indian Institute of Technology (IIT) Roorkee.

+

I was introduced to the C programming language through the Introduction to programming course in my first year of college. I always liked computers, and I was overwhelmed by printing “hello world” in the terminal. The course continued to teach us data structures and algorithms. It was a lot of fun competing with friends over a programming question. I learned python on my own and did a lot of projects. After learning basic programming, I participated in many hackathons and won some, but lost a lot. Coding was enjoyable, and I knew this was what I wanted to do for the rest of my life. +In my second semester, I learned about open-source, git, and GitHub. I came across some computer graphics enthusiasts in my college; they told me that they created a 2D game engine on their own using OpenGL. This gave me enough motivation to learn OpenGL and basic computer graphics.

+
+
+

Intro to Open-Source and GSoC#

+

In October 2021, I participated in Hactoberfest and completed it successfully. I learned a lot about Free and Open Source Software during this time. I heard about GSoC around this time from one of my seniors and asked him about the program.

+

I went through the previous year’s accepted organizations list and shortlisted 2-3 organizations. I started contributing to a few projects based on android and kotlin, but I lost interest after some time. +It was about December, and I hadn’t chosen any organization yet.

+

I heard about FURY from one of my seniors. I started looking at its docs. Picked up some books from the library to brush up on my concepts of computer graphics. The documentation of FURY is remarkable. I created my first pull request by improving one of the tutorials, and It got merged in a few days.

+

I started looking at the source code of FURY and tried to understand it again. I read the API reference part of FURY docs this time along with the documentation of VTK. I also tried to solve some of the open issues. I created a few pull requests for the same. My first contribution was in the fury primitive class, I created a sphere primitive (inspired by the sphere in Blender).

+

I started looking at bugs and improvements that can be made to the source code and created PRs for the same. During this time I was also learning how computer graphics work from the UCSC lectures & OpenGL by Victor Gordon.

+

After the accepted organizations were announced, I was so happy that FURY got selected this year for GSoC and went straight to the Ideas list. The first project idea was glTF Integration. I heard about the glTF file format before but didn’t know how it works. So I went straight through the reference materials provided on the wiki. I read a lot of documentation by the Khronos group. I also tried to implement a basic glTF loader during this time using VTK’s built-in glTFReader.

+

I also liked the Improve UI drawing project idea (I had a basic understanding of line drawing algorithms and rasterizations at that time) and thought I’ll make a proposal for that too. After completing my proposal for glTF integration I started my research on this one too.

+

I started writing the proposal early so that I could get my proposal reviewed at least once with the project mentors. I almost forgot the fact that I had my end-term examinations at hand (Somehow I managed to pass all of my courses), I kept contributing to the project till the end of April 2022.

+

Code contributions:

+
    +
  1. [fury-gl/fury#520]

  2. +
  3. [fury-gl/fury#525]

  4. +
  5. [fury-gl/fury#533]

  6. +
  7. [fury-gl/fury#547]

  8. +
  9. [fury-gl/fury#556]

  10. +
  11. [fury-gl/fury#559]

  12. +
+
+
+

The Day#

+

May 18: I was a bit anxious since on May 18th the GSoC website was showing my proposal for glTF integration had been rejected. (p.s. maybe it was a bug of some sort that they fixed later on).

+

May 20: I woke up very early in the morning and started checking the contributor’s profile. I kept checking for new emails but didn’t receive any emails that day. “The result will be announced at 11:30 PM, isn’t it? “ My dad said, It was 8:00 AM Indian Standard Time. I called my friends in the night to join me on discord, I was talking to them and refreshing the GSoC site at the same time. One of my friends shouted that he got selected in NumFocus. I refreshed the page again, my proposal for glTF Integration was accepted. I can’t express what I felt at that moment. I told my friends and my parents, they were happy for me and I got a lot of blessings :). I received an official email the next day.

+
+
+ +
+ + + + +
+ + + + Previous: + + + + My journey till getting accepted into GSoC22 + + + +   + + + + Next: + + + Pre-GSoC Journey + + + + +
+ + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ +
+ +
+ On this page +
+ +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2022/2022-05-25-pre-gsoc-journey-praneeth.html b/v0.10.x/posts/2022/2022-05-25-pre-gsoc-journey-praneeth.html new file mode 100644 index 000000000..f602081a7 --- /dev/null +++ b/v0.10.x/posts/2022/2022-05-25-pre-gsoc-journey-praneeth.html @@ -0,0 +1,561 @@ + + + + + + + + Pre-GSoC Journey — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Pre-GSoC Journey#

+
+

The Beginning of Programming#

+

Hello Guys!! I am Praneeth Shetty, currently pursuing Bachelor of Engineering in Computer Engineering, and here is my journey from where I started to the selection into GSoC22.

+

My programming journey started way back in 7th std, where we had a subject called Information Technology in which the last two lessons were based on HTML and Javascript. I loved to create simple pages in HTML but was struggling to learn Javascript as it felt a bit complex at the start. +I would practice these programs in our computer lab whenever we would have our practical lab (once or twice a month). +Next year I received a laptop from my cousin brother(which I still use). While setting up the things he started enquiring about my academics and asked me to create an HTML code. He was happy to see that I could do that so to explain to me the usage of javascript he created a small program. He executed it and gave it to me, where it was written “Enter your Name?” I typed Praneeth and pressed Enter. A new page was loaded with a Text stating “Hello Praneeth!! How are you??” I was amazed to see the output. How could that machine know me and greet me?? Is Javascript such a powerful tool?? Can I make the computer talk using Javascript?? These questions flooded my mind. That day I realized that, If I had a good command of Javascript, I could control the whole computer and can make it do whatever I want. Because of this I started giving more attention to Javascript.

+
+
+

Interest in Game Development and Animation#

+

Around one and a half years after this, I was able to code basic javascript programs. In my vacation while I was searching for a gameplay video on Youtube, A video titled “How to make a Game” by Brackeys grabbed my attention and made me click on it. I watched the whole video but was unable to understand the most of the things ie transform, rigidbody, mesh, collider etc. But it generated an internal feeling that I can also create a game. I tried to replicate the process in the video but when I went on to the Official Website of Unity(Game Engine) the whole package size was around 1.5 Gigabytes which was a huge sum at that time(the time when 2G ruled and 100 Megabytes was for 10 INR). So I was unable to work on it. But still, some unknown inspiration motivated me to watch the whole “How to make a Game” playlist of 10 videos. As I moved ahead some concepts were getting cleared and I had a surface level idea of how to make things work in game(Not how games actually worked). As I was pretty much immersed into game development my feeds started showing “How to create a 3D character”, “How to Animate” videos which led me to discover Blender, 3Ds Max, etc. animation software. +I downloaded Blender as it was a lightweight free package and started messing around with things in it. But after a few months Blender made some remarkable changes and brought version 2.80 which required a few system specifications which my laptop didn’t satisfied. +By this time I used to spend some extra hours in my College to learn Unity and created my first Game which was an exact copy of the Brackeys Game Series. I was very happy to successfully create a game all on my own and used to think what all new features can be added to it.

+
+
+

Intro to Opensource#

+

While finding alternatives to Unity and Blender, I found a lightweight software called Godot and I was surprised to see the whole game engine was just around 100 Megabytes(which compared to Unity and Unreal is 10/20 times smaller). I tried searching about How and Why is Godot so Small and one of the reasons I found was, it is an open source software. I had heard this term before while working with blender but still was unable to clearly understand what it is. Another answer I received is an extended application of the previous one which stated most features are implemented from scratch by various contributors in open source software whereas in other big software libraries are used a lot for very minimalistic features too which make it dependent and bulky. Around this time I had also switched to Python and was working on some mini projects and games using it. It also helped me in working with Godot, which has its own language called GDScript which resembles python.

+
+
+

GSoC - 21#

+

As I was drowning in the oceans of Open Source, I read some blogs which mentioned some of the programs and events related to it viz. Google Summer of Code (GSoC), Hacktoberfest, GirlScript Summer of Code(GSSoC), etc. +I was excited to participate in these events but wasn’t getting proper guidance. I used to watch interviews and best practices for these events due to which I found out that for GSoC we have to select the organizations then apply and this would be the basic flow of the program. So taking this into consideration I started searching for organizations on GSoC archives. Firstly I was looking for any Javascript related project as I had a better command on it than python and there I found out about p5.js which was a creative coding library. I forked their repo, cloned it, and then tried to build it on my local machine but after many attempts I was still unsuccessful to build it locally. I raised a question in their community and also mailed an old GSoC student but they too were unable to solve the query. This disappointed me a lot and kind of I was going to end my opensource journey here, but just thought of giving it a try again. While searching through the organizations I found lots of known projects regarding which I had no idea that those too were open source. While searching I found Python Software Foundation in the organization list and thought why not to consider python. After looking into the organization I found out that PSF was an umbrella project for many sub projects in which FURY(Free Unified Rendering in pYthon) suited me the most because I was a beginner and didn’t had any idea regarding the data analysis, API formation and the other stuff. But because of prior experience and interest in Game Dev, I was comfortable with FURY. I again forked, cloned and tried to execute the first tutorial on it, it took few minutes to run then few more minutes to download some required files and then a black box appeared but with nothing on it, I thought there would be some error with something so re executed it and it took few minutes and the first Earth Animation tutorial was successfully executed. I was fascinated by viewing the visuals of the Earth with the orbiting moon and the satellite animation (I had doubts whether my laptop will be able to handle these computations or not, but till now It hasn’t proved me wrong in most of the cases). I checked the code then and within 200 lines of code all this was all possible. That made me understand the real power of FURY. After this I checked for some of the good first issues but as it was GSoC period most of the issues were under process so I tried to learn more about the tutorials and the code. There I found a few documentation errors which I fixed as my first PR. I also pointed out some issues which I faced while working with FURY. FURY has a great discord community which engages newbies and solves most of their issues. After two months GSoC Contributors Applications started and I also tried to apply for the same. I created a proposal on Improving the UI system but due to lack of experience and as I was unable to prove my coding skills, I was rejected. But this didn’t disengage me from FURY. I loved the simplicity by which each part was created. Then as time passed I worked on some of the issues and created some more PRs.

+
+
+

GSoC - 22#

+

Again this year GSoC Started with new rules, new energy and with more enthusiasm I too prepared to participate in it. Five new ideas were posted for GSoC in which I again chose the UI improvement as I had a good understanding of the existing UI system in FURY. Last year’s experience helped me a lot in creating the proposal. This time I was also prepared(compared to last time) as I had made some contributions and also had spent time on the code base to understand it. Days passed and lastly the result day arrived, anxiety was at its peak. I had set an alarm to remind me to keep checking the mail for the result, refreshing and changing tabs. Exactly at 11:32 PM Indian Standard Time, a mail dropped with the subject “Congratulations, your proposal with Python Software Foundation has been accepted!” and my happiness had no bound.

+
+
+ +
+ + + + + + + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2022/2022-06-08-week-1-mohamed.html b/v0.10.x/posts/2022/2022-06-08-week-1-mohamed.html new file mode 100644 index 000000000..592faf1e0 --- /dev/null +++ b/v0.10.x/posts/2022/2022-06-08-week-1-mohamed.html @@ -0,0 +1,554 @@ + + + + + + + + Week 1: Implementing a basic Keyframe animation API — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Week 1: Implementing a basic Keyframe animation API#

+
+

What did you do during the Community Bonding Period?#

+

During the community bonding period, we had weekly meetings in which I got to know the mentors better and bonded with Shivam and Praneeth, my fellow contributors. +We talked about the importance of open-source contribution and discussed scientific visualization, how important it is and how it differs from game engines despite having some similarities. +We also discussed how important the code review is and how to do a proper code review.

+
+
+

What did you do this week?#

+

I continued implementing the Timeline class. Added some functionalities according to what we discussed in the weekly meeting, such as handling Fury Actors, adding, removing, translating, scaling them according to the keyframes. Then made two tutorials for it with simple UI to control the playback of the animation.

+
+
+

Reviewed Bruno’s PR #424 as Filipi advised to help me figure out how to change uniforms’ values during runtime. I found it straightforward. I also found a similar method already used in some tutorials and experiments to set the time uniform, which is based on the same idea. They both are using shaders callback functions. +Going through the VTK’s documentations, I found a more efficient way to do this. It’s newly implemented in VTK 9, does not require callbacks, and is easy to use on individual actors. I had to verify first that Fury does not support an older version of VTK and it does not. I tested it and ran into some issues so As Filip instructed I don’t waste a lot of time with uniforms so I postponed it for the next week.

+

Also, when I was attending Shivam’s meeting, he showed us a smooth glTF model which differed from the last time I saw it. When I asked him he said he applied the normal. Him saying that reminded me of how we can use normals to smooth shade a shapes. I applied this trick to the sphere actor in this PR #604 and worked as expected.

+
+
+

What is coming up next week?#

+

If the implemented Timeline is good to go, I will write the associated tests, finish up any missing methods, and document it properly. +I will probably continue implementing the other interpolation methods as well.

+
+
+

Did you get stuck anywhere?#

+

I got stuck changing the color of some actors.

+
+
+ +
+ + + + +
+ + + + Previous: + + + + Week 2 - Improving DrawPanel UI + + + +   + + + + Next: + + + Week 1 - A Basic glTF Importer + + + + +
+ + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2022/2022-06-08-week-1-praneeth.html b/v0.10.x/posts/2022/2022-06-08-week-1-praneeth.html new file mode 100644 index 000000000..f1de0736a --- /dev/null +++ b/v0.10.x/posts/2022/2022-06-08-week-1-praneeth.html @@ -0,0 +1,550 @@ + + + + + + + + Week 1 - Laying the Foundation of DrawPanel UI — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Week 1 - Laying the Foundation of DrawPanel UI#

+

This week we started with our first technical meeting in which the weekly tasks were assigned. So I had to start with some background or canvas and draw a line using mouse clicks.

+
+

What did you do this week?#

+

I started with a simple Panel2D (which is basically a movable rectangle on which we can add other UI elements) as a background and then assigned its mouse click callback to print “Clicked!” to verify the event triggering.

+

Then I modified the event callback to create a Rectangle2D at that current mouse position(Now you would ask, Why Rectangle2D?? We wanted to change the width of the line, which wasn’t possible with the regular line). This would create a rectangle at that point but it had size. +So I had to then calculate the distance between the first point where the mouse was clicked and the current position to resize it accordingly.

+https://user-images.githubusercontent.com/64432063/174661567-76251ce9-380f-4a41-a572-65865d028a9c.gif +

This thing creates a Rectangle, not a line. So I had to think of some other approach. +The first thing that came to my mind was to keep the width of the rectangle constant and apply some rotation to the rectangle according to the mouse position and this worked!

+https://user-images.githubusercontent.com/64432063/174661632-98e1c4ec-31a2-4c4d-8e52-7bf2a47592c7.gif +

As previously we created an interactive rectangle(unintentionally), I thought it would be great if I could add different modes for creating different shapes(ie. line, rectangle, circle as these shapes already existed in the UI System).

+

Considering this I implemented a class to create and manage these shapes and a panel to select which shape is to be drawn along with a TextBlock2D to show the current mode.

+

DrawPanel UI:

+

fury-gl/fury#599

+https://user-images.githubusercontent.com/64432063/174661680-8a5120ff-ec88-4739-945b-b87074f9742b.gif +
+
+

Did you get stuck anywhere?#

+

I was facing issues with implementing the rotation. I scanned the utils to find some method to do the same but there wasn’t any for Actor2D. Then I read some docs and tried out various functions. +At last, I decided to implement it by the most general method which is to calculate the new rotated points by multiplying them with the rotation matrix and that seemed fine for now!!

+
+
+

What is coming up next?#

+

Deletion of the shapes is to be implemented along with tests and tutorials.

+
+
+ +
+ + + + +
+ + + + Previous: + + + + Pre-GSoC Journey + + + +   + + + + Next: + + + Week 2 - Improving DrawPanel UI + + + + +
+ + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2022/2022-06-15-week-2-praneeth.html b/v0.10.x/posts/2022/2022-06-15-week-2-praneeth.html new file mode 100644 index 000000000..b140ab5c0 --- /dev/null +++ b/v0.10.x/posts/2022/2022-06-15-week-2-praneeth.html @@ -0,0 +1,541 @@ + + + + + + + + Week 2 - Improving DrawPanel UI — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Week 2 - Improving DrawPanel UI#

+
+

What did you do this week?#

+

This week I had to refactor and make my code cleaner along with some bug fixing, I started by adding tests and tutorials so that my changes could be tested by everyone. Then I separated the mode for selection so that it would be easy to select an individual element and work along with it. Once the selection mode was complete I started with the deletion of the elements.

+

Now, as we have various modes the question arises, How do we know which mode is currently active and how would users know it?? For this, I took references from some other similar applications and came up with an idea to toggle the icon of the selected mode whenever the mode is selected/deselected as we had individual buttons with an icon for each mode.

+

fury-gl/fury#599

+https://user-images.githubusercontent.com/64432063/174710174-87604e78-e563-458d-8db7-28941301b02c.gif +

Along with this I also started to learn how to access key events so that in near future some keyboard shortcuts can be added.

+
+
+

Did you get stuck anywhere?#

+

No, Everything went well.

+
+
+

What is coming up next?#

+

In the current version of the DrawPanel, the shapes can be created and translated beyond the canvas boundaries, so we have to clamp the positions according to the canvas.

+
+
+ + + +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2022/2022-06-20-week1-shivam.html b/v0.10.x/posts/2022/2022-06-20-week1-shivam.html new file mode 100644 index 000000000..45538d1c7 --- /dev/null +++ b/v0.10.x/posts/2022/2022-06-20-week1-shivam.html @@ -0,0 +1,565 @@ + + + + + + + + Week 1 - A Basic glTF Importer — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Week 1 - A Basic glTF Importer#

+
+

What did you do during the Community Bonding Period?#

+

In the community bonding period I met with my mentor Serge Koudoro, along with other mentors in FURY and gsoc contributors. +We discussed about my project and set up project timeline on github projects section. As my project (glTF Integration) +and Keyframe animations were related so we discussed on that too.

+

I read documentation of various glTF loading libraries (pygltflib, panda3D-gltf and pyrender) in python and tried to understand how do they work. +I started creating a basic glTF loader, it was using dataclasses to store json data. I created polydata for each primitive in a mesh, each polydata will contain the vertices, triangles, normals. +To apply textures properly, I had to apply texture coordinates to polydata and flip the texture along X axis by 90 degrees.

+
+
+

What did you do this week?#

+

After discussing on pros and cons of various glTF libraries we decided to use pygltflib to handle json to python dataclass conversion. +This week I reshaped PR #600 to use pygltflib. I also modified the code to handle multiple base textures. +While experimenting with textures, I accidentally applied normals to the polydata and discovered that it makes the surface look much smoother, however in few models it results in a darker model which reflects almost no light. So I made it optional for now to apply normals in a model.

+

I also created a basic fetcher (PR #602) to get glTF models from Khronos group’s glTF sample repository. +I also made this function asynchronous, as Serge suggested me to use asyncio and aiohttp to make the API callbacks asynchronous and it decreased the downloading time of multiple models.

+

I am also working on exporting scene to a glTF file. Using pygltflib I am converting the python dataclass to a json like structure.

+
+
+

What is coming up next week?#

+

Create a PR for the fetcher function, add tests, fix bugs and merge it by the end of the week. +Fix the colors issue in the glTF exporter. +Add texture and camera in glTF exporter and create a PR for it.

+
+
+

Did you get stuck anywhere?#

+
    +
  • var: list[int] was causing the error TypeError: 'type' object is not subscriptable since the ability to use the [] operator on types like list was added in 3.9+. I had to modify the dataclasses and use Typing.List instead.

  • +
  • Texture in actors weren’t applied correctly. I tried flipping the texture image by 90 degrees using gimp and the texture worked nicely. The reason for this issue was the coordinate system of glTF texture format which has origin (0, 0) at top-left and (1, 1) in the bottom-right corner, Where as in vtkTexture we want coordinate (0, 0) and (1, 1) at bottom-left and top-right corner respectively. Here’s an example of the issue:

  • +
+https://raw.githubusercontent.com/xtanion/Blog-Images/main/-1_orig.jpg +
    +
  • Praneeth told me that some models with multiple nodes and multiple meshes weren’t loading correctly. The reason for it was the way SCALAR data was extracted from the binary blob, I had to change some variables in get_accessor_data method and everything started to work just fine.

  • +
+
+
+ +
+ + + + + + + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2022/2022-06-22-week-3-praneeth.html b/v0.10.x/posts/2022/2022-06-22-week-3-praneeth.html new file mode 100644 index 000000000..4fdeb9f73 --- /dev/null +++ b/v0.10.x/posts/2022/2022-06-22-week-3-praneeth.html @@ -0,0 +1,546 @@ + + + + + + + + Week 3 - Dealing with Problems — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Week 3 - Dealing with Problems#

+
+

What did you do this week?#

+

This week was full of researching, playing around with things, prototyping ideas, etc. +I started with last week’s clamping issue and managed to solve this issue while drawing shapes by clipping the mouse position according to canvas size, but it didn’t solve the problem with translating these shapes. I tried solving this using various approaches, but if one thing would get fixed, other things would raise a new error.

+

Instead of spending too much time on this, I thought it would be great to switch to other work and discuss this problem with the mentors. So I started to create a basic prototype for the properties panel, which would be used to manipulate different properties of the selected shape.

+https://user-images.githubusercontent.com/64432063/176094716-6be012b8-36c5-43e7-a981-612dbd37ab09.gif +

But then the question arises How to efficiently take data from the user?, Which data format would be easy to compute and best for user experience? and so on.

+

Alongside I was trying to create polylines but whenever I wanted to start the creation of the second line the dragging event wasn’t triggered as each dragging event required a left mouse click event associated with it. +I tried to do that manually but it didn’t work.

+
+
+

Did you get stuck anywhere?#

+

As I mentioned when I translated the shapes it would go out of the canvas bounds. Here the problem was with the reference point by which I was calculating all the transformations it changed depending on various cases as shown below.

+https://user-images.githubusercontent.com/64432063/176093855-6129cc25-d03d-45ba-872e-c8d2c6329a1e.gif +

This became more complex when working with a line because then the cases again differ depending on the quadrant in which the line lies. +I worked around and tried to compute the bounds but it wasn’t getting updated as the shape transformed.

+
+
+

What is coming up next?#

+

Solving the clamping issue to restrict the shape’s position to be in the canvas boundaries.

+
+
+ +
+ + + + + + + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2022/2022-06-28-week-2-mohamed.html b/v0.10.x/posts/2022/2022-06-28-week-2-mohamed.html new file mode 100644 index 000000000..42df8ee44 --- /dev/null +++ b/v0.10.x/posts/2022/2022-06-28-week-2-mohamed.html @@ -0,0 +1,551 @@ + + + + + + + + Week 2: Implementing non-linear and color interpolators — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Week 2: Implementing non-linear and color interpolators#

+
+

What did you do this week?#

+
    +
  • Implemented some other general interpolators such as n-th degree spline and cubic spline interpolators. Also implemented HSV and LAB color interpolators.

    +
    +

    PRs #612 and #613

    +
    +
  • +
  • Added animation slider to seek a particular time and visualize the timeline in real-time.

    +
  • +
  • Managed to do the transformation on the GPU side using GLSL using matrices. And did some digging about how and when we interpolate the camera and also how to do this on the GPU side.

  • +
+
+
+

What is coming up next week?#

+

This week I will do the following

+
    +
  • Allow FURY actors to maintain the number of primitives as an object property so that it can be used to manipulate only a subset of primitives in a single actor.

  • +
  • Change the structure of the Animation API to a newer one designed by Filipi to solve performance issues when creating a large number of timelines.

  • +
  • Implement the Bézier curve interpolation.

  • +
+
+
+

Did you get stuck anywhere?#

+

I got stuck trying to fix the clipping plans not being appropriately set. Which caused actors to disappear at some point.

+
+
+ +
+ + + + + + + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2022/2022-06-29-week-4-praneeth.html b/v0.10.x/posts/2022/2022-06-29-week-4-praneeth.html new file mode 100644 index 000000000..203d31ab3 --- /dev/null +++ b/v0.10.x/posts/2022/2022-06-29-week-4-praneeth.html @@ -0,0 +1,548 @@ + + + + + + + + Week 4 - Fixing the Clamping Issue — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Week 4 - Fixing the Clamping Issue#

+
+

What did you do this week?#

+

Phew!! This week was a tedious week for me as parallelly my End-Sem exams also started. So as usual I started from where I left off last week, The Clamping Issue. As per the discussion with the mentors, we decided to use the AABB bounding box method to calculate the bounding box around the shape and then reposition or transform respectively, as now we had a fixed reference point. So after doing some calculations with the mouse positions and the bounding box points at last, I was able to clamp all the shapes successfully.

+

DrawPanel UI

+https://user-images.githubusercontent.com/64432063/175497817-21974f43-d82b-4245-b93d-2db1081e6b04.gif +

While testing these changes, I found an issue that whenever we just do a single left mouse click on the shape, it automatically translated a bit. As you can see below.

+https://user-images.githubusercontent.com/32108826/175790660-e4b05269-e8d3-44e9-92e1-336c0eeb34ca.gif +

This was due to the difference between the global mouse click position and the canvas position, which was then fixed by converting the mouse click position to the relative canvas position.

+

Along with this, I tried to add some control points using Disk2D for the shape so that we can use them later on to transform the shapes.

+

Control points

+https://user-images.githubusercontent.com/64432063/177264804-15e67715-b714-4e33-ac68-423375d81740.gif +

Also, to enhance the visualization of the bounding box, I added a box border covering the shapes.

+

Bounding Box Borders

+https://user-images.githubusercontent.com/64432063/177264077-a8859a96-e3f7-444c-9760-8b9b17542f0f.gif +
+
+

Did you get stuck anywhere?#

+

No, Everything worked out fine.

+
+
+

What is coming up next?#

+

Enhancing the control points to work perfectly.

+
+
+ + + +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2022/2022-06-29-week2-shivam.html b/v0.10.x/posts/2022/2022-06-29-week2-shivam.html new file mode 100644 index 000000000..15ce59fd6 --- /dev/null +++ b/v0.10.x/posts/2022/2022-06-29-week2-shivam.html @@ -0,0 +1,546 @@ + + + + + + + + Week 2 - Improving Fetcher and Exporting glTF — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Week 2 - Improving Fetcher and Exporting glTF#

+
+

What did you do this week?#

+

This week I worked primarily on the glTF fetcher and exporting scenes to a glTF file. I added tests and docstrings for all functions. I modified the fetch_gltf function to return the downloaded files. As we planned, the PR for the glTF fetcher was merged this week.

+

I fixed the color issue of the glTF exporter by manually appending the color data from the actor to the polydata. But there’s another issue raised while using actors from vtkSource. The utils.get_polydata_triangles(polydata) method only works with primitives and it raises an error when used with vtkSource actors.

+

Textures and Cameras can now be added to the glTF file. However, it supports baseTexture only. I’ll be working on materials support later on.

+
+
+

What is coming up next week?#

+
    +
  • Saving all models download link (from the Khronos glTF-Samples-Models repository) to a JSON file, create a separate branch and add the download script.

  • +
  • Add tests and docstring for PR #600.

  • +
  • Create a PR for glTF exporter.

  • +
+
+
+

Did you get stuck anywhere?#

+
    +
  • I managed to fix colors in polydata by adding them manually, but it raised another issue with indices (triangles) of the actor weren’t of the correct shape. We decided to take a look at it later.

  • +
  • Due to Github’s API limit, it raised an error due to limits exceeding. We decided to save a JSON file with all model names and their download links. Then use that to download the model.

  • +
+
+
+ +
+ + + + + + + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2022/2022-07-04-week-3-mohamed.html b/v0.10.x/posts/2022/2022-07-04-week-3-mohamed.html new file mode 100644 index 000000000..1566be763 --- /dev/null +++ b/v0.10.x/posts/2022/2022-07-04-week-3-mohamed.html @@ -0,0 +1,553 @@ + + + + + + + + Week 3: Redesigning the API, Implementing cubic Bezier Interpolator, and making progress on the GPU side! — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Week 3: Redesigning the API, Implementing cubic Bezier Interpolator, and making progress on the GPU side!#

+
+

What did you do this week?#

+
    +
  • Redesigned the keyframe animations API to optimize having a lot of timelines by composing them into a parent Timeline called CompositeTimeline while maintaining playing individual timelines separately.

  • +
  • Implemented the cubic Bezier Interpolator using two control points for each keyframe. Also made a tutorial for it below:

    +
  • +
  • Also Implemented linear and cubic Bezier in GLSL interpolations to be computed by the GPU by sending two keyframes as uniforms and the current animation time.

  • +
  • Composed the playback panel as a single component PlaybackPanel (slider does not function yet).

  • +
  • As we tried to come up with a way to do keyframe animations on a partial subset of the actor’s primitives not all of them, we found that there is no currently implemented way to get the primitives count of a single actor. So I made this PR #617 so that the primitives’ count is saved inside the polydata of the actor as suggested by Filipi and Javier so that the primitives’ count can be used to distinguish the vertices of different primitives.

  • +
+
+
+

What is coming up next week?#

+

This week I will do the following

+
    +
  • Finish up the PlaybackPanel.

  • +
  • Implement all other interpolators in GLSL (color interpolators included).

  • +
  • Start Implementing slerp interpolation using quaternions in both Python and GLSL.

  • +
  • Add tests for the previous work.

  • +
  • Now that I made some progress with the keyframe animation API, I should be able to make a mergeable PR!

  • +
+
+
+

Did you get stuck anywhere?#

+
    +
  • Couldn’t get the LineSlider2D to work inside my new PlaybackPanel.

  • +
+
+
+ +
+ + + + + + + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2022/2022-07-04-week3-shivam.html b/v0.10.x/posts/2022/2022-07-04-week3-shivam.html new file mode 100644 index 000000000..c00c7a23b --- /dev/null +++ b/v0.10.x/posts/2022/2022-07-04-week3-shivam.html @@ -0,0 +1,549 @@ + + + + + + + + Week 3 - Fixing fetcher, adding tests and docs — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Week 3 - Fixing fetcher, adding tests and docs#

+
+

What did you do this week?#

+
    +
  • The first task for this week was to fix the glTF fetcher. We noticed that while running tests it reaches the API limit. So we decided to use a JSON file that contains the download URLs for all models.

  • +
  • Created a function to generate JSON files with download URLs for all models, which can be found here.

  • +
  • Modified the tests and fetcher.py to download using the JSON URLs and merged the PR #616.

  • +
  • Added docstring for all functions in #600. Wrote tests for transformation functions.

  • +
  • Multiple actor support in glTF export. Added tutorial and created a new branch for the same. Here’s an example: (The glTF model below is created using FURY and rendered back using the glTF class)

  • +
+https://github.com/xtanion/Blog-Images/blob/main/Screenshot%20from%202022-07-05%2014-51-06.png?raw=true +
+
+

What is coming up next week?#

+

I will be doing the following:

+
    +
  • We still need to figure out how to get indices from vtkSource actors

  • +
  • I’ll be finishing the exporting functions and adding tests for the same and I should be able to create a mergeable PR for the exporting function.

  • +
+

Other tasks will be decided after the meeting.

+
+
+

Did you get stuck anywhere?#

+

No

+
+
+ + + +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2022/2022-07-06-week-5-praneeth.html b/v0.10.x/posts/2022/2022-07-06-week-5-praneeth.html new file mode 100644 index 000000000..06cae70ac --- /dev/null +++ b/v0.10.x/posts/2022/2022-07-06-week-5-praneeth.html @@ -0,0 +1,548 @@ + + + + + + + + Week 5 - Working on new features — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Week 5 - Working on new features#

+
+

What did you do this week?#

+

This week I tried to create a base for some upcoming new features. +The first thing I updated was the Properties panel which I prototyped in Week 3. +So previously, it was just displaying the properties but now after the update, it is able to modify the properties(such as color, position, and rotation) too. This was a quick change to test the callbacks.

+

Properties Panel:

+https://user-images.githubusercontent.com/64432063/178412630-a0013a1a-3bfd-46fa-8445-fb5cff728e9c.gif +

Then I worked with the bounding box to make it visible whenever a shape is selected. +For this, I used the existing functionality of the Panel2D actor to create borders around the bounding box.

+

Bounding Box

+https://user-images.githubusercontent.com/64432063/178413769-5e4626d6-a207-489a-9789-59777c3e0522.gif +

Also along with this, I managed to add the polyline feature on user interactions. This creation isn’t that smooth but works as intended.

+

Poly Line

+https://user-images.githubusercontent.com/64432063/178414652-f47f3b25-a2c5-484a-bdbe-94f4ba1eff1f.gif +
+
+

Did you get stuck anywhere?#

+

Handling interactions for the polyline was complicated. I wasn’t able to invoke the left_mouse_click event, then as I was trying to invoke the events internally, it started creating multiple copies of the same line.

+
+
+

What is coming up next?#

+

I will be enhancing the polyline feature.

+
+
+ + + +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2022/2022-07-11-week-4-mohamed.html b/v0.10.x/posts/2022/2022-07-11-week-4-mohamed.html new file mode 100644 index 000000000..8a2e9d295 --- /dev/null +++ b/v0.10.x/posts/2022/2022-07-11-week-4-mohamed.html @@ -0,0 +1,577 @@ + + + + + + + + Week 4: Camera animation, interpolation in GLSL, and a single Timeline! — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Week 4: Camera animation, interpolation in GLSL, and a single Timeline!#

+
+

What did you do this week?#

+
    +
  • Managed to implement a single Timeline using the Container class. So, instead of having two classes: Timeline and CompositeTimeline, now the Timeline can have multiple Timeline objects and controls them as in the code below.

    +
    +
    main_timeline = Timeline()
    +sub_timeline = Timeline(actors_list)
    +main_timeline.add_timeline(sub_timeline)
    +
    +
    +
    +
  • +
+
+

+
+
    +
  • Implemented the HSV, Lab, and XYZ color interpolators in GLSL.

  • +
  • Added support for animating two camera properties: position and focal position, which can be interpolated using any general Interpolator.

    +
    +
    +
  • +
  • Allowed all actors inside all timelines to be added to the Scene automatically when the main (parent) Timeline is added to the Scene.

  • +
  • Fixed the PlaybackPanel, added a counter to display the animation time as in the video above, and added an option to attach a PlaybackPanel to the Timeline.

    +
    +
    main_timeline = Timeline(playback_panel=True)
    +
    +
    +
    +
  • +
+
+

+
+
+
+

What is coming up next week?#

+

This week I will do the following:

+
    +
  • Start Implementing slerp interpolation using quaternions in both Python and GLSL. And use slerp to apply camera rotation.

  • +
  • Add tests for the previous work.

  • +
  • Make a PR to merge the non-shader-based version of the Timeline.

  • +
  • Test how shader attributes can be used to hold keyframes for each vertex and benchmark it.

  • +
  • Study ‘colormaps’ and implement some ‘colormaps’ in GLSL.

  • +
+
+
+

Did you get stuck anywhere?#

+
    +
  • Uniforms don’t maintain their data after shaders are unbounded and another uniform with the same name in a different shader is set.

  • +
+
+
+ +
+ + + + +
+ + + + Previous: + + + + Week 5 - Working on new features + + + +   + + + + Next: + + + Week 4 - Finalizing glTF loader + + + + +
+ + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2022/2022-07-12-week4-shivam.html b/v0.10.x/posts/2022/2022-07-12-week4-shivam.html new file mode 100644 index 000000000..af608bfcb --- /dev/null +++ b/v0.10.x/posts/2022/2022-07-12-week4-shivam.html @@ -0,0 +1,912 @@ + + + + + + + + Week 4 - Finalizing glTF loader — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Week 4 - Finalizing glTF loader#

+
+

What did you do this week?#

+

This week I had to travel back to my college since the summer vacations have ended. +I had a coding session with Serge this week, we modified the exporter function and looked at some bugs I faced.

+

We managed to use the io.load_io function. There was a strange issue with loading png files. I had to convert the PIL Image to RGB format, and it fixed the issue, turns out png images are stored as P (pallet) mode.

+

I also added the glb format support to the importer. While loading a .glb model, I noticed that the image data is also stored in the buffer and there can be a bufferview index to get the buffer.

+

During this time, I also tested the glTF loader with all models in the KhronoosGroup/glTF-samples repository. Here’s the table of models working well: see file.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Model Name

Status

Error Type

BoxInterleaved

No

“BoxInterleaved.gltf: shapes (4,4) and (7,12) not aligned: 4 (dim 1) != 7 (dim 0)”

Box

Yes

SpecularTest

Yes

AnimatedCube

Yes

NormalTangentMirrorTest

Yes

AnimatedTriangle

Yes

SpecGlossVsMetalRough

No

SpecGlossVsMetalRough.gltf: ‘NoneType’ object has no attribute ‘baseColorTexture’

CesiumMilkTruck

Yes

VC

Yes

WaterBottle

Yes

AnimatedMorphCube

Yes

Sponza

Yes

SciFiHelmet

No

SciFiHelmet.gltf: Python int too large to convert to C long

Triangle

No

None: file not downloaded

IridescenceMetallicSpheres

No

None: file not downloaded

Corset

Yes

Cube

Yes

TextureLinearInterpolationTest

Yes

SimpleMeshes

Yes

Lantern

Yes

TextureTransformMultiTest

Yes

TextureSettingsTest

Yes

LightsPunctualLamp

Yes

DamagedHelmet

Yes

CesiumMan

Yes

Cameras

Yes

BarramundiFish

Yes

MetalRoughSpheresNoTextures

Yes

EnvironmentTest

No

None: file not downloaded

MosquitoInAmber

No

MosquitoInAmber.gltf: buffer is smaller than requested size

BoxTexturedNonPowerOfTwo

Yes

BrainStem

Yes

SimpleMorph

Yes

OrientationTest

Yes

BoxAnimated

Yes

StainedGlassLamp

Yes

TextureTransformTest

No

None: file not downloaded

ClearCoatTest

Yes

IridescenceLamp

No

None: file not downloaded

DragonAttenuation

No

DragonAttenuation.gltf: buffer is smaller than requested size

RecursiveSkeletons

No

RecursiveSkeletons.gltf: cannot reshape array of size 120 into shape (9)

Suzanne

Yes

RiggedSimple

Yes

TextureEncodingTest

Yes

2CylinderEngine

Yes

NormalTangentTest

Yes

MorphStressTest

Yes

IridescenceDielectricSpheres

No

None: file not downloaded

TextureCoordinateTest

Yes

Duck

Yes

AlphaBlendModeTest

Yes

TriangleWithoutIndices

Yes

MultiUVTest

Yes

BoomBoxWithAxes

Yes

Box With Spaces

No

Box%20With%20Spaces.gltf: ‘NoneType’ object has no attribute ‘shape’

SheenCloth

Yes

ToyCar

No

None: file not downloaded

MaterialsVariantsShoe

No

MaterialsVariantsShoe.gltf: buffer is smaller than requested size

IridescentDishWithOlives

Yes

VertexColorTest

Yes

SheenChair

Yes

Fox

Yes

AntiqueCamera

Yes

TransmissionTest

No

None: file not downloaded

TransmissionRoughnessTest

Yes

BoxVertexColors

Yes

ReciprocatingSaw

Yes

MorphPrimitivesTest

Yes

MetalRoughSpheres

Yes

GearboxAssy

Yes

TwoSidedPlane

Yes

Buggy

Yes

SimpleSparseAccessor

Yes

BoxTextured

Yes

UnlitTest

Yes

SimpleSkin

Yes

FlightHelmet

Yes

Unicode❤♻Test

No

Unicode%E2%9D%A4%E2%99%BBTest.gltf: ‘NoneType’ object has no attribute ‘shape’

Avocado

Yes

InterpolationTest

Yes

GlamVelvetSofa

Yes

RiggedFigure

Yes

BoomBox

Yes

EmissiveStrengthTest

No

None: file not downloaded

AttenuationTest

Yes

AnimatedMorphSphere

Yes

IridescenceSuzanne

Yes

+
+
+

What is coming up next week?#

+
    +
  • Adding tests and merging export function PR.

  • +
  • Start working on Simple Animations.

  • +
+
+
+

Did you get stuck anywhere?#

+
    +
  • To create a texture, we needed the RGB values, However .png images were returning a 2D array when read using PIL. It is fixed by

    +
    +
    if pil_image.mode in ['P']:
    +   pil_image = pil_image.convert('RGB')
    +
    +
    +
    +
  • +
  • pygltflib’s load method does not handle glb files very well. It does not contain the buffer uri. I used glb2gltf method as of now.

  • +
+
+
+ + + +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2022/2022-07-13-week-6-praneeth.html b/v0.10.x/posts/2022/2022-07-13-week-6-praneeth.html new file mode 100644 index 000000000..adacc4909 --- /dev/null +++ b/v0.10.x/posts/2022/2022-07-13-week-6-praneeth.html @@ -0,0 +1,546 @@ + + + + + + + + Week 6 - Supporting Rotation of the Shapes from the Center — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Week 6 - Supporting Rotation of the Shapes from the Center#

+
+

What did you do this week?#

+

This week I started implementing a new feature to rotate the shapes from the center using RingSlider2D. I already had a rotate function that rotates the shape around its pivot vertex, so I updated it to support rotation from the center.

+

Rotation from center

+https://user-images.githubusercontent.com/64432063/180257893-196baafe-3c42-4152-b5f4-643b794176d2.gif +

Then I tried to group the shapes to transform and modify them all at once. For this, I had to investigate more about the key press and release events. Then I managed to select and deselect shapes by holding the Ctrl key.

+

Grouping Shapes

+https://user-images.githubusercontent.com/64432063/180261113-39760cba-0343-41e7-924a-c741eb838f0b.gif +

I improved the polyline feature by adding a separate class to manage the creation and manipulation of the lines but still; I was facing the same issue with the dragging event, which initialized a new object every time a new line was created.

+
+
+

Did you get stuck anywhere?#

+

It was difficult to rotate the shape from the center because the pivot(or the reference point) of the shape wasn’t consistent. As you can see below it changed depending on how the shape was created.

+https://user-images.githubusercontent.com/64432063/176093855-6129cc25-d03d-45ba-872e-c8d2c6329a1e.gif +

To handle this, I created an interface between the actual pivot point and the center of the bounding box, which made it easy to calculate and set the positions.

+

Also, I wasn’t able to find a way by which I could manually call the dragging event without a preceding click event which was required for the polyline` feature.

+
+
+

What is coming up next?#

+

Complete Rotation from center PR.

+
+
+ + + +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2022/2022-07-19-week-5-mohamed.html b/v0.10.x/posts/2022/2022-07-19-week-5-mohamed.html new file mode 100644 index 000000000..e6bae1c79 --- /dev/null +++ b/v0.10.x/posts/2022/2022-07-19-week-5-mohamed.html @@ -0,0 +1,550 @@ + + + + + + + + Week 5: Slerp implementation, documenting the Timeline, and adding unit tests — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Week 5: Slerp implementation, documenting the Timeline, and adding unit tests#

+
+

What did you do this week?#

+
    +
  • Implemented Slerp (spherical linear interpolation) for rotation keyframes.

  • +
  • Controlling the speed of the animation is now an option.

  • +
  • Added the tests and documented the Timeline.

  • +
  • Used the geometry shader to generate billboard actors using a minimal set of calculations #631.

    +
    +
    +
  • +
+
+
+

What is coming up next week?#

+

This week I will do the following:

+
    +
  • Focus on finalizing PR #626 to be merged.

  • +
  • Make some upgrades to the playback panel to make it more functional and responsive.

  • +
  • Add more tutorials to explain how to use all the functionalities of the Timeline.

  • +
+
+
+

Did you get stuck anywhere?#

+

I didn’t get stuck this week.

+
+
+ + + +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2022/2022-07-19-week5-shivam.html b/v0.10.x/posts/2022/2022-07-19-week5-shivam.html new file mode 100644 index 000000000..a29aad6a5 --- /dev/null +++ b/v0.10.x/posts/2022/2022-07-19-week5-shivam.html @@ -0,0 +1,549 @@ + + + + + + + + Week 5 - Creating PR for glTF exporter and fixing the loader — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Week 5 - Creating PR for glTF exporter and fixing the loader#

+
+

What did you do this week?#

+
    +
  • Finalised the glTF export PR #630., adding tutorial, docs, and tests for all functions.

  • +
  • Added support for exporting lines and dot actors.

  • +
  • primitive.modes is now set if the rendering mode is a line, dot, or triangle.

  • +
  • Working on importing different primitive modes, the current glTF importer can render only triangles.

  • +
+
+
+

What is coming up next week?#

+

This week I’ll be working on the following:

+
    +
  • Get the PR #630. merged by this week.

  • +
  • Loading the animations (simple, morph, and skeletal) data as dictionaries from the glTF model so that it can be sent to the timeline.

  • +
  • Try different examples on Mohamed’s PR (#626.) and try running glTF animations if time permits.

  • +
+
+
+

Did you get stuck anywhere?#

+
    +
  • There wasn’t any model in the Khronos glTF samples repository that uses the LINE or POINT modes. So I had to rely on the models that I exported using the glTF exporter.

  • +
+
+
+ + + +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2022/2022-07-20-week-7-praneeth.html b/v0.10.x/posts/2022/2022-07-20-week-7-praneeth.html new file mode 100644 index 000000000..85c3c6f72 --- /dev/null +++ b/v0.10.x/posts/2022/2022-07-20-week-7-praneeth.html @@ -0,0 +1,550 @@ + + + + + + + + Week 7 - Working on Rotation PR and Trying Freehand Drawing — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Week 7 - Working on Rotation PR and Trying Freehand Drawing#

+
+

What did you do this week?#

+

I continued PR #623 and fixed the displacement of the shape from its original position when applying rotation. This was happening because most of the calculations resulted in float values, but as the pixel position were integers we had to explicitly convert these values into int. This conversion rounded off the values and as we call this function continuously, each time the round-off would happen, the shape would get displaced.

+https://user-images.githubusercontent.com/64432063/181723334-ef9ec75d-d3bf-4b79-83bf-272545c4dd12.gif +

To fix this, I converted all the calculations into integer calculations using floor division // instead of normal division /.

+https://user-images.githubusercontent.com/64432063/181723783-352092aa-b7a7-4d13-8d26-553315c7e1aa.gif +

The tests were failing in Ubuntu and the macOS because the mouse click event wasn’t propagated to the line due to some unknown reasons. When investigating more about the issue, Mohamed suggested and helped me implement another approach to select the shapes. In this approach, we calculate the distance between the mouse click event position and each of the shapes, and if any of the distances is less than a specific value (which I call as limit value), then we send this current event to that element.

+

New shape selection technique:

+https://user-images.githubusercontent.com/64432063/181730428-debd0617-dc32-4232-93ab-18ab903e92de.gif +

I also tried to implement a freehand drawing mode by adding Disk2D as points. But as you can see below, there are many flaws in this.

+
    +
  • First of all, we add many Disk2D objects which make it memory consuming process.

  • +
  • If the mouse moves very fast, then we can see the gaps between points.

  • +
  • Storing, managing, and transforming are difficult.

  • +
+https://user-images.githubusercontent.com/64432063/181731181-1f242c65-ccb8-4589-a2ed-40bfb3718cfd.gif +
+
+

Did you get stuck anywhere?#

+

It was hard to debug why the tests were failing in Ubuntu and macOS. I tried investigating it by installing Ubuntu and got nothing, but then while implementing the new selection approach, it automatically got fixed.

+
+
+

What is coming up next?#

+

Getting PR #623 merged and working on the polyline feature.

+
+
+ + + +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2022/2022-07-25-week-6-mohamed.html b/v0.10.x/posts/2022/2022-07-25-week-6-mohamed.html new file mode 100644 index 000000000..4190f1ac1 --- /dev/null +++ b/v0.10.x/posts/2022/2022-07-25-week-6-mohamed.html @@ -0,0 +1,565 @@ + + + + + + + + Week 6: Fixing the Timeline issues and equipping it with more features — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Week 6: Fixing the Timeline issues and equipping it with more features#

+
+

What did you do this week?#

+
    +
  • Improved the PlaybackPanel by adding speed control and the ability to loop the animation. Also, fixed the lagging issue of play and pause buttons and composed them into a single play/pause button.

  • +
  • Updated the old tutorials’ syntax to match the other tutorials and added a new tutorial on position animation using spline interpolation. Added unit tests for the PlaybackPanel and the newly added color converters in colormap.py.

  • +
  • Added more hooks to the 2D sliders to cover two more states:

    +
      +
    1. on_value_changed, which gets called whenever the value of the slider is changed without interacting with the slider.

    2. +
    3. on_moving_slider, which gets called when the position of the slider is changed by user interaction. #634.

    4. +
    +
      +
    • The reason for adding these two hooks is that there was only the on_change hook, which always gets called when the value of the slider is changed without considering how the value is changed, hence, the functionality of the slider was limited.

    • +
    +
  • +
  • Provided the ability to add static actors to the Timeline, which might be needed in the animation part of Shivam’s glTF project #643.

    +
      +
    • If an actor is added to the Timeline as a static actor, it won’t be animated by the Timeline, but it will get added to the scene along with the Timeline.

    • +
    +
  • +
  • Implemented a custom evaluator for the Timeline’s properties.

    +
      +
    • A custom evaluator uses a user-provided function that takes time as input and evaluates the property at that time. This feature is yet to be discussed more in today’s meeting.

    • +
    +
  • +
  • Fixed camera rotation and the view-up issue when interacting with the scene.

  • +
+
+
+

What is coming up next week?#

+
    +
  • Make a tutorial on how to implement a new custom Interpolator to work with the Timeline.

  • +
  • Add motion path visualization feature for both position and color properties.

  • +
  • Add custom evaluation functions directly, without using the CustomInterpolator.

  • +
  • Implement an already existing complex interpolator using closures instead of classes.

  • +
+
+
+

Did you get stuck anywhere?#

+

I didn’t get stuck this week.

+
+
+ +
+ + + + + + + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2022/2022-07-25-week-6-shivam.html b/v0.10.x/posts/2022/2022-07-25-week-6-shivam.html new file mode 100644 index 000000000..2e1f0ce9b --- /dev/null +++ b/v0.10.x/posts/2022/2022-07-25-week-6-shivam.html @@ -0,0 +1,546 @@ + + + + + + + + Week 6 - Extracting the animation data — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Week 6 - Extracting the animation data#

+
+

What did you do this week?#

+
    +
  • This week, it was all about reading docs and extracting the animation data from buffers.

  • +
  • Currently, the glTF class can extract simple node transformation and morphing data, as they are stored in the Animations of the glTF file.

  • +
  • Skinning (Skeletal Animation) data is stored in Nodes inside the skin parameter. We shall be able to load that before our next meeting on Wednesday.

  • +
  • Created a tutorial using keyframe animations (#626) and adding multiple timelines into a main timeline as suggested by Mohamed.

    +
  • +
+
+
+

What is coming up next week?#

+

As of now, we’ve decided the following:

+
    +
  • Create a custom Interpolator (for simple node transformations, morph and Skeletal animations).

  • +
+
+
+

Did you get stuck anywhere?#

+

No, I didn’t get stuck this week.

+
+
+ + + +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2022/2022-07-27-week-8-praneeth.html b/v0.10.x/posts/2022/2022-07-27-week-8-praneeth.html new file mode 100644 index 000000000..3a83f3879 --- /dev/null +++ b/v0.10.x/posts/2022/2022-07-27-week-8-praneeth.html @@ -0,0 +1,542 @@ + + + + + + + + Week 8 - Working on the polyline feature — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Week 8 - Working on the polyline feature#

+
+

What did you do this week?#

+

This week I started working on the polyline feature. After a lot of investigating and trying out different things, I found a way to call the dragging event manually without any prior click event. VTK actually captures the mouse movement using the MouseMoveEvent. This event is then modified by FURY to only be called after the click event. So I added a new callback to track the mouse movement and set the current canvas as an active prop because it is required to capture the drag event happening on it.

+https://user-images.githubusercontent.com/64432063/182432684-abd015e5-b63d-4aab-b6a5-c8ba5dab3252.gif +

I had to look for some ways by which we could make the icons look smoother. For this, I created an icon test file, which consisted of a set of icons of varying scales. Then on these icons, I used some vtkTexture methods discussed in the meeting, such as MipmapOn and InterpolateOn. You can see some differences in the icons below:

+https://user-images.githubusercontent.com/64432063/182910990-fe4934ee-4201-4c3c-8ab4-1a4f7bfa9276.png +
+
+

Did you get stuck anywhere?#

+

It took some time to get settled with all the things as my college reopened. +I was trying to use shaders with the UI elements to implement the freehand drawing, but then my mentors suggested that I should look into the tracer widget in the VTK.

+
+
+

What is coming up next?#

+

Updating PR #623 to keep rotation_slider on the top of the screen. +Looking into various vtk tracer widgets to see if we can use that to create freehand drawings.

+
+
+ + + +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2022/2022-08-01-week-7-mohamed.html b/v0.10.x/posts/2022/2022-08-01-week-7-mohamed.html new file mode 100644 index 000000000..9a4a85512 --- /dev/null +++ b/v0.10.x/posts/2022/2022-08-01-week-7-mohamed.html @@ -0,0 +1,550 @@ + + + + + + + + Week 7: Billboard spheres and implementing interpolators using closures — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Week 7: Billboard spheres and implementing interpolators using closures#

+
+

What did you do this week?#

+
    +
  • Restructured the keyframe animation interpolators using closures to be functions instead of classes #647. Now it is easier to implement new interpolators with the help of the functions existing in fury/animation/helpers.py. Also, now unit tests can be added for the latter functions.

  • +
  • Added two examples explaining how to implement a custom interpolator that can be used by the Timeline, one using classes and the other using closures.

  • +
  • Fixed rotation issue that Shivam discovered while using the Timeline to animate glTF models. So, rotation in VTK is done by rotating first around Z-axis, then X-axis, then finally around Y-axis, which was not the order I was using to convert from quaternions to Euler degrees.

  • +
  • Made changes requested by Javier and Filipi on the billboards using geometry shader PR, and made an example of how to use this billboard to show an impostor sphere which looks almost like a real high poly sphere. Also benchmarked using this version of billboard vs using a quad-based billboard, and how they both affect the FPS of the animation.

    +
    +
    +
  • +
+
+
+

What is coming up next week?#

+
    +
  • Document the new closure-based interpolators. And make some slight renaming changes that we discussed in today’s meeting.

  • +
  • Add tests to the functions inside fury/animation/helpers.py.

  • +
  • Make changes to the geometry-shader-based billboard to make it more like the quad-based billboard actor while maintaining the new features.

  • +
  • Integrate the already-implemented shader functionality to the new Timeline in a separate draft or PR.

  • +
+
+
+

Did you get stuck anywhere?#

+

I got stuck trying to get and modify the vertices (centers) of the billboard actor.

+
+
+ +
+ + + + + + + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2022/2022-08-01-week-7-shivam.html b/v0.10.x/posts/2022/2022-08-01-week-7-shivam.html new file mode 100644 index 000000000..3b270247a --- /dev/null +++ b/v0.10.x/posts/2022/2022-08-01-week-7-shivam.html @@ -0,0 +1,549 @@ + + + + + + + + Week 7 - Fixing bugs in animations — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Week 7 - Fixing bugs in animations#

+
+

What did you do this week?#

+
    +
  • This week I started with implementing scaling to the animation example.

  • +
  • I had a meeting with Mohamed in which we discussed the rotation issue, and we found out that glTF uses Slerp interpolator instead of the LinearInterpolator. Using Slerp interpolator for rotation fixed the rotation issue.

  • +
  • Another issue we faced was with the multi-actor system. Some actors weren’t rotating or translating as intended. This was caused because the transformations were applied to the polydata before creating an actor; Mohamed suggested applying transformation after the actor is created from polydata (keeping the center to origin).

    +
  • +
+

Expected animation: Interpolation Test Sample

+
    +
  • Created functions to return a list of animation timelines and apply them to the main timeline for keyframe animations.

  • +
  • CubicSpline has not been implemented to glTF animation yet since it works differently than other Interpolators (takes tangent input to smoothen the curve) but it’ll be done before our next meeting.

  • +
+
+
+

What is coming up next week?#

+
    +
  • Adding skinning animations support

  • +
+
+
+

Did you get stuck anywhere?#

+

I still need to figure out how to apply the transformation matrix to the actor and not to the polydata.

+
+
+ + + +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2022/2022-08-03-week-9-praneeth.html b/v0.10.x/posts/2022/2022-08-03-week-9-praneeth.html new file mode 100644 index 000000000..884427e88 --- /dev/null +++ b/v0.10.x/posts/2022/2022-08-03-week-9-praneeth.html @@ -0,0 +1,542 @@ + + + + + + + + Week 9 - Grouping and Transforming Shapes — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Week 9 - Grouping and Transforming Shapes#

+
+

What did you do this week?#

+

I started this week by creating a quick PR #645 for the UI sliders. The sliders raised ZeroDivsionError when the min and max values were the same. To solve this, I handled the case where the value_range becomes zero and then manually set the handle position to zero.

+

Then I updated the implementation of the Grouping Shapes feature to support the translation and rotation of the shapes grouped together, as you can see below.

+https://user-images.githubusercontent.com/64432063/183248609-4281087c-c930-4141-907a-5a906732524a.gif +

After this, I worked on the PolyLine and removed the extra point being added to the start of the PolyLine whenever a new instance was created.

+https://user-images.githubusercontent.com/64432063/183280803-5d7ae350-f080-478d-8a2f-a71460037ea4.gif +
+
+

Did you get stuck anywhere?#

+

No, everything went well.

+
+
+

What is coming up next?#

+

Completing the PR #623 and #653. +Searching different approaches for implementing the freehand drawing.

+
+
+ + + +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2022/2022-08-09-week-08-shivam.html b/v0.10.x/posts/2022/2022-08-09-week-08-shivam.html new file mode 100644 index 000000000..2ebfc32d2 --- /dev/null +++ b/v0.10.x/posts/2022/2022-08-09-week-08-shivam.html @@ -0,0 +1,552 @@ + + + + + + + + Week 8 - Fixing animation bugs — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Week 8 - Fixing animation bugs#

+
+

What did you do this week?#

+

This week I had to fix the transformation issue in glTF animation. As discussed in the last meeting, I disabled vertex transformation and applied the transformation after the actor was formed.

+
    +
  • Creating transformation matrix using the TRS data from nodes.

  • +
  • Extract Translation, Rotation, and Scale matrices from the transformation matrix.

    +
  • +
+

I also started investigating more on the skinning animation.

+
    +
  • I created functions to extract and apply the InvertBindMatrices to the vertices.

  • +
  • Also, applying the globalTransformMatrices to the mesh.

  • +
+
+
+

What is coming up next week?#

+
    +
  • Skeletal animations support

  • +
+
+
+

Did you get stuck anywhere?#

+
    +
  • Even after applying the transformation to the actor, after it’s created. Some models did not behave as intended. We still need to figure this issue out and fix it.

    +
  • +
+
+
+ + + +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2022/2022-08-09-week-8-mohamed.html b/v0.10.x/posts/2022/2022-08-09-week-8-mohamed.html new file mode 100644 index 000000000..27731c8d9 --- /dev/null +++ b/v0.10.x/posts/2022/2022-08-09-week-8-mohamed.html @@ -0,0 +1,548 @@ + + + + + + + + Week 8: Back to the shader-based version of the Timeline — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Week 8: Back to the shader-based version of the Timeline#

+
+

What did you do this week?#

+
    +
  • First, I made some modifications to the main animation PR. Then as Filipi requested, I integrated the vertex shader that I was implementing a few weeks ago to work with the new improved version of the Timeline.

  • +
  • As for how keyframes are sent to the GPU, the method being used is to send the needed keyframes for each draw. This is heavy because we only roll out the interpolation part, which with linear or step interpolation won’t make any difference! Instead, I tried setting all the keyframes at once as a GLSL variable using string manipulation before animation starts. This also was slow to initialize, and the shader was getting bigger and slower to bind and unbind. To solve this problem, I made a uniform that holds all the keyframes of the animation and sent data as vectors, which was faster than string manipulation, also it was faster to render since data are now stored directly in memory, and the shader program was a lot more compact. But this method had an issue; uniforms do not keep data stored as expected! If two or more actors have the same uniform name in their shader program and only one of them was set, the other actor will get this value as well. A way around this is to change the names of the uniforms so that they maintain their data.

  • +
  • Tested animating 160K billboard spheres animation but this time using translation as well. And they performed very well.

    +
    +
    +
  • +
+
+
+

What is coming up next week?#

+
    +
  • Fix issues I encountered this week working with GLSL shaders.

  • +
  • Implement slerp in GLSL as well as figure out a way to optimize sending keyframes to the shader program.

  • +
  • Figure a way to animate primitives of the same actor by different timelines.

  • +
+
+
+

Did you get stuck anywhere?#

+

I had two issues, one mentioned above which was uniforms not being able to hold data. The second one is that VTK does not send specular-related uniforms and lightColor0 to the point primitive, which are needed for light calculations.

+
+
+ + + +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2022/2022-08-10-week-10-praneeth.html b/v0.10.x/posts/2022/2022-08-10-week-10-praneeth.html new file mode 100644 index 000000000..97d90b666 --- /dev/null +++ b/v0.10.x/posts/2022/2022-08-10-week-10-praneeth.html @@ -0,0 +1,545 @@ + + + + + + + + Week 10 - Understanding Codes and Playing with Animation — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Week 10 - Understanding Codes and Playing with Animation#

+
+

What did you do this week?#

+

I started working on the PR #645 created last week and tested a few more corner cases such as What happens if the maximum value is exceeded?? What if we give a value less than the minimum value range?? +Most of these worked as intended.

+

Then I moved on to vtkImageTracer, I tried implementing this locally. It required an ImageSource on which the tracing was done. As you can see below, I managed to implement the pure VTK version of the widget. After this, I tried integrating this with FURY and besides the ImageSource all things were successfully handled by FURY.

+https://user-images.githubusercontent.com/64432063/185802405-b289dbc9-08a3-496a-8cc4-ef8c4d40bf60.gif +

As per the suggestions from the mentors, I started looking at the implementation of the vtkImageTracer to see how they manage the widget. My prior experience with C++ helped me a lot with this because the original implementation of vtk is in C++.

+

Here, I found an approach similar to the polyline. They first grab the current point, check whether it’s inside the area, and then use the last point to draw a line by calculating some kind of motion vector.

+

Using the Animation Architecture created by Mohamed, I created a Bouncing Text Animation using UI elements to check the compatibility of the UI System with the Animation.

+

Bouncing text animation:

+https://user-images.githubusercontent.com/64432063/185803066-70e320de-0777-478d-87bf-30767b02efe2.gif +
+
+

Did you get stuck anywhere?#

+

Proper tutorials weren’t there to implement vtkImageTracer, which took time to make it work locally.

+
+
+

What is coming up next?#

+

Working on the Freehand Drawing.

+
+
+ +
+ + + + + + + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2022/2022-08-16-week-9-mohamed.html b/v0.10.x/posts/2022/2022-08-16-week-9-mohamed.html new file mode 100644 index 000000000..b94ebf229 --- /dev/null +++ b/v0.10.x/posts/2022/2022-08-16-week-9-mohamed.html @@ -0,0 +1,547 @@ + + + + + + + + Week 9: Animating primitives of the same actor — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Week 9: Animating primitives of the same actor#

+
+

What did you do this week?#

+
    +
  • Made two tutorials in this PR that show two approaches on how to animate primitives of the same FURY actor using the Timeline.

    +
    +
    +
  • +
  • Tried sending all keyframes at once as uniforms, but I faced a performance issue doing this.

  • +
  • Set uniforms that are not being sent by VTK for the billboard actor.

  • +
+
+
+

What is coming up next week?#

+
    +
  • Alter the Timeline to use matrices instead of setting values directly to allow hierarchical transformation.

  • +
  • Improve the API of the PartialActor to act almost like a normal actor.

  • +
+
+
+

Did you get stuck anywhere?#

+

I had some issues trying to get shader’s uniforms to hold their data, and solving this issue led to another issue, which was a performance issue.

+
+
+ +
+ + + + + + + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2022/2022-08-17-week-09-shivam.html b/v0.10.x/posts/2022/2022-08-17-week-09-shivam.html new file mode 100644 index 000000000..49d9a01c9 --- /dev/null +++ b/v0.10.x/posts/2022/2022-08-17-week-09-shivam.html @@ -0,0 +1,546 @@ + + + + + + + + Week 9 - First working skeletal animation prototype — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Week 9 - First working skeletal animation prototype#

+
+

What did you do this week?#

+
    +
  • This week I had the first working example of skeletal animation ready. I was able to render the SimpleSkin model. Here’s a quick preview:

    +
    +
    +
  • +
  • I wrote a custom interpolator (just like the tangent cubic spline interpolator) for interpolating two transformation matrices.

  • +
+
+
+

What is coming up next week?#

+
    +
  • Generalising the skinning code to work with other models as well (it supports only the SimpleSkin model as of now).

  • +
  • Creating a custom interpolator to interpolate more than 4 matrices at once.

  • +
+
+
+

Did you get stuck anywhere?#

+

No, I didn’t get stuck this week.

+
+
+ +
+ + + + + + + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2022/2022-08-17-week-11-praneeth.html b/v0.10.x/posts/2022/2022-08-17-week-11-praneeth.html new file mode 100644 index 000000000..fcbc0839a --- /dev/null +++ b/v0.10.x/posts/2022/2022-08-17-week-11-praneeth.html @@ -0,0 +1,542 @@ + + + + + + + + Week 11 - Creating a base for Freehand Drawing — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Week 11 - Creating a base for Freehand Drawing#

+
+

What did you do this week?#

+

This week I tried to imitate the working of vtkImageTracer. Previously, I had created a small prototype for freehand drawing by adding points at the mouse position (which you can check out here). As mentioned, there were some drawback of this method. +So to overcome these issues, I tried combining both methods. Considering points using the previous method and instead of adding points I tried creating lines between them which looks promising. Below you can see a demo.

+

Freehand Drawing:

+https://user-images.githubusercontent.com/64432063/186952329-636a0d81-6631-4e8d-9486-9a8c5e88a9a7.gif +

While doing this, I started working on how I could efficiently draw the lines and smoothen them out. My mentors referred me this to learn more about constructing and rendering lines.

+

Along with this, I updated a few tests and some small bugs in PR #623 and #653.

+
+
+

Did you get stuck anywhere?#

+

No, I didn’t get stuck anywhere.

+
+
+

What is coming up next?#

+

Enhancing the freehand drawing feature.

+
+
+ + + +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2022/2022-08-23-week-10-mohamed.html b/v0.10.x/posts/2022/2022-08-23-week-10-mohamed.html new file mode 100644 index 000000000..e918ba8e8 --- /dev/null +++ b/v0.10.x/posts/2022/2022-08-23-week-10-mohamed.html @@ -0,0 +1,551 @@ + + + + + + + + Week 10: Supporting hierarchical animating — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Week 10: Supporting hierarchical animating#

+
+

What did you do this week?#

+
    +
  • Implemented hierarchical order support for animations using matrices in this PR.

  • +
  • Improved the API of a PartialActor by adding some methods to control the scales, positions and colors.

  • +
  • Added a new example of using the new hierarchical feature to animate an arm robot.

    +
    +
    +
  • +
  • Improved vector_text a little by adding options to control its direction.

  • +
+
+
+

What is coming up next week?#

+
    +
  • Finish the hierarchical order animation support PR.

  • +
  • Explain tutorials in more detail. See this issue.

  • +
  • Fix issues discovered by Serge in this review.

  • +
  • Fix lightColor0 being hard-set to (1, 1, 1). Instead, find a way to get this property the same way other polygon-based actor gets it.

  • +
  • Try to get PRs and issues mentioned above merged, closed or ready for a final review.

  • +
+
+
+

Did you get stuck anywhere?#

+

I didn’t get stuck this week.

+
+
+ + + +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2022/2022-08-24-week-12-praneeth.html b/v0.10.x/posts/2022/2022-08-24-week-12-praneeth.html new file mode 100644 index 000000000..3f53d3840 --- /dev/null +++ b/v0.10.x/posts/2022/2022-08-24-week-12-praneeth.html @@ -0,0 +1,544 @@ + + + + + + + + Week 12 - Fixing translating issues and updating tests — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Week 12 - Fixing translating issues and updating tests#

+
+

What did you do this week?#

+

I started with updating the tests for PR #623 as some of the tests weren’t covering all the aspects in the code. +Previously I was just creating the DrawShape and adding it to the scene but now I had to analyze the scene to see whether they were properly added or not.

+

Then I moved on to PR #653 to resolve the clamping issue. As you can see below, the shapes overlappes when they move nearer to the panel border.

+https://user-images.githubusercontent.com/64432063/187023615-d7c69904-4925-41b1-945d-b5993c20c862.gif +

To solve this, I am thinking of calculating the center of the group and clipping it according to the panel, which may give us the required result. I tried doing the same, and it worked partially.

+https://user-images.githubusercontent.com/64432063/187023880-84e13dab-313b-49e4-9b06-df5465c9d762.gif +

As we can see above, the shapes are kind of clamping but there’s some issue with positioning. It would be good to go once this is fixed.

+

Along this, I tried to integrate shaders with the Rectangle2D but there’s something which I am missing. When I tried executing that program, it executed successfully but I am not getting the desired output. I tried debugging the code as well using the debug flag on the shader_to_actor function but still, it doesn’t throw any error.

+
+
+

Did you get stuck anywhere?#

+

While updating the tests for PR #623 the quad shape wasn’t getting analyzed by the analyse_snapshot method. I tried various approaches to fix it, but it didn’t work.

+
+
+

What is coming up next?#

+

Merging the PRs #623, #653 and working on the freehand drawing.

+
+
+ +
+ + + + + + + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2022/2022-08-25-week-10-shivam.html b/v0.10.x/posts/2022/2022-08-25-week-10-shivam.html new file mode 100644 index 000000000..493da8438 --- /dev/null +++ b/v0.10.x/posts/2022/2022-08-25-week-10-shivam.html @@ -0,0 +1,553 @@ + + + + + + + + Week 10 - Multi-node skinning support — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Week 10 - Multi-node skinning support#

+
+

What did you do this week?#

+

As we figured out that the SimpleSkin model is not animated as intended. This week I started working with that model; +I figured out that we need to apply the InverseBindMatrix to each timer callback. I had a hard time figuring out what inverse bind matrix actually does. +Here’s a good blog that answers that.

+

In short: The InverseBindMatrix “undoes” any transformation that has already been applied to your model in its bind pose. Note: Inverse bind matrix shouldn’t be applied with weights.

+
    +
  • I got the SimpleSkin model to work perfectly. Here’s a preview:

    +
    +
    +
  • +
  • Support for multiple transformations is still missing. However RiggedSimple is also working fine, except that It doesn’t interpolate translation and scaling matrices.

    +
    +
    +
  • +
+
+
+

What is coming up next week?#

+
    +
  • Adding tests and adding support for combining transformation matrices for the same timestamp.

  • +
  • Write an Interpolator that applies skinning to the mesh internally.

  • +
+
+
+

Did you get stuck anywhere?#

+

No, I didn’t get stuck this week.

+
+
+ + + +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2022/2022-08-30-week-11-mohamed.html b/v0.10.x/posts/2022/2022-08-30-week-11-mohamed.html new file mode 100644 index 000000000..b6a908950 --- /dev/null +++ b/v0.10.x/posts/2022/2022-08-30-week-11-mohamed.html @@ -0,0 +1,546 @@ + + + + + + + + Week 11: Improving tutorials a little — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Week 11: Improving tutorials a little#

+
+

What did you do this week?#

+
    +
  • Fixed some issues in the hierarchical order animation support PR that we discussed during last week’s meeting (mostly naming issues).

  • +
  • Explained the introductory tutorial a little. But it is not suitable for beginners. So, I will spend time improving tutorials this week.

  • +
  • Added extrusion to vector_text to allow the z-scaling to be functional.

  • +
  • Fixed lightColor0 being hard-set to (1, 1, 1). Instead, it’s now using the Scene to set the lighting uniforms.

  • +
+
+
+

What is coming up next week?#

+
    +
  • Improve tutorials.

  • +
  • Find out how to get the Scene from the actor instead of manually assigning it.

  • +
  • If I have time, I will try to implement recording animation as GIF or as a video.

  • +
+
+
+

Did you get stuck anywhere?#

+

I didn’t get stuck this week.

+
+
+ + + +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2022/2022-08-31-week-11-shivam.html b/v0.10.x/posts/2022/2022-08-31-week-11-shivam.html new file mode 100644 index 000000000..588d91f61 --- /dev/null +++ b/v0.10.x/posts/2022/2022-08-31-week-11-shivam.html @@ -0,0 +1,550 @@ + + + + + + + + Week 11 - Multiple transformations support and adding tests — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Week 11 - Multiple transformations support and adding tests#

+
+

What did you do this week?#

+

As decided last week, I added support for multiple animations at the same timestamp. But this didn’t solve the animation problems of RiggedSimple model.

+
    +
  • I figured out that I was not applying the global transform of joints in the skinning matrix causing the joints to move to a new position. I referred to this answer by irradicator.

  • +
  • We had to invert the multiplication order (ie, np.dot(skin_mat, vertex) instead of np.dot(vertex, skin_mat)) for this model. We still need to figure out from where we get the multiplication order of the two.

    +
    +
    +
  • +
  • I also tried to create a custom Interpolator that does all calculations required for vertex skinning. However, we couldn’t get this working. I got a few suggestions from Mohamed in our meeting, I’ll try to implement those.

  • +
  • Added tests for animations.

  • +
+
+
+

What is coming up next week?#

+
    +
  • Adding more tests.

  • +
  • Fixing the Interpolator.

  • +
  • Order of multiplication in the skinning matrix.

  • +
+
+
+

Did you get stuck anywhere?#

+

No, I didn’t get stuck this week.

+
+
+ +
+ + + + + + + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2022/2022-08-31-week-13-praneeth.html b/v0.10.x/posts/2022/2022-08-31-week-13-praneeth.html new file mode 100644 index 000000000..5c18ad4c7 --- /dev/null +++ b/v0.10.x/posts/2022/2022-08-31-week-13-praneeth.html @@ -0,0 +1,543 @@ + + + + + + + + Week 13 - Separating tests and fixing bugs — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Week 13 - Separating tests and fixing bugs#

+
+

What did you do this week?#

+

This week I managed to fix the translation issue in PR #653. This was happening because of the calculation error while repositioning the shapes. Now it works as intended.

+https://user-images.githubusercontent.com/64432063/187058183-840df649-163e-44dd-8104-27d6c2db87a9.gif +

Also, the PR #623 got merged as now the tests were passing after the update.

+

As we are now adding new features to the DrawPanel, the current tests are becoming bigger and bigger. +Due to this creating, debugging, and managing tests are becoming harder. +So to keep things simple, separating the tests to validate individual parts and features of the DrawPanel. This was done in PR #674.

+

Along this, there was a redundant parameter called in_progress, which was used to keep a check whether the shapes are added to the panel or not, but it was confusing, and discarding it didn’t affect the codebase. So PR #673 removed that parameter and separated the two functions.

+
+
+

Did you get stuck anywhere?#

+

Debugging the issue in PR #653 took most of the time this week. I had to manually calculate and check whether the calculations were correct or not.

+
+
+

What is coming up next?#

+

Currently, the borders around the shapes are not actually the borders, they are the bounding box of that shape. So I have to find out some ways to highlight the shapes when selected by the user.

+
+
+ +
+ + + + + + + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2022/2022-09-07-week-14-praneeth.html b/v0.10.x/posts/2022/2022-09-07-week-14-praneeth.html new file mode 100644 index 000000000..5b1e4d6ec --- /dev/null +++ b/v0.10.x/posts/2022/2022-09-07-week-14-praneeth.html @@ -0,0 +1,547 @@ + + + + + + + + Week 14 - Updating DrawPanel architecture — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Week 14 - Updating DrawPanel architecture#

+
+

What did you do this week?#

+

This week I continued updating the DrawShape and DrawPanel.

+

So as we can see below, whenever we create, translate, or rotate the shapes on the panel, it sometimes overlaps the mode_panel or mode_text which are used to select and show the current mode respectively.

+https://user-images.githubusercontent.com/64432063/188268649-65ea24f0-3f46-4545-8e52-e07513a94b9f.gif +

To resolve this, I created a PR #678 which moves the mode_panel and the mode_text to be on the borders of the panel.

+https://user-images.githubusercontent.com/64432063/188268804-949ec656-7da3-4310-ba8b-7e4f0281faa1.gif +

Along this, there were some similar functionalities in the Grouping Shapes PR and the DrawShape due to which some lines of code were repeating. To remove this duplicacy I created a PR #679 to move these functions to the helper.py file.

+

Then I tried different ways of highlighting the shapes,

+
    +
  1. To create a copy of the shape and scale it in the background so that it looks like a border or highlighted edges.

  2. +
  3. Add yellow color to the shape so that it looks brighter.

  4. +
+
+
+

Did you get stuck anywhere?#

+

No, I didn’t get stuck this week.

+
+
+

What is coming up next?#

+

Working on these new PRs to get them merged. Implement a highlighting feature.

+
+
+ + + +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2022/2022-09-08-week-12-shivam.html b/v0.10.x/posts/2022/2022-09-08-week-12-shivam.html new file mode 100644 index 000000000..0939b3229 --- /dev/null +++ b/v0.10.x/posts/2022/2022-09-08-week-12-shivam.html @@ -0,0 +1,552 @@ + + + + + + + + Week 12 - Adding skeleton as actors and fix global transformation — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Week 12 - Adding skeleton as actors and fix global transformation#

+
+

What did you do this week?#

+
    +
  • I started this week by fixing the segmentation fault for the skinning test. I could not fix this as of now.

  • +
  • I imported the RiggedFigure model into the Blender and I was quite impressed with how it visualizes each bone. So, I created a function that creates an arrow actor in place of a bone, and by applying the correct transformation, we get the bones of a model in place. Here’s a quick preview of bones in Blender vs bones in FURY:

  • +
+https://user-images.githubusercontent.com/74976752/189194609-e55f6285-b5ed-4eb3-9e78-5fb462fb2dee.png +https://user-images.githubusercontent.com/74976752/189195853-5b1f8945-9822-48f5-8d55-f13e822a43a7.png +
    +
  • After having the bones actor, I noticed that some bones are not aligned correctly. It was happening due to multiplication of the same transformation matrix twice.

  • +
  • I also created a function that calculates the total transformation of a node, it eliminates the need to use timeline.get_value in get_skin_timeline function.

  • +
+
+
+

What is coming up next week?#

+
    +
  • It seems like I fixed everything, but we are not getting the correct model at timestamp 0. We need to find the cause and fix it!

  • +
  • Cleaning the Simple Animation PR #643, and merging it.

  • +
+
+
+

Did you get stuck anywhere?#

+
    +
  • While applying the timeline, we were getting the identity matrix for timestamp 0.0s, it was set to a new value before. We figured this in our meeting that it’s happening due to some model’s animation not starting from 0.0s.

  • +
+https://user-images.githubusercontent.com/74976752/189196234-b28f86f7-223b-40e4-94bf-2ec18d914487.png +
+
+ +
+ + + + + + + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2022/2022-09-14-week-15-praneeth.html b/v0.10.x/posts/2022/2022-09-14-week-15-praneeth.html new file mode 100644 index 000000000..75ed47306 --- /dev/null +++ b/v0.10.x/posts/2022/2022-09-14-week-15-praneeth.html @@ -0,0 +1,544 @@ + + + + + + + + Week 15 - Highlighting DrawShapes — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Week 15 - Highlighting DrawShapes#

+
+

What did you do this week?#

+

This week I started with highlighting the shapes. As discussed earlier, I had two ways, but while implementing them, I found out both ways aren’t that good to continue with. +The first way in which we thought of creating the scaled shapes in the background had an issue with the stacking. The border(blue rectangle) and the shape(grey rectangle) both seem to look like different shapes just grouped together as shown below.

+https://user-images.githubusercontent.com/64432063/192321622-964cef6e-f965-4a24-8dcf-0b899fe5e387.gif +

While playing around with the second way, which was to add yellow color to the shape to make it brighter, it was difficult to identify which shape was selected. Also sometimes instead of making it brighter the addition of color created a new color which again confused the user. +After discussing these issues my mentors suggested having a user-defined highlight color that will be shown whenever the shape is selected.

+https://user-images.githubusercontent.com/64432063/192326416-4454718d-1dda-4a13-9f97-07387a50a580.gif +

Along this, we were also trying to integrate shaders to the Actor2D (i.e. the UI elements) but there were some issues with it. I used this shaders example as a starting point and just replaced the utah actor by Rectangle2D actor. This program executed successfully without any errors, but it didn’t give the required output.

+

So instead of wasting time searching for how it is done, we thought it would be great if we directly ask in the VTK discourse forum. For this, I had to create a minimalistic pure VTK code. You can check out my code as well as the post here.

+
+
+

Did you get stuck anywhere?#

+

No, I didn’t get stuck this week.

+
+
+

What is coming up next?#

+

Working on the rotation slider and the polyline.

+
+
+ + + +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2022/2022-09-15-week-13-blog.html b/v0.10.x/posts/2022/2022-09-15-week-13-blog.html new file mode 100644 index 000000000..5c2463805 --- /dev/null +++ b/v0.10.x/posts/2022/2022-09-15-week-13-blog.html @@ -0,0 +1,551 @@ + + + + + + + + Week 13 - Multi-bone skeletal animation support — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Week 13 - Multi-bone skeletal animation support#

+
+

What did you do this week?#

+

This week I fixed all the issues with skeletal animations, and we got to see our first render of skeletal animation :).

+
    +
  • Implemented a hierarchical timeline system (i.e., one timeline for each bone, and the timeline will contain its parent timeline in a hierarchy).

  • +
  • I figured out that we don’t need to apply the parent transform as we’re applying it to the vertex data while forming the actor. So the skin matrix becomes

  • +
+

SkinMatrix = InverseBindPose * BoneDeform where BoneDeform = CurrentBoneTransform * ParentBonetransform.

+

Here’s a preview using the CesiumMan model:

+
+
+
+
+

What is coming up next week?#

+
    +
  • Add tests for simple animation PR #643.

  • +
  • Multiple actor support for skeletal animation.

  • +
  • Take a look at Morphing.

  • +
+
+
+

Did you get stuck anywhere?#

+
    +
  • No, I didn’t get stuck this week.

  • +
+
+
+ +
+ + + + + + + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2022/2022-09-20-week-13-mohamed.html b/v0.10.x/posts/2022/2022-09-20-week-13-mohamed.html new file mode 100644 index 000000000..959e501ba --- /dev/null +++ b/v0.10.x/posts/2022/2022-09-20-week-13-mohamed.html @@ -0,0 +1,549 @@ + + + + + + + + Week 13: Keyframes animation is now a bit easier in FURY — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Week 13: Keyframes animation is now a bit easier in FURY#

+
+

What did you do this week?#

+
    +
  • Added the ability to have the ShowManager stored inside the Timeline. That way the user does not have to update and render the animations because it will be done internally.

  • +
  • Added a record method to the Timeline that records the animation and saves it as either GIF or MP4 (requires OpenCV). This record functionality has the option to show/hide the PlaybackPanel which makes it better than recording the animation using a third-party software.

    +
    +
    https://user-images.githubusercontent.com/63170874/190892795-f47ceaf1-8dd0-4235-99be-2cf0aec323bb.gif +
    +
  • +
  • Fixed some issues that Serge mentioned while reviewing PR #665.

  • +
+
+
+

What is coming up next week?#

+
    +
  • Instead of adding the ShowManager to the Timeline, doing it the other way around is a better choice and makes the code more readable.

  • +
  • Add tests for the Timeline’s record method.

  • +
  • Add tests for the billboard actor to test consistency among different approaches..

  • +
+
+
+

Did you get stuck anywhere?#

+

I didn’t get stuck this week.

+
+
+ +
+ + + + + + + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2022/2022-09-21-week-16-praneeth.html b/v0.10.x/posts/2022/2022-09-21-week-16-praneeth.html new file mode 100644 index 000000000..f7e63fa2e --- /dev/null +++ b/v0.10.x/posts/2022/2022-09-21-week-16-praneeth.html @@ -0,0 +1,543 @@ + + + + + + + + Week 16 - Working with Rotations! — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Week 16 - Working with Rotations!#

+
+

What did you do this week?#

+

Last week my mentors noticed that each DrawShape has its individual rotation_slider which increases redundancy and complexity in setting its visibility on and off. Instead, they suggested moving the rotation_slider to DrawPanel and keeping a common slider for all the shapes.

+

PR #688 does the above mentioned thing. +There isn’t any visual difference as everything is as it was earlier, just the code was modified a bit to make it work properly.

+

After this, I started working with the rotation for the Polyline feature. For rotating the Polyline, I implemented something similar to what I had did while rotating the individual shapes. Firstly I calculate the bounding box and the center of the shape, then apply the rotation to the points through which the polyline was generated.

+

Polyline:

+https://user-images.githubusercontent.com/64432063/193308748-6bc14acb-b687-4d88-9c41-12991186a104.gif +

As we can see above the rotation seems correct but as earlier the shape is translating from its original center. This should be easy to fix.

+
+
+

Did you get stuck anywhere?#

+

Instead of implementing the approaches for creating and managing the Polyline, I kept on thinking of various ideas on how I could do so, which wasted my time. I should have thought about some approaches and tried to implement them so that I would get an idea of whether things would work or not.

+
+
+

What is coming up next?#

+

Working on Polyline to make sure everything works fine.

+
+
+ +
+ + + + + + + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2022/2022-09-28-week-14-mohamed.html b/v0.10.x/posts/2022/2022-09-28-week-14-mohamed.html new file mode 100644 index 000000000..76b91c8e0 --- /dev/null +++ b/v0.10.x/posts/2022/2022-09-28-week-14-mohamed.html @@ -0,0 +1,547 @@ + + + + + + + + Week 14: Keyframes animation is now a bit easier in FURY — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Week 14: Keyframes animation is now a bit easier in FURY#

+
+

What did you do this week?#

+
    +
  • Separated the Timeline into a Timeline and an Animation. So, instead of having the Timeline do everything. It’s now more like doing animations in Blender and other 3D editing software where the timeline handles the playback of several animations #694.

  • +
  • Added unit tests for the billboards based on geometry shader.

  • +
  • Tried to solve the issue with actors not being rendered when their positions are changed in the vertex shader. For now, I just found a way to force invoke the shader callbacks, but force rendering the actor itself still needs more investigation.

  • +
+
+
+

What is coming up next week?#

+
    +
  • Add unit testing for the Animation, document it well, and implement more properties suggested by Shivam (@xtanion).

  • +
  • Modify Add Timelines to ShowManager directly PR to allow adding Animation to the ShowManager as well.

  • +
  • Update tutorials to adapt to all the new changes in the animation module.

  • +
+
+
+

Did you get stuck anywhere?#

+
    +
  • I got stuck trying to solve the issue mentioned above with actors not being rendered.

  • +
+
+
+ +
+ + + + + + + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2022/2022-09-28-week-14-shivam.html b/v0.10.x/posts/2022/2022-09-28-week-14-shivam.html new file mode 100644 index 000000000..c39a8f020 --- /dev/null +++ b/v0.10.x/posts/2022/2022-09-28-week-14-shivam.html @@ -0,0 +1,551 @@ + + + + + + + + Week 14 - Morphing is here! — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Week 14 - Morphing is here!#

+
+

What did you do this week?#

+
    +
  • This week, I started with multiple actor support in skinning and managed to do it +successfully. Here’s the preview using the BrainStem model.

  • +
+
    +
  • Implementing multiple animation channels support (as seen in the Fox model). The get_skin_timelines() method now returns a dictionary of all animation channels with Timeline as their value.

  • +
  • We merged two PRs, #689 (colors from Material) and #643 (simple animations).

  • +
  • Added ability to load morphing information and create timelines from it. Here’s a preview of the AnimatedMorphCube and AnimatedMorphSphere models:

  • +
+
+
+

What is coming up next week?#

+
    +
  • Cleaning and Rebasing Skinning animation PR #685.

  • +
  • Creating a PR for morphing code.

  • +
  • Multi primitive (actor) support in morphing.

  • +
+
+
+

Did you get stuck anywhere?#

+
    +
  • No, I didn’t get stuck this week.

  • +
+
+
+ +
+ + + + + + + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2022/2022-09-7-week-12-mohamed.html b/v0.10.x/posts/2022/2022-09-7-week-12-mohamed.html new file mode 100644 index 000000000..19e888a6e --- /dev/null +++ b/v0.10.x/posts/2022/2022-09-7-week-12-mohamed.html @@ -0,0 +1,545 @@ + + + + + + + + Week 12: Adding new tutorials — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Week 12: Adding new tutorials#

+
+

What did you do this week?#

+
    +
  • Restructured tutorials to be more readable and more focused on a specific topic.

  • +
  • Replaced the old animation introductory tutorial with a lot simpler one, and added tutorial to explain keyframes and interpolators.

  • +
  • Simplified setting lighting uniforms for the geometry-based-billboard actor by getting the Scene from the actor using actor.GetConsumer(scene_idx).

  • +
+
+
+

What is coming up next week?#

+
    +
  • Allow the Timeline to take the ShowManager as an argument to reduce the amount of code the user has to write every time using FURY animations.

  • +
  • Fix some typos in the tutorials and write some info about Slerp.

  • +
  • Find a way to fix the shader-callback problem of not being executed when the actor is out of the camera’s frustum.

  • +
+
+
+

Did you get stuck anywhere?#

+

I didn’t get stuck this week.

+
+
+ +
+ + + + + + + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2023/2023-01-24-final-report-praneeth.html b/v0.10.x/posts/2023/2023-01-24-final-report-praneeth.html new file mode 100644 index 000000000..0a71f34cc --- /dev/null +++ b/v0.10.x/posts/2023/2023-01-24-final-report-praneeth.html @@ -0,0 +1,799 @@ + + + + + + + + Google Summer of Code Final Work Product — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +https://developers.google.com/open-source/gsoc/resources/downloads/GSoC-logo-horizontal.svg +https://www.python.org/static/community_logos/python-logo.png +https://python-gsoc.org/logos/FURY.png +
+

Google Summer of Code Final Work Product#

+ +
+

Proposed Objectives#

+
    +
  • Visualization UI:

    +
      +
    • Drawing Geometrical Objects

    • +
    • Moving Components

    • +
    • Rotating Components

    • +
    • Erasing Components

    • +
    • Resizing Components

    • +
    +
  • +
  • Stretch Goals:

    +
      +
    • Converting 2D shapes to 3D

    • +
    +
  • +
+
+
+

Objectives Completed#

+
    +
  • DrawPanel (previously known as Visualization UI)

    +

    DrawPanel is the parent component that contains and manages all the other sub-components to efficiently visualize the shapes. The main functions of the DrawPanel are capturing interactions from user, managing modes, drawing shapes and transforming them. The DrawPanel is mainly divided into three parts :

    +
      +
    1. +
      Main Panel

      It is the main background panel(Panel2D) on which the main interaction and visualization happen. Here user can interactively draw shapes, reposition and rotate them. This panel also defines the boundaries for the shapes. It can also be called as a container element as it contains all the shapes and other DrawPanel components.

      +
      +
      +
    2. +
    3. +
      Mode Panel
      +
      It is a composite UI element consisting of the main panel(Panel2D) on which buttons(Button2D) are arranged which can toggle the current working mode. Each button has an icon associated with it which tries to depict the information about the mode. Here mode is nothing but the different channels which on selection can perform different tasks. Some of the modes present in the Mode Panel are discussed below:
        +
      • Selection: This mode is used to select an individual or group of shapes.

      • +
      • Deletion: This mode is used to delete an individual or group of shapes.

      • +
      • +
        The modes mentioned below create an element on the Panel which is described below.
          +
        • Line

        • +
        • Quad

        • +
        • Circle

        • +
        • Polyline

        • +
        • Freehand drawing

        • +
        +
        +
        +
      • +
      • To activate any of these above mode the user has to click on the button with the respective icon present in the mode panel and then interact with the main panel.

      • +
      +
      +
      +
      +
      +
    4. +
    5. Mode Text It is a TextBlock2D which displays the current mode of the DrawPanel. It automatically updates whenever the mode is changed. This helps the user to quickly identify which mode is he currently in.

    6. +
    +

    Pull Requests:

    + +
    +
    https://user-images.githubusercontent.com/64432063/194766188-c6f83b75-82d1-455c-9be1-d2a1cada945a.png +
    +
  • +
  • Drawing Shapes:

    +

    A new class called DrawShape was create to manage all the transformation and to handle the user interaction which are passed by the DrawPanel. To create a shape the required mode can be selected from the mode panel and then on the left_mouse_click event the shape creation starts. Then to resize user needs to drag the mouse depending on how he wants the shape to be. These interactions follow WYSIWYG (What You See Is What You Get) principle. Currently, the following shapes are supported:

    +
      +
    1. Line: Creates a line joining two points using Rectangle2D.

    2. +
    3. Quad: Creates a rectangle using Rectangle2D.

    4. +
    5. Circle: Create a Circle using Disk2D.

    6. +
    7. Polyline: Creates a chain of lines that can either end at the starting point and create a loop or remain an independent collection of lines. Individual line is created using Rectangle2D.

      + +
    8. +
    9. Freehand drawing: Here you can draw any freehand object something similar to doodling. Internally we use Polyline for doing this.

      + +https://user-images.githubusercontent.com/64432063/194773058-b074fde0-e2e1-4719-93e3-38a34032cd88.jpg +
    10. +
    +
  • +
  • Transforming Shapes:

    +

    Following transformation are supported by every DrawShape

    +
      +
    • Translation

      +

      The translation is nothing but repositioning the shapes on the main panel. It is made sure that the shapes don’t exceed the panel boundaries by clamping the new position between the panel bounds. All the UI elements have a center property which can be used to do the above-mentioned thing but the reference point of the Shape may change depending on how it was created. So to resolve this I created an interface that would calculate and return the bounding box data around the shape and which could be then used to reposition the shape on the panel.

      +https://user-images.githubusercontent.com/64432063/194772993-289e10bd-199d-4692-bcb0-5cccdb1b32fe.gif +
    • +
    • Rotation

      +

      Each DrawShape can be rotated from the center of that shape. Whenever you select a shape using the selection mode a rotation slider(RingSlider2D) appears at the lower right corner of the DrawPanel. This rotation slider can be used to rotate the shapes by some specific angle which is displayed at the center of the slider.

      +https://user-images.githubusercontent.com/64432063/194773295-4303ec78-3f2b-44e5-8c85-ff01140a8c95.gif +
    • +
    +

    Pull Requests:

    +
      +
    • DrawPanel Feature: Adding Rotation of shape from Center (Merged) :

      +

      fury-gl/fury#623

      +
    • +
    +
  • +
  • Deleting Shapes:

    +

    Whenever we create anything it’s never perfect we change, modify, and at last delete. Here too every DrawShape is never perfect so to delete the shapes we also have a delete option that can be chosen from the mode panel and by clicking the shape they are removed from the panel.

    +
    +
    https://user-images.githubusercontent.com/64432063/194862464-387edc59-a942-4675-ab44-53c899e70e29.gif +
    +
  • +
+
+
+

Other Objectives#

+
    +
  • Grouping Shapes

    +

    Many times we need to perform some actions on a group of shapes so here we are with the grouping feature using which you can group shapes together, reposition them, rotate them and delete them together. To activate grouping of shapes you have to be on selection mode then by holding Ctrl key select the required shapes and they will get highlighted. To remove shape from the group just hold the Ctrl and click the shape again it will get deselected. Then once everything is grouped you can use the normal transformation as normal i.e. for translation just drag the shapes around and for rotation the rotation slider appears at usual lower left corner which can be used.

    +

    Pull Requests:

    + +
  • +
  • Creating icons

    +

    As most of the things in the DrawPanel are visually seen, each mode also require some icons so that users easily understand the use of that mode, so to achieve this I have created some icons by using the pre-existing icons in the FURY. These icons are stored here. Whenever FURY requires these icons they are fetched using the fetchers present in FURY. To fetch these new icons I created some new fetchers.

    +

    Pull Requests:

    + +
  • +
  • Other PRs

    +
      +
    • Fixing ZeroDivisionError thrown by UI sliders when the value_range is zero (0) (Merged): fury-gl/fury#645

    • +
    • DrawPanel Update: Removing in_progress parameter while drawing shapes (Merged): fury-gl/fury#673

    • +
    • DrawPanel Update: Separating tests to test individual features (Merged): fury-gl/fury#674

    • +
    • DrawPanel Update: Repositioning the mode_panel and mode_text (Merged): fury-gl/fury#678

    • +
    • DrawPanel Update: Moving repetitive functions to helpers (Merged): fury-gl/fury#679

    • +
    • DrawPanel Update: Moving rotation_slider from DrawShape to DrawPanel (Under Review): fury-gl/fury#688

    • +
    +
  • +
+
+
+

Objectives in Progress#

+
    +
  • Resizing Shapes:

    +

    Currently after the shape is created we can only transform it but we might need to resize it. To be able to resize I am currently using the borders of the shape itself. You can switch to resize mode and then select the shape. It would display the bounding box around the shape which act as interactive slider and resizes the shape as shown below.

    +
    +
    https://user-images.githubusercontent.com/64432063/194775648-04c2fa7a-b22f-4dda-a73b-2f8161bb4f3a.gif +
    + +
  • +
+
+
+

GSoC Weekly Blogs#

+ +
+
+

Timeline#

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Date

Description

Blog Post Link

Week 0(25-05-2022)

Pre-GSoC Journey

FURY - Python

Week 1(08-06-2022)

Laying the Foundation of DrawPanel UI

FURY - Python

Week 2(15-06-2022)

Improving DrawPanel UI

FURY - Python

Week 3(22-06-2022)

Dealing with Problems

FURY - Python

Week 4(29-06-2022)

Fixing the Clamping Issue

FURY - Python

Week 5(06-07-2022)

Working on new features

FURY - Python

Week 6(13-07-2022)

Supporting Rotation of the Shapes from the Center

FURY - Python

Week 7(20-07-2022)

Working on Rotation PR and Trying Freehand Drawing

FURY - Python

Week 8(27-07-2022)

Working on the polyline feature

FURY - Python

Week 9(03-08-2022)

Grouping and Transforming Shapes

FURY - Python

Week 10(10-08-2022)

Understanding Codes and Playing with Animation

FURY - Python

Week 11(17-08-2022)

Creating a base for Freehand Drawing

FURY - Python

Week 12(24-08-2022)

Fixing translating issues and updating tests

FURY - Python

Week 13(31-08-2022)

Separating tests and fixing bugs

FURY - Python

Week 14(07-09-2022)

Updating DrawPanel architecture

FURY - Python

Week 15(14-09-2022)

Highlighting DrawShapes

FURY - Python

Week 16(21-09-2022)

Working with Rotations!

FURY - Python

+
+
+ + + +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2023/2023-01-29-final-report-mohamed.html b/v0.10.x/posts/2023/2023-01-29-final-report-mohamed.html new file mode 100644 index 000000000..3153c0beb --- /dev/null +++ b/v0.10.x/posts/2023/2023-01-29-final-report-mohamed.html @@ -0,0 +1,793 @@ + + + + + + + + Google Summer of Code Final Work Product — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
gsoc
+ +fury +
+

Google Summer of Code Final Work Product#

+ +
+

Proposed Objectives#

+
    +
  • Keyframe animations API

    +
      +
    • Basic playback functions, such as playing, pausing, and rewinding the timeline.

    • +
    • Adding keyframes at a specific time for transformations of FURY actors and cameras such as translation, scale, rotation, color, and opacity.

    • +
    • Implement quaternion-based interpolation (SLERP)

    • +
    • Allow the camera to be interpolated by the keyframe system.

    • +
    • Allow the creation and removal of actors from the scene according to the keyframes.

    • +
    • Visualize the motion path of positional animation.

    • +
    • Speed the animation using GLSL vertex and fragment shaders.

    • +
    +
  • +
+
+
+

Modified Objectives#

+
    +
  • Adding a playback panel for controlling the timeline.

  • +
  • Billboard actor using the geometry shader.

  • +
  • Hierarchical animation support.

  • +
  • Animating primitives of the same Fury actor separately.

  • +
  • Color interpolators.

  • +
+
+
+

Objectives Completed#

+
    +
  • Keyframes Animation API

    +
      +
    • Animation Class

    • +
    • The Animation class is the main part of the FURY animation module. It is responsible for keyframe animations for a single or a group of FURY actors. The Animation is able to handle multiple attributes and properties of Fury actors such as position, color, scale, rotation, and opacity. It is also capable of doing the following:

      +
        +
      • Set animation keyframes and events.

      • +
      • Animate custom properties.

      • +
      • Support add-to-scene/remove-from-scene events.

      • +
      • Can animate other animations (Hierarchical animation)

      • +
      • Set or change the keyframes interpolation method.

      • +
      • Visualize the motion path of the positional animation.

      • +
      • Timeline Class +The Timeline is the player of FURY Animations; it controls the playback of one or more FURY animations. It also has the option to include a very useful playback panel to help control the playback of the animation. The Timeline can have a fixed length or get its duration from the animations added to it dynamically. It can loop, play once, change speed, play, pause, and stop.

      • +
      +
    • +
    • +
      Keyframes Interpolators

      Interpolation is also a core part of the keyframes animation. It is responsible for filling in the blanks between the keyframes so that we have transitional states between the set keyframes. Another factor is that interpolators must be super-optimized to interpolate data in a minimum amount of time as possible or else it would be the bottleneck that lags the animation. +The following interpolators have been implemented as a part of the keyframes animation API:

      +
      +
      +
        +
      • Step Interpolator

      • +
      • Linear Interpolator

      • +
      • Spherical Linear Interpolator (Slerp)

      • +
      • Spline Interpolator

      • +
      • Cubic Spline Interpolator

      • +
      • Cubic Bézier Interpolator

      • +
      • Color Interpolators:

        +
          +
        • XYZ Color Interpolator

        • +
        • Lab Color Interpolator

        • +
        • HSV Color Interpolator

        • +
        +
      • +
      +https://user-images.githubusercontent.com/63170874/217738142-2dba8f6a-f8ff-4231-babd-048055074cc0.gif +https://user-images.githubusercontent.com/63170874/190892795-f47ceaf1-8dd0-4235-99be-2cf0aec323bb.gif +
        +
      • +
        Tutorials

        Also included 11 tutorials demonstrating how the FURY keyframe animation API works and how to use it to make some interesting animations. These tutorial will be added soon to the FURY website. +Subjects explained in the tutorials are:

        +
        +
        +
          +
        • Introduction

        • +
        • Timeline

        • +
        • Interpolators

        • +
        • Camera Animation

        • +
        • Hierarchical Animation

        • +
        • Using Color Interpolators

        • +
        • Using Bezier Interpolator

        • +
        • Using Spline Interpolator

        • +
        • Using time-based functions

        • +
        • Creating Custom Interpolators

        • +
        • Arm Robot Animation

        • +
        +
      • +
      +
    • +
    +

    Pull Requests:

    + +
  • +
  • PlaybackPanel UI component

    +

    At first, while in the early development stage of the FURY keyframe animation API, basic playback buttons were used to play, pause, and stop the animation. As the API kept growing, more controllers needed to be implemented, such as the time progress slider, the speed changer, and the loop toggle. And composing all of these controllers into a single UI element was inevitable. +While the PlaybackPanel is a main part of the Timeline, the goal was to make it completely independent from the keyframes animation API so that it can be used for anything else, i.e. a video player actor or a continuous time simulation or any other time-dependent applications.

    +image +

    Pull Requests:

    + +
  • +
  • +
    Billboard actor using the geometry shader

    Fury already has a billboard actor implemented using two triangles to construct the billboard. But the new approach uses only one vertex and the canvas of the billboard is generated by the geometry shader. This approach is faster in initialization since only the center is needed and no additional computations to generate the primitive on the CPU side. Also, animating these new billboards using the method mentioned above in the previous objective is way much faster, and faster is one of the reasons why we use billboards.

    +
    +
    +

    Pull Requests:

    + +
  • +
+
+
+

Objectives in Progress#

+
    +
  • +
    Animating primitives of the same FURY Actor separately

    Animating FURY actors is not a problem and can be done easily using the FURY animation module. The problem appears when trying to animate a massive amount of actors, thousands or even hundreds of thousands of actors, it’s impossible to do that using the animation module. Instead, primitives of the same actor can be animated by changing their vertices and then sending the new vertices buffer to the GPU. This also needs some discussion to find the cleanest way to implement it.

    +
    +
    +

    Pull Requests:

    + +
  • +
  • +
    Speeding up the animation using GLSL shaders

    Using the power of the GPU to help speed up the animations since some interpolators are relatively slow, such as the spline interpolator. Besides, morphing and skeletal animation would be tremendously optimized if they were computed on the GPU side!

    +
    +
    +

    Pull Requests:

    + +
  • +
+
+
+

Other Objectives#

+
    +
  • +
    Added more enhancements to the vector_text actor

    Added the ability to change the direction of the vector_text actor, as well as giving it the option to follow the camera. Also added the option to extrude the text which makes it more like 3D text.

    +

    Pull Requests:

    +
    +
    + +
  • +
  • Other PRs

    + +
  • +
  • GSoC Weekly Blogs

    + +
  • +
+
+
+

Timeline#

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Date

Description

Blog Post Link

Week 0
(23-05-2022)

My journey till getting accepted into GSoC22

FURY - Python

Week 1
(08-06-2022)

Implementing a basic Keyframe animation API

FURY - Python

Week 2
(28-06-2022)

Implementing non-linear and color interpolators

FURY - Python

Week 3
(04-07-2022)

Redesigning the API,
Implementing cubic Bezier Interpolator,
and making progress on the GPU side!

FURY - Python

Week 4
(11-07-2022)

Camera animation,
interpolation in GLSL, and a single Timeline!

FURY - Python

Week 5
(19-07-2022)

Slerp implementation,
documenting the Timeline, and adding unit tests

FURY - Python

Week 6
(25-07-2022)

Fixing the Timeline issues and equipping it with
more features

FURY - Python

Week 7
(01-08-2022)

Billboard spheres and implementing interpolators
using closures

FURY - Python

Week 8
(09-08-2022)

Back to the shader-based version of the Timeline

FURY - Python

Week 9
(16-08-2022)

Animating primitives of the same actor

FURY - Python

Week 10
(23-08-2022)

Supporting hierarchical animating

FURY - Python

Week 11
(30-08-2022)

Improving tutorials a little

FURY - Python

Week 12
(7-09-2022)

Adding new tutorials

FURY - Python

Week 13
(20-09-2022)

Keyframes animation is now a bit easier in FURY

FURY - Python

+
+
+ +
+ + + + + + + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2023/2023-01-29-final-report-shivam.html b/v0.10.x/posts/2023/2023-01-29-final-report-shivam.html new file mode 100644 index 000000000..bc965f528 --- /dev/null +++ b/v0.10.x/posts/2023/2023-01-29-final-report-shivam.html @@ -0,0 +1,884 @@ + + + + + + + + Google Summer of Code Final Work Product — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
gsoc
+ +fury +
+

Google Summer of Code Final Work Product#

+
    +
  • Name: Shivam Anand

  • +
  • Organisation: Python Software Foundation

  • +
  • Sub-Organisation: FURY

  • +
  • Project: FURY - glTF +Integration

  • +
+
+

Proposed Objectives#

+
    +
  • Ability to load glTF models

    +
      +
    • Should be able to load static glTF models

    • +
    • Should be able to add model to the scene.

    • +
    +
  • +
  • Exporting scene data as glTF file

  • +
  • Materials & Textures

    +
      +
    • Textures

    • +
    • PBRs

    • +
    +
  • +
  • Animations

    +
      +
    • Simple Actor animations

    • +
    • Skinning

    • +
    • Morphing

    • +
    +
  • +
  • Stretch Goals

    +
      +
    • Ability to load .glb files

    • +
    +
  • +
+
+
+

Objectives Completed#

+
+

Loading Static glTF models#

+

A glTF file is a JSON like file format containing required data for 3D scenes. VTK has two built-in glTF loaders. However, they lack ability to animate and apply materials. Added methods to load binary +data and create actors from them. These actors can be added directly +to the scene. The glTF class reads texture data from either +base64 encoded string or from the image file, and maps the +texture to the actor using the given UV data. It is capable of doing +the following:

+
    +
  • Loading both gltf and glb files. Get actors from the +model.

  • +
  • Applying textures and colors from materials.

  • +
  • Setting cameras if the model contains multiple cameras.

  • +
  • Apply normals (for a smoother surface).

  • +
+
+image +
+

Pull Requests:

+ +
+
+

Exporting Scene as a glTF#

+

The fury scene can contain multiple objects such as actors, cameras, +textures, etc. We need to get the primitive information (such as +Vertices, Triangles, UVs, Normals, etc.) from these objects and store +them into a .bin file. Added methods that export these +information to a .gltf or .glb file format.

+

Pull Requests:

+ +
+
+

Simple Actor Animations#

+

Added simple actor animations (translation, rotation & scale of +actors) support. The animation data (transformation and timestamp) is +stored in buffers. It converts the binary data to ndarrays and +creates a timleline for each animation in glTF animations. This +timeline contains actors an can be added to the scene. We can animate +the scene by updating timeline inside a timer callback.

+https://user-images.githubusercontent.com/74976752/217645594-6054ea83-12e5-4868-b6a1-eee5a154bd26.gif +

Pull Requests:

+ +
+
+

Morphing in glTF#

+

glTF allows us to animate meshes using morph targets. A morph target +stores displacements or differences for certain mesh attributes. At +runtime, these differences may be added to the original mesh, with +different weights, to animate parts of the mesh. Added methods to +extract this information, update the timeline and apply morphing to +each actor in the scene.

+https://user-images.githubusercontent.com/74976752/217645485-153ec403-6c87-4282-8907-30d921106b34.gif +

Pull Requests:

+ +
+
+

Skeletal Animations (Skining)#

+

Another way of animating a glTF is by skinning. It allows the +geometry (vertices) of a mesh to be deformed based on the pose of a +skeleton. This is essential in order to give animated geometry. It +combines every parameter of a glTF file. While working with skinning, +we need to keep track of the parent-child hierarchy of +transformations. Vertex Skinning takes full advantage of newly +implemented Timeline & Animation modules to track +hierarchical transformation order. Though the current version of the +skinning implementation works with most of the glTF sample modes, It +struggles with models that have multiple actors (e.g. BrainStem). It +can be fixed by using the vertex shader to update the vertices. The +current implementation of skinning supports the following:

+
    +
  • Multiple animation support

  • +
  • Multiple node and multiple actor animation with textures

  • +
  • Show or hide bones/skeleton of the model.

  • +
+https://user-images.githubusercontent.com/74976752/217645367-f901c6ed-ca20-40d6-92dd-f1cd8899ac7a.gif +

Pull Requests:

+ +
+
+
+

Objectives in Progress#

+
+

PBR and emission materials in glTF#

+

The glTF format supports Physically based rendering also. PBR allow +renderers to display objects with a realistic appearance under +different lighting conditions, the shading model has to take the +physical properties of the object surface into account. There are +different representations of these physical material properties. One +that is frequently used is the metallic-roughness-model. We have +various material properties already in FURY, we need to apply it to +glTF models as well.

+
+
+

Skinning for models with no indices#

+

The glTF format supports non-indexed geometry (e.g., the Fox +model). We currently do not know how to render the model without +indices. I tried estimating it in this +branch. +However, It fails to render in skinning.

+

Branch URL:

+
    +
  • Rendering glTF with no indices: (in-progress) +xtanion/fury

  • +
+
+
+
+

Other Objectives#

+
+

Fetcher for importing glTF files from Khronos-glTF-Samples#

+

The +KhronosGroup/gltf-samples +contain multiple glTF sample models to test a glTF viewer for free. +Implemented new methods in fetcher that can load all of these models +by (using type) asynchronously. The glTF fetcher is capable +of the following:

+
    +
  • Downloading multiple models asynchronously.

  • +
  • Get the path to the downloaded model using it - Download any model using the URL of the model.

  • +
+

Pull Requests:

+ +
+
+

Other Pull Requests#

+ +
+
+

GSoC weekly blogs#

+ +
+
+
+

Timeline#

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Date

Description

Blog Post Link

Week 0
(24-05-2022)

My journey to GSoC 2022

FURY - Python

Week 1
(20-06-2022)

A basic glTF Importer

FURY - Python

Week 2
(29-06-2022)

Improving Fetcher and Exporting glTF

FURY - Python

Week 3
(04-07-2022)

Fixing fetcher adding tests and docs

FURY - Python

Week 4
(12-07-2022)

Finalizing glTF loader

FURY - Python

Week 5
(19-07-2022)

Creating PR for glTF exporter and fixing the loader

FURY - Python

Week 6
(25-07-2022)

Extracting the animation data

FURY - Python

Week 7
(01-08-2022)

Fixing bugs in animations

FURY - Python

Week 8
(09-08-2022)

Fixing animation bugs

FURY - Python

Week 9
(17-08-2022)

First working skeletal animation prototype

FURY - Python

Week 10
(25-08-2022)

Multi-node skinning support

FURY - Python

Week 11
(31-08-2022)

Multiple transformations support and adding tests

FURY - Python

Week 12
(08-09-2022)

Adding skeleton as actors and fix global transformation

FURY - Python

Week 13
(15-09-2022)

Multi bone skeletal animations

FURY - Python

Week 14
(28-09-2022)

Morphing is here !

FURY - Python

+
+
+ +
+ + + + + + + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2023/2023-02-01-gsoc.html b/v0.10.x/posts/2023/2023-02-01-gsoc.html new file mode 100644 index 000000000..90e828018 --- /dev/null +++ b/v0.10.x/posts/2023/2023-02-01-gsoc.html @@ -0,0 +1,504 @@ + + + + + + + + Contribute to FURY via Google Summer of Code 2023 — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Contribute to FURY via Google Summer of Code 2023#

+

FURY is participating in the Google Summer of Code 2023 under the umbrella of the Python Software Foundation.

+

FURY is a free and open source software library for scientific visualization and 3D animations. FURY contains many tools for visualizing a series of scientific data including graph and imaging data.

+

A list of project ideas and application info is on our GitHub Wiki.

+

If you are interested in talking to us about projects, applications join us to our discord community or drop us a line on our mailing list.

+

Be part of our community and Enjoy your summer of code!

+

Serge K.

+
+ +
+ + + + +
+ + + + Previous: + + + + Google Summer of Code Final Work Product + + + +   + + + + Next: + + + FURY 0.9.0 Released + + + + +
+ + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2023/2023-04-14-release-announcement.html b/v0.10.x/posts/2023/2023-04-14-release-announcement.html new file mode 100644 index 000000000..a9be4847c --- /dev/null +++ b/v0.10.x/posts/2023/2023-04-14-release-announcement.html @@ -0,0 +1,558 @@ + + + + + + + + FURY 0.9.0 Released — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

FURY 0.9.0 Released#

+

The FURY project is happy to announce the release of FURY 0.9.0! +FURY is a free and open source software library for scientific visualization and 3D animations.

+

You can show your support by adding a star on FURY github project.

+

This Release is mainly a maintenance release. The major highlights of this release are:

+
    +
  • New Streaming System added.

  • +
  • Large improvement of Signed Distance Functions actors (SDF).

  • +
  • Continuous Integration (CI) platform updated. Migrate Windows CI from Azure to Github Actions

  • +
  • Migration from setuptools to hatching. versioning system updated also.

  • +
  • New module fury.animation added.

  • +
  • New module fury.gltf added. Module to support glTF 2.0.

  • +
  • Multiple tutorials added and updated.

  • +
  • Documentation updated.

  • +
  • Website updated.

  • +
+
+

Note

+

The complete release notes are available here

+
+

To upgrade or install FURY

+

Run the following command in your terminal:

+
pip install --upgrade fury
+
+
+

or:

+
conda install -c conda-forge fury
+
+
+

Questions or suggestions?

+

For any questions go to http://fury.gl, or send an e-mail to fury@python.org +We can also join our discord community

+

We would like to thanks to all contributors for this release:

+
    +
  • Anand Shivam

  • +
  • Antriksh Misri

  • +
  • Bruno Messias

  • +
  • Dwij Raj Hari

  • +
  • Eleftherios Garyfallidis

  • +
  • Filipi Nascimento Silva

  • +
  • Francois Rheault

  • +
  • Frank Cerasoli

  • +
  • Javier Guaje

  • +
  • Johny Daras

  • +
  • Mohamed Agour

  • +
  • Nasim Anousheh

  • +
  • Praneeth Shetty

  • +
  • Rohit Kharsan

  • +
  • Sara Hamza

  • +
  • Serge Koudoro

  • +
  • Siddharth Gautam

  • +
  • Soham Biswas

  • +
  • Sreekar Chigurupati

  • +
  • Tania Castillo

  • +
  • Zhiwen Shi

  • +
  • maharshigor

  • +
  • sailesh

  • +
  • sparshg

  • +
+

On behalf of the FURY developers,

+

Serge K.

+
+ +
+ + + + + + + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2023/2023-05-29-week-0-joaodellagli.html b/v0.10.x/posts/2023/2023-05-29-week-0-joaodellagli.html new file mode 100644 index 000000000..ad6b30ca8 --- /dev/null +++ b/v0.10.x/posts/2023/2023-05-29-week-0-joaodellagli.html @@ -0,0 +1,551 @@ + + + + + + + + The Beginning of Everything - Week 0 — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

The Beginning of Everything - Week 0#

+
+

So it begins…#

+

Hello everyone, welcome to the beginning of my journey through GSoC 2023! I would like to thank everyone involved for the opportunity provided, it is an honour to be working side by side with professionals and so many experienced people from around the world.

+
+
+

The Community Bonding Period#

+

During my community bonding period, I had the opportunity to meet my mentors and some people from the FURY team. It was a great time to learn about community guidelines and everything I will need to work with them during this summer.

+
+
+

The Project’s Goal#

+

Briefly explaining this project, I plan to implement a real-time Kernel Density Estimation shader inside FURY library, based on Filipi Nascimento’s WebGL implementation. KDE, or Kernel Density Estimation, is a visualization technique that provides a good macro visualization of large and complex data sets, like point clouds, well summarizing their spatial distribution in smooth areas. I really think FURY will benefit from this as a scientific library, knowing it is a computer graphics library that originated in 2018 based on the Visualization Toolkit API (VTK), and has been improving since then.

+
+
+

This Week’s Goal#

+

For all of this to work, the project needs one component working: the KDE framebuffer. As this Khronos wiki page well explains:

+

“A Framebuffer is a collection of buffers that can be used as the destination for rendering. OpenGL has two kinds of framebuffers: the Default Framebuffer, +which is provided by the OpenGL Context; and user-created framebuffers called Framebuffer Objects (FBOs). +The buffers for default framebuffers are part of the context and usually represent a window or display device. The buffers for FBOs reference images from either Textures or Renderbuffers; they are never directly visible.”

+

Which means that a framebuffer is an object that stores data related to a frame. So the goal for this week is to investigate whether VTK, the API which FURY is written on, has a framebuffer object interface, and if it has, to understand how it works and how to use it for the project.

+

Let’s get to work!

+
+
+ +
+ + + + +
+ + + + Previous: + + + + FURY 0.9.0 Released + + + +   + + + + Next: + + + Week 0: Community Bounding Period + + + + +
+ + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2023/2023-06-02-week-0-praneeth.html b/v0.10.x/posts/2023/2023-06-02-week-0-praneeth.html new file mode 100644 index 000000000..6a2b78e48 --- /dev/null +++ b/v0.10.x/posts/2023/2023-06-02-week-0-praneeth.html @@ -0,0 +1,522 @@ + + + + + + + + Week 0: Community Bounding Period — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Week 0: Community Bounding Period#

+
+

GSoC 2023: Community Bonding Period#

+

Hello All!

+

I’m thrilled to announce that I’ll be participating in Google Summer of Code (GSoC) for yet another year. To catch a glimpse of my previous journey, check out my experiences here.

+

During the community bonding period, we had our first GSoC meet, where we got acquainted with the program’s rules and regulations. It was an excellent opportunity to virtually meet my fellow contributors and discuss our upcoming projects. Excitement filled the air as we exchanged ideas and set goals for the summer ahead.

+

Stay tuned for updates on my GSoC project as I share my progress, challenges, and breakthroughs along the way. I’m grateful for the opportunity to be part of this remarkable community.

+
+
+ +
+ + + + + + + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ +
+ +
+ On this page +
+ +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2023/2023-06-02-week-0-tvcastillod.html b/v0.10.x/posts/2023/2023-06-02-week-0-tvcastillod.html new file mode 100644 index 000000000..983c3fdc0 --- /dev/null +++ b/v0.10.x/posts/2023/2023-06-02-week-0-tvcastillod.html @@ -0,0 +1,546 @@ + + + + + + + + Week 0: Community Bounding Period — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Week 0: Community Bounding Period#

+
+

GSoC 2023: Community Bonding Period#

+

Hello everyone, my name is Tania Castillo, I am close to finishing my degree in Computer Science and I think this is a great opportunity to put my learning and skills into practice. I will be working with FURY on improving the visualization of DTI tensors and HARDI ODFs glyphs by using well-known techniques in computer graphics.

+
+
+

What did I do this week?#

+

During the community bonding period, I had the opportunity to get to know better GSoC mentors and former contributors. I also had the first meeting with FURY mentors where I got to learn more about the dynamic of the program, important things to keep in mind while coding, and suggestions when making the PRs. We also receive some details on how to work with shaders which is something I have to take into account since I will use them to develop part of the project. In addition, I’ve been working on the first part of the project which consists of the creation of tensor ellipsoids using the raymarching technique and SDFs.

+
+
+

What is coming up next?#

+

Since the advances I managed to make are in their most basic stage, I will be working this week on making changes and adjusting details for the implementation to follow FURY guidelines. In this way, I plan to submit my first PR for the project to start getting feedback and making improvements. I will also start working on the first tests for the ellipsoid actor I’m working on.

+
+
+

Did I get stuck anywhere?#

+

For now, everything is going well, although I know I will probably run into some problems when reviewing and adjusting my code. We will see later this week.

+
+
+ +
+ + + + + + + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2023/2023-06-03-week-1-praneeth.html b/v0.10.x/posts/2023/2023-06-03-week-1-praneeth.html new file mode 100644 index 000000000..7c629bc5b --- /dev/null +++ b/v0.10.x/posts/2023/2023-06-03-week-1-praneeth.html @@ -0,0 +1,548 @@ + + + + + + + + Week 1: Working with SpinBox and TextBox Enhancements — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Week 1: Working with SpinBox and TextBox Enhancements#

+
+

What did you do this week?#

+

This week, my focus was on reviewing pull requests (PRs) and issues related to the user interface (UI) of the project. I meticulously went through each PR and issue, identifying those specifically associated with UI improvements. To streamline the process, I categorized them accordingly under the UI category. One of the key tasks was PR #499, which involved the implementation of SpinBoxUI. After rebasing the PR, I identified an alignment issue with the textbox component.

+

To resolve this issue, I started by investigating the root cause. I discovered that the alignment was initially based on the position of the parent UI, which caused the text to extend beyond the boundaries of the textbox. To rectify this, I devised a solution where I calculated the background size of the textbox and adjusted the text’s position accordingly. By aligning the text with the calculated size, I ensured a proper and visually appealing alignment within the textbox.

+

To provide a clear understanding of the improvement, I have prepared a comparison of the textbox alignment before and after the modifications.

+

Before:

+https://user-images.githubusercontent.com/64432063/243150149-30330be2-b529-47e9-850a-6e3a8bc03551.png +

After:

+https://user-images.githubusercontent.com/64432063/243150735-86f85d6c-f9df-4092-abdf-248b6ec77c5e.png +
+
+

Did you get stuck anywhere?#

+

Fortunately, I didn’t encounter any significant challenges this week.

+
+
+

What is coming up next?#

+

Looking ahead, here’s what I have planned for the upcoming week:

+
    +
  1. Completing PR #790 - Fixing Textbox Alignment

  2. +
  3. Wrapping up PR #499 - SpinBoxUI

  4. +
  5. Initiating PR #576 - Icon Flaw in ComboBox

  6. +
+
+
+ +
+ + + + +
+ + + + Previous: + + + + Week 0: Community Bounding Period + + + +   + + + + Next: + + + The FBO Saga - Week 1 + + + + +
+ + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2023/2023-06-05-week-1-joaodellagli.html b/v0.10.x/posts/2023/2023-06-05-week-1-joaodellagli.html new file mode 100644 index 000000000..ca36558ab --- /dev/null +++ b/v0.10.x/posts/2023/2023-06-05-week-1-joaodellagli.html @@ -0,0 +1,569 @@ + + + + + + + + The FBO Saga - Week 1 — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

The FBO Saga - Week 1#

+
+

This Past Week#

+

As mentioned in the last week’s blogpost, the goal for that week was to investigate VTK’s Framebuffer Object framework. +An update on that is that indeed, VTK has one more low-level working FBO class that can be used inside FURY, however, +they come with some issues that I will explain further below.

+
+
+

My Current Problems#

+

The problems I am having with these FBO implementations are first something related to how a FBO works, and second related to how VTK works. +In OpenGL, a custom user’s FBO needs some things to be complete (usable):

+
    +
  1. At least one buffer should be attached. This buffer can be the color, depth or stencil buffer.

  2. +
  3. If no color buffer will be attached then OpenGL needs to be warned no draw or read operations will be done to that buffer. Otherwise, there should be at least one color attachment.

  4. +
  5. All attachments should have their memory allocated.

  6. +
  7. Each buffer should have the same number of samples.

  8. +
+

My first problem relies on the third requirement. VTK’s implementation of FBO requires a vtkTextureObject +as a texture attachment. I figured out how to work with this class, however, I cannot allocate memory for it, as its methods for it, Allocate2D, Create2D and Create2DFromRaw +does not seem to work. Every time I try to use them, my program stops with no error message nor nothing. +For anyone interested in what is happening exactly, below is how I my tests are implemented:

+
| color_texture = vtk.vtkTextureObject() # color texture declaration
+| color_texture.Bind() # binding of the texture for operations
+| color_texture.SetDataType(vtk.VTK_UNSIGNED_CHAR) # setting the datatype for unsigned char
+| color_texture.SetInternalFormat(vtk.VTK_RGBA) # setting the format as RGBA
+| color_texture.SetFormat(vtk.VTK_RGBA)
+| color_texture.SetMinificationFilter(0) # setting the minfilter as linear
+| color_texture.SetMagnificationFilter(0) # setting the magfilter as linear
+|
+| color_texture.Allocate2D(width, height, 4, vtk.VTK_UNSIGNED_CHAR) # here is where the code stops
+
+
+

In contrast, for some reason, the methods for 3D textures, Allocate3D works just fine. +I could use it as a workaround, but I do not wish to, as this just does not make sense.

+

My second problem relies on VTK. As VTK is a library that encapsulates some OpenGL functions in more palatable forms, it comes with some costs. +Working with FBOs is a more low-level work, that requires strict control of some OpenGL states and specific functions that would be simpler if it was the main API here. +However, some of this states and functions are all spread and implicit through VTK’s complex classes and methods, which doubles the time expended to make some otherwise simple instructions, +as I first need to dig in lines and lines of VTK’s documentation, and worse, the code itself.

+
+
+

What About Next Week?#

+

For this next week, I plan to investigate further on why the first problem is happening. If that is accomplished, then things will be more simple, as it will be a lot easier for my project to move forward as I will finally be able +to implement the more pythonic functions needed to finally render some kernel distributions onto my screen.

+

Wish me luck!

+
+
+ + + +
+ + + +
+ +
+
+
+ +
+ + + +
+ +
+ +
+ On this page +
+ +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2023/2023-06-05-week-1-tvcastillod.html b/v0.10.x/posts/2023/2023-06-05-week-1-tvcastillod.html new file mode 100644 index 000000000..b501b40ec --- /dev/null +++ b/v0.10.x/posts/2023/2023-06-05-week-1-tvcastillod.html @@ -0,0 +1,540 @@ + + + + + + + + Week 1: Ellipsoid actor implemented with SDF — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Week 1: Ellipsoid actor implemented with SDF#

+
+

What did I do this week?#

+

PR #791: Ellipsoid actor implemented with SDF

+

I made a first PR with the implementation of the ellipsoid actor defined with a SDF using raymarching. The current sdf actor allows the creation of ellipsoids, but it lacks control over their shape, and the displayed direction does not match the intended orientation. For this reason, a new actor just focused on ellipsoids was made, this one is defined by its axes (3x3 orthogonal matrix) and their corresponding lengths (3x1 vector), along with other attributes like color, opacity, and scale. The goal is to make an implementation that allows displaying a large amount of data, with good visual quality, and without compromising performance. I’m still working on this but here is a first glance of how it looks like:

+https://user-images.githubusercontent.com/31288525/244503195-a626718f-4a13-4275-a2b7-6773823e553c.png +

This will be used later to create the tensor ellipsoids used on tensor_slicer.

+
+
+

What is coming up next?#

+

I need to talk to my mentors first but the idea is to start making improvements on the SDF definition and raymarching algorithm, I have already started looking for information about how I can do it, and if I get good ideas, I will compare if there is an improvement in performance respect to the implementation I have right now. I also need to keep working on tests, the most common way of doing it is to check the number of objects and colors displayed, but I would like to test other things related to performance.

+
+
+

Did I get stuck anywhere?#

+

Not yet, I need to get feedback first to see if there is anything I need to review or correct.

+
+
+ +
+ + + + + + + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2023/2023-06-11-week-2-praneeth.html b/v0.10.x/posts/2023/2023-06-11-week-2-praneeth.html new file mode 100644 index 000000000..c58315e9c --- /dev/null +++ b/v0.10.x/posts/2023/2023-06-11-week-2-praneeth.html @@ -0,0 +1,543 @@ + + + + + + + + Week 2: Tackling Text Justification and Icon Flaw Issues — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Week 2: Tackling Text Justification and Icon Flaw Issues#

+
+

What did you do this week?#

+

This week, I continued tweaking the text justification PR #790 and encountered a new issue when combining both justification and vertical_justification. The problem arose because the vertical_justification did not take into account the applied justification, resulting in unexpected behavior. I focused on resolving this issue by ensuring that both justifications work together correctly. Additionally, during the weekly meeting, we discussed the problem and decided to introduce new properties such as boundaries and padding to enhance the functionality of the text justification feature.

+

Furthermore, I started working on PR #576, which aimed to address the flaw in the icon of the combobox. While investigating this issue, I discovered related problems and PRs, including #562, #731, and #768. The main challenge was related to the propagation of the set_visibility feature of the UI, causing the combobox to automatically open its options. To overcome this issue, I requested the author of PR #768 to rebase their pull request as it can be a solution for the issue.

+
+
+

Did you get stuck anywhere?#

+

A significant portion of my time was dedicated to resolving the text justification issue when both justification types were combined. It required careful analysis and adjustments to ensure the desired behavior.

+
+
+

What is coming up next?#

+

For the upcoming week, I have the following plans:

+
    +
  1. Work on modifying the text justification implementation to address any remaining issues and ensure compatibility with other features.

  2. +
  3. Begin the implementation of the scrollbar class from scratch to provide a robust and customizable scrollbar element.

  4. +
  5. Focus on completing the resolution of the icon flaw issue by collaborating with the relevant stakeholders and ensuring the necessary modifications are made.

  6. +
+
+
+ + + +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2023/2023-06-12-week-2-joaodellagli.html b/v0.10.x/posts/2023/2023-06-12-week-2-joaodellagli.html new file mode 100644 index 000000000..bb1f6083e --- /dev/null +++ b/v0.10.x/posts/2023/2023-06-12-week-2-joaodellagli.html @@ -0,0 +1,585 @@ + + + + + + + + Week 2: The Importance of (good) Documentation — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Week 2: The Importance of (good) Documentation#

+

Hello everybody, welcome to the week 2 of this project! I must admit I thought this would be simpler than it is currently being, but I forgot that when it comes to dealing with computer graphics’ applications, things never are. Below, some updates on what I have been up to for this past week.

+
+

This Last Week’s Effort#

+

Last week, I was facing some issues with a VTK feature essential so I could move forward with my project: Framebuffer Objects. +As described in my last blogpost, for some reason the 2D allocation methods for it weren’t working. +In a meeting with my mentors, while we were discussing and searching through VTK’s FramebufferObject and TextureObject documentation, and the code itself for the problem, +one TextureObject method caught my attention: vtkTextureObject.SetContext().

+
+
+

Where the Problem Was#

+

My last week’s code was:

+
color_texture = vtk.vtkTextureObject() # color texture declaration
+color_texture.Bind() # binding of the texture for operations
+
+color_texture.SetDataType(vtk.VTK_UNSIGNED_CHAR) # setting the datatype for unsigned char
+color_texture.SetInternalFormat(vtk.VTK_RGBA) # setting the format as RGBA
+color_texture.SetFormat(vtk.VTK_RGBA)
+color_texture.SetMinificationFilter(0) # setting the minfilter as linear
+color_texture.SetMagnificationFilter(0) # setting the magfilter as linear
+
+color_texture.Allocate2D(width, height, 4, vtk.VTK_UNSIGNED_CHAR) # here is where the code stops
+
+
+

But it turns out that to allocate the FBO’s textures, of type vtkTextureObject, you need to also set the context where the texture object +will be present, so it lacked a line, that should be added after Bind():

+
color_texture = vtk.vtkTextureObject()
+color_texture.Bind()
+
+color_texture.SetContext(manager.window) # set the context where the texture object will be present
+
+color_texture.SetDataType(vtk.VTK_UNSIGNED_CHAR)
+color_texture.SetInternalFormat(vtk.VTK_RGB)
+color_texture.SetFormat(vtk.VTK_RGB)
+color_texture.SetMinificationFilter(0)
+color_texture.SetMagnificationFilter(0)
+
+
+

The code worked fine. But as my last blogpost showed, Allocate3D() method worked just fine without a (visible) problem, why is that? +Well, in fact, it didn’t work. If we check the code for the Allocate2D() and Allocate3D(), one difference can be spotted:

+Image comparing Allocate2D and Allocate3D methods +

While in Allocate2D() there is an assert(this->Context);, in Allocate3D() the assertion is translated into:

+
if(this->Context==nullptr)
+{
+  vtkErrorMacro("No context specified. Cannot create texture.");
+  return false;
+}
+
+
+

This slight difference is significant: while in Allocate2D() the program immediately fails, in Allocate3D() the function is simply returned +false, with its error pushed to vtkErrorMacro. I could have realised that earlier if I were using vtkErrorMacro, but this difference in their +implementation made it harder for me and my mentors to realise what was happening.

+
+
+

This Week’s Goals#

+

After making that work, this week’s goal is to render something to the Framebuffer Object, now that is working. To do that, +first I will need to do some offscreen rendering to it, and afterwards render what it was drawn to its color attachment, the Texture Object I +was struggling to make work, into the screen, drawing its texture to a billboard. Also, I plan to start using vtkErrorMacro, as it seems like +the main error interface when working with VTK, and that may make my life easier.

+

See you next week!

+
+
+ + + +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2023/2023-06-12-week-2-tvcastillod.html b/v0.10.x/posts/2023/2023-06-12-week-2-tvcastillod.html new file mode 100644 index 000000000..bd2069da3 --- /dev/null +++ b/v0.10.x/posts/2023/2023-06-12-week-2-tvcastillod.html @@ -0,0 +1,541 @@ + + + + + + + + Week 2: Making adjustments to the Ellipsoid Actor — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Week 2: Making adjustments to the Ellipsoid Actor#

+
+

What did I do this week?#

+

I made some minor adjustments to the last PR I submitted. Last time it was a draft since I was waiting for the weekly meeting to know how to proceed, but now it is ready. I am waiting for the review so I can make the necessary corrections and adjustments to merge this first PR soon.

+
+
+

What is coming up next?#

+

As I receive feedback, I will continue to work on the PR #791 and make adjustments and changes as needed. That said, I will start working on another part of the project, which is the visualization of uncertainty. Without going into details (for now) what I have to do is:

+
    +
  • Create a double_cone or dti_uncertainty actor. I’m going to work on the double cone made also with raymarching and SDF, since the implementation is pretty much the same as the ellipsoid I already have.

  • +
  • Make a function that returns the level of the uncertainty given by the angle of the uncertainty cone we want to visualize. For this I need to double-check the maths behind the uncertainty calculation to make sure I’m getting the right results.

  • +
+
+
+

Did I get stuck anywhere?#

+

Not exactly, but one of the things that were mentioned in the last meeting is that we should try to simplify the shader code as much as we can, that is, to break down the entire implementation into simple and easy-to-understand lines of code, which also allows the definition of functions that can be reused later on. I need to keep working on this, so I can make my code even more readable and fit the new shader structure.

+
+
+ + + +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2023/2023-06-17-week-3-praneeth.html b/v0.10.x/posts/2023/2023-06-17-week-3-praneeth.html new file mode 100644 index 000000000..6efcf45ad --- /dev/null +++ b/v0.10.x/posts/2023/2023-06-17-week-3-praneeth.html @@ -0,0 +1,545 @@ + + + + + + + + Week 3: Resolving Combobox Icon Flaw and TextBox Justification — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Week 3: Resolving Combobox Icon Flaw and TextBox Justification#

+
+

What did you do this week?#

+

This week, I tackled the ComboBox2D icon flaw, which was addressed using Pull Request (PR) #576. The problem arose when we added a ComboBox2D to the TabUI. The TabUI would propagate the set_visibility = true for all its child elements, causing the combobox to appear on the screen without the icon change. To fix this issue, PR #768 updated the set_visibility method of the UI class, ensuring that the icon change was applied correctly.

+
+Combobox Icon +
+

Next, I focused on the textbox justification. As discussed in our meeting, I added a new property called boundingbox to the TextBlock2D. However, I encountered a problem when resizing the TextBlock2D. The vtkTextActor property would switch from SetTextScaleModeToNone to SetTextScaleModeToProp, which would scale the font according to the position1 (lower left corner) and position2 (upper right corner) of the UI. This inconsistency in font scaling resulted in misaligned text actors. I spent some time investigating this issue, and you can find my progress in the ongoing PR #803.

+

Additionally, I started working on creating a Scrollbar component by inheriting the LineSlider2D. I made adjustments to the position and other attributes to make it function as a scrollbar. However, I encountered some confusion regarding how to separate the scrollbar component from other elements and determine what should be included in the scrollbar itself.

+
+Scrollbar +
+
+
+

Did you get stuck anywhere?#

+

I faced a challenge while working on the text justification. It took me several days to identify the root cause of the occasional malfunctioning of the TextBlock2D. At last, I found out the reason behind the issue.

+
+
+

What is coming up next?#

+

Next week, I have several tasks lined up. Firstly, I will be working on the CardUI PR #398. Additionally, I plan to complete the segregation of the scrollbar component, ensuring its independence and clarity. Lastly, I will be working on issue #540, which involves updating the use of the numpy_to_vtk_image_data utility function.

+
+
+ +
+ + + + + + + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2023/2023-06-19-week-3-joaodellagli.html b/v0.10.x/posts/2023/2023-06-19-week-3-joaodellagli.html new file mode 100644 index 000000000..7e9da7233 --- /dev/null +++ b/v0.10.x/posts/2023/2023-06-19-week-3-joaodellagli.html @@ -0,0 +1,551 @@ + + + + + + + + Week 3: Watch Your Expectations — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Week 3: Watch Your Expectations#

+

Hello everyone, it’s time for another weekly blogpost! This week, +I will talk about how you should watch your expectations when working with any project.

+
+

This Last Week’s Effort#

+

As I supposedly managed to make the texture allocation part working, this last week’s goal was to render something to a FBO. Well, I could make +textures work, but what I wasn’t expecting and later realised, was that the FBO setup not working. Below I will describe where I got stuck.

+
+
+

Where the Problem Was#

+

After getting the textures setup right, I was ready to render some color to the FBO. Well, I was, because I didn’t expect +I would have another problem, this time, with the FBO setup. As described in my week 1 blogpost, +a FBO needs some requirements to work. My current problem relies on the FBO method FBO.SetContext(), that for some reason is not being able to generate the FBO. +Below, how the method is currently operating:

+Image showing the SetContext's VTK implementation +

Apparently, the method is stuck before the this->CreateFBO(), that can be checked when we call FBO.GetFBOIndex(), that returns a 0 value, +meaning the FBO was not generated by the glGenFramebuffers() function, that is inside the GetContext() method.

+
+
+

This Week’s Goals#

+

As I got stuck again with this simple step, talking with my mentors we concluded that a plan B is needed for my GSoC participation as +my current project is not having much progress. This plan B that I am gonna start working on this week involves working on FURY Speed, +a FURY addon that aims to develop optimized functions and algorithms to help speed up graphical applications. The suggestion was to +work on a PR I submitted months ago, #783, in a way to integrate that into FURY Speed. +Also, I plan to keep working on my current project to find the solution I will need to make the FBO usage work.

+

Let’s get to work!

+
+
+ + + +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2023/2023-06-19-week-3-tvcastillod.html b/v0.10.x/posts/2023/2023-06-19-week-3-tvcastillod.html new file mode 100644 index 000000000..c0fe30e09 --- /dev/null +++ b/v0.10.x/posts/2023/2023-06-19-week-3-tvcastillod.html @@ -0,0 +1,537 @@ + + + + + + + + Week 3: Working on uncertainty and details of the first PR — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Week 3: Working on uncertainty and details of the first PR#

+
+

What did I do this week?#

+

I made some adjustments to the ellipsoid actor definition, now called tensor. This was something discussed in the weekly meeting as the coming changes are related to this actor, the idea now is to have a tensor actor that allows choosing between displaying the tensor ellipsoids or the uncertainty cones (later on). I also worked on the uncertainty calculation, and the cone SDF for the visualization, so I plan to do a WIP PR next to start getting feedback on this new addition.

+
+
+

What is coming up next?#

+

As for the uncertainty calculation, other data is needed such as the noise variance and the design matrix (check this article for more details), I need to identify which should be the parameters for the function definition. I also have to work on the documentation, so the function and its purpose are clear. I plan to make some final adjustments related to the uncertainty so that the next PR is ready for submission this week. I also expect to make final changes to the first PR so that it can be merged soon.

+
+
+

Did I get stuck anywhere?#

+

Not this week, I will wait for feedback to see if there is anything I need to review or correct.

+
+
+ +
+ + + + + + + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2023/2023-06-24-week-4-praneeth.html b/v0.10.x/posts/2023/2023-06-24-week-4-praneeth.html new file mode 100644 index 000000000..c27c1b748 --- /dev/null +++ b/v0.10.x/posts/2023/2023-06-24-week-4-praneeth.html @@ -0,0 +1,543 @@ + + + + + + + + Week 4: Exam Preparations and Reviewing — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Week 4: Exam Preparations and Reviewing#

+
+

What did I do this week?#

+

This week, amidst end-semester exams, I managed to accomplish a few notable tasks. Let’s dive into the highlights:

+
    +
  1. Merging CardUI: The PR #398 introduced the CardUI to the UI system of FURY. After a successful review and test check, it was merged into the codebase.

  2. +
  3. Revisiting PR #540: I restarted working on PR #540 as I wasn’t satisfied with the previous approach when I checked it for rebasing. I took the opportunity to update the code and ensure that the unit tests passed successfully. Although there are a few issues remaining in the tests, I am determined to resolve them and move forward with the implementation. This PR aims to improve the usage of the numpy_to_vtk_image_data utility function.

  4. +
  5. Independent Scrollbar Consideration: We are currently evaluating the necessity of making the Scrollbar an independent element. Currently it is only used by the ListBox2D, we are exploring various use cases to determine if there are other scenarios where the Scrollbar can be employed independently. This evaluation will help us make an informed decision about its future implementation.

  6. +
  7. PR Reviews: In the brief intervals between exams, I utilized the time to review two PRs: #446 - Resize panel and #460 - Tree UI.

  8. +
+
+
+

Did I get stuck anywhere?#

+

No, fortunately, I didn’t encounter any major obstacles or challenges during my tasks this week.

+
+
+

What is coming up next?#

+

Once the exams are over, I am eagerly looking forward to making a full comeback to development. My immediate plans include addressing the remaining issues in PR #540 and completing the pending tasks. I will also catch up on any missed discussions and sync up with the team to align our goals for the upcoming weeks.

+
+
+ +
+ + + + + + + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2023/2023-06-26-week-4-joaodellagli.html b/v0.10.x/posts/2023/2023-06-26-week-4-joaodellagli.html new file mode 100644 index 000000000..886f44184 --- /dev/null +++ b/v0.10.x/posts/2023/2023-06-26-week-4-joaodellagli.html @@ -0,0 +1,570 @@ + + + + + + + + Week 4: Nothing is Ever Lost — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Week 4: Nothing is Ever Lost#

+

Welcome again to another weekly blogpost! Today, let’s talk about the importance of guidance throughout a project.

+
+

Last Week’s Effort#

+

So, last week my project was struggling with some supposedly simple in concept, yet intricate in execution issues. If you recall from +my last blogpost, I could not manage to make the Framebuffer Object setup work, as its method, +SetContext(), wasn’t being able to generate the FBO inside OpenGL. Well, after some (more) research about that as I also dived in my +plan B, that involved studying numba as a way to accelerate a data structure I implemented on my PR #783, +me and one of my mentors decided we needed a pair programming session, that finally happened on thursday. After that session, +we could finally understand what was going on.

+
+
+

Where the Problem Was#

+

Apparently, for the FBO generation to work, it is first needed to initialize the context interactor:

+
FBO = vtk.vtkOpenGLFramebufferObject()
+
+manager.window.SetOffScreenRendering(True) # so the window doesn't show up, but important for later as well
+manager.initialize() # missing part that made everything work
+
+FBO.SetContext(manager.window) # Sets the context for the FBO. Finally, it works
+FBO.PopulateFramebuffer(width, height, True, 1, vtk.VTK_UNSIGNED_CHAR, False, 24, 0) # And now I could populate the FBO with textures
+
+
+

This simple missing line of code was responsible for ending weeks of suffer, as after that, I called:

+
print("FBO of index:", FBO.GetFBOIndex())
+print("Number of color attachments:", FBO.GetNumberOfColorAttachments())
+
+
+

That outputted:

+
FBO of index: 4
+Number of color attachments: 1
+
+
+

That means the FBO generation was successful! One explanation that seems reasonable to me on why was that happening is that, as it was +not initialized, the context was being passed null to the SetContext() method, that returned without any warning of what was happening.

+

Here, I would like to point out how my mentor was essential to this solution to come: I had struggled for some time with that, and could +not find a way out, but a single session of synchronous pair programming where I could expose clearly my problem and talk to someone +way more experienced than I, someone designated for that, was my way out of this torment, so value your mentors! Thanks Bruno!

+
+
+

This Week’s Goals#

+

Now, with the FBO working, I plan to finally render something to it. For this week, I plan to come back to my original plan and +experiment with simple shaders just as a proof of concept that the FBO will be really useful for this project. I hope the road is less +bumpier by now and I don’t step on any other complicated problem.

+

Wish me luck!

+
+
+ + + +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2023/2023-06-27-week-4-tvcastillod.html b/v0.10.x/posts/2023/2023-06-27-week-4-tvcastillod.html new file mode 100644 index 000000000..ca11e09f9 --- /dev/null +++ b/v0.10.x/posts/2023/2023-06-27-week-4-tvcastillod.html @@ -0,0 +1,540 @@ + + + + + + + + Week 4: First draft of the DTI uncertainty visualization — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Week 4: First draft of the DTI uncertainty visualization#

+
+

What did I do this week?#

+

#PR 810: DTI uncertainty visualization

+

I made a second PR with the implementation of DTI uncertainty calculation and visualization. Below is an image of diffusion tensor ellipsoids and their associated uncertainty cones.

+https://user-images.githubusercontent.com/31288525/254747296-09a8674e-bfc0-4b3f-820f-8a1b1ad8c5c9.png +

I had to use some dipy functions, specifically: estimate_sigma for the noise variance calculation, design_matrix to get the b-matrix, and tensor_prediction for the signal estimation. The details of this calculations can be found here.

+
+
+

What is coming up next?#

+

I will continue working on the uncertainty PR which is still in its early stage, I’m going to make a couple of adjustments to the description of the parameters and the actor, and keep working on based on the feedback I receive. There are also minor details to be discussed with my mentors about the first PR, which I hope to finish refining.

+
+
+

Did I get stuck anywhere?#

+

It took me a while to make the PR because I had some problems with the uncertainty function definition. I tried to use the least amount of parameters for the function, since with data, bvals and bvecs it is possible to obtain the rest of the parameters needed to generate the cones, which led me to readjust some calculations from the base implementation I had, to keep everything working correctly.

+
+
+ +
+ + + + + + + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2023/2023-07-01-week-5-praneeth.html b/v0.10.x/posts/2023/2023-07-01-week-5-praneeth.html new file mode 100644 index 000000000..2845aa4ec --- /dev/null +++ b/v0.10.x/posts/2023/2023-07-01-week-5-praneeth.html @@ -0,0 +1,544 @@ + + + + + + + + Week 5: Trying out PRs and Planning Ahead — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Week 5: Trying out PRs and Planning Ahead#

+
+

What did you do this week?#

+

Due to ongoing exams, my productivity was limited this week. However, I managed to find some time to explore and review a few PRs submitted by contributors:

+
    +
  1. Ellipsoid PR #791: +This PR focuses on creating a new ellipsoid actor defined with SDF and raymarching techniques.

  2. +
  3. Website Improvement PR #812: +This PR includes changes for the new compatibility section on the FURY home page.

  4. +
+

Towards the end of the week, I had a meeting with my mentor. We discussed the current status of ongoing PRs and identified action points to focus on in the upcoming weeks. This discussion provided clarity on the challenges faced with certain PRs and issues.

+
+
+

Did you get stuck anywhere?#

+

Fortunately, I didn’t encounter any major roadblocks or challenges that hindered my progress this week.

+
+
+

What is coming up next?#

+

With the action points provided by my mentor, I will be dedicating the next week to completing those tasks.

+
+
+ +
+ + + + + + + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2023/2023-07-03-week-5-joaodellagli.html b/v0.10.x/posts/2023/2023-07-03-week-5-joaodellagli.html new file mode 100644 index 000000000..7c8b7f17d --- /dev/null +++ b/v0.10.x/posts/2023/2023-07-03-week-5-joaodellagli.html @@ -0,0 +1,582 @@ + + + + + + + + Week 5: All Roads Lead to Rome — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Week 5: All Roads Lead to Rome#

+

Hello everyone, time for another weekly blogpost! Today, we will talk about taking different paths to reach your objective.

+
+

Last Week’s Effort#

+

After having the FBO properly set up, the plan was to finally render something to it. Well, I wished for a less bumpy road +at my last blogpost but as in this project things apparently tend to go wrong, +of course the same happened with this step.

+
+
+

Where the Problem Was#

+

Days passed without anything being rendered to the FBO. The setup I was working on followed the simplest OpenGL pipeline of rendering to +an FBO:

+
    +
  1. Setup the FBO

  2. +
  3. Attach a texture to it’s color attachment

  4. +
  5. Setup the shader to be used in the FBO render and the shader to render the FBO’s Color Attachment

  6. +
  7. Render to the FBO

  8. +
  9. Use the color attachment as texture attached to a billboard to render what was on the screen

  10. +
+

But it seems like this pipeline doesn’t translate well into VTK. I paired again on wednesday with my mentors, Bruno and Filipi, to try to figure out +where the problem was, but after hours we could not find it. Wednesday passed and then thursday came, and with thursday, a solution: +Bruno didn’t give up on the idea and dug deep on VTK’s documentation until he found a workaround to do what we wanted, that was retrieving a +texture from what was rendered to the screen and pass it as a texture to render to the billboard. To do it, he figured out we needed to use +a different class, vtkWindowToImageFilter, a class that has the specific +job of doing exactly what I described above. Below, the steps to do it:

+
windowToImageFilter = vtk.vtkWindowToImageFilter()
+windowToImageFilter.SetInput(scene.GetRenderWindow())
+windowToImageFilter.Update()
+
+texture = vtk.vtkTexture()
+texture.SetInputConnection(windowToImageFilter.GetOutputPort())
+
+# Bind the framebuffer texture to the desired actor
+actor.SetTexture(texture)
+
+
+

This is enough to bind to the desired actor a texture that corresponds to what was prior rendered to the screen.

+
+
+

This Week’s Goals#

+

Having a solution to that, now its time to finally render some KDE’s! This week’s plans involve implementing the first version of a KDE +calculation. For anyone interested in understanding what a Kernel Density Estimation is, here is a brief summary from this +Wikipedia page:

+
+

In statistics, kernel density estimation (KDE) is the application of kernel smoothing for probability density estimation, i.e., a +non-parametric method to estimate the probability density function of a random variable based on kernels as weights. KDE answers a +fundamental data smoothing problem where inferences about the population are made, based on a finite data sample. In some fields +such as signal processing and econometrics it is also termed the Parzen–Rosenblatt window method, after Emanuel Parzen and Murray +Rosenblatt, who are usually credited with independently creating it in its current form. One of the famous applications of +kernel density estimation is in estimating the class-conditional marginal densities of data when using a naive Bayes classifier, +which can improve its prediction accuracy.

+
+

This complicated sentence can be translated into the below image:

+KDE plot of 100 random points +

That is what a KDE plot of 100 random points looks like. The greener the area, the greater the density of points. The plan is to implement +something like that with the tools we now have available.

+

Let’s get to work!

+
+
+ + + +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2023/2023-07-03-week-5-tvcastillod.html b/v0.10.x/posts/2023/2023-07-03-week-5-tvcastillod.html new file mode 100644 index 000000000..e746c0cad --- /dev/null +++ b/v0.10.x/posts/2023/2023-07-03-week-5-tvcastillod.html @@ -0,0 +1,537 @@ + + + + + + + + Week 5: Preparing the data for the Ellipsoid tutorial — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Week 5: Preparing the data for the Ellipsoid tutorial#

+
+

What did I do this week?#

+

During the weekly meeting with my mentors, there was a small discussion over the naming of the actor and its usage. On the one hand, although the purpose of the actor is to visualize diffusion tensor ellipsoids, the idea is that it can also be used for any other type of visualization that requires the use of ellipsoids, so in the end, we decided to keep the name ellipsoid as it is more generic. On the other hand, as there is already an actor made for the purpose of tensor visualization, namely tensor_slicer, it might not be obvious how and why one would use this new ellipsoid actor for this purpose, thus it was proposed to make a tutorial that can clarify this. The main difference between both actors relies on the quality and the amount of data that can be displayed, so the idea is to show the difference between both alternatives so the user can choose which one to use depending on their needs. To prepare the tutorial the first step was to add the data I will use on fury-data so I can then fetch and load the datasets I need to work on the tutorial.

+
+
+

What is coming up next?#

+

I need #PR 791 to be reviewed by my GSoC fellows at FURY, so I will address their comments, and additionally make adjustments on #PR 810 based on the feedback I receive. I will also start working on the tutorial, the idea is to show the use that can be made of the ellipsoid actor in the visualization of diffusion tensor ellipsoids, compared to the tensor_slicer actor. I plan to create a WIP PR to start getting feedback on the general structure of the tutorial and the way everything will be explained.

+
+
+

Did I get stuck anywhere?#

+

I did not encounter any obstacles this week.

+
+
+ +
+ + + + + + + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2023/2023-07-08-week-6-praneeth.html b/v0.10.x/posts/2023/2023-07-08-week-6-praneeth.html new file mode 100644 index 000000000..b441a1d8c --- /dev/null +++ b/v0.10.x/posts/2023/2023-07-08-week-6-praneeth.html @@ -0,0 +1,539 @@ + + + + + + + + Week 6: BoundingBox for TextBlock2D! — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Week 6: BoundingBox for TextBlock2D!#

+
+

What did you do this week?#

+

This week, I worked on improving the TextBlock2D component in the UI system. I started from scratch to address alignment and scaling issues. When resizing the TextBlock2D, the text alignment and justification with the background rectangle were inconsistent. To resolve this, I introduced a new “boundingbox” property that calculates the text bounding box based on its content. Additionally, I separated the scaling mode from the resizing action with the new “auto_font_scale” property, enabling automatic font scaling according to the bounding box. This will provide better alignment, justified text, and smoother font scaling for the TextBlock2D component. Try it out at PR #803.

+TextBlock2D will different justifications +

As discussed last week, we also made a decision regarding the scrollbar. After exploring different use cases, we concluded that creating an independent scrollbar is not necessary at the moment. Therefore, we will close the related pull requests. You can find out more about it in the discussion here.

+
+
+

Did you get stuck anywhere?#

+

Implementing the bounding box feature took some extra time as I needed to carefully consider its impact on other UI elements that rely on the TextBlock2D component.

+
+
+

What is coming up next?#

+

Next, I will focus on completing the TextBlock2D Bounding Box PR, which will also indirectly finalize the Spinbox PR.

+
+
+ + + +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2023/2023-07-10-week-6-joaodellagli.html b/v0.10.x/posts/2023/2023-07-10-week-6-joaodellagli.html new file mode 100644 index 000000000..5bfea9f4f --- /dev/null +++ b/v0.10.x/posts/2023/2023-07-10-week-6-joaodellagli.html @@ -0,0 +1,569 @@ + + + + + + + + Week 6: Things are Starting to Build Up — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Week 6: Things are Starting to Build Up#

+

Hello everyone, time for a other weekly blogpost! Today, I will show you my current progress on my project and latest activities.

+
+

What I did Last Week#

+

Last week I had the goal to implement KDE rendering to the screen (if you want to understand what this is, check my :doc:`last blogpost <2023-07-03-week-5-joaodellagli>`_). +After some days diving into the code, I finally managed to do it:

+KDE render to a billboard +

This render may seem clean and working, but the code isn’t exactly like that. For this to work, some tricks and work arounds needed to +be done, as I will describe in the section below.

+

Also, I reviewed the shader part of Tania’s PR #791, that implement ellipsoid actors inside +FURY. It was my first review of a PR that isn’t a blogpost, so it was an interesting experience and I hope I can get better at it.

+

It is important as well to point out that I had to dedicate myself to finishing my graduation capstone project’s presentation that I will attend +to this week, so I had limited time to polish my code, which I plan to do better this week.

+
+
+

Where the Problem Was#

+

The KDE render basically works rendering the KDE of a point to a texture and summing that texture to the next render. For this to work, +the texture, rendered to a billboard, needs to be the same size of the screen, otherwise the captured texture will include the black background. +The problem I faced with that is that the billboard scaling isn’t exactly well defined, so I had to guess for a fixed screen size +(in this example, I worked with 600x600) what scaling value made the billboard fit exactly inside the screen (it’s 3.4). That is far from ideal as I +will need to modularize this behavior inside a function that needs to work for every case, so I will need to figure out a way to fix that +for every screen size. For that, I have two options:

+
    +
  1. Find the scaling factor function that makes the billboard fit into any screen size.

  2. +
  3. Figure out how the scaling works inside the billboard actor to understand if it needs to be refactored.

  4. +
+

The first seems ok to do, but it is kind of a work around as well. The second one is a good general solution, but it is a more delicate one, +as it deals with how the billboard works and already existing applications of it may suffer problems if the scaling is changed. +I will see what is better talking with my mentors.

+

Another problem I faced (that is already fixed) relied on shaders. I didn’t fully understood how shaders work inside FURY so I was +using my own fragment shader implementation, replacing the already existing one completely. That was working, but I was having an issue +with the texture coordinates of the rendering texture. As I completely replaced the fragment shader, I had to pass custom texture coordinates +to it, resulting in distorted textures that ruined the calculations. Those issues motivated me to learn the shaders API, which allowed me +to use the right texture coordinates and finally render the results you see above.

+
+
+

This Week’s Goals#

+

For this week, I plan to try a different approach Filipi, one of my mentors, told me to do. This approach was supposed to be the original +one, but a communication failure lead to this path I am currently in. This approach renders each KDE calculation into its own billboard, +and those are rendered together with additive blending. After this first pass, this render is captured into a texture and then rendered to +another big billboard.

+

Also, I plan to refactor my draft PR #804 to make it more understandable, as its description still dates back to the time I was using the +flawed Framebuffer implementation, and my fellow GSoC contributors will eventually review it, and to do so, they will need to understand it.

+

Wish me luck!

+
+
+ +
+ + + + + + + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2023/2023-07-10-week-6-tvcastillod.html b/v0.10.x/posts/2023/2023-07-10-week-6-tvcastillod.html new file mode 100644 index 000000000..ae291a235 --- /dev/null +++ b/v0.10.x/posts/2023/2023-07-10-week-6-tvcastillod.html @@ -0,0 +1,539 @@ + + + + + + + + Week 6: First draft of the Ellipsoid tutorial — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Week 6: First draft of the Ellipsoid tutorial#

+
+

What did I do this week?#

+

#PR 818: Tutorial on using ellipsoid actor to visualize tensor ellipsoids for DTI

+

I created the PR for the tutorial that will show the use that can be made of the ellipsoid actor in the visualization of diffusion tensor ellipsoids. It is still in its most basic stage, but the structure that I have thought of for now consists of: displaying a slice using tensor_slicer with spheres of 100, 200, and 724 vertices, and using ellipsoid actor, and show a comparison of the visual quality of the tensor ellipsoids. Then, display a ROI using both actors and a whole brain using the ellipsoid actor, to show that this new actor gives the possibility to display more data.

+

I also submitted the uncertainty PR for review, in order to start making the necessary corrections.

+
+
+

What is coming up next?#

+

I need #PR 791 to be merged first, but meanwhile, I will start working on the explanation of the tutorial, since I already have the code structure and the idea of what I want to illustrate. I will discuss further work with my mentors at the upcoming meeting, so I can organize myself better and plan how I’m going to address the pending parts of my project.

+
+
+

Did I get stuck anywhere?#

+

I found no major difficulties this week.

+
+
+ +
+ + + + + + + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2023/2023-07-15-week-7-praneeth.html b/v0.10.x/posts/2023/2023-07-15-week-7-praneeth.html new file mode 100644 index 000000000..d3df31e97 --- /dev/null +++ b/v0.10.x/posts/2023/2023-07-15-week-7-praneeth.html @@ -0,0 +1,543 @@ + + + + + + + + Week 7: Sowing the seeds for TreeUI — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Week 7: Sowing the seeds for TreeUI#

+
+

What did you do this week?#

+

This week, I focused on completing the TextBlock2D Bounding Box feature. However, the tests were failing due to automatic background resizing based on content and improper text actor alignment during setup. I encountered difficulties while positioning the text, which caused the text to appear offset and led to test failures.

+

Text background greater than the actual maximum size:

+Text background greater than the actual maximum size in ComboBox2D +

Text offset from center:

+Text offset from center in RingSlider2D +

Additionally, I reviewed PR #814 and noticed that after PR #769, all demos and examples were merged into a single folder, which affected the paths used in the Scientific Domain Section. To address this, I created PR #820 to redirect the links to the correct path.

+

As I faced issues with the TextBlock2D PR, I took the opportunity to rebase and continue working on the TreeUI PR since there were no updates from the author.

+
+
+

Did you get stuck anywhere?#

+

While fixing the issues with the tests for the TextBlock2D bounding box, I encountered a weird behavior in text positioning when using the center alignment. The output varied depending on the sequence of repositioning which we are still investigating.

+
+
+

What is coming up next?#

+

I will continue working on the TreeUI and resolve the TextBlock2D error to ensure both PRs progress smoothly.

+
+
+ + + +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2023/2023-07-17-week-7-joaodellagli.html b/v0.10.x/posts/2023/2023-07-17-week-7-joaodellagli.html new file mode 100644 index 000000000..5d3d734b9 --- /dev/null +++ b/v0.10.x/posts/2023/2023-07-17-week-7-joaodellagli.html @@ -0,0 +1,573 @@ + + + + + + + + Week 7: Experimentation Done — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Week 7: Experimentation Done#

+

Hello everyone, welcome to another weekly blogpost! Let’s talk about the current status of my project (spoiler: it is beautiful).

+
+

Last Week’s Effort#

+

Having accomplished a KDE rendering to a billboard last week, I was then tasked with trying a different approach to how the +rendering was done. So, to recap, below was how I was doing it:

+
    +
  1. Render one point’s KDE offscreen to a single billboard, passing its position and sigma to the fragment shader as uniforms.

  2. +
  3. Capture the last rendering’s screen as a texture.

  4. +
  5. Render the next point’s KDE, and sum it up with the last rendering’s texture.

  6. +
  7. Do this until the end of the points.

  8. +
  9. Capture the final render screen as a texture.

  10. +
  11. Apply post processing effects (colormapping).

  12. +
  13. Render the result to the screen.

  14. +
+

This approach was good, but it had some later limitations and issues that would probably take more processing time and attention to details (correct matrix +transformations, etc) than the ideal. The different idea is pretty similar, but with some differences:

+
    +
  1. Activate additive blending in OpenGL.

  2. +
  3. Render each point’s KDE to its own billboard, with position defined by the point’s position, all together in one pass.

  4. +
  5. Capture the rendered screen as a texture.

  6. +
  7. Pass this texture to a billboard.

  8. +
  9. Apply post processing effects (colormapping).

  10. +
  11. Render the result to the screen.

  12. +
+

So I needed to basically do that.

+
+
+

Was it Hard?#

+

Fortunately, it wasn’t so hard to do it in the end. Following those steps turned out pretty smooth, and after some days, +I had the below result:

+Final 2D KDE render +

This is a 2D KDE render of random 1000 points. For this I used the “viridis” colormap from matplotlib. Some details worth noting:

+
    +
  • For this to work, I have implemented three texture helper functions: window_to_texture(), texture_to_actor() and colormap_to_texture(). The first one captures a window and pass it as a texture to an actor, the second one passes an imported texture to an actor, and the last one passes a colormap, prior passed as an array, as a texture to an actor.

  • +
  • The colormap is directly get from matplotlib, available in its colormaps object.

  • +
  • This was only a 2D flatten plot. At first, I could not figure out how to make the connection between the offscreen interactor and the onscreen one, so rotating and moving around the render was not happening. After some ponder and talk to my mentors, they told me to use callback functions inside the interactor, and after doing that, I managed to make the 3D render work, which had the following result:

  • +
+3D KDE render +

After those results, I refactored my PR #804 to better fit its current status, and it is +now ready for review. Success!

+
+
+

This Week’s Goals#

+

After finishing the first iteration of my experimental program, the next step is to work on an API for KDE rendering. I plan to meet +with my mentors and talk about the details of this API, so expect an update next week. Also, I plan to take a better look on my fellow GSoC FURY +contributors work so when their PRs are ready for review, I will have to be better prepared for it.

+

Let’s get to work!

+
+
+ + + +
+ + + +
+ +
+
+
+ +
+ + + +
+ +
+ +
+ On this page +
+ +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2023/2023-07-17-week-7-tvcastillod.html b/v0.10.x/posts/2023/2023-07-17-week-7-tvcastillod.html new file mode 100644 index 000000000..3c1a1f462 --- /dev/null +++ b/v0.10.x/posts/2023/2023-07-17-week-7-tvcastillod.html @@ -0,0 +1,538 @@ + + + + + + + + Week 7: Adjustments on the Uncertainty Cones visualization — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Week 7: Adjustments on the Uncertainty Cones visualization#

+
+

What did I do this week?#

+

I was told to refactor some parts of the uncertainty PR, since I was relying too much on dipy functions which is not good because it makes maintenance more difficult as dipy requires FURY for some functionalities. So I did some adjustments on the uncertainty function parameters and the corresponding tests, hopefully I managed to get with the most appropriate definition but I need to receive a first feedback to see how much I have to adjust the implementation. As I had to delete some relevant code lines inside the uncertainty calculation which consisted of preprocessing the data in order to define the necessary variables for the uncertainty formula, I was also suggested to make a tutorial of this new feature, so I can explain in detail how to obtain and adjust the necessary information, before passing it to the actor, and in general how and what is the purpose of this new function.

+

I also continued working on the ellipsoid tutorial, which I hope to finish this week so that I can ask for a first revision.

+
+
+

What is coming up next?#

+

I will finish defining some details of the tutorial so that it is ready for review, and now I will start working on the tutorial related to the uncertainty, while I receive feedback on the other PRs. Also, as preparation for the next step I will start exploring on how to address visualization of spherical harmonics for ODF glyphs visualization, I found that a previous GSoC participant at FURY started working on that and also did several work with raymarching and SDF (here is a summary of the work), so I will take a deeper look on that to see if I can get something useful I can start with.

+
+
+

Did I get stuck anywhere?#

+

Not this week, but I foresee some problems with the uncertainty PR, we will see how it goes.

+
+
+ +
+ + + + +
+ + + + Previous: + + + + Week 7: Sowing the seeds for TreeUI + + + +   + + + + Next: + + + Week 7: Experimentation Done + + + + +
+ + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2023/2023-07-22-week-8-praneeth.html b/v0.10.x/posts/2023/2023-07-22-week-8-praneeth.html new file mode 100644 index 000000000..1e8e7a03a --- /dev/null +++ b/v0.10.x/posts/2023/2023-07-22-week-8-praneeth.html @@ -0,0 +1,544 @@ + + + + + + + + Week 8: Another week with TextBlockUI — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Week 8: Another week with TextBlockUI#

+
+

What did you do this week?#

+

This week, I delved deeper into the TextBlock2D Bounding Box PR to address the challenges with tests and offsetting issues. In a pair programming session with my mentor, we discovered that the offsetting background problem stemmed from the dynamic nature of the bounding box. The issue arose when the RingSlider2D component began with an initial text size larger than the current text, which changed as the value was adjusted between 0-100%. This resulted in problems with offsetting and shrinking the bounding box. To resolve this, we decided to make the dynamic bounding box an optional feature.

+

Now, the TextBlock2D component offers three main features:

+
    +
  1. Completely static background

  2. +
  3. Dynamic bounding box scaled according to the text

  4. +
  5. Font scaling based on the bounding box

  6. +
+

After tweaking and testing, all the features work seamlessly.

+
+
+

Did you get stuck anywhere?#

+

The pair programming session with my mentor proved to be immensely helpful, as it guided me through the whole week.

+
+
+

What is coming up next?#

+

I will dedicate time to further enhancing the TreeUI. My focus will be on updating tree nodes and ensuring proper node positioning during movement.

+
+
+ +
+ + + + + + + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2023/2023-07-24-week-8-joaodellagli.html b/v0.10.x/posts/2023/2023-07-24-week-8-joaodellagli.html new file mode 100644 index 000000000..1e0cd06d7 --- /dev/null +++ b/v0.10.x/posts/2023/2023-07-24-week-8-joaodellagli.html @@ -0,0 +1,611 @@ + + + + + + + + Week 8: The Birth of a Versatile API — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Week 8: The Birth of a Versatile API#

+

Hello everyone, it’s time for another weekly blogpost! Today, I am going to tell you all about how is the KDE API development going, and +to show you the potential this holds for the future!

+
+

Last Week’s Effort#

+

Last week I told you how I managed to render some KDE renders to the screen, both in 2D and 3D, as you may check by my last blogpost. +My new task was, as I had this example working, to start the API development. In a meeting with Bruno, one of my mentors, we debated +on how could this work, reaching two options:

+
    +
  1. Implement the KDE in a single, simple actor.

  2. +
  3. Implement a KDE rendering manager, as a class.

  4. +
+

The first one would have the advantage of being simple and pretty straightforward, as a user would only need to call the actor and have +it working on their hands, having the tradeoff of leaving some important steps for a clean API hidden and static. These steps I mention +are related to how this rendering works, as I have previously showed you, it relies on post-processing effects, +which need an offscreen rendering, that for example are done by the callback functions.

+

In short, these functions are instructions the user gives to the interactor to run inside the interaction loop. Inside FURY there are tree +types of callbacks passed to the window interactor:

+
    +
  1. Timer Callbacks: Added to the window interactor, they are a set of instructions that will be called from time to time, with interval defined by the user.

  2. +
  3. Window Callbacks: Added directly to the window, they are a set of instructions called whenever an specific event is triggered.

  4. +
  5. Interactor Callbacks: Added to the window interactor, they are a set of instructions called whenever an specific interaction, for example a mouse left-click, is triggered.

  6. +
+

In this API, I will be using the Interactor Callback, set by the window.add_iren_callback() function, that will be called whenever a Render +interaction is detected, and needs to be first passed to the onscreen manager.

+

These details are more complicated, and would need, for example, for the user to pass the onscreen manager to the actor.kde() function. +Also, in the case of a kde actor not being used anymore and being declared, the callback then passed would still exist inside the manager and +be called even when the kde actor is not on screen anymore, which is not ideal.

+

Knowing these problems, we thought of a second option, that would have the advantage of not leaving those details and steps behind. It has +the tradeoff of maybe complicating things as it would need to be called after calling the effects manager, but as I will show you below, +it is not that complicated at all.

+

I also reviewed my fellow GSoC contributors PR’s as well, PR #810 and +#803. Bruno told me to take a look as well on Conventional Commits , a way to standardize +commits by prefixes, so I did that as well.

+
+
+

So how did it go?#

+

Well, the implemented manager class is named EffectManager() and to initialize it you only need to pass the onscreen manager. +The onscreen manager is the standard FURY window manager you would use in a normal FURY-based program:

+
# Onscreen manager setup
+from fury import window
+
+scene = window.Scene()
+
+onscreen_manager = window.ShowManager(scene, "demo", (width, height))
+
+effects = EffectManager(onscreen_manager)
+
+
+

After that, to render a KDE calculation of points to the screen, you need only to call its kde() function:

+
kde_actor = effects.kde(center, points, sigmas, scale = 10.0, colormap = "inferno")
+# Those last two are optional
+
+
+

Pass it to the onscreen manager scene:

+
onscreen_manager.scene.add(kde_actor)
+
+
+

And to start it, as usual:

+
onscreen_manager.start()
+
+
+

As simple as that. This three lines of code output the same result as I showed you last week, this time, with different sigmas for each +point:

+3D KDE render +

After having that working, I experimented beyond. See, as I previously said, we are dealing here with post-processing effects, with KDE +being only one of the many existing ones, as this Wikipedia Page on post processing shows. +Knowing that, I tried one of the first filters I learned, the Laplacian one. This filter is, as its name hints, applying the +Discrete Laplace Operator in an image. This filter shows sudden changes of value, a +good way to detect borders. The process is the same as the kde actor, requiring only the actor you want to apply the filter to. +Below, the result I got from applying that to a box actor:

+Laplacian filter applied to a cube object. +

Something I found important to leave as an option was filter compositing. What if an user wanted to, for example, apply one laplacian filter +after another? Well, the example below shows that is possible as well:

+Double laplacian application on the box actor. +

It still needs some tweaks and suffers from some bugs, but it works! Those represent important progress as it shows the versatility this +API may present. I have also already implemented grayscale and 3x3 gaussian blur as well:

+3x3 Gaussian Blur filter applied to a cube. +Grayscale filter applied to a cube. +
+
+

This Week’s Goals#

+

My plans for this week are to keep working and polishing the API, mainly the KDE part, so it can be ready for a first review. +When that is ready, I plan to experiment with more filters and make this more dynamic, maybe implementing a way to apply custom kernel +transformations, passed by the user, to the rendering process. This has been a really exciting journey and I am getting happy with the results!

+

Wish me luck!

+
+
+ + + +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2023/2023-07-25-week-8-tvcastillod.html b/v0.10.x/posts/2023/2023-07-25-week-8-tvcastillod.html new file mode 100644 index 000000000..d2a30b139 --- /dev/null +++ b/v0.10.x/posts/2023/2023-07-25-week-8-tvcastillod.html @@ -0,0 +1,537 @@ + + + + + + + + Week 8: Working on Ellipsoid Tutorial and exploring SH — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Week 8: Working on Ellipsoid Tutorial and exploring SH#

+
+

What did I do this week?#

+

I mainly worked on the ellipsoid actor tutorial, as PR #791 is finally merged, so I was able to complete the tutorial by adding my implementation. In addition, during the weekly meeting, I received a good overview of the next issue I will be working on, which is using raymarching SDFs to display spherical harmonics (SH) for visualizing ODF glyphs for DTI. I got several ideas and resources which I can start experimenting with, such as Shadertoy and some base implementations from other FURY contributors. The main drawback when creating these objects is the amount of data required to create them, because depending on the SH order, the number of parameters that the function receives may vary, also unlike the tensors, which are represented only with a 3x3 matrix, here we could have more than 9 values associated with a single glyph, so passing the information from python to the shaders is not so trivial, besides requiring more resources as there is more information that needs to be processed. Some ideas I received were using matrixes instead of vectors, using templating, or even using texture to pass the data. I started to explore these options further, as well as to review in more detail the existing implementations of SH with raymarching, in order to understand them better.

+
+
+

What is coming up next?#

+

I currently have two PRs under review, so I will address the comments I receive and update them accordingly. I also will continue to explore and start working on the implementation of these objects so that I can start making adjustments and further discuss possible improvements to the implementation I will make.

+
+
+

Did I get stuck anywhere?#

+

Fortunately, I did not encounter any drawbacks this week.

+
+
+ +
+ + + + + + + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2023/2023-07-29-week-9-praneeth.html b/v0.10.x/posts/2023/2023-07-29-week-9-praneeth.html new file mode 100644 index 000000000..fe159596f --- /dev/null +++ b/v0.10.x/posts/2023/2023-07-29-week-9-praneeth.html @@ -0,0 +1,539 @@ + + + + + + + + Week 9: TextBlock2D is Finally Merged! — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Week 9: TextBlock2D is Finally Merged!#

+
+

What did you do this week?#

+

Continuing from the previous week, it seemed like we were almost done with the TextBlock2D, but there remained a final task of addressing conflicting issues. Being a core part of the UI, TextBlock2D had a few compatibility problems with certain other UI elements.

+

The default behavior of TextBox2D now includes a dynamic bounding box, which scales automatically based on the contained text. Users can customize this option through a simple flag setting. However, this change affected some UI elements like Combobox2d, which relied on the default textbox size. Consequently, I had to make updates to ensure compatibility. Additionally, the default initialization of the TextBlock2D was completely static, which led to the possibility of the text extending beyond the background and failing certain tests. To tackle this, I made adjustments to the overflow helper function in the test_elements.py file. After a few tweaks and issue resolutions, the PR was ready for review and was successfully merged after passing the review process.

+TextBlock2D with different attributes +
+
+

Did you get stuck anywhere?#

+

I encountered some peculiar test failures that were indirectly related to the TextBlock2D which at first glance didn’t came up. Although after some debugging and a thorough line-by-line analysis, I managed to identify and resolve them.

+
+
+

What is coming up next?#

+

My next priority will be completing the SpinBoxUI now that the TextBlock2D is fixed and successfully integrated.

+
+
+ +
+ + + + + + + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2023/2023-07-31-week-9-joaodellagli.html b/v0.10.x/posts/2023/2023-07-31-week-9-joaodellagli.html new file mode 100644 index 000000000..a0e5e0e39 --- /dev/null +++ b/v0.10.x/posts/2023/2023-07-31-week-9-joaodellagli.html @@ -0,0 +1,614 @@ + + + + + + + + Week 9: It is Polishing Time! — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Week 9: It is Polishing Time!#

+

Hello everyone, it’s time for another weekly blogpost! Today, I am going to update you on my project’s latest changes.

+
+

Last Week’s Effort#

+

After having finished a first draft of the API that will be used for the KDE rendering, and showing how it could be used +for other post-processing effects, my goal was to clean the code and try some details that would add to it so it could be better +complete. Having that in mind, I invested in three work fronts:

+
    +
  1. Fixing some bugs related to the rendering more than one post-processing effect actor.

  2. +
  3. Experimenting with other rendering kernels (I was using the gaussian one only).

  4. +
  5. Completing the KDE render by renormalizing the values in relation to the number of points (one of the core KDE details).

  6. +
+

Both three turned out more complicated than it initially seemed, as I will show below.

+
+
+

So how did it go?#

+

The first one I did on monday-tuesday, and I had to deal with some issues regarding scaling and repositioning. Due to implementation +choices, the final post-processed effects were rendered either bigger than they were in reality, or out of their original place. +After some time dedicated to finding the root of the problems, I could fix the scaling issue, however I realised I would need to, +probably, rethink the way the API was implemented. As this general post-processing effects is a side-project that comes as a consequence of +my main one, I decided to leave that investment to another time, as I would need to guarantee the quality of the second.

+

The second was an easy and rather interesting part of my week, as I just needed to setup new kernel shaders. Based on +scikit-learn KDE documentation, I could successfully implement the following kernels:

+
    +
  • Gaussian

  • +
+
+\[K(x, y) = e^{\frac{-(x^2 + y^2)}{2\sigma^2}}\]
+
    +
  • Tophat

  • +
+
+\[K(x, y) = 1.0, \ \ |x^2 + y^2| < \sigma\]
+
    +
  • Epanechnikov

  • +
+
+\[K(x, y) = 1 - \frac{x^2 + y^2}{\sigma^2}\]
+
    +
  • Exponential

  • +
+
+\[K(x, y) = e^{\frac{-|x^2 + y^2|}{\sigma}}\]
+
    +
  • Linear

  • +
+
+\[K(x, y) = 1 - \frac{|x^2 + y^2|}{\sigma}, \ \ |x^2 + y^2| < \sigma\]
+
    +
  • Cosine

  • +
+
+\[K(x, y) = cos(\frac{\pi|x^2 + y^2|}{2\sigma})\]
+

That outputted the following (beautiful) results for a set of 1000 random points with random sigmas:

+Different kernel approaches +

The third one is still being a trickier challenge. If you recall from my first blogposts, I spent something around one month trying to setup +float framebuffer objects to FURY with VTK so I could use them in my project. After spending all of that time with no results, +me and Bruno, my mentor, found a way to do what we wanted to do, but using a different VTK class, +vtkWindowToImageFilter. Well, it was a good workaround back then and +it lead me all the way here, however now it is costing a price. The float framebuffers were an important part of the project because they +would allow us to pass 32-bit float information from one shader to another, which would be important as they would allow the densities to +have higher precision and more fidelity to the calculations. When rendering a KDE of a given set of points, we use the below function:

+
+\[KDE(x, y) = \frac{1}{n} \sum_{i = 0}^n K(x, y)\]
+

If the number of points \(n\) is big enough, some KDE results will be really low. This presents a real problem to our implementation because, without +the float framebuffers, it is currently only being possible to pass 8-bit unsigned char information, that only allows 256 values. +This is far from ideal, as low values would have alone densities low enough to disappear. This presented a problem as to renormalize the +densities, I was retrieving the texture to the CPU, calculating its minimum and maximum values, and passing to the fragment shader as uniforms +for the renormalization, which didn’t work if the maximum values calculated were zero.

+

One solution I thought to solve that was a really heavy workaround: if an unsigned float is 32-bit and I have exactly 4 8-bit +unsigned chars, why not try to pack this float into these 4 chars? Well, this is an interesting approach which I figured out is already an +old one, being reported in GPU Gems’s chapter 12. +Unfortunately I haven’t tried yet this implementation yet, and went for one I thought myself, which haven’t exactly worked. I also tried +this implementation from Aras Pranckevičius’ website, which seems +to be working, even though not perfectly:

+Noisy float to RGBA encoding +

As you can see, this implementation is really noisy. I think this has to deal with floating point rounding errors, so to try to mitigate +that, I experimented applying a 13x13 gaussian blur to it. Below, what I got from that:

+Blurred KDE result +

That looks way better, even though not ideal yet.

+
+
+

This Week’s Goals#

+

Talking with my mentors, we decided it was better if I focused on the version without the renormalization for now, as it was already +done and running fine. So for this week, I plan to clean my PR to finally have it ready for a first review, and maybe add to it a little +UI tool to control the intensity of the densities. That should take me some time and discussion, but I hope for it to be ready by the +end of the week.

+

Let’s get to work!

+
+
+ +
+ + + + + + + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2023/2023-07-31-week-9-tvcastillod.html b/v0.10.x/posts/2023/2023-07-31-week-9-tvcastillod.html new file mode 100644 index 000000000..2728b498d --- /dev/null +++ b/v0.10.x/posts/2023/2023-07-31-week-9-tvcastillod.html @@ -0,0 +1,538 @@ + + + + + + + + Week 9: Tutorial done and polishing DTI uncertainty — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Week 9: Tutorial done and polishing DTI uncertainty#

+
+

What did I do this week?#

+

I addressed the comments from the tutorial of PR #818 related to how to display specific visualizations I wanted to make. I was suggested to use ShowManager to handle the zoom of the scene and also to use GridUI to display several actors at the same time for a visual quality comparison of the tensors. Below are some images generated for the tutorial that is almost done.

+https://user-images.githubusercontent.com/31288525/260906510-d422e7b4-3ba3-4de6-bfd0-09c04bec8876.png +
+
+

What is coming up next?#

+

There are some issues with the tests of the uncertainty implementation, specifically a segmentation problem that has to be with the shaders, so I expect to correct the problem by next week.

+
+
+

Did I get stuck anywhere?#

+

I’m still thinking about how to approach the implementation of the spherical harmonics for ODF glyphs. Most of the implementations I have found are static so my task would be to try to parametrize the existing functions, so I can pass data from Python to the shaders properly so that I can obtain the same result as the current odf_slicer.

+
+
+ +
+ + + + +
+ + + + Previous: + + + + Week 9: It is Polishing Time! + + + +   + + + + Next: + + + Week 10: Its time for a Spin-Box! + + + + +
+ + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2023/2023-08-05-week-10-praneeth.html b/v0.10.x/posts/2023/2023-08-05-week-10-praneeth.html new file mode 100644 index 000000000..377dd023c --- /dev/null +++ b/v0.10.x/posts/2023/2023-08-05-week-10-praneeth.html @@ -0,0 +1,538 @@ + + + + + + + + Week 10: Its time for a Spin-Box! — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Week 10: Its time for a Spin-Box!#

+
+

What did you do this week?#

+

This week, my focus shifted to the SpinBoxUI after wrapping up work on TextBlock2D. SpinBoxUI is a component that allows users to select a value by spinning through a range. To ensure a smooth transition, I made adjustments in SpinBoxUI to align it with the recent updates in TextBlock2D. To make things even clearer and more user-friendly, I initiated a continuous code improvement process. I introduced setters and getters that enable easier customization of TextBlock2D’s new features, such as auto_font_scale and dynamic_bbox. These tools simplify the process of adjusting these settings, and you can see the ongoing changes in pull request #830.

+

Simultaneously, I worked on improving the FileDialog component. Since the FileDialog PR was based on an older version, it required updates to match the recent developments in TextBlock2D. This involved restructuring the code and making sure that everything worked smoothly together. You can checkout the progress here at PR #832.

+
+
+

Did you get stuck anywhere?#

+

Thankfully, this week was quite smooth sailing without any major roadblocks.

+
+
+

What is coming up next?#

+

Looking ahead, my plan is to finalize the integration of the updated TextBlock and SpinBoxUI components. This entails making sure that everything works seamlessly together and is ready for the next stages of development.

+
+
+ +
+ + + + + + + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2023/2023-08-07-week-10-joaodellagli.html b/v0.10.x/posts/2023/2023-08-07-week-10-joaodellagli.html new file mode 100644 index 000000000..e7ac8f69f --- /dev/null +++ b/v0.10.x/posts/2023/2023-08-07-week-10-joaodellagli.html @@ -0,0 +1,549 @@ + + + + + + + + Week 10: Ready for Review! — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Week 10: Ready for Review!#

+

Hello everyone, it’s time for another weekly blogpost!

+
+

Last Week’s Effort#

+

After talking with my mentors, I was tasked with getting my API PR #826 ready for review, +as it still needed some polishing, and the most important of all, it needed its tests working, as this was something I haven’t invested time since its creation. +Having that in mind, I have spent the whole week cleaning whatever needed, writing the tests, and also writing a simple example of its +usage. I also tried implementing a little piece of UI so the user could control the intensity of the bandwidth of the KDE render, but +I had a little problem I will talk about below.

+
+
+

So how did it go?#

+

Fortunately, for the cleaning part, I didn’t have any trouble, and my PR is finally ready for review! The most complicated part was to write the tests, as this is something that +requires attention to understand what needs to be tested, exactly. As for the UI part, I managed to have a slider working for the +intensity, however, it was crashing the whole program for a reason, so I decided to leave this idea behind for now. +Below, an example of how this should work:

+Buggy slider for the intensity control of the bandwidth of the KDE +
+
+

This Week’s Goals#

+

After a meeting with my mentors, we decided that this week’s focus should be on finding a good usage example of the KDE rendering feature, +to have it as a showcase of the capability of this API. Also, they hinted me some changes that need to be done regarding the API, so I +will also invest some time on refactoring it.

+

Wish me luck!

+
+
+ +
+ + + + + + + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2023/2023-08-08-week-10-tvcastillod.html b/v0.10.x/posts/2023/2023-08-08-week-10-tvcastillod.html new file mode 100644 index 000000000..b7c8f51c9 --- /dev/null +++ b/v0.10.x/posts/2023/2023-08-08-week-10-tvcastillod.html @@ -0,0 +1,540 @@ + + + + + + + + Week 10 : Start of SH implementation experiments — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Week 10 : Start of SH implementation experiments#

+
+

What did I do this week?#

+

I started formally working on SH implementation. I was told to start first doing a simple program where I can modify in real-time the order \(l\) and degree \(m\), parameters corresponding to the Spherical Harmonics function \(Y^m_l(\theta,\phi)=\), based on previous work. That is just one part of the final ODF calculation, but here is what a first experimental script looks like.

+https://user-images.githubusercontent.com/31288525/260910073-10b0edd4-40e3-495c-85ad-79993aef3b19.png +

I did it in order to make sure it was visually correct and also to understand better how those 2 parameters are related and need to be incorporated into the final calculation. There is one issue at first sight that needs to be addressed, and that is the scaling, since for SH with a degree near 0, the object gets out of bounds.

+
+
+

What is coming up next?#

+

I will keep polishing details from my current open PRs, hopefully, I will get another PR merged before the last GSoC week.

+
+
+

Did I get stuck anywhere?#

+

Not sure about how to use the current implementation I have to get similar visualizations made with odf_slicer, since the parameters that the function receive are different, so I need to take a deeper look and see where it might be the connection or if I should make some adjustments on the parameters.

+
+
+ +
+ + + + +
+ + + + Previous: + + + + Week 10: Ready for Review! + + + +   + + + + Next: + + + Week 11: Bye Bye SpinBox + + + + +
+ + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2023/2023-08-12-week-11-praneeth.html b/v0.10.x/posts/2023/2023-08-12-week-11-praneeth.html new file mode 100644 index 000000000..2fece2c8a --- /dev/null +++ b/v0.10.x/posts/2023/2023-08-12-week-11-praneeth.html @@ -0,0 +1,543 @@ + + + + + + + + Week 11: Bye Bye SpinBox — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Week 11: Bye Bye SpinBox#

+
+

What did you do this week?#

+

Building upon the progress of the previous week, a major milestone was reached with the merging of PR #830. This PR added essential “getters” and “setters” for the new features of TextBlock, making it easier to handle changes. This, in turn, facilitated the integration of SpinBoxUI with the updated TextBlock.

+

However, while working on SpinBoxUI, a critical issue emerged. As SpinBoxUI allows users to input characters and symbols into an editable textbox, it posed a risk of program crashes due to invalid inputs. To counter this, I introduced a validation check to ensure that the input was a valid number. If valid, the input was converted; otherwise, it reverted to the previous value. After thorough testing and review, PR #499 was successfully merged.

+SpinBoxUI +

Meanwhile, a concern with the textbox’s behavior was identified when SpinBoxUI was scaled to a larger size. Specifically, the text occasionally touched the top or bottom boundary, creating an overflow appearance. Although initial solutions were attempted, the complexity of the issue required further consideration. This issue has been documented in more detail in Issue #838, where it is marked as a low-priority item.

+
+TextBlock2D text positioning issue +
+
+
+

Did you get stuck anywhere?#

+

The challenge of the week centered around addressing the textbox’s overflow behavior in SpinBoxUI.

+
+
+

What is coming up next?#

+

Looking ahead, the focus remains on refining the FileDialog component, as the significant progress with TextBlock and SpinBoxUI prepares us to shift attention to other aspects of development.

+
+
+ +
+ + + + + + + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2023/2023-08-14-week-11-joaodellagli.html b/v0.10.x/posts/2023/2023-08-14-week-11-joaodellagli.html new file mode 100644 index 000000000..4c8c89bee --- /dev/null +++ b/v0.10.x/posts/2023/2023-08-14-week-11-joaodellagli.html @@ -0,0 +1,590 @@ + + + + + + + + Week 11: A Refactor is Sometimes Needed — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Week 11: A Refactor is Sometimes Needed#

+

Hello everyone, it’s time for another weekly blogpost! Today I am going to share some updates on the API refactoring +I was working on with my mentors.

+
+

Last Week’s Effort#

+

As I shared with you last week, the first draft of my API was finally ready for review, as +I finished tweaking some remaining details missing. I was tasked with finding a good example of the usage of the tools we proposed, +and I started to do that, however after testing it with some examples, I figured out some significant bugs were to be fixed. Also, +after some reviews and hints from some of my mentors and other GSoC contributors, we realised that some refactoring should be done, +mainly focused on avoiding bad API usage from the user.

+
+
+

So how did it go?#

+

Initially, I thought only one bug was the source of the issues the rendering presented, but it turned out to be two, which I will +explain further.

+

The first bug was related to scaling and misalignment of the KDE render. The render of the points being post-processed was not only +with sizes different from the original set size, but it was also misaligned, making it appear in positions different from the points’ +original ones. After some time spent, I figured out the bug was related to the texture coordinates I was using. Before, this is how +my fragment shader looked:

+
vec2 res_factor = vec2(res.y/res.x, 1.0);
+vec2 tex_coords = res_factor*normalizedVertexMCVSOutput.xy*0.5 + 0.5;
+float intensity = texture(screenTexture, tex_coords).r;
+
+
+

It turns out using this texture coordinates for this case was not the best choice, as even though it matches the fragment positions, +the idea here was to render the offscreen window, which has the same size as the onscreen one, to the billboard actor. With that in mind, +I realised the best choice was using texture coordinates that matched the whole screen positions, coordinates that were derived from the +gl_FragCoord.xy, being the division of that by the resolution of the screen, for normalization. Below, the change made:

+
vec2 tex_coords = gl_FragCoord.xy/res;
+float intensity = texture(screenTexture, tex_coords).r;
+
+
+

This change worked initially, although with some problems, that later revealed the resolution of the offscreen window needed to be +updated inside the callback function as well. Fixing that, it was perfectly aligned and scaled!

+

The second bug was related with the handling of the bandwidth, former sigma parameter. I realised I wasn’t dealing properly with the option of the user passing only +one single bandwidth value being passed, so when trying that, only the first point was being rendered. I also fixed that and it worked, +so cheers!

+

As I previously said, the bugs were not the only details I spent my time on last week. Being reviewed, the API design, even +though simple, showed itself vulnerable to bad usage from the user side, requiring some changes. The changes suggested by mentors were, +to, basically, take the kde method out of the EffectManager class, and create a new class from it inside an effects module, +like it was a special effects class. With this change, the KDE setup would go from:

+
em = EffectManager(show_manager)
+
+kde_actor = em.kde(...)
+
+show_manager.scene.add(kde_actor)
+
+
+

To:

+
em = EffectManager(show_manager)
+
+kde_effect = KDE(...)
+
+em.add(kde_effect)
+
+
+

Not a gain in line shortening, however, a gain in security, as preventing users from misusing the kde_actor. Something worth noting is +that I learned how to use the functools.partial function, that allowed me to partially call the callback function with only some +parameters passed.

+
+
+

This Week’s Goals#

+

Having that refactoring made, now I am awaiting for a second review so we could finally wrap it up and merge the first stage of this API. +With that being done, I will write the final report and wrap this all up.

+

Let’s get to work!

+
+
+ + + +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2023/2023-08-16-week-11-tvcastillod.html b/v0.10.x/posts/2023/2023-08-16-week-11-tvcastillod.html new file mode 100644 index 000000000..f1b9e40db --- /dev/null +++ b/v0.10.x/posts/2023/2023-08-16-week-11-tvcastillod.html @@ -0,0 +1,545 @@ + + + + + + + + Week 11 : Adjusting ODF implementation and looking for solutions on issues found — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Week 11 : Adjusting ODF implementation and looking for solutions on issues found#

+
+

What did I do this week?#

+

I continued to experiment with the ODF glyph implementation. Thanks to one of my mentors I figured out how to get the missing data corresponding to the SH coefficients \(a^l_m\) part of the function \(f(\theta, \phi)\) described here. I also was told to make sure to implement the correct SH basis since there are different definitions from the literature, I have to focus now in the one proposed by Descoteaux, described in this paper, which is labeled in dipy as descoteaux07. To do this I had to make a small adjustment to the base implementation that I took as a reference, from which I obtained a first result using SH of order 4.

+https://user-images.githubusercontent.com/31288525/260909561-fd90033c-018a-465b-bd16-3586bb31ca36.png +

It appears that the results on the shape are about the same, except for the direction, but there is still work to be done.

+
+
+

What is coming up next?#

+

For now, there are 3 things I will continue to work on:

+
    +
  • The color and lighting. As these objects present curvatures with quite a bit of detail in some cases, this is something that requires more specific lighting work, in addition to having now not only one color but a color map.

  • +
  • The scaling. This is something I still don’t know how to deal with. I had to adjust it manually for now, but the idea is to find a relationship between the coefficients and the final object size so it can be automatically scaled, or maybe there is a proper way to pre-process this data before passing it to the shaders to get the right result at once.

  • +
  • How to pass the information of the coefficients efficiently. Right now I’m creating one actor per glyph since I’m using a uniform array to pass the coefficients, but the idea is to pass all the data at once. I found several ideas here of how to pass a list of values to the fragment shader directly, I just need to explore deeper how this can be done on FURY, and see which option is most suitable.

  • +
+
+
+

Did I get stuck anywhere?#

+

All the points mentioned above are things that I tried to fix, however, it is something that I need to look at in much more detail and that I know is going to take me some time to understand and test before I get to the expected result. I hope to get some ideas from my mentors and fellow GSoC contributors on how I can proceed to deal with each of the problems.

+
+
+ +
+ + + + + + + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2023/2023-08-19-week-12-praneeth.html b/v0.10.x/posts/2023/2023-08-19-week-12-praneeth.html new file mode 100644 index 000000000..3d487032a --- /dev/null +++ b/v0.10.x/posts/2023/2023-08-19-week-12-praneeth.html @@ -0,0 +1,552 @@ + + + + + + + + Week 12: FileDialog Quest Begins! — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Week 12: FileDialog Quest Begins!#

+
+

What did you do this week?#

+

During this week, I initiated my work on the FileDialog PR, which had been started by Soham. The initial version of the FileDialog can be found at #294. To start, I focused on rebasing the PR. Since this PR was based on an older version, there were some updates to the overall UI structure that needed to be addressed for compatibility. While handling this, I identified a set of issues that I documented in the current PR #832. These mainly revolved around:

+
    +
  1. Resizing FileDialog and related components.

  2. +
  3. Rectifying the text overflow problem.

  4. +
  5. Dealing with a ZeroDivisionError.

  6. +
  7. Fixing the positioning of items in the ListBox2D.

  8. +
+

I systematically approached each of these challenges:

+

Resizing FileMenu and Related Components: This was a fairly complex task since it involved intricate dependencies, such as the FileDialog relying on the FileMenu, which, in turn, was dependent on ListBox2D and Panel2D resizing. To make the process manageable, I decided to progress incrementally in a separate PR a bit later.

+

Text Overflow Issue: The problem with text overflow was rooted in our previous approach, which involved executing these actions only when the TextBlock2D had a scene property. Although this approach suited the previous version of TextBlock2D, the recent refactoring led to the removal of this property. The scene was previously utilized to determine the text actor’s size. However, we had new methodologies to calculate these sizes, which are detailed in #803.

+Text Overflow Before +Text Overflow After +

Addressing ZeroDivisionError: The ZeroDivisionError emerged when the total number of values was the same as the number of slots. The issue lay in the separation of these values for calculating the scrollbar’s height parameter. Unfortunately, this calculation error occurred when this would return us zero while updating the scrollbar. To counter this, I implemented a conditional check to ascertain whether the value is zero or not.

+

Correcting ``ListBox2D`` Item Positioning: Another challenge I encountered related to the improper positioning of ListBox2D item’s background. When a slot was not visible, its background was resized to zero, and visibility was set to off. Consequently, during the calculation of updated positions, the height was considered zero, leading to mispositioning. I resolved this by refraining from resizing and solely toggling visibility, achieving the desired result.

+ListBox2D mispositioning Before +Fixed ListBox2D mispositioning +
+
+

Did you get stuck anywhere?#

+

Among the challenges I faced, one notable instance involved addressing the visibility issue in TreeUI. Despite my attempts at various solutions, none yielded the desired outcome. The TreeUI exhibited either full visibility or no visibility at all. In this situation, I sought guidance from my mentor to find a viable solution.

+
+
+

What is coming up next?#

+

The FileDialog implementation is nearly finalized, and my plan is to work on any review, feedback or suggestions that might arise. Following this, I will shift my attention towards addressing the TreeUI.

+
+
+ + + +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2023/2023-08-21-joaodellagli-final-report.html b/v0.10.x/posts/2023/2023-08-21-joaodellagli-final-report.html new file mode 100644 index 000000000..e9d118818 --- /dev/null +++ b/v0.10.x/posts/2023/2023-08-21-joaodellagli-final-report.html @@ -0,0 +1,816 @@ + + + + + + + + Google Summer of Code Final Work Product — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +https://developers.google.com/open-source/gsoc/resources/downloads/GSoC-logo-horizontal.svg +https://www.python.org/static/img/python-logo@2x.png +https://python-gsoc.org/logos/fury_logo.png +
+

Google Summer of Code Final Work Product#

+ +
+

Abstract#

+

This project had the goal to implement 3D Kernel Density Estimation rendering to FURY. Kernel Density Estimation, or KDE, is a +statistical method that uses kernel smoothing for modeling and estimating the density distribution of a set of points defined +inside a given region. For its graphical implementation, it was used post-processing techniques such as offscreen rendering to +framebuffers and colormap post-processing as tools to achieve the desired results. This was completed with a functional basic KDE +rendering result, that relies on a solid and easy-to-use API, as well as some additional features.

+
+
+

Proposed Objectives#

+
    +
  • +
    First PhaseImplement framebuffer usage in FURY
      +
    • Investigate the usage of float framebuffers inside FURY’s environment.

    • +
    • Implement a float framebuffer API.

    • +
    +
    +
    +
  • +
  • +
    Second PhaseShader-framebuffer integration
      +
    • Implement a shader that uses a colormap to render framebuffers.

    • +
    • Escalate this rendering for composing multiple framebuffers.

    • +
    +
    +
    +
  • +
  • +
    Third PhaseKDE Calculations
      +
    • Investigate KDE calculation for point-cloud datasets.

    • +
    • Implement KDE calculation inside the framebuffer rendering shaders.

    • +
    • Test KDE for multiple datasets.

    • +
    +
    +
    +
  • +
+
+
+

Objectives Completed#

+
    +
  • +
    Implement framebuffer usage in FURY

    The first phase, addressed from May/29 to July/07, started with the investigation of +VTK’s Framebuffer Object, a vital part of this project, to understand +how to use it properly.

    +

    Framebuffer Objects, abbreviated as FBOs, are the key to post-processing effects in OpenGL, as they are used to render things offscreen and save the resulting image to a texture +that will be later used to apply the desired post-processing effects within the object’s fragment shader +rendered to screen, in this case, a billboard. In the case of the +Kernel Density Estimation post-processing effect, we need a special kind of FBO, one that stores textures’ +values as floats, different from the standard 8-bit unsigned int storage. This is necessary because the KDE rendering involves rendering every KDE point calculation +to separate billboards, rendered to the same scene, which will have their intensities, divided by the number of points rendered, blended with +OpenGL Additive Blending, and if a relative big number of points are rendered at the +same time, 32-bit float precision is needed to guarantee that small-intensity values will not be capped to zero, and disappear.

    +

    After a month going through VTK’s FBO documentation and weeks spent trying different approaches to this method, it would not work +properly, as some details seemed to be missing from the documentation, and asking the community haven’t solved the problem as well. +Reporting that to my mentors, which unsuccessfully tried themselves to make it work, they decided it was better if another path was taken, using +VTK’s WindowToImageFilter method as a workaround, described +in this blogpost. This method helped the development of +three new functions to FURY, window_to_texture(), texture_to_actor() and colormap_to_texture(), that allow the passing of +different kinds of textures to FURY’s actor’s shaders, the first one to capture a window and pass it as a texture to an actor, +the second one to pass an external texture to an actor, and the third one to specifically pass a colormap as a texture to an +actor. It is important to say that WindowToImageFilter() is not the ideal way to make it work, as this method does not seem to +support float textures. However, a workaround to that is currently being worked on, as I will describe later on.

    +

    Pull Requests:

    + +

    The result of this whole FBO and WindowToImageFilter experimentation is well documented in PR +#804 that implements an experimental version of a KDE rendering program. +The future of this PR, as discussed with my mentors, is to be better documented to be used as an example for developers on +how to develop features in FURY with the tools used, and it shall be done soon.

    +
    +
    +
  • +
  • +
    Shader-framebuffer integration

    The second phase, which initially was thought of as “Implement a shader that uses a colormap to render framebuffers” and “Escalate this +rendering for composing multiple framebuffers” was actually a pretty simple phase that could be addressed in one week, July/10 +to July/17, done at the same time as the third phase goal, documented in this +blogpost. As FURY already had a tool for generating and +using colormaps, they were simply connected to the shader part of the program as textures, with the functions explained above. +Below, is the result of the matplotlib viridis colormap passed to a simple gaussian KDE render:

    +Final 2D plot +

    That is also included in PR #804. Having the 2D plot ready, some time was taken to +figure out how to enable a 3D render, that includes rotation and other movement around the set rendered, which was solved by +learning about the callback properties that exist inside VTK. Callbacks are ways to enable code execution inside the VTK rendering +loop, enclosed inside vtkRenderWindowInteractor.start(). If it is desired to add a piece of code that, for example, passes a time +variable to the fragment shader over time, a callback function can be declared:

    +
    from fury import window
    +t = 0
    +showm = window.ShowManager(...)
    +
    +def callback_function:
    +    t += 0.01
    +    pass_shader_uniforms_to_fs(t, "t")
    +
    +showm.add_iren_callback(callback_function, "RenderEvent")
    +
    +
    +

    The piece of code above created a function that updates the time variable t in every “RenderEvent”, and passes it to the +fragment shader. With that property, the camera and some other parameters could be updated, which enabled 3D visualization, that +then, outputted the following result, using matplotlib inferno colormap:

    +3D Render gif +
    +
    +
  • +
  • +
    KDE Calculations (ongoing)

    As said before, the second and third phases were done simultaneously, so after having a way to capture the window and use it as a +texture ready, the colormap ready, and an initial KDE render ready, all it was needed to do was to improve the KDE calculations. +As this Wikipedia page explains, a KDE calculation is to estimate an +abstract density around a set of points defined inside a given region with a kernel, that is a function that models the density +around a point based on its associated distribution \(\sigma\).

    +

    A well-known kernel is, for example, the Gaussian Kernel, that says that the density around a point \(p\) with distribution +\(\sigma\) is defined as:

    +
    +\[GK_{\textbf{p}, \sigma} (\textbf{x}) = e^{-\frac{1}{2}\frac{||\textbf{x} - \textbf{p}||^2}{\sigma^2}}\]
    +

    Using that kernel, we can calculate the KDE of a set of points \(P\) with associated distributions \(S\) calculating their individual +Gaussian distributions, summing them up and dividing them by the total number of points \(n\):

    +
    +\[KDE(A, S)=\frac{1}{n}\sum_{i = 0}^{n}GK(x, p_{i}, \sigma_{i})\]
    +

    So I dove into implementing all of that into the offscreen rendering part, and that is when the lack of a float framebuffer would +charge its cost. As it can be seen above, just calculating each point’s density isn’t the whole part, as I also need to divide +everyone by the total number of points \(n\), and then sum them all. The problem is that, if the number of points its big enough, +the individual densities will be really low, and that would not be a problem for a 32-bit precision float framebuffer, but that is +definitely a problem for a 8-bit integer framebuffer, as small enough values will simply underflow and disappear. That issue is +currently under investigation, and some solutions have already being presented, as I will show in the Objectives in Progress +section.

    +

    Apart from that, after having the experimental program ready, I focused on modularizing it into a functional and simple API +(without the \(n\) division for now), and I could get a good set of results from that. The API I first developed implemented the +EffectManager class, responsible for managing all of the behind-the-scenes steps necessary for the kde render to work, +encapsulated inside the ÈffectManager.kde() method. It had the following look:

    +

    Those straightforward instructions, that hid several lines of code and setup, could manage to output the following result:

    +API 3D KDE plot +

    And this was not the only feature I had implemented for this API, as the use of WindowToImageFilter method opened doors for a +whole new world for FURY: The world of post-processing effects. With this features setup, I managed to implement a gaussian blur +effect, a grayscale effect and a Laplacian effect for calculating “borders”:

    +Gaussian Blur effect +Grayscale effect +Laplacian effect +

    As this wasn’t the initial goal of the project and I still had several issues to deal with, I have decided to leave these features as a +future addition.

    +

    Talking with my mentors, we realized that the first KDE API, even though simple, could lead to bad usage from users, as the +em.kde() method, that outputted a FURY actor, had dependencies different from any other object of its kind, making it a new +class of actors, which could lead to confusion and bad handling. After some pair programming sessions, they instructed me to take +a similar, but different road from what I was doing, turning the kde actor into a new class, the KDE class. This class would +have almost the same set of instructions present in the prior method, but it would break them in a way it would only be completely +set up after being passed to the EffectManager via its add function. Below, how the refactoring handles it:

    +
    from fury.effects import EffectManager, KDE
    +from fury import window
    +
    +showm = window.ShowManager(...)
    +
    +# KDE rendering setup
    +em = EffectManager(showm)
    +kde_effect = KDE(...)
    +em.add(kde_effect)
    +# End of KDE rendering setup
    +
    +showm.start()
    +
    +
    +

    Which outputted the same results as shown above. It may have cost some simplicity as we are now one line farther from having it +working, but it is more explicit in telling the user this is not just a normal actor.

    +

    Another detail I worked on was the kernel variety. The Gaussian Kernel isn’t the only one available to model density distributions, +there are several others that can do that job, as it can be seen in this scikit-learn piece of documentation +and this Wikipedia page on kernels. Based on the scikit-learn KDE +implementation, I worked on implementing the following kernels inside our API, that can be chosen as a parameter when calling the +KDE class:

    +
      +
    • Cosine

    • +
    • Epanechnikov

    • +
    • Exponential

    • +
    • Gaussian

    • +
    • Linear

    • +
    • Tophat

    • +
    +

    Below, the comparison between them using the same set of points and bandwidths:

    +Comparison between the six implemented kernels +

    Pull Requests:

    +
      +
    • First Stage of the KDE Rendering API (will be merged soon): fury-gl/fury#826

    • +
    +

    All of this work culminated in PR #826, that proposes to add the first stage of +this API (there are some details yet to be completed, like the \(n\) division) to FURY. This PR added the described API, and also +proposed some minor changes to some already existing FURY functions related to callbacks, changes necessary for this and other +future applications that would use it to work. It also added the six kernels described, and a simple documented example on how +to use this feature.

    +
    +
    +
  • +
+
+
+

Other Objectives#

+
    +
  • +
    Stretch GoalsSDE Implementation, Network/Graph visualization using SDE/KDE, Tutorials
      +
    • Investigate SDE calculation for surface datasets.

    • +
    • Implement SDE calculation inside the framebuffer rendering shaders.

    • +
    • Test SDE for multiple datasets.

    • +
    • Develop comprehensive tutorials that explain SDE concepts and FURY API usage.

    • +
    • Create practical, scenario-based tutorials using real datasets and/or simulations.

    • +
    +
    +
    +
  • +
+
+
+

Objectives in Progress#

+
    +
  • +
    KDE Calculations (ongoing)

    The KDE rendering, even though almost complete, have the $n$ division, an important step, missing, as this normalization allows colormaps +to cover the whole range o values rendered. The lack of a float FBO made a big difference in the project, as the search for a functional implementation of it not only delayed the project, but it is vital for +the correct calculations to work.

    +

    For the last part, a workaround thought was to try an approach I later figured out is an old one, as it can be check in +GPU Gems 12.3.3 section: +If I need 32-bit float precision and I got 4 8-bit integer precision available, why not trying to pack this float into this RGBA +texture? I have first tried to do one myself, but it didn’t work for some reason, so I tried Aras Pranckevičius +implementation, that does the following:

    +
    vec4 float_to_rgba(float value) {
    +    vec4 bitEnc = vec4(1.,256.,65536.0,16777216.0);
    +    vec4 enc = bitEnc * value;
    +    enc = fract(enc);
    +    enc -= enc.yzww * vec2(1./255., 0.).xxxy;
    +    return enc;
    +}
    +
    +
    +

    That initially worked, but for some reason I am still trying to understand, it is resulting in a really noisy texture:

    +Noisy KDE render +

    One way to try to mitigate that while is to pass this by a gaussian blur filter, to try to smooth out the result:

    +Blurred result +

    But it is not an ideal solution as well, as it may lead to distortions in the actual density values, depending on the application of +the KDE. Now, my goal is to first find the root of the noise problem, and then, if that does not work, try to make the gaussian filter +work.

    +

    Another detail that would be a good addition to the API is UI controls. Filipi, one of my mentors, told me it would be a good feature +if the user could control the intensities of the bandwidths for a better structural visualization of the render, and knowing FURY already +have a good set of UI elements, I just needed to integrate +that into my program via callbacks. I tried implementing an intensity slider. However, for some reason, it is making the program crash +randomly, for reasons I still don’t know, so that is another issue under investigation. Below, we show a first version of that feature, +which was working before the crashes:

    +Slider for bandwidths +

    Pull Requests

    + +
    +
    +
  • +
+
+
+

GSoC Weekly Blogs#

+ +
+
+

Timeline#

+
+
+ +
+ + + + + + + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2023/2023-08-21-week-12-joaodellagli.html b/v0.10.x/posts/2023/2023-08-21-week-12-joaodellagli.html new file mode 100644 index 000000000..8c85c7fb7 --- /dev/null +++ b/v0.10.x/posts/2023/2023-08-21-week-12-joaodellagli.html @@ -0,0 +1,553 @@ + + + + + + + + Week 12: Now That is (almost) a Wrap! — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Week 12: Now That is (almost) a Wrap!#

+

Hello everyone, it’s time for another GSoC blogpost! Today, I am going to talk about some minor details I worked on last week on my +project.

+
+

Last Week’s Effort#

+

After the API refactoring was done last week, I focused on addressing the reviews I would get from it. The first issues I addressed was related to +style, as there were some minor details my GSoC contributors pointed out that needed change. Also, I have addressed an issue I was having +with the typed hint of one of my functions. Filipi, my mentor, showed me there is a way to have more than one typed hint in the same parameter, +all I needed to do was to use the Union class from the typing module, as shown below:

+
from typing import Union as tUnion
+from numpy import ndarray
+
+def function(variable : tUnion(float, np.ndarray)):
+   pass
+
+
+

Using that, I could set the typedhint of the bandwidth variable to float and np.ndarray.

+
+
+

So how did it go?#

+

All went fine with no difficult at all, thankfully.

+
+
+

The Next Steps#

+

My next plans are, after having PR #826 merged, to work on the float encoding issue described in +this blogpost. Also, I plan to tackle the UI idea once again, to see if I can finally give the user +a way to control the intensities of the distributions.

+

Wish me luck!

+
+
+ +
+ + + + + + + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ +
+ +
+ On this page +
+ +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2023/2023-08-24-final-report-tvcastillod.html b/v0.10.x/posts/2023/2023-08-24-final-report-tvcastillod.html new file mode 100644 index 000000000..d4d3a0a0c --- /dev/null +++ b/v0.10.x/posts/2023/2023-08-24-final-report-tvcastillod.html @@ -0,0 +1,744 @@ + + + + + + + + Google Summer of Code Final Work Product — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +https://developers.google.com/open-source/gsoc/resources/downloads/GSoC-logo-horizontal.svg +https://www.python.org/static/community_logos/python-logo.png +https://python-gsoc.org/logos/FURY.png +
+

Google Summer of Code Final Work Product#

+ +
+

Abstract#

+

Diffusion Magnetic Resonance Imaging (dMRI) is a non-invasive imaging technique used by neuroscientists to measure the diffusion of water molecules in biological tissue. The directional information is reconstructed using either a Diffusion Tensor Imaging (DTI) or High Angular Resolution Diffusion Imaging (HARDI) based model, which is graphically represented as tensors and Orientation Distribution Functions (ODF). Traditional rendering engines discretize Tensor and ODF surfaces using triangles or quadrilateral polygons, making their visual quality depending on the number of polygons used to build the 3D mesh, which might compromise real-time display performance. This project proposes a methodological approach to further improve the visualization of DTI tensors and HARDI ODFs glyphs by using well-established techniques in the field of computer graphics, such as geometry amplification, billboarding, signed distance functions (SDFs), and ray marching.

+
+
+

Proposed Objectives#

+
    +
  • Implement a parallelized version of computer-generated billboards using geometry shaders for amplification.

  • +
  • Model the mathematical functions that express the geometry of ellipsoid glyphs and implement them using Ray Marching techniques.

  • +
  • Model the mathematical functions that express the geometry of ODF glyphs and implement them using Ray Marching techniques.

  • +
  • Use SDF properties and techniques to represent the uncertainty of dMRI reconstruction models.

  • +
+
+
+

Objectives Completed#

+
+

Ellipsoid actor implemented with SDF#

+

A first approach for tensor glyph generation has been made, using ray marching and SDF applied to a box. The current implementation (tensor_slicer) requires a sphere with a specific number of vertices to be deformed. Based on this model, a sphere with more vertices is needed to get a higher resolution. Because the ray marching technique does not use polygonal meshes, it is possible to define perfectly smooth surfaces and still obtain a fast rendering.

+

Details of the implementation:

+
    +
  • Vertex shader pre-calculations: Some minor calculations are done in the vertex shader. One, corresponding to the eigenvalues constraining and min-max normalization, are to avoid incorrect visualizations when the difference between the eigenvalues is too large. And the other is related to the tensor matrix calculation given by the diffusion tensor definition \(T = R^{−1}\Lambda R\), where \(R\) is a rotation matrix that transforms the standard basis onto the eigenvector basis, and \(\Lambda\) is the diagonal matrix of eigenvalues [4].

  • +
  • Ellipsoid SDF definition: The definition of the SDF is done in the fragment shader inside the map function, which is used later for the ray marching algorithm and the normals calculation. We define the SDF more simply by transforming a sphere into an ellipsoid, considering that the SDF of a sphere is easily computed and the definition of a tensor gives us a linear transformation of a given geometry. Also, as scaling is not a rigid body transformation, we multiply the final result by a factor to compensate for the difference, which gave us the SDF of the ellipsoid defined as sdSphere(tensorMatrix * (position - centerMCVSOutput), scaleVSOutput*0.48) * scFactor.

  • +
  • Ray marching algorithm and lighting: For the ray marching algorithm, a small value of 20 was taken as the maximum distance since we apply the technique to each individual object and not all at the same time. Additionally, we set the convergence precision to 0.001. We use the central differences method to compute the normals necessary for the scene’s illumination, besides the Blinn-Phong lighting technique, which is high-quality and computationally cheap.

  • +
  • Visualization example: Below is a detailed visualization of the ellipsoids created from this new implementation.

  • +
+https://user-images.githubusercontent.com/31288525/244503195-a626718f-4a13-4275-a2b7-6773823e553c.png +

This implementation does show a better quality in the displayed glyphs, and supports the display of a large amount of data, as seen in the image below. For this reason, a tutorial was made to justify in more detail the value of this new implementation. Below are some images generated for the tutorial.

+https://user-images.githubusercontent.com/31288525/260906510-d422e7b4-3ba3-4de6-bfd0-09c04bec8876.png +

Pull Requests:

+
    +
  • Ellipsoid actor implemented with SDF (Merged) fury-gl/fury#791

  • +
  • Tutorial on using ellipsoid actor to visualize tensor ellipsoids for DTI (Merged) fury-gl/fury#818

  • +
+

Future work: In line with one of the initial objectives, it is expected to implement billboards later on to improve the performance, i.e., higher frame rate and less memory usage for the tensor ellipsoid creation. In addition to looking for ways to optimize the naive ray marching algorithm and the definition of SDFs.

+
+
+
+

Objectives in Progress#

+
+

DTI uncertainty visualization#

+

The DTI visualization pipeline is fairly complex, as a level of uncertainty arises, which, if visualized, helps to assess the model’s accuracy. This measure is not currently implemented, and even though there are several methods to calculate and visualize the uncertainty in the DTI model, because of its simplicity and visual representation, we considered Matrix Perturbation Analysis (MPA) proposed by Basser [1]. This measurement is visualized as double cones representing the variance of the main direction of diffusion, for which the ray marching technique was also used to create these objects.

+

Details of the implementation:

+
    +
  • Source of uncertainty: The method of MPA arises from the susceptibility of DTI to dMRI noise present in diffusion-weighted images (DWIs), and also because the model is inherently statistical, making the tensor estimation and other derived quantities to be random variables [1]. For this reason, this method focus on the premise that image noise produces a random perturbation in the diffusion tensor estimation, and therefore in the calculation of eigenvalues and eigenvectors, particularly in the first eigenvector associated with the main diffusion direction.

  • +
  • Mathematical equation: The description of the perturbation of the principal eigenvector is given by math formula where \(\Delta D\) corresponds to the estimated perturbation matrix of \(D\) given by the diagonal elements of the covariance matrix \(\Sigma_{\alpha} \approx (B^T\Sigma^{−1}_{e}B)^{−1}\), where \(\Sigma_{e}\) is the covariance matrix of the error e, defined as a diagonal matrix made with the diagonal elements of \((\Sigma^{−1}_{e}) = ⟨S(b)⟩^2 / \sigma^{2}_{\eta}\). Then, to get the angle \(\theta\) between the perturbed principal eigenvector of \(D\), \(\varepsilon_1 + \Delta\varepsilon_1\), and the estimated eigenvector \(\varepsilon_1\), it can be approximated by \(\theta = \tan^{−1}( \| \Delta\varepsilon_1 \|)\) [2]. Taking into account the above, we define the function main_dir_uncertainty(evals, evecs, signal, sigma, b_matrix) that calculates the uncertainty of the eigenvector associated to the main direction of diffusion.

  • +
  • Double cone SDF definition: The final SDF is composed by the union of 2 separately cones using the definition taken from this list of distance functions, in this way we have the SDF for the double cone defined as opUnion(sdCone(p,a,h), sdCone(-p,a,h)) * scaleVSOutput

  • +
  • Visualization example: Below is a demo of how this new feature is intended to be used, an image of diffusion tensor ellipsoids and their associated uncertainty cones.

  • +
+https://user-images.githubusercontent.com/31288525/254747296-09a8674e-bfc0-4b3f-820f-8a1b1ad8c5c9.png +

The implementation is almost complete, but as it is a new addition that includes mathematical calculations and for which there is no direct reference for comparison, it requires a more detail review before it can be incorporated.

+

Pull Request:

+ +

Future work: A tutorial will be made explaining in more detail how to calculate the parameters needed for the uncertainty cones using dipy functions, specifically: estimate_sigma for the noise variance calculation, design_matrix to get the b-matrix, and tensor_prediction for the signal estimation. Additionally, when the ODF implementation is complete, uncertainty for this other reconstruction model is expected to be added, using semitransparent glyphs representing the mean directional information proposed by Tournier [3].

+
+
+

ODF actor implemented with SDF#

+

HARDI-based techniques require more images than DTI, however, they model the diffusion directions as probability distribution functions (PDFs), and the fitted values are returned as orientation distribution functions (ODFs). ODFs are more diffusion sensitive than the diffusion tensor and, therefore, can determine the structure of multi-directional voxels very common in the white matter regions of the brain [3]. The current actor to display this kind of glyphs is the odf_slicer which, given an array of spherical harmonics (SH) coefficients renders a grid of ODFs, which are created from a sphere with a specific number of vertices that fit the data.

+

For the application of this model using the same SDF ray marching techniques, we need the data of the SH coefficients, which are used to calculate the orientation distribution function (ODF) described here. Different SH bases can be used, but for this first approach we focus on descoteaux07 (as labeled in dipy). After performing the necessary calculations, we obtain an approximate result of the current implementation of FURY, as seen below.

+https://user-images.githubusercontent.com/31288525/260909561-fd90033c-018a-465b-bd16-3586bb31ca36.png +

With a first implementation we start to solve some issues related to direction, color, and data handling, to obtain exactly the same results as the current implementation.

+

Details on the issues:

+
    +
  • The direction and the scaling: When the shape of the ODF is more sphere-like, the size of the glyph is smaller, so for the moment it needs to be adjusted manually, but the idea is to find a relationship between the coefficients and the final object size so it can be automatically scaled. Additionally, as seen in the image, the direction does not match. To fix this, an adjustment in the calculation of the spherical coordinates can be made, or pass the direction information directly.

  • +
  • Pass the coefficients data efficiently: I’m currently creating one actor per glyph since I’m using a uniform array to pass the coefficients, but the idea is to pass all the data simultaneously. The first idea is to encode the coefficients data through a texture and retrieve them in the fragment shader.

  • +
  • The colormapping and the lighting: As these objects present curvatures with quite a bit of detail in some cases, this requires more specific lighting work, in addition to having now not only one color but a color map. This can also be done with texture, but it is necessary to see in more detail how to adjust the texture to the glyph’s shape.

  • +
+

More details on current progress can be seen in blogpost of week 11 and week 12.

+

Working branch:

+ +
+
+
+

GSoC Weekly Blogs#

+ +
+
+

Timeline#

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Date

Description

Blog Post Link

Week 0(02-06-2022)

Community Bounding Period

FURY - Python

Week 1(05-06-2022)

Ellipsoid actor implemented with SDF

FURY - Python

Week 2(12-06-2022)

Making adjustments to the Ellipsoid Actor

FURY - Python

Week 3(19-06-2022)

Working on uncertainty and details of the first PR

FURY - Python

Week 4(27-06-2022)

First draft of the DTI uncertainty visualization

FURY - Python

Week 5(03-07-2022)

Preparing the data for the Ellipsoid tutorial

FURY - Python

Week 6(10-07-2022)

First draft of the Ellipsoid tutorial

FURY - Python

Week 7(17-07-2022)

Adjustments on the Uncertainty Cones visualization

FURY - Python

Week 8(25-07-2022)

Working on Ellipsoid Tutorial and exploring SH

FURY - Python

Week 9(31-07-2022)

Tutorial done and polishing DTI uncertainty

FURY - Python

Week 10(08-08-2022)

Start of SH implementation experiments

FURY - Python

Week 11(16-08-2022)

Adjusting ODF implementation and looking for solutions on issues found

FURY - Python

Week 12(24-08-2022)

Experimenting with ODFs implementation

FURY - Python

+
+
+

References#

+ +
+
+ +
+ + + + + + + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2023/2023-08-24-week-12-tvcastillod.html b/v0.10.x/posts/2023/2023-08-24-week-12-tvcastillod.html new file mode 100644 index 000000000..6f8a3f467 --- /dev/null +++ b/v0.10.x/posts/2023/2023-08-24-week-12-tvcastillod.html @@ -0,0 +1,546 @@ + + + + + + + + Week 12 : Experimenting with ODFs implementation — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Week 12 : Experimenting with ODFs implementation#

+
+

What did I do this week?#

+

There were different issues I needed to address for the ODF implementation. Even though I could not solve any of them completely, I did check each of the issues and made some progress. All the work in progress is being recorded in the following branch SH-for-ODF-impl, which when ready will be associated with a well-structured PR.

+

First, about the scaling, I was suggested to check Generalized Fractional Anisotropy gfa metric to adjust the scaling depending on the shape of the ODF glyph, i.e., the less the gfa the more sphere-shaped and smaller, so I had to associate a greater scaling for those. However, this did not work very well as I was unable to define an appropriate scale relation that would give an equitable result for each glyph. For this reason, I opted to use peak values which are extracted from the ODFs, setting the scales as 1/peak_value*0.4 and I got a more uniformly sized glyph without the need of setting it manually. That is a temporal solution as I would like to see better why this happens and if possible do the adjustment inside the shader instead of a precalculation.

+

Second, for the direction, I made a small adjustment to the spherical coordinates which affected the direction of the ODF glyph. As you can see below,

+https://user-images.githubusercontent.com/31288525/263122770-b9ee19d2-d82b-4d7f-a5bb-1cbbf5907049.png +

All the glyphs are aligned over the y-axis but not over the z-axis, to correct this I precalculated the main direction of each glyph using peaks and passed it to the shader as a vec3, then used vec2vecrotmat to align the main axis vector of the ODF to the required direction vector, the only problem with this is that not all the glyps are equally aligned to the axis, i.e., the first 3 glyphs are aligned with the x-axis but the last one is aligned with the y-axis, so the final rotation gives a different result for that one.

+https://user-images.githubusercontent.com/31288525/263122752-b2aa696f-62a5-4b09-b8dd-0cb1ec49431c.png +

As with the first small adjustment of the coordinates the direction was partially correct, I need to double check the theta, phi and r definitions to see if I can get the right direction without the need of the additional data of direction. Also, there might be a way to get the specific rotation angles associated to each individual glyph from the data associated with the ODFs.

+

Third, about passing the coefficients data through textures, I understand better now how to pass textures to the shaders but I still have problems understanding how to retrieve the data inside the shader. I used this base implementation, suggested by one of my mentors, to store the data as a texture cubemap, “a texture, where each mipmap level consists of six 2D images which must be square. The 6 images represent the faces of a cube”. I had 4x15 coefficients and inside the function, a grid of RGB colors is made so then it can be mapped as a texture. To check if was passing the data correctly, I used the same value, .5, for all the textures, so then I could pick a random texel get a specific color (gray), and pass it as fragOutput0 to see if the value was correct. However, it didn’t appear to work correctly as I couldn’t get the expected color. To get the specific color I used texture(sampler, P) which samples texels from the texture bound to sampler at texture coordinate P. Now, what I still need to figure out is which should be the corresponding texture coordinate. I have tried with random coordinates, as they are supposed to correspond to a point on the cube and since the information I have encoded in the texture is all the same, I assumed that I would get the expected result for any set of values. It might be a problem with the data normalization, or maybe there is something failing on the texture definition, but I need to review it in more detail to see where is the problem.

+

Lastly, about the colormapping, I created the texture based on a generic colormap from matplotlib. I was able to give some color to the glyph but it does not match correctly its shape. Some adjustment must be done regarding the texels, as the colormap is mapped on a cube, but I need it to fit the shape of the glyph correctly.

+https://user-images.githubusercontent.com/31288525/263122760-7d1fff5e-7787-473c-8053-ea69f3009fb4.png +
+
+

What is coming up next?#

+

I will continue to explore more on how to handle textures so I can solve the issues related to the coefficient data and colormapping. Also, take a deeper look at the SH implementation and check what is the information needed to adjust the main direction of the ODF correctly.

+
+
+

Did I get stuck anywhere?#

+

As I mentioned I had some drawbacks in understanding the use of textures and how to retrieve the data inside the shaders. This is a topic that might take some time to manage properly but if I can master it and understand it better, it is a tool that can be useful later. Additionally, there are details of the SH implementation that I still need to understand and explore better in order to make sure I get exactly the same result as the current odf_slicer implementation.

+
+
+ +
+ + + + + + + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/posts/2023/2023-08-25-final-report-praneeth.html b/v0.10.x/posts/2023/2023-08-25-final-report-praneeth.html new file mode 100644 index 000000000..efbbe3b7a --- /dev/null +++ b/v0.10.x/posts/2023/2023-08-25-final-report-praneeth.html @@ -0,0 +1,748 @@ + + + + + + + + Google Summer of Code Final Work Product — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +https://developers.google.com/open-source/gsoc/resources/downloads/GSoC-logo-horizontal.svg +https://www.python.org/static/community_logos/python-logo.png +https://python-gsoc.org/logos/FURY.png +
+

Google Summer of Code Final Work Product#

+ +
+

Proposed Objectives#

+
    +
  • SpinBoxUI

  • +
  • Scrollbar as Independent Element

  • +
  • FileDialog

  • +
  • TreeUI

  • +
  • AccordionUI

  • +
  • ColorPickerUI

  • +
  • +
    Stretch Goals:
      +
    • Exploring new UI Framework

    • +
    • Implementing Borders for UI elements

    • +
    +
    +
    +
  • +
+
+
+

Objectives Completed#

+
    +
  • +
    SpinBoxUI:

    The SpinBoxUI element is essential for user interfaces as it allows users to pick a numeric value from a set range. While we had an active pull request (PR) to add this element, updates in the main code caused conflicts and required further changes for added features. At one point, we noticed that text alignment wasn’t centered properly within the box due to a flaw. To fix this, we began a PR to adjust the alignment, but it turned into a larger refactoring of the TextBlock2D, a core component connected to various parts. This was a complex task that needed careful handling. After sorting out the TextBlock2D, we returned to the SpinBoxUI and made a few tweaks. Once we were confident with the changes, the PR was successfully merged after thorough review and testing.

    +

    Pull Requests:

    +
    +
    + +
  • +
  • +
    `TextBlock2D` Refactoring:

    This was a significant aspect of the GSoC period and occupied a substantial portion of the timeline. The process began when we observed misaligned text in the SpinBoxUI, as previously discussed. The root cause of the alignment issue was the mispositioning of the text actor concerning the background actor. The text actor’s independent repositioning based on justification conflicted with the static position of the background actor, leading to the alignment problem.

    +

    To address this, the initial focus was on resolving the justification issue. However, as the work progressed, we recognized that solely adjusting justification would not suffice. The alignment was inherently linked to the UI’s size, which was currently retrieved only when a valid scene was present. This approach lacked scalability and efficiency, as it constrained size retrieval to scene availability.

    +

    To overcome these challenges, we devised a solution involving the creation of a bounding box around the TextBlock2D. This bounding box would encapsulate the size information, enabling proper text alignment. This endeavor spanned several weeks of development, culminating in a finalized solution that underwent rigorous testing before being merged.

    +

    As a result of this refactoring effort, the TextBlock2D now offers three distinct modes:

    +
      +
    1. Fully Static Background: This mode requires background setup during initialization.

    2. +
    3. Dynamic Background: The background dynamically scales based on the text content.

    4. +
    5. Auto Font Scale Mode: The font within the background box automatically scales to fill the available space.

    6. +
    +

    An issue has been identified with TextBlock2D where its text actor aligns with the top boundary of the background actor, especially noticeable with letters like “g,” “y,” and “j”. These letters extend beyond the baseline of standard alphabets, causing the text box to shift upwards.

    +

    However, resolving this matter is complex. Adjusting the text’s position might lead to it touching the bottom boundary, especially in font scale mode, resulting in unexpected positioning and transformations. To address this, the plan is to defer discussions about this matter until after GSoC, allowing for thorough consideration and solutions.

    +

    For more detailed insights into the individual steps and nuances of this process, you can refer to the comprehensive weekly blog post provided below. It delves into the entire journey of this TextBlock2D refactoring effort.

    +

    Pull Requests:

    +
    +
    + +
  • +
  • +
    ScrollbarUI as Independent Element:

    We initially planned to make the scrollbar independent based on PR #16. The main goal was to avoid redundancy by not rewriting the scrollbar code for each element that requires it, such as the FileMenu2D. However, upon further analysis, we realized that elements like the FileMenu2D and others utilize the Listbox2D, which already includes an integrated scrollbar. We also examined other UI libraries and found that they also have independent scrollbars but lack a proper use case. Typically, display containers like Listbox2D are directly used instead of utilizing an independent scrollbar.

    +

    Based on these findings, we have decided to close all related issues and pull requests for now. If the need arises in the future, we can revisit this topic.

    +

    Topic: - fury-gl/fury#816

    +
    +
    +
  • +
+
+
+

Other Objectives#

+
    +
  • +
    Reviewing & Merging:

    In this phase, my focus was not on specific coding but rather on facilitating the completion of ongoing PRs. Here are two instances where I played a role:

    +
      +
    1. CardUI PR: +I assisted with the CardUI PR by aiding in the rebase process and reviewing the changes. The CardUI is a simple UI element consisting of an image and a description, designed to function like a flash card. I worked closely with my mentor to ensure a smooth rebase and review process.

    2. +
    3. ComboBox Issue: +There was an issue with the ComboBox2D functionality, where adding it to a TabUI caused all elements to open simultaneously, which shouldn’t be the case. I tested various PRs addressing this problem and identified a suitable solution. I then helped the lead in reviewing the PR that fixed the issue, which was successfully merged.

    4. +
    +

    Pull Requests:

    +
    +
    + +
  • +
  • +
    Updating Broken Website Links:

    I addressed an issue with malfunctioning links in the Scientific Section of the website. The problem emerged from alterations introduced in PR #769. These changes consolidated demos and examples into a unified “auto_examples” folder, and a toml file was utilized to retrieve this data and construct examples. However, this led to challenges with the paths employed in website generation. My responsibility was to rectify these links, ensuring they accurately direct users to the intended content.

    +

    Pull Requests:

    +
    +
    + +
  • +
+
+
+

Objectives in Progress#

+
    +
  • +
    FileDialogUI:

    An existing FileDialog PR by Soham (#294) was worked upon. The primary task was to rebase the PR to match the current UI structure, resolving compatibility concerns with the older base. In PR #832, we detailed issues encompassing resizing FileDialog and components, addressing text overflow, fixing ZeroDivisionError, and correcting ListBox2D item positioning. The PR is complete with comprehensive testing and documentation. Presently, it’s undergoing review, and upon approval, it will be prepared for integration.

    +

    Pull Requests:

    +
    +
    + +
  • +
  • +
    TreeUI:

    Continuing Antriksh’s initial PR for TreeUI posed some challenges. Antriksh had set the foundation, and I picked up from there. The main issue was with the visibility of TreeUI due to updates in the set_visibility method of Panel2D. These updates affected how TreeUI was displayed, and after investigating the actors involved, it was clear that the visibility features had changed. This took some time to figure out, and I had a helpful pair programming session with my mentor, Serge, to narrow down the problem. Now, I’ve updated the code to address this issue. However, I’m still a bit cautious about potential future problems. The PR is now ready for review.

    +

    Pull Requests:

    +
    +
    + +
  • +
+
+
+

GSoC Weekly Blogs#

+ +
+
+

Timeline#

+ +++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Date

Description

Blog Post Link

Week 0 (27-05-2023)

Community Bounding Period

FURY - Python

Week 1 (03-06-2023)

Working with SpinBox and TextBox Enhancements

FURY - Python

Week 2 (10-06-2023)

Tackling Text Justification and Icon Flaw Issues

FURY - Python

Week 3 (17-06-2023)

Resolving Combobox Icon Flaw and TextBox Justification

FURY - Python

Week 4 (24-06-2023)

Exam Preparations and Reviewing

FURY - Python

Week 5 (01-07-2023)

Trying out PRs and Planning Ahead

FURY - Python

Week 6 (08-07-2023)

BoundingBox for TextBlock2D!

FURY - Python

Week 7 (15-07-2023)

Sowing the seeds for TreeUI

FURY - Python

Week 8 (22-07-2023)

Another week with TextBlockUI

FURY - Python

Week 9 (29-07-2023)

TextBlock2D is Finally Merged!

FURY - Python

Week 10 (05-08-2023)

Its time for a Spin-Box!

FURY - Python

Week 11 (12-08-2023)

Bye Bye SpinBox

FURY - Python

Week 12 (19-08-2023)

FileDialog Quest Begins!

FURY - Python

+
+
+ +
+ + + + +
+ + + + Previous: + + + + Week 12 : Experimenting with ODFs implementation + + + +   + + + +
+ + + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/py-modindex.html b/v0.10.x/py-modindex.html new file mode 100644 index 000000000..e87c5816a --- /dev/null +++ b/v0.10.x/py-modindex.html @@ -0,0 +1,651 @@ + + + + + + + Python Module Index — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ + +

Python Module Index

+ +
+ f +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
 
+ f
+ fury +
    + fury.actor +
    + fury.actors +
    + fury.actors.odf_slicer +
    + fury.actors.peak +
    + fury.actors.tensor +
    + fury.animation +
    + fury.animation.animation +
    + fury.animation.helpers +
    + fury.animation.interpolator +
    + fury.animation.timeline +
    + fury.colormap +
    + fury.convert +
    + fury.data +
    + fury.data.fetcher +
    + fury.decorators +
    + fury.deprecator +
    + fury.gltf +
    + fury.io +
    + fury.layout +
    + fury.lib +
    + fury.material +
    + fury.molecular +
    + fury.pick +
    + fury.pkg_info +
    + fury.primitive +
    + fury.shaders +
    + fury.shaders.base +
    + fury.stream +
    + fury.stream.client +
    + fury.stream.constants +
    + fury.stream.server +
    + fury.stream.server.async_app +
    + fury.stream.server.main +
    + fury.stream.tools +
    + fury.stream.widget +
    + fury.transform +
    + fury.ui +
    + fury.ui.containers +
    + fury.ui.core +
    + fury.ui.elements +
    + fury.ui.helpers +
    + fury.utils +
    + fury.window +
+ + +
+ + + +
+ +
+
+
+ +
+ + + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/reference/fury.actor.html b/v0.10.x/reference/fury.actor.html new file mode 100644 index 000000000..41a5a79c1 --- /dev/null +++ b/v0.10.x/reference/fury.actor.html @@ -0,0 +1,3324 @@ + + + + + + + + actor — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

actor#

+

Module that provide actors to render.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Container([layout])

Provides functionalities for grouping multiple actors using a given layout.

slicer(data[, affine, value_range, opacity, ...])

Cut 3D scalar or rgb volumes into 2D images.

surface(vertices[, faces, colors, smooth, ...])

Generate a surface actor from an array of vertices.

contour_from_roi(data[, affine, color, opacity])

Generate surface actor from a binary ROI.

contour_from_label(data[, affine, color])

Generate surface actor from a labeled Array.

streamtube(lines[, colors, opacity, ...])

Use streamtubes to visualize polylines.

line(lines[, colors, opacity, linewidth, ...])

Create an actor for one or more lines.

scalar_bar([lookup_table, title])

Default scalar bar actor for a given colormap (colorbar).

axes([scale, colorx, colory, colorz, opacity])

Create an actor with the coordinate's system axes where red = x, green = y, blue = z.

odf_slicer(odfs[, affine, mask, sphere, ...])

Create an actor for rendering a grid of ODFs given an array of spherical function (SF) or spherical harmonics (SH) coefficients.

tensor_slicer(evals, evecs[, affine, mask, ...])

Slice many tensors as ellipsoids in native or world coordinates.

peak_slicer(peaks_dirs[, peaks_values, ...])

Visualize peak directions as given from peaks_from_model.

peak(peaks_dirs[, peaks_values, mask, ...])

Visualize peak directions as given from peaks_from_model.

dot(points[, colors, opacity, dot_size])

Create one or more 3d points.

dots(points[, colors, opacity, dot_size])

Create one or more 3d points.

point(points, colors[, point_radius, phi, ...])

Visualize points as sphere glyphs.

sphere(centers, colors[, radii, phi, theta, ...])

Visualize one or many spheres with different colors and radii.

cylinder(centers, directions, colors[, ...])

Visualize one or many cylinder with different features.

disk(centers, directions, colors[, rinner, ...])

Visualize one or many disks with different features.

square(centers[, directions, colors, scales])

Visualize one or many squares with different features.

rectangle(centers[, directions, colors, scales])

Visualize one or many rectangles with different features.

box(centers[, directions, colors, scales])

Visualize one or many boxes with different features.

cube(centers[, directions, colors, scales])

Visualize one or many cubes with different features.

arrow(centers, directions, colors[, ...])

Visualize one or many arrows with different features.

cone(centers, directions, colors[, heights, ...])

Visualize one or many cones with different features.

triangularprism(centers[, directions, ...])

Visualize one or many regular triangular prisms with different features.

rhombicuboctahedron(centers[, directions, ...])

Visualize one or many rhombicuboctahedron with different features.

pentagonalprism(centers[, directions, ...])

Visualize one or many pentagonal prisms with different features.

octagonalprism(centers[, directions, ...])

Visualize one or many octagonal prisms with different features.

frustum(centers[, directions, colors, scales])

Visualize one or many frustum pyramids with different features.

superquadric(centers[, roundness, ...])

Visualize one or many superquadrics with different features.

billboard(centers[, colors, scales, vs_dec, ...])

Create a billboard actor.

vector_text([text, pos, scale, color, ...])

Create a label actor.

label([text, pos, scale, color, direction, ...])

Create a label actor.

text_3d(text[, position, color, font_size, ...])

Generate 2D text that lives in the 3D world.

grid(actors[, captions, caption_offset, ...])

Creates a grid of actors that lies in the xy-plane.

figure(pic[, interpolation])

Return a figure as an image actor.

texture(rgb[, interp])

Map an RGB or RGBA texture on a plane.

texture_update(texture_actor, arr)

Updates texture of an actor by updating the vtkImageData assigned to the vtkTexture object.

texture_on_sphere(rgb[, theta, phi, interpolate])

Map an RGB or RGBA texture on a sphere.

texture_2d(rgb[, interp])

Create 2D texture from array.

sdf(centers[, directions, colors, ...])

Create a SDF primitive based actor.

markers(centers[, colors, scales, marker, ...])

Create a marker actor with different shapes.

ellipsoid(centers, axes, lengths[, colors, ...])

VTK actor for visualizing ellipsoids.

uncertainty_cone(evals, evecs, signal, ...)

VTK actor for visualizing the cone of uncertainty representing the variance of the main direction of diffusion.

+
+

Container#

+
+
+class fury.actor.Container(layout=<fury.layout.Layout object>)[source]#
+

Bases: object

+

Provides functionalities for grouping multiple actors using a given +layout.

+
+
+anchor#
+

Anchor of this container used when laying out items in a container. +The anchor point is relative to the center of the container. +Default: (0, 0, 0).

+
+
Type:
+

3-tuple of float

+
+
+
+ +
+
+padding#
+

Padding around this container bounding box. The 6-tuple represents +(pad_x_neg, pad_x_pos, pad_y_neg, pad_y_pos, pad_z_neg, pad_z_pos). +Default: (0, 0, 0, 0, 0, 0).

+
+
Type:
+

6-tuple of float

+
+
+
+ +
+
+__init__(layout=<fury.layout.Layout object>)[source]#
+
+
Parameters:
+

layout (fury.layout.Layout object) – Items of this container will be arranged according to layout.

+
+
+
+ +
+
+AddPosition(position)[source]#
+
+ +
+
+GetBounds()[source]#
+

Get the bounds of the container.

+
+ +
+
+GetCenter()[source]#
+

Get the center of the bounding box.

+
+ +
+
+GetLength()[source]#
+

Get the length of bounding box diagonal.

+
+ +
+
+GetPosition()[source]#
+
+ +
+
+GetVisibility()[source]#
+
+ +
+
+NewInstance()[source]#
+
+ +
+
+SetPosition(position)[source]#
+
+ +
+
+SetVisibility(visibility)[source]#
+
+ +
+
+ShallowCopy(other)[source]#
+
+ +
+
+add(*items, **kwargs)[source]#
+

Adds some items to this container.

+
+
Parameters:
+
    +
  • items (vtkProp3D objects) – Items to add to this container.

  • +
  • borrow (bool) – If True the items are added as-is, otherwise a shallow copy is +made first. If you intend to reuse the items elsewhere you +should set borrow=False. Default: True.

  • +
+
+
+
+ +
+
+add_to_scene(scene)[source]#
+

Adds the items of this container to a given scene.

+
+ +
+
+clear()[source]#
+

Clears all items of this container.

+
+ +
+
+property items#
+
+ +
+
+remove_from_scene(scene)[source]#
+

Removes the items of this container from a given scene.

+
+ +
+
+update()[source]#
+

Updates the position of the items of this container.

+
+ +
+ +
+
+

slicer#

+
+
+fury.actor.slicer(data, affine=None, value_range=None, opacity=1.0, lookup_colormap=None, interpolation='linear', picking_tol=0.025)[source]#
+

Cut 3D scalar or rgb volumes into 2D images.

+
+
Parameters:
+
    +
  • data (array, shape (X, Y, Z) or (X, Y, Z, 3)) – A grayscale or rgb 4D volume as a numpy array. If rgb then values +expected on the range [0, 255].

  • +
  • affine (array, shape (4, 4)) – Grid to space (usually RAS 1mm) transformation matrix. Default is None. +If None then the identity matrix is used.

  • +
  • value_range (None or tuple (2,)) – If None then the values will be interpolated from (data.min(), +data.max()) to (0, 255). Otherwise from (value_range[0], +value_range[1]) to (0, 255).

  • +
  • opacity (float, optional) – Opacity of 0 means completely transparent and 1 completely visible.

  • +
  • lookup_colormap (vtkLookupTable, optional) – If None (default) then a grayscale map is created.

  • +
  • interpolation (string, optional) – If ‘linear’ (default) then linear interpolation is used on the final +texture mapping. If ‘nearest’ then nearest neighbor interpolation is +used on the final texture mapping.

  • +
  • picking_tol (float, optional) – The tolerance for the vtkCellPicker, specified as a fraction of +rendering window size.

  • +
+
+
Returns:
+

image_actor – An object that is capable of displaying different parts of the volume +as slices. The key method of this object is display_extent where +one can input grid coordinates and display the slice in space (or grid) +coordinates as calculated by the affine parameter.

+
+
Return type:
+

ImageActor

+
+
+
+ +
+
+

surface#

+
+
+fury.actor.surface(vertices, faces=None, colors=None, smooth=None, subdivision=3)[source]#
+

Generate a surface actor from an array of vertices.

+

The color and smoothness of the surface can be customized by specifying +the type of subdivision algorithm and the number of subdivisions.

+
+
Parameters:
+
    +
  • vertices (array, shape (X, Y, Z)) – The point cloud defining the surface.

  • +
  • faces (array) – An array of precomputed triangulation for the point cloud. +It is an optional parameter, it is computed locally if None.

  • +
  • colors ((N, 3) array) – Specifies the colors associated with each vertex in the +vertices array. Range should be 0 to 1. +Optional parameter, if not passed, all vertices +are colored white.

  • +
  • smooth (string - "loop" or "butterfly") – Defines the type of subdivision to be used +for smoothing the surface.

  • +
  • subdivision (integer, default = 3) – Defines the number of subdivisions to do for +each triangulation of the point cloud. +The higher the value, smoother the surface +but at the cost of higher computation.

  • +
+
+
Returns:
+

surface_actor – An Actor visualizing the final surface +computed from the point cloud is returned.

+
+
Return type:
+

Actor

+
+
+
+ +
+
+

contour_from_roi#

+
+
+fury.actor.contour_from_roi(data, affine=None, color=array([1, 0, 0]), opacity=1)[source]#
+

Generate surface actor from a binary ROI.

+

The color and opacity of the surface can be customized.

+
+
Parameters:
+
    +
  • data (array, shape (X, Y, Z)) – An ROI file that will be binarized and displayed.

  • +
  • affine (array, shape (4, 4)) – Grid to space (usually RAS 1mm) transformation matrix. Default is None. +If None then the identity matrix is used.

  • +
  • color ((1, 3) ndarray) – RGB values in [0,1].

  • +
  • opacity (float) – Opacity of surface between 0 and 1.

  • +
+
+
Returns:
+

contour_assembly – ROI surface object displayed in space +coordinates as calculated by the affine parameter.

+
+
Return type:
+

vtkAssembly

+
+
+
+ +
+
+

contour_from_label#

+
+
+fury.actor.contour_from_label(data, affine=None, color=None)[source]#
+

Generate surface actor from a labeled Array.

+

The color and opacity of individual surfaces can be customized.

+
+
Parameters:
+
    +
  • data (array, shape (X, Y, Z)) – A labeled array file that will be binarized and displayed.

  • +
  • affine (array, shape (4, 4)) – Grid to space (usually RAS 1mm) transformation matrix. Default is None. +If None then the identity matrix is used.

  • +
  • color ((N, 3) or (N, 4) ndarray) – RGB/RGBA values in [0,1]. Default is None. +If None then random colors are used. +Alpha channel is set to 1 by default.

  • +
+
+
Returns:
+

contour_assembly – Array surface object displayed in space +coordinates as calculated by the affine parameter +in the order of their roi ids.

+
+
Return type:
+

vtkAssembly

+
+
+
+ +
+
+

streamtube#

+
+
+fury.actor.streamtube(lines, colors=None, opacity=1, linewidth=0.1, tube_sides=9, lod=True, lod_points=10000, lod_points_size=3, spline_subdiv=None, lookup_colormap=None, replace_strips=False)[source]#
+

Use streamtubes to visualize polylines.

+
+
Parameters:
+
    +
  • lines (list) – list of N curves represented as 2D ndarrays

  • +
  • colors (array (N, 3), list of arrays, tuple (3,), array (K,)) – If None or False, a standard orientation colormap is used for every +line. +If one tuple of color is used. Then all streamlines will have the same +colour. +If an array (N, 3) is given, where N is equal to the number of lines. +Then every line is coloured with a different RGB color. +If a list of RGB arrays is given then every point of every line takes +a different color. +If an array (K, 3) is given, where K is the number of points of all +lines then every point is colored with a different RGB color. +If an array (K,) is given, where K is the number of points of all +lines then these are considered as the values to be used by the +colormap. +If an array (L,) is given, where L is the number of streamlines then +these are considered as the values to be used by the colormap per +streamline. +If an array (X, Y, Z) or (X, Y, Z, 3) is given then the values for the +colormap are interpolated automatically using trilinear interpolation.

  • +
  • opacity (float, optional) – Takes values from 0 (fully transparent) to 1 (opaque). Default is 1.

  • +
  • linewidth (float, optional) – Default is 0.01.

  • +
  • tube_sides (int, optional) – Default is 9.

  • +
  • lod (bool, optional) – Use LODActor(level of detail) rather than Actor. Default is True. +Level of detail actors do not render the full geometry when the +frame rate is low.

  • +
  • lod_points (int, optional) – Number of points to be used when LOD is in effect. Default is 10000.

  • +
  • lod_points_size (int, optional) – Size of points when lod is in effect. Default is 3.

  • +
  • spline_subdiv (int, optional) – Number of splines subdivision to smooth streamtubes. Default is None.

  • +
  • lookup_colormap (vtkLookupTable, optional) – Add a default lookup table to the colormap. Default is None which calls +fury.actor.colormap_lookup_table().

  • +
  • replace_strips (bool, optional) – If True it changes streamtube representation from triangle strips to +triangles. Useful with SelectionManager or PickingManager. +Default False.

  • +
+
+
+

Examples

+
>>> import numpy as np
+>>> from fury import actor, window
+>>> scene = window.Scene()
+>>> lines = [np.random.rand(10, 3), np.random.rand(20, 3)]
+>>> colors = np.random.rand(2, 3)
+>>> c = actor.streamtube(lines, colors)
+>>> scene.add(c)
+>>> #window.show(scene)
+
+
+

Notes

+

Streamtubes can be heavy on GPU when loading many streamlines and +therefore, you may experience slow rendering time depending on system GPU. +A solution to this problem is to reduce the number of points in each +streamline. In Dipy we provide an algorithm that will reduce the number of +points on the straighter parts of the streamline but keep more points on +the curvier parts. This can be used in the following way:

+
from dipy.tracking.distances import approx_polygon_track
+lines = [approx_polygon_track(line, 0.2) for line in lines]
+
+
+

Alternatively we suggest using the line actor which is much more +efficient.

+
+

See also

+

fury.actor.line()

+
+
+ +
+
+

line#

+
+
+fury.actor.line(lines, colors=None, opacity=1, linewidth=1, spline_subdiv=None, lod=True, lod_points=10000, lod_points_size=3, lookup_colormap=None, depth_cue=False, fake_tube=False)[source]#
+

Create an actor for one or more lines.

+
+
Parameters:
+
    +
  • lines (list of arrays) –

  • +
  • colors (array (N, 3), list of arrays, tuple (3,), array (K,)) – If None or False, a standard orientation colormap is used for every +line. +If one tuple of color is used. Then all streamlines will have the same +colour. +If an array (N, 3) is given, where N is equal to the number of lines. +Then every line is coloured with a different RGB color. +If a list of RGB arrays is given then every point of every line takes +a different color. +If an array (K, 3) is given, where K is the number of points of all +lines then every point is colored with a different RGB color. +If an array (K,) is given, where K is the number of points of all +lines then these are considered as the values to be used by the +colormap. +If an array (L,) is given, where L is the number of streamlines then +these are considered as the values to be used by the colormap per +streamline. +If an array (X, Y, Z) or (X, Y, Z, 3) is given then the values for the +colormap are interpolated automatically using trilinear interpolation.

  • +
  • opacity (float, optional) – Takes values from 0 (fully transparent) to 1 (opaque). Default is 1.

  • +
  • linewidth (float, optional) – Line thickness. Default is 1.

  • +
  • spline_subdiv (int, optional) – Number of splines subdivision to smooth streamtubes. Default is None +which means no subdivision.

  • +
  • lod (bool, optional) – Use LODActor(level of detail) rather than Actor. Default is True. +Level of detail actors do not render the full geometry when the +frame rate is low.

  • +
  • lod_points (int, optional) – Number of points to be used when LOD is in effect. Default is 10000.

  • +
  • lod_points_size (int) – Size of points when lod is in effect. Default is 3.

  • +
  • lookup_colormap (vtkLookupTable, optional) – Add a default lookup table to the colormap. Default is None which calls +fury.actor.colormap_lookup_table().

  • +
  • depth_cue (boolean, optional) – Add a size depth cue so that lines shrink with distance to the camera. +Works best with linewidth <= 1.

  • +
  • fake_tube (boolean, optional) – Add shading to lines to approximate the look of tubes.

  • +
+
+
Returns:
+

v – Line.

+
+
Return type:
+

Actor or LODActor object

+
+
+

Examples

+
>>> from fury import actor, window
+>>> scene = window.Scene()
+>>> lines = [np.random.rand(10, 3), np.random.rand(20, 3)]
+>>> colors = np.random.rand(2, 3)
+>>> c = actor.line(lines, colors)
+>>> scene.add(c)
+>>> #window.show(scene)
+
+
+
+ +
+
+

scalar_bar#

+
+
+fury.actor.scalar_bar(lookup_table=None, title=' ')[source]#
+

Default scalar bar actor for a given colormap (colorbar).

+
+
Parameters:
+
    +
  • lookup_table (vtkLookupTable or None) – If None then colormap_lookup_table is called with default options.

  • +
  • title (str) –

  • +
+
+
Returns:
+

scalar_bar

+
+
Return type:
+

vtkScalarBarActor

+
+
+
+

See also

+

fury.actor.colormap_lookup_table()

+
+
+ +
+
+

axes#

+
+
+fury.actor.axes(scale=(1, 1, 1), colorx=(1, 0, 0), colory=(0, 1, 0), colorz=(0, 0, 1), opacity=1)[source]#
+

Create an actor with the coordinate’s system axes where +red = x, green = y, blue = z.

+
+
Parameters:
+
    +
  • scale (tuple (3,)) – Axes size e.g. (100, 100, 100). Default is (1, 1, 1).

  • +
  • colorx (tuple (3,)) – x-axis color. Default red (1, 0, 0).

  • +
  • colory (tuple (3,)) – y-axis color. Default green (0, 1, 0).

  • +
  • colorz (tuple (3,)) – z-axis color. Default blue (0, 0, 1).

  • +
  • opacity (float, optional) – Takes values from 0 (fully transparent) to 1 (opaque). Default is 1.

  • +
+
+
Returns:
+

arrow_actor

+
+
Return type:
+

Actor

+
+
+
+ +
+
+

odf_slicer#

+
+
+fury.actor.odf_slicer(odfs, affine=None, mask=None, sphere=None, scale=0.5, norm=True, radial_scale=True, opacity=1.0, colormap=None, global_cm=False, B_matrix=None)[source]#
+

Create an actor for rendering a grid of ODFs given an array of +spherical function (SF) or spherical harmonics (SH) coefficients.

+
+
Parameters:
+
    +
  • odfs (ndarray) – 4D ODFs array in SF or SH coefficients. If SH coefficients, +B_matrix must be supplied.

  • +
  • affine (array) – 4x4 transformation array from native coordinates to world coordinates.

  • +
  • mask (ndarray) – 3D mask to apply to ODF field.

  • +
  • sphere (dipy Sphere) – The sphere used for SH to SF projection. If None, a default sphere +of 100 vertices will be used.

  • +
  • scale (float) – Multiplicative factor to apply to ODF amplitudes.

  • +
  • norm (bool) – Normalize SF amplitudes so that the maximum +ODF amplitude per voxel along a direction is 1.

  • +
  • radial_scale (bool) – Scale sphere points by ODF values.

  • +
  • opacity (float) – Takes values from 0 (fully transparent) to 1 (opaque).

  • +
  • colormap (None or str or tuple) – The name of the colormap to use. Matplotlib colormaps are supported +(e.g., ‘inferno’). A plain color can be supplied as a RGB tuple in +range [0, 255]. If None then a RGB colormap is used.

  • +
  • global_cm (bool) – If True the colormap will be applied in all ODFs. If False +it will be applied individually at each voxel.

  • +
  • B_matrix (ndarray (n_coeffs, n_vertices)) – Optional SH to SF matrix for projecting odfs given in SH +coefficients on the sphere. If None, then the input is assumed +to be expressed in SF coefficients.

  • +
+
+
Returns:
+

actor – Actor representing the ODF field.

+
+
Return type:
+

OdfSlicerActor

+
+
+
+ +
+
+

tensor_slicer#

+
+
+fury.actor.tensor_slicer(evals, evecs, affine=None, mask=None, sphere=None, scale=2.2, norm=True, opacity=1.0, scalar_colors=None)[source]#
+

Slice many tensors as ellipsoids in native or world coordinates.

+
+
Parameters:
+
    +
  • evals ((3,) or (X, 3) or (X, Y, 3) or (X, Y, Z, 3) ndarray) – eigenvalues

  • +
  • evecs ((3, 3) or (X, 3, 3) or (X, Y, 3, 3) or (X, Y, Z, 3, 3) ndarray) – eigenvectors

  • +
  • affine (array) – 4x4 transformation array from native coordinates to world coordinates*

  • +
  • mask (ndarray) – 3D mask

  • +
  • sphere (Sphere) – a sphere

  • +
  • scale (float) – Distance between spheres.

  • +
  • norm (bool) – Normalize sphere_values.

  • +
  • opacity (float) – Takes values from 0 (fully transparent) to 1 (opaque). Default is 1.

  • +
  • scalar_colors ((3,) or (X, 3) or (X, Y, 3) or (X, Y, Z, 3) ndarray) – RGB colors used to show the tensors +Default None, color the ellipsoids using color_fa

  • +
+
+
Returns:
+

tensor_actor – Ellipsoid

+
+
Return type:
+

Actor

+
+
+
+ +
+
+

peak_slicer#

+
+
+fury.actor.peak_slicer(peaks_dirs, peaks_values=None, mask=None, affine=None, colors=(1, 0, 0), opacity=1.0, linewidth=1, lod=False, lod_points=10000, lod_points_size=3, symmetric=True)[source]#
+

Visualize peak directions as given from peaks_from_model.

+
+
Parameters:
+
    +
  • peaks_dirs (ndarray) – Peak directions. The shape of the array can be (M, 3) or (X, M, 3) or +(X, Y, M, 3) or (X, Y, Z, M, 3).

  • +
  • peaks_values (ndarray) – Peak values. The shape of the array can be (M, ) or (X, M) or +(X, Y, M) or (X, Y, Z, M).

  • +
  • affine (array) – 4x4 transformation array from native coordinates to world coordinates.

  • +
  • mask (ndarray) – 3D mask.

  • +
  • colors (tuple or None) – Default red color. If None then every peak gets an orientation color +in similarity to a DEC map.

  • +
  • opacity (float, optional) – Takes values from 0 (fully transparent) to 1 (opaque).

  • +
  • linewidth (float, optional) – Line thickness. Default is 1.

  • +
  • lod (bool) – Use LODActor(level of detail) rather than Actor. +Default is False. Level of detail actors do not render the full +geometry when the frame rate is low.

  • +
  • lod_points (int) – Number of points to be used when LOD is in effect. Default is 10000.

  • +
  • lod_points_size (int) – Size of points when lod is in effect. Default is 3.

  • +
  • symmetric (bool, optional) – If True, peaks are drawn for both peaks_dirs and -peaks_dirs. Else, +peaks are only drawn for directions given by peaks_dirs. Default is +True.

  • +
+
+
Returns:
+

peak_actor

+
+
Return type:
+

Actor

+
+
+
+

See also

+

fury.actor.odf_slice()

+
+
+ +
+
+

peak#

+
+
+fury.actor.peak(peaks_dirs, peaks_values=None, mask=None, affine=None, colors=None, linewidth=1, lookup_colormap=None, symmetric=True)[source]#
+

Visualize peak directions as given from peaks_from_model.

+
+
Parameters:
+
    +
  • peaks_dirs (ndarray) – Peak directions. The shape of the array should be (X, Y, Z, D, 3).

  • +
  • peaks_values (ndarray, optional) – Peak values. The shape of the array should be (X, Y, Z, D).

  • +
  • affine (array, optional) – 4x4 transformation array from native coordinates to world coordinates.

  • +
  • mask (ndarray, optional) – 3D mask

  • +
  • colors (tuple or None, optional) – Default None. If None then every peak gets an orientation color +in similarity to a DEC map.

  • +
  • lookup_colormap (vtkLookupTable, optional) – Add a default lookup table to the colormap. Default is None which calls +fury.actor.colormap_lookup_table().

  • +
  • linewidth (float, optional) – Line thickness. Default is 1.

  • +
  • symmetric (bool, optional) – If True, peaks are drawn for both peaks_dirs and -peaks_dirs. Else, +peaks are only drawn for directions given by peaks_dirs. Default is +True.

  • +
+
+
Returns:
+

peak_actor – Actor or LODActor representing the peaks directions and/or +magnitudes.

+
+
Return type:
+

PeakActor

+
+
+

Examples

+
>>> from fury import actor, window
+>>> import numpy as np
+>>> scene = window.Scene()
+>>> peak_dirs = np.random.rand(3, 3, 3, 3, 3)
+>>> c = actor.peak(peak_dirs)
+>>> scene.add(c)
+>>> #window.show(scene)
+
+
+
+ +
+
+

dot#

+
+
+fury.actor.dot(points, colors=None, opacity=None, dot_size=5)[source]#
+

Create one or more 3d points.

+
+
Parameters:
+
    +
  • points (ndarray, (N, 3)) – dots positions.

  • +
  • colors (ndarray (N,3) or (N, 4) or tuple (3,) or tuple (4,)) – RGB or RGBA (for opacity) R, G, B and A should be at the range [0, 1].

  • +
  • opacity (float, optional) – Takes values from 0 (fully transparent) to 1 (opaque). +If a value is given, each dot will have the same opacity otherwise +opacity is set to 1 by default, or is defined by Alpha parameter +in colors if given.

  • +
  • dot_size (int) –

  • +
+
+
Returns:
+

dot_actor

+
+
Return type:
+

Actor

+
+
+
+

See also

+

fury.actor.point()

+
+
+ +
+
+

dots#

+
+
+fury.actor.dots(points, colors=None, opacity=None, dot_size=5)#
+

Create one or more 3d points.

+

dots function has been renamed dot

+
    +
  • deprecated from version: 0.8.1

  • +
  • Raises <class ‘fury.deprecator.ExpiredDeprecationError’> as of version: 0.9.0

  • +
+
+
Parameters:
+
    +
  • points (ndarray, (N, 3)) – dots positions.

  • +
  • colors (ndarray (N,3) or (N, 4) or tuple (3,) or tuple (4,)) – RGB or RGBA (for opacity) R, G, B and A should be at the range [0, 1].

  • +
  • opacity (float, optional) – Takes values from 0 (fully transparent) to 1 (opaque). +If a value is given, each dot will have the same opacity otherwise +opacity is set to 1 by default, or is defined by Alpha parameter +in colors if given.

  • +
  • dot_size (int) –

  • +
+
+
Returns:
+

dot_actor

+
+
Return type:
+

Actor

+
+
+
+

See also

+

fury.actor.point()

+
+
+ +
+
+

point#

+
+
+fury.actor.point(points, colors, point_radius=0.1, phi=8, theta=8, opacity=1.0)[source]#
+

Visualize points as sphere glyphs.

+
+
Parameters:
+
    +
  • points (ndarray, shape (N, 3)) –

  • +
  • colors (ndarray (N,3) or tuple (3,)) –

  • +
  • point_radius (float) –

  • +
  • phi (int) –

  • +
  • theta (int) –

  • +
  • opacity (float, optional) – Takes values from 0 (fully transparent) to 1 (opaque). Default is 1.

  • +
+
+
Returns:
+

point_actor

+
+
Return type:
+

Actor

+
+
+ +

Examples

+
>>> from fury import window, actor
+>>> scene = window.Scene()
+>>> pts = np.random.rand(5, 3)
+>>> point_actor = actor.point(pts, window.colors.coral)
+>>> scene.add(point_actor)
+>>> # window.show(scene)
+
+
+
+ +
+
+

sphere#

+
+
+fury.actor.sphere(centers, colors, radii=1.0, phi=16, theta=16, vertices=None, faces=None, opacity=1, use_primitive=False)[source]#
+

Visualize one or many spheres with different colors and radii.

+
+
Parameters:
+
    +
  • centers (ndarray, shape (N, 3)) – Spheres positions.

  • +
  • colors (ndarray (N,3) or (N, 4) or tuple (3,) or tuple (4,)) – RGB or RGBA (for opacity) R, G, B and A should be at the range [0, 1].

  • +
  • radii (float or ndarray, shape (N,)) – Sphere radius.

  • +
  • phi (int, optional) – Set the number of points in the latitude direction.

  • +
  • theta (int, optional) – Set the number of points in the longitude direction.

  • +
  • vertices (ndarray, shape (N, 3)) – The point cloud defining the sphere.

  • +
  • faces (ndarray, shape (M, 3)) – If faces is None then a sphere is created based on theta and phi angles +If not then a sphere is created with the provided vertices and faces.

  • +
  • opacity (float, optional) – Takes values from 0 (fully transparent) to 1 (opaque). Default is 1.

  • +
  • use_primitive (boolean, optional) – If True, uses primitives to create an actor.

  • +
+
+
Returns:
+

sphere_actor

+
+
Return type:
+

Actor

+
+
+

Examples

+
>>> from fury import window, actor
+>>> scene = window.Scene()
+>>> centers = np.random.rand(5, 3)
+>>> sphere_actor = actor.sphere(centers, window.colors.coral)
+>>> scene.add(sphere_actor)
+>>> # window.show(scene)
+
+
+
+ +
+
+

cylinder#

+
+
+fury.actor.cylinder(centers, directions, colors, radius=0.05, heights=1, capped=False, resolution=8, vertices=None, faces=None, repeat_primitive=True)[source]#
+

Visualize one or many cylinder with different features.

+
+
Parameters:
+
    +
  • centers (ndarray, shape (N, 3)) – Cylinder positions.

  • +
  • directions (ndarray, shape (N, 3)) – The orientation vector of the cylinder.

  • +
  • colors (ndarray (N,3) or (N, 4) or tuple (3,) or tuple (4,)) – RGB or RGBA (for opacity) R, G, B and A should be at the range [0, 1].

  • +
  • radius (float) – cylinder radius.

  • +
  • heights (ndarray, shape (N)) – The height of the cylinder.

  • +
  • capped (bool) – Turn on/off whether to cap cylinder with polygons. Default (False).

  • +
  • resolution (int) – Number of facets/sectors used to define cylinder.

  • +
  • vertices (ndarray, shape (N, 3)) – The point cloud defining the sphere.

  • +
  • faces (ndarray, shape (M, 3)) – If faces is None then a sphere is created based on theta and phi angles. +If not then a sphere is created with the provided vertices and faces.

  • +
  • repeat_primitive (bool) – If True, cylinder will be generated with primitives +If False, repeat_sources will be invoked to use VTK filters for cylinder.

  • +
+
+
Returns:
+

cylinder_actor

+
+
Return type:
+

Actor

+
+
+

Examples

+
>>> from fury import window, actor
+>>> scene = window.Scene()
+>>> centers = np.random.rand(5, 3)
+>>> dirs = np.random.rand(5, 3)
+>>> heights = np.random.rand(5)
+>>> actor = actor.cylinder(centers, dirs, (1, 1, 1), heights=heights)
+>>> scene.add(actor)
+>>> # window.show(scene)
+
+
+
+ +
+
+

disk#

+
+
+fury.actor.disk(centers, directions, colors, rinner=0.3, router=0.7, cresolution=6, rresolution=2, vertices=None, faces=None)[source]#
+

Visualize one or many disks with different features.

+
+
Parameters:
+
    +
  • centers (ndarray, shape (N, 3)) – Disk positions.

  • +
  • directions (ndarray, shape (N, 3)) – The orientation vector of the disk.

  • +
  • colors (ndarray (N,3) or (N, 4) or tuple (3,) or tuple (4,)) – RGB or RGBA (for opacity) R, G, B and A should be at the range [0, 1].

  • +
  • rinner (float) – disk inner radius, default: 0.3

  • +
  • router (float) – disk outer radius, default: 0.5

  • +
  • cresolution (int, optional) – Number of facets used to define perimeter of disk, default: 6

  • +
  • rresolution (int, optional) – Number of facets used radially, default: 2

  • +
  • vertices (ndarray, shape (N, 3)) – The point cloud defining the disk.

  • +
  • faces (ndarray, shape (M, 3)) – If faces is None then a disk is created based on theta and phi angles. +If not then a disk is created with the provided vertices and faces.

  • +
+
+
Returns:
+

disk_actor

+
+
Return type:
+

Actor

+
+
+

Examples

+
>>> from fury import window, actor
+>>> import numpy as np
+>>> scene = window.Scene()
+>>> centers = np.random.rand(5, 3)
+>>> dirs = np.random.rand(5, 3)
+>>> colors = np.random.rand(5, 4)
+>>> actor = actor.disk(centers, dirs, colors,
+>>>                    rinner=.1, router=.8, cresolution=30)
+>>> scene.add(actor)
+>>> window.show(scene)
+
+
+
+ +
+
+

square#

+
+
+fury.actor.square(centers, directions=(1, 0, 0), colors=(1, 0, 0), scales=1)[source]#
+

Visualize one or many squares with different features.

+
+
Parameters:
+
    +
  • centers (ndarray, shape (N, 3)) – Square positions.

  • +
  • directions (ndarray, shape (N, 3), optional) – The orientation vector of the square.

  • +
  • colors (ndarray (N,3) or (N, 4) or tuple (3,) or tuple (4,), optional) – RGB or RGBA (for opacity) R, G, B and A should be at the range [0, 1].

  • +
  • scales (int or ndarray (N,3) or tuple (3,), optional) – Square size on each direction (x, y), default(1)

  • +
+
+
Returns:
+

sq_actor

+
+
Return type:
+

Actor

+
+
+

Examples

+
>>> from fury import window, actor
+>>> scene = window.Scene()
+>>> centers = np.random.rand(5, 3)
+>>> dirs = np.random.rand(5, 3)
+>>> sq_actor = actor.square(centers, dirs)
+>>> scene.add(sq_actor)
+>>> # window.show(scene)
+
+
+
+ +
+
+

rectangle#

+
+
+fury.actor.rectangle(centers, directions=(1, 0, 0), colors=(1, 0, 0), scales=(1, 2, 0))[source]#
+

Visualize one or many rectangles with different features.

+
+
Parameters:
+
    +
  • centers (ndarray, shape (N, 3)) – Rectangle positions.

  • +
  • directions (ndarray, shape (N, 3), optional) – The orientation vector of the rectangle.

  • +
  • colors (ndarray (N,3) or (N, 4) or tuple (3,) or tuple (4,), optional) – RGB or RGBA (for opacity) R, G, B and A should be at the range [0, 1].

  • +
  • scales (int or ndarray (N,3) or tuple (3,), optional) – Rectangle size on each direction (x, y), default(1)

  • +
+
+
Returns:
+

rect_actor

+
+
Return type:
+

Actor

+
+
+
+

See also

+

fury.actor.square()

+
+

Examples

+
>>> from fury import window, actor
+>>> scene = window.Scene()
+>>> centers = np.random.rand(5, 3)
+>>> dirs = np.random.rand(5, 3)
+>>> rect_actor = actor.rectangle(centers, dirs)
+>>> scene.add(rect_actor)
+>>> # window.show(scene)
+
+
+
+ +
+
+

box#

+
+
+fury.actor.box(centers, directions=(1, 0, 0), colors=(1, 0, 0), scales=(1, 2, 3))[source]#
+

Visualize one or many boxes with different features.

+
+
Parameters:
+
    +
  • centers (ndarray, shape (N, 3)) – Box positions.

  • +
  • directions (ndarray, shape (N, 3), optional) – The orientation vector of the box.

  • +
  • colors (ndarray (N,3) or (N, 4) or tuple (3,) or tuple (4,), optional) – RGB or RGBA (for opacity) R, G, B and A should be at the range [0, 1].

  • +
  • scales (int or ndarray (N,3) or tuple (3,), optional) – Box size on each direction (x, y), default(1)

  • +
+
+
Returns:
+

box_actor

+
+
Return type:
+

Actor

+
+
+

Examples

+
>>> from fury import window, actor
+>>> scene = window.Scene()
+>>> centers = np.random.rand(5, 3)
+>>> dirs = np.random.rand(5, 3)
+>>> box_actor = actor.box(centers, dirs, (1, 1, 1))
+>>> scene.add(box_actor)
+>>> # window.show(scene)
+
+
+
+ +
+
+

cube#

+
+
+fury.actor.cube(centers, directions=(1, 0, 0), colors=(1, 0, 0), scales=1)[source]#
+

Visualize one or many cubes with different features.

+
+
Parameters:
+
    +
  • centers (ndarray, shape (N, 3)) – Cube positions.

  • +
  • directions (ndarray, shape (N, 3), optional) – The orientation vector of the cube.

  • +
  • colors (ndarray (N,3) or (N, 4) or tuple (3,) or tuple (4,), optional) – RGB or RGBA (for opacity) R, G, B and A should be at the range [0, 1].

  • +
  • scales (int or ndarray (N,3) or tuple (3,), optional) – Cube size, default: 1

  • +
+
+
Returns:
+

cube_actor

+
+
Return type:
+

Actor

+
+
+

Examples

+
>>> from fury import window, actor
+>>> scene = window.Scene()
+>>> centers = np.random.rand(5, 3)
+>>> dirs = np.random.rand(5, 3)
+>>> cube_actor = actor.cube(centers, dirs)
+>>> scene.add(cube_actor)
+>>> # window.show(scene)
+
+
+
+ +
+
+

arrow#

+
+
+fury.actor.arrow(centers, directions, colors, heights=1.0, resolution=10, tip_length=0.35, tip_radius=0.1, shaft_radius=0.03, scales=1, vertices=None, faces=None, repeat_primitive=True)[source]#
+

Visualize one or many arrows with different features.

+
+
Parameters:
+
    +
  • centers (ndarray, shape (N, 3)) – Arrow positions.

  • +
  • directions (ndarray, shape (N, 3)) – The orientation vector of the arrow.

  • +
  • colors (ndarray (N,3) or (N, 4) or tuple (3,) or tuple (4,)) – RGB or RGBA (for opacity) R, G, B and A should be at the range [0, 1].

  • +
  • heights (ndarray, shape (N)) – The height of the arrow.

  • +
  • resolution (int) – The resolution of the arrow.

  • +
  • tip_length (float) – The tip size of the arrow (default: 0.35)

  • +
  • tip_radius (float) – the tip radius of the arrow (default: 0.1)

  • +
  • shaft_radius (float) – The shaft radius of the arrow (default: 0.03)

  • +
  • vertices (ndarray, shape (N, 3)) – The point cloud defining the arrow.

  • +
  • faces (ndarray, shape (M, 3)) – If faces is None then a arrow is created based on directions, heights +and resolution. If not then a arrow is created with the provided +vertices and faces.

  • +
+
+
Returns:
+

arrow_actor

+
+
Return type:
+

Actor

+
+
+

Examples

+
>>> from fury import window, actor
+>>> scene = window.Scene()
+>>> centers = np.random.rand(5, 3)
+>>> directions = np.random.rand(5, 3)
+>>> heights = np.random.rand(5)
+>>> arrow_actor = actor.arrow(centers, directions, (1, 1, 1), heights)
+>>> scene.add(arrow_actor)
+>>> # window.show(scene)
+
+
+
+ +
+
+

cone#

+
+
+fury.actor.cone(centers, directions, colors, heights=1.0, resolution=10, vertices=None, faces=None, use_primitive=True)[source]#
+

Visualize one or many cones with different features.

+
+
Parameters:
+
    +
  • centers (ndarray, shape (N, 3)) – Cone positions.

  • +
  • directions (ndarray, shape (N, 3)) – The orientation vector of the cone.

  • +
  • colors (ndarray (N,3) or (N, 4) or tuple (3,) or tuple (4,)) – RGB or RGBA (for opacity) R, G, B and A should be at the range [0, 1].

  • +
  • heights (ndarray, shape (N)) – The height of the cone.

  • +
  • resolution (int) – The resolution of the cone.

  • +
  • vertices (ndarray, shape (N, 3)) – The point cloud defining the cone.

  • +
  • faces (ndarray, shape (M, 3)) – If faces is None then a cone is created based on directions, heights +and resolution. If not then a cone is created with the provided. +vertices and faces.

  • +
  • use_primitive (boolean, optional) – If True uses primitives to create the cone actor.

  • +
+
+
Returns:
+

cone_actor

+
+
Return type:
+

Actor

+
+
+

Examples

+
>>> from fury import window, actor
+>>> scene = window.Scene()
+>>> centers = np.random.rand(5, 3)
+>>> directions = np.random.rand(5, 3)
+>>> heights = np.random.rand(5)
+>>> cone_actor = actor.cone(centers, directions, (1, 1, 1), heights)
+>>> scene.add(cone_actor)
+>>> # window.show(scene)
+
+
+
+ +
+
+

triangularprism#

+
+
+fury.actor.triangularprism(centers, directions=(1, 0, 0), colors=(1, 0, 0), scales=1)[source]#
+

Visualize one or many regular triangular prisms with different features.

+
+
Parameters:
+
    +
  • centers (ndarray, shape (N, 3)) – Triangular prism positions.

  • +
  • directions (ndarray, shape (N, 3)) – The orientation vector(s) of the triangular prism(s).

  • +
  • colors (ndarray (N,3) or (N, 4) or tuple (3,) or tuple (4,)) – RGB or RGBA (for opacity) R, G, B and A should be at the range [0, 1].

  • +
  • scales (int or ndarray (N,3) or tuple (3,), optional) – Triangular prism size on each direction (x, y), default(1)

  • +
+
+
Returns:
+

tprism_actor

+
+
Return type:
+

Actor

+
+
+

Examples

+
>>> from fury import window, actor
+>>> scene = window.Scene()
+>>> centers = np.random.rand(3, 3)
+>>> dirs = np.random.rand(3, 3)
+>>> colors = np.random.rand(3, 3)
+>>> scales = np.random.rand(3, 1)
+>>> actor = actor.triangularprism(centers, dirs, colors, scales)
+>>> scene.add(actor)
+>>> # window.show(scene)
+
+
+
+ +
+
+

rhombicuboctahedron#

+
+
+fury.actor.rhombicuboctahedron(centers, directions=(1, 0, 0), colors=(1, 0, 0), scales=1)[source]#
+

Visualize one or many rhombicuboctahedron with different features.

+
+
Parameters:
+
    +
  • centers (ndarray, shape (N, 3)) – Rhombicuboctahedron positions.

  • +
  • directions (ndarray, shape (N, 3)) – The orientation vector(s) of the Rhombicuboctahedron(s).

  • +
  • colors (ndarray (N,3) or (N, 4) or tuple (3,) or tuple (4,)) – RGB or RGBA (for opacity) R, G, B and A should be at the range [0, 1].

  • +
  • scales (int or ndarray (N,3) or tuple (3,), optional) – Rhombicuboctahedron size on each direction (x, y), default(1)

  • +
+
+
Returns:
+

rcoh_actor

+
+
Return type:
+

Actor

+
+
+

Examples

+
>>> from fury import window, actor
+>>> scene = window.Scene()
+>>> centers = np.random.rand(3, 3)
+>>> dirs = np.random.rand(3, 3)
+>>> colors = np.random.rand(3, 3)
+>>> scales = np.random.rand(3, 1)
+>>> actor = actor.rhombicuboctahedron(centers, dirs, colors, scales)
+>>> scene.add(actor)
+>>> # window.show(scene)
+
+
+
+ +
+
+

pentagonalprism#

+
+
+fury.actor.pentagonalprism(centers, directions=(1, 0, 0), colors=(1, 0, 0), scales=1)[source]#
+

Visualize one or many pentagonal prisms with different features.

+
+
Parameters:
+
    +
  • centers (ndarray, shape (N, 3), optional) – Pentagonal prism positions.

  • +
  • directions (ndarray, shape (N, 3), optional) – The orientation vector of the pentagonal prism.

  • +
  • colors (ndarray (N,3) or (N, 4) or tuple (3,) or tuple (4,), optional) – RGB or RGBA (for opacity) R, G, B and A should be at the range [0, 1].

  • +
  • scales (int or ndarray (N,3) or tuple (3,), optional) – Pentagonal prism size on each direction (x, y), default(1)

  • +
+
+
Returns:
+

pent_actor

+
+
Return type:
+

Actor

+
+
+

Examples

+
>>> import numpy as np
+>>> from fury import window, actor
+>>> scene = window.Scene()
+>>> centers = np.random.rand(3, 3)
+>>> dirs = np.random.rand(3, 3)
+>>> colors = np.random.rand(3, 3)
+>>> scales = np.random.rand(3, 1)
+>>> actor_pentagonal = actor.pentagonalprism(centers, dirs, colors, scales)
+>>> scene.add(actor_pentagonal)
+>>> # window.show(scene)
+
+
+
+ +
+
+

octagonalprism#

+
+
+fury.actor.octagonalprism(centers, directions=(1, 0, 0), colors=(1, 0, 0), scales=1)[source]#
+

Visualize one or many octagonal prisms with different features.

+
+
Parameters:
+
    +
  • centers (ndarray, shape (N, 3)) – Octagonal prism positions.

  • +
  • directions (ndarray, shape (N, 3)) – The orientation vector of the octagonal prism.

  • +
  • colors (ndarray (N,3) or (N, 4) or tuple (3,) or tuple (4,)) – RGB or RGBA (for opacity) R, G, B and A should be at the range [0, 1].

  • +
  • scales (int or ndarray (N,3) or tuple (3,), optional) – Octagonal prism size on each direction (x, y), default(1)

  • +
+
+
Returns:
+

oct_actor

+
+
Return type:
+

Actor

+
+
+

Examples

+
>>> from fury import window, actor
+>>> scene = window.Scene()
+>>> centers = np.random.rand(3, 3)
+>>> dirs = np.random.rand(3, 3)
+>>> colors = np.random.rand(3, 3)
+>>> scales = np.random.rand(3, 1)
+>>> actor = actor.octagonalprism(centers, dirs, colors, scales)
+>>> scene.add(actor)
+>>> # window.show(scene)
+
+
+
+ +
+
+

frustum#

+
+
+fury.actor.frustum(centers, directions=(1, 0, 0), colors=(0, 1, 0), scales=1)[source]#
+

Visualize one or many frustum pyramids with different features.

+
+
Parameters:
+
    +
  • centers (ndarray, shape (N, 3)) – Frustum pyramid positions.

  • +
  • directions (ndarray, shape (N, 3)) – The orientation vector of the frustum pyramid.

  • +
  • colors (ndarray (N,3) or (N, 4) or tuple (3,) or tuple (4,)) – RGB or RGBA (for opacity) R, G, B and A should be at the range [0, 1].

  • +
  • scales (int or ndarray (N,3) or tuple (3,), optional) – Frustum pyramid size on each direction (x, y), default(1)

  • +
+
+
Returns:
+

frustum_actor

+
+
Return type:
+

Actor

+
+
+

Examples

+
>>> from fury import window, actor
+>>> scene = window.Scene()
+>>> centers = np.random.rand(4, 3)
+>>> dirs = np.random.rand(4, 3)
+>>> colors = np.random.rand(4, 3)
+>>> scales = np.random.rand(4, 1)
+>>> actor = actor.frustum(centers, dirs, colors, scales)
+>>> scene.add(actor)
+>>> # window.show(scene)
+
+
+
+ +
+
+

superquadric#

+
+
+fury.actor.superquadric(centers, roundness=(1, 1), directions=(1, 0, 0), colors=(1, 0, 0), scales=1)[source]#
+

Visualize one or many superquadrics with different features.

+
+
Parameters:
+
    +
  • centers (ndarray, shape (N, 3)) – Superquadrics positions.

  • +
  • roundness (ndarray, shape (N, 2) or tuple/list (2,), optional) – parameters (Phi and Theta) that control the shape of the superquadric.

  • +
  • directions (ndarray, shape (N, 3) or tuple (3,), optional) – The orientation vector of the cone.

  • +
  • colors (ndarray (N,3) or (N, 4) or tuple (3,) or tuple (4,)) – RGB or RGBA (for opacity) R, G, B and A should be at the range [0, 1].

  • +
  • scales (ndarray, shape (N) or (N,3) or float or int, optional) – The height of the cone.

  • +
+
+
Returns:
+

spq_actor

+
+
Return type:
+

Actor

+
+
+

Examples

+
>>> from fury import window, actor
+>>> scene = window.Scene()
+>>> centers = np.random.rand(3, 3) * 10
+>>> directions = np.random.rand(3, 3)
+>>> scales = np.random.rand(3)
+>>> colors = np.random.rand(3, 3)
+>>> roundness = np.array([[1, 1], [1, 2], [2, 1]])
+>>> sq_actor = actor.superquadric(centers, roundness=roundness,
+...                               directions=directions,
+...                               colors=colors, scales=scales)
+>>> scene.add(sq_actor)
+>>> # window.show(scene)
+
+
+
+ +
+
+

billboard#

+
+
+fury.actor.billboard(centers, colors=(0, 1, 0), scales=1, vs_dec=None, vs_impl=None, gs_prog=None, fs_dec=None, fs_impl=None, bb_type='spherical')[source]#
+

Create a billboard actor. +- +Billboards are 2D elements placed in a 3D world. They offer possibility to +draw different shapes/elements at the fragment shader level.

+
+
Parameters:
+
    +
  • centers (ndarray, shape (N, 3)) – Billboard positions.

  • +
  • colors (ndarray (N,3) or (N, 4) or tuple (3,) or tuple (4,)) – RGB or RGBA (for opacity) R, G, B and A should be at the range [0, 1].

  • +
  • scales (ndarray, shape (N) or (N,3) or float or int, optional) – The scale of the billboards.

  • +
  • vs_dec (str or list of str, optional) – Vertex Shader code that contains all variable/function declarations.

  • +
  • vs_impl (str or list of str, optional) – Vertex Shaders code that contains all variable/function +implementations.

  • +
  • gs_prog (str, optional) – Geometry Shader program.

  • +
  • fs_dec (str or list of str, optional) – Fragment Shaders code that contains all variable/function declarations.

  • +
  • fs_impl (str or list of str, optional) – Fragment Shaders code that contains all variable/function +implementation.

  • +
  • bb_type (str, optional) – Type of billboard (spherical, cylindrical_x, cylindrical_y). +If spherical, billboard will always face the camera. +If cylindrical_x or cylindrical_y, billboard will face the camera only +when rotating around x-axis and y-axis respectively.

  • +
+
+
Returns:
+

billboard_actor

+
+
Return type:
+

Actor

+
+
+
+ +
+
+

vector_text#

+
+
+fury.actor.vector_text(text='Origin', pos=(0, 0, 0), scale=(0.2, 0.2, 0.2), color=(1, 1, 1), direction=(0, 0, 1), extrusion=0.0, align_center=False)[source]#
+

Create a label actor.

+

This actor will always face the camera.

+
+
Parameters:
+
    +
  • text (str) – Text for the label.

  • +
  • pos ((3,) array_like, optional) – Left down position of the label.

  • +
  • scale ((3,) array_like) – Changes the size of the label.

  • +
  • color ((3,) array_like) – Label color as (r,g,b) tuple.

  • +
  • direction ((3,) array_like, optional, default: (0, 0, 1)) – The direction of the label. If None, label will follow the camera.

  • +
  • extrusion (float, optional) – The extrusion amount of the text in Z axis.

  • +
  • align_center (bool, optional, default: True) – If True, the anchor of the actor will be the center of the text. +If False, the anchor will be at the left bottom of the text.

  • +
+
+
Returns:
+

l – Label.

+
+
Return type:
+

Actor object

+
+
+

Examples

+
>>> from fury import window, actor
+>>> scene = window.Scene()
+>>> l = actor.vector_text(text='Hello')
+>>> scene.add(l)
+>>> # window.show(scene)
+
+
+
+ +
+
+

label#

+
+
+fury.actor.label(text='Origin', pos=(0, 0, 0), scale=(0.2, 0.2, 0.2), color=(1, 1, 1), direction=(0, 0, 1), extrusion=0.0, align_center=False)#
+

Create a label actor.

+

Label function has been renamed vector_text

+
    +
  • deprecated from version: 0.7.1

  • +
  • Raises <class ‘fury.deprecator.ExpiredDeprecationError’> as of version: 0.9.0

  • +
+

This actor will always face the camera.

+
+
Parameters:
+
    +
  • text (str) – Text for the label.

  • +
  • pos ((3,) array_like, optional) – Left down position of the label.

  • +
  • scale ((3,) array_like) – Changes the size of the label.

  • +
  • color ((3,) array_like) – Label color as (r,g,b) tuple.

  • +
  • direction ((3,) array_like, optional, default: (0, 0, 1)) – The direction of the label. If None, label will follow the camera.

  • +
  • extrusion (float, optional) – The extrusion amount of the text in Z axis.

  • +
  • align_center (bool, optional, default: True) – If True, the anchor of the actor will be the center of the text. +If False, the anchor will be at the left bottom of the text.

  • +
+
+
Returns:
+

l – Label.

+
+
Return type:
+

Actor object

+
+
+

Examples

+
>>> from fury import window, actor
+>>> scene = window.Scene()
+>>> l = actor.vector_text(text='Hello')
+>>> scene.add(l)
+>>> # window.show(scene)
+
+
+
+ +
+
+

text_3d#

+
+
+fury.actor.text_3d(text, position=(0, 0, 0), color=(1, 1, 1), font_size=12, font_family='Arial', justification='left', vertical_justification='bottom', bold=False, italic=False, shadow=False)[source]#
+

Generate 2D text that lives in the 3D world.

+
+
Parameters:
+
    +
  • text (str) –

  • +
  • position (tuple) –

  • +
  • color (tuple) –

  • +
  • font_size (int) –

  • +
  • font_family (str) –

  • +
  • justification (str) – Left, center or right (default left).

  • +
  • vertical_justification (str) – Bottom, middle or top (default bottom).

  • +
  • bold (bool) –

  • +
  • italic (bool) –

  • +
  • shadow (bool) –

  • +
+
+
Return type:
+

Text3D

+
+
+
+ +
+
+

grid#

+
+
+fury.actor.grid(actors, captions=None, caption_offset=(0, -100, 0), cell_padding=0, cell_shape='rect', aspect_ratio=1.7777777777777777, dim=None)[source]#
+

Creates a grid of actors that lies in the xy-plane.

+
+
Parameters:
+
    +
  • actors (list of vtkProp3D objects) – Actors to be layout in a grid manner.

  • +
  • captions (list of vtkProp3D objects or list of str) – Objects serving as captions (can be any vtkProp3D object, not +necessarily text). There should be one caption per actor. By +default, there are no captions.

  • +
  • caption_offset (tuple of float (optional)) – Tells where to position the caption w.r.t. the center of its +associated actor. Default: (0, -100, 0).

  • +
  • cell_padding (tuple of 2 floats or float) – Each grid cell will be padded according to (pad_x, pad_y) i.e. +horizontally and vertically. Padding is evenly distributed on each +side of the cell. If a single float is provided then both pad_x and +pad_y will have the same value.

  • +
  • cell_shape (str) – Specifies the desired shape of every grid cell. +‘rect’ ensures the cells are the tightest. +‘square’ ensures the cells are as wide as high. +‘diagonal’ ensures the content of the cells can be rotated without +colliding with content of the neighboring cells.

  • +
  • aspect_ratio (float) – Aspect ratio of the grid (width/height). Default: 16:9.

  • +
  • dim (tuple of int) – Dimension (nb_rows, nb_cols) of the grid. If provided, +aspect_ratio will be ignored.

  • +
+
+
Returns:
+

Object that represents the grid containing all the actors and +captions, if any.

+
+
Return type:
+

fury.actor.Container object

+
+
+
+ +
+
+

figure#

+
+
+fury.actor.figure(pic, interpolation='nearest')[source]#
+

Return a figure as an image actor.

+
+
Parameters:
+
    +
  • pic (filename or numpy RGBA array) –

  • +
  • interpolation (str) – Options are nearest, linear or cubic. Default is nearest.

  • +
+
+
Returns:
+

image_actor

+
+
Return type:
+

vtkImageActor

+
+
+
+ +
+
+

texture#

+
+
+fury.actor.texture(rgb, interp=True)[source]#
+

Map an RGB or RGBA texture on a plane.

+
+
Parameters:
+
    +
  • rgb (ndarray) – Input 2D RGB or RGBA array. Dtype should be uint8.

  • +
  • interp (bool) – Interpolate between grid centers. Default True.

  • +
+
+
Returns:
+

act

+
+
Return type:
+

Actor

+
+
+
+ +
+
+

texture_update#

+
+
+fury.actor.texture_update(texture_actor, arr)[source]#
+

Updates texture of an actor by updating the vtkImageData +assigned to the vtkTexture object.

+
+
Parameters:
+
    +
  • texture_actor (Actor) – Actor whose texture is to be updated.

  • +
  • arr (ndarray) – Input 2D image in the form of RGB or RGBA array. +This is the new image to be rendered on the actor. +Dtype should be uint8.

  • +
  • Implementation

  • +
  • --------------

  • +
  • docs/examples/viz_video_on_plane.py (Check) –

  • +
+
+
+
+ +
+
+

texture_on_sphere#

+
+
+fury.actor.texture_on_sphere(rgb, theta=60, phi=60, interpolate=True)[source]#
+

Map an RGB or RGBA texture on a sphere.

+
+
Parameters:
+
    +
  • rgb (ndarray) – Input 2D RGB or RGBA array. Dtype should be uint8.

  • +
  • theta (int, optional) – Set the number of points in the longitude direction.

  • +
  • phi (int, optional) – Set the number of points in the latitude direction.

  • +
  • interpolate (bool, optional) – Interpolate between grid centers.

  • +
+
+
Returns:
+

earthActor

+
+
Return type:
+

Actor

+
+
+
+ +
+
+

texture_2d#

+
+
+fury.actor.texture_2d(rgb, interp=False)[source]#
+

Create 2D texture from array.

+
+
Parameters:
+
    +
  • rgb (ndarray) – Input 2D RGB or RGBA array. Dtype should be uint8.

  • +
  • interp (bool, optional) – Interpolate between grid centers.

  • +
+
+
Return type:
+

vtkTexturedActor

+
+
+
+ +
+
+

sdf#

+
+
+fury.actor.sdf(centers, directions=(1, 0, 0), colors=(1, 0, 0), primitives='torus', scales=1)[source]#
+

Create a SDF primitive based actor.

+
+
Parameters:
+
    +
  • centers (ndarray, shape (N, 3)) – SDF primitive positions.

  • +
  • colors (ndarray (N,3) or (N, 4) or tuple (3,) or tuple (4,), optional) – RGB or RGBA (for opacity) R, G, B and A should be at the range [0, 1].

  • +
  • directions (ndarray, shape (N, 3)) – The orientation vector of the SDF primitive.

  • +
  • primitives (str, list, tuple, np.ndarray) – The primitive of choice to be rendered. +Options are sphere, torus and ellipsoid. Default is torus.

  • +
  • scales (float) – The size of the SDF primitive.

  • +
+
+
Returns:
+

box_actor

+
+
Return type:
+

Actor

+
+
+
+ +
+
+

markers#

+
+
+fury.actor.markers(centers, colors=(0, 1, 0), scales=1, marker='3d', marker_opacity=0.8, edge_width=0.0, edge_color=(255, 255, 255), edge_opacity=0.8)[source]#
+

Create a marker actor with different shapes.

+
+
Parameters:
+
    +
  • centers (ndarray, shape (N, 3)) –

  • +
  • colors (ndarray (N,3) or (N, 4) or tuple (3,) or tuple (4,)) – RGB or RGBA (for opacity) R, G, B and A should be at the range [0, 1].

  • +
  • scales (ndarray, shape (N) or (N,3) or float or int, optional) –

  • +
  • marker (str or a list) – Available markers are: ‘3d’, ‘o’, ‘s’, ‘d’, ‘^’, ‘p’, ‘h’, ‘s6’, +‘x’, ‘+’, optional.

  • +
  • marker_opacity (float, optional) –

  • +
  • edge_width (int, optional) –

  • +
  • edge_color (ndarray, shape (3), optional) –

  • +
  • edge_opacity (float, optional) –

  • +
+
+
Returns:
+

sq_actor

+
+
Return type:
+

Actor

+
+
+

Examples

+
>>> import numpy as np
+>>> from fury import actor, window
+>>> scene = window.Scene()
+>>> markers = ['o', 'x', '^', 's']  # some examples
+>>> n = len(markers)
+>>> centers = np.random.normal(size=(n, 3), scale=10)
+>>> colors = np.random.rand(n, 4)
+>>> nodes_actor = actor.markers(
+        centers,
+        marker=markers,
+        edge_width=.1,
+        edge_color=[255, 255, 0],
+        colors=colors,
+        scales=10,
+    )
+>>> center = np.random.normal(size=(1, 3), scale=10)
+>>> nodes_3d_actor = actor.markers(
+        center,
+        marker='3d',
+        scales=5,
+    )
+>>> scene.add(nodes_actor, nodes_3d_actor)
+>>> # window.show(scene, size=(600, 600))
+
+
+
+ +
+
+

ellipsoid#

+
+
+fury.actor.ellipsoid(centers, axes, lengths, colors=(1, 0, 0), scales=1.0, opacity=1.0)[source]#
+

VTK actor for visualizing ellipsoids.

+
+
Parameters:
+
    +
  • centers (ndarray(N, 3)) – Ellipsoid positions.

  • +
  • axes (ndarray (3, 3) or (N, 3, 3)) – Axes of the ellipsoid.

  • +
  • lengths (ndarray (3, ) or (N, 3)) – Axes lengths.

  • +
  • colors (ndarray (N,3) or tuple (3,), optional) – Default red color. R, G and B should be in the range [0, 1].

  • +
  • scales (float or ndarray (N, ), optional) – Ellipsoid size, default(1.0).

  • +
  • opacity (float, optional) – Takes values from 0 (fully transparent) to 1 (opaque), default(1.0).

  • +
+
+
Returns:
+

tensor_ellipsoid

+
+
Return type:
+

Actor

+
+
+
+ +
+
+

uncertainty_cone#

+
+
+fury.actor.uncertainty_cone(evals, evecs, signal, sigma, b_matrix, scales=0.6, opacity=1.0)[source]#
+

VTK actor for visualizing the cone of uncertainty representing the +variance of the main direction of diffusion.

+
+
Parameters:
+
    +
  • evals (ndarray (3, ) or (N, 3)) – Eigenvalues.

  • +
  • evecs (ndarray (3, 3) or (N, 3, 3)) – Eigenvectors.

  • +
  • signal (3D or 4D ndarray) – Predicted signal.

  • +
  • sigma (ndarray) – Standard deviation of the noise.

  • +
  • b_matrix (array (N, 7)) – Design matrix for DTI.

  • +
  • scales (float or ndarray (N, ), optional) – Cones of uncertainty size.

  • +
  • opacity (float, optional) – Takes values from 0 (fully transparent) to 1 (opaque), default(1.0).

  • +
+
+
Returns:
+

double_cone

+
+
Return type:
+

Actor

+
+
+
+ +
+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ +
+ On this page +
+ +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/reference/fury.actors.html b/v0.10.x/reference/fury.actors.html new file mode 100644 index 000000000..3d5242662 --- /dev/null +++ b/v0.10.x/reference/fury.actors.html @@ -0,0 +1,1126 @@ + + + + + + + + actors — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

actors#

+ + + +
+
+

Module: actors.odf_slicer#

+ + + + + + +

OdfSlicerActor(odfs, vertices, faces, ...[, ...])

VTK actor for visualizing slices of ODF field.

+
+
+

Module: actors.peak#

+ + + + + + +

PeakActor(directions, indices[, values, ...])

FURY actor for visualizing DWI peaks.

+
+
+

Module: actors.tensor#

+ + + + + + + + + + + + +

tensor_ellipsoid(centers, axes, lengths, ...)

Visualize one or many Tensor Ellipsoids with different features.

double_cone(centers, axes, angles, colors, ...)

Visualize one or many Double Cones with different features.

main_dir_uncertainty(evals, evecs, signal, ...)

Calculate the angle of the cone of uncertainty that represents the perturbation of the main eigenvector of the diffusion tensor matrix.

+
+

OdfSlicerActor#

+
+
+class fury.actors.odf_slicer.OdfSlicerActor(odfs, vertices, faces, indices, scale, norm, radial_scale, shape, global_cm, colormap, opacity, affine=None, B=None)[source]#
+

Bases: vtkActor

+

VTK actor for visualizing slices of ODF field.

+
+
Parameters:
+
    +
  • odfs (ndarray) – SF or SH coefficients 2-dimensional array.

  • +
  • vertices (ndarray) – The sphere vertices used for SH to SF projection.

  • +
  • faces (ndarray) – Indices of sphere vertices forming triangles. Should be +ordered clockwise (see fury.utils.fix_winding_order).

  • +
  • indices (tuple) – Indices given in tuple(x_indices, y_indices, z_indices) +format for mapping 2D ODF array to 3D voxel grid.

  • +
  • scale (float) – Multiplicative factor to apply to ODF amplitudes.

  • +
  • norm (bool) – Normalize SF amplitudes so that the maximum +ODF amplitude per voxel along a direction is 1.

  • +
  • radial_scale (bool) – Scale sphere points by ODF values.

  • +
  • global_cm (bool) – If True the colormap will be applied in all ODFs. If False +it will be applied individually at each voxel.

  • +
  • colormap (None or str) – The name of the colormap to use. Matplotlib colormaps are supported +(e.g., ‘inferno’). If None then a RGB colormap is used.

  • +
  • opacity (float) – Takes values from 0 (fully transparent) to 1 (opaque).

  • +
  • affine (array) – optional 4x4 transformation array from native +coordinates to world coordinates.

  • +
  • B (ndarray (n_coeffs, n_vertices)) – Optional SH to SF matrix for projecting odfs given in SH +coefficients on the sphere. If None, then the input is assumed +to be expressed in SF coefficients.

  • +
+
+
+
+
+__init__(odfs, vertices, faces, indices, scale, norm, radial_scale, shape, global_cm, colormap, opacity, affine=None, B=None)[source]#
+
+ +
+
+display(x=None, y=None, z=None)[source]#
+

Display a slice along x, y, or z axis.

+
+ +
+
+display_extent(x1, x2, y1, y2, z1, z2)[source]#
+

Set visible volume from x1 (inclusive) to x2 (inclusive), +y1 (inclusive) to y2 (inclusive), z1 (inclusive) to z2 +(inclusive).

+
+ +
+
+set_opacity(opacity)[source]#
+

Set opacity value of ODFs to display.

+
+ +
+
+slice_along_axis(slice_index, axis='zaxis')[source]#
+

Slice ODF field at given slice_index along axis +in [‘xaxis’, ‘yaxis’, zaxis’].

+
+ +
+
+update_sphere(vertices, faces, B)[source]#
+

Dynamically change the sphere used for SH to SF projection.

+
+ +
+ +
+
+

PeakActor#

+
+
+class fury.actors.peak.PeakActor(directions, indices, values=None, affine=None, colors=None, lookup_colormap=None, linewidth=1, symmetric=True)[source]#
+

Bases: vtkActor

+

FURY actor for visualizing DWI peaks.

+
+
Parameters:
+
    +
  • directions (ndarray) – Peak directions. The shape of the array should be (X, Y, Z, D, 3).

  • +
  • indices (tuple) – Indices given in tuple(x_indices, y_indices, z_indices) +format for mapping 2D ODF array to 3D voxel grid.

  • +
  • values (ndarray, optional) – Peak values. The shape of the array should be (X, Y, Z, D).

  • +
  • affine (array, optional) – 4x4 transformation array from native coordinates to world coordinates.

  • +
  • colors (None or string ('rgb_standard') or tuple (3D or 4D) or) –

    +
    array/ndarray (N, 3 or 4) or array/ndarray (K, 3 or 4) or

    array/ndarray(N, ) or array/ndarray (K, )

    +
    +
    +

    If None a standard orientation colormap is used for every line. +If one tuple of color is used. Then all streamlines will have the same +color. +If an array (N, 3 or 4) is given, where N is equal to the number of +points. Then every point is colored with a different RGB(A) color. +If an array (K, 3 or 4) is given, where K is equal to the number of +lines. Then every line is colored with a different RGB(A) color. +If an array (N, ) is given, where N is the number of points then these +are considered as the values to be used by the colormap. +If an array (K,) is given, where K is the number of lines then these +are considered as the values to be used by the colormap.

    +

  • +
  • lookup_colormap (vtkLookupTable, optional) – Add a default lookup table to the colormap. Default is None which calls +fury.actor.colormap_lookup_table().

  • +
  • linewidth (float, optional) – Line thickness. Default is 1.

  • +
  • symmetric (bool, optional) – If True, peaks are drawn for both peaks_dirs and -peaks_dirs. Else, +peaks are only drawn for directions given by peaks_dirs. Default is +True.

  • +
+
+
+
+
+__init__(directions, indices, values=None, affine=None, colors=None, lookup_colormap=None, linewidth=1, symmetric=True)[source]#
+
+ +
+
+property cross_section#
+
+ +
+
+display_cross_section(x, y, z)[source]#
+
+ +
+
+display_extent(x1, x2, y1, y2, z1, z2)[source]#
+
+ +
+
+property global_opacity#
+
+ +
+
+property high_ranges#
+
+ +
+
+property is_range#
+
+ +
+
+property linewidth#
+
+ +
+
+property low_ranges#
+
+ +
+
+property max_centers#
+
+ +
+
+property min_centers#
+
+ +
+ +
+
+

tensor_ellipsoid#

+
+
+fury.actors.tensor.tensor_ellipsoid(centers, axes, lengths, colors, scales, opacity)[source]#
+

Visualize one or many Tensor Ellipsoids with different features.

+
+
Parameters:
+
    +
  • centers (ndarray(N, 3)) – Tensor ellipsoid positions.

  • +
  • axes (ndarray (3, 3) or (N, 3, 3)) – Axes of the tensor ellipsoid.

  • +
  • lengths (ndarray (3, ) or (N, 3)) – Axes lengths.

  • +
  • colors (ndarray (N,3) or tuple (3,)) – R, G and B should be in the range [0, 1].

  • +
  • scales (float or ndarray (N, )) – Tensor ellipsoid size.

  • +
  • opacity (float) – Takes values from 0 (fully transparent) to 1 (opaque).

  • +
+
+
Returns:
+

box_actor

+
+
Return type:
+

Actor

+
+
+
+ +
+
+

double_cone#

+
+
+fury.actors.tensor.double_cone(centers, axes, angles, colors, scales, opacity)[source]#
+

Visualize one or many Double Cones with different features.

+
+
Parameters:
+
    +
  • centers (ndarray(N, 3)) – Cone positions.

  • +
  • axes (ndarray (3, 3) or (N, 3, 3)) – Axes of the cone.

  • +
  • angles (float or ndarray (N, )) – Angles of the cone.

  • +
  • colors (ndarray (N, 3) or tuple (3,)) – R, G and B should be in the range [0, 1].

  • +
  • scales (float or ndarray (N, )) – Cone size.

  • +
  • opacity (float) – Takes values from 0 (fully transparent) to 1 (opaque).

  • +
+
+
Returns:
+

box_actor

+
+
Return type:
+

Actor

+
+
+
+ +
+
+

main_dir_uncertainty#

+
+
+fury.actors.tensor.main_dir_uncertainty(evals, evecs, signal, sigma, b_matrix)[source]#
+

Calculate the angle of the cone of uncertainty that represents the +perturbation of the main eigenvector of the diffusion tensor matrix.

+
+
Parameters:
+
    +
  • evals (ndarray (3, ) or (N, 3)) – Eigenvalues.

  • +
  • evecs (ndarray (3, 3) or (N, 3, 3)) – Eigenvectors.

  • +
  • signal (3D or 4D ndarray) – Predicted signal.

  • +
  • sigma (ndarray) – Standard deviation of the noise.

  • +
  • b_matrix (array (N, 7)) – Design matrix for DTI.

  • +
+
+
Returns:
+

angles

+
+
Return type:
+

array

+
+
+

Notes

+

The uncertainty calculation is based on first-order matrix perturbation +analysis described in [1]. The idea is to estimate the variance of the +main eigenvector which corresponds to the main direction of diffusion, +directly from estimated D and its estimated covariance matrix +\(\Delta D\) (see [2], equation 4). The angle \(\Theta\) +between the perturbed principal eigenvector of D, +\(\epsilon_1+\Delta\epsilon_1\), and the estimated eigenvector +\(\epsilon_1\), measures the angular deviation of the main fiber +direction and can be approximated by:

+
+\[\Theta=tan^{-1}(\|\Delta\epsilon_1\|)\]
+

Giving way to a graphical construct for displaying both the main +eigenvector of D and its associated uncertainty, with the so-called +“uncertainty cone”.

+

References

+ +

diffusion tensor field maps resulting from MR noise. In 5th Scientific +Meeting of the ISMRM (Vol. 1740).

+ +

Variance of estimated DTI-derived parameters via first-order perturbation +methods. Magnetic Resonance in Medicine: An Official Journal of the +International Society for Magnetic Resonance in Medicine, 57(1), 141-149.

+
+ +
+
+
+ +
+ + +
+ +
+ + + + + +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/reference/fury.animation.html b/v0.10.x/reference/fury.animation.html new file mode 100644 index 000000000..8a3b01e8b --- /dev/null +++ b/v0.10.x/reference/fury.animation.html @@ -0,0 +1,3698 @@ + + + + + + + + animation — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

animation#

+ + + +
+
+

Module: animation.animation#

+ + + + + + + + + +

Animation([actors, length, loop, ...])

Keyframe animation class.

CameraAnimation([camera, length, loop, ...])

Camera keyframe animation class.

+
+
+

Module: animation.helpers#

+ + + + + + + + + + + + + + + + + + + + + + + + +

get_previous_timestamp(timestamps, current_time)

Return the maximum previous timestamp of a given time.

get_next_timestamp(timestamps, current_time)

Return the minimum next timestamp of a given time.

get_timestamps_from_keyframes(keyframes)

Return a sorted array of timestamps given dict of keyframes.

get_values_from_keyframes(keyframes)

Return an array of keyframes values sorted using timestamps.

get_time_tau(t, t0, t1)

Return a capped time tau between 0 and 1.

lerp(v0, v1, t0, t1, t)

Return a linearly interpolated value.

euclidean_distances(points)

Return a list of euclidean distances of a list of points or values.

+
+
+

Module: animation.interpolator#

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

spline_interpolator(keyframes, degree)

N-th degree spline interpolator for keyframes.

cubic_spline_interpolator(keyframes)

Cubic spline interpolator for keyframes.

step_interpolator(keyframes)

Step interpolator for keyframes.

linear_interpolator(keyframes)

Linear interpolator for keyframes.

cubic_bezier_interpolator(keyframes)

Cubic Bézier interpolator for keyframes.

slerp(keyframes)

Spherical based rotation keyframes interpolator.

color_interpolator(keyframes, rgb2space, ...)

Custom-space color interpolator.

hsv_color_interpolator(keyframes)

HSV interpolator for color keyframes

lab_color_interpolator(keyframes)

LAB interpolator for color keyframes

xyz_color_interpolator(keyframes)

XYZ interpolator for color keyframes

tan_cubic_spline_interpolator(keyframes)

Cubic spline interpolator for keyframes using tangents.

+
+
+

Module: animation.timeline#

+ + + + + + +

Timeline([animations, playback_panel, loop, ...])

Keyframe animation Timeline.

+
+

Animation#

+
+
+class fury.animation.animation.Animation(actors=None, length=None, loop=True, motion_path_res=None)[source]#
+

Bases: object

+

Keyframe animation class.

+

Animation is responsible for keyframe animations for a single or a +group of actors. +It’s used to handle multiple attributes and properties of Fury actors such +as transformations, color, and scale. +It also accepts custom data and interpolates them, such as temperature. +Linear interpolation is used by default to interpolate data between the +main keyframes.

+
+
+actors#
+

Actor/s to be animated.

+
+
Type:
+

Actor or list[Actor], optional, default: None

+
+
+
+ +
+
+length#
+

the fixed length of the animation. If set to None, the animation will +get its duration from the keyframes being set.

+
+
Type:
+

float or int, default: None, optional

+
+
+
+ +
+
+loop#
+

Whether to loop the animation (True) of play once (False).

+
+
Type:
+

bool, optional, default: True

+
+
+
+ +
+
+motion_path_res#
+

the number of line segments used to visualizer the animation’s motion +path (visualizing position).

+
+
Type:
+

int, default: None

+
+
+
+ +
+
+__init__(actors=None, length=None, loop=True, motion_path_res=None)[source]#
+
+ +
+
+property actors#
+

Return a list of actors.

+
+
Returns:
+

List of actors controlled by the Animation.

+
+
Return type:
+

list

+
+
+
+ +
+
+add(item)[source]#
+

Add an item to the Animation. +This item can be an Actor, Animation, list of Actors, or a list of +Animations.

+
+
Parameters:
+

item (Animation, vtkActor, list[Animation], or list[vtkActor]) – Actor/s to be animated by the Animation.

+
+
+
+ +
+
+add_actor(actor, static=False)[source]#
+

Add an actor or list of actors to the Animation.

+
+
Parameters:
+
    +
  • actor (vtkActor or list(vtkActor)) – Actor/s to be animated by the Animation.

  • +
  • static (bool) – Indicated whether the actor should be animated and controlled by +the animation or just a static actor that gets added to the scene +along with the Animation.

  • +
+
+
+
+ +
+
+add_child_animation(animation)[source]#
+

Add child Animation or list of Animations.

+
+
Parameters:
+

animation (Animation or list[Animation]) – Animation/s to be added.

+
+
+
+ +
+
+add_static_actor(actor)[source]#
+

Add an actor or list of actors as static actor/s which will not be +controlled nor animated by the Animation. All static actors will be +added to the scene when the Animation is added to the scene.

+
+
Parameters:
+

actor (vtkActor or list(vtkActor)) – Static actor/s.

+
+
+
+ +
+
+add_to_scene(scene)[source]#
+

Add this Animation, its actors and sub Animations to the scene

+
+ +
+
+add_to_scene_at(timestamp)[source]#
+

Set timestamp for adding Animation to scene event.

+
+
Parameters:
+

timestamp (float) – Timestamp of the event.

+
+
+
+ +
+
+add_update_callback(callback, prop=None)[source]#
+

Add a function to be called each time animation is updated +This function must accept only one argument which is the current value +of the named property.

+
+
Parameters:
+
    +
  • callback (callable) – The function to be called whenever the animation is updated.

  • +
  • prop (str, optional, default: None) – The name of the property.

  • +
+
+
+

Notes

+

If no attribute name was provided, current time of the animation will +be provided instead of current value for the callback.

+
+ +
+
+property child_animations: list[Animation]#
+

Return a list of child Animations.

+
+
Returns:
+

List of child Animations of this Animation.

+
+
Return type:
+

list

+
+
+
+ +
+
+property current_timestamp#
+

Return the current time of the animation.

+
+
Returns:
+

The current time of the animation.

+
+
Return type:
+

float

+
+
+
+ +
+
+property duration#
+

Return the duration of the animation.

+
+
Returns:
+

The duration of the animation.

+
+
Return type:
+

float

+
+
+
+ +
+
+get_color(t)[source]#
+

Return the interpolated color.

+
+
Parameters:
+

t (float) – The time to interpolate color value at.

+
+
Returns:
+

The interpolated color.

+
+
Return type:
+

ndarray(1, 3)

+
+
+
+ +
+
+get_current_value(attrib)[source]#
+

Return the value of an attribute at current time.

+
+
Parameters:
+

attrib (str) – The attribute name.

+
+
+
+ +
+
+get_keyframes(attrib=None)[source]#
+

Get a keyframe for a specific or all attributes.

+
+
Parameters:
+

attrib (str, optional, default: None) – The name of the attribute. +If None, all keyframes for all set attributes will be returned.

+
+
+
+ +
+
+get_opacity(t)[source]#
+

Return the opacity value.

+
+
Parameters:
+

t (float) – The time to interpolate opacity at.

+
+
Returns:
+

The interpolated opacity.

+
+
Return type:
+

ndarray(1, 1)

+
+
+
+ +
+
+get_position(t)[source]#
+

Return the interpolated position.

+
+
Parameters:
+

t (float) – The time to interpolate position at.

+
+
Returns:
+

The interpolated position.

+
+
Return type:
+

ndarray(1, 3)

+
+
+
+ +
+
+get_rotation(t, as_quat=False)[source]#
+

Return the interpolated rotation.

+
+
Parameters:
+
    +
  • t (float) – the time to interpolate rotation at.

  • +
  • as_quat (bool) – Returned rotation will be as quaternion if True.

  • +
+
+
Returns:
+

The interpolated rotation as Euler degrees by default.

+
+
Return type:
+

ndarray(1, 3)

+
+
+
+ +
+
+get_scale(t)[source]#
+

Return the interpolated scale.

+
+
Parameters:
+

t (float) – The time to interpolate scale at.

+
+
Returns:
+

The interpolated scale.

+
+
Return type:
+

ndarray(1, 3)

+
+
+
+ +
+
+get_value(attrib, timestamp)[source]#
+

Return the value of an attribute at any given timestamp.

+
+
Parameters:
+
    +
  • attrib (str) – The attribute name.

  • +
  • timestamp (float) – The timestamp to interpolate at.

  • +
+
+
+
+ +
+
+is_inside_scene_at(timestamp)[source]#
+

Check if the Animation is set to be inside the scene at a specific +timestamp.

+
+
Returns:
+

True if the Animation is set to be inside the scene at the given +timestamp.

+
+
Return type:
+

bool

+
+
+

Notes

+

If the parent Animation is set to be out of the scene at that time, all +of their child animations will be out of the scene as well.

+
+ +
+
+is_interpolatable(attrib)[source]#
+

Check whether a property is interpolatable.

+
+
Parameters:
+

attrib (str) – The name of the property.

+
+
Returns:
+

True if the property is interpolatable by the Animation.

+
+
Return type:
+

bool

+
+
+

Notes

+

True means that it’s safe to use Interpolator.interpolate(t) for the +specified property. And False means the opposite.

+
+ +
+
+property loop#
+

Get loop condition of the current animation.

+
+
Returns:
+

Whether the animation in loop mode (True) or play one mode (False).

+
+
Return type:
+

bool

+
+
+
+ +
+
+property parent_animation#
+

Return the hierarchical parent Animation for current Animation.

+
+
Returns:
+

The parent Animation.

+
+
Return type:
+

Animation

+
+
+
+ +
+
+remove_actor(actor)[source]#
+

Remove an actor from the Animation.

+
+
Parameters:
+

actor (vtkActor) – Actor to be removed from the Animation.

+
+
+
+ +
+
+remove_actors()[source]#
+

Remove all actors from the Animation

+
+ +
+
+remove_animations()[source]#
+

Remove all child Animations from the Animation

+
+ +
+
+remove_from_scene(scene)[source]#
+

Remove Animation, its actors and sub Animations from the scene

+
+ +
+
+remove_from_scene_at(timestamp)[source]#
+

Set timestamp for removing Animation to scene event.

+
+
Parameters:
+

timestamp (float) – Timestamp of the event.

+
+
+
+ +
+
+set_color(timestamp, color, **kwargs)[source]#
+

Set color keyframe at a specific timestamp.

+
+
Parameters:
+
    +
  • timestamp (float) – Timestamp of the keyframe

  • +
  • color (ndarray, shape(1, 3)) – Color keyframe value associated with the timestamp.

  • +
+
+
+
+ +
+
+set_color_interpolator(interpolator, is_evaluator=False)[source]#
+

Set the color interpolator.

+
+
Parameters:
+
    +
  • interpolator (callable) – The generator function of the interpolator that would handle +the color keyframes.

  • +
  • is_evaluator (bool, optional) – Specifies whether the interpolator is time-only based evaluation +function that does not depend on keyframes.

  • +
+
+
+

Examples

+
>>> Animation.set_color_interpolator(lab_color_interpolator)
+
+
+
+ +
+
+set_color_keyframes(keyframes)[source]#
+

Set a dict of color keyframes at once. +Should be in the following form: +{timestamp_1: color_1, timestamp_2: color_2}

+
+
Parameters:
+

keyframes (dict) – A dict with timestamps as keys and color as values.

+
+
+

Examples

+
>>> color_keyframes = {1, np.array([1, 0, 1]), 3, np.array([0, 0, 1])}
+>>> Animation.set_color_keyframes(color_keyframes)
+
+
+
+ +
+
+set_interpolator(attrib, interpolator, is_evaluator=False, **kwargs)[source]#
+

Set keyframes interpolator for a certain property

+
+
Parameters:
+
    +
  • attrib (str) – The name of the property.

  • +
  • interpolator (callable) – The generator function of the interpolator to be used to +interpolate/evaluate keyframes.

  • +
  • is_evaluator (bool, optional) – Specifies whether the interpolator is time-only based evaluation +function that does not depend on keyframes such as: +>>> def get_position(t): +>>> return np.array([np.sin(t), np.cos(t) * 5, 5])

  • +
  • spline_degree (int, optional) – The degree of the spline in case of setting a spline interpolator.

  • +
+
+
+

Notes

+

If an evaluator is used to set the values of actor’s properties such as +position, scale, color, rotation, or opacity, it has to return a value +with the same shape as the evaluated property, i.e.: for scale, it +has to return an array with shape 1x3, and for opacity, it has to +return a 1x1, an int, or a float value.

+

Examples

+
>>> Animation.set_interpolator('position', linear_interpolator)
+
+
+
>>> pos_fun = lambda t: np.array([np.sin(t), np.cos(t), 0])
+>>> Animation.set_interpolator('position', pos_fun)
+
+
+
+ +
+
+set_keyframe(attrib, timestamp, value, update_interpolator=True, **kwargs)[source]#
+

Set a keyframe for a certain attribute.

+
+
Parameters:
+
    +
  • attrib (str) – The name of the attribute.

  • +
  • timestamp (float) – Timestamp of the keyframe.

  • +
  • value (ndarray or float or bool) – Value of the keyframe at the given timestamp.

  • +
  • update_interpolator (bool, optional) – Interpolator will be reinitialized if True

  • +
  • in_cp (ndarray, shape (1, M), optional) – The in control point in case of using cubic Bézier interpolator.

  • +
  • out_cp (ndarray, shape (1, M), optional) – The out control point in case of using cubic Bézier interpolator.

  • +
  • in_tangent (ndarray, shape (1, M), optional) – The in tangent at that position for the cubic spline curve.

  • +
  • out_tangent (ndarray, shape (1, M), optional) – The out tangent at that position for the cubic spline curve.

  • +
+
+
+
+ +
+
+set_keyframes(attrib, keyframes)[source]#
+

Set multiple keyframes for a certain attribute.

+
+
Parameters:
+
    +
  • attrib (str) – The name of the attribute.

  • +
  • keyframes (dict) – A dict object containing keyframes to be set.

  • +
+
+
+

Notes

+

Keyframes can be on any of the following forms: +>>> key_frames_simple = {1: [1, 2, 1], 2: [3, 4, 5]} +>>> key_frames_bezier = {1: {‘value’: [1, 2, 1]}, +>>> 2: {‘value’: [3, 4, 5], ‘in_cp’: [1, 2, 3]}} +>>> pos_keyframes = {1: np.array([1, 2, 3]), 3: np.array([5, 5, 5])} +>>> Animation.set_keyframes(‘position’, pos_keyframes)

+
+ +
+
+set_opacity(timestamp, opacity, **kwargs)[source]#
+

Set opacity keyframe at a specific timestamp.

+
+
Parameters:
+
    +
  • timestamp (float) – Timestamp of the keyframe

  • +
  • opacity (ndarray, shape(1, 3)) – Opacity keyframe value associated with the timestamp.

  • +
+
+
+
+ +
+
+set_opacity_interpolator(interpolator, is_evaluator=False)[source]#
+

Set the opacity interpolator.

+
+
Parameters:
+
    +
  • interpolator (callable) – The generator function of the interpolator that would handle +the opacity keyframes.

  • +
  • is_evaluator (bool, optional) – Specifies whether the interpolator is time-only based evaluation +function that does not depend on keyframes.

  • +
+
+
+

Examples

+
>>> Animation.set_opacity_interpolator(step_interpolator)
+
+
+
+ +
+
+set_opacity_keyframes(keyframes)[source]#
+

Set a dict of opacity keyframes at once. +Should be in the following form: +{timestamp_1: opacity_1, timestamp_2: opacity_2}

+
+
Parameters:
+

keyframes (dict(float: ndarray, shape(1, 1) or float or int)) – A dict with timestamps as keys and opacities as values.

+
+
+

Notes

+

Opacity values should be between 0 and 1.

+

Examples

+
>>> opacity = {1, np.array([1, 1, 1]), 3, np.array([2, 2, 3])}
+>>> Animation.set_scale_keyframes(opacity)
+
+
+
+ +
+
+set_position(timestamp, position, **kwargs)[source]#
+

Set a position keyframe at a specific timestamp.

+
+
Parameters:
+
    +
  • timestamp (float) – Timestamp of the keyframe

  • +
  • position (ndarray, shape (1, 3)) – Position value

  • +
  • in_cp (float) – The control point in case of using cubic Bézier interpolator when +time exceeds this timestamp.

  • +
  • out_cp (float) – The control point in case of using cubic Bézier interpolator when +time precedes this timestamp.

  • +
  • in_tangent (ndarray, shape (1, M), optional) – The in tangent at that position for the cubic spline curve.

  • +
  • out_tangent (ndarray, shape (1, M), optional) – The out tangent at that position for the cubic spline curve.

  • +
+
+
+

Notes

+

in_cp and out_cp only needed when using the cubic bezier +interpolation method.

+
+ +
+
+set_position_interpolator(interpolator, is_evaluator=False, **kwargs)[source]#
+

Set the position interpolator.

+
+
Parameters:
+
    +
  • interpolator (callable) –

    +
    The generator function of the interpolator that would handle the

    position keyframes.

    +
    +
    +

  • +
  • is_evaluator (bool, optional) – Specifies whether the interpolator is time-only based evaluation +function that does not depend on keyframes.

  • +
  • degree (int) – The degree of the spline interpolation in case of setting +the spline_interpolator.

  • +
+
+
+

Examples

+
>>> Animation.set_position_interpolator(spline_interpolator, degree=5)
+
+
+
+ +
+
+set_position_keyframes(keyframes)[source]#
+

Set a dict of position keyframes at once. +Should be in the following form: +{timestamp_1: position_1, timestamp_2: position_2}

+
+
Parameters:
+

keyframes (dict) – A dict with timestamps as keys and positions as values.

+
+
+

Examples

+
>>> pos_keyframes = {1, np.array([0, 0, 0]), 3, np.array([50, 6, 6])}
+>>> Animation.set_position_keyframes(pos_keyframes)
+
+
+
+ +
+
+set_rotation(timestamp, rotation, **kwargs)[source]#
+

Set a rotation keyframe at a specific timestamp.

+
+
Parameters:
+
    +
  • timestamp (float) – Timestamp of the keyframe

  • +
  • rotation (ndarray, shape(1, 3) or shape(1, 4)) – Rotation data in euler degrees with shape(1, 3) or in quaternions +with shape(1, 4).

  • +
+
+
+

Notes

+

Euler rotations are executed by rotating first around Z then around X, +and finally around Y.

+
+ +
+
+set_rotation_as_vector(timestamp, vector, **kwargs)[source]#
+

Set a rotation keyframe at a specific timestamp.

+
+
Parameters:
+
    +
  • timestamp (float) – Timestamp of the keyframe

  • +
  • vector (ndarray, shape(1, 3)) – Directional vector that describes the rotation.

  • +
+
+
+
+ +
+
+set_rotation_interpolator(interpolator, is_evaluator=False)[source]#
+

Set the rotation interpolator .

+
+
Parameters:
+
    +
  • interpolator (callable) – The generator function of the interpolator that would handle the +rotation (orientation) keyframes.

  • +
  • is_evaluator (bool, optional) – Specifies whether the interpolator is time-only based evaluation +function that does not depend on keyframes.

  • +
+
+
+

Examples

+
>>> Animation.set_rotation_interpolator(slerp)
+
+
+
+ +
+
+set_scale(timestamp, scalar, **kwargs)[source]#
+

Set a scale keyframe at a specific timestamp.

+
+
Parameters:
+
    +
  • timestamp (float) – Timestamp of the keyframe

  • +
  • scalar (ndarray, shape(1, 3)) – Scale keyframe value associated with the timestamp.

  • +
+
+
+
+ +
+
+set_scale_interpolator(interpolator, is_evaluator=False)[source]#
+

Set the scale interpolator.

+
+
Parameters:
+
    +
  • interpolator (callable) – The generator function of the interpolator that would handle +the scale keyframes.

  • +
  • is_evaluator (bool, optional) – Specifies whether the interpolator is time-only based evaluation +function that does not depend on keyframes.

  • +
+
+
+

Examples

+
>>> Animation.set_scale_interpolator(step_interpolator)
+
+
+
+ +
+
+set_scale_keyframes(keyframes)[source]#
+

Set a dict of scale keyframes at once. +Should be in the following form: +{timestamp_1: scale_1, timestamp_2: scale_2}

+
+
Parameters:
+

keyframes (dict) – A dict with timestamps as keys and scales as values.

+
+
+

Examples

+
>>> scale_keyframes = {1, np.array([1, 1, 1]), 3, np.array([2, 2, 3])}
+>>> Animation.set_scale_keyframes(scale_keyframes)
+
+
+
+ +
+
+property static_actors#
+

Return a list of static actors.

+
+
Returns:
+

List of static actors.

+
+
Return type:
+

list

+
+
+
+ +
+
+property timeline#
+

Return the Timeline handling the current animation.

+
+
Returns:
+

The Timeline handling the current animation, None, if there is no +associated Timeline.

+
+
Return type:
+

Timeline

+
+
+
+ +
+
+update_animation(time=None)[source]#
+

Update the animation.

+

Update the animation at a certain time. This will make sure all +attributes are calculated and set to the actors at that given time.

+
+
Parameters:
+

time (float or int, optional, default: None) – The time to update animation at. If None, the animation will play +without adding it to a Timeline.

+
+
+
+ +
+
+update_duration()[source]#
+

Update and return the duration of the Animation.

+
+
Returns:
+

The duration of the animation.

+
+
Return type:
+

float

+
+
+
+ +
+
+update_motion_path()[source]#
+

Update motion path visualization actor

+
+ +
+ +
+
+

CameraAnimation#

+
+
+class fury.animation.animation.CameraAnimation(camera=None, length=None, loop=True, motion_path_res=None)[source]#
+

Bases: Animation

+

Camera keyframe animation class.

+

This is used for animating a single camera using a set of keyframes.

+
+
+camera#
+

Camera to be animated. If None, active camera will be animated.

+
+
Type:
+

Camera, optional, default: None

+
+
+
+ +
+
+length#
+

the fixed length of the animation. If set to None, the animation will +get its duration from the keyframes being set.

+
+
Type:
+

float or int, default: None, optional

+
+
+
+ +
+
+loop#
+

Whether to loop the animation (True) of play once (False).

+
+
Type:
+

bool, optional, default: True

+
+
+
+ +
+
+motion_path_res#
+

the number of line segments used to visualizer the animation’s motion +path (visualizing position).

+
+
Type:
+

int, default: None

+
+
+
+ +
+
+__init__(camera=None, length=None, loop=True, motion_path_res=None)[source]#
+
+ +
+
+property camera: vtkCamera#
+

Return the camera assigned to this animation.

+
+
Returns:
+

The camera that is being animated by this CameraAnimation.

+
+
Return type:
+

Camera

+
+
+
+ +
+
+get_focal(t)[source]#
+

Return the interpolated camera’s focal position.

+
+
Parameters:
+

t (float) – The time to interpolate at.

+
+
Returns:
+

The interpolated camera’s focal position.

+
+
Return type:
+

ndarray(1, 3)

+
+
+

Notes

+

The returned focal position does not necessarily reflect the current +camera’s focal position, but the expected one.

+
+ +
+
+get_view_up(t)[source]#
+

Return the interpolated camera’s view-up directional vector.

+
+
Parameters:
+

t (float) – The time to interpolate at.

+
+
Returns:
+

The interpolated camera view-up directional vector.

+
+
Return type:
+

ndarray(1, 3)

+
+
+

Notes

+

The returned focal position does not necessarily reflect the actual +camera view up directional vector, but the expected one.

+
+ +
+
+set_focal(timestamp, position, **kwargs)[source]#
+

Set camera’s focal position keyframe.

+
+
Parameters:
+
    +
  • timestamp (float) – The time to interpolate opacity at.

  • +
  • position (ndarray, shape(1, 3)) – The camera position

  • +
+
+
+
+ +
+
+set_focal_interpolator(interpolator, is_evaluator=False)[source]#
+

Set the camera focal position interpolator.

+
+
Parameters:
+
    +
  • interpolator (callable) – The generator function of the interpolator that would handle the +interpolation of the camera focal position keyframes.

  • +
  • is_evaluator (bool, optional) – Specifies whether the interpolator is time-only based evaluation +function that does not depend on keyframes.

  • +
+
+
+
+ +
+
+set_focal_keyframes(keyframes)[source]#
+

Set multiple camera focal position keyframes at once. +Should be in the following form: +{timestamp_1: focal_1, timestamp_2: focal_1, …}

+
+
Parameters:
+

keyframes (dict) – A dict with timestamps as keys and camera focal positions as +values.

+
+
+

Examples

+
>>> focal_pos = {0, np.array([1, 1, 1]), 3, np.array([20, 0, 0])}
+>>> CameraAnimation.set_focal_keyframes(focal_pos)
+
+
+
+ +
+
+set_view_up(timestamp, direction, **kwargs)[source]#
+

Set the camera view-up direction keyframe.

+
+
Parameters:
+
    +
  • timestamp (float) – The time to interpolate at.

  • +
  • direction (ndarray, shape(1, 3)) – The camera view-up direction

  • +
+
+
+
+ +
+
+set_view_up_interpolator(interpolator, is_evaluator=False)[source]#
+

Set the camera up-view vector animation interpolator.

+
+
Parameters:
+
    +
  • interpolator (callable) – The generator function of the interpolator that would handle the +interpolation of the camera view-up keyframes.

  • +
  • is_evaluator (bool, optional) – Specifies whether the interpolator is time-only based evaluation +function that does not depend on keyframes.

  • +
+
+
+
+ +
+
+set_view_up_keyframes(keyframes)[source]#
+

Set multiple camera view up direction keyframes. +Should be in the following form: +{timestamp_1: view_up_1, timestamp_2: view_up_2, …}

+
+
Parameters:
+

keyframes (dict) – A dict with timestamps as keys and camera view up vectors as +values.

+
+
+

Examples

+
>>> view_ups = {0, np.array([1, 0, 0]), 3, np.array([0, 1, 0])}
+>>> CameraAnimation.set_view_up_keyframes(view_ups)
+
+
+
+ +
+
+update_animation(time=None)[source]#
+

Update the camera animation.

+
+
Parameters:
+

time (float or int, optional, default: None) – The time to update the camera animation at. If None, the animation +will play.

+
+
+
+ +
+ +
+
+

get_previous_timestamp#

+
+
+fury.animation.helpers.get_previous_timestamp(timestamps, current_time, include_last=False)[source]#
+

Return the maximum previous timestamp of a given time.

+
+
Parameters:
+
    +
  • timestamps (ndarray) – Sorted list of timestamps.

  • +
  • current_time (float or int) – The time to get previous timestamp for.

  • +
  • include_last (bool, optional, default: False) – If True, even the last timestamp will be considered a valid previous +timestamp.

  • +
+
+
Returns:
+

The previous timestamp

+
+
Return type:
+

float or int

+
+
+
+ +
+
+

get_next_timestamp#

+
+
+fury.animation.helpers.get_next_timestamp(timestamps, current_time, include_first=False)[source]#
+

Return the minimum next timestamp of a given time.

+
+
Parameters:
+
    +
  • timestamps (ndarray) – Sorted list of timestamps.

  • +
  • current_time (float or int) – The time to get previous timestamp for.

  • +
  • include_first (bool, optional, default: False) – If True, even the first timestamp will be considered a valid next +timestamp.

  • +
+
+
Returns:
+

The next timestamp

+
+
Return type:
+

float or int

+
+
+
+ +
+
+

get_timestamps_from_keyframes#

+
+
+fury.animation.helpers.get_timestamps_from_keyframes(keyframes)[source]#
+

Return a sorted array of timestamps given dict of keyframes.

+
+
Parameters:
+

keyframes (dict) – keyframes dict that contains timestamps as keys.

+
+
Returns:
+

Array of sorted timestamps extracted from the keyframes.

+
+
Return type:
+

ndarray

+
+
+
+ +
+
+

get_values_from_keyframes#

+
+
+fury.animation.helpers.get_values_from_keyframes(keyframes)[source]#
+

Return an array of keyframes values sorted using timestamps.

+
+
Parameters:
+

keyframes (dict) – keyframes dict that contains timestamps as keys and data as values.

+
+
Returns:
+

Array of sorted values extracted from the keyframes.

+
+
Return type:
+

ndarray

+
+
+
+ +
+
+

get_time_tau#

+
+
+fury.animation.helpers.get_time_tau(t, t0, t1)[source]#
+

Return a capped time tau between 0 and 1.

+
+
Parameters:
+
    +
  • t (float or int) – Current time to calculate tau for.

  • +
  • t0 (float or int) – Lower timestamp of the time period.

  • +
  • t1 (float or int) – Higher timestamp of the time period.

  • +
+
+
Returns:
+

The time tau

+
+
Return type:
+

float

+
+
+
+ +
+
+

lerp#

+
+
+fury.animation.helpers.lerp(v0, v1, t0, t1, t)[source]#
+

Return a linearly interpolated value.

+
+
Parameters:
+
    +
  • v0 (ndarray or float or int.) – The first value

  • +
  • v1 (ndarray or float or int.) – The second value

  • +
  • t (float or int) – Current time to interpolate at.

  • +
  • t0 (float or int) – Timestamp associated with v0.

  • +
  • t1 (float or int) – Timestamp associated with v1.

  • +
+
+
Returns:
+

The interpolated value

+
+
Return type:
+

ndarray or float

+
+
+
+ +
+
+

euclidean_distances#

+
+
+fury.animation.helpers.euclidean_distances(points)[source]#
+

Return a list of euclidean distances of a list of points or values.

+
+
Parameters:
+

points (ndarray) – Array of points or valued to calculate euclidean distances between.

+
+
Returns:
+

A List of euclidean distance between each consecutive points or values.

+
+
Return type:
+

list

+
+
+
+ +
+
+

spline_interpolator#

+
+
+fury.animation.interpolator.spline_interpolator(keyframes, degree)[source]#
+

N-th degree spline interpolator for keyframes.

+

This is a general n-th degree spline interpolator to be used for any shape +of keyframes data.

+
+
Parameters:
+

keyframes (dict) – Keyframe data containing timestamps and values to form the spline +curve. Data should be on the following format: +>>> {1: {‘value’: np.array([…])}, 2: {‘value’: np.array([…])}}

+
+
Returns:
+

The interpolation function that take time and return interpolated +value at that time.

+
+
Return type:
+

function

+
+
+
+ +
+
+

cubic_spline_interpolator#

+
+
+fury.animation.interpolator.cubic_spline_interpolator(keyframes)[source]#
+

Cubic spline interpolator for keyframes.

+

This is a general cubic spline interpolator to be used for any shape of +keyframes data.

+
+
Parameters:
+

keyframes (dict) – Keyframe data containing timestamps and values to form the cubic spline +curve.

+
+
Returns:
+

The interpolation function that take time and return interpolated +value at that time.

+
+
Return type:
+

function

+
+
+
+

See also

+

spline_interpolator

+
+
+ +
+
+

step_interpolator#

+
+
+fury.animation.interpolator.step_interpolator(keyframes)[source]#
+

Step interpolator for keyframes.

+

This is a simple step interpolator to be used for any shape of +keyframes data.

+
+
Parameters:
+

keyframes (dict) – Keyframe data containing timestamps and values to form the spline

+
+
Returns:
+

The interpolation function that take time and return interpolated +value at that time.

+
+
Return type:
+

function

+
+
+
+ +
+
+

linear_interpolator#

+
+
+fury.animation.interpolator.linear_interpolator(keyframes)[source]#
+

Linear interpolator for keyframes.

+

This is a general linear interpolator to be used for any shape of +keyframes data.

+
+
Parameters:
+

keyframes (dict) – Keyframe data to be linearly interpolated.

+
+
Returns:
+

The interpolation function that take time and return interpolated +value at that time.

+
+
Return type:
+

function

+
+
+
+ +
+
+

cubic_bezier_interpolator#

+
+
+fury.animation.interpolator.cubic_bezier_interpolator(keyframes)[source]#
+

Cubic Bézier interpolator for keyframes.

+

This is a general cubic Bézier interpolator to be used for any shape of +keyframes data.

+
+
Parameters:
+

keyframes (dict) – Keyframes to be interpolated at any time.

+
+
Returns:
+

The interpolation function that take time and return interpolated +value at that time.

+
+
Return type:
+

function

+
+
+

Notes

+

If no control points are set in the keyframes, The cubic +Bézier interpolator will almost behave as a linear interpolator.

+
+ +
+
+

slerp#

+
+
+fury.animation.interpolator.slerp(keyframes)[source]#
+

Spherical based rotation keyframes interpolator.

+

A rotation interpolator to be used for rotation keyframes.

+
+
Parameters:
+

keyframes (dict) – Rotation keyframes to be interpolated at any time.

+
+
Returns:
+

The interpolation function that take time and return interpolated +value at that time.

+
+
Return type:
+

function

+
+
+

Notes

+

Rotation keyframes must be in the form of quaternions.

+
+ +
+
+

color_interpolator#

+
+
+fury.animation.interpolator.color_interpolator(keyframes, rgb2space, space2rgb)[source]#
+

Custom-space color interpolator.

+

Interpolate values linearly inside a custom color space.

+
+
Parameters:
+
    +
  • keyframes (dict) – Rotation keyframes to be interpolated at any time.

  • +
  • rgb2space (function) –

    +
    A functions that take color value in rgb and return that color

    converted to the targeted space.

    +
    +
    +

  • +
  • space2rgb (function) – A functions that take color value in the targeted space and returns +that color in rgb space.

  • +
+
+
Returns:
+

The interpolation function that take time and return interpolated +value at that time.

+
+
Return type:
+

function

+
+
+
+ +
+
+

hsv_color_interpolator#

+
+
+fury.animation.interpolator.hsv_color_interpolator(keyframes)[source]#
+

HSV interpolator for color keyframes

+
+

See also

+

color_interpolator

+
+
+ +
+
+

lab_color_interpolator#

+
+
+fury.animation.interpolator.lab_color_interpolator(keyframes)[source]#
+

LAB interpolator for color keyframes

+
+

See also

+

color_interpolator

+
+
+ +
+
+

xyz_color_interpolator#

+
+
+fury.animation.interpolator.xyz_color_interpolator(keyframes)[source]#
+

XYZ interpolator for color keyframes

+
+

See also

+

color_interpolator

+
+
+ +
+
+

tan_cubic_spline_interpolator#

+
+
+fury.animation.interpolator.tan_cubic_spline_interpolator(keyframes)[source]#
+

Cubic spline interpolator for keyframes using tangents. +glTF contains additional tangent information for the cubic spline +interpolator.

+
+
Parameters:
+

keyframes (dict) – Keyframe data containing timestamps and values to form the cubic spline +curve.

+
+
Returns:
+

The interpolation function that take time and return interpolated +value at that time.

+
+
Return type:
+

function

+
+
+
+ +
+
+

Timeline#

+
+
+class fury.animation.timeline.Timeline(animations=None, playback_panel=False, loop=True, length=None)[source]#
+

Bases: object

+

Keyframe animation Timeline.

+

Timeline is responsible for handling the playback of keyframes animations. +It has multiple playback options which makes it easy +to control the playback, speed, state of the animation with/without a GUI +playback panel.

+
+
+animations#
+

Actor/s to be animated directly by the Timeline (main Animation).

+
+
Type:
+

Animation or list[Animation], optional, default: None

+
+
+
+ +
+
+playback_panel#
+

If True, the timeline will have a playback panel set, which can be used +to control the playback of the timeline.

+
+
Type:
+

bool, optional

+
+
+
+ +
+
+length#
+
+
the fixed length of the timeline. If set to None, the timeline will get

its length from the animations that it controls automatically.

+
+
+
+
Type:
+

float or int, default: None, optional

+
+
+
+ +
+
+loop#
+

Whether loop playing the timeline or play once.

+
+
Type:
+

bool, optional

+
+
+
+ +
+
+__init__(animations=None, playback_panel=False, loop=True, length=None)[source]#
+
+ +
+
+add_animation(animation)[source]#
+

Add Animation or list of Animations.

+
+
Parameters:
+

animation (Animation or list[Animation] or tuple[Animation]) – Animation/s to be added.

+
+
+
+ +
+
+add_to_scene(scene)[source]#
+

Add Timeline and all of its Animations to the scene

+
+ +
+
+property animations: list[Animation]#
+

Return a list of Animations.

+
+
Returns:
+

List of Animations controlled by the timeline.

+
+
Return type:
+

list

+
+
+
+ +
+
+property current_timestamp#
+

Get current timestamp of the Timeline.

+
+
Returns:
+

The current time of the Timeline.

+
+
Return type:
+

float

+
+
+
+ +
+
+property duration#
+

Return the duration of the Timeline.

+
+
Returns:
+

The duration of the Timeline.

+
+
Return type:
+

float

+
+
+
+ +
+
+property has_playback_panel#
+

Return whether the Timeline has a playback panel.

+
+
Returns:
+

bool

+
+
Return type:
+

‘True’ if the Timeline has a playback panel. otherwise, ‘False’

+
+
+
+ +
+
+property loop#
+

Get loop condition of the timeline.

+
+
Returns:
+

Whether the playback is in loop mode (True) or play one mode +(False).

+
+
Return type:
+

bool

+
+
+
+ +
+
+pause()[source]#
+

Pause the animation

+
+ +
+
+property paused#
+

Return whether the Timeline is paused.

+
+
Returns:
+

True if the Timeline is paused.

+
+
Return type:
+

bool

+
+
+
+ +
+
+play()[source]#
+

Play the animation

+
+ +
+
+property playing#
+

Return whether the Timeline is playing.

+
+
Returns:
+

True if the Timeline is playing.

+
+
Return type:
+

bool

+
+
+
+ +
+
+record(fname=None, fps=30, speed=1.0, size=(900, 768), order_transparent=True, multi_samples=8, max_peels=4, show_panel=False)[source]#
+

Record the animation

+
+
Parameters:
+
    +
  • fname (str, optional) – The file name. Save a GIF file if name ends with ‘.gif’, or mp4 +video if name ends with’.mp4’. +If None, this method will only return an array of frames.

  • +
  • fps (int, optional) – The number of frames per second of the record.

  • +
  • size ((int, int)) – (width, height) of the window. Default is (900, 768).

  • +
  • speed (float, optional, default 1.0) – The speed of the animation.

  • +
  • order_transparent (bool, optional) – Default False. Use depth peeling to sort transparent objects. +If True also enables anti-aliasing.

  • +
  • multi_samples (int, optional) – Number of samples for anti-aliasing (Default 8). +For no anti-aliasing use 0.

  • +
  • max_peels (int, optional) – Maximum number of peels for depth peeling (Default 4).

  • +
  • show_panel (bool, optional, default False) – Controls whether to show the playback (if True) panel of hide it +(if False)

  • +
+
+
Returns:
+

The recorded frames.

+
+
Return type:
+

ndarray

+
+
+

Notes

+

It’s recommended to use 50 or 30 FPS while recording to a GIF file.

+
+ +
+
+remove_from_scene(scene)[source]#
+

Remove Timeline and all of its Animations to the scene

+
+ +
+
+restart()[source]#
+

Restart the animation

+
+ +
+
+seek(timestamp)[source]#
+

Set the current timestamp of the Timeline.

+
+
Parameters:
+

timestamp (float) – The time to seek.

+
+
+
+ +
+
+seek_percent(percent)[source]#
+

Seek a percentage of the Timeline’s final timestamp.

+
+
Parameters:
+

percent (float) – Value from 1 to 100.

+
+
+
+ +
+
+property speed#
+

Return the speed of the timeline’s playback.

+
+
Returns:
+

The speed of the timeline’s playback.

+
+
Return type:
+

float

+
+
+
+ +
+
+stop()[source]#
+

Stop the animation

+
+ +
+
+property stopped#
+

Return whether the Timeline is stopped.

+
+
Returns:
+

True if Timeline is stopped.

+
+
Return type:
+

bool

+
+
+
+ +
+
+update(force=False)[source]#
+

Update the timeline.

+

Update the Timeline and all the animations that it controls. As well as +the playback of the Timeline (if exists).

+
+
Parameters:
+

force (bool, optional, default: False) – If True, the timeline will update even when the timeline is paused +or stopped and hence, more resources will be used.

+
+
+
+ +
+
+update_duration()[source]#
+

Update and return the duration of the Timeline.

+
+
Returns:
+

The duration of the Timeline.

+
+
Return type:
+

float

+
+
+
+ +
+ +
+
+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ +
+ On this page +
+ +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/reference/fury.colormap.html b/v0.10.x/reference/fury.colormap.html new file mode 100644 index 000000000..37671f61e --- /dev/null +++ b/v0.10.x/reference/fury.colormap.html @@ -0,0 +1,2208 @@ + + + + + + + + colormap — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

colormap#

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

colormap_lookup_table([scale_range, ...])

Lookup table for the colormap.

cc(na, nd)

ss(na, nd)

boys2rgb(v)

Boys 2 rgb cool colormap

orient2rgb(v)

Get Standard orientation 2 rgb colormap.

line_colors(streamlines[, cmap])

Create colors for streamlines to be used in actor.line.

get_cmap(name)

Make a callable, similar to maptlotlib.pyplot.get_cmap.

create_colormap(v[, name, auto])

Create colors from a specific colormap and return it as an array of shape (N,3) where every row gives the corresponding r,g,b value.

distinguishable_colormap([bg, exclude, ...])

Generate colors that are maximally perceptually distinct.

hex_to_rgb(color)

Converts Hexadecimal color code to rgb()

rgb2hsv(rgb)

RGB to HSV color space conversion.

hsv2rgb(hsv)

HSV to RGB color space conversion.

xyz_from_rgb

ndarray(shape, dtype=float, buffer=None, offset=0,

rgb_from_xyz

ndarray(shape, dtype=float, buffer=None, offset=0,

xyz2rgb(xyz)

XYZ to RGB color space conversion.

rgb2xyz(rgb)

RGB to XYZ color space conversion.

get_xyz_coords(illuminant, observer)

Get the XYZ coordinates of the given illuminant and observer [1]_.

xyz2lab(xyz[, illuminant, observer])

XYZ to CIE-LAB color space conversion.

lab2xyz(lab[, illuminant, observer])

CIE-LAB to XYZcolor space conversion.

rgb2lab(rgb[, illuminant, observer])

Conversion from the sRGB color space (IEC 61966-2-1:1999) to the CIE Lab colorspace under the given illuminant and observer.

lab2rgb(lab[, illuminant, observer])

Lab to RGB color space conversion.

+
+

colormap_lookup_table#

+
+
+fury.colormap.colormap_lookup_table(scale_range=(0, 1), hue_range=(0.8, 0), saturation_range=(1, 1), value_range=(0.8, 0.8))[source]#
+

Lookup table for the colormap.

+
+
Parameters:
+
    +
  • scale_range (tuple) – It can be anything e.g. (0, 1) or (0, 255). Usually it is the minimum +and maximum value of your data. Default is (0, 1).

  • +
  • hue_range (tuple of floats) – HSV values (min 0 and max 1). Default is (0.8, 0).

  • +
  • saturation_range (tuple of floats) – HSV values (min 0 and max 1). Default is (1, 1).

  • +
  • value_range (tuple of floats) – HSV value (min 0 and max 1). Default is (0.8, 0.8).

  • +
+
+
Returns:
+

lookup_table

+
+
Return type:
+

LookupTable

+
+
+
+ +
+
+

cc#

+
+
+fury.colormap.cc(na, nd)[source]#
+
+ +
+
+

ss#

+
+
+fury.colormap.ss(na, nd)[source]#
+
+ +
+
+

boys2rgb#

+
+
+fury.colormap.boys2rgb(v)[source]#
+

Boys 2 rgb cool colormap

+

Maps a given field of undirected lines (line field) to rgb +colors using Boy’s Surface immersion of the real projective +plane. +Boy’s Surface is one of the three possible surfaces +obtained by gluing a Mobius strip to the edge of a disk. +The other two are the crosscap and Roman surface, +Steiner surfaces that are homeomorphic to the real +projective plane (Pinkall 1986). The Boy’s surface +is the only 3D immersion of the projective plane without +singularities. +Visit http://www.cs.brown.edu/~cad/rp2coloring for further details. +Cagatay Demiralp, 9/7/2008.

+

Code was initially in matlab and was rewritten in Python for fury by +the FURY Team. Thank you Cagatay for putting this online.

+
+
Parameters:
+

v (array, shape (N, 3) of unit vectors (e.g., principal eigenvectors of) – tensor data) representing one of the two directions of the +undirected lines in a line field.

+
+
Returns:
+

c – given in V.

+
+
Return type:
+

array, shape (N, 3) matrix of rgb colors corresponding to the vectors

+
+
+

Examples

+
>>> from fury import colormap
+>>> v = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]])
+>>> c = colormap.boys2rgb(v)
+
+
+
+ +
+
+

orient2rgb#

+
+
+fury.colormap.orient2rgb(v)[source]#
+

Get Standard orientation 2 rgb colormap.

+

v : array, shape (N, 3) of vectors not necessarily normalized

+
+
Returns:
+

c – given in V.

+
+
Return type:
+

array, shape (N, 3) matrix of rgb colors corresponding to the vectors

+
+
+

Examples

+
>>> from fury import colormap
+>>> v = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]])
+>>> c = colormap.orient2rgb(v)
+
+
+
+ +
+
+

line_colors#

+
+
+fury.colormap.line_colors(streamlines, cmap='rgb_standard')[source]#
+

Create colors for streamlines to be used in actor.line.

+
+
Parameters:
+
    +
  • streamlines (sequence of ndarrays) –

  • +
  • cmap (('rgb_standard', 'boys_standard')) –

  • +
+
+
Returns:
+

colors

+
+
Return type:
+

ndarray

+
+
+
+ +
+
+

get_cmap#

+
+
+fury.colormap.get_cmap(name)[source]#
+

Make a callable, similar to maptlotlib.pyplot.get_cmap.

+
+ +
+
+

create_colormap#

+
+
+fury.colormap.create_colormap(v, name='plasma', auto=True)[source]#
+

Create colors from a specific colormap and return it +as an array of shape (N,3) where every row gives the corresponding +r,g,b value. The colormaps we use are similar with those of matplotlib.

+
+
Parameters:
+
    +
  • v ((N,) array) – vector of values to be mapped in RGB colors according to colormap

  • +
  • name (str.) – Name of the colormap. Currently implemented: ‘jet’, ‘blues’, +‘accent’, ‘bone’ and matplotlib colormaps if you have matplotlib +installed. For example, we suggest using ‘plasma’, ‘viridis’ or +‘inferno’. ‘jet’ is popular but can be often misleading and we will +deprecate it the future.

  • +
  • auto (bool,) – if auto is True then v is interpolated to [0, 1] from v.min() +to v.max()

  • +
+
+
+

Notes

+

FURY supports a few colormaps for those who do not use Matplotlib, for +more colormaps consider downloading Matplotlib (see matplotlib.org).

+
+ +
+
+

distinguishable_colormap#

+
+
+fury.colormap.distinguishable_colormap(bg=(0, 0, 0), exclude=[], nb_colors=None)[source]#
+

Generate colors that are maximally perceptually distinct.

+

This function generates a set of colors which are distinguishable +by reference to the “Lab” color space, which more closely matches +human color perception than RGB. Given an initial large list of possible +colors, it iteratively chooses the entry in the list that is farthest (in +Lab space) from all previously-chosen entries. While this “greedy” +algorithm does not yield a global maximum, it is simple and efficient. +Moreover, the sequence of colors is consistent no matter how many you +request, which facilitates the users’ ability to learn the color order +and avoids major changes in the appearance of plots when adding or +removing lines.

+
+
Parameters:
+
    +
  • bg (tuple (optional)) – Background RGB color, to make sure that your colors are also +distinguishable from the background. Default: (0, 0, 0).

  • +
  • exclude (list of tuples (optional)) – Additional RGB colors to be distinguishable from.

  • +
  • nb_colors (int (optional)) – Number of colors desired. Default: generate as many colors as needed.

  • +
+
+
Returns:
+

If nb_colors is provided, returns a list of RBG colors. +Otherwise, yields the next RBG color maximally perceptually +distinct from previous ones.

+
+
Return type:
+

iterable of ndarray

+
+
+

Examples

+
>>> from dipy.viz.colormap import distinguishable_colormap
+>>> # Generate 5 colors
+>>> [c for i, c in zip(range(5), distinguishable_colormap())]
+[array([ 0.,  1.,  0.]),
+ array([ 1.,  0.,  1.]),
+ array([ 1.        ,  0.75862069,  0.03448276]),
+ array([ 0.        ,  1.        ,  0.89655172]),
+ array([ 0.        ,  0.17241379,  1.        ])]
+
+
+

Notes

+

Code was initially in matlab and was rewritten in Python for dipy by +the Dipy Team. Thank you Tim Holy for putting this online. Visit +http://www.mathworks.com/matlabcentral/fileexchange/29702 for the +original implementation (v1.2), 14 Dec 2010 (Updated 07 Feb 2011).

+
+ +
+
+

hex_to_rgb#

+
+
+fury.colormap.hex_to_rgb(color)[source]#
+

Converts Hexadecimal color code to rgb()

+

color : string containing hexcode of color (can also start with a hash)

+
+
Returns:
+

c – hexcode string given in color.

+
+
Return type:
+

array, shape(1, 3) matrix of rbg colors corresponding to the

+
+
+

Examples

+
>>> from fury import colormap
+>>> color = "#FFFFFF"
+>>> c = colormap.hex_to_rgb(color)
+
+
+
>>> from fury import colormap
+>>> color = "FFFFFF"
+>>> c = colormap.hex_to_rgb(color)
+
+
+
+ +
+
+

rgb2hsv#

+
+
+fury.colormap.rgb2hsv(rgb)[source]#
+

RGB to HSV color space conversion.

+
+
Parameters:
+

rgb ((..., 3, ...) array_like) – The image in RGB format. By default, the final dimension denotes +channels.

+
+
Returns:
+

out – The image in HSV format. Same dimensions as input.

+
+
Return type:
+

(…, 3, …) ndarray

+
+
+

Notes

+

Original Implementation from scikit-image package. +it can be found at: +scikit-image/scikit-image +This implementation might have been modified.

+
+ +
+
+

hsv2rgb#

+
+
+fury.colormap.hsv2rgb(hsv)[source]#
+

HSV to RGB color space conversion.

+
+
Parameters:
+

hsv ((..., 3, ...) array_like) – The image in HSV format. By default, the final dimension denotes +channels.

+
+
Returns:
+

out – The image in RGB format. Same dimensions as input.

+
+
Return type:
+

(…, 3, …) ndarray

+
+
+

Notes

+

Original Implementation from scikit-image package. +it can be found at: +scikit-image/scikit-image +This implementation might have been modified.

+
+ +
+
+

xyz_from_rgb#

+
+
+fury.colormap.xyz_from_rgb()#
+
+
ndarray(shape, dtype=float, buffer=None, offset=0,

strides=None, order=None)

+
+
+

An array object represents a multidimensional, homogeneous array +of fixed-size items. An associated data-type object describes the +format of each element in the array (its byte-order, how many bytes it +occupies in memory, whether it is an integer, a floating point number, +or something else, etc.)

+

Arrays should be constructed using array, zeros or empty (refer +to the See Also section below). The parameters given here refer to +a low-level method (ndarray(…)) for instantiating an array.

+

For more information, refer to the numpy module and examine the +methods and attributes of an array.

+
+
Parameters:
+
    +
  • below) ((for the __new__ method; see Notes) –

  • +
  • shape (tuple of ints) – Shape of created array.

  • +
  • dtype (data-type, optional) – Any object that can be interpreted as a numpy data type.

  • +
  • buffer (object exposing buffer interface, optional) – Used to fill the array with data.

  • +
  • offset (int, optional) – Offset of array data in buffer.

  • +
  • strides (tuple of ints, optional) – Strides of data in memory.

  • +
  • order ({'C', 'F'}, optional) – Row-major (C-style) or column-major (Fortran-style) order.

  • +
+
+
+
+
+fury.colormap.T#
+

Transpose of the array.

+
+
Type:
+

ndarray

+
+
+
+ +
+
+fury.colormap.data#
+

The array’s elements, in memory.

+
+
Type:
+

buffer

+
+
+
+ +
+
+fury.colormap.dtype#
+

Describes the format of the elements in the array.

+
+
Type:
+

dtype object

+
+
+
+ +
+
+fury.colormap.flags#
+

Dictionary containing information related to memory use, e.g., +‘C_CONTIGUOUS’, ‘OWNDATA’, ‘WRITEABLE’, etc.

+
+
Type:
+

dict

+
+
+
+ +
+
+fury.colormap.flat#
+

Flattened version of the array as an iterator. The iterator +allows assignments, e.g., x.flat = 3 (See ndarray.flat for +assignment examples; TODO).

+
+
Type:
+

numpy.flatiter object

+
+
+
+ +
+
+fury.colormap.imag#
+

Imaginary part of the array.

+
+
Type:
+

ndarray

+
+
+
+ +
+
+fury.colormap.real#
+

Real part of the array.

+
+
Type:
+

ndarray

+
+
+
+ +
+
+fury.colormap.size#
+

Number of elements in the array.

+
+
Type:
+

int

+
+
+
+ +
+
+fury.colormap.itemsize#
+

The memory use of each array element in bytes.

+
+
Type:
+

int

+
+
+
+ +
+
+fury.colormap.nbytes#
+

The total number of bytes required to store the array data, +i.e., itemsize * size.

+
+
Type:
+

int

+
+
+
+ +
+
+fury.colormap.ndim#
+

The array’s number of dimensions.

+
+
Type:
+

int

+
+
+
+ +
+
+fury.colormap.shape#
+

Shape of the array.

+
+
Type:
+

tuple of ints

+
+
+
+ +
+
+fury.colormap.strides#
+

The step-size required to move from one element to the next in +memory. For example, a contiguous (3, 4) array of type +int16 in C-order has strides (8, 2). This implies that +to move from element to element in memory requires jumps of 2 bytes. +To move from row-to-row, one needs to jump 8 bytes at a time +(2 * 4).

+
+
Type:
+

tuple of ints

+
+
+
+ +
+
+fury.colormap.ctypes#
+

Class containing properties of the array needed for interaction +with ctypes.

+
+
Type:
+

ctypes object

+
+
+
+ +
+
+fury.colormap.base#
+

If the array is a view into another array, that array is its base +(unless that array is also a view). The base array is where the +array data is actually stored.

+
+
Type:
+

ndarray

+
+
+
+ +
+

See also

+
+
array

Construct an array.

+
+
zeros

Create an array, each element of which is zero.

+
+
empty

Create an array, but leave its allocated memory unchanged (i.e., it contains “garbage”).

+
+
dtype

Create a data-type.

+
+
numpy.typing.NDArray

An ndarray alias generic w.r.t. its dtype.type <numpy.dtype.type>.

+
+
+
+

Notes

+

There are two modes of creating an array using __new__:

+
    +
  1. If buffer is None, then only shape, dtype, and order +are used.

  2. +
  3. If buffer is an object exposing the buffer interface, then +all keywords are interpreted.

  4. +
+

No __init__ method is needed because the array is fully initialized +after the __new__ method.

+

Examples

+

These examples illustrate the low-level ndarray constructor. Refer +to the See Also section above for easier ways of constructing an +ndarray.

+

First mode, buffer is None:

+
>>> np.ndarray(shape=(2,2), dtype=float, order='F')
+array([[0.0e+000, 0.0e+000], # random
+       [     nan, 2.5e-323]])
+
+
+

Second mode:

+
>>> np.ndarray((2,), buffer=np.array([1,2,3]),
+...            offset=np.int_().itemsize,
+...            dtype=int) # offset = 1*itemsize, i.e. skip first element
+array([2, 3])
+
+
+
+ +
+
+

rgb_from_xyz#

+
+
+fury.colormap.rgb_from_xyz()#
+
+
ndarray(shape, dtype=float, buffer=None, offset=0,

strides=None, order=None)

+
+
+

An array object represents a multidimensional, homogeneous array +of fixed-size items. An associated data-type object describes the +format of each element in the array (its byte-order, how many bytes it +occupies in memory, whether it is an integer, a floating point number, +or something else, etc.)

+

Arrays should be constructed using array, zeros or empty (refer +to the See Also section below). The parameters given here refer to +a low-level method (ndarray(…)) for instantiating an array.

+

For more information, refer to the numpy module and examine the +methods and attributes of an array.

+
+
Parameters:
+
    +
  • below) ((for the __new__ method; see Notes) –

  • +
  • shape (tuple of ints) – Shape of created array.

  • +
  • dtype (data-type, optional) – Any object that can be interpreted as a numpy data type.

  • +
  • buffer (object exposing buffer interface, optional) – Used to fill the array with data.

  • +
  • offset (int, optional) – Offset of array data in buffer.

  • +
  • strides (tuple of ints, optional) – Strides of data in memory.

  • +
  • order ({'C', 'F'}, optional) – Row-major (C-style) or column-major (Fortran-style) order.

  • +
+
+
+
+
+fury.colormap.T#
+

Transpose of the array.

+
+
Type:
+

ndarray

+
+
+
+ +
+
+fury.colormap.data#
+

The array’s elements, in memory.

+
+
Type:
+

buffer

+
+
+
+ +
+
+fury.colormap.dtype#
+

Describes the format of the elements in the array.

+
+
Type:
+

dtype object

+
+
+
+ +
+
+fury.colormap.flags#
+

Dictionary containing information related to memory use, e.g., +‘C_CONTIGUOUS’, ‘OWNDATA’, ‘WRITEABLE’, etc.

+
+
Type:
+

dict

+
+
+
+ +
+
+fury.colormap.flat#
+

Flattened version of the array as an iterator. The iterator +allows assignments, e.g., x.flat = 3 (See ndarray.flat for +assignment examples; TODO).

+
+
Type:
+

numpy.flatiter object

+
+
+
+ +
+
+fury.colormap.imag#
+

Imaginary part of the array.

+
+
Type:
+

ndarray

+
+
+
+ +
+
+fury.colormap.real#
+

Real part of the array.

+
+
Type:
+

ndarray

+
+
+
+ +
+
+fury.colormap.size#
+

Number of elements in the array.

+
+
Type:
+

int

+
+
+
+ +
+
+fury.colormap.itemsize#
+

The memory use of each array element in bytes.

+
+
Type:
+

int

+
+
+
+ +
+
+fury.colormap.nbytes#
+

The total number of bytes required to store the array data, +i.e., itemsize * size.

+
+
Type:
+

int

+
+
+
+ +
+
+fury.colormap.ndim#
+

The array’s number of dimensions.

+
+
Type:
+

int

+
+
+
+ +
+
+fury.colormap.shape#
+

Shape of the array.

+
+
Type:
+

tuple of ints

+
+
+
+ +
+
+fury.colormap.strides#
+

The step-size required to move from one element to the next in +memory. For example, a contiguous (3, 4) array of type +int16 in C-order has strides (8, 2). This implies that +to move from element to element in memory requires jumps of 2 bytes. +To move from row-to-row, one needs to jump 8 bytes at a time +(2 * 4).

+
+
Type:
+

tuple of ints

+
+
+
+ +
+
+fury.colormap.ctypes#
+

Class containing properties of the array needed for interaction +with ctypes.

+
+
Type:
+

ctypes object

+
+
+
+ +
+
+fury.colormap.base#
+

If the array is a view into another array, that array is its base +(unless that array is also a view). The base array is where the +array data is actually stored.

+
+
Type:
+

ndarray

+
+
+
+ +
+

See also

+
+
array

Construct an array.

+
+
zeros

Create an array, each element of which is zero.

+
+
empty

Create an array, but leave its allocated memory unchanged (i.e., it contains “garbage”).

+
+
dtype

Create a data-type.

+
+
numpy.typing.NDArray

An ndarray alias generic w.r.t. its dtype.type <numpy.dtype.type>.

+
+
+
+

Notes

+

There are two modes of creating an array using __new__:

+
    +
  1. If buffer is None, then only shape, dtype, and order +are used.

  2. +
  3. If buffer is an object exposing the buffer interface, then +all keywords are interpreted.

  4. +
+

No __init__ method is needed because the array is fully initialized +after the __new__ method.

+

Examples

+

These examples illustrate the low-level ndarray constructor. Refer +to the See Also section above for easier ways of constructing an +ndarray.

+

First mode, buffer is None:

+
>>> np.ndarray(shape=(2,2), dtype=float, order='F')
+array([[0.0e+000, 0.0e+000], # random
+       [     nan, 2.5e-323]])
+
+
+

Second mode:

+
>>> np.ndarray((2,), buffer=np.array([1,2,3]),
+...            offset=np.int_().itemsize,
+...            dtype=int) # offset = 1*itemsize, i.e. skip first element
+array([2, 3])
+
+
+
+ +
+
+

xyz2rgb#

+
+
+fury.colormap.xyz2rgb(xyz)[source]#
+

XYZ to RGB color space conversion.

+
+
Parameters:
+

xyz ((..., 3, ...) array_like) – The image in XYZ format. By default, the final dimension denotes +channels.

+
+
Returns:
+

out – The image in RGB format. Same dimensions as input.

+
+
Return type:
+

(…, 3, …) ndarray

+
+
+

Notes

+

Original Implementation from scikit-image package. +it can be found at: +scikit-image/scikit-image +This implementation might have been modified.

+
+ +
+
+

rgb2xyz#

+
+
+fury.colormap.rgb2xyz(rgb)[source]#
+

RGB to XYZ color space conversion.

+
+
Parameters:
+

rgb ((..., 3, ...) array_like) – The image in RGB format. By default, the final dimension denotes +channels.

+
+
Returns:
+

out – The image in XYZ format. Same dimensions as input.

+
+
Return type:
+

(…, 3, …) ndarray

+
+
+

Notes

+

Original Implementation from scikit-image package. +it can be found at: +scikit-image/scikit-image +This implementation might have been modified.

+
+ +
+
+

get_xyz_coords#

+
+
+fury.colormap.get_xyz_coords(illuminant, observer)[source]#
+

Get the XYZ coordinates of the given illuminant and observer [1]_.

+
+
Parameters:
+
    +
  • illuminant ({"A", "B", "C", "D50", "D55", "D65", "D75", "E"}, optional) – The name of the illuminant (the function is NOT case sensitive).

  • +
  • observer ({"2", "10", "R"}, optional) – One of: 2-degree observer, 10-degree observer, or ‘R’ observer as in +R function grDevices::convertColor.

  • +
+
+
Returns:
+

out – Array with 3 elements containing the XYZ coordinates of the given +illuminant.

+
+
Return type:
+

array

+
+
+

Notes

+

Original Implementation from scikit-image package. +it can be found at: +scikit-image/scikit-image +This implementation might have been modified.

+
+ +
+
+

xyz2lab#

+
+
+fury.colormap.xyz2lab(xyz, illuminant='D65', observer='2')[source]#
+

XYZ to CIE-LAB color space conversion.

+
+
Parameters:
+
    +
  • xyz ((..., 3, ...) array_like) – The image in XYZ format. By default, the final dimension denotes +channels.

  • +
  • illuminant ({"A", "B", "C", "D50", "D55", "D65", "D75", "E"}, optional) – The name of the illuminant (the function is NOT case sensitive).

  • +
  • observer ({"2", "10", "R"}, optional) – One of: 2-degree observer, 10-degree observer, or ‘R’ observer as in +R function grDevices::convertColor.

  • +
+
+
Returns:
+

out – The image in CIE-LAB format. Same dimensions as input.

+
+
Return type:
+

(…, 3, …) ndarray

+
+
+

Notes

+

Original Implementation from scikit-image package. +it can be found at: +scikit-image/scikit-image +This implementation might have been modified.

+
+ +
+
+

lab2xyz#

+
+
+fury.colormap.lab2xyz(lab, illuminant='D65', observer='2')[source]#
+

CIE-LAB to XYZcolor space conversion.

+
+
Parameters:
+
    +
  • lab ((..., 3, ...) array_like) – The image in Lab format. By default, the final dimension denotes +channels.

  • +
  • illuminant ({"A", "B", "C", "D50", "D55", "D65", "D75", "E"}, optional) – The name of the illuminant (the function is NOT case-sensitive).

  • +
  • observer ({"2", "10", "R"}, optional) – The aperture angle of the observer.

  • +
+
+
Returns:
+

out – The image in XYZ format. Same dimensions as input.

+
+
Return type:
+

(…, 3, …) ndarray

+
+
+

Notes

+

Original Implementation from scikit-image package. +it can be found at: +scikit-image/scikit-image +This implementation might have been modified.

+
+ +
+
+

rgb2lab#

+
+
+fury.colormap.rgb2lab(rgb, illuminant='D65', observer='2')[source]#
+

Conversion from the sRGB color space (IEC 61966-2-1:1999) +to the CIE Lab colorspace under the given illuminant and observer.

+
+
Parameters:
+
    +
  • rgb ((..., 3, ...) array_like) – The image in RGB format. By default, the final dimension denotes +channels.

  • +
  • illuminant ({"A", "B", "C", "D50", "D55", "D65", "D75", "E"}, optional) – The name of the illuminant (the function is NOT case sensitive).

  • +
  • observer ({"2", "10", "R"}, optional) – The aperture angle of the observer.

  • +
+
+
Returns:
+

out – The image in Lab format. Same dimensions as input.

+
+
Return type:
+

(…, 3, …) ndarray

+
+
+

Notes

+

Original Implementation from scikit-image package. +it can be found at: +scikit-image/scikit-image +This implementation might have been modified.

+
+ +
+
+

lab2rgb#

+
+
+fury.colormap.lab2rgb(lab, illuminant='D65', observer='2')[source]#
+

Lab to RGB color space conversion.

+
+
Parameters:
+
    +
  • lab ((..., 3, ...) array_like) – The image in Lab format. By default, the final dimension denotes +channels.

  • +
  • illuminant ({"A", "B", "C", "D50", "D55", "D65", "D75", "E"}, optional) – The name of the illuminant (the function is NOT case sensitive).

  • +
  • observer ({"2", "10", "R"}, optional) – The aperture angle of the observer.

  • +
+
+
Returns:
+

out – The image in RGB format. Same dimensions as input.

+
+
Return type:
+

(…, 3, …) ndarray

+
+
+

Notes

+

Original Implementation from scikit-image package. +it can be found at: +scikit-image/scikit-image +This implementation might have been modified.

+
+ +
+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ +
+ On this page +
+ +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/reference/fury.convert.html b/v0.10.x/reference/fury.convert.html new file mode 100644 index 000000000..6cf8eb7d2 --- /dev/null +++ b/v0.10.x/reference/fury.convert.html @@ -0,0 +1,580 @@ + + + + + + + + convert — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

convert#

+ + + + + + +

matplotlib_figure_to_numpy(fig[, dpi, ...])

Convert a Matplotlib figure to a 3D numpy array with RGBA channels.

+
+

matplotlib_figure_to_numpy#

+
+
+fury.convert.matplotlib_figure_to_numpy(fig, dpi=100, fname=None, flip_up_down=True, transparent=False)[source]#
+

Convert a Matplotlib figure to a 3D numpy array with RGBA channels.

+
+
Parameters:
+
    +
  • fig (obj) – A matplotlib figure object

  • +
  • dpi (int, optional) – Dots per inch

  • +
  • fname (str, optional) – If fname is given then the array will be saved as a png to this +position.

  • +
  • flip_up_down (bool, optional) – The origin is different from matlplotlib default and VTK’s default +behaviour (default True).

  • +
  • transparent (bool, optional) – Make background transparent (default False).

  • +
+
+
Returns:
+

arr – a numpy 3D array of RGBA values

+
+
Return type:
+

ndarray

+
+
+

Notes

+

The safest way to read the pixel values from the figure was to save them +using savefig as a png and then read again the png. There is a cleaner +way found here http://www.icare.univ-lille1.fr/drupal/node/1141 where +you can actually use fig.canvas.tostring_argb() to get the values directly +without saving to the disk. However, this was not stable across different +machines and needed more investigation from what time permitted.

+
+ +
+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/reference/fury.data.html b/v0.10.x/reference/fury.data.html new file mode 100644 index 000000000..a1703bc4e --- /dev/null +++ b/v0.10.x/reference/fury.data.html @@ -0,0 +1,1254 @@ + + + + + + + + data — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

data#

+

Read or fetch test or example data.

+ + + + + + +

DATA_DIR

str(object='') -> str str(bytes_or_buffer[, encoding[, errors]]) -> str

+
+

Module: data.fetcher#

+

Fetcher based on dipy.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

update_progressbar(progress, total_length)

Show progressbar.

copyfileobj_withprogress(fsrc, fdst, ...[, ...])

check_sha(filename[, stored_sha256])

Check the generated sha checksum.

fetch_data(files, folder[, data_size])

Download files to folder and checks their sha checksums.

fetch_gltf([name, mode])

Download glTF samples from Khronos Group Github.

fetch_viz_cubemaps()

Download cube map textures for fury

fetch_viz_icons()

Download icons for fury

fetch_viz_new_icons()

Download the new icons for DrawPanel

fetch_viz_wiki_nw()

Download the following wiki informationInterdisciplinary map of the journals

fetch_viz_models()

Download the models for shader tutorial

fetch_viz_dmri()

fetch_viz_textures()

Download textures for fury

read_viz_cubemap(name[, suffix_type, ext])

Read specific cube map with specific suffix type and extension.

read_viz_icons([style, fname])

Read specific icon from specific style.

read_viz_models(fname)

Read specific model.

read_viz_textures(fname)

Read specific texture.

read_viz_dmri(fname)

Read specific dMRI image.

read_viz_gltf(fname[, mode])

Read specific gltf sample.

list_gltf_sample_models()

Return all model name from the glTF-samples repository.

+
+

DATA_DIR#

+
+
+fury.data.DATA_DIR()#
+

str(object=’’) -> str +str(bytes_or_buffer[, encoding[, errors]]) -> str

+

Create a new string object from the given object. If encoding or +errors is specified, then the object must expose a data buffer +that will be decoded using the given encoding and error handler. +Otherwise, returns the result of object.__str__() (if defined) +or repr(object). +encoding defaults to sys.getdefaultencoding(). +errors defaults to ‘strict’.

+
+ +
+
+

update_progressbar#

+
+
+fury.data.fetcher.update_progressbar(progress, total_length)[source]#
+

Show progressbar.

+

Takes a number between 0 and 1 to indicate progress from 0 to 100%.

+
+ +
+
+

copyfileobj_withprogress#

+
+
+fury.data.fetcher.copyfileobj_withprogress(fsrc, fdst, total_length, length=16384)[source]#
+
+ +
+
+

check_sha#

+
+
+fury.data.fetcher.check_sha(filename, stored_sha256=None)[source]#
+

Check the generated sha checksum.

+
+
Parameters:
+
    +
  • filename (str) – The path to the file whose checksum is to be compared

  • +
  • stored_sha256 (str, optional) – Used to verify the generated SHA checksum. +Default: None, checking is skipped

  • +
+
+
+
+ +
+
+

fetch_data#

+
+
+fury.data.fetcher.fetch_data(files, folder, data_size=None)[source]#
+

Download files to folder and checks their sha checksums.

+
+
Parameters:
+
    +
  • files (dictionary) – For each file in files the value should be (url, sha). The file will +be downloaded from url if the file does not already exist or if the +file exists but the sha checksum does not match.

  • +
  • folder (str) – The directory where to save the file, the directory will be created if +it does not already exist.

  • +
  • data_size (str, optional) – A string describing the size of the data (e.g. “91 MB”) to be logged to +the screen. Default does not produce any information about data size.

  • +
+
+
Raises:
+

FetcherError – Raises if the sha checksum of the file does not match the expected + value. The downloaded file is not deleted when this error is raised.

+
+
+
+ +
+
+

fetch_gltf#

+
+
+fury.data.fetcher.fetch_gltf(name=None, mode='glTF')[source]#
+

Download glTF samples from Khronos Group Github.

+
+
Parameters:
+
    +
  • name (str, list, optional) – Name of the glTF model (for e.g. Box, BoxTextured, FlightHelmet, etc) +KhronosGroup/glTF-Sample-Models +Default: None, Downloads essential glTF samples for tests.

  • +
  • mode (str, optional) – Type of glTF format. +You can choose from different options +(e.g. glTF, glTF-Embedded, glTF-Binary, glTF-Draco) +Default: glTF, .bin and texture files are stored separately.

  • +
+
+
Returns:
+

filenames – tuple of feteched filenames (list) and folder (str) path.

+
+
Return type:
+

tuple

+
+
+
+ +
+
+

fetch_viz_cubemaps#

+
+
+fury.data.fetcher.fetch_viz_cubemaps()#
+

Download cube map textures for fury

+
+ +
+
+

fetch_viz_icons#

+
+
+fury.data.fetcher.fetch_viz_icons()#
+

Download icons for fury

+
+ +
+
+

fetch_viz_new_icons#

+
+
+fury.data.fetcher.fetch_viz_new_icons()#
+

Download the new icons for DrawPanel

+
+ +
+
+

fetch_viz_wiki_nw#

+
+
+fury.data.fetcher.fetch_viz_wiki_nw()#
+

Download the following wiki informationInterdisciplinary map of the journals

+
+ +
+
+

fetch_viz_models#

+
+
+fury.data.fetcher.fetch_viz_models()#
+

Download the models for shader tutorial

+
+ +
+
+

fetch_viz_dmri#

+
+
+fury.data.fetcher.fetch_viz_dmri()#
+
+ +
+
+

fetch_viz_textures#

+
+
+fury.data.fetcher.fetch_viz_textures()#
+

Download textures for fury

+
+ +
+
+

read_viz_cubemap#

+
+
+fury.data.fetcher.read_viz_cubemap(name, suffix_type=1, ext='.jpg')[source]#
+

Read specific cube map with specific suffix type and extension.

+
+
Parameters:
+
    +
  • name (str) –

  • +
  • suffix_type (int, optional) – 0 for numeric suffix (e.g., skybox_0.jpg, skybox_1.jpg, etc.), 1 for +-p/nC encoding where C is either x, y or z (e.g., skybox-px.jpeg, +skybox-ny.jpeg, etc.), 2 for pos/negC where C is either x, y, z (e.g., +skybox_posx.png, skybox_negy.png, etc.), and 3 for position in the cube +map (e.g., skybox_right.jpg, skybox_front.jpg, etc).

  • +
  • ext (str, optional) – Image type extension. (.jpg, .jpeg, .png, etc.).

  • +
+
+
Returns:
+

list of paths – List with the complete paths of the skybox textures.

+
+
Return type:
+

list

+
+
+
+ +
+
+

read_viz_icons#

+
+
+fury.data.fetcher.read_viz_icons(style='icomoon', fname='infinity.png')[source]#
+

Read specific icon from specific style.

+
+
Parameters:
+
    +
  • style (str) – Current icon style. Default is icomoon.

  • +
  • fname (str) – Filename of icon. This should be found in folder HOME/.fury/style/. +Default is infinity.png.

  • +
+
+
Returns:
+

path – Complete path of icon.

+
+
Return type:
+

str

+
+
+
+ +
+
+

read_viz_models#

+
+
+fury.data.fetcher.read_viz_models(fname)[source]#
+

Read specific model.

+
+
Parameters:
+

fname (str) – Filename of the model. +This should be found in folder HOME/.fury/models/.

+
+
Returns:
+

path – Complete path of models.

+
+
Return type:
+

str

+
+
+
+ +
+
+

read_viz_textures#

+
+
+fury.data.fetcher.read_viz_textures(fname)[source]#
+

Read specific texture.

+
+
Parameters:
+

fname (str) – Filename of the texture. +This should be found in folder HOME/.fury/textures/.

+
+
Returns:
+

path – Complete path of textures.

+
+
Return type:
+

str

+
+
+
+ +
+
+

read_viz_dmri#

+
+
+fury.data.fetcher.read_viz_dmri(fname)[source]#
+

Read specific dMRI image.

+
+
Parameters:
+

fname (str) – Filename of the texture. +This should be found in folder HOME/.fury/dmri/.

+
+
Returns:
+

path – Complete path of dMRI image.

+
+
Return type:
+

str

+
+
+
+ +
+
+

read_viz_gltf#

+
+
+fury.data.fetcher.read_viz_gltf(fname, mode='glTF')[source]#
+

Read specific gltf sample.

+
+
Parameters:
+
    +
  • fname (str) – Name of the model. +This should be found in folder HOME/.fury/models/glTF/.

  • +
  • mode (str, optional) – Model type (e.g. glTF-Binary, glTF-Embedded, etc) +Default : glTF

  • +
+
+
Returns:
+

path – Complete path of models.

+
+
Return type:
+

str

+
+
+
+ +
+
+

list_gltf_sample_models#

+
+
+fury.data.fetcher.list_gltf_sample_models()[source]#
+

Return all model name from the glTF-samples repository.

+
+
Returns:
+

model_names – Lists the name of glTF sample from +KhronosGroup/glTF-Sample-Models

+
+
Return type:
+

list

+
+
+
+ +
+
+
+ +
+ + +
+ +
+ + + + + +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/reference/fury.decorators.html b/v0.10.x/reference/fury.decorators.html new file mode 100644 index 000000000..48a5ec4f6 --- /dev/null +++ b/v0.10.x/reference/fury.decorators.html @@ -0,0 +1,597 @@ + + + + + + + + decorators — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

decorators#

+

Decorators for FURY tests.

+ + + + + + + + + +

SKIP_RE

Compiled regular expression object.

doctest_skip_parser(func)

Decorator replaces custom skip test markup in doctests.

+
+

SKIP_RE#

+
+
+fury.decorators.SKIP_RE()#
+

Compiled regular expression object.

+
+ +
+
+

doctest_skip_parser#

+
+
+fury.decorators.doctest_skip_parser(func)[source]#
+

Decorator replaces custom skip test markup in doctests.

+

Say a function has a docstring:: +>>> something # skip if not HAVE_AMODULE +>>> something + else +>>> something # skip if HAVE_BMODULE +This decorator will evaluate the expression after skip if. If this +evaluates to True, then the comment is replaced by # doctest: +SKIP. +If False, then the comment is just removed. The expression is evaluated in +the globals scope of func. +For example, if the module global HAVE_AMODULE is False, and module +global HAVE_BMODULE is False, the returned function will have +docstring:: +>>> something # doctest: +SKIP +>>> something + else +>>> something

+
+ +
+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/reference/fury.deprecator.html b/v0.10.x/reference/fury.deprecator.html new file mode 100644 index 000000000..1a012c366 --- /dev/null +++ b/v0.10.x/reference/fury.deprecator.html @@ -0,0 +1,895 @@ + + + + + + + + deprecator — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

deprecator#

+

Function for recording and reporting deprecations.

+

Notes

+

this file is copied (with minor modifications) from the Nibabel. +nipy/nibabel. See COPYING file distributed along with +the Nibabel package for the copyright and license terms.

+ + + + + + + + + + + + + + + + + + + + + + + + +

ExpiredDeprecationError

Error for expired deprecation.

ArgsDeprecationWarning

Warning for args deprecation.

_LEADING_WHITE

Compiled regular expression object.

cmp_pkg_version(version_str[, pkg_version_str])

Compare version_str to current package version.

is_bad_version(version_str[, version_comparator])

Return True if version_str is too high.

deprecate_with_version(message[, since, ...])

Return decorator function for deprecation warning / error.

deprecated_params(old_name[, new_name, ...])

Deprecate a renamed or removed function argument.

+
+

ExpiredDeprecationError#

+
+
+class fury.deprecator.ExpiredDeprecationError[source]#
+

Bases: RuntimeError

+

Error for expired deprecation.

+

Error raised when a called function or method has passed out of its +deprecation period.

+
+
+__init__(*args, **kwargs)#
+
+ +
+ +
+
+

ArgsDeprecationWarning#

+
+
+class fury.deprecator.ArgsDeprecationWarning[source]#
+

Bases: DeprecationWarning

+

Warning for args deprecation.

+

Warning raised when a function or method argument has changed or removed.

+
+
+__init__(*args, **kwargs)#
+
+ +
+ +
+
+

_LEADING_WHITE#

+
+
+fury.deprecator._LEADING_WHITE()#
+

Compiled regular expression object.

+
+ +
+
+

cmp_pkg_version#

+
+
+fury.deprecator.cmp_pkg_version(version_str, pkg_version_str='0.10.0')[source]#
+

Compare version_str to current package version.

+
+
Parameters:
+
    +
  • version_str (str) – Version string to compare to current package version

  • +
  • pkg_version_str (str, optional) – Version of our package. Optional, set from __version__ by default.

  • +
+
+
Returns:
+

version_cmp – 1 if version_str is a later version than pkg_version_str, 0 if +same, -1 if earlier.

+
+
Return type:
+

int

+
+
+

Examples

+
>>> cmp_pkg_version('1.2.1', '1.2.0')
+1
+>>> cmp_pkg_version('1.2.0dev', '1.2.0')
+-1
+
+
+
+ +
+
+

is_bad_version#

+
+
+fury.deprecator.is_bad_version(version_str, version_comparator=<function cmp_pkg_version>)[source]#
+

Return True if version_str is too high.

+
+ +
+
+

deprecate_with_version#

+
+
+fury.deprecator.deprecate_with_version(message, since='', until='', version_comparator=<function cmp_pkg_version>, warn_class=<class 'DeprecationWarning'>, error_class=<class 'fury.deprecator.ExpiredDeprecationError'>)[source]#
+

Return decorator function for deprecation warning / error.

+

The decorated function / method will:

+
    +
  • Raise the given warning_class warning when the function / method gets +called, up to (and including) version until (if specified);

  • +
  • Raise the given error_class error when the function / method gets +called, when the package version is greater than version until (if +specified).

  • +
+
+
Parameters:
+
    +
  • message (str) – Message explaining deprecation, giving possible alternatives.

  • +
  • since (str, optional) – Released version at which object was first deprecated.

  • +
  • until (str, optional) – Last released version at which this function will still raise a +deprecation warning. Versions higher than this will raise an +error.

  • +
  • version_comparator (callable) – Callable accepting string as argument, and return 1 if string +represents a higher version than encoded in the version_comparator`, 0 +if the version is equal, and -1 if the version is lower. For example, +the version_comparator may compare the input version string to the +current package version string.

  • +
  • warn_class (class, optional) – Class of warning to generate for deprecation.

  • +
  • error_class (class, optional) – Class of error to generate when version_comparator returns 1 for a +given argument of until.

  • +
+
+
Returns:
+

deprecator – Function returning a decorator.

+
+
Return type:
+

func

+
+
+
+ +
+
+

deprecated_params#

+
+
+fury.deprecator.deprecated_params(old_name, new_name=None, since='', until='', version_comparator=<function cmp_pkg_version>, arg_in_kwargs=False, warn_class=<class 'fury.deprecator.ArgsDeprecationWarning'>, error_class=<class 'fury.deprecator.ExpiredDeprecationError'>, alternative='')[source]#
+

Deprecate a renamed or removed function argument.

+

The decorator assumes that the argument with the old_name was removed +from the function signature and the new_name replaced it at the +same position in the signature. If the old_name argument is +given when calling the decorated function the decorator will catch it and +issue a deprecation warning and pass it on as new_name argument.

+
+
Parameters:
+
    +
  • old_name (str or list/tuple thereof) – The old name of the argument.

  • +
  • new_name (str or list/tuple thereof or None, optional) – The new name of the argument. Set this to None to remove the +argument old_name instead of renaming it.

  • +
  • since (str or number or list/tuple thereof, optional) – The release at which the old argument became deprecated.

  • +
  • until (str or number or list/tuple thereof, optional) – Last released version at which this function will still raise a +deprecation warning. Versions higher than this will raise an +error.

  • +
  • version_comparator (callable) – Callable accepting string as argument, and return 1 if string +represents a higher version than encoded in the version_comparator, +0 if the version is equal, and -1 if the version is lower. For example, +the version_comparator may compare the input version string to the +current package version string.

  • +
  • arg_in_kwargs (bool or list/tuple thereof, optional) – If the argument is not a named argument (for example it +was meant to be consumed by **kwargs) set this to +True. Otherwise the decorator will throw an Exception +if the new_name cannot be found in the signature of +the decorated function. +Default is False.

  • +
  • warn_class (warning, optional) – Warning to be issued.

  • +
  • error_class (Exception, optional) – Error to be issued

  • +
  • alternative (str, optional) – An alternative function or class name that the user may use in +place of the deprecated object if new_name is None. The deprecation +warning will tell the user about this alternative if provided.

  • +
+
+
Raises:
+

TypeError – If the new argument name cannot be found in the function + signature and arg_in_kwargs was False or if it is used to + deprecate the name of the *args-, **kwargs-like arguments. + At runtime such an Error is raised if both the new_name + and old_name were specified when calling the function and + “relax=False”.

+
+
+

Notes

+

This function is based on the Astropy (major modification). +astropy/astropy. See COPYING file distributed along with +the astropy package for the copyright and license terms.

+

Examples

+

The deprecation warnings are not shown in the following examples. +To deprecate a positional or keyword argument:: +>>> from fury.deprecator import deprecated_params +>>> @deprecated_params(‘sig’, ‘sigma’, ‘0.3’) +… def test(sigma): +… return sigma +>>> test(2) +2 +>>> test(sigma=2) +2 +>>> test(sig=2) # doctest: +SKIP +2

+

It is also possible to replace multiple arguments. The old_name, +new_name and since have to be tuple or list and contain the +same number of entries:: +>>> @deprecated_params([‘a’, ‘b’], [‘alpha’, ‘beta’], +… [‘0.2’, 0.4]) +… def test(alpha, beta): +… return alpha, beta +>>> test(a=2, b=3) # doctest: +SKIP +(2, 3)

+
+ +
+
+ +
+ + +
+ +
+ + + + + +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/reference/fury.gltf.html b/v0.10.x/reference/fury.gltf.html new file mode 100644 index 000000000..d9de03e50 --- /dev/null +++ b/v0.10.x/reference/fury.gltf.html @@ -0,0 +1,1641 @@ + + + + + + + + gltf — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

gltf#

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

glTF(filename[, apply_normals])

export_scene(scene[, filename])

Generate gltf from FURY scene.

write_scene(gltf, nodes)

Create scene

write_node(gltf[, mesh_id, camera_id])

Create node

write_mesh(gltf, primitives)

Create mesh and add primitive.

write_camera(gltf, camera)

Create and add camera.

get_prim(vertex, index, color, tcoord, ...)

Return a Primitive object.

write_material(gltf, basecolortexture, uri)

Write Material, Images and Textures

write_accessor(gltf, bufferview, ...[, max, min])

Write accessor in the gltf.

write_bufferview(gltf, buffer, byte_offset, ...)

Write bufferview in the gltf.

write_buffer(gltf, byte_length, uri)

Write buffer int the gltf

+
+

glTF#

+
+
+class fury.gltf.glTF(filename, apply_normals=False)[source]#
+

Bases: object

+
+
+__init__(filename, apply_normals=False)[source]#
+

Read and generate actors from glTF files.

+
+
Parameters:
+
    +
  • filename (str) – Path of the gltf file

  • +
  • apply_normals (bool, optional) – If True applies normals to the mesh.

  • +
+
+
+
+ +
+
+actors()[source]#
+

Generate actors from glTF file.

+
+
Returns:
+

actors – List of vtkActors with texture.

+
+
Return type:
+

list

+
+
+
+ +
+
+apply_morph_vertices(vertices, weights, cnt)[source]#
+

Calculate weighted vertex from the morph data.

+
+
Parameters:
+
    +
  • vertices (ndarray) – Vertices of a actor.

  • +
  • weights (ndarray) – Morphing weights used to calculate the weighted average of new +vertex.

  • +
  • cnt (int) – Count of the actor.

  • +
+
+
+
+ +
+
+apply_skin_matrix(vertices, joint_matrices, actor_index=0)[source]#
+

Apply the skinnig matrix, that transform the vertices.

+
+
Parameters:
+
    +
  • vertices (ndarray) – Vertices of an actor.

  • +
  • join_matrices (list) – List of skinning matrix to calculate the weighted transformation.

  • +
+
+
Returns:
+

vertices – Modified vertices.

+
+
Return type:
+

ndarray

+
+
+
+ +
+
+generate_tmatrix(transf, prop)[source]#
+

Create transformation matrix from TRS array.

+
+
Parameters:
+
    +
  • transf (ndarray) – Array containing translation, rotation or scale values.

  • +
  • prop (str) – String that defines the type of array +(values: translation, rotation or scale).

  • +
+
+
Returns:
+

matrix – ransformation matrix of shape (4, 4) with respective transforms.

+
+
Return type:
+

ndarray (4, 4)

+
+
+
+ +
+
+get_acc_data(acc_id)[source]#
+

Get the correct data from buffer using accessors and bufferviews.

+
+
Parameters:
+

acc_id (int) – Accessor index

+
+
Returns:
+

buffer_array – Numpy array extracted from the buffer.

+
+
Return type:
+

ndarray

+
+
+
+ +
+
+get_animations()[source]#
+

Return list of animations.

+
+
Returns:
+

animations – List of animations containing actors.

+
+
Return type:
+

List

+
+
+
+ +
+
+get_buff_array(buff_id, d_type, byte_length, byte_offset, byte_stride)[source]#
+

Extract the mesh data from buffer.

+
+
Parameters:
+
    +
  • buff_id (int) – Buffer Index

  • +
  • d_type (type) – Element data type

  • +
  • byte_length (int) – The length of the buffer data

  • +
  • byte_offset (int) – The offset into the buffer in bytes

  • +
  • byte_stride (int) – The stride, in bytes

  • +
+
+
Returns:
+

out_arr – Numpy array of size byte_length from buffer.

+
+
Return type:
+

ndarray

+
+
+
+ +
+
+get_joint_actors(length=0.5, with_transforms=False)[source]#
+

Create an arrow actor for each bone in a skinned model.

+
+
Parameters:
+
    +
  • length (float (default = 0.5)) – Length of the arrow actor

  • +
  • with_transforms (bool (default = False)) – Applies respective transformations to bone. Bones will be at origin +if set to False.

  • +
+
+
+
+ +
+
+get_materials(mat_id)[source]#
+

Get the material data.

+
+
Parameters:
+

mat_id (int) – Material index

+
+
Returns:
+

materials – Dictionary of all textures.

+
+
Return type:
+

dict

+
+
+
+ +
+
+get_matrix_from_sampler(prop, node, anim_channel, sampler: Sampler)[source]#
+

Return transformation matrix for a given timestamp from Sampler +data. Combine matrices for a given common timestamp.

+
+
Parameters:
+
    +
  • prop (str) – Property of the array (‘translation’, ‘rotation’ or ‘scale’)

  • +
  • node (int) – Node index of the sampler data.

  • +
  • anim_channel (dict) – Containing previous animations with node as keys.

  • +
  • sampler (gltflib.Sampler) – Sampler object for an animation channel.

  • +
+
+
+
+ +
+
+get_morph_data(target, mesh_id)[source]#
+
+ +
+
+get_sampler_data(sampler: Sampler, node_id: int, transform_type)[source]#
+

Get the animation and transformation data from sampler.

+
+
Parameters:
+
    +
  • sampler (glTFlib.Sampler) – pygltflib sampler object.

  • +
  • node_id (int) – Node index of the current animation channel.

  • +
  • transform_type (str) – Property of the node to be transformed.

  • +
+
+
Returns:
+

sampler_data – dictionary of data containing timestamps, node transformations and +interpolation type.

+
+
Return type:
+

dict

+
+
+
+ +
+
+get_skin_data(skin_id)[source]#
+

Get the inverse bind matrix for each bone in the skin.

+
+
Parameters:
+

skin_id (int) – Index of the skin.

+
+
Returns:
+

    +
  • joint_nodes (list) – List of bones in the skin.

  • +
  • inv_bind_matrix (ndarray) – Numpy array containing inverse bind pose for each bone.

  • +
+

+
+
+
+ +
+
+get_texture(tex_id)[source]#
+

Read and convert image into vtk texture.

+
+
Parameters:
+

tex_id (int) – Texture index

+
+
Returns:
+

atexture – Returns flipped vtk texture from image.

+
+
Return type:
+

Texture

+
+
+
+ +
+
+initialize_skin(animation, bones=False, length=0.2)[source]#
+

Create bones and add to the animation and initialise update_skin

+
+
Parameters:
+
    +
  • animation (Animation) – Skin animation object.

  • +
  • bones (bool) – Switches the visibility of bones in scene. +(default=False)

  • +
  • length (float) – Length of the bones. +(default=0.2)

  • +
+
+
+
+ +
+
+inspect_scene(scene_id=0)[source]#
+

Loop over nodes in a scene.

+
+
Parameters:
+

scene_id (int, optional) – scene index of the glTF.

+
+
+
+ +
+
+load_camera(camera_id, transform_mat)[source]#
+

Load the camera data of a node.

+
+
Parameters:
+
    +
  • camera_id (int) – Camera index of a node.

  • +
  • transform_mat (ndarray (4, 4)) – Transformation matrix of the camera.

  • +
+
+
+
+ +
+
+load_mesh(mesh_id, transform_mat, parent)[source]#
+

Load the mesh data from accessor and applies the transformation.

+
+
Parameters:
+
    +
  • mesh_id (int) – Mesh index to be loaded

  • +
  • transform_mat (ndarray (4, 4)) – Transformation matrix.

  • +
+
+
+
+ +
+
+main_animation()[source]#
+

Return main animation with all glTF animations.

+
+
Returns:
+

main_animation – A parent animation containing all child animations for simple +animation.

+
+
Return type:
+

Animation

+
+
+
+ +
+
+morph_animation()[source]#
+

Create animation for each channel in animations.

+
+
Returns:
+

root_animations – A dictionary containing animations as values and animation name as +keys.

+
+
Return type:
+

Dict

+
+
+
+ +
+
+skin_animation()[source]#
+

One animation for each bone, contains parent transforms.

+
+
Returns:
+

root_animations – An animation containing all the child animations for bones.

+
+
Return type:
+

Dict

+
+
+
+ +
+
+transverse_animations(animation, bone_id, timestamp, joint_matrices, parent_bone_deform=array([[1., 0., 0., 0.], [0., 1., 0., 0.], [0., 0., 1., 0.], [0., 0., 0., 1.]]))[source]#
+

Calculate skinning matrix (Joint Matrices) and transform bone for +each animation.

+
+
Parameters:
+
    +
  • animation (Animation) – Animation object.

  • +
  • bone_id (int) – Bone index of the current transform.

  • +
  • timestamp (float) – Current timestamp of the animation.

  • +
  • joint_matrices (dict) – Empty dictionary that will contain joint matrices.

  • +
  • parent_bone_transform (ndarray (4, 4)) – Transformation matrix of the parent bone. +(default=np.identity(4))

  • +
+
+
+
+ +
+
+transverse_bones(bone_id, channel_name, parent_animation: Animation)[source]#
+

Loop over the bones and add child bone animation to their parent +animation.

+
+
Parameters:
+
    +
  • bone_id (int) – Index of the bone.

  • +
  • channel_name (str) – Animation name.

  • +
  • parent_animation (Animation) – The animation of the parent bone. Should be root_animation by +default.

  • +
+
+
+
+ +
+
+transverse_channels(animation: Animation, count: int)[source]#
+

Loop over animation channels and sets animation data.

+
+
Parameters:
+
    +
  • animation (glTflib.Animation) – pygltflib animation object.

  • +
  • count (int) – Animation count.

  • +
+
+
+
+ +
+
+transverse_node(nextnode_id, matrix, parent=None, is_joint=False)[source]#
+

Load mesh and generates transformation matrix.

+
+
Parameters:
+
    +
  • nextnode_id (int) – Index of the node

  • +
  • matrix (ndarray (4, 4)) – Transformation matrix

  • +
  • parent (list, optional) – List of indices of parent nodes +Default: None.

  • +
  • is_joint (Bool) – To determine if the current node is a joint/bone of skins. +Default: False

  • +
+
+
+
+ +
+
+update_morph(animation)[source]#
+

Update the animation and actors with morphing.

+
+
Parameters:
+

animation (Animation) – Animation object.

+
+
+
+ +
+
+update_skin(animation)[source]#
+

Update the animation and actors with skinning data.

+
+
Parameters:
+

animation (Animation) – Animation object.

+
+
+
+ +
+ +
+
+

export_scene#

+
+
+fury.gltf.export_scene(scene, filename='default.gltf')[source]#
+

Generate gltf from FURY scene.

+
+
Parameters:
+
    +
  • scene (Scene) – FURY scene object.

  • +
  • filename (str, optional) – Name of the model to be saved

  • +
+
+
+
+ +
+
+

write_scene#

+
+
+fury.gltf.write_scene(gltf, nodes)[source]#
+

Create scene

+
+
Parameters:
+
    +
  • gltf (GLTF2) – Pygltflib GLTF2 object

  • +
  • nodes (list) – List of node indices.

  • +
+
+
+
+ +
+
+

write_node#

+
+
+fury.gltf.write_node(gltf, mesh_id=None, camera_id=None)[source]#
+

Create node

+
+
Parameters:
+
    +
  • gltf (GLTF2) – Pygltflib GLTF2 object

  • +
  • mesh_id (int, optional) – Mesh index

  • +
  • camera_id (int, optional) – Camera index.

  • +
+
+
+
+ +
+
+

write_mesh#

+
+
+fury.gltf.write_mesh(gltf, primitives)[source]#
+

Create mesh and add primitive.

+
+
Parameters:
+
    +
  • gltf (GLTF2) – Pygltflib GLTF2 object.

  • +
  • primitives (list) – List of Primitive object.

  • +
+
+
+
+ +
+
+

write_camera#

+
+
+fury.gltf.write_camera(gltf, camera)[source]#
+

Create and add camera.

+
+
Parameters:
+
    +
  • gltf (GLTF2) – Pygltflib GLTF2 object.

  • +
  • camera (vtkCamera) – scene camera.

  • +
+
+
+
+ +
+
+

get_prim#

+
+
+fury.gltf.get_prim(vertex, index, color, tcoord, normal, material, mode=4)[source]#
+

Return a Primitive object.

+
+
Parameters:
+
    +
  • vertex (int) – Accessor index for the vertices data.

  • +
  • index (int) – Accessor index for the triangles data.

  • +
  • color (int) – Accessor index for the colors data.

  • +
  • tcoord (int) – Accessor index for the texture coordinates data.

  • +
  • normal (int) – Accessor index for the normals data.

  • +
  • material (int) – Materials index.

  • +
  • mode (int, optional) – The topology type of primitives to render. +Default: 4

  • +
+
+
Returns:
+

prim – pygltflib primitive object.

+
+
Return type:
+

Primitive

+
+
+
+ +
+
+

write_material#

+
+
+fury.gltf.write_material(gltf, basecolortexture: int, uri: str)[source]#
+

Write Material, Images and Textures

+
+
Parameters:
+
    +
  • gltf (GLTF2) – Pygltflib GLTF2 object.

  • +
  • basecolortexture (int) – BaseColorTexture index.

  • +
  • uri (str) – BaseColorTexture uri.

  • +
+
+
+
+ +
+
+

write_accessor#

+
+
+fury.gltf.write_accessor(gltf, bufferview, byte_offset, comp_type, count, accssor_type, max=None, min=None)[source]#
+

Write accessor in the gltf.

+
+
Parameters:
+
    +
  • gltf (GLTF2) –

    Pygltflib GLTF2 objecomp_type

    +
    +

    bufferview: int

    +
    +

    BufferView Index

    +

  • +
  • byte_offset (int) – ByteOffset of the accessor

  • +
  • comp_type (type) – Type of a single component

  • +
  • count (int) – Elements count of the accessor

  • +
  • accssor_type (type) – Type of the accessor(SCALAR, VEC2, VEC3, VEC4)

  • +
  • max (ndarray, optional) – Maximum elements of an array

  • +
  • min (ndarray, optional) – Minimum elements of an array

  • +
+
+
+
+ +
+
+

write_bufferview#

+
+
+fury.gltf.write_bufferview(gltf, buffer, byte_offset, byte_length, byte_stride=None)[source]#
+

Write bufferview in the gltf.

+
+
Parameters:
+
    +
  • gltf (GLTF2) – Pygltflib GLTF2 object

  • +
  • buffer (int) – Buffer index

  • +
  • byte_offset (int) – Byte offset of the bufferview

  • +
  • byte_length (int) – Byte length ie, Length of the data we want to get from +the buffer

  • +
  • byte_stride (int, optional) – Byte stride of the bufferview.

  • +
+
+
+
+ +
+
+

write_buffer#

+
+
+fury.gltf.write_buffer(gltf, byte_length, uri)[source]#
+

Write buffer int the gltf

+
+
Parameters:
+
    +
  • gltf (GLTF2) – Pygltflib GLTF2 object

  • +
  • byte_length (int) – Length of the buffer

  • +
  • uri (str) – Path to the external .bin file.

  • +
+
+
+
+ +
+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ +
+ On this page +
+ +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/reference/fury.html b/v0.10.x/reference/fury.html new file mode 100644 index 000000000..912995f80 --- /dev/null +++ b/v0.10.x/reference/fury.html @@ -0,0 +1,632 @@ + + + + + + + + fury — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

fury#

+

Init file for visualization package.

+ + + + + + + + + + + + +

get_info([verbose])

Return dict describing the context of this package.

enable_warnings([warnings_origin])

Enable global warnings.

disable_warnings([warnings_origin])

Disable global warnings.

+
+

get_info#

+
+
+fury.get_info(verbose=False)[source]#
+

Return dict describing the context of this package.

+
+
Parameters:
+

pkg_path (str) – path containing __init__.py for package

+
+
Returns:
+

context – with named parameters of interest

+
+
Return type:
+

dict

+
+
+
+ +
+
+

enable_warnings#

+
+
+fury.enable_warnings(warnings_origin=None)[source]#
+

Enable global warnings.

+
+
Parameters:
+

warnings_origin (list) – list origin [‘all’, ‘fury’, ‘vtk’, ‘matplotlib’, …]

+
+
+
+ +
+
+

disable_warnings#

+
+
+fury.disable_warnings(warnings_origin=None)[source]#
+

Disable global warnings.

+
+
Parameters:
+

warnings_origin (list) – list origin [‘all’, ‘fury’, ‘vtk’, ‘matplotlib’, …]

+
+
+
+ +
+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/reference/fury.io.html b/v0.10.x/reference/fury.io.html new file mode 100644 index 000000000..78f3636cb --- /dev/null +++ b/v0.10.x/reference/fury.io.html @@ -0,0 +1,816 @@ + + + + + + + + io — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

io#

+ + + + + + + + + + + + + + + + + + + + + + + + +

load_cubemap_texture(fnames[, ...])

Load a cube map texture from a list of 6 images.

load_image(filename[, as_vtktype, use_pillow])

Load an image.

load_text(file)

Load a text file.

save_image(arr, filename[, ...])

Save a 2d or 3d image.

load_polydata(file_name)

Load a vtk polydata to a supported format file.

save_polydata(polydata, file_name[, binary, ...])

Save a vtk polydata to a supported format file.

load_sprite_sheet(sheet_path, nb_rows, nb_cols)

Process and load sprites from a sprite sheet.

+
+

load_cubemap_texture#

+
+
+fury.io.load_cubemap_texture(fnames, interpolate_on=True, mipmap_on=True)[source]#
+

Load a cube map texture from a list of 6 images.

+
+
Parameters:
+
    +
  • fnames (list of strings) – List of 6 filenames with bmp, jpg, jpeg, png, tif or tiff extensions.

  • +
  • interpolate_on (bool, optional) –

  • +
  • mipmap_on (bool, optional) –

  • +
+
+
Returns:
+

output – Cube map texture.

+
+
Return type:
+

vtkTexture

+
+
+
+ +
+
+

load_image#

+
+
+fury.io.load_image(filename, as_vtktype=False, use_pillow=True)[source]#
+

Load an image.

+
+
Parameters:
+
    +
  • filename (str) – should be png, bmp, jpeg or jpg files

  • +
  • as_vtktype (bool, optional) – if True, return vtk output otherwise an ndarray. Default False.

  • +
  • use_pillow (bool, optional) – Use pillow python library to load the files. Default True

  • +
+
+
Returns:
+

image – desired image array

+
+
Return type:
+

ndarray or vtk output

+
+
+
+ +
+
+

load_text#

+
+
+fury.io.load_text(file)[source]#
+

Load a text file.

+
+
Parameters:
+

file (str) – Path to the text file.

+
+
Returns:
+

text – Text contained in the file.

+
+
Return type:
+

str

+
+
+
+ +
+
+

save_image#

+
+
+fury.io.save_image(arr, filename, compression_quality=75, compression_type='deflation', use_pillow=True, dpi=(72, 72))[source]#
+

Save a 2d or 3d image.

+

Expect an image with the following shape: (H, W) or (H, W, 1) or +(H, W, 3) or (H, W, 4).

+
+
Parameters:
+
    +
  • arr (ndarray) – array to save

  • +
  • filename (string) – should be png, bmp, jpeg or jpg files

  • +
  • compression_quality (int, optional) – compression_quality for jpeg data. +0 = Low quality, 100 = High quality

  • +
  • compression_type (str, optional) – compression type for tiff file +select between: None, lzw, deflation (default)

  • +
  • use_pillow (bool, optional) – Use imageio python library to save the files.

  • +
  • dpi (float or (float, float)) – Dots per inch (dpi) for saved image. +Single values are applied as dpi for both dimensions.

  • +
+
+
+
+ +
+
+

load_polydata#

+
+
+fury.io.load_polydata(file_name)[source]#
+

Load a vtk polydata to a supported format file.

+

Supported file formats are VTK, VTP, FIB, PLY, STL XML and OBJ

+
+
Parameters:
+

file_name (string) –

+
+
Returns:
+

output

+
+
Return type:
+

vtkPolyData

+
+
+
+ +
+
+

save_polydata#

+
+
+fury.io.save_polydata(polydata, file_name, binary=False, color_array_name=None)[source]#
+

Save a vtk polydata to a supported format file.

+

Save formats can be VTK, FIB, PLY, STL and XML.

+
+
Parameters:
+
    +
  • polydata (vtkPolyData) –

  • +
  • file_name (string) –

  • +
  • binary (bool) –

  • +
  • color_array_name (ndarray) –

  • +
+
+
+
+ +
+
+

load_sprite_sheet#

+
+
+fury.io.load_sprite_sheet(sheet_path, nb_rows, nb_cols, as_vtktype=False)[source]#
+

Process and load sprites from a sprite sheet.

+
+
Parameters:
+
    +
  • sheet_path (str) – Path to the sprite sheet

  • +
  • nb_rows (int) – Number of rows in the sprite sheet

  • +
  • nb_cols (int) – Number of columns in the sprite sheet

  • +
  • as_vtktype (bool, optional) – If True, the output is a vtkImageData

  • +
+
+
Return type:
+

Dict containing the processed sprites.

+
+
+
+ +
+
+ +
+ + +
+ +
+ + + + + +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/reference/fury.layout.html b/v0.10.x/reference/fury.layout.html new file mode 100644 index 000000000..3af30f56d --- /dev/null +++ b/v0.10.x/reference/fury.layout.html @@ -0,0 +1,1353 @@ + + + + + + + + layout — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

layout#

+ + + + + + + + + + + + + + + + + + + + + + + + +

Layout()

Provide functionalities for laying out actors in a 3D scene.

GridLayout([cell_padding, cell_shape, ...])

Provide functionalities for laying out actors in a 2D grid fashion.

HorizontalLayout([cell_padding, cell_shape])

Provide functionalities for laying out actors in a horizontal layout.

VerticalLayout([cell_padding, cell_shape])

Provide functionalities for laying out actors in a vertical stack.

XLayout([direction, cell_padding, cell_shape])

Provide functionalities for laying out actors along x-axis.

YLayout([direction, cell_padding, cell_shape])

Provide functionalities for laying out actors along y-axis.

ZLayout([direction, cell_padding, cell_shape])

Provide functionalities for laying out actors along z-axis.

+
+

Layout#

+
+
+class fury.layout.Layout[source]#
+

Bases: object

+

Provide functionalities for laying out actors in a 3D scene.

+
+
+__init__()#
+
+ +
+
+apply(actors)[source]#
+

Position the actors according to a certain layout.

+
+ +
+
+compute_positions(_actors)[source]#
+

Compute the 3D coordinates of some actors.

+
+ +
+ +
+
+

GridLayout#

+
+
+class fury.layout.GridLayout(cell_padding=0, cell_shape='rect', aspect_ratio=1.7777777777777777, dim=None, position_offset=(0, 0, 0))[source]#
+

Bases: Layout

+

Provide functionalities for laying out actors in a 2D grid fashion.

+

The GridLayout class lays the actors in a 2D structured grid aligned +with the xy-plane.

+
+
+__init__(cell_padding=0, cell_shape='rect', aspect_ratio=1.7777777777777777, dim=None, position_offset=(0, 0, 0))[source]#
+

Initialize the grid layout. +:param cell_padding: Each grid cell will be padded according to (pad_x, pad_y) i.e.

+
+

horizontally and vertically. Padding is evenly distributed on each +side of the cell. If a single float is provided then both pad_x and +pad_y will have the same value.

+
+
+
Parameters:
+
    +
  • cell_shape ({'rect', 'square', 'diagonal'} (optional)) – Specifies the desired shape of every grid cell. +‘rect’ ensures the cells are the tightest. +‘square’ ensures the cells are as wide as high. +‘diagonal’ ensures the content of the cells can be rotated without +colliding with content of the neighboring cells.

  • +
  • aspect_ratio (float (optional)) – Aspect ratio of the grid (width/height). Default: 16:9.

  • +
  • dim (tuple of int (optional)) – Dimension (nb_rows, nb_cols) of the grid. If provided, +aspect_ratio will be ignored.

  • +
  • position_offset (tuple (optional)) – Offset the grid by some factor

  • +
+
+
+
+ +
+
+compute_positions(actors)[source]#
+

Compute the 3D coordinates of some actors. +The coordinates will lie on the xy-plane and form a 2D grid.

+
+
Parameters:
+

actors (list of vtkProp3D objects) – Actors to be layout in a grid manner.

+
+
Returns:
+

The computed 3D coordinates of every actors.

+
+
Return type:
+

list of 3-tuple

+
+
+
+ +
+
+compute_sizes(actor)[source]#
+

Compute the bounding box size of the actor/UI element

+
+
Parameters:
+

actor (vtkProp3D or UI element) – Actor/UI element whose size is to be calculated

+
+
Returns:
+

bounding box sizes

+
+
Return type:
+

tuple

+
+
+
+ +
+
+get_cells_shape(actors)[source]#
+

Get the 2D shape (on the xy-plane) of some actors according to +self.cell_shape.

+
+
Parameters:
+

actors (list of vtkProp3D objects) – Actors from which to calculate the 2D shape.

+
+
Returns:
+

The 2D shape (on the xy-plane) of every actors.

+
+
Return type:
+

list of 2-tuple

+
+
+
+ +
+ +
+
+

HorizontalLayout#

+
+
+class fury.layout.HorizontalLayout(cell_padding=0, cell_shape='rect')[source]#
+

Bases: GridLayout

+

Provide functionalities for laying out actors in a horizontal layout.

+
+
+__init__(cell_padding=0, cell_shape='rect')[source]#
+

Initialize the Horizontal layout.

+
+
Parameters:
+
    +
  • cell_padding (2-tuple of float or float (optional)) – Each grid cell will be padded according to (pad_x, pad_y) i.e. +horizontally and vertically. Padding is evenly distributed on each +side of the cell. If a single float is provided then both pad_x and +pad_y will have the same value.

  • +
  • cell_shape ({'rect', 'square', 'diagonal'} (optional)) – Specifies the desired shape of every grid cell. +‘rect’ ensures the cells are the tightest. +‘square’ ensures the cells are as wide as high. +‘diagonal’ ensures the content of the cells can be rotated without +colliding with content of the neighboring cells.

  • +
+
+
+
+ +
+
+compute_positions(actors)[source]#
+

Compute the 3D coordinates of some actors. +The coordinates will lie on the xy-plane and form a horizontal stack.

+
+
Parameters:
+

actors (list of vtkProp3D objects) – Actors to be layout in a horizontal fashion.

+
+
Returns:
+

The computed 3D coordinates of every actors.

+
+
Return type:
+

list of 3-tuple

+
+
+
+ +
+ +
+
+

VerticalLayout#

+
+
+class fury.layout.VerticalLayout(cell_padding=0, cell_shape='rect')[source]#
+

Bases: GridLayout

+

Provide functionalities for laying out actors in a vertical stack.

+
+
+__init__(cell_padding=0, cell_shape='rect')[source]#
+

Initialize the Vertical layout.

+
+
Parameters:
+
    +
  • cell_padding (2-tuple of float or float (optional)) – Each cell will be padded according to (pad_x, pad_y) i.e. +horizontally and vertically. Padding is evenly distributed on each +side of the cell. If a single float is provided then both pad_x and +pad_y will have the same value.

  • +
  • cell_shape ({'rect', 'square', 'diagonal'} (optional)) – Specifies the desired shape of every cell. +‘rect’ ensures the cells are the tightest. +‘square’ ensures the cells are as wide as high. +‘diagonal’ ensures the content of the cells can be rotated without +colliding with content of the neighboring cells.

  • +
+
+
+
+ +
+
+compute_positions(actors)[source]#
+

Compute the 3D coordinates of some actors.

+
+
Parameters:
+

actors (list of vtkProp3D objects) – Actors to be layout in a vertical stack.

+
+
Returns:
+

The computed 3D coordinates of every actors.

+
+
Return type:
+

list of 3-tuple

+
+
+
+ +
+ +
+
+

XLayout#

+
+
+class fury.layout.XLayout(direction='x+', cell_padding=0, cell_shape='rect')[source]#
+

Bases: HorizontalLayout

+

Provide functionalities for laying out actors along x-axis.

+
+
+__init__(direction='x+', cell_padding=0, cell_shape='rect')[source]#
+

Initialize the X layout.

+
+
Parameters:
+
    +
  • direction (str, optional) – The direction of layout. +‘x+’ means actors will be placed along positive x-axis. +‘x-’ means actors will be placed along negative x-axis.

  • +
  • cell_padding (2-tuple of float or float (optional)) – Each cell will be padded according to (pad_x, pad_y) i.e. +horizontally and vertically. Padding is evenly distributed on each +side of the cell. If a single float is provided then both pad_x and +pad_y will have the same value.

  • +
  • cell_shape ({'rect', 'square', 'diagonal'} (optional)) – Specifies the desired shape of every cell. +‘rect’ ensures the cells are the tightest. +‘square’ ensures the cells are as wide as high. +‘diagonal’ ensures the content of the cells can be rotated without +colliding with content of the neighboring cells.

  • +
+
+
+
+ +
+
+apply(actors)[source]#
+

Position the actors according to a certain layout.

+
+ +
+
+compute_positions(actors)[source]#
+

Compute the 3D coordinates of some actors.

+

The coordinates will lie on the xy-plane and +will be placed along x-axis.

+
+
Parameters:
+

actors (list of vtkProp3D objects) – Actors to be layout along the x-axis.

+
+
Returns:
+

The computed 3D coordinates of every actors.

+
+
Return type:
+

list of 3-tuple

+
+
+
+ +
+
+get_cells_shape(actors)[source]#
+

Get the 2D shape (on the xy-plane) of some actors according to +self.cell_shape.

+
+
Parameters:
+

actors (list of vtkProp3D objects) – Actors from which to calculate the 2D shape.

+
+
Returns:
+

The 2D shape (on the xy-plane) of every actors.

+
+
Return type:
+

list of 2-tuple

+
+
+
+ +
+ +
+
+

YLayout#

+
+
+class fury.layout.YLayout(direction='y+', cell_padding=0, cell_shape='rect')[source]#
+

Bases: VerticalLayout

+

Provide functionalities for laying out actors along y-axis.

+
+
+__init__(direction='y+', cell_padding=0, cell_shape='rect')[source]#
+

Initialize the Y layout.

+
+
Parameters:
+
    +
  • direction (str, optional) – The direction of layout. +‘y+’ means actors will be placed along positive y-axis. +‘y-’ means actors will be placed along negative y-axis.

  • +
  • cell_padding (2-tuple of float or float (optional)) – Each cell will be padded according to (pad_x, pad_y) i.e. +horizontally and vertically. Padding is evenly distributed on each +side of the cell. If a single float is provided then both pad_x and +pad_y will have the same value.

  • +
  • cell_shape ({'rect', 'square', 'diagonal'} (optional)) – Specifies the desired shape of every cell. +‘rect’ ensures the cells are the tightest. +‘square’ ensures the cells are as wide as high. +‘diagonal’ ensures the content of the cells can be rotated without +colliding with content of the neighboring cells.

  • +
+
+
+
+ +
+
+apply(actors)[source]#
+

Position the actors according to a certain layout.

+
+ +
+
+compute_positions(actors)[source]#
+

Compute the 3D coordinates of some actors.

+

The coordinates will lie on the xy-plane and +will be placed along y-axis.

+
+
Parameters:
+

actors (list of vtkProp3D objects) – Actors to be layout along the y-axis.

+
+
Returns:
+

The computed 3D coordinates of every actors.

+
+
Return type:
+

list of 3-tuple

+
+
+
+ +
+
+get_cells_shape(actors)[source]#
+

Get the 2D shape (on the xy-plane) of some actors according to +self.cell_shape.

+
+
Parameters:
+

actors (list of vtkProp3D objects) – Actors from which to calculate the 2D shape.

+
+
Returns:
+

The 2D shape (on the xy-plane) of every actors.

+
+
Return type:
+

list of 2-tuple

+
+
+
+ +
+ +
+
+

ZLayout#

+
+
+class fury.layout.ZLayout(direction='z+', cell_padding=0, cell_shape='rect')[source]#
+

Bases: GridLayout

+

Provide functionalities for laying out actors along z-axis.

+
+
+__init__(direction='z+', cell_padding=0, cell_shape='rect')[source]#
+

Initialize the Z layout.

+
+
Parameters:
+
    +
  • direction (str, optional) – The direction of layout. +‘z+’ means actors will be placed along positive z-axis. +‘z-’ means actors will be placed along negative z-axis.

  • +
  • cell_padding (2-tuple of float or float (optional)) – Each cell will be padded according to (pad_x, pad_y) i.e. +horizontally and vertically. Padding is evenly distributed on each +side of the cell. If a single float is provided then both pad_x and +pad_y will have the same value.

  • +
  • cell_shape ({'rect', 'square', 'diagonal'} (optional)) – Specifies the desired shape of every cell. +‘rect’ ensures the cells are the tightest. +‘square’ ensures the cells are as wide as high. +‘diagonal’ ensures the content of the cells can be rotated without +colliding with content of the neighboring cells.

  • +
+
+
+
+ +
+
+apply(actors)[source]#
+

Position the actors according to a certain layout.

+
+ +
+
+compute_positions(actors)[source]#
+

Compute the 3D coordinates of some actors.

+
+
Parameters:
+

actors (list of vtkProp3D objects) – Actors to be layout along the z-axis.

+
+
Returns:
+

The computed 3D coordinates of every actors.

+
+
Return type:
+

list of 3-tuple

+
+
+
+ +
+
+get_cells_shape(actors)[source]#
+

Get the shape (on the z-plane) of some actors according to +self.cell_shape.

+
+
Parameters:
+

actors (list of vtkProp3D objects) – Actors from which to calculate the shape.

+
+
Returns:
+

The shape (on the z-plane) of every actors.

+
+
Return type:
+

list of floats

+
+
+
+ +
+ +
+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ + + +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/reference/fury.lib.html b/v0.10.x/reference/fury.lib.html new file mode 100644 index 000000000..55c6bf101 --- /dev/null +++ b/v0.10.x/reference/fury.lib.html @@ -0,0 +1,3954 @@ + + + + + + + + lib — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

lib#

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Command

class for callback/observer methods

LookupTable

class for LookupTable methods

Points

class for Points methods

IdTypeArray

class for IdTypeArray methods

FloatArray

class for FloatArray methods

DoubleArray

class for DoubleArray methods

StringArray

class for StringArray methods

UnsignedCharArray

class for UnsignedCharArray

AlgorithmOutput

class for AlgorithmOutput

Renderer

class for Renderer

Skybox

class for Skybox

Volume

class for Volume

Actor2D

class for Actor2D

Actor

class for Actor

RenderWindow

class for RenderWindow

RenderWindowInteractor

class for RenderWindowInteractor

InteractorEventRecorder

class for InteractorEventRecorder

WindowToImageFilter

class for WindowToImageFilter

InteractorStyle

class for InteractorStyle

PropPicker

class for PropPicker

PointPicker

class for PointPicker

CellPicker

class for CellPicker

WorldPointPicker

class for WorldPointPicker

HardwareSelector

class for HardwareSelector

ImageActor

class for ImageActor

PolyDataMapper

class for PolyDataMapper

PolyDataMapper2D

class for PolyDataMapper2D

Assembly

class for Assembly

DataSetMapper

class for DataSetMapper

Texture

class for Texture

TexturedActor2D

class for TexturedActor2D

Follower

class for Follower

TextActor

class for TextActor

TextActor3D

class for TextActor3D

Property2D

class for Property2D

Camera

class for Camera

VectorText

class for VectorText

LODActor

class for LODActor

ScalarBarActor

class for ScalarBarActor

OpenGLRenderer

class for OpenGLRenderer

Shader

class for Shader

InteractorStyleImage

class for InteractorStyleImage

InteractorStyleTrackballActor

class for InteractorStyleTrackballActor

InteractorStyleTrackballCamera

class for InteractorStyleTrackballCamera

InteractorStyleUser

class for InteractorStyleUser

CleanPolyData

class for CleanPolyData

PolyDataNormals

class for PolyDataNormals

ContourFilter

class for ContourFilter

TubeFilter

class for TubeFilter

Glyph3D

class for Glyph3D

TriangleFilter

class for TriangleFilter

SplineFilter

class for SplineFilter

TransformPolyDataFilter

class for TransformPolyDataFilter

RenderLargeImage

class for RenderLargeImage

LoopSubdivisionFilter

class for LoopSubdivisionFilter

ButterflySubdivisionFilter

class for ButterflySubdivisionFilter

OutlineFilter

class for OutlineFilter

LinearExtrusionFilter

class for LinearExtrusionFilter

TextureMapToPlane

class for TextureMapToPlane

SphereSource

class for SphereSource

CylinderSource

class for CylinderSource

ArrowSource

class for ArrowSource

ConeSource

class for ConeSource

DiskSource

class for DiskSource

TexturedSphereSource

class for TexturedSphereSource

RegularPolygonSource

class for RegularPolygonSource

PolyData

class for PolyData

ImageData

class for ImageData

DataObject

class for DataObject

CellArray

class for CellArray

PolyVertex

class for PolyVertex

UnstructuredGrid

class for UnstructuredGrid

Polygon

class for Polygon

DataObject

class for DataObject

Molecule

class for Molecule

DataSetAttributes

class for DataSetAttributes

Transform

class for Transform

Matrix4x4

class for Matrix4x4

Matrix3x3

class for Matrix3x3

ImageFlip

class for ImageFlip

ImageReslice

class for ImageReslice

ImageMapToColors

class for ImageMapToColors

ImageReader2Factory

class for ImageReader2Factory

PNGReader

class for PNGReader

BMPReader

class for BMPReader

JPEGReader

class for JPEGReader

TIFFReader

class for TIFFReader

PLYReader

class for PLYReader

STLReader

class for STLReader

OBJReader

class for OBJReader

MNIObjectReader

class for MNIObjectReader

PolyDataReader

class for PolyDataReader

XMLPolyDataReader

class for XMLPolyDataReader

PNGWriter

class for PNGWriter

BMPWriter

class for BMPWriter

JPEGWriter

class for JPEGWriter

TIFFWriter

class for TIFFWriter

PLYWriter

class for PLYWriter

STLWriter

class for STLWriter

MNIObjectWriter

class for MNIObjectWriter

PolyDataWriter

class for PolyDataWriter

XMLPolyDataWriter

class for XMLPolyDataWriter

SimpleBondPerceiver

class for SimpleBondPerceiver

ProteinRibbonFilter

class for ProteinRibbonFilter

PeriodicTable

class for PeriodicTable

OpenGLMoleculeMapper

class for OpenGLMoleculeMapper

VTK_VERSION

str(object='') -> str str(bytes_or_buffer[, encoding[, errors]]) -> str

+
+

Command#

+
+
+fury.lib.Command#
+

class for callback/observer methods

+
+ +
+
+

LookupTable#

+
+
+fury.lib.LookupTable#
+

class for LookupTable methods

+
+ +
+
+

Points#

+
+
+fury.lib.Points#
+

class for Points methods

+
+ +
+
+

IdTypeArray#

+
+
+fury.lib.IdTypeArray#
+

class for IdTypeArray methods

+
+ +
+
+

FloatArray#

+
+
+fury.lib.FloatArray#
+

class for FloatArray methods

+
+ +
+
+

DoubleArray#

+
+
+fury.lib.DoubleArray#
+

class for DoubleArray methods

+
+ +
+
+

StringArray#

+
+
+fury.lib.StringArray#
+

class for StringArray methods

+
+ +
+
+

UnsignedCharArray#

+
+
+fury.lib.UnsignedCharArray#
+

class for UnsignedCharArray

+
+ +
+
+

AlgorithmOutput#

+
+
+fury.lib.AlgorithmOutput#
+

class for AlgorithmOutput

+
+ +
+
+

Renderer#

+
+
+fury.lib.Renderer#
+

class for Renderer

+
+ +
+
+

Skybox#

+
+
+fury.lib.Skybox#
+

class for Skybox

+
+ +
+
+

Volume#

+
+
+fury.lib.Volume#
+

class for Volume

+
+ +
+
+

Actor2D#

+
+
+fury.lib.Actor2D#
+

class for Actor2D

+
+ +
+
+

Actor#

+
+
+fury.lib.Actor#
+

class for Actor

+
+ +
+
+

RenderWindow#

+
+
+fury.lib.RenderWindow#
+

class for RenderWindow

+
+ +
+
+

RenderWindowInteractor#

+
+
+fury.lib.RenderWindowInteractor#
+

class for RenderWindowInteractor

+
+ +
+
+

InteractorEventRecorder#

+
+
+fury.lib.InteractorEventRecorder#
+

class for InteractorEventRecorder

+
+ +
+
+

WindowToImageFilter#

+
+
+fury.lib.WindowToImageFilter#
+

class for WindowToImageFilter

+
+ +
+
+

InteractorStyle#

+
+
+fury.lib.InteractorStyle#
+

class for InteractorStyle

+
+ +
+
+

PropPicker#

+
+
+fury.lib.PropPicker#
+

class for PropPicker

+
+ +
+
+

PointPicker#

+
+
+fury.lib.PointPicker#
+

class for PointPicker

+
+ +
+
+

CellPicker#

+
+
+fury.lib.CellPicker#
+

class for CellPicker

+
+ +
+
+

WorldPointPicker#

+
+
+fury.lib.WorldPointPicker#
+

class for WorldPointPicker

+
+ +
+
+

HardwareSelector#

+
+
+fury.lib.HardwareSelector#
+

class for HardwareSelector

+
+ +
+
+

ImageActor#

+
+
+fury.lib.ImageActor#
+

class for ImageActor

+
+ +
+
+

PolyDataMapper#

+
+
+fury.lib.PolyDataMapper#
+

class for PolyDataMapper

+
+ +
+
+

PolyDataMapper2D#

+
+
+fury.lib.PolyDataMapper2D#
+

class for PolyDataMapper2D

+
+ +
+
+

Assembly#

+
+
+fury.lib.Assembly#
+

class for Assembly

+
+ +
+
+

DataSetMapper#

+
+
+fury.lib.DataSetMapper#
+

class for DataSetMapper

+
+ +
+
+

Texture#

+
+
+fury.lib.Texture#
+

class for Texture

+
+ +
+
+

TexturedActor2D#

+
+
+fury.lib.TexturedActor2D#
+

class for TexturedActor2D

+
+ +
+
+

Follower#

+
+
+fury.lib.Follower#
+

class for Follower

+
+ +
+
+

TextActor#

+
+
+fury.lib.TextActor#
+

class for TextActor

+
+ +
+
+

TextActor3D#

+
+
+fury.lib.TextActor3D#
+

class for TextActor3D

+
+ +
+
+

Property2D#

+
+
+fury.lib.Property2D#
+

class for Property2D

+
+ +
+
+

Camera#

+
+
+fury.lib.Camera#
+

class for Camera

+
+ +
+
+

VectorText#

+
+
+fury.lib.VectorText#
+

class for VectorText

+
+ +
+
+

LODActor#

+
+
+fury.lib.LODActor#
+

class for LODActor

+
+ +
+
+

ScalarBarActor#

+
+
+fury.lib.ScalarBarActor#
+

class for ScalarBarActor

+
+ +
+
+

OpenGLRenderer#

+
+
+fury.lib.OpenGLRenderer#
+

class for OpenGLRenderer

+
+ +
+
+

Shader#

+
+
+fury.lib.Shader#
+

class for Shader

+
+ +
+
+

InteractorStyleImage#

+
+
+fury.lib.InteractorStyleImage#
+

class for InteractorStyleImage

+
+ +
+
+

InteractorStyleTrackballActor#

+
+
+fury.lib.InteractorStyleTrackballActor#
+

class for InteractorStyleTrackballActor

+
+ +
+
+

InteractorStyleTrackballCamera#

+
+
+fury.lib.InteractorStyleTrackballCamera#
+

class for InteractorStyleTrackballCamera

+
+ +
+
+

InteractorStyleUser#

+
+
+fury.lib.InteractorStyleUser#
+

class for InteractorStyleUser

+
+ +
+
+

CleanPolyData#

+
+
+fury.lib.CleanPolyData#
+

class for CleanPolyData

+
+ +
+
+

PolyDataNormals#

+
+
+fury.lib.PolyDataNormals#
+

class for PolyDataNormals

+
+ +
+
+

ContourFilter#

+
+
+fury.lib.ContourFilter#
+

class for ContourFilter

+
+ +
+
+

TubeFilter#

+
+
+fury.lib.TubeFilter#
+

class for TubeFilter

+
+ +
+
+

Glyph3D#

+
+
+fury.lib.Glyph3D#
+

class for Glyph3D

+
+ +
+
+

TriangleFilter#

+
+
+fury.lib.TriangleFilter#
+

class for TriangleFilter

+
+ +
+
+

SplineFilter#

+
+
+fury.lib.SplineFilter#
+

class for SplineFilter

+
+ +
+
+

TransformPolyDataFilter#

+
+
+fury.lib.TransformPolyDataFilter#
+

class for TransformPolyDataFilter

+
+ +
+
+

RenderLargeImage#

+
+
+fury.lib.RenderLargeImage#
+

class for RenderLargeImage

+
+ +
+
+

LoopSubdivisionFilter#

+
+
+fury.lib.LoopSubdivisionFilter#
+

class for LoopSubdivisionFilter

+
+ +
+
+

ButterflySubdivisionFilter#

+
+
+fury.lib.ButterflySubdivisionFilter#
+

class for ButterflySubdivisionFilter

+
+ +
+
+

OutlineFilter#

+
+
+fury.lib.OutlineFilter#
+

class for OutlineFilter

+
+ +
+
+

LinearExtrusionFilter#

+
+
+fury.lib.LinearExtrusionFilter#
+

class for LinearExtrusionFilter

+
+ +
+
+

TextureMapToPlane#

+
+
+fury.lib.TextureMapToPlane#
+

class for TextureMapToPlane

+
+ +
+
+

SphereSource#

+
+
+fury.lib.SphereSource#
+

class for SphereSource

+
+ +
+
+

CylinderSource#

+
+
+fury.lib.CylinderSource#
+

class for CylinderSource

+
+ +
+
+

ArrowSource#

+
+
+fury.lib.ArrowSource#
+

class for ArrowSource

+
+ +
+
+

ConeSource#

+
+
+fury.lib.ConeSource#
+

class for ConeSource

+
+ +
+
+

DiskSource#

+
+
+fury.lib.DiskSource#
+

class for DiskSource

+
+ +
+
+

TexturedSphereSource#

+
+
+fury.lib.TexturedSphereSource#
+

class for TexturedSphereSource

+
+ +
+
+

RegularPolygonSource#

+
+
+fury.lib.RegularPolygonSource#
+

class for RegularPolygonSource

+
+ +
+
+

PolyData#

+
+
+fury.lib.PolyData#
+

class for PolyData

+
+ +
+
+

ImageData#

+
+
+fury.lib.ImageData#
+

class for ImageData

+
+ +
+
+

DataObject#

+
+
+fury.lib.DataObject#
+

class for DataObject

+
+ +
+
+

CellArray#

+
+
+fury.lib.CellArray#
+

class for CellArray

+
+ +
+
+

PolyVertex#

+
+
+fury.lib.PolyVertex#
+

class for PolyVertex

+
+ +
+
+

UnstructuredGrid#

+
+
+fury.lib.UnstructuredGrid#
+

class for UnstructuredGrid

+
+ +
+
+

Polygon#

+
+
+fury.lib.Polygon#
+

class for Polygon

+
+ +
+
+

DataObject#

+
+
+fury.lib.DataObject#
+

class for DataObject

+
+ +
+
+

Molecule#

+
+
+fury.lib.Molecule#
+

class for Molecule

+
+ +
+
+

DataSetAttributes#

+
+
+fury.lib.DataSetAttributes#
+

class for DataSetAttributes

+
+ +
+
+

Transform#

+
+
+fury.lib.Transform#
+

class for Transform

+
+ +
+
+

Matrix4x4#

+
+
+fury.lib.Matrix4x4#
+

class for Matrix4x4

+
+ +
+
+

Matrix3x3#

+
+
+fury.lib.Matrix3x3#
+

class for Matrix3x3

+
+ +
+
+

ImageFlip#

+
+
+fury.lib.ImageFlip#
+

class for ImageFlip

+
+ +
+
+

ImageReslice#

+
+
+fury.lib.ImageReslice#
+

class for ImageReslice

+
+ +
+
+

ImageMapToColors#

+
+
+fury.lib.ImageMapToColors#
+

class for ImageMapToColors

+
+ +
+
+

ImageReader2Factory#

+
+
+fury.lib.ImageReader2Factory#
+

class for ImageReader2Factory

+
+ +
+
+

PNGReader#

+
+
+fury.lib.PNGReader#
+

class for PNGReader

+
+ +
+
+

BMPReader#

+
+
+fury.lib.BMPReader#
+

class for BMPReader

+
+ +
+
+

JPEGReader#

+
+
+fury.lib.JPEGReader#
+

class for JPEGReader

+
+ +
+
+

TIFFReader#

+
+
+fury.lib.TIFFReader#
+

class for TIFFReader

+
+ +
+
+

PLYReader#

+
+
+fury.lib.PLYReader#
+

class for PLYReader

+
+ +
+
+

STLReader#

+
+
+fury.lib.STLReader#
+

class for STLReader

+
+ +
+
+

OBJReader#

+
+
+fury.lib.OBJReader#
+

class for OBJReader

+
+ +
+
+

MNIObjectReader#

+
+
+fury.lib.MNIObjectReader#
+

class for MNIObjectReader

+
+ +
+
+

PolyDataReader#

+
+
+fury.lib.PolyDataReader#
+

class for PolyDataReader

+
+ +
+
+

XMLPolyDataReader#

+
+
+fury.lib.XMLPolyDataReader#
+

class for XMLPolyDataReader

+
+ +
+
+

PNGWriter#

+
+
+fury.lib.PNGWriter#
+

class for PNGWriter

+
+ +
+
+

BMPWriter#

+
+
+fury.lib.BMPWriter#
+

class for BMPWriter

+
+ +
+
+

JPEGWriter#

+
+
+fury.lib.JPEGWriter#
+

class for JPEGWriter

+
+ +
+
+

TIFFWriter#

+
+
+fury.lib.TIFFWriter#
+

class for TIFFWriter

+
+ +
+
+

PLYWriter#

+
+
+fury.lib.PLYWriter#
+

class for PLYWriter

+
+ +
+
+

STLWriter#

+
+
+fury.lib.STLWriter#
+

class for STLWriter

+
+ +
+
+

MNIObjectWriter#

+
+
+fury.lib.MNIObjectWriter#
+

class for MNIObjectWriter

+
+ +
+
+

PolyDataWriter#

+
+
+fury.lib.PolyDataWriter#
+

class for PolyDataWriter

+
+ +
+
+

XMLPolyDataWriter#

+
+
+fury.lib.XMLPolyDataWriter#
+

class for XMLPolyDataWriter

+
+ +
+
+

SimpleBondPerceiver#

+
+
+fury.lib.SimpleBondPerceiver#
+

class for SimpleBondPerceiver

+
+ +
+
+

ProteinRibbonFilter#

+
+
+fury.lib.ProteinRibbonFilter#
+

class for ProteinRibbonFilter

+
+ +
+
+

PeriodicTable#

+
+
+fury.lib.PeriodicTable#
+

class for PeriodicTable

+
+ +
+
+

OpenGLMoleculeMapper#

+
+
+fury.lib.OpenGLMoleculeMapper#
+

class for OpenGLMoleculeMapper

+
+ +
+
+

VTK_VERSION#

+
+
+fury.lib.VTK_VERSION()#
+

str(object=’’) -> str +str(bytes_or_buffer[, encoding[, errors]]) -> str

+

Create a new string object from the given object. If encoding or +errors is specified, then the object must expose a data buffer +that will be decoded using the given encoding and error handler. +Otherwise, returns the result of object.__str__() (if defined) +or repr(object). +encoding defaults to sys.getdefaultencoding(). +errors defaults to ‘strict’.

+
+ +
+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ +
+ On this page +
+ +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/reference/fury.material.html b/v0.10.x/reference/fury.material.html new file mode 100644 index 000000000..665240395 --- /dev/null +++ b/v0.10.x/reference/fury.material.html @@ -0,0 +1,679 @@ + + + + + + + + material — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

material#

+ + + + + + + + + + + + +

manifest_pbr(actor[, metallic, roughness, ...])

Apply VTK's Physically Based Rendering properties to the selected actor.

manifest_principled(actor[, subsurface, ...])

Apply the Principled Shading properties to the selected actor.

manifest_standard(actor[, ambient_level, ...])

Apply the standard material to the selected actor.

+
+

manifest_pbr#

+
+
+fury.material.manifest_pbr(actor, metallic=0, roughness=0.5, anisotropy=0, anisotropy_rotation=0, coat_strength=0, coat_roughness=0, base_ior=1.5, coat_ior=2)[source]#
+

Apply VTK’s Physically Based Rendering properties to the selected actor.

+
+
Parameters:
+
    +
  • actor (actor) –

  • +
  • metallic (float, optional) – Metallic or non-metallic (dielectric) shading computation value. Values +must be between 0.0 and 1.0.

  • +
  • roughness (float, optional) – Parameter used to specify how glossy the actor should be. Values must +be between 0.0 and 1.0.

  • +
  • anisotropy (float, optional) – Isotropic or anisotropic material parameter. Values must be between +0.0 and 1.0.

  • +
  • anisotropy_rotation (float, optional) – Rotation of the anisotropy around the normal in a counter-clockwise +fashion. Values must be between 0.0 and 1.0. A value of 1.0 means a +rotation of 2 * pi.

  • +
  • coat_strength (float, optional) – Strength of the coat layer. Values must be between 0.0 and 1.0 (0.0 +means no clear coat will be modeled).

  • +
  • coat_roughness (float, optional) – Roughness of the coat layer. Values must be between 0.0 and 1.0.

  • +
  • base_ior (float, optional) – Index of refraction of the base material. Default is 1.5. Values must +be between 1.0 and 2.3.

  • +
  • coat_ior (float, optional) – Index of refraction of the coat material. Default is 1.5. Values must +be between 1.0 and 2.3.

  • +
+
+
+
+ +
+
+

manifest_principled#

+
+
+fury.material.manifest_principled(actor, subsurface=0, metallic=0, specular=0, specular_tint=0, roughness=0, anisotropic=0, anisotropic_direction=[0, 1, 0.5], sheen=0, sheen_tint=0, clearcoat=0, clearcoat_gloss=0)[source]#
+

Apply the Principled Shading properties to the selected actor.

+
+
Parameters:
+
    +
  • actor (actor) –

  • +
  • subsurface (float, optional) – Subsurface scattering computation value. Values must be between 0.0 and +1.0.

  • +
  • metallic (float, optional) – Metallic or non-metallic (dielectric) shading computation value. Values +must be between 0.0 and 1.0.

  • +
  • specular (float, optional) – Specular lighting coefficient. Value must be between 0.0 and 1.0.

  • +
  • specular_tint (float, optional) – Specular tint coefficient value. Values must be between 0.0 and 1.0.

  • +
  • roughness (float, optional) – Parameter used to specify how glossy the actor should be. Values must +be between 0.0 and 1.0.

  • +
  • anisotropic (float, optional) – Anisotropy coefficient. Values must be between 0.0 and 1.0.

  • +
  • anisotropic_direction (list, optional) – Anisotropy direction where X, Y and Z should be in the range [-1, 1].

  • +
  • sheen (float, optional) – Sheen coefficient. Values must be between 0.0 and 1.0.

  • +
  • sheen_tint (float, optional) – Sheen tint coefficient value. Values must be between 0.0 and 1.0.

  • +
  • clearcoat (float, optional) – Clearcoat coefficient. Values must be between 0.0 and 1.0.

  • +
  • clearcoat_gloss (float, optional) – Clearcoat gloss coefficient value. Values must be between 0.0 and 1.0.

  • +
+
+
Returns:
+

principled_params – Dictionary containing the Principled Shading parameters.

+
+
Return type:
+

dict

+
+
+
+ +
+
+

manifest_standard#

+
+
+fury.material.manifest_standard(actor, ambient_level=0, ambient_color=(1, 1, 1), diffuse_level=1, diffuse_color=(1, 1, 1), specular_level=0, specular_color=(1, 1, 1), specular_power=1, interpolation='gouraud')[source]#
+

Apply the standard material to the selected actor.

+
+
Parameters:
+
    +
  • actor (actor) –

  • +
  • ambient_level (float, optional) – Ambient lighting coefficient. Value must be between 0.0 and 1.0.

  • +
  • ambient_color (tuple (3,), optional) – Ambient RGB color where R, G and B should be in the range [0, 1].

  • +
  • diffuse_level (float, optional) – Diffuse lighting coefficient. Value must be between 0.0 and 1.0.

  • +
  • diffuse_color (tuple (3,), optional) – Diffuse RGB color where R, G and B should be in the range [0, 1].

  • +
  • specular_level (float, optional) – Specular lighting coefficient. Value must be between 0.0 and 1.0.

  • +
  • specular_color (tuple (3,), optional) – Specular RGB color where R, G and B should be in the range [0, 1].

  • +
  • specular_power (float, optional) – Parameter used to specify the intensity of the specular reflection. +Value must be between 0.0 and 128.0.

  • +
  • interpolation (string, optional) – If ‘flat’, the actor will be shaded using flat interpolation. If +‘gouraud’ (default), then the shading will be calculated at the +vertex level. If ‘phong’, then the shading will be calculated at the +fragment level.

  • +
+
+
+
+ +
+
+ +
+ + +
+ +
+ + + + + +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/reference/fury.molecular.html b/v0.10.x/reference/fury.molecular.html new file mode 100644 index 000000000..4fe831ac8 --- /dev/null +++ b/v0.10.x/reference/fury.molecular.html @@ -0,0 +1,1573 @@ + + + + + + + + molecular — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

molecular#

+

Module that provides molecular visualization tools.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Molecule([atomic_numbers, coords, ...])

Your molecule class.

PTable

A class to obtain properties of elements (eg: Covalent Radius, Van Der Waals Radius, Symbol etc.).

add_atom(molecule, atomic_num, x_coord, ...)

Add atomic data to our molecule.

add_bond(molecule, atom1_index, atom2_index)

Add bonding data to our molecule.

get_atomic_number(molecule, atom_index)

Get the atomic number of an atom for a specified index.

set_atomic_number(molecule, atom_index, ...)

Set the atomic number of an atom for a specified index.

get_atomic_position(molecule, atom_index)

Get the atomic coordinates of an atom for a specified index.

set_atomic_position(molecule, atom_index, ...)

Set the atomic coordinates of an atom for a specified index.

get_bond_order(molecule, bond_index)

Get the order of bond for a specified index.

set_bond_order(molecule, bond_index, bond_order)

Set the bond order of a bond for a specified index.

get_all_atomic_numbers(molecule)

Return an array of atomic numbers corresponding to the atoms present in a given molecule.

get_all_bond_orders(molecule)

Return an array of integers containing the bond orders (single/double/ triple) corresponding to the bonds present in the molecule.

get_all_atomic_positions(molecule)

Return an array of atomic coordinates corresponding to the atoms present in the molecule.

deep_copy_molecule(molecule1, molecule2)

Deep copies the atomic information (atoms and bonds) from molecule2 into molecule1.

compute_bonding(molecule)

Uses vtkSimpleBondPerceiver to generate bonding information for a molecule.

sphere_cpk(molecule[, colormode])

Create an actor for sphere molecular representation.

ball_stick(molecule[, colormode, ...])

Create an actor for ball and stick molecular representation.

stick(molecule[, colormode, bond_thickness])

Create an actor for stick molecular representation.

ribbon(molecule)

Create an actor for ribbon molecular representation.

bounding_box(molecule[, colors, linewidth])

Create a bounding box for a molecule.

+
+

Molecule#

+
+
+class fury.molecular.Molecule(atomic_numbers=None, coords=None, atom_names=None, model=None, residue_seq=None, chain=None, sheet=None, helix=None, is_hetatm=None)[source]#
+

Bases: vtkMolecule

+

Your molecule class.

+

An object that is used to create molecules and store molecular data (e.g. +coordinate and bonding data). +This is a more pythonic version of Molecule.

+
+
+__init__(atomic_numbers=None, coords=None, atom_names=None, model=None, residue_seq=None, chain=None, sheet=None, helix=None, is_hetatm=None)[source]#
+

Send the atomic data to the molecule.

+
+
Parameters:
+
    +
  • atomic_numbers (ndarray of integers, optional) – The shape of the array must be (N, ) where N is the total number of +atoms present in the molecule. +Array having atomic number corresponding to each atom of the +molecule.

  • +
  • coords (ndarray of floats, optional) – The shape of the array must be (N, 3) where N is the total number +of atoms present in the molecule. +Array having coordinates corresponding to each atom of the +molecule.

  • +
  • atom_names (ndarray of strings, optional) – The shape of the array must be (N, ) where N is the total number of +atoms present in the molecule. +Array having the names of atoms.

  • +
  • model (ndarray of integers, optional) – The shape of the array must be (N, ) where N is the total number of +atoms present in the molecule. +Array having the model number corresponding to each atom.

  • +
  • residue_seq (ndarray of integers, optional) – The shape of the array must be (N, ) where N is the total number of +atoms present in the molecule. +Array having the residue sequence number corresponding to each atom +of the molecule.

  • +
  • chain (ndarray of integers, optional) – The shape of the array must be (N, ) where N is the total number of +atoms present in the molecule. +Array having the chain number corresponding to each atom.

  • +
  • sheet (ndarray of integers, optional) – The shape of the array must be (S, 4) where S is the total number +of sheets present in the molecule. +Array containing information about sheets present in the molecule.

  • +
  • helix (ndarray of integers, optional) – The shape of the array must be (H, 4) where H is the total number +of helices present in the molecule. +Array containing information about helices present in the molecule.

  • +
  • is_hetatm (ndarray of bools, optional) – The shape of the array must be (N, ) where N is the total number of +atoms present in the molecule. +Array containing a bool value to indicate if an atom is a +heteroatom.

  • +
+
+
+
+ +
+
+property total_num_atoms#
+

Return the total number of atoms in a given molecule.

+
+ +
+
+property total_num_bonds#
+

Return the total number of bonds in a given molecule.

+
+ +
+ +
+
+

PTable#

+
+
+class fury.molecular.PTable[source]#
+

Bases: vtkPeriodicTable

+

A class to obtain properties of elements (eg: Covalent Radius, +Van Der Waals Radius, Symbol etc.).

+

This is a more pythonic version of vtkPeriodicTable providing simple +methods to access atomic properties. It provides access to essential +functionality available in vtkPeriodicTable. An object of this class +provides access to atomic information sourced from Blue Obelisk Data +Repository.

+
+
+__init__()#
+
+ +
+
+atom_color(atomic_number)[source]#
+

Given an atomic number, return the RGB tuple associated with that +element (CPK coloring convention) provided by the Blue Obelisk Data +Repository.

+
+
Parameters:
+

atomicNumber (int) – Atomic number of the element whose RGB tuple is to be obtained.

+
+
+
+ +
+
+atomic_number(element_name)[source]#
+

Given a case-insensitive string that contains the symbol or name of +an element, return the corresponding atomic number.

+
+
Parameters:
+

element_name (string) – Name of the element whose atomic number is to be obtained.

+
+
+
+ +
+
+atomic_radius(atomic_number, radius_type='VDW')[source]#
+

Given an atomic number, return either the covalent radius of the +atom (in Å) or return the Van Der Waals radius (in Å) of the atom +depending on radius_type.

+
+
Parameters:
+
    +
  • atomic_number (int) – Atomic number of the element whose atomic radius is to be obtained.

  • +
  • radius_type (string) –

    Type of atomic radius to be obtained. Two valid choices:

    +
      +
    • ’VDW’ : for Van der Waals radius of the atom

    • +
    • ’Covalent’ : for covalent radius of the atom

    • +
    +

    Default: ‘VDW’

    +

  • +
+
+
+
+ +
+
+atomic_symbol(atomic_number)[source]#
+

Given an atomic number, returns the symbol associated with the +element.

+
+
Parameters:
+

atomic_number (int) – Atomic number of the element whose symbol is to be obtained.

+
+
+
+ +
+
+element_name(atomic_number)[source]#
+

Given an atomic number, returns the name of the element.

+
+
Parameters:
+

atomic_number (int) – Atomic number of the element whose name is to be obtained.

+
+
+
+ +
+ +
+
+

add_atom#

+
+
+fury.molecular.add_atom(molecule, atomic_num, x_coord, y_coord, z_coord)[source]#
+

Add atomic data to our molecule.

+
+
Parameters:
+
    +
  • molecule (Molecule) – The molecule to which the atom is to be added.

  • +
  • atomic_num (int) – Atomic number of the atom.

  • +
  • x_coord (float) – x-coordinate of the atom.

  • +
  • y_coord (float) – y-coordinate of the atom.

  • +
  • z_coord (float) – z-coordinate of the atom.

  • +
+
+
+
+ +
+
+

add_bond#

+
+
+fury.molecular.add_bond(molecule, atom1_index, atom2_index, bond_order=1)[source]#
+

Add bonding data to our molecule. Establish a bond of type bond_order +between the atom at atom1_index and the atom at atom2_index.

+
+
Parameters:
+
    +
  • molecule (Molecule) – The molecule to which the bond is to be added.

  • +
  • atom1_index (int) – Index of the first atom.

  • +
  • atom2_index (int) – Index of the second atom.

  • +
  • bond_order (int (optional)) – Bond order (whether it’s a single/double/triple bond). Default: 1

  • +
+
+
+

Notes

+

Ensure that the total number of bonds between two atoms doesn’t exceed 3. +Calling add_bond to add bonds between atoms that already have a triple +bond between them leads to erratic behavior and must be avoided.

+
+ +
+
+

get_atomic_number#

+
+
+fury.molecular.get_atomic_number(molecule, atom_index)[source]#
+

Get the atomic number of an atom for a specified index.

+

Returns the atomic number of the atom present at index atom_index.

+
+
Parameters:
+
    +
  • molecule (Molecule) – The molecule to which the atom belongs.

  • +
  • atom_index (int) – Index of the atom whose atomic number is to be obtained.

  • +
+
+
+
+ +
+
+

set_atomic_number#

+
+
+fury.molecular.set_atomic_number(molecule, atom_index, atomic_num)[source]#
+

Set the atomic number of an atom for a specified index.

+

Assign atomic_num as the atomic number of the atom present at +atom_index.

+
+
Parameters:
+
    +
  • molecule (Molecule) – The molecule to which the atom belongs.

  • +
  • atom_index (int) – Index of the atom to whom the atomic number is to be assigned.

  • +
  • atom_num (int) – Atomic number to be assigned to the atom.

  • +
+
+
+
+ +
+
+

get_atomic_position#

+
+
+fury.molecular.get_atomic_position(molecule, atom_index)[source]#
+

Get the atomic coordinates of an atom for a specified index.

+

Returns the atomic coordinates of the atom present at index atom_index.

+
+
Parameters:
+
    +
  • molecule (Molecule) – The molecule to which the atom belongs.

  • +
  • atom_index (int) – Index of the atom whose atomic coordinates are to be obtained.

  • +
+
+
+
+ +
+
+

set_atomic_position#

+
+
+fury.molecular.set_atomic_position(molecule, atom_index, x_coord, y_coord, z_coord)[source]#
+

Set the atomic coordinates of an atom for a specified index.

+

Assign atom_coordinate to the coordinates of the atom present at +atom_index.

+
+
Parameters:
+
    +
  • molecule (Molecule) – The molecule to which the atom belongs.

  • +
  • atom_index (int) – Index of the atom to which the coordinates are to be assigned.

  • +
  • x_coord (float) – x-coordinate of the atom.

  • +
  • y_coord (float) – y-coordinate of the atom.

  • +
  • z_coord (float) – z-coordinate of the atom.

  • +
+
+
+
+ +
+
+

get_bond_order#

+
+
+fury.molecular.get_bond_order(molecule, bond_index)[source]#
+

Get the order of bond for a specified index.

+

Returns the order of bond (whether it’s a single/double/triple bond) +present at bond_index.

+
+
Parameters:
+
    +
  • molecule (Molecule) – The molecule to which the bond belongs.

  • +
  • bond_index (int) – Index of the bond whose order is to be obtained.

  • +
+
+
+
+ +
+
+

set_bond_order#

+
+
+fury.molecular.set_bond_order(molecule, bond_index, bond_order)[source]#
+

Set the bond order of a bond for a specified index.

+

Assign bond_order (whether it’s a single/double/triple bond) to the bond +present at the bond_index.

+
+
Parameters:
+
    +
  • molecule (Molecule) – The molecule to which the bond belongs.

  • +
  • bond_index (int) – Index of the bond whose order is to be assigned.

  • +
  • bond_order (int) – Bond order (whether it’s a single/double/triple bond).

  • +
+
+
+
+ +
+
+

get_all_atomic_numbers#

+
+
+fury.molecular.get_all_atomic_numbers(molecule)[source]#
+

Return an array of atomic numbers corresponding to the atoms +present in a given molecule.

+
+
Parameters:
+

molecule (Molecule) – The molecule whose atomic number array is to be obtained.

+
+
+
+ +
+
+

get_all_bond_orders#

+
+
+fury.molecular.get_all_bond_orders(molecule)[source]#
+

Return an array of integers containing the bond orders (single/double/ +triple) corresponding to the bonds present in the molecule.

+
+
Parameters:
+

molecule (Molecule) – The molecule whose bond types array is to be obtained.

+
+
+
+ +
+
+

get_all_atomic_positions#

+
+
+fury.molecular.get_all_atomic_positions(molecule)[source]#
+

Return an array of atomic coordinates corresponding to the atoms +present in the molecule.

+
+
Parameters:
+

molecule (Molecule) – The molecule whose atomic position array is to be obtained.

+
+
+
+ +
+
+

deep_copy_molecule#

+
+
+fury.molecular.deep_copy_molecule(molecule1, molecule2)[source]#
+

Deep copies the atomic information (atoms and bonds) from molecule2 into +molecule1.

+
+
Parameters:
+
    +
  • molecule1 (Molecule) – The molecule to which the atomic information is copied.

  • +
  • molecule2 (Molecule) – The molecule from which the atomic information is copied.

  • +
+
+
+
+ +
+
+

compute_bonding#

+
+
+fury.molecular.compute_bonding(molecule)[source]#
+

Uses vtkSimpleBondPerceiver to generate bonding information for a +molecule. +vtkSimpleBondPerceiver performs a simple check of all interatomic +distances and adds a single bond between atoms that are reasonably +close. If the interatomic distance is less than the sum of the two +atom’s covalent radii plus a tolerance, a single bond is added.

+
+
Parameters:
+

molecule (Molecule) – The molecule for which bonding information is to be generated.

+
+
+

Notes

+

This algorithm does not consider valences, hybridization, aromaticity, +or anything other than atomic separations. It will not produce anything +other than single bonds.

+
+ +
+
+

sphere_cpk#

+
+
+fury.molecular.sphere_cpk(molecule, colormode='discrete')[source]#
+

Create an actor for sphere molecular representation. It’s also referred +to as CPK model and space-filling model.

+
+
Parameters:
+
    +
  • molecule (Molecule) – The molecule to be rendered.

  • +
  • colormode (string, optional) –

    Set the colormode for coloring the atoms. Two valid color modes:

    +
      +
    • ’discrete’: Atoms are colored using CPK coloring convention.

    • +
    • ’single’: All atoms are colored with same color (grey). RGB tuple +used for coloring the atoms when ‘single’ colormode is selected: +(150, 150, 150).

    • +
    +

    Default: ‘discrete’

    +

  • +
+
+
Returns:
+

molecule_actor – Actor created to render the space filling representation of the +molecule to be visualized.

+
+
Return type:
+

vtkActor

+
+
+

References

+

Corey R.B.; Pauling L. Molecular Models of Amino Acids, +Peptides, and Proteins +Review of Scientific Instruments 1953, 24 (8), 621-627.

+
+ +
+
+

ball_stick#

+
+
+fury.molecular.ball_stick(molecule, colormode='discrete', atom_scale_factor=0.3, bond_thickness=0.1, multiple_bonds=True)[source]#
+

Create an actor for ball and stick molecular representation.

+
+
Parameters:
+
    +
  • molecule (Molecule) – The molecule to be rendered.

  • +
  • colormode (string, optional) –

    Set the colormode for coloring the atoms. Two valid color modes:

    +
      +
    • ’discrete’: Atoms and bonds are colored using CPK coloring +convention.

    • +
    • ’single’: All atoms are colored with same color (grey) and all bonds +are colored with same color (dark grey). RGB tuple used for coloring +the atoms when ‘single’ colormode is selected: (150, 150, 150). RGB +tuple used for coloring the bonds when ‘single’ colormode is +selected: (50, 50, 50)

    • +
    +

    Default: ‘discrete’

    +

  • +
  • atom_scale_factor (float, optional) – Scaling factor. Default: 0.3

  • +
  • bond_thickness (float, optional) – Used to manipulate the thickness of bonds (i.e. thickness of tubes +which are used to render bonds) +Default: 0.1 (Optimal range: 0.1 - 0.5).

  • +
  • multiple_bonds (bool, optional) – Set whether multiple tubes will be used to represent multiple +bonds. If True, multiple bonds (double, triple) will be shown by using +multiple tubes. If False, all bonds (single, double, triple) will be +shown as single bonds (i.e. shown using one tube each). +Default is True.

  • +
+
+
Returns:
+

molecule_actor – Actor created to render the ball and stick representation of the +molecule to be visualized.

+
+
Return type:
+

vtkActor

+
+
+

References

+

Turner, M. Ball and stick models for organic chemistry +J. Chem. Educ. 1971, 48, 6, 407.

+
+ +
+
+

stick#

+
+
+fury.molecular.stick(molecule, colormode='discrete', bond_thickness=0.1)[source]#
+

Create an actor for stick molecular representation.

+
+
Parameters:
+
    +
  • molecule (Molecule) – The molecule to be rendered.

  • +
  • colormode (string, optional) –

    Set the colormode for coloring the bonds. Two valid color modes:

    +
      +
    • ’discrete’: Bonds are colored using CPK coloring convention.

    • +
    • ’single’: All bonds are colored with the same color (dark grey) +RGB tuple used for coloring the bonds when ‘single’ colormode is +selected: (50, 50, 50)

    • +
    +

    Default: ‘discrete’

    +

  • +
  • bond_thickness (float, optional) – Used to manipulate the thickness of bonds (i.e. thickness of tubes +which are used to render bonds). +Default: 0.1 (Optimal range: 0.1 - 0.5).

  • +
+
+
Returns:
+

molecule_actor – Actor created to render the stick representation of the molecule to be +visualized.

+
+
Return type:
+

vtkActor

+
+
+
+ +
+
+

ribbon#

+
+
+fury.molecular.ribbon(molecule)[source]#
+

Create an actor for ribbon molecular representation.

+
+
Parameters:
+

molecule (Molecule) – The molecule to be rendered.

+
+
Returns:
+

molecule_actor – Actor created to render the rubbon representation of the molecule to be +visualized.

+
+
Return type:
+

vtkActor

+
+
+

References

+

Richardson, J.S. The anatomy and taxonomy of protein structure +Advances in Protein Chemistry, 1981, 34, 167-339.

+
+ +
+
+

bounding_box#

+
+
+fury.molecular.bounding_box(molecule, colors=(1, 1, 1), linewidth=0.3)[source]#
+

Create a bounding box for a molecule.

+
+
Parameters:
+
    +
  • molecule (Molecule) – The molecule around which the bounding box is to be created.

  • +
  • colors (tuple (3,) or ndarray of shape (3,), optional) – Color of the bounding box. Default: (1, 1, 1)

  • +
  • linewidth (float, optional) – Thickness of tubes used to compose bounding box. Default: 0.3

  • +
+
+
Returns:
+

bbox_actor – Actor created to serve as a bounding box for a given molecule.

+
+
Return type:
+

vtkActor

+
+
+
+ +
+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ +
+ On this page +
+ +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/reference/fury.pick.html b/v0.10.x/reference/fury.pick.html new file mode 100644 index 000000000..1a5070803 --- /dev/null +++ b/v0.10.x/reference/fury.pick.html @@ -0,0 +1,883 @@ + + + + + + + + pick — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

pick#

+ + + + + + + + + +

PickingManager([vertices, faces, actors, ...])

Picking Manager helps with picking 3D objects.

SelectionManager([select])

Selection Manager helps with picking many objects simultaneously.

+
+

PickingManager#

+
+
+class fury.pick.PickingManager(vertices=True, faces=True, actors=True, world_coords=True)[source]#
+

Bases: object

+

Picking Manager helps with picking 3D objects.

+
+
+__init__(vertices=True, faces=True, actors=True, world_coords=True)[source]#
+

Initialize Picking Manager.

+
+
Parameters:
+
    +
  • vertices (bool) – If True allows to pick vertex indices.

  • +
  • faces (bool) – If True allows to pick face indices.

  • +
  • actors (bool) – If True allows to pick actor indices.

  • +
  • world_coords (bool) – If True allows to pick xyz position in world coordinates.

  • +
+
+
+
+ +
+
+event_position(iren)[source]#
+

Return event display position from interactor.

+
+
Parameters:
+

iren (interactor) – The interactor object can be retrieved for example +using providing ShowManager’s iren attribute.

+
+
+
+ +
+
+pick(disp_xy, sc)[source]#
+

Pick on display coordinates.

+
+
Parameters:
+
    +
  • disp_xy (tuple) – Display coordinates x, y.

  • +
  • sc (Scene) –

  • +
+
+
+
+ +
+
+pickable_off(actors)[source]#
+

Choose which actors cannot be picked.

+
+
Parameters:
+

actors (actor or sequence of actors) –

+
+
+
+ +
+
+pickable_on(actors)[source]#
+

Choose which actors can be picked.

+
+
Parameters:
+

actors (actor or sequence of actors) –

+
+
+
+ +
+ +
+
+

SelectionManager#

+
+
+class fury.pick.SelectionManager(select='faces')[source]#
+

Bases: object

+

Selection Manager helps with picking many objects simultaneously.

+
+
+__init__(select='faces')[source]#
+

Initialize Selection Manager.

+
+
Parameters:
+

select ('faces') – Options are ‘faces’, ‘vertices’ or ‘actors’. +Default ‘faces’.

+
+
+
+
+select()[source]#
+
+ +
+
+pick()[source]#
+
+ +
+ +
+
+event_position(iren)[source]#
+

Return event display position from interactor.

+
+
Parameters:
+

iren (interactor) – The interactor object can be retrieved for example +using ShowManager’s iren attribute.

+
+
+
+ +
+
+pick(disp_xy, sc)[source]#
+

Pick on display coordinates returns a single object.

+
+
Parameters:
+
    +
  • disp_xy (tuple) – Display coordinates x, y.

  • +
  • sc (Scene) –

  • +
+
+
+
+ +
+
+select(disp_xy, sc, area=0)[source]#
+

Select multiple objects using display coordinates.

+
+
Parameters:
+
    +
  • disp_xy (tuple) – Display coordinates x, y.

  • +
  • sc (Scene) –

  • +
  • area (int or 2d tuple of ints) – Selection area around x, y coords.

  • +
+
+
+
+ +
+
+selectable_off(actors)[source]#
+

Choose which actors cannot be selected.

+
+
Parameters:
+

actors (actor or sequence of actors) –

+
+
+
+ +
+
+selectable_on(actors)[source]#
+

Choose which actors can be selected.

+
+
Parameters:
+

actors (actor or sequence of actors) –

+
+
+
+ +
+
+update_selection_type(select)[source]#
+

Update selection type.

+
+
Parameters:
+

select ('faces') – Options are ‘faces’, ‘vertices’ or ‘actors’. +Default ‘faces’.

+
+
+
+ +
+ +
+
+ +
+ + +
+ +
+ + + + + +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/reference/fury.pkg_info.html b/v0.10.x/reference/fury.pkg_info.html new file mode 100644 index 000000000..8486bd336 --- /dev/null +++ b/v0.10.x/reference/fury.pkg_info.html @@ -0,0 +1,576 @@ + + + + + + + + pkg_info — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

pkg_info#

+ + + + + + +

pkg_commit_hash([pkg_path])

Get short form of commit hash

+
+

pkg_commit_hash#

+
+
+fury.pkg_info.pkg_commit_hash(pkg_path: str | None = None) tuple[str, str][source]#
+

Get short form of commit hash

+

In this file is a variable called COMMIT_HASH. This contains a substitution +pattern that may have been filled by the execution of git archive.

+

We get the commit hash from (in order of preference):

+
    +
  • A substituted value in archive_subst_hash

  • +
  • A truncated commit hash value that is part of the local portion of the +version

  • +
  • git’s output, if we are in a git repository

  • +
+

If all these fail, we return a not-found placeholder tuple

+
+
Parameters:
+

pkg_path (str) – directory containing package

+
+
Returns:
+

    +
  • hash_from (str) – Where we got the hash from - description

  • +
  • hash_str (str) – short form of hash

  • +
+

+
+
+
+ +
+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ +
+ On this page +
+ +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/reference/fury.primitive.html b/v0.10.x/reference/fury.primitive.html new file mode 100644 index 000000000..0e5aa11e1 --- /dev/null +++ b/v0.10.x/reference/fury.primitive.html @@ -0,0 +1,1297 @@ + + + + + + + + primitive — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

primitive#

+

Module dedicated for basic primitive.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

faces_from_sphere_vertices(vertices)

Triangulate a set of vertices on the sphere.

repeat_primitive_function(func, centers[, ...])

Repeat Vertices and triangles of a specific primitive function.

repeat_primitive(vertices, faces, centers[, ...])

Repeat Vertices and triangles of a specific primitive shape.

prim_square()

Return vertices and triangles for a square geometry.

prim_box()

Return vertices and triangle for a box geometry.

prim_sphere([name, gen_faces, phi, theta])

Provide vertices and triangles of the spheres.

prim_superquadric([roundness, sphere_name])

Provide vertices and triangles of a superquadrics.

prim_tetrahedron()

Return vertices and triangles for a tetrahedron.

prim_icosahedron()

Return vertices and triangles for icosahedron.

prim_rhombicuboctahedron()

Return vertices and triangles for rhombicuboctahedron.

prim_star([dim])

Return vertices and triangle for star geometry.

prim_triangularprism()

Return vertices and triangle for a regular triangular prism.

prim_pentagonalprism()

Return vertices and triangles for a pentagonal prism.

prim_octagonalprism()

Return vertices and triangle for an octagonal prism.

prim_frustum()

Return vertices and triangle for a square frustum prism.

prim_cylinder([radius, height, sectors, capped])

Return vertices and triangles for a cylinder.

prim_arrow([height, resolution, tip_length, ...])

Return vertices and triangle for arrow geometry.

prim_cone([radius, height, sectors])

Return vertices and triangle of a Cone.

+
+

faces_from_sphere_vertices#

+
+
+fury.primitive.faces_from_sphere_vertices(vertices)[source]#
+

Triangulate a set of vertices on the sphere.

+
+
Parameters:
+

vertices ((M, 3) ndarray) – XYZ coordinates of vertices on the sphere.

+
+
Returns:
+

faces – Indices into vertices; forms triangular faces.

+
+
Return type:
+

(N, 3) ndarray

+
+
+
+ +
+
+

repeat_primitive_function#

+
+
+fury.primitive.repeat_primitive_function(func, centers, func_args=[], directions=(1, 0, 0), colors=(1, 0, 0), scales=1)[source]#
+

Repeat Vertices and triangles of a specific primitive function.

+

It could be seen as a glyph. The primitive function should generate and +return vertices and faces

+
+
Parameters:
+
    +
  • func (callable) – primitive functions

  • +
  • centers (ndarray, shape (N, 3)) – Superquadrics positions

  • +
  • func_args (args) – primitive functions arguments/parameters

  • +
  • directions (ndarray, shape (N, 3) or tuple (3,), optional) – The orientation vector of the cone.

  • +
  • colors (ndarray (N,3) or (N, 4) or tuple (3,) or tuple (4,)) – RGB or RGBA (for opacity) R, G, B and A should be at the range [0, 1]

  • +
  • scales (ndarray, shape (N) or (N,3) or float or int, optional) – The height of the cone.

  • +
+
+
Returns:
+

    +
  • big_vertices (ndarray) – Expanded vertices at the centers positions

  • +
  • big_triangles (ndarray) – Expanded triangles that composed our shape to duplicate

  • +
  • big_colors (ndarray) – Expanded colors applied to all vertices/faces

  • +
+

+
+
+
+ +
+
+

repeat_primitive#

+
+
+fury.primitive.repeat_primitive(vertices, faces, centers, directions=None, colors=(1, 0, 0), scales=1, have_tiled_verts=False)[source]#
+

Repeat Vertices and triangles of a specific primitive shape.

+

It could be seen as a glyph.

+
+
Parameters:
+
    +
  • vertices (ndarray) – vertices coords to duplicate at the centers positions

  • +
  • triangles (ndarray) – triangles that composed our shape to duplicate

  • +
  • centers (ndarray, shape (N, 3)) – Superquadrics positions

  • +
  • directions (ndarray, shape (N, 3) or tuple (3,), optional) – The orientation vector of the cone.

  • +
  • colors (ndarray (N,3) or (N, 4) or tuple (3,) or tuple (4,)) – RGB or RGBA (for opacity) R, G, B and A should be at the range [0, 1]

  • +
  • scales (ndarray, shape (N) or (N,3) or float or int, optional) – The height of the cone.

  • +
  • have_tiled_verts (bool) – option to control if we need to duplicate vertices of a shape or not

  • +
+
+
Returns:
+

    +
  • big_vertices (ndarray) – Expanded vertices at the centers positions

  • +
  • big_triangles (ndarray) – Expanded triangles that composed our shape to duplicate

  • +
  • big_colors (ndarray) – Expanded colors applied to all vertices/faces

  • +
  • big_centers (ndarray) – Expanded centers for all vertices/faces

  • +
+

+
+
+
+ +
+
+

prim_square#

+
+
+fury.primitive.prim_square()[source]#
+

Return vertices and triangles for a square geometry.

+
+
Returns:
+

    +
  • vertices (ndarray) – 4 vertices coords that composed our square

  • +
  • triangles (ndarray) – 2 triangles that composed our square

  • +
+

+
+
+
+ +
+
+

prim_box#

+
+
+fury.primitive.prim_box()[source]#
+

Return vertices and triangle for a box geometry.

+
+
Returns:
+

    +
  • vertices (ndarray) – 8 vertices coords that composed our box

  • +
  • triangles (ndarray) – 12 triangles that composed our box

  • +
+

+
+
+
+ +
+
+

prim_sphere#

+
+
+fury.primitive.prim_sphere(name='symmetric362', gen_faces=False, phi=None, theta=None)[source]#
+

Provide vertices and triangles of the spheres.

+
+
Parameters:
+
    +
  • name (str, optional) – which sphere - one of: +* ‘symmetric362’ +* ‘symmetric642’ +* ‘symmetric724’ +* ‘repulsion724’ +* ‘repulsion100’ +* ‘repulsion200’

  • +
  • gen_faces (bool, optional) – If True, triangulate a set of vertices on the sphere to get the faces. +Otherwise, we load the saved faces from a file. Default: False

  • +
  • phi (int, optional) – Set the number of points in the latitude direction

  • +
  • theta (int, optional) – Set the number of points in the longitude direction

  • +
+
+
Returns:
+

    +
  • vertices (ndarray) – vertices coords that composed our sphere

  • +
  • triangles (ndarray) – triangles that composed our sphere

  • +
+

+
+
+

Examples

+
>>> import numpy as np
+>>> from fury.primitive import prim_sphere
+>>> verts, faces = prim_sphere('symmetric362')
+>>> verts.shape == (362, 3)
+True
+>>> faces.shape == (720, 3)
+True
+
+
+
+ +
+
+

prim_superquadric#

+
+
+fury.primitive.prim_superquadric(roundness=(1, 1), sphere_name='symmetric362')[source]#
+

Provide vertices and triangles of a superquadrics.

+
+
Parameters:
+
    +
  • roundness (tuple, optional) – parameters (Phi and Theta) that control the shape of the superquadric

  • +
  • sphere_name (str, optional) – which sphere - one of: +* ‘symmetric362’ +* ‘symmetric642’ +* ‘symmetric724’ +* ‘repulsion724’ +* ‘repulsion100’ +* ‘repulsion200’

  • +
+
+
Returns:
+

    +
  • vertices (ndarray) – vertices coords that composed our sphere

  • +
  • triangles (ndarray) – triangles that composed our sphere

  • +
+

+
+
+

Examples

+
>>> import numpy as np
+>>> from fury.primitive import prim_superquadric
+>>> verts, faces = prim_superquadric(roundness=(1, 1))
+>>> verts.shape == (362, 3)
+True
+>>> faces.shape == (720, 3)
+True
+
+
+
+ +
+
+

prim_tetrahedron#

+
+
+fury.primitive.prim_tetrahedron()[source]#
+

Return vertices and triangles for a tetrahedron.

+

This shape has a side length of two units.

+
+
Returns:
+

    +
  • pyramid_vert (numpy.ndarray) – 4 vertices coordinates

  • +
  • triangles (numpy.ndarray) – 4 triangles representing the tetrahedron

  • +
+

+
+
+
+ +
+
+

prim_icosahedron#

+
+
+fury.primitive.prim_icosahedron()[source]#
+

Return vertices and triangles for icosahedron.

+
+
Returns:
+

    +
  • icosahedron_vertices (numpy.ndarray) – 12 vertices coordinates to the icosahedron

  • +
  • icosahedron_mesh (numpy.ndarray) – 20 triangles representing the tetrahedron

  • +
+

+
+
+
+ +
+
+

prim_rhombicuboctahedron#

+
+
+fury.primitive.prim_rhombicuboctahedron()[source]#
+

Return vertices and triangles for rhombicuboctahedron.

+
+
Returns:
+

    +
  • vertices (numpy.ndarray) – 24 vertices coordinates to the rhombicuboctahedron

  • +
  • triangles (numpy.ndarray) – 44 triangles representing the rhombicuboctahedron

  • +
+

+
+
+
+ +
+
+

prim_star#

+
+
+fury.primitive.prim_star(dim=2)[source]#
+

Return vertices and triangle for star geometry.

+
+
Parameters:
+

dim (int) – Represents the dimension of the wanted star

+
+
Returns:
+

    +
  • vertices (ndarray) – vertices coords that composed our star

  • +
  • triangles (ndarray) – Triangles that composed our star

  • +
+

+
+
+
+ +
+
+

prim_triangularprism#

+
+
+fury.primitive.prim_triangularprism()[source]#
+

Return vertices and triangle for a regular triangular prism.

+
+
Returns:
+

    +
  • vertices (ndarray) – vertices coords that compose our prism

  • +
  • triangles (ndarray) – triangles that compose our prism

  • +
+

+
+
+
+ +
+
+

prim_pentagonalprism#

+
+
+fury.primitive.prim_pentagonalprism()[source]#
+

Return vertices and triangles for a pentagonal prism.

+
+
Returns:
+

    +
  • vertices (ndarray) – vertices coords that compose our prism

  • +
  • triangles (ndarray) – triangles that compose our prism

  • +
+

+
+
+
+ +
+
+

prim_octagonalprism#

+
+
+fury.primitive.prim_octagonalprism()[source]#
+

Return vertices and triangle for an octagonal prism.

+
+
Returns:
+

    +
  • vertices (ndarray) – vertices coords that compose our prism

  • +
  • triangles (ndarray) – triangles that compose our prism

  • +
+

+
+
+
+ +
+
+

prim_frustum#

+
+
+fury.primitive.prim_frustum()[source]#
+

Return vertices and triangle for a square frustum prism.

+
+
Returns:
+

    +
  • vertices (ndarray) – vertices coords that compose our prism

  • +
  • triangles (ndarray) – triangles that compose our prism

  • +
+

+
+
+
+ +
+
+

prim_cylinder#

+
+
+fury.primitive.prim_cylinder(radius=0.5, height=1, sectors=36, capped=True)[source]#
+

Return vertices and triangles for a cylinder.

+
+
Parameters:
+
    +
  • radius (float) – Radius of the cylinder

  • +
  • height (float) – Height of the cylinder

  • +
  • sectors (int) – Sectors in the cylinder

  • +
  • capped (bool) – Whether the cylinder is capped at both ends or open

  • +
+
+
Returns:
+

    +
  • vertices (ndarray) – vertices coords that compose our cylinder

  • +
  • triangles (ndarray) – triangles that compose our cylinder

  • +
+

+
+
+
+ +
+
+

prim_arrow#

+
+
+fury.primitive.prim_arrow(height=1.0, resolution=10, tip_length=0.35, tip_radius=0.1, shaft_radius=0.03)[source]#
+

Return vertices and triangle for arrow geometry.

+
+
Parameters:
+
    +
  • height (float) – The height of the arrow (default: 1.0).

  • +
  • resolution (int) – The resolution of the arrow.

  • +
  • tip_length (float) – The tip size of the arrow (default: 0.35)

  • +
  • tip_radius (float) – the tip radius of the arrow (default: 0.1)

  • +
  • shaft_radius (float) – The shaft radius of the arrow (default: 0.03)

  • +
+
+
Returns:
+

    +
  • vertices (ndarray) – vertices of the Arrow

  • +
  • triangles (ndarray) – Triangles of the Arrow

  • +
+

+
+
+
+ +
+
+

prim_cone#

+
+
+fury.primitive.prim_cone(radius=0.5, height=1, sectors=10)[source]#
+

Return vertices and triangle of a Cone.

+
+
Parameters:
+
    +
  • radius (float, optional) – Radius of the cone

  • +
  • height (float, optional) – Height of the cone

  • +
  • sectors (int, optional) – Sectors in the cone

  • +
+
+
Returns:
+

    +
  • vertices (ndarray) – vertices coords that compose our cone

  • +
  • triangles (ndarray) – triangles that compose our cone

  • +
+

+
+
+
+ +
+
+ +
+ + +
+ +
+ + + + + +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/reference/fury.shaders.html b/v0.10.x/reference/fury.shaders.html new file mode 100644 index 000000000..221d74e55 --- /dev/null +++ b/v0.10.x/reference/fury.shaders.html @@ -0,0 +1,1006 @@ + + + + + + + + shaders — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

shaders#

+ + + +
+
+

Module: shaders.base#

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

SHADERS_DIR

str(object='') -> str str(bytes_or_buffer[, encoding[, errors]]) -> str

compose_shader(glsl_code)

Merge GLSL shader code from a list of strings.

import_fury_shader(shader_file)

Import a Fury shader.

load_shader(shader_file)

Load a shader from a file.

load(filename)

Load a Fury shader file.

shader_to_actor(actor, shader_type[, ...])

Apply your own substitutions to the shader creation process.

replace_shader_in_actor(actor, shader_type, code)

Set and replace the shader template with a new one.

add_shader_callback(actor, callback[, priority])

Add a shader callback to the actor.

shader_apply_effects(window, actor, effects)

This applies a specific opengl state (effect) or a list of effects just before the actor's shader is executed.

attribute_to_actor(actor, arr, attr_name[, deep])

Link a numpy array with vertex attribute.

+
+

SHADERS_DIR#

+
+
+fury.shaders.base.SHADERS_DIR()#
+

str(object=’’) -> str +str(bytes_or_buffer[, encoding[, errors]]) -> str

+

Create a new string object from the given object. If encoding or +errors is specified, then the object must expose a data buffer +that will be decoded using the given encoding and error handler. +Otherwise, returns the result of object.__str__() (if defined) +or repr(object). +encoding defaults to sys.getdefaultencoding(). +errors defaults to ‘strict’.

+
+ +
+
+

compose_shader#

+
+
+fury.shaders.base.compose_shader(glsl_code)[source]#
+

Merge GLSL shader code from a list of strings.

+
+
Parameters:
+

glsl_code (list of str (code or filenames).) –

+
+
Returns:
+

code – GLSL shader code.

+
+
Return type:
+

str

+
+
+
+ +
+
+

import_fury_shader#

+
+
+fury.shaders.base.import_fury_shader(shader_file)[source]#
+

Import a Fury shader.

+
+
Parameters:
+

shader_file (str) – Filename of shader. The file must be in the fury/shaders directory and +must have the one of the supported extensions specified by the Khronos +Group +(KhronosGroup/glslang).

+
+
Returns:
+

code – GLSL shader code.

+
+
Return type:
+

str

+
+
+
+ +
+
+

load_shader#

+
+
+fury.shaders.base.load_shader(shader_file)[source]#
+

Load a shader from a file.

+
+
Parameters:
+

shader_file (str) – Full path to a shader file ending with one of the file extensions +defined by the Khronos Group +(KhronosGroup/glslang).

+
+
Returns:
+

code – GLSL shader code.

+
+
Return type:
+

str

+
+
+
+ +
+
+

load#

+
+
+fury.shaders.base.load(filename)[source]#
+

Load a Fury shader file.

+

Load function has been reimplemented as import_fury_shader.

+
    +
  • deprecated from version: 0.8.1

  • +
  • Raises <class ‘fury.deprecator.ExpiredDeprecationError’> as of version: 0.9.0

  • +
+
+
Parameters:
+

filename (str) – Filename of the shader file.

+
+
Returns:
+

code – Shader code.

+
+
Return type:
+

str

+
+
+
+ +
+
+

shader_to_actor#

+
+
+fury.shaders.base.shader_to_actor(actor, shader_type, impl_code='', decl_code='', block='valuepass', keep_default=True, replace_first=True, replace_all=False, debug=False)[source]#
+

Apply your own substitutions to the shader creation process.

+

A set of string replacements is applied to a shader template. This +function let’s apply custom string replacements.

+
+
Parameters:
+
    +
  • actor (vtkActor) – Fury actor you want to set the shader code to.

  • +
  • shader_type (str) – Shader type: vertex, fragment

  • +
  • impl_code (str, optional) – Shader implementation code, should be a string or filename. Default +None.

  • +
  • decl_code (str, optional) – Shader declaration code, should be a string or filename. Default None.

  • +
  • block (str, optional) – Section name to be replaced. VTK use of heavy string replacements to +insert shader and make it flexible. Each section of the shader +template have a specific name. For more information: +https://vtk.org/Wiki/Shaders_In_VTK. The possible values are: +position, normal, light, tcoord, color, clip, camera, prim_id, +valuepass. by default valuepass

  • +
  • keep_default (bool, optional) – Keep the default block tag to let VTK replace it with its default +behavior. Default True.

  • +
  • replace_first (bool, optional) – If True, apply this change before the standard VTK replacements. +Default True.

  • +
  • replace_all (bool, optional) – [description], by default False

  • +
  • debug (bool, optional) – Introduce a small error to debug shader code. Default False.

  • +
+
+
+
+ +
+
+

replace_shader_in_actor#

+
+
+fury.shaders.base.replace_shader_in_actor(actor, shader_type, code)[source]#
+

Set and replace the shader template with a new one.

+
+
Parameters:
+
    +
  • actor (vtkActor) – Fury actor you want to set the shader code to.

  • +
  • shader_type (str) – Shader type: vertex, geometry, fragment.

  • +
  • code (str) – New shader template code.

  • +
+
+
+
+ +
+
+

add_shader_callback#

+
+
+fury.shaders.base.add_shader_callback(actor, callback, priority=0.0)[source]#
+

Add a shader callback to the actor.

+
+
Parameters:
+
    +
  • actor (vtkActor) – Fury actor you want to add the callback to.

  • +
  • callback (callable) – Function or class that contains 3 parameters: caller, event, calldata. +This callback will be trigger at each UpdateShaderEvent event.

  • +
  • priority (float, optional) – Commands with a higher priority are called first.

  • +
+
+
Returns:
+

id_observer – An unsigned Int tag which can be used later to remove the event +or retrieve the vtkCommand used in the observer. +See more at: https://vtk.org/doc/nightly/html/classvtkObject.html

+
+
Return type:
+

int

+
+
+

Examples

+
add_shader_callback(actor, func_call1)
+id_observer = add_shader_callback(actor, func_call2)
+actor.GetMapper().RemoveObserver(id_observer)
+
+
+

Priority calls

+
test_values = []
+def callbackLow(_caller, _event, calldata=None):
+    program = calldata
+    if program is not None:
+        test_values.append(0)
+
+def callbackHigh(_caller, _event, calldata=None):
+    program = calldata
+    if program is not None:
+        test_values.append(999)
+
+def callbackMean(_caller, _event, calldata=None):
+    program = calldata
+    if program is not None:
+        test_values.append(500)
+
+fs.add_shader_callback(
+        actor, callbackHigh, 999)
+fs.add_shader_callback(
+        actor, callbackLow, 0)
+id_mean = fs.add_shader_callback(
+        actor, callbackMean, 500)
+
+showm.start()
+# test_values = [999, 500, 0, 999, 500, 0, ...]
+
+
+
+ +
+
+

shader_apply_effects#

+
+
+fury.shaders.base.shader_apply_effects(window, actor, effects, priority=0)[source]#
+

This applies a specific opengl state (effect) or a list of effects just +before the actor’s shader is executed.

+
+
Parameters:
+
    +
  • window (RenderWindow) – For example, this is provided by the ShowManager.window attribute.

  • +
  • actor (actor) –

  • +
  • effects (a function or a list of functions) –

  • +
  • priority (float, optional) – Related with the shader callback command. +Effects with a higher priority are applied first and +can be override by the others.

  • +
+
+
Returns:
+

id_observer – An unsigned Int tag which can be used later to remove the event +or retrieve the vtkCommand used in the observer. +See more at: https://vtk.org/doc/nightly/html/classvtkObject.html

+
+
Return type:
+

int

+
+
+
+ +
+
+

attribute_to_actor#

+
+
+fury.shaders.base.attribute_to_actor(actor, arr, attr_name, deep=True)[source]#
+

Link a numpy array with vertex attribute.

+
+
Parameters:
+
    +
  • actor (vtkActor) – Fury actor you want to add the vertex attribute to.

  • +
  • arr (ndarray) – Array to link to vertices.

  • +
  • attr_name (str) – Vertex attribute name. The vtk array will take the same name as the +attribute.

  • +
  • deep (bool, optional) – If True a deep copy is applied, otherwise a shallow copy is applied. +Default True.

  • +
+
+
+
+ +
+
+
+ +
+ + +
+ +
+ + + + + +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/reference/fury.stream.html b/v0.10.x/reference/fury.stream.html new file mode 100644 index 000000000..766a587d6 --- /dev/null +++ b/v0.10.x/reference/fury.stream.html @@ -0,0 +1,3115 @@ + + + + + + + + stream — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

stream#

+ + + +
+
+

Module: stream.client#

+ + + + + + + + + + + + + + + +

FuryStreamClient(showm[, max_window_size, ...])

This obj is responsible to create a StreamClient.

FuryStreamInteraction(showm[, ...])

This obj.

callback_stream_client(stream_client)

This callback is used to update the image inside of the ImageManager instance

interaction_callback(circular_queue, showm, ...)

This callback is used to invoke vtk interaction events reading those events from the provided circular_queue instance

+
+
+

Module: stream.constants#

+ + + + + + + + + + + + +

_CQUEUE_EVENT_IDs

CQUEUE_EVENT_IDS(mouse_weel, mouse_move, mouse_ids, left_btn_press, left_btn_release, middle_btn_press, middle_btn_release, right_btn_press, right_btn_release)

_CQUEUE_INDEX_INFO

CQUEUE_INDEX_INFO(weel, x, y, ctrl, shift, user_timestamp)

_CQUEUE

CQUEUE(dimension, event_ids, index_info)

+
+
+

Module: stream.server#

+ + + +
+
+
+

Module: stream.server.async_app#

+ + + + + + + + + + + + + + + + + + +

pcs

set() -> new empty set object set(iterable) -> new set object

set_weel(data, circular_queue)

set_mouse(data, circular_queue)

set_mouse_click(data, circular_queue)

3 | LeftButtonPressEvent 4 | LeftButtonReleaseEvent 5 | MiddleButtonPressEvent 6 | MiddleButtonReleaseEvent 7 | RightButtonPressEvent 8 | RightButtonReleaseEvent

get_app([rtc_server, folder, ...])

+
+
+

Module: stream.server.main#

+ + + + + + + + + + + + +

RTCServer(image_buffer_manager)

This Obj it's responsible to create the VideoStream for the WebRTCServer

web_server_raw_array([image_buffers, ...])

This will create a streaming webserver running on the given port and host using RawArrays.

web_server([image_buffer_names, ...])

This will create a streaming webserver running on the given port and host using SharedMemory.

+
+
+

Module: stream.tools#

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

GenericMultiDimensionalBuffer([max_size, ...])

This implements a abstract (generic) multidimensional buffer.

RawArrayMultiDimensionalBuffer(max_size[, ...])

This implements a multidimensional buffer with RawArray.

SharedMemMultiDimensionalBuffer(max_size[, ...])

This implements a generic multidimensional buffer with SharedMemory.

GenericCircularQueue([max_size, dimension, ...])

This implements a generic circular queue which works with shared memory resources.

ArrayCircularQueue([max_size, dimension, ...])

This implements a MultiDimensional Queue which works with Arrays and RawArrays.

SharedMemCircularQueue([max_size, ...])

This implements a MultiDimensional Queue which works with SharedMemory.

GenericImageBufferManager([max_window_size, ...])

This implements a abstract (generic) ImageBufferManager with the n-buffer technique.

RawArrayImageBufferManager([...])

This implements an ImageBufferManager using RawArrays.

SharedMemImageBufferManager([...])

This implements an ImageBufferManager using the SharedMemory approach.

IntervalTimerThreading(seconds, callback, ...)

Implements a object with the same behavior of setInterval from Js

IntervalTimer(seconds, callback, *args, **kwargs)

A object that creates a timer that calls a function periodically.

remove_shm_from_resource_tracker()

Monkey-patch multiprocessing.resource_tracker so SharedMemory won't be tracked

+
+
+

Module: stream.widget#

+ + + + + + + + + +

Widget(showm[, ms_stream, ms_interaction, ...])

This Obj it's able execute the fury streaming system using the SharedMemory object from Python multiprocessing.

check_port_is_available(host, port)

Check if a given port it's available

+
+

FuryStreamClient#

+
+
+class fury.stream.client.FuryStreamClient(showm, max_window_size=None, use_raw_array=True, whithout_iren_start=False, num_buffers=2)[source]#
+

Bases: object

+

This obj is responsible to create a StreamClient.

+
+
+__init__(showm, max_window_size=None, use_raw_array=True, whithout_iren_start=False, num_buffers=2)[source]#
+

A StreamClient extracts a framebuffer from the OpenGL context +and writes into a shared memory resource.

+
+
Parameters:
+
    +
  • showm (ShowManager) –

  • +
  • max_window_size (tuple of ints, optional) – This allows resize events inside of the FURY window instance. +Should be greater than the window size.

  • +
  • use_raw_array (bool, optional) – If False then FuryStreamClient will use SharedMemory +instead of RawArrays. Notice that Python >=3.8 it’s a +requirement +to use SharedMemory)

  • +
  • whithout_iren_start (bool, optional) – Sometimes you can’t initiate the vtkInteractor instance.

  • +
  • num_buffers (int, optional) – Number of buffers to be used in the n-buffering +technique.

  • +
+
+
+
+ +
+
+cleanup()[source]#
+

Release the shared memory resources if necessary.

+
+ +
+
+start(ms=0, use_asyncio=False)[source]#
+

Start the stream client.

+
+
Parameters:
+
    +
  • ms (float, optional) – positive number. This update the image buffer using a interval +of ms milliseconds. If ms is 0 then the stream client +will update the buffer after every Render event.

  • +
  • use_asyncio (bool, optional) – If False then the stream client will update the image +using a threading technique.

  • +
+
+
+
+ +
+
+stop()[source]#
+

Stop the stream client.

+
+ +
+ +
+
+

FuryStreamInteraction#

+
+
+class fury.stream.client.FuryStreamInteraction(showm, max_queue_size=50, use_raw_array=True, whithout_iren_start=False)[source]#
+

Bases: object

+

This obj. is responsible to manage the user interaction

+
+
+__init__(showm, max_queue_size=50, use_raw_array=True, whithout_iren_start=False)[source]#
+

Initialize the StreamInteraction obj.

+
+
Parameters:
+
    +
  • showm (ShowmManager) –

  • +
  • max_queue_size (int, optional) – maximum number of events to be stored.

  • +
  • use_raw_array (bool, optional) – If False then a CircularQueue will be created using +SharedMemory instead of RawArrays. Notice that +Python >=3.8 it’s requirement to use SharedMemory.

  • +
  • whithout_iren_start (bool, optional) – Set that to True if you can’t initiate the vtkInteractor +instance.

  • +
+
+
+
+ +
+
+cleanup()[source]#
+

Release the shared memory resources if necessary.

+
+ +
+
+start(ms=3, use_asyncio=False)[source]#
+

Start the stream interaction client.

+
+
Parameters:
+
    +
  • ms (float, optional) – positive number greater than zero.

  • +
  • use_asyncio (bool, optional) – If False then the interaction will be performed in a +separate thread.

  • +
+
+
+
+ +
+
+stop()[source]#
+

Stop the stream interaction client.

+
+ +
+ +
+
+

callback_stream_client#

+
+
+fury.stream.client.callback_stream_client(stream_client)[source]#
+

This callback is used to update the image inside of +the ImageManager instance

+
+
Parameters:
+

stream_client (StreamClient) –

+
+
+
+ +
+
+

interaction_callback#

+
+
+fury.stream.client.interaction_callback(circular_queue, showm, iren, render_after)[source]#
+

This callback is used to invoke vtk interaction events +reading those events from the provided circular_queue instance

+
+
Parameters:
+
    +
  • circular_queue (CircularQueue) –

  • +
  • showm (ShowmManager) –

  • +
  • iren (vtkInteractor) –

  • +
  • render_after (bool, optional) – If the render method should be called after an +dequeue

  • +
+
+
+
+ +
+
+

_CQUEUE_EVENT_IDs#

+
+
+fury.stream.constants._CQUEUE_EVENT_IDs()#
+

CQUEUE_EVENT_IDS(mouse_weel, mouse_move, mouse_ids, left_btn_press, left_btn_release, middle_btn_press, middle_btn_release, right_btn_press, right_btn_release)

+
+ +
+
+

_CQUEUE_INDEX_INFO#

+
+
+fury.stream.constants._CQUEUE_INDEX_INFO()#
+

CQUEUE_INDEX_INFO(weel, x, y, ctrl, shift, user_timestamp)

+
+ +
+
+

_CQUEUE#

+
+
+fury.stream.constants._CQUEUE()#
+

CQUEUE(dimension, event_ids, index_info)

+
+ +
+
+

pcs#

+
+
+fury.stream.server.async_app.pcs()#
+

set() -> new empty set object +set(iterable) -> new set object

+

Build an unordered collection of unique elements.

+
+ +
+
+

set_weel#

+
+
+fury.stream.server.async_app.set_weel(data, circular_queue)[source]#
+
+ +
+
+

set_mouse#

+
+
+fury.stream.server.async_app.set_mouse(data, circular_queue)[source]#
+
+ +
+
+

set_mouse_click#

+
+
+fury.stream.server.async_app.set_mouse_click(data, circular_queue)[source]#
+

3 | LeftButtonPressEvent +4 | LeftButtonReleaseEvent +5 | MiddleButtonPressEvent +6 | MiddleButtonReleaseEvent +7 | RightButtonPressEvent +8 | RightButtonReleaseEvent

+
+ +
+
+

get_app#

+
+
+fury.stream.server.async_app.get_app(rtc_server=None, folder=None, circular_queue=None, image_buffer_manager=None, provides_mjpeg=False, broadcast=True)[source]#
+
+ +
+
+

RTCServer#

+
+
+class fury.stream.server.main.RTCServer(image_buffer_manager)[source]#
+

Bases: object

+

This Obj it’s responsible to create the VideoStream for +the WebRTCServer

+
+
+__init__(image_buffer_manager)[source]#
+

Initialize the RTCServer

+
+
Parameters:
+

image_buffer_manager (ImageBufferManager) –

+
+
+
+ +
+
+async recv()[source]#
+

Return a VideoFrame to be used in the WebRTC Server

+

The frame will be created using the image stored in the +shared memory

+
+
Returns:
+

frame

+
+
Return type:
+

VideoFrame

+
+
+
+ +
+
+release()[source]#
+

Release the RTCServer

+
+ +
+ +
+
+

web_server_raw_array#

+
+
+fury.stream.server.main.web_server_raw_array(image_buffers=None, info_buffer=None, queue_head_tail_buffer=None, queue_buffer=None, port=8000, host='localhost', provides_mjpeg=True, provides_webrtc=True, ms_jpeg=16, run_app=True)[source]#
+

This will create a streaming webserver running on the +given port and host using RawArrays.

+
+
Parameters:
+
    +
  • image_buffers (list of buffers) – A list of buffers with each one containing a frame.

  • +
  • info_buffer (buffer) – A buffer with the information about the current +frame to be streamed and the respective sizes

  • +
  • queue_head_tail_buffer (buffer) – If buffer is passed than this Obj will read a +a already created RawArray.

  • +
  • queue_buffer (buffer) – If queue_buffer is passed than this Obj will read a +a already created RawArray containing the user interactions +events stored in the queue_buffer.

  • +
  • port (int, optional) – Port to be used by the aiohttp server

  • +
  • host (str, optional, default localhost) – host to be used by the aiohttp server

  • +
  • provides_mjpeg (bool, default True) – If a MJPEG streaming should be available. +If True you can consume that through +host:port/video/mjpeg +or if you want to interact you can consume that +through your browser +http://host:port?encoding=mjpeg

  • +
  • provides_webrtc (bool, default True) – If a WebRTC streaming should be available. +http://host:port

  • +
  • ms_jpeg (float, optional) – This it’s used only if the MJPEG will be used. The +ms_jpeg represents the amount of milliseconds between to +consecutive calls of the jpeg encoding.

  • +
  • run_app (bool, default True) – This will run the aiohttp application. The False condition +is used just to be able to test the server.

  • +
+
+
+
+ +
+
+

web_server#

+
+
+fury.stream.server.main.web_server(image_buffer_names=None, info_buffer_name=None, queue_head_tail_buffer_name=None, queue_buffer_name=None, port=8000, host='localhost', provides_mjpeg=True, provides_webrtc=True, avoid_unlink_shared_mem=True, ms_jpeg=16, run_app=True)[source]#
+

This will create a streaming webserver running on the given port +and host using SharedMemory.

+
+
Parameters:
+
    +
  • image_buffers_name (list of str) – A list of buffers with each one containing a frame.

  • +
  • info_buffer_name (str) – A buffer with the information about the current +frame to be streamed and the respective sizes

  • +
  • queue_head_tail_buffer_name (str, optional) – If buffer is passed than this Obj will read a +a already created RawArray.

  • +
  • buffer_name (str, optional) – If queue_buffer is passed than this Obj will read a +a already created RawArray containing the user interactions +events stored in the queue_buffer.

  • +
  • port (int, optional) – Port to be used by the aiohttp server

  • +
  • host (str, optional, default localhost) – host to be used by the aiohttp server

  • +
  • provides_mjpeg (bool, default True) – If a MJPEG streaming should be available. +If True you can consume that through +host:port/video/mjpeg +or if you want to interact you can consume that +through your browser +http://host:port?encoding=mjpeg

  • +
  • provides_webrtc (bool, default True) – If a WebRTC streaming should be available. +http://host:port

  • +
  • avoid_unlink_shared_mem (bool, default False) – If True, then this will apply a monkey-patch solution to +a python>=3.8 core bug

  • +
  • ms_jpeg (float, optional) – This it’s used only if the MJPEG will be used. The +ms_jpeg represents the amount of milliseconds between to +consecutive calls of the jpeg encoding.

  • +
  • run_app (bool, default True) – This will run the aiohttp application. The False condition +is used just to be able to test the server.

  • +
+
+
+
+ +
+
+

GenericMultiDimensionalBuffer#

+
+
+class fury.stream.tools.GenericMultiDimensionalBuffer(max_size=None, dimension=8)[source]#
+

Bases: ABC

+

This implements a abstract (generic) multidimensional buffer.

+
+
+__init__(max_size=None, dimension=8)[source]#
+

Initialize the multidimensional buffer.

+
+
Parameters:
+
    +
  • max_size (int, optional) – If buffer_name or buffer was not passed then max_size +it’s mandatory

  • +
  • dimension (int, default 8) –

  • +
+
+
+
+ +
+
+property buffer#
+
+ +
+
+abstract cleanup()[source]#
+
+ +
+
+abstract create_mem_resource()[source]#
+
+ +
+
+get_start_end(idx)[source]#
+
+ +
+
+abstract load_mem_resource()[source]#
+
+ +
+ +
+
+

RawArrayMultiDimensionalBuffer#

+
+
+class fury.stream.tools.RawArrayMultiDimensionalBuffer(max_size, dimension=4, buffer=None)[source]#
+

Bases: GenericMultiDimensionalBuffer

+

This implements a multidimensional buffer with RawArray.

+
+
+__init__(max_size, dimension=4, buffer=None)[source]#
+

Stream system uses that to implement the CircularQueue +with shared memory resources.

+
+
Parameters:
+
    +
  • max_size (int, optional) – If buffer_name or buffer was not passed then max_size +it’s mandatory

  • +
  • dimension (int, default 8) –

  • +
  • buffer (buffer, optional) – If buffer is not passed to __init__ +then the multidimensional buffer obj will create a new +RawArray object to store the data +If buffer is passed than this Obj will read a +a already created RawArray

  • +
+
+
+
+ +
+
+cleanup()[source]#
+
+ +
+
+create_mem_resource()[source]#
+
+ +
+
+load_mem_resource()[source]#
+
+ +
+ +
+
+

SharedMemMultiDimensionalBuffer#

+
+
+class fury.stream.tools.SharedMemMultiDimensionalBuffer(max_size, dimension=4, buffer_name=None)[source]#
+

Bases: GenericMultiDimensionalBuffer

+

This implements a generic multidimensional buffer +with SharedMemory.

+
+
+__init__(max_size, dimension=4, buffer_name=None)[source]#
+

Stream system uses that to implement the +CircularQueue with shared memory resources.

+
+
Parameters:
+
    +
  • max_size (int, optional) – If buffer_name or buffer was not passed then max_size +it’s mandatory

  • +
  • dimension (int, default 8) –

  • +
  • buffer_name (str, optional) – if buffer_name is passed than this Obj will read a +a already created SharedMemory

  • +
+
+
+
+ +
+
+cleanup()[source]#
+
+ +
+
+create_mem_resource()[source]#
+
+ +
+
+load_mem_resource()[source]#
+
+ +
+ +
+
+

GenericCircularQueue#

+
+
+class fury.stream.tools.GenericCircularQueue(max_size=None, dimension=8, use_shared_mem=False, buffer=None, buffer_name=None)[source]#
+

Bases: ABC

+

This implements a generic circular queue which works with +shared memory resources.

+
+
+__init__(max_size=None, dimension=8, use_shared_mem=False, buffer=None, buffer_name=None)[source]#
+

Initialize the circular queue.

+
+
Parameters:
+
    +
  • max_size (int, optional) – If buffer_name or buffer was not passed then max_size +it’s mandatory. This will be used to construct the +multidimensional buffer

  • +
  • dimension (int, default 8) – This will be used to construct the multidimensional buffer

  • +
  • use_shared_mem (bool, default False) – If the multidimensional memory resource should create or read +using SharedMemory or RawArrays

  • +
  • buffer (RawArray, optional) –

  • +
  • buffer_name (str, optional) –

  • +
+
+
+
+ +
+
+abstract cleanup()[source]#
+
+ +
+
+abstract create_mem_resource()[source]#
+
+ +
+
+abstract dequeue()[source]#
+
+ +
+
+abstract enqueue(data)[source]#
+
+ +
+
+property head#
+
+ +
+
+abstract load_mem_resource()[source]#
+
+ +
+
+set_head_tail(head, tail, lock=1)[source]#
+
+ +
+
+property tail#
+
+ +
+ +
+
+

ArrayCircularQueue#

+
+
+class fury.stream.tools.ArrayCircularQueue(max_size=10, dimension=6, head_tail_buffer=None, buffer=None)[source]#
+

Bases: GenericCircularQueue

+

This implements a MultiDimensional Queue which works with +Arrays and RawArrays.

+
+
+__init__(max_size=10, dimension=6, head_tail_buffer=None, buffer=None)[source]#
+

Stream system uses that to implement user interactions

+
+
Parameters:
+
    +
  • max_size (int, optional) – If buffer_name or buffer was not passed then max_size +it’s mandatory. This will be used to construct the +multidimensional buffer

  • +
  • dimension (int, default 8) – This will be used to construct the multidimensional buffer

  • +
  • head_tail_buffer (buffer, optional) – If buffer is not passed to __init__ +then this obj will create a new +RawArray to store head and tail position.

  • +
  • buffer (buffer, optional) – If buffer is not passed to __init__ +then the multidimensional buffer obj will create a new +RawArray to store the data

  • +
+
+
+
+ +
+
+cleanup()[source]#
+
+ +
+
+create_mem_resource()[source]#
+
+ +
+
+dequeue()[source]#
+
+ +
+
+enqueue(data)[source]#
+
+ +
+
+load_mem_resource()[source]#
+
+ +
+ +
+
+

SharedMemCircularQueue#

+
+
+class fury.stream.tools.SharedMemCircularQueue(max_size=10, dimension=6, head_tail_buffer_name=None, buffer_name=None)[source]#
+

Bases: GenericCircularQueue

+

This implements a MultiDimensional Queue which works with +SharedMemory.

+
+
+__init__(max_size=10, dimension=6, head_tail_buffer_name=None, buffer_name=None)[source]#
+

Stream system uses that to implement user interactions

+
+
Parameters:
+
    +
  • max_size (int, optional) – If buffer_name or buffer was not passed then max_size +it’s mandatory. This will be used to construct the +multidimensional buffer

  • +
  • dimension (int, default 8) – This will be used to construct the multidimensional buffer

  • +
  • head_tail_buffer_name (str, optional) – if buffer_name is passed than this Obj will read a +a already created SharedMemory with the head and tail +information

  • +
  • buffer_name (str, optional) – if buffer_name is passed than this Obj will read a +a already created SharedMemory to create the MultiDimensionalBuffer

  • +
+
+
+
+ +
+
+cleanup()[source]#
+
+ +
+
+create_mem_resource()[source]#
+
+ +
+
+dequeue()[source]#
+
+ +
+
+enqueue(data)[source]#
+
+ +
+
+is_unlocked()[source]#
+
+ +
+
+load_mem_resource()[source]#
+
+ +
+
+lock()[source]#
+
+ +
+
+unlock()[source]#
+
+ +
+ +
+
+

GenericImageBufferManager#

+
+
+class fury.stream.tools.GenericImageBufferManager(max_window_size=None, num_buffers=2, use_shared_mem=False)[source]#
+

Bases: ABC

+

This implements a abstract (generic) ImageBufferManager with +the n-buffer technique.

+
+
+__init__(max_window_size=None, num_buffers=2, use_shared_mem=False)[source]#
+

Initialize the ImageBufferManager.

+
+
Parameters:
+
    +
  • max_window_size (tuple of ints, optional) – This allows resize events inside of the FURY window instance. +Should be greater than the window size.

  • +
  • num_buffers (int, optional) – Number of buffers to be used in the n-buffering +technique.

  • +
  • use_shared_mem (bool, default False) –

  • +
+
+
+
+ +
+
+async async_get_jpeg(ms=33)[source]#
+
+ +
+
+property buffer_index#
+
+ +
+
+abstract cleanup()[source]#
+
+ +
+
+abstract create_mem_resource()[source]#
+
+ +
+
+get_current_frame()[source]#
+

Get the current frame from the buffer.

+
+ +
+
+get_jpeg()[source]#
+

Returns a jpeg image from the buffer.

+
+
Returns:
+

bytes

+
+
Return type:
+

jpeg image.

+
+
+
+ +
+
+abstract load_mem_resource()[source]#
+
+ +
+
+property next_buffer_index#
+
+ +
+
+write_into(w, h, np_arr)[source]#
+
+ +
+ +
+
+

RawArrayImageBufferManager#

+
+
+class fury.stream.tools.RawArrayImageBufferManager(max_window_size=(100, 100), num_buffers=2, image_buffers=None, info_buffer=None)[source]#
+

Bases: GenericImageBufferManager

+

This implements an ImageBufferManager using RawArrays.

+
+
+__init__(max_window_size=(100, 100), num_buffers=2, image_buffers=None, info_buffer=None)[source]#
+

Initialize the ImageBufferManager.

+
+
Parameters:
+
    +
  • max_window_size (tuple of ints, optional) – This allows resize events inside of the FURY window instance. +Should be greater than the window size.

  • +
  • num_buffers (int, optional) – Number of buffers to be used in the n-buffering +technique.

  • +
  • info_buffer (buffer, optional) – A buffer with the information about the current +frame to be streamed and the respective sizes

  • +
  • image_buffers (list of buffers, optional) – A list of buffers with each one containing a frame.

  • +
+
+
+
+ +
+
+cleanup()[source]#
+
+ +
+
+create_mem_resource()[source]#
+
+ +
+
+load_mem_resource()[source]#
+
+ +
+ +
+
+

SharedMemImageBufferManager#

+
+
+class fury.stream.tools.SharedMemImageBufferManager(max_window_size=(100, 100), num_buffers=2, image_buffer_names=None, info_buffer_name=None)[source]#
+

Bases: GenericImageBufferManager

+

This implements an ImageBufferManager using the +SharedMemory approach.

+
+
+__init__(max_window_size=(100, 100), num_buffers=2, image_buffer_names=None, info_buffer_name=None)[source]#
+

Initialize the ImageBufferManager.

+
+
Parameters:
+
    +
  • max_window_size (tuple of ints, optional) – This allows resize events inside of the FURY window instance. +Should be greater than the window size.

  • +
  • num_buffers (int, optional) – Number of buffers to be used in the n-buffering +technique.

  • +
  • info_buffer_name (str) – The name of a buffer with the information about the current +frame to be streamed and the respective sizes

  • +
  • image_buffer_names (list of str, optional) – a list of buffer names. Each buffer contains a frame

  • +
+
+
+

Notes

+

Python >=3.8 is a requirement to use this object.

+
+ +
+
+cleanup()[source]#
+

Release the resources used by the Shared Memory Manager

+
+ +
+
+create_mem_resource()[source]#
+
+ +
+
+load_mem_resource()[source]#
+
+ +
+ +
+
+

IntervalTimerThreading#

+
+
+class fury.stream.tools.IntervalTimerThreading(seconds, callback, *args, **kwargs)[source]#
+

Bases: object

+

Implements a object with the same behavior of setInterval from Js

+
+
+__init__(seconds, callback, *args, **kwargs)[source]#
+
+
Parameters:
+
    +
  • seconds (float) – A positive float number. Represents the total amount of +seconds between each call

  • +
  • callback (function) – The function to be called

  • +
  • *args (args) – args to be passed to callback

  • +
  • **kwargs (kwargs) – kwargs to be passed to callback

  • +
+
+
+

Examples

+
def callback(arr):
+    arr += [len(arr)]
+arr = []
+interval_timer = tools.IntervalTimer(1, callback, arr)
+interval_timer.start()
+time.sleep(5)
+interval_timer.stop()
+# len(arr) == 5
+
+
+

References

+

[1] https://stackoverflow.com/questions/3393612/run-certain-code-every-n-seconds

+
+ +
+
+start()[source]#
+

Start the timer

+
+ +
+
+stop()[source]#
+

Stop the timer

+
+ +
+ +
+
+

IntervalTimer#

+
+
+class fury.stream.tools.IntervalTimer(seconds, callback, *args, **kwargs)[source]#
+

Bases: object

+

A object that creates a timer that calls a function periodically.

+
+
+__init__(seconds, callback, *args, **kwargs)[source]#
+
+
Parameters:
+
    +
  • seconds (float) – A positive float number. Represents the total amount of +seconds between each call

  • +
  • callback (function) – The function to be called

  • +
  • *args (args) – args to be passed to callback

  • +
  • **kwargs (kwargs) – kwargs to be passed to callback

  • +
+
+
+
+ +
+
+start()[source]#
+

Start the timer

+
+ +
+
+stop()[source]#
+

Stop the timer

+
+ +
+ +
+
+

remove_shm_from_resource_tracker#

+
+
+fury.stream.tools.remove_shm_from_resource_tracker()[source]#
+

Monkey-patch multiprocessing.resource_tracker so SharedMemory won’t +be tracked

+

Notes

+

More details at: https://bugs.python.org/issue38119

+
+ +
+
+

Widget#

+
+
+class fury.stream.widget.Widget(showm, ms_stream=33, ms_interaction=33, host='localhost', port=None, encoding='mjpeg', ms_jpeg=33, queue_size=20)[source]#
+

Bases: object

+

This Obj it’s able execute the fury streaming system +using the SharedMemory object from Python multiprocessing.

+
+
+__init__(showm, ms_stream=33, ms_interaction=33, host='localhost', port=None, encoding='mjpeg', ms_jpeg=33, queue_size=20)[source]#
+

Initialize the widget.

+
+
Parameters:
+
    +
  • showm (ShowmManager) –

  • +
  • ms_stream (float, optional) – time in mileseconds between each frame buffer update.

  • +
  • ms_interaction (float, optional) – time in mileseconds between each user interaction update.

  • +
  • host (str, optional) –

  • +
  • port (int, optional) –

  • +
  • encoding (str, optional) – If should use MJPEG streaming or WebRTC.

  • +
  • ms_jpeg (float, optional) – This it’s used only if the MJPEG will be used. The +ms_jpeg represents the amount of milliseconds between to +consecutive calls of the jpeg encoding.

  • +
  • queue_size (int, optional) – maximum number of user interactions to be stored

  • +
+
+
+
+ +
+
+cleanup()[source]#
+

Release the shared memory

+
+ +
+
+property command_string#
+

Return the command string to start the server

+
+
Returns:
+

command_string

+
+
Return type:
+

str

+
+
+
+ +
+
+display(height=150)[source]#
+

Start the server and display the url in an iframe

+
+ +
+
+return_iframe(height=200)[source]#
+

Return the jupyter div iframe used to show the stream

+
+ +
+
+run_command()[source]#
+

Evaluate the command string to start the server

+
+ +
+
+start(use_asyncio=False)[source]#
+

Start the fury client and the interaction client and return the url

+
+
Parameters:
+

use_asyncio (bool, optional) – If should use the asyncio version of the server. +Default is False.

+
+
+
+ +
+
+stop()[source]#
+

Stop the streaming server and release the shared memory

+
+ +
+
+property url#
+

Return the url to access the server

+
+ +
+ +
+
+

check_port_is_available#

+
+
+fury.stream.widget.check_port_is_available(host, port)[source]#
+

Check if a given port it’s available

+
+
Parameters:
+
    +
  • host (str) –

  • +
  • port (int) –

  • +
+
+
Returns:
+

available

+
+
Return type:
+

bool

+
+
+
+ +
+
+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ +
+ On this page +
+ +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/reference/fury.transform.html b/v0.10.x/reference/fury.transform.html new file mode 100644 index 000000000..ce8dbd1ac --- /dev/null +++ b/v0.10.x/reference/fury.transform.html @@ -0,0 +1,996 @@ + + + + + + + + transform — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

transform#

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

_TUPLE2AXES

dict() -> new empty dictionary dict(mapping) -> new dictionary initialized from a mapping object's (key, value) pairs dict(iterable) -> new dictionary initialized as if via: d = {} for k, v in iterable: d[k] = v dict(**kwargs) -> new dictionary initialized with the name=value pairs in the keyword argument list. For example: dict(one=1, two=2).

euler_matrix(ai, aj, ak[, axes])

Return homogeneous rotation matrix from Euler angles and axis sequence.

sphere2cart(r, theta, phi)

Spherical to Cartesian coordinates.

cart2sphere(x, y, z)

Return angles for Cartesian 3D coordinates x, y, and z.

translate(translation)

Return transformation matrix for translation array.

rotate(quat)

Return transformation matrix for rotation quaternion.

scale(scales)

Return transformation matrix for scales array.

apply_transformation(vertices, transformation)

Multiplying transformation matrix with vertices

transform_from_matrix(matrix)

Returns translation, rotation and scale arrays from transformation matrix.

+
+

_TUPLE2AXES#

+
+
+fury.transform._TUPLE2AXES()#
+

dict() -> new empty dictionary +dict(mapping) -> new dictionary initialized from a mapping object’s

+
+

(key, value) pairs

+
+
+
dict(iterable) -> new dictionary initialized as if via:

d = {} +for k, v in iterable:

+
+

d[k] = v

+
+
+
dict(**kwargs) -> new dictionary initialized with the name=value pairs

in the keyword argument list. For example: dict(one=1, two=2)

+
+
+
+ +
+
+

euler_matrix#

+
+
+fury.transform.euler_matrix(ai, aj, ak, axes='sxyz')[source]#
+

Return homogeneous rotation matrix from Euler angles and axis sequence.

+

Code modified from the work of Christoph Gohlke link provided here +http://www.lfd.uci.edu/~gohlke/code/transformations.py.html

+
+
Parameters:
+
    +
  • ai (Euler's roll, pitch and yaw angles) –

  • +
  • aj (Euler's roll, pitch and yaw angles) –

  • +
  • ak (Euler's roll, pitch and yaw angles) –

  • +
  • axes (One of 24 axis sequences as string or encoded tuple) –

  • +
+
+
Returns:
+

    +
  • matrix (ndarray (4, 4))

  • +
  • Code modified from the work of Christoph Gohlke link provided here

  • +
  • http (//www.lfd.uci.edu/~gohlke/code/transformations.py.html)

  • +
+

+
+
+

Examples

+
>>> import numpy
+>>> R = euler_matrix(1, 2, 3, 'syxz')
+>>> numpy.allclose(numpy.sum(R[0]), -1.34786452)
+True
+>>> R = euler_matrix(1, 2, 3, (0, 1, 0, 1))
+>>> numpy.allclose(numpy.sum(R[0]), -0.383436184)
+True
+>>> ai, aj, ak = (4.0*math.pi) * (numpy.random.random(3) - 0.5)
+>>> for axes in _AXES2TUPLE.keys():
+...    _ = euler_matrix(ai, aj, ak, axes)
+>>> for axes in _TUPLE2AXES.keys():
+...    _ = euler_matrix(ai, aj, ak, axes)
+
+
+
+ +
+
+

sphere2cart#

+
+
+fury.transform.sphere2cart(r, theta, phi)[source]#
+

Spherical to Cartesian coordinates.

+

This is the standard physics convention where theta is the +inclination (polar) angle, and phi is the azimuth angle.

+

Imagine a sphere with center (0,0,0). Orient it with the z axis +running south-north, the y axis running west-east and the x axis +from posterior to anterior. theta (the inclination angle) is the +angle to rotate from the z-axis (the zenith) around the y-axis, +towards the x axis. Thus the rotation is counter-clockwise from the +point of view of positive y. phi (azimuth) gives the angle of +rotation around the z-axis towards the y axis. The rotation is +counter-clockwise from the point of view of positive z.

+

Equivalently, given a point P on the sphere, with coordinates x, y, +z, theta is the angle between P and the z-axis, and phi is +the angle between the projection of P onto the XY plane, and the X +axis.

+

Geographical nomenclature designates theta as ‘co-latitude’, and phi +as ‘longitude’

+
+
Parameters:
+
    +
  • r (array_like) – radius

  • +
  • theta (array_like) – inclination or polar angle

  • +
  • phi (array_like) – azimuth angle

  • +
+
+
Returns:
+

    +
  • x (array) – x coordinate(s) in Cartesian space

  • +
  • y (array) – y coordinate(s) in Cartesian space

  • +
  • z (array) – z coordinate

  • +
+

+
+
+

Notes

+

See these pages:

+ +

for excellent discussion of the many different conventions +possible. Here we use the physics conventions, used in the +wikipedia page.

+

Derivations of the formulae are simple. Consider a vector x, y, z of +length r (norm of x, y, z). The inclination angle (theta) can be +found from: cos(theta) == z / r -> z == r * cos(theta). This gives +the hypotenuse of the projection onto the XY plane, which we will +call Q. Q == r*sin(theta). Now x / Q == cos(phi) -> x == r * +sin(theta) * cos(phi) and so on.

+

We have deliberately named this function sphere2cart rather than +sph2cart to distinguish it from the Matlab function of that +name, because the Matlab function uses an unusual convention for the +angles that we did not want to replicate. The Matlab function is +trivial to implement with the formulae given in the Matlab help.

+
+ +
+
+

cart2sphere#

+
+
+fury.transform.cart2sphere(x, y, z)[source]#
+

Return angles for Cartesian 3D coordinates x, y, and z.

+

See doc for sphere2cart for angle conventions and derivation +of the formulae.

+

$0lethetamathrm{(theta)}lepi$ and $-pilephimathrm{(phi)}lepi$

+
+
Parameters:
+
    +
  • x (array_like) – x coordinate in Cartesian space

  • +
  • y (array_like) – y coordinate in Cartesian space

  • +
  • z (array_like) – z coordinate

  • +
+
+
Returns:
+

    +
  • r (array) – radius

  • +
  • theta (array) – inclination (polar) angle

  • +
  • phi (array) – azimuth angle

  • +
+

+
+
+
+ +
+
+

translate#

+
+
+fury.transform.translate(translation)[source]#
+

Return transformation matrix for translation array.

+
+
Parameters:
+

translation (ndarray) – translation in x, y and z directions.

+
+
Returns:
+

translation – Numpy array of shape 4,4 containing translation parameter in the last +column of the matrix.

+
+
Return type:
+

ndarray (4, 4)

+
+
+

Examples

+
>>> import numpy as np
+>>> tran = np.array([0.3, 0.2, 0.25])
+>>> transform = translate(tran)
+>>> transform
+>>> [[1.  0.  0.  0.3 ]
+     [0.  1.  0.  0.2 ]
+     [0.  0.  1.  0.25]
+     [0.  0.  0.  1.  ]]
+
+
+
+ +
+
+

rotate#

+
+
+fury.transform.rotate(quat)[source]#
+

Return transformation matrix for rotation quaternion.

+
+
Parameters:
+

quat (ndarray (4, )) – rotation quaternion.

+
+
Returns:
+

rotation_mat – Transformation matrix of shape (4, 4) to rotate a vector.

+
+
Return type:
+

ndarray (4, 4)

+
+
+

Examples

+
>>> import numpy as np
+>>> quat = np.array([0.259, 0.0, 0.0, 0.966])
+>>> rotation = rotate(quat)
+>>> rotation
+>>> [[1.  0.      0.     0.]
+     [0.  0.866  -0.5    0.]
+     [0.  0.5     0.866  0.]
+     [0.  0.      0.     1.]]
+
+
+
+ +
+
+

scale#

+
+
+fury.transform.scale(scales)[source]#
+

Return transformation matrix for scales array.

+
+
Parameters:
+

scales (ndarray) – scales in x, y and z directions.

+
+
Returns:
+

scale_mat – Numpy array of shape 4,4 containing elements of scale matrix along +the diagonal.

+
+
Return type:
+

ndarray (4, 4)

+
+
+

Examples

+
>>> import numpy as np
+>>> scales = np.array([2.0, 1.0, 0.5])
+>>> transform = scale(scales)
+>>> transform
+>>> [[2.  0.  0.   0.]
+     [0.  1.  0.   0.]
+     [0.  0.  0.5  0.]
+     [0.  0.  0.   1.]]
+
+
+
+ +
+
+

apply_transformation#

+
+
+fury.transform.apply_transformation(vertices, transformation)[source]#
+

Multiplying transformation matrix with vertices

+
+
Parameters:
+
    +
  • vertices (ndarray (n, 3)) – vertices of the mesh

  • +
  • transformation (ndarray (4, 4)) – transformation matrix

  • +
+
+
Returns:
+

vertices – transformed vertices of the mesh

+
+
Return type:
+

ndarray (n, 3)

+
+
+
+ +
+
+

transform_from_matrix#

+
+
+fury.transform.transform_from_matrix(matrix)[source]#
+

Returns translation, rotation and scale arrays from transformation +matrix.

+
+
Parameters:
+

matrix (ndarray (4, 4)) – the transformation matrix of shape 4*4

+
+
Returns:
+

    +
  • translate (ndarray (3, )) – translation component from the transformation matrix

  • +
  • rotate (ndarray (4, )) – rotation component from the transformation matrix

  • +
  • scale (ndarray (3, )) – scale component from the transformation matrix.

  • +
+

+
+
+
+ +
+
+ +
+ + +
+ +
+ + + + + +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/reference/fury.ui.html b/v0.10.x/reference/fury.ui.html new file mode 100644 index 000000000..6435e6fb4 --- /dev/null +++ b/v0.10.x/reference/fury.ui.html @@ -0,0 +1,8725 @@ + + + + + + + + ui — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

ui#

+ + + +
+
+

Module: ui.containers#

+

UI container module.

+ + + + + + + + + + + + + + + + + + +

Panel2D(size[, position, color, opacity, ...])

A 2D UI Panel.

TabPanel2D([position, size, title, color, ...])

Render content within a Tab.

TabUI([position, size, nb_tabs, ...])

UI element to add multiple panels within a single window.

ImageContainer2D(img_path[, position, size])

A 2D container to hold an image.

GridUI(actors[, captions, caption_offset, ...])

Add actors in a grid and interact with them individually.

+
+
+

Module: ui.core#

+

UI core module that describe UI abstract class.

+ + + + + + + + + + + + + + + + + + +

UI([position])

An umbrella class for all UI elements.

Rectangle2D([size, position, color, opacity])

A 2D rectangle sub-classed from UI.

Disk2D(outer_radius[, inner_radius, center, ...])

A 2D disk UI component.

TextBlock2D([text, font_size, font_family, ...])

Wrap over the default vtkTextActor and helps setting the text.

Button2D(icon_fnames[, position, size])

A 2D overlay button and is of type vtkTexturedActor2D.

+
+
+

Module: ui.elements#

+

UI components module.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

TextBox2D(width, height[, text, position, ...])

An editable 2D text box that behaves as a UI component.

LineSlider2D([center, initial_value, ...])

A 2D Line Slider.

LineDoubleSlider2D([line_width, ...])

A 2D Line Slider with two sliding rings.

RingSlider2D([center, initial_value, ...])

A disk slider.

RangeSlider([line_width, inner_radius, ...])

A set of a LineSlider2D and a LineDoubleSlider2D.

Option(label[, position, font_size, checked])

A set of a Button2D and a TextBlock2D to act as a single option for checkboxes and radio buttons.

Checkbox(labels[, checked_labels, padding, ...])

A 2D set of :class:'Option' objects.

RadioButton(labels, checked_labels[, ...])

A 2D set of :class:'Option' objects.

ComboBox2D([items, position, size, ...])

UI element to create drop-down menus.

ListBox2D(values[, position, size, ...])

UI component that allows the user to select items from a list.

ListBoxItem2D(list_box, size[, text_color, ...])

The text displayed in a listbox.

FileMenu2D(directory_path[, extensions, ...])

A menu to select files in the current folder.

DrawShape(shape_type[, drawpanel, position])

Create and Manage 2D Shapes.

DrawPanel([size, position, is_draggable])

The main Canvas(Panel2D) on which everything would be drawn.

PlaybackPanel([loop, position, width])

A playback controller that can do essential functionalities.

Card2D(image_path[, body_text, draggable, ...])

Card element to show image and related text

SpinBox([position, size, padding, ...])

SpinBox UI.

+
+
+

Module: ui.helpers#

+

Helper variable or function for UI Elements.

+ + + + + + + + + + + + + + + + + + +

clip_overflow(textblock, width[, side])

Clips overflowing text of TextBlock2D with respect to width.

wrap_overflow(textblock, wrap_width[, side])

Wraps overflowing text of TextBlock2D with respect to width.

check_overflow(textblock, width[, ...])

Checks if the text is overflowing.

cal_bounding_box_2d(vertices)

Calculate the min, max position and the size of the bounding box.

rotate_2d(vertices, angle)

Rotate the given vertices by an angle.

+
+

Panel2D#

+
+
+class fury.ui.containers.Panel2D(size, position=(0, 0), color=(0.1, 0.1, 0.1), opacity=0.7, align='left', border_color=(1, 1, 1), border_width=0, has_border=False)[source]#
+

Bases: UI

+

A 2D UI Panel.

+

Can contain one or more UI elements.

+
+
+alignment#
+

Alignment of the panel with respect to the overall screen.

+
+
Type:
+

[left, right]

+
+
+
+ +
+
+__init__(size, position=(0, 0), color=(0.1, 0.1, 0.1), opacity=0.7, align='left', border_color=(1, 1, 1), border_width=0, has_border=False)[source]#
+

Init class instance.

+
+
Parameters:
+
    +
  • size ((int, int)) – Size (width, height) in pixels of the panel.

  • +
  • position ((float, float)) – Absolute coordinates (x, y) of the lower-left corner of the panel.

  • +
  • color ((float, float, float)) – Must take values in [0, 1].

  • +
  • opacity (float) – Must take values in [0, 1].

  • +
  • align ([left, right]) – Alignment of the panel with respect to the overall screen.

  • +
  • border_color ((float, float, float), optional) – Must take values in [0, 1].

  • +
  • border_width (float, optional) – width of the border

  • +
  • has_border (bool, optional) – If the panel should have borders.

  • +
+
+
+
+ +
+
+add_element(element, coords, anchor='position')[source]#
+

Add a UI component to the panel.

+

The coordinates represent an offset from the lower left corner of the +panel.

+
+
Parameters:
+
    +
  • element (UI) – The UI item to be added.

  • +
  • coords ((float, float) or (int, int)) – If float, normalized coordinates are assumed and they must be +between [0,1]. +If int, pixels coordinates are assumed and it must fit within the +panel’s size.

  • +
+
+
+
+ +
+
+property border_color#
+
+ +
+
+property border_width#
+
+ +
+
+property color#
+
+ +
+
+left_button_dragged(i_ren, _obj, _panel2d_object)[source]#
+
+ +
+
+left_button_pressed(i_ren, _obj, panel2d_object)[source]#
+
+ +
+
+property opacity#
+
+ +
+
+re_align(window_size_change)[source]#
+

Re-organise the elements in case the window size is changed.

+
+
Parameters:
+

window_size_change ((int, int)) – New window size (width, height) in pixels.

+
+
+
+ +
+
+remove_element(element)[source]#
+

Remove a UI component from the panel.

+
+
Parameters:
+

element (UI) – The UI item to be removed.

+
+
+
+ +
+
+resize(size)[source]#
+

Set the panel size.

+
+
Parameters:
+

size ((float, float)) – Panel size (width, height) in pixels.

+
+
+
+ +
+
+set_visibility(visibility)[source]#
+

Set visibility of this UI component.

+
+ +
+
+update_border_coords()[source]#
+

Update the coordinates of the borders

+
+ +
+
+update_element(element, coords, anchor='position')[source]#
+

Update the position of a UI component in the panel.

+
+
Parameters:
+
    +
  • element (UI) – The UI item to be updated.

  • +
  • coords ((float, float) or (int, int)) – New coordinates. +If float, normalized coordinates are assumed and they must be +between [0,1]. +If int, pixels coordinates are assumed and it must fit within the +panel’s size.

  • +
+
+
+
+ +
+ +
+
+

TabPanel2D#

+
+
+class fury.ui.containers.TabPanel2D(position=(0, 0), size=(100, 100), title='New Tab', color=(0.5, 0.5, 0.5), content_panel=None)[source]#
+

Bases: UI

+

Render content within a Tab.

+
+
+content_panel#
+

Hold all the content UI components.

+
+
Type:
+
+
class:
+

‘Panel2D’

+
+
+
+
+
+ +
+
+text_block#
+

Renders the title of the tab.

+
+
Type:
+
+
class:
+

‘TextBlock2D’

+
+
+
+
+
+ +
+
+__init__(position=(0, 0), size=(100, 100), title='New Tab', color=(0.5, 0.5, 0.5), content_panel=None)[source]#
+

Init class instance.

+
+
Parameters:
+
    +
  • position ((float, float)) – Absolute coordinates (x, y) of the lower-left corner of the +UI component

  • +
  • size ((int, int)) – Width and height of the pixels of this UI component.

  • +
  • title (str) – Renders the title for Tab panel.

  • +
  • color (list of 3 floats) – Background color of tab panel.

  • +
  • content_panel (Panel2D) – Panel consisting of the content UI elements.

  • +
+
+
+
+ +
+
+add_element(element, coords, anchor='position')[source]#
+

Add a UI component to the content panel.

+

The coordinates represent an offset from the lower left corner of the +panel.

+
+
Parameters:
+
    +
  • element (UI) – The UI item to be added.

  • +
  • coords ((float, float) or (int, int)) – If float, normalized coordinates are assumed and they must be +between [0,1]. +If int, pixels coordinates are assumed and it must fit within the +panel’s size.

  • +
+
+
+
+ +
+
+property color#
+

Return the background color of tab panel.

+
+ +
+
+remove_element(element)[source]#
+

Remove a UI component from the content panel.

+
+
Parameters:
+

element (UI) – The UI item to be removed.

+
+
+
+ +
+
+resize(size)[source]#
+

Resize Tab panel.

+
+
Parameters:
+

size ((int, int)) – New width and height in pixels.

+
+
+
+ +
+
+property title#
+

Return the title of tab panel.

+
+ +
+
+property title_bold#
+

Is the title of a tab panel bold.

+
+ +
+
+property title_color#
+

Return the title color of tab panel.

+
+ +
+
+property title_font_size#
+

Return the title font size of tab panel.

+
+ +
+
+property title_italic#
+

Is the title of a tab panel italic.

+
+ +
+
+update_element(element, coords, anchor='position')[source]#
+

Update the position of a UI component in the content panel.

+
+
Parameters:
+
    +
  • element (UI) – The UI item to be updated.

  • +
  • coords ((float, float) or (int, int)) – New coordinates. +If float, normalized coordinates are assumed and they must be +between [0,1]. +If int, pixels coordinates are assumed and it must fit within the +panel’s size.

  • +
+
+
+
+ +
+ +
+
+

TabUI#

+
+
+class fury.ui.containers.TabUI(position=(0, 0), size=(100, 100), nb_tabs=1, active_color=(1, 1, 1), inactive_color=(0.5, 0.5, 0.5), draggable=False, startup_tab_id=None)[source]#
+

Bases: UI

+

UI element to add multiple panels within a single window.

+
+
+tabs#
+

Stores all the instances of ‘TabPanel2D’ that renders the contents.

+
+
Type:
+
+
class:
+

List of ‘TabPanel2D’

+
+
+
+
+
+ +
+
+__init__(position=(0, 0), size=(100, 100), nb_tabs=1, active_color=(1, 1, 1), inactive_color=(0.5, 0.5, 0.5), draggable=False, startup_tab_id=None)[source]#
+

Init class instance.

+
+
Parameters:
+
    +
  • position ((float, float)) – Absolute coordinates (x, y) of the lower-left corner of this +UI component.

  • +
  • size ((int, int)) – Width and height in pixels of this UI component.

  • +
  • nb_tabs (int) – Number of tabs to be renders.

  • +
  • active_color (tuple of 3 floats.) – Background color of active tab panel.

  • +
  • inactive_color (tuple of 3 floats.) – Background color of inactive tab panels.

  • +
  • draggable (bool) – Whether the UI element is draggable or not.

  • +
  • startup_tab_id (int, optional) – Tab to be activated and uncollapsed on startup. +by default None is activated/ all collapsed.

  • +
+
+
+
+ +
+
+add_element(tab_idx, element, coords, anchor='position')[source]#
+

Add element to content panel after checking its existence.

+
+ +
+
+collapse_tab_ui(iren, _obj, _tab_comp)[source]#
+

Handle events when Tab UI is collapsed.

+
+ +
+
+left_button_dragged(i_ren, _obj, _sub_component)[source]#
+
+ +
+
+left_button_pressed(i_ren, _obj, _sub_component)[source]#
+
+ +
+
+remove_element(tab_idx, element)[source]#
+

Remove element from content panel after checking its existence.

+
+ +
+
+select_tab_callback(iren, _obj, _tab_comp)[source]#
+

Handle events when a tab is selected.

+
+ +
+
+update_element(tab_idx, element, coords, anchor='position')[source]#
+

Update element on content panel after checking its existence.

+
+ +
+
+update_tabs()[source]#
+

Update position, size and callbacks for tab panels.

+
+ +
+ +
+
+

ImageContainer2D#

+
+
+class fury.ui.containers.ImageContainer2D(img_path, position=(0, 0), size=(100, 100))[source]#
+

Bases: UI

+

A 2D container to hold an image.

+

Currently Supports: +- png and jpg/jpeg images

+
+
+size#
+

Image size (width, height) in pixels.

+
+
Type:
+

(float, float)

+
+
+
+ +
+
+img#
+

The image loaded from the specified path.

+
+
Type:
+

ImageData

+
+
+
+ +
+
+__init__(img_path, position=(0, 0), size=(100, 100))[source]#
+

Init class instance.

+
+
Parameters:
+
    +
  • img_path (string) – URL or local path of the image

  • +
  • position ((float, float), optional) – Absolute coordinates (x, y) of the lower-left corner of the image.

  • +
  • size ((int, int), optional) – Width and height in pixels of the image.

  • +
+
+
+
+ +
+
+resize(size)[source]#
+

Resize the image.

+
+
Parameters:
+

size ((float, float)) – image size (width, height) in pixels.

+
+
+
+ +
+
+scale(factor)[source]#
+

Scale the image.

+
+
Parameters:
+

factor ((float, float)) – Scaling factor (width, height) in pixels.

+
+
+
+ +
+
+set_img(img)[source]#
+

Modify the image used by the vtkTexturedActor2D.

+
+
Parameters:
+

img (imageData) –

+
+
+
+ +
+ +
+
+

GridUI#

+
+
+class fury.ui.containers.GridUI(actors, captions=None, caption_offset=(0, -100, 0), cell_padding=0, cell_shape='rect', aspect_ratio=1.7777777777777777, dim=None, rotation_speed=1, rotation_axis=(0, 1, 0))[source]#
+

Bases: UI

+

Add actors in a grid and interact with them individually.

+
+
+__init__(actors, captions=None, caption_offset=(0, -100, 0), cell_padding=0, cell_shape='rect', aspect_ratio=1.7777777777777777, dim=None, rotation_speed=1, rotation_axis=(0, 1, 0))[source]#
+

Init scene.

+
+
Parameters:
+

position ((float, float)) – Absolute coordinates (x, y) of the lower-left corner of this +UI component.

+
+
+
+ +
+
+ANTICLOCKWISE_ROTATION_X = array([-10,   1,   0,   0])#
+
+ +
+
+ANTICLOCKWISE_ROTATION_Y = array([-10,   0,   1,   0])#
+
+ +
+
+CLOCKWISE_ROTATION_X = array([10,  1,  0,  0])#
+
+ +
+
+CLOCKWISE_ROTATION_Y = array([10,  0,  1,  0])#
+
+ +
+
+key_press_callback(istyle, obj, _what)[source]#
+
+ +
+
+static left_click_callback(istyle, _obj, _what)[source]#
+
+ +
+
+static left_click_callback2(istyle, obj, self)[source]#
+
+ +
+
+static left_release_callback(istyle, _obj, _what)[source]#
+
+ +
+
+static left_release_callback2(istyle, _obj, _what)[source]#
+
+ +
+
+static mouse_move_callback(istyle, _obj, _what)[source]#
+
+ +
+
+static mouse_move_callback2(istyle, obj, self)[source]#
+
+ +
+
+resize(size)[source]#
+

Resize the button.

+
+
Parameters:
+

size ((float, float)) – Button size (width, height) in pixels.

+
+
+
+ +
+ +
+
+

UI#

+
+
+class fury.ui.core.UI(position=(0, 0))[source]#
+

Bases: object

+

An umbrella class for all UI elements.

+

While adding UI elements to the scene, we go over all the sub-elements +that come with it and add those to the scene automatically.

+
+
+position#
+

Absolute coordinates (x, y) of the lower-left corner of this +UI component.

+
+
Type:
+

(float, float)

+
+
+
+ +
+
+center#
+

Absolute coordinates (x, y) of the center of this UI component.

+
+
Type:
+

(float, float)

+
+
+
+ +
+
+size#
+

Width and height in pixels of this UI component.

+
+
Type:
+

(int, int)

+
+
+
+ +
+
+on_left_mouse_button_pressed#
+

Callback function for when the left mouse button is pressed.

+
+
Type:
+

function

+
+
+
+ +
+
+on_left_mouse_button_released#
+

Callback function for when the left mouse button is released.

+
+
Type:
+

function

+
+
+
+ +
+
+on_left_mouse_button_clicked#
+

Callback function for when clicked using the left mouse button +(i.e. pressed -> released).

+
+
Type:
+

function

+
+
+
+ +
+
+on_left_mouse_double_clicked#
+

Callback function for when left mouse button is double clicked +(i.e pressed -> released -> pressed -> released).

+
+
Type:
+

function

+
+
+
+ +
+
+on_left_mouse_button_dragged#
+

Callback function for when dragging using the left mouse button.

+
+
Type:
+

function

+
+
+
+ +
+
+on_right_mouse_button_pressed#
+

Callback function for when the right mouse button is pressed.

+
+
Type:
+

function

+
+
+
+ +
+
+on_right_mouse_button_released#
+

Callback function for when the right mouse button is released.

+
+
Type:
+

function

+
+
+
+ +
+
+on_right_mouse_button_clicked#
+

Callback function for when clicking using the right mouse button +(i.e. pressed -> released).

+
+
Type:
+

function

+
+
+
+ +
+
+on_right_mouse_double_clicked#
+

Callback function for when right mouse button is double clicked +(i.e pressed -> released -> pressed -> released).

+
+
Type:
+

function

+
+
+
+ +
+
+on_right_mouse_button_dragged#
+

Callback function for when dragging using the right mouse button.

+
+
Type:
+

function

+
+
+
+ +
+
+on_middle_mouse_button_pressed#
+

Callback function for when the middle mouse button is pressed.

+
+
Type:
+

function

+
+
+
+ +
+
+on_middle_mouse_button_released#
+

Callback function for when the middle mouse button is released.

+
+
Type:
+

function

+
+
+
+ +
+
+on_middle_mouse_button_clicked#
+

Callback function for when clicking using the middle mouse button +(i.e. pressed -> released).

+
+
Type:
+

function

+
+
+
+ +
+
+on_middle_mouse_double_clicked#
+

Callback function for when middle mouse button is double clicked +(i.e pressed -> released -> pressed -> released).

+
+
Type:
+

function

+
+
+
+ +
+
+on_middle_mouse_button_dragged#
+

Callback function for when dragging using the middle mouse button.

+
+
Type:
+

function

+
+
+
+ +
+
+on_key_press#
+

Callback function for when a keyboard key is pressed.

+
+
Type:
+

function

+
+
+
+ +
+
+__init__(position=(0, 0))[source]#
+

Init scene.

+
+
Parameters:
+

position ((float, float)) – Absolute coordinates (x, y) of the lower-left corner of this +UI component.

+
+
+
+ +
+
+property actors#
+

Actors composing this UI component.

+
+ +
+
+add_callback(prop, event_type, callback, priority=0)[source]#
+

Add a callback to a specific event for this UI component.

+
+
Parameters:
+
    +
  • prop (vtkProp) – The prop on which is callback is to be added.

  • +
  • event_type (string) – The event code.

  • +
  • callback (function) – The callback function.

  • +
  • priority (int) – Higher number is higher priority.

  • +
+
+
+
+ +
+
+add_to_scene(scene)[source]#
+

Allow UI objects to add their own props to the scene.

+
+
Parameters:
+

scene (scene) –

+
+
+
+ +
+
+property center#
+
+ +
+
+handle_events(actor)[source]#
+
+ +
+
+static key_press_callback(i_ren, obj, self)[source]#
+
+ +
+
+static left_button_click_callback(i_ren, obj, self)[source]#
+
+ +
+
+static left_button_release_callback(i_ren, obj, self)[source]#
+
+ +
+
+static middle_button_click_callback(i_ren, obj, self)[source]#
+
+ +
+
+static middle_button_release_callback(i_ren, obj, self)[source]#
+
+ +
+
+static mouse_move_callback(i_ren, obj, self)[source]#
+
+ +
+
+property position#
+
+ +
+
+static right_button_click_callback(i_ren, obj, self)[source]#
+
+ +
+
+static right_button_release_callback(i_ren, obj, self)[source]#
+
+ +
+
+set_visibility(visibility)[source]#
+

Set visibility of this UI component.

+
+ +
+
+property size#
+
+ +
+ +
+
+

Rectangle2D#

+
+
+class fury.ui.core.Rectangle2D(size=(0, 0), position=(0, 0), color=(1, 1, 1), opacity=1.0)[source]#
+

Bases: UI

+

A 2D rectangle sub-classed from UI.

+
+
+__init__(size=(0, 0), position=(0, 0), color=(1, 1, 1), opacity=1.0)[source]#
+

Initialize a rectangle.

+
+
Parameters:
+
    +
  • size ((int, int)) – The size of the rectangle (width, height) in pixels.

  • +
  • position ((float, float)) – Coordinates (x, y) of the lower-left corner of the rectangle.

  • +
  • color ((float, float, float)) – Must take values in [0, 1].

  • +
  • opacity (float) – Must take values in [0, 1].

  • +
+
+
+
+ +
+
+property color#
+

Get the rectangle’s color.

+
+ +
+
+property height#
+
+ +
+
+property opacity#
+

Get the rectangle’s opacity.

+
+ +
+
+resize(size)[source]#
+

Set the button size.

+
+
Parameters:
+

size ((float, float)) – Button size (width, height) in pixels.

+
+
+
+ +
+
+property width#
+
+ +
+ +
+
+

Disk2D#

+
+
+class fury.ui.core.Disk2D(outer_radius, inner_radius=0, center=(0, 0), color=(1, 1, 1), opacity=1.0)[source]#
+

Bases: UI

+

A 2D disk UI component.

+
+
+__init__(outer_radius, inner_radius=0, center=(0, 0), color=(1, 1, 1), opacity=1.0)[source]#
+

Initialize a 2D Disk.

+
+
Parameters:
+
    +
  • outer_radius (int) – Outer radius of the disk.

  • +
  • inner_radius (int, optional) – Inner radius of the disk. A value > 0, makes a ring.

  • +
  • center ((float, float), optional) – Coordinates (x, y) of the center of the disk.

  • +
  • color ((float, float, float), optional) – Must take values in [0, 1].

  • +
  • opacity (float, optional) – Must take values in [0, 1].

  • +
+
+
+
+ +
+
+property color#
+

Get the color of this UI component.

+
+ +
+
+property inner_radius#
+
+ +
+
+property opacity#
+

Get the opacity of this UI component.

+
+ +
+
+property outer_radius#
+
+ +
+ +
+
+

TextBlock2D#

+
+
+class fury.ui.core.TextBlock2D(text='Text Block', font_size=18, font_family='Arial', justification='left', vertical_justification='bottom', bold=False, italic=False, shadow=False, size=None, color=(1, 1, 1), bg_color=None, position=(0, 0), auto_font_scale=False, dynamic_bbox=False)[source]#
+

Bases: UI

+

Wrap over the default vtkTextActor and helps setting the text.

+

Contains member functions for text formatting.

+
+
+actor#
+

The text actor.

+
+
Type:
+

vtkTextActor

+
+
+
+ +
+
+message#
+

The initial text while building the actor.

+
+
Type:
+

str

+
+
+
+ +
+
+position#
+

(x, y) in pixels.

+
+
Type:
+

(float, float)

+
+
+
+ +
+
+color#
+

RGB: Values must be between 0-1.

+
+
Type:
+

(float, float, float)

+
+
+
+ +
+
+bg_color#
+

RGB: Values must be between 0-1.

+
+
Type:
+

(float, float, float)

+
+
+
+ +
+
+font_size#
+

Size of the text font.

+
+
Type:
+

int

+
+
+
+ +
+
+font_family#
+

Currently only supports Arial.

+
+
Type:
+

str

+
+
+
+ +
+
+justification#
+

left, right or center.

+
+
Type:
+

str

+
+
+
+ +
+
+vertical_justification#
+

bottom, middle or top.

+
+
Type:
+

str

+
+
+
+ +
+
+bold#
+

Makes text bold.

+
+
Type:
+

bool

+
+
+
+ +
+
+italic#
+

Makes text italicised.

+
+
Type:
+

bool

+
+
+
+ +
+
+shadow#
+

Adds text shadow.

+
+
Type:
+

bool

+
+
+
+ +
+
+size#
+

Size (width, height) in pixels of the text bounding box.

+
+
Type:
+

(int, int)

+
+
+
+ +
+
+auto_font_scale#
+

Automatically scale font according to the text bounding box.

+
+
Type:
+

bool

+
+
+
+ +
+
+dynamic_bbox#
+

Automatically resize the bounding box according to the content.

+
+
Type:
+

bool

+
+
+
+ +
+
+__init__(text='Text Block', font_size=18, font_family='Arial', justification='left', vertical_justification='bottom', bold=False, italic=False, shadow=False, size=None, color=(1, 1, 1), bg_color=None, position=(0, 0), auto_font_scale=False, dynamic_bbox=False)[source]#
+

Init class instance.

+
+
Parameters:
+
    +
  • text (str) – The initial text while building the actor.

  • +
  • position ((float, float)) – (x, y) in pixels.

  • +
  • color ((float, float, float)) – RGB: Values must be between 0-1.

  • +
  • bg_color ((float, float, float)) – RGB: Values must be between 0-1.

  • +
  • font_size (int) – Size of the text font.

  • +
  • font_family (str) – Currently only supports Arial.

  • +
  • justification (str) – left, right or center.

  • +
  • vertical_justification (str) – bottom, middle or top.

  • +
  • bold (bool) – Makes text bold.

  • +
  • italic (bool) – Makes text italicised.

  • +
  • shadow (bool) – Adds text shadow.

  • +
  • size ((int, int)) – Size (width, height) in pixels of the text bounding box.

  • +
  • auto_font_scale (bool, optional) – Automatically scale font according to the text bounding box.

  • +
  • dynamic_bbox (bool, optional) – Automatically resize the bounding box according to the content.

  • +
+
+
+
+ +
+
+property auto_font_scale#
+

Return whether text font is automatically scaled.

+
+
Returns:
+

Text is auto_font_scaled if True.

+
+
Return type:
+

bool

+
+
+
+ +
+
+property background_color#
+

Get background color.

+
+
Returns:
+

If None, there no background color. +Otherwise, background color in RGB.

+
+
Return type:
+

(float, float, float) or None

+
+
+
+ +
+
+property bold#
+

Return whether the text is bold.

+
+
Returns:
+

Text is bold if True.

+
+
Return type:
+

bool

+
+
+
+ +
+
+cal_size_from_message()[source]#
+

Calculate size of background according to the message it contains.

+
+ +
+
+property color#
+

Get text color.

+
+
Returns:
+

Returns text color in RGB.

+
+
Return type:
+

(float, float, float)

+
+
+
+ +
+
+property dynamic_bbox#
+

Automatically resize the bounding box according to the content.

+
+
Returns:
+

Bounding box is dynamic if True.

+
+
Return type:
+

bool

+
+
+
+ +
+
+property font_family#
+

Get font family.

+
+
Returns:
+

Text font family.

+
+
Return type:
+

str

+
+
+
+ +
+
+property font_size#
+

Get text font size.

+
+
Returns:
+

Text font size.

+
+
Return type:
+

int

+
+
+
+ +
+
+property italic#
+

Return whether the text is italicised.

+
+
Returns:
+

Text is italicised if True.

+
+
Return type:
+

bool

+
+
+
+ +
+
+property justification#
+

Get text justification.

+
+
Returns:
+

Text justification.

+
+
Return type:
+

str

+
+
+
+ +
+
+property message#
+

Get message from the text.

+
+
Returns:
+

The current text message.

+
+
Return type:
+

str

+
+
+
+ +
+
+resize(size)[source]#
+

Resize TextBlock2D.

+
+
Parameters:
+

size ((int, int)) – Text bounding box size(width, height) in pixels.

+
+
+
+ +
+
+property shadow#
+

Return whether the text has shadow.

+
+
Returns:
+

Text is shadowed if True.

+
+
Return type:
+

bool

+
+
+
+ +
+
+update_alignment()[source]#
+

Update Text Alignment.

+
+ +
+
+update_bounding_box(size=None)[source]#
+

Update Text Bounding Box.

+
+
Parameters:
+

size ((int, int) or None) – If None, calculates bounding box. +Otherwise, uses the given size.

+
+
+
+ +
+
+property vertical_justification#
+

Get text vertical justification.

+
+
Returns:
+

Text vertical justification.

+
+
Return type:
+

str

+
+
+
+ +
+ +
+
+

Button2D#

+
+
+class fury.ui.core.Button2D(icon_fnames, position=(0, 0), size=(30, 30))[source]#
+

Bases: UI

+

A 2D overlay button and is of type vtkTexturedActor2D.

+

Currently supports:

+
- Multiple icons.
+- Switching between icons.
+
+
+
+
+__init__(icon_fnames, position=(0, 0), size=(30, 30))[source]#
+

Init class instance.

+
+
Parameters:
+
    +
  • icon_fnames (List(string, string)) – ((iconname, filename), (iconname, filename), ….)

  • +
  • position ((float, float), optional) – Absolute coordinates (x, y) of the lower-left corner of the button.

  • +
  • size ((int, int), optional) – Width and height in pixels of the button.

  • +
+
+
+
+ +
+
+property color#
+

Get the button’s color.

+
+ +
+
+next_icon()[source]#
+

Increment the state of the Button.

+

Also changes the icon.

+
+ +
+
+next_icon_id()[source]#
+

Set the next icon ID while cycling through icons.

+
+ +
+
+resize(size)[source]#
+

Resize the button.

+
+
Parameters:
+

size ((float, float)) – Button size (width, height) in pixels.

+
+
+
+ +
+
+scale(factor)[source]#
+

Scale the button.

+
+
Parameters:
+

factor ((float, float)) – Scaling factor (width, height) in pixels.

+
+
+
+ +
+
+set_icon(icon)[source]#
+

Modify the icon used by the vtkTexturedActor2D.

+
+
Parameters:
+

icon (imageData) –

+
+
+
+ +
+
+set_icon_by_name(icon_name)[source]#
+

Set the button icon using its name.

+
+
Parameters:
+

icon_name (str) –

+
+
+
+ +
+ +
+
+

TextBox2D#

+
+
+class fury.ui.elements.TextBox2D(width, height, text='Enter Text', position=(100, 10), color=(0, 0, 0), font_size=18, font_family='Arial', justification='left', bold=False, italic=False, shadow=False)[source]#
+

Bases: UI

+

An editable 2D text box that behaves as a UI component.

+

Currently supports: +- Basic text editing. +- Cursor movements. +- Single and multi-line text boxes. +- Pre text formatting (text needs to be formatted beforehand).

+
+
+text#
+

The current text state.

+
+
Type:
+

str

+
+
+
+ +
+
+actor#
+

The text actor.

+
+
Type:
+

vtkActor2d

+
+
+
+ +
+
+width#
+

The number of characters in a single line of text.

+
+
Type:
+

int

+
+
+
+ +
+
+height#
+

The number of lines in the textbox.

+
+
Type:
+

int

+
+
+
+ +
+
+window_left#
+

Left limit of visible text in the textbox.

+
+
Type:
+

int

+
+
+
+ +
+
+window_right#
+

Right limit of visible text in the textbox.

+
+
Type:
+

int

+
+
+
+ +
+
+caret_pos#
+

Position of the caret in the text.

+
+
Type:
+

int

+
+
+
+ +
+
+init#
+

Flag which says whether the textbox has just been initialized.

+
+
Type:
+

bool

+
+
+
+ +
+
+__init__(width, height, text='Enter Text', position=(100, 10), color=(0, 0, 0), font_size=18, font_family='Arial', justification='left', bold=False, italic=False, shadow=False)[source]#
+

Init this UI element.

+
+
Parameters:
+
    +
  • width (int) – The number of characters in a single line of text.

  • +
  • height (int) – The number of lines in the textbox.

  • +
  • text (str) – The initial text while building the actor.

  • +
  • position ((float, float)) – (x, y) in pixels.

  • +
  • color ((float, float, float)) – RGB: Values must be between 0-1.

  • +
  • font_size (int) – Size of the text font.

  • +
  • font_family (str) – Currently only supports Arial.

  • +
  • justification (str) – left, right or center.

  • +
  • bold (bool) – Makes text bold.

  • +
  • italic (bool) – Makes text italicised.

  • +
  • shadow (bool) – Adds text shadow.

  • +
+
+
+
+ +
+
+add_character(character)[source]#
+

Insert a character into the text and moves window and caret.

+
+
Parameters:
+

character (str) –

+
+
+
+ +
+
+edit_mode()[source]#
+

Turn on edit mode.

+
+ +
+
+handle_character(key, key_char)[source]#
+

Handle button events.

+

# TODO: Need to handle all kinds of characters like !, +, etc.

+
+
Parameters:
+

character (str) –

+
+
+
+ +
+
+key_press(i_ren, _obj, _textbox_object)[source]#
+

Handle Key press for textboxself.

+
+
Parameters:
+
    +
  • i_ren (CustomInteractorStyle) –

  • +
  • obj (vtkActor) – The picked actor

  • +
  • _textbox_object (TextBox2D) –

  • +
+
+
+
+ +
+
+left_button_press(i_ren, _obj, _textbox_object)[source]#
+

Handle left button press for textbox.

+
+
Parameters:
+
    +
  • i_ren (CustomInteractorStyle) –

  • +
  • obj (vtkActor) – The picked actor

  • +
  • _textbox_object (TextBox2D) –

  • +
+
+
+
+ +
+
+left_move_left()[source]#
+

Move left boundary of the text window left-wards.

+
+ +
+
+left_move_right()[source]#
+

Move left boundary of the text window right-wards.

+
+ +
+
+move_caret_left()[source]#
+

Move the caret towards left.

+
+ +
+
+move_caret_right()[source]#
+

Move the caret towards right.

+
+ +
+
+move_left()[source]#
+

Handle left button press.

+
+ +
+
+move_right()[source]#
+

Handle right button press.

+
+ +
+
+remove_character()[source]#
+

Remove a character and moves window and caret accordingly.

+
+ +
+
+render_text(show_caret=True)[source]#
+

Render text after processing.

+
+
Parameters:
+

show_caret (bool) – Whether or not to show the caret.

+
+
+
+ +
+
+right_move_left()[source]#
+

Move right boundary of the text window left-wards.

+
+ +
+
+right_move_right()[source]#
+

Move right boundary of the text window right-wards.

+
+ +
+
+set_message(message)[source]#
+

Set custom text to textbox.

+
+
Parameters:
+

message (str) – The custom message to be set.

+
+
+
+ +
+
+showable_text(show_caret)[source]#
+

Chop out text to be shown on the screen.

+
+
Parameters:
+

show_caret (bool) – Whether or not to show the caret.

+
+
+
+ +
+
+width_set_text(text)[source]#
+

Add newlines to text where necessary.

+

This is needed for multi-line text boxes.

+
+
Parameters:
+

text (str) – The final text to be formatted.

+
+
Returns:
+

A multi line formatted text.

+
+
Return type:
+

str

+
+
+
+ +
+ +
+
+

LineSlider2D#

+
+
+class fury.ui.elements.LineSlider2D(center=(0, 0), initial_value=50, min_value=0, max_value=100, length=200, line_width=5, inner_radius=0, outer_radius=10, handle_side=20, font_size=16, orientation='horizontal', text_alignment='', text_template='{value:.1f} ({ratio:.0%})', shape='disk')[source]#
+

Bases: UI

+

A 2D Line Slider.

+

A sliding handle on a line with a percentage indicator.

+
+
+line_width#
+

Width of the line on which the disk will slide.

+
+
Type:
+

int

+
+
+
+ +
+
+length#
+

Length of the slider.

+
+
Type:
+

int

+
+
+
+ +
+
+track#
+

The line on which the slider’s handle moves.

+
+
Type:
+

Rectangle2D

+
+
+
+ +
+
+handle#
+

The moving part of the slider.

+
+
Type:
+

Disk2D

+
+
+
+ +
+
+text#
+

The text that shows percentage.

+
+
Type:
+

TextBlock2D

+
+
+
+ +
+
+shape#
+

Describes the shape of the handle. +Currently supports ‘disk’ and ‘square’.

+
+
Type:
+

string

+
+
+
+ +
+
+default_color#
+

Color of the handle when in unpressed state.

+
+
Type:
+

(float, float, float)

+
+
+
+ +
+
+active_color#
+

Color of the handle when it is pressed.

+
+
Type:
+

(float, float, float)

+
+
+
+ +
+
+__init__(center=(0, 0), initial_value=50, min_value=0, max_value=100, length=200, line_width=5, inner_radius=0, outer_radius=10, handle_side=20, font_size=16, orientation='horizontal', text_alignment='', text_template='{value:.1f} ({ratio:.0%})', shape='disk')[source]#
+

Init this UI element.

+
+
Parameters:
+
    +
  • center ((float, float)) – Center of the slider’s center.

  • +
  • initial_value (float) – Initial value of the slider.

  • +
  • min_value (float) – Minimum value of the slider.

  • +
  • max_value (float) – Maximum value of the slider.

  • +
  • length (int) – Length of the slider.

  • +
  • line_width (int) – Width of the line on which the disk will slide.

  • +
  • inner_radius (int) – Inner radius of the handles (if disk).

  • +
  • outer_radius (int) – Outer radius of the handles (if disk).

  • +
  • handle_side (int) – Side length of the handles (if square).

  • +
  • font_size (int) – Size of the text to display alongside the slider (pt).

  • +
  • orientation (str) – horizontal or vertical

  • +
  • text_alignment (str) – define text alignment on a slider. Left (default)/ right for the +vertical slider or top/bottom (default) for an horizontal slider.

  • +
  • text_template (str, callable) – If str, text template can contain one or multiple of the +replacement fields: {value:}, {ratio:}. +If callable, this instance of :class:LineSlider2D will be +passed as argument to the text template function.

  • +
  • shape (string) – Describes the shape of the handle. +Currently supports ‘disk’ and ‘square’.

  • +
+
+
+
+ +
+
+property bottom_y_position#
+
+ +
+
+format_text()[source]#
+

Return formatted text to display along the slider.

+
+ +
+
+handle_move_callback(i_ren, _vtkactor, _slider)[source]#
+

Handle movement.

+
+
Parameters:
+
    +
  • i_ren (CustomInteractorStyle) –

  • +
  • vtkactor (vtkActor) – The picked actor

  • +
  • slider (LineSlider2D) –

  • +
+
+
+
+ +
+
+handle_release_callback(i_ren, _vtkactor, _slider)[source]#
+

Change color when handle is released.

+
+
Parameters:
+
    +
  • i_ren (CustomInteractorStyle) –

  • +
  • vtkactor (vtkActor) – The picked actor

  • +
  • slider (LineSlider2D) –

  • +
+
+
+
+ +
+
+property left_x_position#
+
+ +
+
+property ratio#
+
+ +
+
+property right_x_position#
+
+ +
+
+set_position(position)[source]#
+

Set the disk’s position.

+
+
Parameters:
+

position ((float, float)) – The absolute position of the disk (x, y).

+
+
+
+ +
+
+property top_y_position#
+
+ +
+
+track_click_callback(i_ren, _vtkactor, _slider)[source]#
+

Update disk position and grab the focus.

+
+
Parameters:
+
    +
  • i_ren (CustomInteractorStyle) –

  • +
  • vtkactor (vtkActor) – The picked actor

  • +
  • _slider (LineSlider2D) –

  • +
+
+
+
+ +
+
+update()[source]#
+

Update the slider.

+
+ +
+
+property value#
+
+ +
+ +
+
+

LineDoubleSlider2D#

+
+
+class fury.ui.elements.LineDoubleSlider2D(line_width=5, inner_radius=0, outer_radius=10, handle_side=20, center=(450, 300), length=200, initial_values=(0, 100), min_value=0, max_value=100, font_size=16, text_template='{value:.1f}', orientation='horizontal', shape='disk')[source]#
+

Bases: UI

+

A 2D Line Slider with two sliding rings.

+

Useful for setting min and max values for something.

+

Currently supports: +- Setting positions of both disks.

+
+
+line_width#
+

Width of the line on which the disk will slide.

+
+
Type:
+

int

+
+
+
+ +
+
+length#
+

Length of the slider.

+
+
Type:
+

int

+
+
+
+ +
+
+track#
+

The line on which the handles move.

+
+
Type:
+

vtkActor

+
+
+
+ +
+
+handles#
+

The moving slider disks.

+
+
Type:
+

[vtkActor, vtkActor]

+
+
+
+ +
+
+text#
+

The texts that show the values of the disks.

+
+
Type:
+

[TextBlock2D, TextBlock2D]

+
+
+
+ +
+
+shape#
+

Describes the shape of the handle. +Currently supports ‘disk’ and ‘square’.

+
+
Type:
+

string

+
+
+
+ +
+
+default_color#
+

Color of the handles when in unpressed state.

+
+
Type:
+

(float, float, float)

+
+
+
+ +
+
+active_color#
+

Color of the handles when they are pressed.

+
+
Type:
+

(float, float, float)

+
+
+
+ +
+
+__init__(line_width=5, inner_radius=0, outer_radius=10, handle_side=20, center=(450, 300), length=200, initial_values=(0, 100), min_value=0, max_value=100, font_size=16, text_template='{value:.1f}', orientation='horizontal', shape='disk')[source]#
+

Init this UI element.

+
+
Parameters:
+
    +
  • line_width (int) – Width of the line on which the disk will slide.

  • +
  • inner_radius (int) – Inner radius of the handles (if disk).

  • +
  • outer_radius (int) – Outer radius of the handles (if disk).

  • +
  • handle_side (int) – Side length of the handles (if square).

  • +
  • center ((float, float)) – Center of the slider.

  • +
  • length (int) – Length of the slider.

  • +
  • initial_values ((float, float)) – Initial values of the two handles.

  • +
  • min_value (float) – Minimum value of the slider.

  • +
  • max_value (float) – Maximum value of the slider.

  • +
  • font_size (int) – Size of the text to display alongside the slider (pt).

  • +
  • text_template (str, callable) – If str, text template can contain one or multiple of the +replacement fields: {value:}, {ratio:}. +If callable, this instance of :class:LineDoubleSlider2D will be +passed as argument to the text template function.

  • +
  • orientation (str) – horizontal or vertical

  • +
  • shape (string) – Describes the shape of the handle. +Currently supports ‘disk’ and ‘square’.

  • +
+
+
+
+ +
+
+property bottom_disk_ratio#
+

Return the ratio of the bottom disk.

+
+ +
+
+property bottom_disk_value#
+

Return the value of the bottom disk.

+
+ +
+
+property bottom_y_position#
+
+ +
+
+coord_to_ratio(coord)[source]#
+

Convert the x coordinate of a disk to the ratio.

+
+
Parameters:
+

coord (float) –

+
+
+
+ +
+
+format_text(disk_number)[source]#
+

Return formatted text to display along the slider.

+
+
Parameters:
+

disk_number (int) – Index of the disk.

+
+
+
+ +
+
+handle_move_callback(i_ren, vtkactor, _slider)[source]#
+

Handle movement.

+
+
Parameters:
+
    +
  • i_ren (CustomInteractorStyle) –

  • +
  • vtkactor (vtkActor) – The picked actor

  • +
  • _slider (LineDoubleSlider2D) –

  • +
+
+
+
+ +
+
+handle_release_callback(i_ren, vtkactor, _slider)[source]#
+

Change color when handle is released.

+
+
Parameters:
+
    +
  • i_ren (CustomInteractorStyle) –

  • +
  • vtkactor (vtkActor) – The picked actor

  • +
  • _slider (LineDoubleSlider2D) –

  • +
+
+
+
+ +
+
+property left_disk_ratio#
+

Return the ratio of the left disk.

+
+ +
+
+property left_disk_value#
+

Return the value of the left disk.

+
+ +
+
+property left_x_position#
+
+ +
+
+ratio_to_coord(ratio)[source]#
+

Convert the ratio to the absolute coordinate.

+
+
Parameters:
+

ratio (float) –

+
+
+
+ +
+
+ratio_to_value(ratio)[source]#
+

Convert the ratio to the value of the disk.

+
+
Parameters:
+

ratio (float) –

+
+
+
+ +
+
+property right_disk_ratio#
+

Return the ratio of the right disk.

+
+ +
+
+property right_disk_value#
+

Return the value of the right disk.

+
+ +
+
+property right_x_position#
+
+ +
+
+set_position(position, disk_number)[source]#
+

Set the disk’s position.

+
+
Parameters:
+
    +
  • position ((float, float)) – The absolute position of the disk (x, y).

  • +
  • disk_number (int) – The index of disk being moved.

  • +
+
+
+
+ +
+
+property top_disk_ratio#
+

Return the ratio of the top disk.

+
+ +
+
+property top_disk_value#
+

Return the value of the top disk.

+
+ +
+
+property top_y_position#
+
+ +
+
+update(disk_number)[source]#
+

Update the slider.

+
+
Parameters:
+

disk_number (int) – Index of the disk to be updated.

+
+
+
+ +
+
+value_to_ratio(value)[source]#
+

Convert the value of a disk to the ratio.

+
+
Parameters:
+

value (float) –

+
+
+
+ +
+ +
+
+

RingSlider2D#

+
+
+class fury.ui.elements.RingSlider2D(center=(0, 0), initial_value=180, min_value=0, max_value=360, slider_inner_radius=40, slider_outer_radius=44, handle_inner_radius=0, handle_outer_radius=10, font_size=16, text_template='{ratio:.0%}')[source]#
+

Bases: UI

+

A disk slider.

+

A disk moves along the boundary of a ring. +Goes from 0-360 degrees.

+
+
+mid_track_radius#
+

Distance from the center of the slider to the middle of the track.

+
+
Type:
+

float

+
+
+
+ +
+
+previous_value#
+

Value of Rotation of the actor before the current value.

+
+
Type:
+

float

+
+
+
+ +
+
+track#
+

The circle on which the slider’s handle moves.

+
+
Type:
+

Disk2D

+
+
+
+ +
+
+handle#
+

The moving part of the slider.

+
+
Type:
+

Disk2D

+
+
+
+ +
+
+text#
+

The text that shows percentage.

+
+
Type:
+

TextBlock2D

+
+
+
+ +
+
+default_color#
+

Color of the handle when in unpressed state.

+
+
Type:
+

(float, float, float)

+
+
+
+ +
+
+active_color#
+

Color of the handle when it is pressed.

+
+
Type:
+

(float, float, float)

+
+
+
+ +
+
+__init__(center=(0, 0), initial_value=180, min_value=0, max_value=360, slider_inner_radius=40, slider_outer_radius=44, handle_inner_radius=0, handle_outer_radius=10, font_size=16, text_template='{ratio:.0%}')[source]#
+

Init this UI element.

+
+
Parameters:
+
    +
  • center ((float, float)) – Position (x, y) of the slider’s center.

  • +
  • initial_value (float) – Initial value of the slider.

  • +
  • min_value (float) – Minimum value of the slider.

  • +
  • max_value (float) – Maximum value of the slider.

  • +
  • slider_inner_radius (int) – Inner radius of the base disk.

  • +
  • slider_outer_radius (int) – Outer radius of the base disk.

  • +
  • handle_outer_radius (int) – Outer radius of the slider’s handle.

  • +
  • handle_inner_radius (int) – Inner radius of the slider’s handle.

  • +
  • font_size (int) – Size of the text to display alongside the slider (pt).

  • +
  • text_template (str, callable) – If str, text template can contain one or multiple of the +replacement fields: {value:}, {ratio:}, {angle:}. +If callable, this instance of :class:RingSlider2D will be +passed as argument to the text template function.

  • +
+
+
+
+ +
+
+property angle#
+

Return Angle (in rad) the handle makes with x-axis.

+
+ +
+
+format_text()[source]#
+

Return formatted text to display along the slider.

+
+ +
+
+handle_move_callback(i_ren, _obj, _slider)[source]#
+

Move the slider’s handle.

+
+
Parameters:
+
    +
  • i_ren (CustomInteractorStyle) –

  • +
  • obj (vtkActor) – The picked actor

  • +
  • _slider (RingSlider2D) –

  • +
+
+
+
+ +
+
+handle_release_callback(i_ren, _obj, _slider)[source]#
+

Change color when handle is released.

+
+
Parameters:
+
    +
  • i_ren (CustomInteractorStyle) –

  • +
  • vtkactor (vtkActor) – The picked actor

  • +
  • _slider (RingSlider2D) –

  • +
+
+
+
+ +
+
+property mid_track_radius#
+
+ +
+
+move_handle(click_position)[source]#
+

Move the slider’s handle.

+
+
Parameters:
+

click_position ((float, float)) – Position of the mouse click.

+
+
+
+ +
+
+property previous_value#
+
+ +
+
+property ratio#
+
+ +
+
+track_click_callback(i_ren, _obj, _slider)[source]#
+

Update disk position and grab the focus.

+
+
Parameters:
+
    +
  • i_ren (CustomInteractorStyle) –

  • +
  • obj (vtkActor) – The picked actor

  • +
  • _slider (RingSlider2D) –

  • +
+
+
+
+ +
+
+update()[source]#
+

Update the slider.

+
+ +
+
+property value#
+
+ +
+ +
+
+

RangeSlider#

+
+
+class fury.ui.elements.RangeSlider(line_width=5, inner_radius=0, outer_radius=10, handle_side=20, range_slider_center=(450, 400), value_slider_center=(450, 300), length=200, min_value=0, max_value=100, font_size=16, range_precision=1, orientation='horizontal', value_precision=2, shape='disk')[source]#
+

Bases: UI

+

A set of a LineSlider2D and a LineDoubleSlider2D. +The double slider is used to set the min and max value +for the LineSlider2D

+
+
+range_slider_center#
+

Center of the LineDoubleSlider2D object.

+
+
Type:
+

(float, float)

+
+
+
+ +
+
+value_slider_center#
+

Center of the LineSlider2D object.

+
+
Type:
+

(float, float)

+
+
+
+ +
+
+range_slider#
+

The line slider which sets the min and max values

+
+
Type:
+

LineDoubleSlider2D

+
+
+
+ +
+
+value_slider#
+

The line slider which sets the value

+
+
Type:
+

LineSlider2D

+
+
+
+ +
+
+__init__(line_width=5, inner_radius=0, outer_radius=10, handle_side=20, range_slider_center=(450, 400), value_slider_center=(450, 300), length=200, min_value=0, max_value=100, font_size=16, range_precision=1, orientation='horizontal', value_precision=2, shape='disk')[source]#
+

Init this class instance.

+
+
Parameters:
+
    +
  • line_width (int) – Width of the slider tracks

  • +
  • inner_radius (int) – Inner radius of the handles.

  • +
  • outer_radius (int) – Outer radius of the handles.

  • +
  • handle_side (int) – Side length of the handles (if square).

  • +
  • range_slider_center ((float, float)) – Center of the LineDoubleSlider2D object.

  • +
  • value_slider_center ((float, float)) – Center of the LineSlider2D object.

  • +
  • length (int) – Length of the sliders.

  • +
  • min_value (float) – Minimum value of the double slider.

  • +
  • max_value (float) – Maximum value of the double slider.

  • +
  • font_size (int) – Size of the text to display alongside the sliders (pt).

  • +
  • range_precision (int) – Number of decimal places to show the min and max values set.

  • +
  • orientation (str) – horizontal or vertical

  • +
  • value_precision (int) – Number of decimal places to show the value set on slider.

  • +
  • shape (string) – Describes the shape of the handle. +Currently supports ‘disk’ and ‘square’.

  • +
+
+
+
+ +
+
+range_slider_handle_move_callback(i_ren, obj, _slider)[source]#
+

Update range_slider’s handles.

+
+
Parameters:
+
    +
  • i_ren (CustomInteractorStyle) –

  • +
  • obj (vtkActor) – The picked actor

  • +
  • _slider (RangeSlider) –

  • +
+
+
+
+ +
+ +
+
+

Option#

+
+
+class fury.ui.elements.Option(label, position=(0, 0), font_size=18, checked=False)[source]#
+

Bases: UI

+

A set of a Button2D and a TextBlock2D to act as a single option +for checkboxes and radio buttons. +Clicking the button toggles its checked/unchecked status.

+
+
+label#
+

The label for the option.

+
+
Type:
+

str

+
+
+
+ +
+
+font_size#
+

Font Size of the label.

+
+
Type:
+

int

+
+
+
+ +
+
+__init__(label, position=(0, 0), font_size=18, checked=False)[source]#
+

Init this class instance.

+
+
Parameters:
+
    +
  • label (str) – Text to be displayed next to the option’s button.

  • +
  • position ((float, float)) – Absolute coordinates (x, y) of the lower-left corner of +the button of the option.

  • +
  • font_size (int) – Font size of the label.

  • +
  • checked (bool, optional) – Boolean value indicates the initial state of the option

  • +
+
+
+
+ +
+
+deselect()[source]#
+
+ +
+
+select()[source]#
+
+ +
+
+toggle(i_ren, _obj, _element)[source]#
+
+ +
+ +
+
+

Checkbox#

+
+
+class fury.ui.elements.Checkbox(labels, checked_labels=(), padding=1, font_size=18, font_family='Arial', position=(0, 0))[source]#
+

Bases: UI

+

A 2D set of :class:’Option’ objects. +Multiple options can be selected.

+
+
+labels#
+

List of labels of each option.

+
+
Type:
+

list(string)

+
+
+
+ +
+
+options#
+

Dictionary of all the options in the checkbox set.

+
+
Type:
+

dict(Option)

+
+
+
+ +
+
+padding#
+

Distance between two adjacent options

+
+
Type:
+

float

+
+
+
+ +
+
+__init__(labels, checked_labels=(), padding=1, font_size=18, font_family='Arial', position=(0, 0))[source]#
+

Init this class instance.

+
+
Parameters:
+
    +
  • labels (list(str)) – List of labels of each option.

  • +
  • checked_labels (list(str), optional) – List of labels that are checked on setting up.

  • +
  • padding (float, optional) – The distance between two adjacent options

  • +
  • font_size (int, optional) – Size of the text font.

  • +
  • font_family (str, optional) – Currently only supports Arial.

  • +
  • position ((float, float), optional) – Absolute coordinates (x, y) of the lower-left corner of +the button of the first option.

  • +
+
+
+
+ +
+
+property font_size#
+

Gets the font size of text.

+
+ +
+
+property padding#
+

Get the padding between options.

+
+ +
+ +
+
+

RadioButton#

+
+
+class fury.ui.elements.RadioButton(labels, checked_labels, padding=1, font_size=18, font_family='Arial', position=(0, 0))[source]#
+

Bases: Checkbox

+

A 2D set of :class:’Option’ objects. +Only one option can be selected.

+
+
+labels#
+

List of labels of each option.

+
+
Type:
+

list(string)

+
+
+
+ +
+
+options#
+

Dictionary of all the options in the checkbox set.

+
+
Type:
+

dict(Option)

+
+
+
+ +
+
+padding#
+

Distance between two adjacent options

+
+
Type:
+

float

+
+
+
+ +
+
+__init__(labels, checked_labels, padding=1, font_size=18, font_family='Arial', position=(0, 0))[source]#
+

Init class instance.

+
+
Parameters:
+
    +
  • labels (list(str)) – List of labels of each option.

  • +
  • checked_labels (list(str), optional) – List of labels that are checked on setting up.

  • +
  • padding (float, optional) – The distance between two adjacent options

  • +
  • font_size (int, optional) – Size of the text font.

  • +
  • font_family (str, optional) – Currently only supports Arial.

  • +
  • position ((float, float), optional) – Absolute coordinates (x, y) of the lower-left corner of +the button of the first option.

  • +
+
+
+
+ +
+ +
+
+

ComboBox2D#

+
+
+class fury.ui.elements.ComboBox2D(items=[], position=(0, 0), size=(300, 200), placeholder='Choose selection...', draggable=True, selection_text_color=(0, 0, 0), selection_bg_color=(1, 1, 1), menu_text_color=(0.2, 0.2, 0.2), selected_color=(0.9, 0.6, 0.6), unselected_color=(0.6, 0.6, 0.6), scroll_bar_active_color=(0.6, 0.2, 0.2), scroll_bar_inactive_color=(0.9, 0.0, 0.0), menu_opacity=1.0, reverse_scrolling=False, font_size=20, line_spacing=1.4)[source]#
+

Bases: UI

+

UI element to create drop-down menus.

+
+
+selection_box#
+

Display selection and placeholder text.

+
+
Type:
+
+
class:
+

‘TextBox2D’

+
+
+
+
+
+ +
+
+drop_down_button#
+

Button to show or hide menu.

+
+
Type:
+
+
class:
+

‘Button2D’

+
+
+
+
+
+ +
+
+drop_down_menu#
+

Container for item list.

+
+
Type:
+
+
class:
+

‘ListBox2D’

+
+
+
+
+
+ +
+
+__init__(items=[], position=(0, 0), size=(300, 200), placeholder='Choose selection...', draggable=True, selection_text_color=(0, 0, 0), selection_bg_color=(1, 1, 1), menu_text_color=(0.2, 0.2, 0.2), selected_color=(0.9, 0.6, 0.6), unselected_color=(0.6, 0.6, 0.6), scroll_bar_active_color=(0.6, 0.2, 0.2), scroll_bar_inactive_color=(0.9, 0.0, 0.0), menu_opacity=1.0, reverse_scrolling=False, font_size=20, line_spacing=1.4)[source]#
+

Init class Instance.

+
+
Parameters:
+
    +
  • items (list(string)) – List of items to be displayed as choices.

  • +
  • position ((float, float)) – Absolute coordinates (x, y) of the lower-left corner of this +UI component.

  • +
  • size ((int, int)) – Width and height in pixels of this UI component.

  • +
  • placeholder (str) – Holds the default text to be displayed.

  • +
  • draggable ({True, False}) – Whether the UI element is draggable or not.

  • +
  • selection_text_color (tuple of 3 floats) – Color of the selected text to be displayed.

  • +
  • selection_bg_color (tuple of 3 floats) – Background color of the selection text.

  • +
  • menu_text_color (tuple of 3 floats.) – Color of the options displayed in drop down menu.

  • +
  • selected_color (tuple of 3 floats.) – Background color of the selected option in drop down menu.

  • +
  • unselected_color (tuple of 3 floats.) – Background color of the unselected option in drop down menu.

  • +
  • scroll_bar_active_color (tuple of 3 floats.) – Color of the scrollbar when in active use.

  • +
  • scroll_bar_inactive_color (tuple of 3 floats.) – Color of the scrollbar when inactive.

  • +
  • reverse_scrolling ({True, False}) – If True, scrolling up will move the list of files down.

  • +
  • font_size (int) – The font size of selected text in pixels.

  • +
  • line_spacing (float) – Distance between drop down menu’s items in pixels.

  • +
+
+
+
+ +
+
+append_item(*items)[source]#
+

Append additional options to the menu.

+
+
Parameters:
+

items (n-d list, n-d tuple, Number or str) – Additional options.

+
+
+
+ +
+
+left_button_dragged(i_ren, _obj, _sub_component)[source]#
+
+ +
+
+left_button_pressed(i_ren, _obj, _sub_component)[source]#
+
+ +
+
+menu_toggle_callback(i_ren, _vtkactor, _combobox)[source]#
+

Toggle visibility of drop down menu list.

+
+
Parameters:
+
    +
  • i_ren (CustomInteractorStyle) –

  • +
  • vtkactor (vtkActor) – The picked actor

  • +
  • combobox (ComboBox2D) –

  • +
+
+
+
+ +
+
+resize(size)[source]#
+

Resize ComboBox2D.

+
+
Parameters:
+

size ((int, int)) – ComboBox size(width, height) in pixels.

+
+
+
+ +
+
+select_option_callback(i_ren, _obj, listboxitem)[source]#
+

Select the appropriate option

+
+
Parameters:
+
    +
  • i_ren (CustomInteractorStyle) –

  • +
  • obj (vtkActor) – The picked actor

  • +
  • listboxitem (ListBoxItem2D) –

  • +
+
+
+
+ +
+
+property selected_text#
+
+ +
+
+property selected_text_index#
+
+ +
+
+set_visibility(visibility)[source]#
+

Set visibility of this UI component.

+
+ +
+ +
+
+

ListBox2D#

+
+
+class fury.ui.elements.ListBox2D(values, position=(0, 0), size=(100, 300), multiselection=True, reverse_scrolling=False, font_size=20, line_spacing=1.4, text_color=(0.2, 0.2, 0.2), selected_color=(0.9, 0.6, 0.6), unselected_color=(0.6, 0.6, 0.6), scroll_bar_active_color=(0.6, 0.2, 0.2), scroll_bar_inactive_color=(0.9, 0.0, 0.0), background_opacity=1.0)[source]#
+

Bases: UI

+

UI component that allows the user to select items from a list.

+
+
+on_change#
+

Callback function for when the selected items have changed.

+
+
Type:
+

function

+
+
+
+ +
+
+__init__(values, position=(0, 0), size=(100, 300), multiselection=True, reverse_scrolling=False, font_size=20, line_spacing=1.4, text_color=(0.2, 0.2, 0.2), selected_color=(0.9, 0.6, 0.6), unselected_color=(0.6, 0.6, 0.6), scroll_bar_active_color=(0.6, 0.2, 0.2), scroll_bar_inactive_color=(0.9, 0.0, 0.0), background_opacity=1.0)[source]#
+

Init class instance.

+
+
Parameters:
+
    +
  • values (list of objects) – Values used to populate this listbox. Objects must be castable +to string.

  • +
  • position ((float, float)) – Absolute coordinates (x, y) of the lower-left corner of this +UI component.

  • +
  • size ((int, int)) – Width and height in pixels of this UI component.

  • +
  • multiselection ({True, False}) – Whether multiple values can be selected at once.

  • +
  • reverse_scrolling ({True, False}) – If True, scrolling up will move the list of files down.

  • +
  • font_size (int) – The font size in pixels.

  • +
  • line_spacing (float) – Distance between listbox’s items in pixels.

  • +
  • text_color (tuple of 3 floats) –

  • +
  • selected_color (tuple of 3 floats) –

  • +
  • unselected_color (tuple of 3 floats) –

  • +
  • scroll_bar_active_color (tuple of 3 floats) –

  • +
  • scroll_bar_inactive_color (tuple of 3 floats) –

  • +
  • background_opacity (float) –

  • +
+
+
+
+ +
+
+clear_selection()[source]#
+
+ +
+
+down_button_callback(i_ren, _obj, _list_box)[source]#
+

Pressing down button scrolls down in the combo box.

+
+
Parameters:
+
    +
  • i_ren (CustomInteractorStyle) –

  • +
  • obj (vtkActor) – The picked actor

  • +
  • _list_box (ListBox2D) –

  • +
+
+
+
+ +
+
+resize(size)[source]#
+
+ +
+
+scroll_click_callback(i_ren, _obj, _rect_obj)[source]#
+

Callback to change the color of the bar when it is clicked.

+
+
Parameters:
+
    +
  • i_ren (CustomInteractorStyle) –

  • +
  • obj (vtkActor) – The picked actor

  • +
  • _rect_obj (Rectangle2D) –

  • +
+
+
+
+ +
+
+scroll_drag_callback(i_ren, _obj, _rect_obj)[source]#
+

Drag scroll bar in the combo box.

+
+
Parameters:
+
    +
  • i_ren (CustomInteractorStyle) –

  • +
  • obj (vtkActor) – The picked actor

  • +
  • rect_obj (Rectangle2D) –

  • +
+
+
+
+ +
+
+scroll_release_callback(i_ren, _obj, _rect_obj)[source]#
+

Callback to change the color of the bar when it is released.

+
+
Parameters:
+
    +
  • i_ren (CustomInteractorStyle) –

  • +
  • obj (vtkActor) – The picked actor

  • +
  • rect_obj (Rectangle2D) –

  • +
+
+
+
+ +
+
+select(item, multiselect=False, range_select=False)[source]#
+

Select the item.

+
+
Parameters:
+
    +
  • item (ListBoxItem2D's object) – Item to select.

  • +
  • multiselect ({True, False}) – If True and multiselection is allowed, the item is added to the +selection. +Otherwise, the selection will only contain the provided item unless +range_select is True.

  • +
  • range_select ({True, False}) – If True and multiselection is allowed, all items between the last +selected item and the current one will be added to the selection. +Otherwise, the selection will only contain the provided item unless +multi_select is True.

  • +
+
+
+
+ +
+
+up_button_callback(i_ren, _obj, _list_box)[source]#
+

Pressing up button scrolls up in the combo box.

+
+
Parameters:
+
    +
  • i_ren (CustomInteractorStyle) –

  • +
  • obj (vtkActor) – The picked actor

  • +
  • _list_box (ListBox2D) –

  • +
+
+
+
+ +
+
+update()[source]#
+

Refresh listbox’s content.

+
+ +
+
+update_scrollbar()[source]#
+

Change the scroll-bar height when the values +in the listbox change

+
+ +
+ +
+
+

ListBoxItem2D#

+
+
+class fury.ui.elements.ListBoxItem2D(list_box, size, text_color=(1.0, 0.0, 0.0), selected_color=(0.4, 0.4, 0.4), unselected_color=(0.9, 0.9, 0.9), background_opacity=1.0)[source]#
+

Bases: UI

+

The text displayed in a listbox.

+
+
+__init__(list_box, size, text_color=(1.0, 0.0, 0.0), selected_color=(0.4, 0.4, 0.4), unselected_color=(0.9, 0.9, 0.9), background_opacity=1.0)[source]#
+

Init ListBox Item instance.

+
+
Parameters:
+
    +
  • list_box (ListBox) – The ListBox reference this text belongs to.

  • +
  • size (tuple of 2 ints) – The size of the listbox item.

  • +
  • text_color (tuple of 3 floats) –

  • +
  • unselected_color (tuple of 3 floats) –

  • +
  • selected_color (tuple of 3 floats) –

  • +
  • background_opacity (float) –

  • +
+
+
+
+ +
+
+deselect()[source]#
+
+ +
+
+property element#
+
+ +
+
+left_button_clicked(i_ren, _obj, _list_box_item)[source]#
+

Handle left click for this UI element.

+
+
Parameters:
+
    +
  • i_ren (CustomInteractorStyle) –

  • +
  • obj (vtkActor) – The picked actor

  • +
  • _list_box_item (ListBoxItem2D) –

  • +
+
+
+
+ +
+
+resize(size)[source]#
+
+ +
+
+select()[source]#
+
+ +
+ +
+
+

FileMenu2D#

+
+
+class fury.ui.elements.FileMenu2D(directory_path, extensions=None, position=(0, 0), size=(100, 300), multiselection=True, reverse_scrolling=False, font_size=20, line_spacing=1.4)[source]#
+

Bases: UI

+

A menu to select files in the current folder.

+

Can go to new folder, previous folder and select multiple files.

+
+
+extensions#
+

To show all files, extensions=[“*”] or [“”] +List of extensions to be shown as files.

+
+
Type:
+

[‘extension1’, ‘extension2’, ….]

+
+
+
+ +
+
+listbox#
+

Container for the menu.

+
+
Type:
+
+
class:
+

‘ListBox2D’

+
+
+
+
+
+ +
+
+__init__(directory_path, extensions=None, position=(0, 0), size=(100, 300), multiselection=True, reverse_scrolling=False, font_size=20, line_spacing=1.4)[source]#
+

Init class instance.

+
+
Parameters:
+
    +
  • extensions (list(string)) – List of extensions to be shown as files.

  • +
  • directory_path (string) – Path of the directory where this dialog should open.

  • +
  • position ((float, float)) – Absolute coordinates (x, y) of the lower-left corner of this +UI component.

  • +
  • size ((int, int)) – Width and height in pixels of this UI component.

  • +
  • multiselection ({True, False}) – Whether multiple values can be selected at once.

  • +
  • reverse_scrolling ({True, False}) – If True, scrolling up will move the list of files down.

  • +
  • font_size (int) – The font size in pixels.

  • +
  • line_spacing (float) – Distance between listbox’s items in pixels.

  • +
+
+
+
+ +
+
+directory_click_callback(i_ren, _obj, listboxitem)[source]#
+

Handle the move into a directory if it has been clicked.

+
+
Parameters:
+
    +
  • i_ren (CustomInteractorStyle) –

  • +
  • obj (vtkActor) – The picked actor

  • +
  • listboxitem (ListBoxItem2D) –

  • +
+
+
+
+ +
+
+get_all_file_names()[source]#
+

Get file and directory names.

+
+
Returns:
+

all_file_names – List of all file and directory names as string.

+
+
Return type:
+

list((string, {“directory”, “file”}))

+
+
+
+ +
+
+get_directory_names()[source]#
+

Find names of all directories in the current_directory

+
+
Returns:
+

directory_names – List of all directory names as string.

+
+
Return type:
+

list(string)

+
+
+
+ +
+
+get_file_names()[source]#
+

Find names of all files in the current_directory

+
+
Returns:
+

file_names – List of all file names as string.

+
+
Return type:
+

list(string)

+
+
+
+ +
+
+resize(size)[source]#
+
+ +
+
+scroll_callback(i_ren, _obj, _filemenu_item)[source]#
+

Handle scroll and change the slot text colors.

+
+
Parameters:
+
    +
  • i_ren (CustomInteractorStyle) –

  • +
  • obj (vtkActor) – The picked actor

  • +
  • _filemenu_item (FileMenu2D) –

  • +
+
+
+
+ +
+
+set_slot_colors()[source]#
+

Set the text color of the slots based on the type of element +they show. Blue for directories and green for files.

+
+ +
+ +
+
+

DrawShape#

+
+
+class fury.ui.elements.DrawShape(shape_type, drawpanel=None, position=(0, 0))[source]#
+

Bases: UI

+

Create and Manage 2D Shapes.

+
+
+__init__(shape_type, drawpanel=None, position=(0, 0))[source]#
+

Init this UI element.

+
+
Parameters:
+
    +
  • shape_type (string) – Type of shape to be created.

  • +
  • drawpanel (DrawPanel, optional) – Reference to the main canvas on which it is drawn.

  • +
  • position ((float, float), optional) – (x, y) in pixels.

  • +
+
+
+
+ +
+
+cal_bounding_box()[source]#
+

Calculate the min, max position and the size of the bounding box.

+
+ +
+
+property center#
+
+ +
+
+clamp_position(center=None)[source]#
+

Clamp the given center according to the DrawPanel canvas.

+
+
Parameters:
+

center ((float, float)) – (x, y) in pixels.

+
+
Returns:
+

new_center – New center for the shape.

+
+
Return type:
+

ndarray(int)

+
+
+
+ +
+
+property is_selected#
+
+ +
+
+left_button_dragged(i_ren, _obj, shape)[source]#
+
+ +
+
+left_button_pressed(i_ren, _obj, shape)[source]#
+
+ +
+
+left_button_released(i_ren, _obj, shape)[source]#
+
+ +
+
+remove()[source]#
+

Remove the Shape and all related actors.

+
+ +
+
+resize(size)[source]#
+

Resize the UI.

+
+ +
+
+rotate(angle)[source]#
+

Rotate the vertices of the UI component using specific angle.

+
+
Parameters:
+

angle (float) – Value by which the vertices are rotated in radian.

+
+
+
+ +
+
+selection_change()[source]#
+
+ +
+
+update_shape_position(center_position)[source]#
+

Update the center position on the canvas.

+
+
Parameters:
+

center_position ((float, float)) – Absolute pixel coordinates (x, y).

+
+
+
+ +
+ +
+
+

DrawPanel#

+
+
+class fury.ui.elements.DrawPanel(size=(400, 400), position=(0, 0), is_draggable=False)[source]#
+

Bases: UI

+

The main Canvas(Panel2D) on which everything would be drawn.

+
+
+__init__(size=(400, 400), position=(0, 0), is_draggable=False)[source]#
+

Init this UI element.

+
+
Parameters:
+
    +
  • size ((int, int), optional) – Width and height in pixels of this UI component.

  • +
  • position ((float, float), optional) – (x, y) in pixels.

  • +
  • is_draggable (bool, optional) – Whether the background canvas will be draggble or not.

  • +
+
+
+
+ +
+
+cal_min_boundary_distance(position)[source]#
+

Calculate minimum distance between the current position and canvas boundary.

+
+
Parameters:
+

position ((float,float)) – current position of the shape.

+
+
Returns:
+

Minimum distance from the boundary.

+
+
Return type:
+

float

+
+
+
+ +
+
+clamp_mouse_position(mouse_position)[source]#
+

Restrict the mouse position to the canvas boundary.

+
+
Parameters:
+

mouse_position ((float,float)) – Current mouse position.

+
+
Returns:
+

New clipped position.

+
+
Return type:
+

list(float)

+
+
+
+ +
+
+property current_mode#
+
+ +
+
+draw_shape(shape_type, current_position)[source]#
+

Draw the required shape at the given position.

+
+
Parameters:
+
    +
  • shape_type (string) – Type of shape - line, quad, circle.

  • +
  • current_position ((float,float)) – Lower left corner position for the shape.

  • +
+
+
+
+ +
+
+handle_mouse_click(position)[source]#
+
+ +
+
+handle_mouse_drag(position)[source]#
+
+ +
+
+left_button_dragged(i_ren, _obj, element)[source]#
+
+ +
+
+left_button_pressed(i_ren, _obj, element)[source]#
+
+ +
+
+resize(size)[source]#
+

Resize the UI.

+
+ +
+
+resize_shape(current_position)[source]#
+

Resize the shape.

+
+
Parameters:
+

current_position ((float,float)) – Lower left corner position for the shape.

+
+
+
+ +
+
+show_rotation_slider()[source]#
+

Display the RingSlider2D to allow rotation of shape from the center.

+
+ +
+
+update_button_icons(current_mode)[source]#
+

Update the button icon.

+
+
Parameters:
+

current_mode (string) – Current mode of the UI.

+
+
+
+ +
+
+update_shape_selection(selected_shape)[source]#
+
+ +
+ +
+
+

PlaybackPanel#

+
+
+class fury.ui.elements.PlaybackPanel(loop=False, position=(0, 0), width=None)[source]#
+

Bases: UI

+

A playback controller that can do essential functionalities. +such as play, pause, stop, and seek.

+
+
+__init__(loop=False, position=(0, 0), width=None)[source]#
+

Init scene.

+
+
Parameters:
+

position ((float, float)) – Absolute coordinates (x, y) of the lower-left corner of this +UI component.

+
+
+
+ +
+
+property current_time#
+

Get current time of the progress slider.

+
+
Returns:
+

Progress slider current value.

+
+
Return type:
+

float

+
+
+
+ +
+
+property current_time_str#
+

Returns current time as a string.

+
+
Returns:
+

Current time formatted as a string in the form:HH:MM:SS.

+
+
Return type:
+

str

+
+
+
+ +
+
+property final_time#
+

Set final progress slider time value.

+
+
Returns:
+

Final time for the progress slider.

+
+
Return type:
+

float

+
+
+
+ +
+
+hide()[source]#
+
+ +
+
+loop()[source]#
+

Set repeating mode to loop.

+
+ +
+
+pause()[source]#
+

Pause the playback

+
+ +
+
+play()[source]#
+

Play the playback

+
+ +
+
+play_once()[source]#
+

Set repeating mode to repeat once.

+
+ +
+
+show()[source]#
+
+ +
+
+property speed#
+

Returns current speed.

+
+
Returns:
+

Current time formatted as a string in the form:HH:MM:SS.

+
+
Return type:
+

str

+
+
+
+ +
+
+stop()[source]#
+

Stop the playback

+
+ +
+
+property width#
+

Return the width of the PlaybackPanel

+
+
Returns:
+

The width of the PlaybackPanel.

+
+
Return type:
+

float

+
+
+
+ +
+ +
+
+

Card2D#

+
+
+class fury.ui.elements.Card2D(image_path, body_text='', draggable=True, title_text='', padding=10, position=(0, 0), size=(400, 400), image_scale=0.5, bg_color=(0.5, 0.5, 0.5), bg_opacity=1, title_color=(0.0, 0.0, 0.0), body_color=(0.0, 0.0, 0.0), border_color=(1.0, 1.0, 1.0), border_width=0, maintain_aspect=False)[source]#
+

Bases: UI

+

Card element to show image and related text

+
+
+image#
+

Renders the image on the card.

+
+
Type:
+
+
class:
+

‘ImageContainer2D’

+
+
+
+
+
+ +
+
+title_box#
+

Displays the title on card.

+
+
Type:
+
+
class:
+

‘TextBlock2D’

+
+
+
+
+
+ +
+
+body_box#
+

Displays the body text.

+
+
Type:
+
+
class:
+

‘TextBLock2D’

+
+
+
+
+
+ +
+
+__init__(image_path, body_text='', draggable=True, title_text='', padding=10, position=(0, 0), size=(400, 400), image_scale=0.5, bg_color=(0.5, 0.5, 0.5), bg_opacity=1, title_color=(0.0, 0.0, 0.0), body_color=(0.0, 0.0, 0.0), border_color=(1.0, 1.0, 1.0), border_width=0, maintain_aspect=False)[source]#
+
+
Parameters:
+
    +
  • image_path (str) – Path of the image, supports png and jpg/jpeg images

  • +
  • body_text (str, optional) – Card body text

  • +
  • draggable (Bool, optional) – If the card should be draggable

  • +
  • title_text (str, optional) – Card title text

  • +
  • padding (int, optional) – Padding between image, title, body

  • +
  • position ((float, float), optional) – Absolute coordinates (x, y) of the lower-left corner of the +UI component

  • +
  • size ((int, int), optional) – Width and height of the pixels of this UI component.

  • +
  • image_scale (float, optional) – fraction of size taken by the image (between 0 , 1)

  • +
  • bg_color ((float, float, float), optional) – Background color of card

  • +
  • bg_opacity (float, optional) – Background opacity

  • +
  • title_color ((float, float, float), optional) – Title text color

  • +
  • body_color ((float, float, float), optional) – Body text color

  • +
  • border_color ((float, float, float), optional) – Border color

  • +
  • border_width (int, optional) – Width of the border

  • +
  • maintain_aspect (bool, optional) – If the image should be scaled to maintain aspect ratio

  • +
+
+
+
+ +
+
+property body#
+

Returns the body text of the card.

+
+ +
+
+property color#
+

Returns the background color of card.

+
+ +
+
+left_button_dragged(i_ren, _obj, _sub_component)[source]#
+
+ +
+
+left_button_pressed(i_ren, _obj, _sub_component)[source]#
+
+ +
+
+resize(size)[source]#
+

Resize Card2D.

+
+
Parameters:
+

size ((int, int)) – Card2D size(width, height) in pixels.

+
+
+
+ +
+
+property title#
+

Returns the title text of the card

+
+ +
+ +
+
+

SpinBox#

+
+
+class fury.ui.elements.SpinBox(position=(350, 400), size=(300, 100), padding=10, panel_color=(1, 1, 1), min_val=0, max_val=100, initial_val=50, step=1, max_column=10, max_line=2)[source]#
+

Bases: UI

+

SpinBox UI.

+
+
+__init__(position=(350, 400), size=(300, 100), padding=10, panel_color=(1, 1, 1), min_val=0, max_val=100, initial_val=50, step=1, max_column=10, max_line=2)[source]#
+

Init this UI element.

+
+
Parameters:
+
    +
  • position ((int, int), optional) – Absolute coordinates (x, y) of the lower-left corner of this +UI component.

  • +
  • size ((int, int), optional) – Width and height in pixels of this UI component.

  • +
  • padding (int, optional) – Distance between TextBox and Buttons.

  • +
  • panel_color ((float, float, float), optional) – Panel color of SpinBoxUI.

  • +
  • min_val (int, optional) – Minimum value of SpinBoxUI.

  • +
  • max_val (int, optional) – Maximum value of SpinBoxUI.

  • +
  • initial_val (int, optional) – Initial value of SpinBoxUI.

  • +
  • step (int, optional) – Step value of SpinBoxUI.

  • +
  • max_column (int, optional) – Max number of characters in a line.

  • +
  • max_line (int, optional) – Max number of lines in the textbox.

  • +
+
+
+
+ +
+
+decrement()[source]#
+

Decrement the current value by the step.

+
+ +
+
+decrement_callback(i_ren, _obj, _button)[source]#
+
+ +
+
+increment()[source]#
+

Increment the current value by the step.

+
+ +
+
+increment_callback(i_ren, _obj, _button)[source]#
+
+ +
+
+resize(size)[source]#
+

Resize SpinBox.

+
+
Parameters:
+

size ((float, float)) – SpinBox size(width, height) in pixels.

+
+
+
+ +
+
+textbox_update_value(textbox)[source]#
+
+ +
+
+validate_value(value)[source]#
+

Validate and convert the given value into integer.

+
+
Parameters:
+

value (str) – Input value received from the textbox.

+
+
Returns:
+

If valid return converted integer else the previous value.

+
+
Return type:
+

int

+
+
+
+ +
+
+property value#
+
+ +
+ +
+
+

clip_overflow#

+
+
+fury.ui.helpers.clip_overflow(textblock, width, side='right')[source]#
+

Clips overflowing text of TextBlock2D with respect to width.

+
+
Parameters:
+
    +
  • textblock (TextBlock2D) – The textblock object whose text needs to be clipped.

  • +
  • width (int) – Required width of the clipped text.

  • +
  • side (str, optional) – Clips the overflowing text according to side. +It takes values “left” or “right”.

  • +
+
+
Returns:
+

clipped text – Clipped version of the text.

+
+
Return type:
+

str

+
+
+
+ +
+
+

wrap_overflow#

+
+
+fury.ui.helpers.wrap_overflow(textblock, wrap_width, side='right')[source]#
+

Wraps overflowing text of TextBlock2D with respect to width.

+
+
Parameters:
+
    +
  • textblock (TextBlock2D) – The textblock object whose text needs to be wrapped.

  • +
  • wrap_width (int) – Required width of the wrapped text.

  • +
  • side (str, optional) – Clips the overflowing text according to side. +It takes values “left” or “right”.

  • +
+
+
Returns:
+

wrapped text – Wrapped version of the text.

+
+
Return type:
+

str

+
+
+
+ +
+
+

check_overflow#

+
+
+fury.ui.helpers.check_overflow(textblock, width, overflow_postfix='', side='right')[source]#
+

Checks if the text is overflowing.

+
+
Parameters:
+
    +
  • textblock (TextBlock2D) – The textblock object whose text is to be checked.

  • +
  • width (int) – Required width of the text.

  • +
  • overflow_postfix (str, optional) – Postfix to be added to the text if it is overflowing.

  • +
+
+
Returns:
+

mid_ptr – Overflow index of the text.

+
+
Return type:
+

int

+
+
+
+ +
+
+

cal_bounding_box_2d#

+
+
+fury.ui.helpers.cal_bounding_box_2d(vertices)[source]#
+

Calculate the min, max position and the size of the bounding box.

+
+
Parameters:
+

vertices (ndarray) – vertices of the actors.

+
+
+
+ +
+
+

rotate_2d#

+
+
+fury.ui.helpers.rotate_2d(vertices, angle)[source]#
+

Rotate the given vertices by an angle.

+
+
Parameters:
+
    +
  • vertices (ndarray) – vertices of the actors.

  • +
  • angle (float) – Value by which the vertices are rotated in radian.

  • +
+
+
+
+ +
+
+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ +
+ On this page +
+ +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/reference/fury.utils.html b/v0.10.x/reference/fury.utils.html new file mode 100644 index 000000000..5cb48e4ff --- /dev/null +++ b/v0.10.x/reference/fury.utils.html @@ -0,0 +1,3057 @@ + + + + + + + + utils — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

utils#

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

remove_observer_from_actor(actor, id)

Remove the observer with the given id from the actor.

set_input(vtk_object, inp)

Set Generic input function which takes into account VTK 5 or 6.

numpy_to_vtk_points(points)

Convert Numpy points array to a vtk points array.

numpy_to_vtk_colors(colors)

Convert Numpy color array to a vtk color array.

numpy_to_vtk_cells(data[, is_coords])

Convert numpy array to a vtk cell array.

numpy_to_vtk_image_data(array[, spacing, ...])

Convert numpy array to a vtk image data.

map_coordinates_3d_4d(input_array, indices)

Evaluate input_array at the given indices using trilinear interpolation.

lines_to_vtk_polydata(lines[, colors])

Create a vtkPolyData with lines and colors.

get_polydata_lines(line_polydata)

Convert vtk polydata to a list of lines ndarrays.

get_polydata_triangles(polydata)

Get triangles (ndarrays Nx3 int) from a vtk polydata.

get_polydata_vertices(polydata)

Get vertices (ndarrays Nx3 int) from a vtk polydata.

get_polydata_tcoord(polydata)

Get texture coordinates (ndarrays Nx2 float) from a vtk polydata.

get_polydata_normals(polydata)

Get vertices normal (ndarrays Nx3 int) from a vtk polydata.

get_polydata_tangents(polydata)

Get vertices tangent (ndarrays Nx3 int) from a vtk polydata.

get_polydata_colors(polydata)

Get points color (ndarrays Nx3 int) from a vtk polydata.

get_polydata_field(polydata, field_name[, ...])

Get a field from a vtk polydata.

add_polydata_numeric_field(polydata, ...[, ...])

Add a field to a vtk polydata.

set_polydata_primitives_count(polydata, ...)

Add primitives count to polydata.

get_polydata_primitives_count(polydata)

Get primitives count from actor's polydata.

primitives_count_to_actor(actor, ...)

Add primitives count to actor's polydata.

primitives_count_from_actor(actor)

Get primitives count from actor's polydata.

set_polydata_triangles(polydata, triangles)

Set polydata triangles with a numpy array (ndarrays Nx3 int).

set_polydata_vertices(polydata, vertices)

Set polydata vertices with a numpy array (ndarrays Nx3 int).

set_polydata_normals(polydata, normals)

Set polydata normals with a numpy array (ndarrays Nx3 int).

set_polydata_tangents(polydata, tangents)

Set polydata tangents with a numpy array (ndarrays Nx3 int).

set_polydata_colors(polydata, colors[, ...])

Set polydata colors with a numpy array (ndarrays Nx3 int).

set_polydata_tcoords(polydata, tcoords)

Set polydata texture coordinates with a numpy array (ndarrays Nx2 float).

update_polydata_normals(polydata)

Generate and update polydata normals.

get_polymapper_from_polydata(polydata)

Get vtkPolyDataMapper from a vtkPolyData.

get_actor_from_polymapper(poly_mapper)

Get actor from a vtkPolyDataMapper.

get_actor_from_polydata(polydata)

Get actor from a vtkPolyData.

get_actor_from_primitive(vertices, triangles)

Get actor from a vtkPolyData.

repeat_sources(centers, colors[, ...])

Transform a vtksource to glyph.

apply_affine_to_actor(act, affine)

Apply affine matrix affine to the actor act.

apply_affine(aff, pts)

Apply affine matrix aff to points pts.

asbytes(s)

vtk_matrix_to_numpy(matrix)

Convert VTK matrix to numpy array.

numpy_to_vtk_matrix(array)

Convert a numpy array to a VTK matrix.

get_bounding_box_sizes(actor)

Get the bounding box sizes of an actor.

get_grid_cells_position(shapes[, ...])

Construct a XY-grid based on the cells content shape.

shallow_copy(vtk_object)

Create a shallow copy of a given vtkObject object.

rotate(actor[, rotation])

Rotate actor around axis by angle.

rgb_to_vtk(data)

RGB or RGBA images to VTK arrays.

normalize_v3(arr)

Normalize a numpy array of 3 component vectors shape=(N, 3).

normals_from_v_f(vertices, faces)

Calculate normals from vertices and faces.

tangents_from_direction_of_anisotropy(...)

Calculate tangents from normals and a 3D vector representing the

triangle_order(vertices, faces)

Determine the winding order of a given set of vertices and a triangle.

change_vertices_order(triangle)

Change the vertices order of a given triangle.

fix_winding_order(vertices, triangles[, ...])

Return corrected triangles.

vertices_from_actor(actor[, as_vtk])

Access to vertices from actor.

colors_from_actor(actor[, array_name, as_vtk])

Access colors from actor which uses polydata.

normals_from_actor(act)

Access normals from actor which uses polydata.

tangents_from_actor(act)

Access tangents from actor which uses polydata.

array_from_actor(actor, array_name[, as_vtk])

Access array from actor which uses polydata.

normals_to_actor(act, normals)

Set normals to actor which uses polydata.

tangents_to_actor(act, tangents)

Set tangents to actor which uses polydata.

compute_bounds(actor)

Compute Bounds of actor.

update_actor(actor[, all_arrays])

Update actor.

get_bounds(actor)

Return Bounds of actor.

represent_actor_as_wireframe(actor)

Returns the actor wireframe.

update_surface_actor_colors(actor, colors)

Update colors of a surface actor.

color_check(pts_len[, colors])

Returns a VTK scalar array containing colors information for each one of the points according to the policy defined by the parameter colors.

is_ui(actor)

Method to check if the passed actor is UI or vtkProp3D

set_actor_origin(actor[, center])

Change the origin of an actor to a custom position.

+
+

remove_observer_from_actor#

+
+
+fury.utils.remove_observer_from_actor(actor, id)[source]#
+

Remove the observer with the given id from the actor.

+
+
Parameters:
+
    +
  • actor (vtkActor) –

  • +
  • id (int) – id of the observer to remove

  • +
+
+
+
+ +
+
+

set_input#

+
+
+fury.utils.set_input(vtk_object, inp)[source]#
+

Set Generic input function which takes into account VTK 5 or 6.

+
+
Parameters:
+
    +
  • vtk_object (vtk object) –

  • +
  • inp (vtkPolyData or vtkImageData or vtkAlgorithmOutput) –

  • +
+
+
Return type:
+

vtk_object

+
+
+

Notes

+
+
This can be used in the following way::

from fury.utils import set_input +poly_mapper = set_input(PolyDataMapper(), poly_data)

+
+
+
+ +
+
+

numpy_to_vtk_points#

+
+
+fury.utils.numpy_to_vtk_points(points)[source]#
+

Convert Numpy points array to a vtk points array.

+
+
Parameters:
+

points (ndarray) –

+
+
Returns:
+

vtk_points

+
+
Return type:
+

vtkPoints()

+
+
+
+ +
+
+

numpy_to_vtk_colors#

+
+
+fury.utils.numpy_to_vtk_colors(colors)[source]#
+

Convert Numpy color array to a vtk color array.

+
+
Parameters:
+

colors (ndarray) –

+
+
Returns:
+

vtk_colors

+
+
Return type:
+

vtkDataArray

+
+
+

Notes

+

If colors are not already in UNSIGNED_CHAR you may need to multiply by 255.

+

Examples

+
>>> import numpy as np
+>>> from fury.utils import numpy_to_vtk_colors
+>>> rgb_array = np.random.rand(100, 3)
+>>> vtk_colors = numpy_to_vtk_colors(255 * rgb_array)
+
+
+
+ +
+
+

numpy_to_vtk_cells#

+
+
+fury.utils.numpy_to_vtk_cells(data, is_coords=True)[source]#
+

Convert numpy array to a vtk cell array.

+
+
Parameters:
+
    +
  • data (ndarray) – points coordinate or connectivity array (e.g triangles).

  • +
  • is_coords (ndarray) – Select the type of array. default: True.

  • +
+
+
Returns:
+

vtk_cell – connectivity + offset information

+
+
Return type:
+

vtkCellArray

+
+
+
+ +
+
+

numpy_to_vtk_image_data#

+
+
+fury.utils.numpy_to_vtk_image_data(array, spacing=(1.0, 1.0, 1.0), origin=(0.0, 0.0, 0.0), deep=True)[source]#
+

Convert numpy array to a vtk image data.

+
+
Parameters:
+
    +
  • array (ndarray) – pixel coordinate and colors values.

  • +
  • spacing ((float, float, float) (optional)) – sets the size of voxel (unit of space in each direction x,y,z)

  • +
  • origin ((float, float, float) (optional)) – sets the origin at the given point

  • +
  • deep (bool (optional)) – decides the type of copy(ie. deep or shallow)

  • +
+
+
Returns:
+

vtk_image

+
+
Return type:
+

vtkImageData

+
+
+
+ +
+
+

map_coordinates_3d_4d#

+
+
+fury.utils.map_coordinates_3d_4d(input_array, indices)[source]#
+

Evaluate input_array at the given indices using trilinear interpolation.

+
+
Parameters:
+
    +
  • input_array (ndarray,) – 3D or 4D array

  • +
  • indices (ndarray) –

  • +
+
+
Returns:
+

output – 1D or 2D array

+
+
Return type:
+

ndarray

+
+
+
+ +
+
+

lines_to_vtk_polydata#

+
+
+fury.utils.lines_to_vtk_polydata(lines, colors=None)[source]#
+

Create a vtkPolyData with lines and colors.

+
+
Parameters:
+
    +
  • lines (list) – list of N curves represented as 2D ndarrays

  • +
  • colors (array (N, 3), list of arrays, tuple (3,), array (K,)) – If None or False, a standard orientation colormap is used for every +line. +If one tuple of color is used. Then all streamlines will have the same +colour. +If an array (N, 3) is given, where N is equal to the number of lines. +Then every line is coloured with a different RGB color. +If a list of RGB arrays is given then every point of every line takes +a different color. +If an array (K, 3) is given, where K is the number of points of all +lines then every point is colored with a different RGB color. +If an array (K,) is given, where K is the number of points of all +lines then these are considered as the values to be used by the +colormap. +If an array (L,) is given, where L is the number of streamlines then +these are considered as the values to be used by the colormap per +streamline. +If an array (X, Y, Z) or (X, Y, Z, 3) is given then the values for the +colormap are interpolated automatically using trilinear interpolation.

  • +
+
+
Returns:
+

    +
  • poly_data (vtkPolyData)

  • +
  • color_is_scalar (bool, true if the color array is a single scalar) – Scalar array could be used with a colormap lut +None if no color was used

  • +
+

+
+
+
+ +
+
+

get_polydata_lines#

+
+
+fury.utils.get_polydata_lines(line_polydata)[source]#
+

Convert vtk polydata to a list of lines ndarrays.

+
+
Parameters:
+

line_polydata (vtkPolyData) –

+
+
Returns:
+

lines – List of N curves represented as 2D ndarrays

+
+
Return type:
+

list

+
+
+
+ +
+
+

get_polydata_triangles#

+
+
+fury.utils.get_polydata_triangles(polydata)[source]#
+

Get triangles (ndarrays Nx3 int) from a vtk polydata.

+
+
Parameters:
+

polydata (vtkPolyData) –

+
+
Returns:
+

output – triangles

+
+
Return type:
+

array (N, 3)

+
+
+
+ +
+
+

get_polydata_vertices#

+
+
+fury.utils.get_polydata_vertices(polydata)[source]#
+

Get vertices (ndarrays Nx3 int) from a vtk polydata.

+
+
Parameters:
+

polydata (vtkPolyData) –

+
+
Returns:
+

output – points, represented as 2D ndarrays

+
+
Return type:
+

array (N, 3)

+
+
+
+ +
+
+

get_polydata_tcoord#

+
+
+fury.utils.get_polydata_tcoord(polydata)[source]#
+

Get texture coordinates (ndarrays Nx2 float) from a vtk polydata.

+
+
Parameters:
+

polydata (vtkPolyData) –

+
+
Returns:
+

output – Tcoords, represented as 2D ndarrays. None if there are no texture +in the vtk polydata.

+
+
Return type:
+

array (N, 2)

+
+
+
+ +
+
+

get_polydata_normals#

+
+
+fury.utils.get_polydata_normals(polydata)[source]#
+

Get vertices normal (ndarrays Nx3 int) from a vtk polydata.

+
+
Parameters:
+

polydata (vtkPolyData) –

+
+
Returns:
+

output – Normals, represented as 2D ndarrays (Nx3). None if there are no normals +in the vtk polydata.

+
+
Return type:
+

array (N, 3)

+
+
+
+ +
+
+

get_polydata_tangents#

+
+
+fury.utils.get_polydata_tangents(polydata)[source]#
+

Get vertices tangent (ndarrays Nx3 int) from a vtk polydata.

+
+
Parameters:
+

polydata (vtkPolyData) –

+
+
Returns:
+

output – Tangents, represented as 2D ndarrays (Nx3). None if there are no +tangents in the vtk polydata.

+
+
Return type:
+

array (N, 3)

+
+
+
+ +
+
+

get_polydata_colors#

+
+
+fury.utils.get_polydata_colors(polydata)[source]#
+

Get points color (ndarrays Nx3 int) from a vtk polydata.

+
+
Parameters:
+

polydata (vtkPolyData) –

+
+
Returns:
+

output – Colors. None if no normals in the vtk polydata.

+
+
Return type:
+

array (N, 3)

+
+
+
+ +
+
+

get_polydata_field#

+
+
+fury.utils.get_polydata_field(polydata, field_name, as_vtk=False)[source]#
+

Get a field from a vtk polydata.

+
+
Parameters:
+
    +
  • polydata (vtkPolyData) –

  • +
  • field_name (str) –

  • +
  • as_vtk (optional) – By default, ndarray is returned.

  • +
+
+
Returns:
+

output – Field data. The return type depends on the value of the as_vtk +parameter. None if the field is not found.

+
+
Return type:
+

ndarray or vtkDataArray

+
+
+
+ +
+
+

add_polydata_numeric_field#

+
+
+fury.utils.add_polydata_numeric_field(polydata, field_name, field_data, array_type=6)[source]#
+

Add a field to a vtk polydata.

+
+
Parameters:
+
    +
  • polydata (vtkPolyData) –

  • +
  • field_name (str) –

  • +
  • field_data (bool, int, float, double, numeric array or ndarray) –

  • +
  • array_type (vtkArrayType) –

  • +
+
+
+
+ +
+
+

set_polydata_primitives_count#

+
+
+fury.utils.set_polydata_primitives_count(polydata, primitives_count)[source]#
+

Add primitives count to polydata.

+
+
Parameters:
+
    +
  • polydata (vtkPolyData) –

  • +
  • primitives_count (int) –

  • +
+
+
+
+ +
+
+

get_polydata_primitives_count#

+
+
+fury.utils.get_polydata_primitives_count(polydata)[source]#
+

Get primitives count from actor’s polydata.

+
+
Parameters:
+

polydata (vtkPolyData) –

+
+
Returns:
+

primitives count

+
+
Return type:
+

int

+
+
+
+ +
+
+

primitives_count_to_actor#

+
+
+fury.utils.primitives_count_to_actor(actor, primitives_count)[source]#
+

Add primitives count to actor’s polydata.

+
+
Parameters:
+
    +
  • actor

  • +
  • primitives_count (int) –

  • +
+
+
+
+ +
+
+

primitives_count_from_actor#

+
+
+fury.utils.primitives_count_from_actor(actor)[source]#
+

Get primitives count from actor’s polydata.

+
+
Parameters:
+

actor

+
+
Returns:
+

primitives count

+
+
Return type:
+

int

+
+
+
+ +
+
+

set_polydata_triangles#

+
+
+fury.utils.set_polydata_triangles(polydata, triangles)[source]#
+

Set polydata triangles with a numpy array (ndarrays Nx3 int).

+
+
Parameters:
+
    +
  • polydata (vtkPolyData) –

  • +
  • triangles (array (N, 3)) – triangles, represented as 2D ndarrays (Nx3)

  • +
+
+
+
+ +
+
+

set_polydata_vertices#

+
+
+fury.utils.set_polydata_vertices(polydata, vertices)[source]#
+

Set polydata vertices with a numpy array (ndarrays Nx3 int).

+
+
Parameters:
+
    +
  • polydata (vtkPolyData) –

  • +
  • vertices (vertices, represented as 2D ndarrays (Nx3)) –

  • +
+
+
+
+ +
+
+

set_polydata_normals#

+
+
+fury.utils.set_polydata_normals(polydata, normals)[source]#
+

Set polydata normals with a numpy array (ndarrays Nx3 int).

+
+
Parameters:
+
    +
  • polydata (vtkPolyData) –

  • +
  • normals (normals, represented as 2D ndarrays (Nx3) (one per vertex)) –

  • +
+
+
+
+ +
+
+

set_polydata_tangents#

+
+
+fury.utils.set_polydata_tangents(polydata, tangents)[source]#
+

Set polydata tangents with a numpy array (ndarrays Nx3 int).

+
+
Parameters:
+
    +
  • polydata (vtkPolyData) –

  • +
  • tangents (tangents, represented as 2D ndarrays (Nx3) (one per vertex)) –

  • +
+
+
+
+ +
+
+

set_polydata_colors#

+
+
+fury.utils.set_polydata_colors(polydata, colors, array_name='colors')[source]#
+

Set polydata colors with a numpy array (ndarrays Nx3 int).

+
+
Parameters:
+
    +
  • polydata (vtkPolyData) –

  • +
  • colors (colors, represented as 2D ndarrays (Nx3)) – colors are uint8 [0,255] RGB for each points

  • +
+
+
+
+ +
+
+

set_polydata_tcoords#

+
+
+fury.utils.set_polydata_tcoords(polydata, tcoords)[source]#
+

Set polydata texture coordinates with a numpy array (ndarrays Nx2 float).

+
+
Parameters:
+
    +
  • polydata (vtkPolyData) –

  • +
  • tcoords (texture coordinates, represented as 2D ndarrays (Nx2)) – (one per vertex range (0, 1))

  • +
+
+
+
+ +
+
+

update_polydata_normals#

+
+
+fury.utils.update_polydata_normals(polydata)[source]#
+

Generate and update polydata normals.

+
+
Parameters:
+

polydata (vtkPolyData) –

+
+
+
+ +
+
+

get_polymapper_from_polydata#

+
+
+fury.utils.get_polymapper_from_polydata(polydata)[source]#
+

Get vtkPolyDataMapper from a vtkPolyData.

+
+
Parameters:
+

polydata (vtkPolyData) –

+
+
Returns:
+

poly_mapper

+
+
Return type:
+

vtkPolyDataMapper

+
+
+
+ +
+
+

get_actor_from_polymapper#

+
+
+fury.utils.get_actor_from_polymapper(poly_mapper)[source]#
+

Get actor from a vtkPolyDataMapper.

+
+
Parameters:
+

poly_mapper (vtkPolyDataMapper) –

+
+
Returns:
+

actor

+
+
Return type:
+

actor

+
+
+
+ +
+
+

get_actor_from_polydata#

+
+
+fury.utils.get_actor_from_polydata(polydata)[source]#
+

Get actor from a vtkPolyData.

+
+
Parameters:
+

polydata (vtkPolyData) –

+
+
Returns:
+

actor

+
+
Return type:
+

actor

+
+
+
+ +
+
+

get_actor_from_primitive#

+
+
+fury.utils.get_actor_from_primitive(vertices, triangles, colors=None, normals=None, backface_culling=True, prim_count=1)[source]#
+

Get actor from a vtkPolyData.

+
+
Parameters:
+
    +
  • vertices ((Mx3) ndarray) – XYZ coordinates of the object

  • +
  • triangles ((Nx3) ndarray) – Indices into vertices; forms triangular faces.

  • +
  • colors ((Nx3) or (Nx4) ndarray) – RGB or RGBA (for opacity) R, G, B and A should be at the range [0, 1] +N is equal to the number of vertices.

  • +
  • normals ((Nx3) ndarray) – normals, represented as 2D ndarrays (Nx3) (one per vertex)

  • +
  • backface_culling (bool) – culling of polygons based on orientation of normal with respect to +camera. If backface culling is True, polygons facing away from camera +are not drawn. Default: True

  • +
  • prim_count (int, optional) – primitives count to be associated with the actor

  • +
+
+
Returns:
+

actor

+
+
Return type:
+

actor

+
+
+
+ +
+
+

repeat_sources#

+
+
+fury.utils.repeat_sources(centers, colors, active_scalars=1.0, directions=None, source=None, vertices=None, faces=None, orientation=None)[source]#
+

Transform a vtksource to glyph.

+
+ +
+
+

apply_affine_to_actor#

+
+
+fury.utils.apply_affine_to_actor(act, affine)[source]#
+

Apply affine matrix affine to the actor act.

+
+
Parameters:
+
    +
  • act (Actor) –

  • +
  • affine ((4, 4) array-like) – Homogeneous affine, for 3D object.

  • +
+
+
Returns:
+

transformed_act

+
+
Return type:
+

Actor

+
+
+
+ +
+
+

apply_affine#

+
+
+fury.utils.apply_affine(aff, pts)[source]#
+

Apply affine matrix aff to points pts.

+

Returns result of application of aff to the right of pts. The +coordinate dimension of pts should be the last. +For the 3D case, aff will be shape (4,4) and pts will have final axis +length 3 - maybe it will just be N by 3. The return value is the +transformed points, in this case:: +res = np.dot(aff[:3,:3], pts.T) + aff[:3,3:4] +transformed_pts = res.T +This routine is more general than 3D, in that aff can have any shape +(N,N), and pts can have any shape, as long as the last dimension is for +the coordinates, and is therefore length N-1.

+
+
Parameters:
+
    +
  • aff ((N, N) array-like) – Homogeneous affine, for 3D points, will be 4 by 4. Contrary to first +appearance, the affine will be applied on the left of pts.

  • +
  • pts ((..., N-1) array-like) – Points, where the last dimension contains the coordinates of each +point. For 3D, the last dimension will be length 3.

  • +
+
+
Returns:
+

transformed_pts – transformed points

+
+
Return type:
+

(…, N-1) array

+
+
+

Notes

+

Copied from nibabel to remove dependency.

+

Examples

+
>>> aff = np.array([[0,2,0,10],[3,0,0,11],[0,0,4,12],[0,0,0,1]])
+>>> pts = np.array([[1,2,3],[2,3,4],[4,5,6],[6,7,8]])
+>>> apply_affine(aff, pts) 
+array([[14, 14, 24],
+       [16, 17, 28],
+       [20, 23, 36],
+       [24, 29, 44]]...)
+Just to show that in the simple 3D case, it is equivalent to:
+>>> (np.dot(aff[:3,:3], pts.T) + aff[:3,3:4]).T 
+array([[14, 14, 24],
+       [16, 17, 28],
+       [20, 23, 36],
+       [24, 29, 44]]...)
+But `pts` can be a more complicated shape:
+>>> pts = pts.reshape((2,2,3))
+>>> apply_affine(aff, pts) 
+array([[[14, 14, 24],
+        [16, 17, 28]],
+
+       [[20, 23, 36],
+        [24, 29, 44]]]...)
+
+
+
+ +
+
+

asbytes#

+
+
+fury.utils.asbytes(s)[source]#
+
+ +
+
+

vtk_matrix_to_numpy#

+
+
+fury.utils.vtk_matrix_to_numpy(matrix)[source]#
+

Convert VTK matrix to numpy array.

+
+ +
+
+

numpy_to_vtk_matrix#

+
+
+fury.utils.numpy_to_vtk_matrix(array)[source]#
+

Convert a numpy array to a VTK matrix.

+
+ +
+
+

get_bounding_box_sizes#

+
+
+fury.utils.get_bounding_box_sizes(actor)[source]#
+

Get the bounding box sizes of an actor.

+
+ +
+
+

get_grid_cells_position#

+
+
+fury.utils.get_grid_cells_position(shapes, aspect_ratio=1.7777777777777777, dim=None)[source]#
+

Construct a XY-grid based on the cells content shape.

+

This function generates the coordinates of every grid cell. The width and +height of every cell correspond to the largest width and the largest height +respectively. The grid dimensions will automatically be adjusted to respect +the given aspect ratio unless they are explicitly specified.

+

The grid follows a row-major order with the top left corner being at +coordinates (0,0,0) and the bottom right corner being at coordinates +(nb_cols*cell_width, -nb_rows*cell_height, 0). Note that the X increases +while the Y decreases.

+
+
Parameters:
+
    +
  • shapes (list of tuple of int) – The shape (width, height) of every cell content.

  • +
  • aspect_ratio (float (optional)) – Aspect ratio of the grid (width/height). Default: 16:9.

  • +
  • dim (tuple of int (optional)) – Dimension (nb_rows, nb_cols) of the grid, if provided.

  • +
+
+
Returns:
+

3D coordinates of every grid cell.

+
+
Return type:
+

ndarray

+
+
+
+ +
+
+

shallow_copy#

+
+
+fury.utils.shallow_copy(vtk_object)[source]#
+

Create a shallow copy of a given vtkObject object.

+
+ +
+
+

rotate#

+
+
+fury.utils.rotate(actor, rotation=(90, 1, 0, 0))[source]#
+

Rotate actor around axis by angle.

+
+
Parameters:
+
    +
  • actor (actor or other prop) –

  • +
  • rotation (tuple) – Rotate with angle w around axis x, y, z. Needs to be provided +in the form (w, x, y, z).

  • +
+
+
+
+ +
+
+

rgb_to_vtk#

+
+
+fury.utils.rgb_to_vtk(data)[source]#
+

RGB or RGBA images to VTK arrays.

+
+
Parameters:
+

data (ndarray) – Shape can be (X, Y, 3) or (X, Y, 4)

+
+
Return type:
+

vtkImageData

+
+
+
+ +
+
+

normalize_v3#

+
+
+fury.utils.normalize_v3(arr)[source]#
+

Normalize a numpy array of 3 component vectors shape=(N, 3).

+
+
Parameters:
+

array (ndarray) – Shape (N, 3)

+
+
Return type:
+

norm_array

+
+
+
+ +
+
+

normals_from_v_f#

+
+
+fury.utils.normals_from_v_f(vertices, faces)[source]#
+

Calculate normals from vertices and faces.

+
+
Parameters:
+
    +
  • verices (ndarray) –

  • +
  • faces (ndarray) –

  • +
+
+
Returns:
+

normals – Shape same as vertices

+
+
Return type:
+

ndarray

+
+
+
+ +
+
+

tangents_from_direction_of_anisotropy#

+
+
+fury.utils.tangents_from_direction_of_anisotropy(normals, direction)[source]#
+
+
Calculate tangents from normals and a 3D vector representing the

direction of anisotropy.

+
+
+
+
Parameters:
+
    +
  • normals (normals, represented as 2D ndarrays (Nx3) (one per vertex)) –

  • +
  • direction (tuple (3,) or array (3,)) –

  • +
+
+
Returns:
+

output – Tangents, represented as 2D ndarrays (Nx3).

+
+
Return type:
+

array (N, 3)

+
+
+
+ +
+
+

triangle_order#

+
+
+fury.utils.triangle_order(vertices, faces)[source]#
+

Determine the winding order of a given set of vertices and a triangle.

+
+
Parameters:
+
    +
  • vertices (ndarray) – array of vertices making up a shape

  • +
  • faces (ndarray) – array of triangles

  • +
+
+
Returns:
+

order – If the order is counter clockwise (CCW), returns True. +Otherwise, returns False.

+
+
Return type:
+

int

+
+
+
+ +
+
+

change_vertices_order#

+
+
+fury.utils.change_vertices_order(triangle)[source]#
+

Change the vertices order of a given triangle.

+
+
Parameters:
+

triangle (ndarray, shape(1, 3)) – array of 3 vertices making up a triangle

+
+
Returns:
+

new_triangle – new array of vertices making up a triangle in the opposite winding +order of the given parameter

+
+
Return type:
+

ndarray, shape(1, 3)

+
+
+
+ +
+
+

fix_winding_order#

+
+
+fury.utils.fix_winding_order(vertices, triangles, clockwise=False)[source]#
+

Return corrected triangles.

+

Given an ordering of the triangle’s three vertices, a triangle can appear +to have a clockwise winding or counter-clockwise winding. +Clockwise means that the three vertices, in order, rotate clockwise around +the triangle’s center.

+
+
Parameters:
+
    +
  • vertices (ndarray) – array of vertices corresponding to a shape

  • +
  • triangles (ndarray) – array of triangles corresponding to a shape

  • +
  • clockwise (bool) – triangle order type: clockwise (default) or counter-clockwise.

  • +
+
+
Returns:
+

corrected_triangles – The corrected order of the vert parameter

+
+
Return type:
+

ndarray

+
+
+
+ +
+
+

vertices_from_actor#

+
+
+fury.utils.vertices_from_actor(actor, as_vtk=False)[source]#
+

Access to vertices from actor.

+
+
Parameters:
+
    +
  • actor (actor) –

  • +
  • as_vtk (bool, optional) – by default, ndarray is returned.

  • +
+
+
Returns:
+

vertices

+
+
Return type:
+

ndarray

+
+
+
+ +
+
+

colors_from_actor#

+
+
+fury.utils.colors_from_actor(actor, array_name='colors', as_vtk=False)[source]#
+

Access colors from actor which uses polydata.

+
+
Parameters:
+
    +
  • actor (actor) –

  • +
  • array_name (str) –

  • +
  • as_vtk (bool, optional) – by default, numpy array is returned.

  • +
+
+
Returns:
+

output – Colors

+
+
Return type:
+

array (N, 3)

+
+
+
+ +
+
+

normals_from_actor#

+
+
+fury.utils.normals_from_actor(act)[source]#
+

Access normals from actor which uses polydata.

+
+
Parameters:
+

act (actor) –

+
+
Returns:
+

output – Normals

+
+
Return type:
+

array (N, 3)

+
+
+
+ +
+
+

tangents_from_actor#

+
+
+fury.utils.tangents_from_actor(act)[source]#
+

Access tangents from actor which uses polydata.

+
+
Parameters:
+

act (actor) –

+
+
Returns:
+

output – Tangents

+
+
Return type:
+

array (N, 3)

+
+
+
+ +
+
+

array_from_actor#

+
+
+fury.utils.array_from_actor(actor, array_name, as_vtk=False)[source]#
+

Access array from actor which uses polydata.

+
+
Parameters:
+
    +
  • actor (actor) –

  • +
  • array_name (str) –

  • +
  • as_vtk_type (bool, optional) – by default, ndarray is returned.

  • +
+
+
Returns:
+

output

+
+
Return type:
+

array (N, 3)

+
+
+
+ +
+
+

normals_to_actor#

+
+
+fury.utils.normals_to_actor(act, normals)[source]#
+

Set normals to actor which uses polydata.

+
+
Parameters:
+
    +
  • act (actor) –

  • +
  • normals (normals, represented as 2D ndarrays (Nx3) (one per vertex)) –

  • +
+
+
Return type:
+

actor

+
+
+
+ +
+
+

tangents_to_actor#

+
+
+fury.utils.tangents_to_actor(act, tangents)[source]#
+

Set tangents to actor which uses polydata.

+
+
Parameters:
+
    +
  • act (actor) –

  • +
  • tangents (tangents, represented as 2D ndarrays (Nx3) (one per vertex)) –

  • +
+
+
+
+ +
+
+

compute_bounds#

+
+
+fury.utils.compute_bounds(actor)[source]#
+

Compute Bounds of actor.

+
+
Parameters:
+

actor (actor) –

+
+
+
+ +
+
+

update_actor#

+
+
+fury.utils.update_actor(actor, all_arrays=True)[source]#
+

Update actor.

+
+
Parameters:
+
    +
  • actor (actor) –

  • +
  • all_arrays (bool, optional) – if False, only vertices are updated +if True, all arrays associated to the actor are updated +Default: True

  • +
+
+
+
+ +
+
+

get_bounds#

+
+
+fury.utils.get_bounds(actor)[source]#
+

Return Bounds of actor.

+
+
Parameters:
+

actor (actor) –

+
+
Returns:
+

vertices

+
+
Return type:
+

ndarray

+
+
+
+ +
+
+

represent_actor_as_wireframe#

+
+
+fury.utils.represent_actor_as_wireframe(actor)[source]#
+

Returns the actor wireframe.

+
+
Parameters:
+

actor (actor) –

+
+
Returns:
+

actor

+
+
Return type:
+

actor

+
+
+
+ +
+
+

update_surface_actor_colors#

+
+
+fury.utils.update_surface_actor_colors(actor, colors)[source]#
+

Update colors of a surface actor.

+
+
Parameters:
+
    +
  • actor (surface actor) –

  • +
  • colors (ndarray of shape (N, 3) having colors. The colors should be in the) – range [0, 1].

  • +
+
+
+
+ +
+
+

color_check#

+
+
+fury.utils.color_check(pts_len, colors=None)[source]#
+

Returns a VTK scalar array containing colors information for each one of +the points according to the policy defined by the parameter colors.

+
+
Parameters:
+
    +
  • pts_len (int) – length of points ndarray

  • +
  • colors (None or tuple (3D or 4D) or array/ndarray (N, 3 or 4)) – If None a predefined color is used for each point. +If a tuple of color is used. Then all points will have the same color. +If an array (N, 3 or 4) is given, where N is equal to the number of +points. Then every point is colored with a different RGB(A) color.

  • +
+
+
Returns:
+

    +
  • color_array (vtkDataArray) – vtk scalar array with name ‘colors’.

  • +
  • global_opacity (float) – returns 1 if the colors array doesn’t contain opacity otherwise -1. +If colors array has 4 dimensions, it checks values of the fourth +dimension. If the value is the same, then assign it to global_opacity.

  • +
+

+
+
+
+ +
+
+

is_ui#

+
+
+fury.utils.is_ui(actor)[source]#
+

Method to check if the passed actor is UI or vtkProp3D

+
+
Parameters:
+

actor – actor that is to be checked

+
+
+
+ +
+
+

set_actor_origin#

+
+
+fury.utils.set_actor_origin(actor, center=None)[source]#
+

Change the origin of an actor to a custom position.

+
+
Parameters:
+
    +
  • actor (Actor) – The actor object to change origin for.

  • +
  • center (ndarray, optional, default: None) – The new center position. If None, the origin will be set to the mean +of the actor’s vertices.

  • +
+
+
+
+ +
+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ +
+ On this page +
+ +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/reference/fury.window.html b/v0.10.x/reference/fury.window.html new file mode 100644 index 000000000..90205a4c5 --- /dev/null +++ b/v0.10.x/reference/fury.window.html @@ -0,0 +1,2478 @@ + + + + + + + + window — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

window#

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Scene([background, skybox])

Your scene class.

ShowManager([scene, title, size, ...])

Class interface between the scene, the window and the interactor.

show(scene[, title, size, png_magnify, ...])

Show window with current scene.

record([scene, cam_pos, cam_focal, ...])

Record a video of your scene.

antialiasing(scene, win[, multi_samples, ...])

Enable anti-aliasing and ordered transparency.

snapshot(scene[, fname, size, offscreen, ...])

Save a snapshot of the scene in a file or in memory.

analyze_scene(scene)

analyze_snapshot(im[, bg_color, colors, ...])

Analyze snapshot from memory or file.

enable_stereo(renwin, stereo_type)

Enable the given stereo type on the RenderWindow.

gl_get_current_state(gl_state)

Returns a dict which describes the current state of the opengl context

gl_reset_blend(gl_state)

Redefines the state of the OpenGL context related with how the RGBA channels will be combined.

gl_enable_depth(gl_state)

Enable OpenGl depth test

gl_disable_depth(gl_state)

Disable OpenGl depth test

gl_enable_blend(gl_state)

Enable OpenGl blending

gl_disable_blend(gl_state)

This it will disable any gl behavior which has no function for opaque objects.

gl_set_additive_blending(gl_state)

Enable additive blending

gl_set_additive_blending_white_background(...)

Enable additive blending for a white background

gl_set_normal_blending(gl_state)

Enable normal blending

gl_set_multiplicative_blending(gl_state)

Enable multiplicative blending

gl_set_subtractive_blending(gl_state)

Enable subtractive blending

release_context(window)

Release the context of the window

+
+

Scene#

+
+
+class fury.window.Scene(background=(0, 0, 0), skybox=None)[source]#
+

Bases: vtkOpenGLRenderer

+

Your scene class.

+

This is an important object that is responsible for preparing objects +e.g. actors and volumes for rendering. This is a more pythonic version +of vtkRenderer providing simple methods for adding and removing actors +but also it provides access to all the functionality +available in vtkRenderer if necessary.

+
+
+__init__(background=(0, 0, 0), skybox=None)[source]#
+
+ +
+
+add(*actors)[source]#
+

Add an actor to the scene.

+
+ +
+
+azimuth(angle)[source]#
+

Rotate scene’s camera.

+

Rotate the camera about the view up vector centered at the focal +point. Note that the view up vector is whatever was set via SetViewUp, +and is not necessarily perpendicular to the direction of projection. +The result is a horizontal rotation of the camera.

+
+ +
+
+background(color)[source]#
+

Set a background color.

+
+ +
+
+camera()[source]#
+

Return the camera object.

+
+ +
+
+camera_direction()[source]#
+

Get camera direction.

+

Get the vector in the direction from the camera position to the +focal point. This is usually the opposite of the ViewPlaneNormal, the +vector perpendicular to the screen, unless the view is oblique.

+
+ +
+
+camera_info()[source]#
+

Return Camera information.

+
+ +
+
+clear()[source]#
+

Remove all actors from the scene.

+
+ +
+
+dolly(value)[source]#
+

Dolly In/Out scene’s camera.

+

Divide the camera’s distance from the focal point by the given +dolly value. Use a value greater than one to dolly-in toward the focal +point, and use a value less than one to dolly-out away from the focal +point.

+
+ +
+
+elevation(angle)[source]#
+

Elevate scene’s camera.

+

Rotate the camera about the cross product of the negative of the +direction of projection and the view up vector, using the focal point +as the center of rotation. The result is a vertical rotation of the +scene.

+
+ +
+
+fxaa_off()[source]#
+
+ +
+
+fxaa_on()[source]#
+
+ +
+
+get_camera()[source]#
+

Return Camera information: Position, Focal Point, View Up.

+
+ +
+
+property last_render_time#
+

Returns the last render time in seconds.

+
+ +
+
+pitch(angle)[source]#
+

Pitch scene’s camera.

+

Rotate the focal point about the cross product of the view up +vector and the direction of projection, using the camera’s position as +the center of rotation. The result is a vertical rotation of the +camera.

+
+ +
+
+projection(proj_type='perspective')[source]#
+

Decide between parallel or perspective projection.

+
+
Parameters:
+

proj_type (str) – Can be ‘parallel’ or ‘perspective’ (default).

+
+
+
+ +
+
+reset_camera()[source]#
+

Reset the camera to an automatic position given by the engine.

+
+ +
+
+reset_camera_tight(margin_factor=1.02)[source]#
+

Resets camera so the content fit tightly within the window.

+
+
Parameters:
+

margin_factor (float (optional)) – Margin added around the content. Default: 1.02.

+
+
+
+ +
+
+reset_clipping_range()[source]#
+

Reset the camera to an automatic position given by the engine.

+
+ +
+
+rm(*actors)[source]#
+

Remove more than once actors at once.

+
+ +
+
+rm_all()[source]#
+

Remove all actors from the scene.

+
+ +
+
+roll(angle)[source]#
+

Roll scene’s camera.

+

Rotate the camera about the direction of projection. This will +spin the camera about its axis.

+
+ +
+
+set_camera(position=None, focal_point=None, view_up=None)[source]#
+

Set up camera position / Focal Point / View Up.

+
+ +
+
+size()[source]#
+

Scene size.

+
+ +
+
+skybox(visible=True, gamma_correct=True)[source]#
+

Show or hide the skybox.

+
+
Parameters:
+
    +
  • visible (bool) – Whether to show the skybox or not.

  • +
  • gamma_correct (bool) – Whether to apply gamma correction to the skybox or not.

  • +
+
+
+
+ +
+
+yaw(angle)[source]#
+

Yaw scene’s camera.

+

Rotate the focal point about the view up vector, using the camera’s +position as the center of rotation. Note that the view up vector is +whatever was set via SetViewUp, and is not necessarily perpendicular +to the direction of projection. The result is a horizontal rotation of +the scene.

+
+ +
+
+zoom(value)[source]#
+

Rescale scene’s camera.

+

In perspective mode, decrease the view angle by the specified +factor. In parallel mode, decrease the parallel scale by the specified +factor. A value greater than 1 is a zoom-in, a value less than 1 is a +zoom-out.

+
+ +
+ +
+
+

ShowManager#

+
+
+class fury.window.ShowManager(scene=None, title='FURY', size=(300, 300), png_magnify=1, reset_camera=True, order_transparent=False, interactor_style='custom', stereo='off', multi_samples=8, max_peels=4, occlusion_ratio=0.0)[source]#
+

Bases: object

+

Class interface between the scene, the window and the interactor.

+
+
+__init__(scene=None, title='FURY', size=(300, 300), png_magnify=1, reset_camera=True, order_transparent=False, interactor_style='custom', stereo='off', multi_samples=8, max_peels=4, occlusion_ratio=0.0)[source]#
+

Manage the visualization pipeline.

+
+
Parameters:
+
    +
  • scene (Scene() or vtkRenderer()) – The scene that holds all the actors.

  • +
  • title (string) – A string for the window title bar.

  • +
  • size ((int, int)) – (width, height) of the window. Default is (300, 300).

  • +
  • png_magnify (int) – Number of times to magnify the screenshot. This can be used to save +high resolution screenshots when pressing ‘s’ inside the window.

  • +
  • reset_camera (bool) – Default is True. You can change this option to False if you want to +keep the camera as set before calling this function.

  • +
  • order_transparent (bool) – True is useful when you want to order transparent +actors according to their relative position to the camera. The +default option which is False will order the actors according to +the order of their addition to the Scene().

  • +
  • interactor_style (str or vtkInteractorStyle) – If str then if ‘trackball’ then vtkInteractorStyleTrackballCamera() +is used, if ‘image’ then vtkInteractorStyleImage() is used (no +rotation) or if ‘custom’ then CustomInteractorStyle is used. +Otherwise you can input your own interactor style.

  • +
  • stereo (string) –

    Set the stereo type. Default is ‘off’. Other types include:

    +
      +
    • ’opengl’: OpenGL frame-sequential stereo. Referred to as +‘CrystalEyes’ by VTK.

    • +
    • ’anaglyph’: For use with red/blue glasses. See VTK docs to +use different colors.

    • +
    • ’interlaced’: Line interlaced.

    • +
    • ’checkerboard’: Checkerboard interlaced.

    • +
    • ’left’: Left eye only.

    • +
    • ’right’: Right eye only.

    • +
    • ’horizontal’: Side-by-side.

    • +
    +

  • +
  • multi_samples (int) – Number of samples for anti-aliazing (Default 8). +For no anti-aliasing use 0.

  • +
  • max_peels (int) – Maximum number of peels for depth peeling (Default 4).

  • +
  • occlusion_ratio (float) – Occlusion ration for depth peeling (Default 0 - exact image).

  • +
+
+
+
+
+scene#
+
+
Type:
+

Scene() or vtkRenderer()

+
+
+
+ +
+
+iren#
+
+
Type:
+

vtkRenderWindowInteractor()

+
+
+
+ +
+
+style#
+
+
Type:
+

vtkInteractorStyle()

+
+
+
+ +
+
+window#
+
+
Type:
+

vtkRenderWindow()

+
+
+
+ +

Examples

+
>>> from fury import actor, window
+>>> scene = window.Scene()
+>>> scene.add(actor.axes())
+>>> showm = window.ShowManager(scene)
+>>> # showm.render()
+>>> # showm.start()
+
+
+
+ +
+
+add_animation(animation)[source]#
+

Add an Animation or a Timeline to the ShowManager.

+

Adding an Animation or a Timeline to the ShowManager ensures that it +gets added to the scene, gets updated and rendered without any extra +code.

+
+
Parameters:
+

animation (Animation or Timeline) – The Animation or Timeline to be added to the ShowManager.

+
+
+
+ +
+
+add_iren_callback(iren_callback, event='MouseMoveEvent')[source]#
+
+ +
+
+add_timer_callback(repeat, duration, timer_callback)[source]#
+
+ +
+
+add_window_callback(win_callback, event=33)[source]#
+

Add window callbacks.

+
+ +
+
+property animations#
+

Return a list of Animations that were added to the ShowManager.

+
+
Returns:
+

List of Animations.

+
+
Return type:
+

list[Animation]

+
+
+
+ +
+
+destroy_timer(timer_id)[source]#
+
+ +
+
+destroy_timers()[source]#
+
+ +
+
+exit()[source]#
+

Close window and terminate interactor.

+
+ +
+
+property frame_rate#
+

Returns number of frames per second.

+
+ +
+
+initialize()[source]#
+

Initialize interaction.

+
+ +
+
+is_done()[source]#
+

Check if show manager is done.

+
+ +
+
+lock()[source]#
+

Lock the render window.

+
+ +
+
+lock_current()[source]#
+

Lock the render window and acquire the current context and +check if the lock was successfully acquired.

+
+
Returns:
+

    +
  • successful (bool)

  • +
  • Returns if the lock was acquired.

  • +
+

+
+
+
+ +
+
+play_events(events)[source]#
+

Play recorded events of a past interaction.

+

The VTK events that happened during the recorded interaction will be +played back.

+
+
Parameters:
+

events (str) – Recorded events (one per line).

+
+
+
+ +
+
+play_events_from_file(filename)[source]#
+

Play recorded events of a past interaction.

+

The VTK events that happened during the recorded interaction will be +played back from filename.

+
+
Parameters:
+

filename (str) – Name of the file containing the recorded events (.log|.log.gz).

+
+
+
+ +
+
+record_events()[source]#
+

Record events during the interaction.

+

The recording is represented as a list of VTK events that happened +during the interaction. The recorded events are then returned.

+
+
Returns:
+

events – Recorded events (one per line).

+
+
Return type:
+

str

+
+
+

Notes

+

Since VTK only allows recording events to a file, we use a +temporary file from which we then read the events.

+
+ +
+
+record_events_to_file(filename='record.log')[source]#
+

Record events during the interaction.

+

The recording is represented as a list of VTK events +that happened during the interaction. The recording is +going to be saved into filename.

+
+
Parameters:
+

filename (str) – Name of the file that will contain the recording (.log|.log.gz).

+
+
+
+ +
+
+release_current()[source]#
+

Release the window context and lock of the render window.

+
+ +
+
+release_lock()[source]#
+

Release the lock of the render window.

+
+ +
+
+remove_animation(animation)[source]#
+

Remove an Animation or a Timeline from the ShowManager.

+

Animation will be removed from the Scene as well as from the +ShowManager.

+
+
Parameters:
+

animation (Animation or Timeline) – The Timeline to be removed.

+
+
+
+ +
+
+render()[source]#
+

Render only once.

+
+ +
+
+save_screenshot(fname, magnification=1, size=None, stereo=None)[source]#
+

Save a screenshot of the current window in the specified filename.

+
+
Parameters:
+
    +
  • fname (str or None) – File name where to save the screenshot.

  • +
  • magnification (int, optional) – Applies a magnification factor to the scene before taking the +screenshot which improves the quality. A value greater than 1 +increases the quality of the image. However, the output size will +be larger. For example, 200x200 image with magnification of 2 will +result in a 400x400 image. Default is 1.

  • +
  • size (tuple of 2 ints, optional) – Size of the output image in pixels. If None, the size of the scene +will be used. If magnification > 1, then the size will be +determined by the magnification factor. Default is None.

  • +
  • stereo (str, optional) –

    Set the type of stereo for the screenshot. Supported values are:

    +
    +
      +
    • ’opengl’: OpenGL frame-sequential stereo. Referred to as +‘CrystalEyes’ by VTK.

    • +
    • ’anaglyph’: For use with red/blue glasses. See VTK docs to +use different colors.

    • +
    • ’interlaced’: Line interlaced.

    • +
    • ’checkerboard’: Checkerboard interlaced.

    • +
    • ’left’: Left eye only.

    • +
    • ’right’: Right eye only.

    • +
    • ’horizontal’: Side-by-side.

    • +
    +
    +

  • +
+
+
+
+ +
+
+start(multithreaded=False, desired_fps=60)[source]#
+

Start interaction.

+
+
Parameters:
+
    +
  • multithreaded (bool) – Whether to use multithreading. (Default False)

  • +
  • desired_fps (int) – Desired frames per second when using multithreading is enabled. +(Default 60)

  • +
+
+
+
+ +
+
+property timelines#
+

Return a list of Timelines that were added to the ShowManager.

+
+
Returns:
+

List of Timelines.

+
+
Return type:
+

list[Timeline]

+
+
+
+ +
+
+wait()[source]#
+

Wait for thread to finish.

+
+ +
+ +
+
+

show#

+
+
+fury.window.show(scene, title='FURY', size=(300, 300), png_magnify=1, reset_camera=True, order_transparent=False, stereo='off', multi_samples=8, max_peels=4, occlusion_ratio=0.0)[source]#
+

Show window with current scene.

+
+
Parameters:
+
    +
  • scene (Scene() or vtkRenderer()) – The scene that holds all the actors.

  • +
  • title (string) – A string for the window title bar. Default is FURY and current version.

  • +
  • size ((int, int)) – (width, height) of the window. Default is (300, 300).

  • +
  • png_magnify (int) – Number of times to magnify the screenshot. Default is 1. This can be +used to save high resolution screenshots when pressing ‘s’ inside the +window.

  • +
  • reset_camera (bool) – Default is True. You can change this option to False if you want to +keep the camera as set before calling this function.

  • +
  • order_transparent (bool) – True is useful when you want to order transparent +actors according to their relative position to the camera. The default +option which is False will order the actors according to the order of +their addition to the Scene().

  • +
  • stereo (string) –

    Set the stereo type. Default is ‘off’. Other types include:

    +
      +
    • ’opengl’: OpenGL frame-sequential stereo. Referred to as +‘CrystalEyes’ by VTK.

    • +
    • ’anaglyph’: For use with red/blue glasses. See VTK docs to +use different colors.

    • +
    • ’interlaced’: Line interlaced.

    • +
    • ’checkerboard’: Checkerboard interlaced.

    • +
    • ’left’: Left eye only.

    • +
    • ’right’: Right eye only.

    • +
    • ’horizontal’: Side-by-side.

    • +
    +

  • +
  • multi_samples (int) – Number of samples for anti-aliazing (Default 8). +For no anti-aliasing use 0.

  • +
  • max_peels (int) – Maximum number of peels for depth peeling (Default 4).

  • +
  • occlusion_ratio (float) – Occlusion ration for depth peeling (Default 0 - exact image).

  • +
+
+
+

Examples

+
>>> import numpy as np
+>>> from fury import window, actor
+>>> r = window.Scene()
+>>> lines=[np.random.rand(10,3),np.random.rand(20,3)]
+>>> colors=np.array([[0.2,0.2,0.2],[0.8,0.8,0.8]])
+>>> c=actor.line(lines,colors)
+>>> r.add(c)
+>>> l=actor.label(text="Hello")
+>>> r.add(l)
+>>> #window.show(r)
+
+
+ +
+ +
+
+

record#

+
+
+fury.window.record(scene=None, cam_pos=None, cam_focal=None, cam_view=None, out_path=None, path_numbering=False, n_frames=1, az_ang=10, magnification=1, size=(300, 300), reset_camera=True, screen_clip=False, stereo='off', verbose=False)[source]#
+

Record a video of your scene.

+

Records a video as a series of .png files of your scene by rotating the +azimuth angle az_angle in every frame.

+
+
Parameters:
+
    +
  • scene (Scene() or vtkRenderer() object) – Scene instance

  • +
  • cam_pos (None or sequence (3,), optional) – Camera’s position. If None then default camera’s position is used.

  • +
  • cam_focal (None or sequence (3,), optional) – Camera’s focal point. If None then default camera’s focal point is +used.

  • +
  • cam_view (None or sequence (3,), optional) – Camera’s view up direction. If None then default camera’s view up +vector is used.

  • +
  • out_path (str, optional) – Output path for the frames. If None a default fury.png is created.

  • +
  • path_numbering (bool) – When recording it changes out_path to out_path + str(frame number)

  • +
  • n_frames (int, optional) – Number of frames to save, default 1

  • +
  • az_ang (float, optional) – Azimuthal angle of camera rotation.

  • +
  • magnification (int, optional) – How much to magnify the saved frame. Default is 1. A value greater +than 1 increases the quality of the image. However, the output +size will be larger. For example, 200x200 image with magnification +of 2 will be a 400x400 image.

  • +
  • size ((int, int)) – (width, height) of the window. Default is (300, 300).

  • +
  • screen_clip (bool) – Clip the png based on screen resolution. Default is False.

  • +
  • reset_camera (bool) –

    +
    If True Call scene.reset_camera(). Otherwise you need to set the

    camera before calling this function.

    +
    +
    +

  • +
  • stereo (string) –

    Set the stereo type. Default is ‘off’. Other types include:

    +
      +
    • ’opengl’: OpenGL frame-sequential stereo. Referred to as +‘CrystalEyes’ by VTK.

    • +
    • ’anaglyph’: For use with red/blue glasses. See VTK docs to +use different colors.

    • +
    • ’interlaced’: Line interlaced.

    • +
    • ’checkerboard’: Checkerboard interlaced.

    • +
    • ’left’: Left eye only.

    • +
    • ’right’: Right eye only.

    • +
    • ’horizontal’: Side-by-side.

    • +
    +

  • +
  • verbose (bool) – print information about the camera. Default is False.

  • +
+
+
+

Examples

+
>>> from fury import window, actor
+>>> scene = window.Scene()
+>>> a = actor.axes()
+>>> scene.add(a)
+>>> # uncomment below to record
+>>> # window.record(scene)
+>>> # check for new images in current directory
+
+
+
+ +
+
+

antialiasing#

+
+
+fury.window.antialiasing(scene, win, multi_samples=8, max_peels=4, occlusion_ratio=0.0)[source]#
+

Enable anti-aliasing and ordered transparency.

+
+
Parameters:
+
    +
  • scene (Scene) –

  • +
  • win (Window) – Provided by ShowManager.window attribute.

  • +
  • multi_samples (int) – Number of samples for anti-aliasing (Default 8). +For no anti-aliasing use 0.

  • +
  • max_peels (int) – Maximum number of peels for depth peeling (Default 4).

  • +
  • occlusion_ratio (float) – Occlusion ratio for depth peeling (Default 0 - exact image).

  • +
+
+
+
+ +
+
+

snapshot#

+
+
+fury.window.snapshot(scene, fname=None, size=(300, 300), offscreen=True, order_transparent=False, stereo='off', multi_samples=8, max_peels=4, occlusion_ratio=0.0, dpi=(72, 72), render_window=None)[source]#
+

Save a snapshot of the scene in a file or in memory.

+
+
Parameters:
+
    +
  • scene (Scene() or vtkRenderer) – Scene instance

  • +
  • fname (str or None) – Save PNG file. If None return only an array without saving PNG.

  • +
  • size ((int, int)) – (width, height) of the window. Default is (300, 300).

  • +
  • offscreen (bool) – Default True. Go stealth mode no window should appear.

  • +
  • order_transparent (bool) – Default False. Use depth peeling to sort transparent objects. +If True also enables anti-aliasing.

  • +
  • stereo (string) –

    Set the stereo type. Default is ‘off’. Other types include:

    +
      +
    • ’opengl’: OpenGL frame-sequential stereo. Referred to as +‘CrystalEyes’ by VTK.

    • +
    • ’anaglyph’: For use with red/blue glasses. See VTK docs to +use different colors.

    • +
    • ’interlaced’: Line interlaced.

    • +
    • ’checkerboard’: Checkerboard interlaced.

    • +
    • ’left’: Left eye only.

    • +
    • ’right’: Right eye only.

    • +
    • ’horizontal’: Side-by-side.

    • +
    +

  • +
  • multi_samples (int) – Number of samples for anti-aliazing (Default 8). +For no anti-aliasing use 0.

  • +
  • max_peels (int) – Maximum number of peels for depth peeling (Default 4).

  • +
  • occlusion_ratio (float) – Occlusion ration for depth peeling (Default 0 - exact image).

  • +
  • dpi (float or (float, float)) – Dots per inch (dpi) for saved image. +Single values are applied as dpi for both dimensions.

  • +
  • render_window (RenderWindow) – If provided, use this window instead of creating a new one.

  • +
+
+
Returns:
+

arr – Color array of size (width, height, 3) where the last dimension +holds the RGB values.

+
+
Return type:
+

ndarray

+
+
+
+ +
+
+

analyze_scene#

+
+
+fury.window.analyze_scene(scene)[source]#
+
+ +
+
+

analyze_snapshot#

+
+
+fury.window.analyze_snapshot(im, bg_color=(0.0, 0.0, 0.0), colors=None, find_objects=True, strel=None)[source]#
+

Analyze snapshot from memory or file.

+
+
Parameters:
+
    +
  • im (str or array) – If string then the image is read from a file otherwise the image is +read from a numpy array. The array is expected to be of shape (X, Y, 3) +or (X, Y, 4) where the last dimensions are the RGB or RGBA values.

  • +
  • colors (tuple (3,) or list of tuples (3,)) – List of colors to search in the image

  • +
  • find_objects (bool) – If True it will calculate the number of objects that are different +from the background and return their position in a new image.

  • +
  • strel (2d array) – Structure element to use for finding the objects.

  • +
+
+
Returns:
+

report – This is an object with attributes like colors_found that give +information about what was found in the current snapshot array im.

+
+
Return type:
+

ReportSnapshot

+
+
+
+ +
+
+

enable_stereo#

+
+
+fury.window.enable_stereo(renwin, stereo_type)[source]#
+

Enable the given stereo type on the RenderWindow.

+
+
Parameters:
+
    +
  • renwin (vtkRenderWindow) –

  • +
  • stereo_type (string) –

      +
    • ‘opengl’: OpenGL frame-sequential stereo. Referred to as +‘CrystalEyes’ by VTK.

    • +
    • ’anaglyph’: For use with red/blue glasses. See VTK docs to +use different colors.

    • +
    • ’interlaced’: Line interlaced.

    • +
    • ’checkerboard’: Checkerboard interlaced.

    • +
    • ’left’: Left eye only.

    • +
    • ’right’: Right eye only.

    • +
    • ’horizontal’: Side-by-side.

    • +
    +

  • +
+
+
+
+ +
+
+

gl_get_current_state#

+
+
+fury.window.gl_get_current_state(gl_state)[source]#
+

Returns a dict which describes the current state of the opengl +context

+
+
Parameters:
+

gl_state (vtkOpenGLState) –

+
+
+
+ +
+
+

gl_reset_blend#

+
+
+fury.window.gl_reset_blend(gl_state)[source]#
+

Redefines the state of the OpenGL context related with how the RGBA +channels will be combined.

+
+
Parameters:
+
    +
  • gl_state (vtkOpenGLState) –

  • +
  • more (See) –

  • +
  • ---------

  • +
  • https ([3]) –

  • +
  • https

  • +
  • specification (vtk) –

  • +
  • https

  • +
+
+
+
+ +
+
+

gl_enable_depth#

+
+
+fury.window.gl_enable_depth(gl_state)[source]#
+

Enable OpenGl depth test

+
+
Parameters:
+

gl_state (vtkOpenGLState) –

+
+
+
+ +
+
+

gl_disable_depth#

+
+
+fury.window.gl_disable_depth(gl_state)[source]#
+

Disable OpenGl depth test

+
+
Parameters:
+

gl_state (vtkOpenGLState) –

+
+
+
+ +
+
+

gl_enable_blend#

+
+
+fury.window.gl_enable_blend(gl_state)[source]#
+

Enable OpenGl blending

+
+
Parameters:
+

gl_state (vtkOpenGLState) –

+
+
+
+ +
+
+

gl_disable_blend#

+
+
+fury.window.gl_disable_blend(gl_state)[source]#
+

This it will disable any gl behavior which has no +function for opaque objects. This has the benefit of +speeding up the rendering of the image.

+
+
Parameters:
+
    +
  • gl_state (vtkOpenGLState) –

  • +
  • more (See) –

  • +
  • --------

  • +
  • https ([1]) –

  • +
+
+
+
+ +
+
+

gl_set_additive_blending#

+
+
+fury.window.gl_set_additive_blending(gl_state)[source]#
+

Enable additive blending

+
+
Parameters:
+

gl_state (vtkOpenGLState) –

+
+
+
+ +
+
+

gl_set_additive_blending_white_background#

+
+
+fury.window.gl_set_additive_blending_white_background(gl_state)[source]#
+

Enable additive blending for a white background

+
+
Parameters:
+

gl_state (vtkOpenGLState) –

+
+
+
+ +
+
+

gl_set_normal_blending#

+
+
+fury.window.gl_set_normal_blending(gl_state)[source]#
+

Enable normal blending

+
+
Parameters:
+

gl_state (vtkOpenGLState) –

+
+
+
+ +
+
+

gl_set_multiplicative_blending#

+
+
+fury.window.gl_set_multiplicative_blending(gl_state)[source]#
+

Enable multiplicative blending

+
+
Parameters:
+

gl_state (vtkOpenGLState) –

+
+
+
+ +
+
+

gl_set_subtractive_blending#

+
+
+fury.window.gl_set_subtractive_blending(gl_state)[source]#
+

Enable subtractive blending

+
+
Parameters:
+

gl_state (vtkOpenGLState) –

+
+
+
+ +
+
+

release_context#

+
+
+fury.window.release_context(window)[source]#
+

Release the context of the window

+
+
Parameters:
+

window (vtkRenderWindow) –

+
+
+
+ +
+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ +
+ On this page +
+ +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/reference/index.html b/v0.10.x/reference/index.html new file mode 100644 index 000000000..1018750ae --- /dev/null +++ b/v0.10.x/reference/index.html @@ -0,0 +1,3351 @@ + + + + + + + + API Reference — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

API Reference#

+
+ +
+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/release-history.html b/v0.10.x/release-history.html new file mode 100644 index 000000000..3cef0d136 --- /dev/null +++ b/v0.10.x/release-history.html @@ -0,0 +1,521 @@ + + + + + + + + Release History — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ + +
+ + + +
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/release_notes/releasev0.1.0.html b/v0.10.x/release_notes/releasev0.1.0.html new file mode 100644 index 000000000..253188749 --- /dev/null +++ b/v0.10.x/release_notes/releasev0.1.0.html @@ -0,0 +1,531 @@ + + + + + + + + Release notes v0.1.0 (2018-09-21) — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ + +
+ + +
+
+ +
+ +
+ + +
+ +
+

Release notes v0.1.0 (2018-09-21)#

+
+

Quick Overview#

+

This initial release is a split from DIPY. It contains:

+
    +
  • from dipy.viz.actors to fury.actors

  • +
  • from dipy.viz.window to fury.window

  • +
  • from dipy.viz.ui to fury.ui

  • +
  • from dipy.viz.widget to fury.widget

  • +
  • from dipy.viz.interactor to fury.interactor

  • +
  • from dipy.viz.colormap to fury.colormap

  • +
  • from dipy.viz.utils to fury.utils

  • +
+
+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ +
+ On this page +
+ +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/release_notes/releasev0.1.1.html b/v0.10.x/release_notes/releasev0.1.1.html new file mode 100644 index 000000000..d15bd5351 --- /dev/null +++ b/v0.10.x/release_notes/releasev0.1.1.html @@ -0,0 +1,527 @@ + + + + + + + + Release notes v0.1.1 (2018-10-29) — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ + +
+ + +
+
+ +
+ +
+ + +
+ +
+

Release notes v0.1.1 (2018-10-29)#

+
+

Quick Overview#

+

This is a maintenance release

+
    +
  • Fix error on python 2.7

  • +
  • Travis integration

  • +
  • Documentation integration

  • +
+
+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ +
+ On this page +
+ +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/release_notes/releasev0.1.3.html b/v0.10.x/release_notes/releasev0.1.3.html new file mode 100644 index 000000000..8cf1f54df --- /dev/null +++ b/v0.10.x/release_notes/releasev0.1.3.html @@ -0,0 +1,526 @@ + + + + + + + + Release notes v0.1.2 and v0.1.3 (2018-10-31) — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ + +
+ + +
+
+ +
+ +
+ + +
+ +
+

Release notes v0.1.2 and v0.1.3 (2018-10-31)#

+
+

Quick Overview#

+

This is a maintenance release

+
    +
  • Update setup.py

  • +
  • Remove dependence on requirements.txt

  • +
+
+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ +
+ On this page +
+ +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/release_notes/releasev0.1.4.html b/v0.10.x/release_notes/releasev0.1.4.html new file mode 100644 index 000000000..cec6dedc7 --- /dev/null +++ b/v0.10.x/release_notes/releasev0.1.4.html @@ -0,0 +1,526 @@ + + + + + + + + Release notes v0.1.4 (2018-11-26) — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ + +
+ + +
+
+ +
+ +
+ + +
+ +
+

Release notes v0.1.4 (2018-11-26)#

+
+

Quick Overview#

+

This is a maintenance release

+
    +
  • Add vtk.utils.color on window package

  • +
  • Update Readme, codecov, travis…

  • +
+
+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ +
+ On this page +
+ +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/release_notes/releasev0.10.0.html b/v0.10.x/release_notes/releasev0.10.0.html new file mode 100644 index 000000000..a3b1588f6 --- /dev/null +++ b/v0.10.x/release_notes/releasev0.10.0.html @@ -0,0 +1,691 @@ + + + + + + + + Release notes v0.10.0 (2024/02/28) — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ + +
+ + +
+
+ +
+ +
+ + +
+ +
+

Release notes v0.10.0 (2024/02/28)#

+
+

Quick Overview#

+
    +
  • Uncertainty Visualization added.

  • +
  • New actors added.

  • +
  • Many UI components updated.

  • +
  • Multiple tutorials added and updated.

  • +
  • Documentation updated.

  • +
  • Website updated.

  • +
+
+
+

Details#

+

GitHub stats for 2023/04/15 - 2024/02/27 (tag: v0.9.0)

+

These lists are automatically generated, and may be incomplete or contain duplicates.

+

The following 11 authors contributed 382 commits.

+
    +
  • Antriksh Misri

  • +
  • Dwij Raj Hari

  • +
  • Eleftherios Garyfallidis

  • +
  • Joao Victor Dell Agli

  • +
  • Maharshi Gor

  • +
  • Praneeth Shetty

  • +
  • Robin Roy

  • +
  • Serge Koudoro

  • +
  • Tania Castillo

  • +
  • dependabot[bot]

  • +
  • maharshigor

  • +
+

We closed a total of 129 issues, 54 pull requests and 75 regular issues; +this is the full list (generated with the script +tools/github_stats.py):

+

Pull Requests (54):

+
    +
  • PR #810: DTI uncertainty visualization

  • +
  • PR #861: Added/Modified docstrings for 3 actor.py functions

  • +
  • PR #863: UI Bug fixes for Horizon

  • +
  • PR #866: build(deps): bump the actions group with 6 updates

  • +
  • PR #865: Fix ci

  • +
  • PR #845: GSoC: Final Report

  • +
  • PR #847: GSoC: Adding Final Report 23

  • +
  • PR #848: Added Final Report

  • +
  • PR #852: add Code of conduct

  • +
  • PR #846: Added blogpost week 12

  • +
  • PR #844: GSoC: Week 12 Blogpost

  • +
  • PR #843: GSoC: Adding Week 12 Blogpost

  • +
  • PR #842: GSoC: Week 11 Blogpost

  • +
  • PR #839: GSoC: Adding Week 10 Blogpost

  • +
  • PR #840: Added blogposts week 8, 9, 10, 11

  • +
  • PR #841: GSoC: Adding Week 11 Blogpost

  • +
  • PR #831: GSoC: Week 9 Blogpost

  • +
  • PR #833: GSoC: Adding Week 9 Blogpost

  • +
  • PR #836: GSoC: Week 10 Blogpost

  • +
  • PR #499: Adding SpinBoxUI to the UI module

  • +
  • PR #818: Tutorial on using ellipsoid actor to visualize tensor ellipsoids for DTI

  • +
  • PR #834: citation section added

  • +
  • PR #830: UI: Adding getters and setters for the TextBlock2D properties

  • +
  • PR #829: GSoC: Adding Week 8 Blogpost

  • +
  • PR #828: GSoC: Week 8 Blogpost

  • +
  • PR #803: UI: Adding Bounding Box & Fixing Alignment issue in TextBlock2D

  • +
  • PR #814: physics-simulation done

  • +
  • PR #827: Added blogpost week 4, 5, 6, 7

  • +
  • PR #822: GSoC: Week 7 Blogpost

  • +
  • PR #823: GSoC: Adding Week 6 - 7 Blogpost

  • +
  • PR #791: Ellipsoid actor implemented with SDF

  • +
  • PR #817: GSoC: Adding Week 5 Blogpost

  • +
  • PR #820: Updating broken links in the Scientific Domain Section

  • +
  • PR #819: GSoC: Week 6 Blogpost

  • +
  • PR #815: Week 5 blogpost

  • +
  • PR #812: Feature/compatible software

  • +
  • PR #811: GSoC: Adding Week 4 Blogpost

  • +
  • PR #809: Week 4 Blogpost

  • +
  • PR #807: Added blogpost week 3

  • +
  • PR #806: Week 3 Blogpost

  • +
  • PR #805: GSoC: Adding Week3 Blogpost

  • +
  • PR #398: feat: added a Card2D widget to UI

  • +
  • PR #800: Week2 Blogpost

  • +
  • PR #802: Added blogpost week 2

  • +
  • PR #801: [fix] update deprecated Test

  • +
  • PR #799: Adding Week2 BlogPost

  • +
  • PR #798: Added blogpost week 1

  • +
  • PR #768: Overload set_visibility for Panel2D and Combobox2D

  • +
  • PR #797: Week 1 blogpost

  • +
  • PR #796: Adding Week1 Blogpost

  • +
  • PR #792: Adding week 0 blogpost

  • +
  • PR #789: Added blogpost week 0

  • +
  • PR #788: Adding Week0 Blogpost

  • +
  • PR #629: Release preparation 0.9.0

  • +
+

Issues (75):

+
    +
  • #810: DTI uncertainty visualization

  • +
  • #861: Added/Modified docstrings for 3 actor.py functions

  • +
  • #863: UI Bug fixes for Horizon

  • +
  • #866: build(deps): bump the actions group with 6 updates

  • +
  • #864: Missing files for sprite test

  • +
  • #865: Fix ci

  • +
  • #845: GSoC: Final Report

  • +
  • #847: GSoC: Adding Final Report 23

  • +
  • #848: Added Final Report

  • +
  • #425: WIP: Cube Axes Actor.

  • +
  • #852: add Code of conduct

  • +
  • #846: Added blogpost week 12

  • +
  • #844: GSoC: Week 12 Blogpost

  • +
  • #843: GSoC: Adding Week 12 Blogpost

  • +
  • #842: GSoC: Week 11 Blogpost

  • +
  • #397: Card2D UI widget

  • +
  • #839: GSoC: Adding Week 10 Blogpost

  • +
  • #840: Added blogposts week 8, 9, 10, 11

  • +
  • #841: GSoC: Adding Week 11 Blogpost

  • +
  • #837: UI: Adding Text Offset to contain text into the Background

  • +
  • #831: GSoC: Week 9 Blogpost

  • +
  • #833: GSoC: Adding Week 9 Blogpost

  • +
  • #836: GSoC: Week 10 Blogpost

  • +
  • #499: Adding SpinBoxUI to the UI module

  • +
  • #818: Tutorial on using ellipsoid actor to visualize tensor ellipsoids for DTI

  • +
  • #834: citation section added

  • +
  • #830: UI: Adding getters and setters for the TextBlock2D properties

  • +
  • #294: File Dialog UI component

  • +
  • #829: GSoC: Adding Week 8 Blogpost

  • +
  • #828: GSoC: Week 8 Blogpost

  • +
  • #803: UI: Adding Bounding Box & Fixing Alignment issue in TextBlock2D

  • +
  • #814: physics-simulation done

  • +
  • #827: Added blogpost week 4, 5, 6, 7

  • +
  • #822: GSoC: Week 7 Blogpost

  • +
  • #823: GSoC: Adding Week 6 - 7 Blogpost

  • +
  • #825: [WIP] KDE Rendering API

  • +
  • #824: [WIP] KDE Rendering API

  • +
  • #791: Ellipsoid actor implemented with SDF

  • +
  • #817: GSoC: Adding Week 5 Blogpost

  • +
  • #820: Updating broken links in the Scientific Domain Section

  • +
  • #819: GSoC: Week 6 Blogpost

  • +
  • #815: Week 5 blogpost

  • +
  • #460: [WIP] Adding Tree2D to the UI sub-module

  • +
  • #592: Creating ScrollBar as a separate UI element

  • +
  • #285: Separation of Scrollbars as a standalone API.

  • +
  • #222: Attempt to refactor scrolling in FileMenu2D

  • +
  • #812: Feature/compatible software

  • +
  • #811: GSoC: Adding Week 4 Blogpost

  • +
  • #809: Week 4 Blogpost

  • +
  • #808: sponsors added

  • +
  • #807: Added blogpost week 3

  • +
  • #806: Week 3 Blogpost

  • +
  • #805: GSoC: Adding Week3 Blogpost

  • +
  • #402: ImageContainer2D renders RGB .png images in black and white

  • +
  • #398: feat: added a Card2D widget to UI

  • +
  • #800: Week2 Blogpost

  • +
  • #802: Added blogpost week 2

  • +
  • #801: [fix] update deprecated Test

  • +
  • #799: Adding Week2 BlogPost

  • +
  • #794: FURY dependencies aren’t accurate in the README

  • +
  • #790: Fixing TextBlock2D justification issue

  • +
  • #798: Added blogpost week 1

  • +
  • #576: Resolving icon flaw in comboBox2D

  • +
  • #731: Clicking the tab of a ComboBox2D opens dropdown without changing icon

  • +
  • #562: drop_down_menu icon flaw in ComboBox2D

  • +
  • #768: Overload set_visibility for Panel2D and Combobox2D

  • +
  • #797: Week 1 blogpost

  • +
  • #796: Adding Week1 Blogpost

  • +
  • #792: Adding week 0 blogpost

  • +
  • #789: Added blogpost week 0

  • +
  • #787: Segmentation Fault while plotting (diffusion tractography) images on a non-interactive remote cluster

  • +
  • #788: Adding Week0 Blogpost

  • +
  • #448: Added the watcher class to UI

  • +
  • #774: WIP: Double arrow actor and a few utility functions

  • +
  • #629: Release preparation 0.9.0

  • +
+
+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ +
+ On this page +
+ +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/release_notes/releasev0.2.0.html b/v0.10.x/release_notes/releasev0.2.0.html new file mode 100644 index 000000000..83d357c35 --- /dev/null +++ b/v0.10.x/release_notes/releasev0.2.0.html @@ -0,0 +1,614 @@ + + + + + + + + Release notes v0.2.0 (2019-03-08) — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ + +
+ + +
+
+ +
+ +
+ + +
+ +
+

Release notes v0.2.0 (2019-03-08)#

+
+

Quick Overview#

+
    +
  • Replace fury.window.Renderer by fury.window.Scene

  • +
  • Add stereo support

  • +
  • Add GridUI object

  • +
  • Increase tests coverage and code quality

  • +
+
+
+

Details#

+

GitHub stats for 2018/11/26 - 2019/03/08 (tag: v0.1.4)

+

These lists are automatically generated, and may be incomplete or contain duplicates.

+

The following 5 authors contributed 186 commits.

+
    +
  • David Reagan

  • +
  • Eleftherios Garyfallidis

  • +
  • Jon Haitz Legarreta Gorroño

  • +
  • Marc-Alexandre Côté

  • +
  • Serge Koudoro

  • +
+

We closed a total of 60 issues, 20 pull requests and 40 regular issues; +this is the full list (generated with the script +ext/github_tools.py):

+

Pull Requests (20):

+
    +
  • PR #61: [Fix] fetch github api from documentation

  • +
  • PR #55: Add stereo rendering support

  • +
  • PR #50: [NF] Doc version

  • +
  • PR #60: backward compatibilities

  • +
  • PR #59: [NF] Add get_info function

  • +
  • PR #58: Tests addition

  • +
  • PR #57: Add tests to utils module

  • +
  • PR #52: [Fix] add filterwarnings

  • +
  • PR #56: Increase Codacy rank

  • +
  • PR #32: The grid - add actors in a grid and interact with each one of them independently

  • +
  • PR #47: BUG: Fix TensorSlicerActor actor opacity property not being enforced.

  • +
  • PR #48: ENH: Exercise the PeakSlicerActor opacity explicitly.

  • +
  • PR #43: BUG: Fix peaks_slicer actor properties not being enforced.

  • +
  • PR #44: BUG: Fix elementwise comparison deprecation warning.

  • +
  • PR #42: [Fix] viz_surface

  • +
  • PR #40: Re-enable transparency test, change colors

  • +
  • PR #39: removing widget module

  • +
  • PR #21: Add depth_cue and fake_tube to simulate tubes with lines

  • +
  • PR #30: Add doc generation on Travis

  • +
  • PR #28: Renaming Renderer to Scene

  • +
+

Issues (40):

+
    +
  • #61: [Fix] fetch github api from documentation

  • +
  • #55: Add stereo rendering support

  • +
  • #50: [NF] Doc version

  • +
  • #60: backward compatibilities

  • +
  • #59: [NF] Add get_info function

  • +
  • #58: Tests addition

  • +
  • #8: dipy.viz.colormap crash on single fibers

  • +
  • #57: Add tests to utils module

  • +
  • #52: [Fix] add filterwarnings

  • +
  • #46: Hide/Ignore numpy_vtk support warning

  • +
  • #56: Increase Codacy rank

  • +
  • #32: The grid - add actors in a grid and interact with each one of them independently

  • +
  • #49: Add a Codacy badge to README.rst

  • +
  • #47: BUG: Fix TensorSlicerActor actor opacity property not being enforced.

  • +
  • #48: ENH: Exercise the PeakSlicerActor opacity explicitly.

  • +
  • #43: BUG: Fix peaks_slicer actor properties not being enforced.

  • +
  • #22: Peak slicer doesn’t honor linewidth parameter

  • +
  • #37: Fix DeprecationWarning

  • +
  • #44: BUG: Fix elementwise comparison deprecation warning.

  • +
  • #45: Change Miniconda version

  • +
  • #42: [Fix] viz_surface

  • +
  • #41: module ‘fury.window’ has no attribute ‘Scene’

  • +
  • #6: VTK and Python 3 support in fvtk

  • +
  • #40: Re-enable transparency test, change colors

  • +
  • #2: Dipy visualization (fvtk) crash when saving series of images

  • +
  • #4: fvtk contour function ignores voxsz parameter

  • +
  • #1: fvtk.label won’t show up if called twice

  • +
  • #39: removing widget module

  • +
  • #21: Add depth_cue and fake_tube to simulate tubes with lines

  • +
  • #3: Dipy visualization with missing (?) affine parameter

  • +
  • #5: How to resolve python-vtk6 link issues in Ubuntu

  • +
  • #29: Added surface function

  • +
  • #30: Add doc generation on Travis

  • +
  • #23: DOC: sphinx_gallery master branch is required

  • +
  • #28: Renaming Renderer to Scene

  • +
  • #26: Rename Renderer to Scene

  • +
  • #24: VTK dependency on installation

  • +
  • #11: Reorienting peak_slicer and ODF_slicer

  • +
  • #14: dipy test failed on mac osx sierra with ananoda python.

  • +
  • #17: dipy test failed on mac osx sierra with ananoda python.

  • +
+
+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ +
+ On this page +
+ +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/release_notes/releasev0.3.0.html b/v0.10.x/release_notes/releasev0.3.0.html new file mode 100644 index 000000000..b14fe1a54 --- /dev/null +++ b/v0.10.x/release_notes/releasev0.3.0.html @@ -0,0 +1,595 @@ + + + + + + + + Release notes v0.3.0 (2019-08-02) — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ + +
+ + +
+
+ +
+ +
+ + +
+ +
+

Release notes v0.3.0 (2019-08-02)#

+
+

Quick Overview#

+
    +
  • Add cone actor and update odf actor

  • +
  • Add Appveyor CI and update MacOS CI

  • +
  • Update Documentation, examples and tutorials

  • +
  • Increase tests coverage and code quality

  • +
+
+
+

Details#

+

GitHub stats for 2019/03/08 - 2019/08/02 (tag: v0.2.0)

+

These lists are automatically generated, and may be incomplete or contain duplicates.

+

The following 7 authors contributed 164 commits.

+
    +
  • Ariel Rokem

  • +
  • Eleftherios Garyfallidis

  • +
  • Guillaume Favelier

  • +
  • Kevin Sitek

  • +
  • Prashil

  • +
  • Scott Trinkle

  • +
  • Serge Koudoro

  • +
+

We closed a total of 39 issues, 15 pull requests and 24 regular issues; +this is the full list (generated with the script +tools/github_stats.py):

+

Pull Requests (15):

+
    +
  • PR #91: [Doc] add installation instruction

  • +
  • PR #53: [Fix] resolution limit

  • +
  • PR #89: [Fix] cmap when not have matplotlib

  • +
  • PR #88: Updates and corrections in slicer and ui

  • +
  • PR #69: Add middle button callback

  • +
  • PR #86: Fixes a typo in the viz_ui tutorial.

  • +
  • PR #83: Remove issue template

  • +
  • PR #87: TEST: updated order transparency issue for vtk 8.2.0

  • +
  • PR #80: Add cones as glyphs

  • +
  • PR #73: Add appveyor

  • +
  • PR #72: Update OSX bots on Travis

  • +
  • PR #68: Allow Str for Grid Caption

  • +
  • PR #67: [Fix] Update doc management

  • +
  • PR #62: Directional color odfs

  • +
  • PR #31: new surface function

  • +
+

Issues (24):

+
    +
  • #91: [Doc] add installation instruction

  • +
  • #36: Tests Documentation

  • +
  • #53: [Fix] resolution limit

  • +
  • #13: window.record() resolution limit

  • +
  • #89: [Fix] cmap when not have matplotlib

  • +
  • #90: [Fix] dtype problem for x64 machine

  • +
  • #88: Updates and corrections in slicer and ui

  • +
  • #69: Add middle button callback

  • +
  • #86: Fixes a typo in the viz_ui tutorial.

  • +
  • #84: Test_order_transparent failed with VTK 8.2.0

  • +
  • #83: Remove issue template

  • +
  • #87: TEST: updated order transparency issue for vtk 8.2.0

  • +
  • #85: Save from active window?

  • +
  • #79: add link to fury example gallery in sphinx-gallery readme

  • +
  • #80: Add cones as glyphs

  • +
  • #73: Add appveyor

  • +
  • #72: Update OSX bots on Travis

  • +
  • #18: Improve unit tests

  • +
  • #63: Improve doc generation

  • +
  • #68: Allow Str for Grid Caption

  • +
  • #67: [Fix] Update doc management

  • +
  • #62: Directional color odfs

  • +
  • #65: Directed Arrows

  • +
  • #31: new surface function

  • +
+
+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ +
+ On this page +
+ +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/release_notes/releasev0.4.0.html b/v0.10.x/release_notes/releasev0.4.0.html new file mode 100644 index 000000000..a1119c5cf --- /dev/null +++ b/v0.10.x/release_notes/releasev0.4.0.html @@ -0,0 +1,588 @@ + + + + + + + + Release notes v0.4.0 (2019-10-29) — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ + +
+ + +
+
+ +
+ +
+ + +
+ +
+

Release notes v0.4.0 (2019-10-29)#

+
+

Quick Overview#

+
    +
  • Enable Anti aliasing and frame rate features

  • +
  • Add multiples actors (arrow, box, …)

  • +
  • Glyph extensions

  • +
  • Remove Nose dependency

  • +
  • Replace Appveyor by Azure pipeline for Windows

  • +
  • Update Documentation, examples and tutorials

  • +
  • Increase tests coverage and code quality

  • +
+
+
+

Details#

+

GitHub stats for 2019/08/02 - 2019/10/29 (tag: v0.3.0)

+

These lists are automatically generated, and may be incomplete or contain duplicates.

+

The following 4 authors contributed 169 commits.

+
    +
  • Eleftherios Garyfallidis

  • +
  • Etienne St-Onge

  • +
  • Javier Guaje

  • +
  • Serge Koudoro

  • +
+

We closed a total of 32 issues, 15 pull requests and 17 regular issues; +this is the full list (generated with the script +tools/github_stats.py):

+

Pull Requests (15):

+
    +
  • PR #109: Show frame rate and enable anti-aliasing

  • +
  • PR #112: Use glyph for several actors

  • +
  • PR #110: Experimental work

  • +
  • PR #107: Increase coverage for test_actors

  • +
  • PR #106: [Fix] doc generation

  • +
  • PR #104: Made it simpler to change color in ListBox

  • +
  • PR #105: Replacing appveyor by Azure

  • +
  • PR #103: Remove nose dependency

  • +
  • PR #101: Update travis

  • +
  • PR #102: from assert to npt_assert_equal

  • +
  • PR #98: [Fix] layout with small cells

  • +
  • PR #97: Bug fix for double slider

  • +
  • PR #100: fix snapshot when size is not square

  • +
  • PR #92: [Fix] update travis to manage pip

  • +
  • PR #94: [miniconda] move to https

  • +
+

Issues (17):

+
    +
  • #109: Show frame rate and enable anti-aliasing

  • +
  • #112: Use glyph for several actors

  • +
  • #66: Directed Arrows

  • +
  • #110: Experimental work

  • +
  • #107: Increase coverage for test_actors

  • +
  • #106: [Fix] doc generation

  • +
  • #104: Made it simpler to change color in ListBox

  • +
  • #105: Replacing appveyor by Azure

  • +
  • #103: Remove nose dependency

  • +
  • #101: Update travis

  • +
  • #102: from assert to npt_assert_equal

  • +
  • #98: [Fix] layout with small cells

  • +
  • #97: Bug fix for double slider

  • +
  • #96: Double slider handles not at right position when window starts

  • +
  • #100: fix snapshot when size is not square

  • +
  • #92: [Fix] update travis to manage pip

  • +
  • #94: [miniconda] move to https

  • +
+
+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ +
+ On this page +
+ +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/release_notes/releasev0.5.1.html b/v0.10.x/release_notes/releasev0.5.1.html new file mode 100644 index 000000000..768024f96 --- /dev/null +++ b/v0.10.x/release_notes/releasev0.5.1.html @@ -0,0 +1,726 @@ + + + + + + + + Release notes v0.5.1 (2020-04-01) — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ + +
+ + +
+
+ +
+ +
+ + +
+ +
+

Release notes v0.5.1 (2020-04-01)#

+
+

Quick Overview#

+
    +
  • Remove python 2 compatibility

  • +
  • Added texture management

  • +
  • Added multiples primitives.

  • +
  • Added multiples actors (contour_from_label, billboard…)

  • +
  • Huge improvement of multiple UI (RangeSlider, …)

  • +
  • Improved security (from md5 to sha256)

  • +
  • Large documentation update, examples and tutorials

  • +
  • Increased tests coverage and code quality

  • +
+
+
+

Details#

+

GitHub stats for 2019/10/29 - 2020/04/02 (tag: v0.4.0)

+

These lists are automatically generated, and may be incomplete or contain duplicates.

+

The following 20 authors contributed 407 commits.

+
    +
  • ChenCheng0630

  • +
  • Devanshu Modi

  • +
  • Eleftherios Garyfallidis

  • +
  • Etienne St-Onge

  • +
  • Filipi Nascimento Silva

  • +
  • Gottipati Gautam

  • +
  • Javier Guaje

  • +
  • Jon Haitz Legarreta Gorroño

  • +
  • Liam Donohue

  • +
  • Marc-Alexandre Côté

  • +
  • Marssis

  • +
  • Naman Bansal

  • +
  • Nasim

  • +
  • Saransh Jain

  • +
  • Serge Koudoro

  • +
  • Shreyas Bhujbal

  • +
  • Soham Biswas

  • +
  • Vivek Choudhary

  • +
  • ibrahimAnis

  • +
  • lenixlobo

  • +
+

We closed a total of 153 issues, 49 pull requests and 104 regular issues; +this is the full list (generated with the script +tools/github_stats.py):

+

Pull Requests (49):

+
    +
  • PR #227: [Fix] update streamlines default color

  • +
  • PR #210: Added contour_from_label method

  • +
  • PR #225: update tutorial folder structure

  • +
  • PR #223: [Fix] sphere winding issue

  • +
  • PR #218: Changed options attribute from list to dict and updated respective tests

  • +
  • PR #220: bumping scipy version to 1.2.0

  • +
  • PR #213: Utils vtk

  • +
  • PR #215: Remove more than one actors at once

  • +
  • PR #207: updated fetcher

  • +
  • PR #206: [FIX] avoid in-place replacements

  • +
  • PR #203: Namanb009 windowtitlefix

  • +
  • PR #204: Vertical Layout for RangeSlider

  • +
  • PR #190: Add initial state to checkbox

  • +
  • PR #201: [FIX] icons flipping

  • +
  • PR #181: Vertical Layout for LineDoubleSlider2D

  • +
  • PR #198: Utils test and winding order algorithm

  • +
  • PR #192: Tetrahedron, Icosahedron primitives

  • +
  • PR #189: Added dynamic text positioning

  • +
  • PR #194: [FIX] Update superquadrics test

  • +
  • PR #182: [Doc] Reshape the documentation

  • +
  • PR #177: [Fix] Flipping during save

  • +
  • PR #191: DOC: Fix actor.line parameter type and add optional keyword

  • +
  • PR #173: Fixing Text Overflow of ListBox2D

  • +
  • PR #167: Animated Network Visualization Example

  • +
  • PR #165: Vertical Layout for LineSlider2D

  • +
  • PR #154: Added Shader tutorial

  • +
  • PR #153: Sep viz ui

  • +
  • PR #132: Add Billboard actor

  • +
  • PR #164: Documentation

  • +
  • PR #163: Spelling error

  • +
  • PR #157: Corrected Disk2D comments

  • +
  • PR #148: Replace md5 by sha 256

  • +
  • PR #145: DOC: Fix io:load_image and io:save_image docstrings

  • +
  • PR #144: STYLE: Change examples README file extension to reStructuredText

  • +
  • PR #143: STYLE: Improve the requirements’ files’ style.

  • +
  • PR #139: [Fix] some docstring for doc generation

  • +
  • PR #140: [DOC] Add demo for showing an network

  • +
  • PR #136: Started new tutorial about using normals to make spiky spheres

  • +
  • PR #134: Add event parameter on add_window_callback method in ShowManager class.

  • +
  • PR #129: update loading and saving IO for polydata

  • +
  • PR #131: Add Superquadric primitives and actors

  • +
  • PR #130: Adding Sphere primitives

  • +
  • PR #128: Update Deprecated function

  • +
  • PR #126: Add basic primitives

  • +
  • PR #125: Add Deprecated decorator

  • +
  • PR #124: Texture utilities and actors

  • +
  • PR #118: Remove python2 compatibility

  • +
  • PR #120: Replace pickle with JSON for “events_counts” dict serialization

  • +
  • PR #115: Release 0.4.0 preparation

  • +
+

Issues (104):

+
    +
  • #150: Re-compute Bounds in Slicer

  • +
  • #227: [Fix] update streamlines default color

  • +
  • #135: Backward compatibilities problem with streamtube

  • +
  • #77: contour_from_label

  • +
  • #210: Added contour_from_label method

  • +
  • #225: update tutorial folder structure

  • +
  • #223: [Fix] sphere winding issue

  • +
  • #137: Issues with provided spheres

  • +
  • #152: Improve checkbox options cases

  • +
  • #218: Changed options attribute from list to dict and updated respective tests

  • +
  • #76: Improve Checkbox options access

  • +
  • #219: Issue occur when I Start testing the project

  • +
  • #220: bumping scipy version to 1.2.0

  • +
  • #217: Transformed options attribute from list to dict and updated respective tests

  • +
  • #213: Utils vtk

  • +
  • #179: Utility functions are needed for getting numpy arrays from actors

  • +
  • #212: Namanb009 issue 133 fix

  • +
  • #214: Namanb009 Remove multiple actors

  • +
  • #215: Remove more than one actors at once

  • +
  • #211: Namanb009 hexadecimal color support

  • +
  • #187: New utility functions are added in utils.py and tests are added in te…

  • +
  • #209: Namanb009 viz_ui.py does not show render window when run

  • +
  • #207: updated fetcher

  • +
  • #206: [FIX] avoid in-place replacements

  • +
  • #203: Namanb009 windowtitlefix

  • +
  • #202: Window Title name does not change

  • +
  • #204: Vertical Layout for RangeSlider

  • +
  • #190: Add initial state to checkbox

  • +
  • #75: Improve Checkbox initialisation

  • +
  • #201: [FIX] icons flipping

  • +
  • #199: Loading of Inverted icons using read_viz_icons

  • +
  • #181: Vertical Layout for LineDoubleSlider2D

  • +
  • #175: LineDoubleSlider2D vertical layout

  • +
  • #198: Utils test and winding order algorithm

  • +
  • #192: Tetrahedron, Icosahedron primitives

  • +
  • #189: Added dynamic text positioning

  • +
  • #176: Allowing to change text position on Sliders

  • +
  • #185: NF: winding order in utils

  • +
  • #170: NF: adding primitive stars, 3D stars, rhombi.

  • +
  • #195: Added dynamic text position on sliders

  • +
  • #194: [FIX] Update superquadrics test

  • +
  • #171: bug-in-image 0.1

  • +
  • #182: [Doc] Reshape the documentation

  • +
  • #156: Test Case File Updated

  • +
  • #155: There are libraries we have to install not mentioned in the requirement.txt file to run the test case.

  • +
  • #122: Documentation not being rendered correctly

  • +
  • #177: [Fix] Flipping during save

  • +
  • #160: Saved Images are vertically Inverted

  • +
  • #193: Merge pull request #2 from fury-gl/master

  • +
  • #191: DOC: Fix actor.line parameter type and add optional keyword

  • +
  • #178: changed text position

  • +
  • #188: Added dynamic text positioning

  • +
  • #173: Fixing Text Overflow of ListBox2D

  • +
  • #15: viz.ui.ListBoxItem2D text overflow

  • +
  • #166: Build Native File Dialogs

  • +
  • #180: Native File Dialog Text Overflow Issue

  • +
  • #186: add name

  • +
  • #184: Added winding order algorithm to utils

  • +
  • #183: Added star2D and 3D, rhombicuboctahedron to tests_primitive

  • +
  • #54: generating directed arrows

  • +
  • #174: List box text overflow

  • +
  • #167: Animated Network Visualization Example

  • +
  • #165: Vertical Layout for LineSlider2D

  • +
  • #108: Slider vertical layout

  • +
  • #172: window.show() is giving Attribute error.

  • +
  • #154: Added Shader tutorial

  • +
  • #151: Prim shapes

  • +
  • #162: Winding order 2

  • +
  • #168: Prim test

  • +
  • #158: nose is missing

  • +
  • #71: viz_ui.py example needs expansion

  • +
  • #153: Sep viz ui

  • +
  • #132: Add Billboard actor

  • +
  • #164: Documentation

  • +
  • #163: Spelling error

  • +
  • #161: Merge pull request #1 from fury-gl/master

  • +
  • #157: Corrected Disk2D comments

  • +
  • #121: Replace md5 by sha2 or sha3 for security issue

  • +
  • #148: Replace md5 by sha 256

  • +
  • #147: update md5 to sha256

  • +
  • #146: Shapes

  • +
  • #145: DOC: Fix io:load_image and io:save_image docstrings

  • +
  • #144: STYLE: Change examples README file extension to reStructuredText

  • +
  • #142: STYLE: Change examples README file extension to markdown

  • +
  • #143: STYLE: Improve the requirements’ files’ style.

  • +
  • #139: [Fix] some docstring for doc generation

  • +
  • #140: [DOC] Add demo for showing an network

  • +
  • #136: Started new tutorial about using normals to make spiky spheres

  • +
  • #134: Add event parameter on add_window_callback method in ShowManager class.

  • +
  • #81: Add superquadric function in actor.py

  • +
  • #129: update loading and saving IO for polydata

  • +
  • #131: Add Superquadric primitives and actors

  • +
  • #130: Adding Sphere primitives

  • +
  • #128: Update Deprecated function

  • +
  • #126: Add basic primitives

  • +
  • #125: Add Deprecated decorator

  • +
  • #124: Texture utilities and actors

  • +
  • #99: [WIP] Adding util to get Numpy 3D array of RGBA values

  • +
  • #118: Remove python2 compatibility

  • +
  • #117: Remove compatibility with python 2

  • +
  • #123: WIP: Texture support

  • +
  • #119: Improve data Serialization

  • +
  • #120: Replace pickle with JSON for “events_counts” dict serialization

  • +
  • #115: Release 0.4.0 preparation

  • +
+
+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ +
+ On this page +
+ +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/release_notes/releasev0.6.0.html b/v0.10.x/release_notes/releasev0.6.0.html new file mode 100644 index 000000000..8a90003df --- /dev/null +++ b/v0.10.x/release_notes/releasev0.6.0.html @@ -0,0 +1,623 @@ + + + + + + + + Release notes v0.6.0 (2020-07-20) — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ + +
+ + +
+
+ +
+ +
+ + +
+ +
+

Release notes v0.6.0 (2020-07-20)#

+
+

Quick Overview#

+
    +
  • Added new features: Picking and double-click callback.

  • +
  • Added Signed Distance Field actor.

  • +
  • Added a new UI ComboBox.

  • +
  • Added multiples primitives (Rhombocuboctahedron, …).

  • +
  • Huge improvement of multiple UIs and actors.

  • +
  • Fixed Compatibility with VTK9.

  • +
  • Large documentation update, examples and tutorials (5 new).

  • +
  • Added a blog system.

  • +
  • Increased tests coverage and code quality.

  • +
+
+
+

Details#

+

GitHub stats for 2020/04/09 - 2020/07/20 (tag: v0.5.1)

+

These lists are automatically generated, and may be incomplete or contain duplicates.

+

The following 9 authors contributed 266 commits.

+
    +
  • Eleftherios Garyfallidis

  • +
  • Liam Donohue

  • +
  • Marc-Alexandre Côté

  • +
  • Melina Raglin

  • +
  • Naman Bansal

  • +
  • Serge Koudoro

  • +
  • Soham Biswas

  • +
  • Tushar

  • +
  • Lenix Lobo

  • +
+

We closed a total of 60 issues, 25 pull requests and 35 regular issues; +this is the full list (generated with the script +tools/github_stats.py):

+

Pull Requests (25):

+
    +
  • PR #241: Adding a Blog system to fury

  • +
  • PR #268: Clip Text Overflow

  • +
  • PR #267: SDF tutorial

  • +
  • PR #250: SDF based FURY actors

  • +
  • PR #246: ComboBox UI tutorial

  • +
  • PR #265: Adding new Earth coordinates tutorial

  • +
  • PR #240: ComboBox2D UI element

  • +
  • PR #169: Use primitive for box, cube, square, rectangle actors

  • +
  • PR #262: Solar System Tutorial

  • +
  • PR #248: Setting Bounding Box for TextBlock2D

  • +
  • PR #263: [NF] Deprecated parameters

  • +
  • PR #127: [CI] add Python 3.8

  • +
  • PR #255: Let VTK delete timers on exit.

  • +
  • PR #233: Picking API and picking tutorial

  • +
  • PR #261: Adding Earth Animation Tutorial

  • +
  • PR #249: Octagonal Prism and Frustum Square Pyramid

  • +
  • PR #258: Updating test of order_transparency for compatibility with vtk 9

  • +
  • PR #259: Updated Step 3 in README.rst

  • +
  • PR #231: Adding Double Click Callback

  • +
  • PR #256: Install ssl certificate for azure pipeline windows

  • +
  • PR #245: [FIX] Compatibility with VTK 9

  • +
  • PR #244: Added new texture tutorial

  • +
  • PR #235: Function to use Hexadecimal color code in Colormap

  • +
  • PR #238: Added Rhombocuboctahedron, 2D and 3D star to primitive

  • +
  • PR #237: update copyright years

  • +
+

Issues (35):

+
    +
  • #241: Adding a Blog system to fury

  • +
  • #268: Clip Text Overflow

  • +
  • #264: Re-implementation of Text Overflow in ListBox2D

  • +
  • #267: SDF tutorial

  • +
  • #247: PR idea: create SDF alternatives to FURY primitive actors

  • +
  • #250: SDF based FURY actors

  • +
  • #246: ComboBox UI tutorial

  • +
  • #265: Adding new Earth coordinates tutorial

  • +
  • #240: ComboBox2D UI element

  • +
  • #169: Use primitive for box, cube, square, rectangle actors

  • +
  • #138: Box, cone etc. to work similarly to superquadric

  • +
  • #262: Solar System Tutorial

  • +
  • #248: Setting Bounding Box for TextBlock2D

  • +
  • #263: [NF] Deprecated parameters

  • +
  • #127: [CI] add Python 3.8

  • +
  • #51: Improvements from VTK 8.2.0?

  • +
  • #255: Let VTK delete timers on exit.

  • +
  • #253: Programs with timers hang on exit. [VTK9] [Linux]

  • +
  • #233: Picking API and picking tutorial

  • +
  • #261: Adding Earth Animation Tutorial

  • +
  • #249: Octagonal Prism and Frustum Square Pyramid

  • +
  • #258: Updating test of order_transparency for compatibility with vtk 9

  • +
  • #254: unexpected order transparent behavior [VTK9] [Ubuntu 18.04]

  • +
  • #259: Updated Step 3 in README.rst

  • +
  • #251: Developer installation instructions should describe -e option

  • +
  • #226: Adding double-click event

  • +
  • #231: Adding double-click Callback

  • +
  • #256: Install ssl certificate for azure pipeline windows

  • +
  • #245: [FIX] Compatibility with VTK 9

  • +
  • #244: Added new texture tutorial

  • +
  • #235: Function to use Hexadecimal color code in Colormap

  • +
  • #238: Added Rhombocuboctahedron, 2D and 3D star to primitive

  • +
  • #197: Added Rhombocuboctahedron, 2D and 3D star to primitive

  • +
  • #237: update copyright years

  • +
  • #216: Utiltiy function to use Hexadecimal color code

  • +
+
+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ +
+ On this page +
+ +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/release_notes/releasev0.6.1.html b/v0.10.x/release_notes/releasev0.6.1.html new file mode 100644 index 000000000..cfdd27b96 --- /dev/null +++ b/v0.10.x/release_notes/releasev0.6.1.html @@ -0,0 +1,601 @@ + + + + + + + + Release notes v0.6.1 (2020-08-20) — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ + +
+ + +
+
+ +
+ +
+ + +
+ +
+

Release notes v0.6.1 (2020-08-20)#

+
+

Quick Overview#

+
    +
  • Added Shaders Manager.

  • +
  • Standardized colors across API.

  • +
  • Added a new UI Tab.

  • +
  • Added Physics Engine Tutorial.

  • +
  • Large documentation update, examples and tutorials (4 new).

  • +
  • Increased tests coverage and code quality.

  • +
+
+
+

Details#

+

GitHub stats for 2020/07/21 - 2020/08/20 (tag: v0.6.0)

+

These lists are automatically generated, and may be incomplete or contain duplicates.

+

The following 8 authors contributed 164 commits.

+
    +
  • Eleftherios Garyfallidis

  • +
  • Javier Guaje

  • +
  • Lenix Lobo

  • +
  • Melina Raglin

  • +
  • Nasim Anousheh

  • +
  • Serge Koudoro

  • +
  • Soham Biswas

  • +
  • Vivek Choudhary

  • +
+

We closed a total of 42 issues, 15 pull requests and 27 regular issues; +this is the full list (generated with the script +tools/github_stats.py):

+

Pull Requests (15):

+
    +
  • PR #288: Shader manager

  • +
  • PR #292: Disable VTK Warnings on release version

  • +
  • PR #289: Rename parameter scale to scales

  • +
  • PR #287: Add Physics simulation examples.

  • +
  • PR #284: Colliding particles in the box

  • +
  • PR #275: Tab UI tutorial

  • +
  • PR #208: Added tutorial for RadioButton and CheckBox UI

  • +
  • PR #281: Radio checkbox tutorial using Fury API

  • +
  • PR #283: Standardize colors across API

  • +
  • PR #282: Standardize Colors array name

  • +
  • PR #252: Tab ui

  • +
  • PR #279: Decreasing the size of the sun in solarsystem tutorial

  • +
  • PR #273: Python GSoC Weekly blogs

  • +
  • PR #276: Update Deprecated test

  • +
  • PR #272: Python GSoC Blogs upto 19th July 2020

  • +
+

Issues (27):

+
    +
  • #260: Changes to shader API in VTK 9

  • +
  • #116: Update Shader system

  • +
  • #288: Shader manager

  • +
  • #292: Disable VTK Warnings on release version

  • +
  • #270: Disable VTK Warnings on release version

  • +
  • #289: Rename parameter scale to scales

  • +
  • #236: Pybullet examples

  • +
  • #287: Add Physics simulation examples.

  • +
  • #205: Create a tutorial for checkbox/radiobutton UI

  • +
  • #284: Colliding particles in the box

  • +
  • #275: Tab UI tutorial

  • +
  • #208: Added tutorial for RadioButton and CheckBox UI

  • +
  • #281: Radio checkbox tutorial using Fury API

  • +
  • #283: Standardize colors across API

  • +
  • #269: Fixed bug in tutorial with accessing colors for latest release

  • +
  • #242: Standardize colors across API

  • +
  • #243: Single Color in Primitive Does Not Work

  • +
  • #271: Some issues with actor.box after release 0.6.0

  • +
  • #282: Standardize Colors array name

  • +
  • #280: Unable to extract colors from a Box

  • +
  • #252: Tab ui

  • +
  • #279: Decreasing the size of the sun in solarsystem tutorial

  • +
  • #278: Changing Size of Sun in viz_solar_system.py Tutorial

  • +
  • #273: Python GSoC Weekly blogs

  • +
  • #277: Sun

  • +
  • #276: Update Deprecated test

  • +
  • #272: Python GSoC Blogs upto 19th July 2020

  • +
+
+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ +
+ On this page +
+ +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/release_notes/releasev0.7.0.html b/v0.10.x/release_notes/releasev0.7.0.html new file mode 100644 index 000000000..6547a9fc0 --- /dev/null +++ b/v0.10.x/release_notes/releasev0.7.0.html @@ -0,0 +1,665 @@ + + + + + + + + Release notes v0.7.0 (2021/03/13) — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ + +
+ + +
+
+ +
+ +
+ + +
+ +
+

Release notes v0.7.0 (2021/03/13)#

+
+

Quick Overview#

+
    +
  • New SDF actors added.

  • +
  • Materials module added.

  • +
  • ODF slicer actor performance improved.

  • +
  • New primitive (Cylinder) added.

  • +
  • Compatibility with VTK 9 added.

  • +
  • Five new demos added.

  • +
  • Large Documentation Update.

  • +
  • Migration from Travis to Github Action.

  • +
+
+
+

Details#

+

GitHub stats for 2020/08/20 - 2021/03/13 (tag: v0.6.1)

+

These lists are automatically generated, and may be incomplete or contain duplicates.

+

The following 14 authors contributed 195 commits.

+
    +
  • Eleftherios Garyfallidis

  • +
  • Serge Koudoro

  • +
  • Charles Poirier

  • +
  • Javier Guaje

  • +
  • Soham Biswas

  • +
  • Sajag Swami

  • +
  • Lenix Lobo

  • +
  • Pietro Astolfi

  • +
  • Sanjay Marreddi

  • +
  • Tushar

  • +
  • ganimtron-10

  • +
  • haran2001

  • +
  • Aju100

  • +
  • Aman Soni

  • +
+

We closed a total of 98 issues, 37 pull requests and 61 regular issues; +this is the full list (generated with the script +tools/github_stats.py):

+

Pull Requests (37):

+
    +
  • PR #388: added simulation for brownian motion

  • +
  • PR #389: ENH: peaks_slicer option for asymmetric peaks visualization

  • +
  • PR #370: Materials module including Physically Based Rendering (PBR)

  • +
  • PR #385: fixed the example for superquadric function

  • +
  • PR #387: [fix] Propagate update_actor

  • +
  • PR #382: Added an sdf for rendering a Capsule actor

  • +
  • PR #383: Minor documentation fix

  • +
  • PR #376: Added animations for some electromagnetic phenomena

  • +
  • PR #374: ENH: Refactor actor.odf_slicer for increased performances

  • +
  • PR #373: Updated actor.py

  • +
  • PR #368: Solving The Minor Documentation Error

  • +
  • PR #343: Adding physics engine integration docs

  • +
  • PR #353: fix: Minor docs changes

  • +
  • PR #346: Fix the sdf bug by checking the arguments passed

  • +
  • PR #351: Opacity bug fix for point and sphere actors

  • +
  • PR #350: modelsuzanne to suzanne

  • +
  • PR #348: Added center forwarding in billboard shaders.

  • +
  • PR #341: Add Option to generate the documentation without examples

  • +
  • PR #342: From Travis to Github Actions

  • +
  • PR #339: Update Readme information

  • +
  • PR #340: Pass OAuth token through header

  • +
  • PR #337: Add support for clipping side in clip_overflow_text

  • +
  • PR #336: Update UI tutorials.

  • +
  • PR #334: Added Domino-Simulation-file for Review

  • +
  • PR #332: Fixing UI warnings

  • +
  • PR #328: Added cylinder primitive

  • +
  • PR #329: [FIX] Force LUT to be RGB

  • +
  • PR #286: GSoC blogs for Third Evaluation.

  • +
  • PR #319: fixed discord icon bug in documentation

  • +
  • PR #311: Remove python35 from Travis

  • +
  • PR #307: Fixed translating and scaling issues on billboard and SDF actors

  • +
  • PR #304: Blogs for the final review

  • +
  • PR #306: merged basic UI and advanced UI tutorials into one

  • +
  • PR #302: moved physics tutorials to examples under the heading ‘Integrate physics using pybullet’

  • +
  • PR #303: FIX vtp reader

  • +
  • PR #300: BF: Out should be varying and alpha is not passed to shader

  • +
  • PR #295: Update fetcher

  • +
+

Issues (61):

+
    +
  • #388: added simulation for brownian motion

  • +
  • #389: ENH: peaks_slicer option for asymmetric peaks visualization

  • +
  • #370: Materials module including Physically Based Rendering (PBR)

  • +
  • #385: fixed the example for superquadric function

  • +
  • #387: [fix] Propagate update_actor

  • +
  • #382: Added an sdf for rendering a Capsule actor

  • +
  • #383: Minor documentation fix

  • +
  • #376: Added animations for some electromagnetic phenomena

  • +
  • #374: ENH: Refactor actor.odf_slicer for increased performances

  • +
  • #364: New Animated Network Demo/Example

  • +
  • #379: Merge pull request #2 from fury-gl/master

  • +
  • #361: Closes #352

  • +
  • #373: Updated actor.py

  • +
  • #372: Ellipsoid primitive needs to be added in the comment section of sdf actor.

  • +
  • #369: Added Special Character Support

  • +
  • #363: Minor error in documentation of create_colormap function

  • +
  • #368: Solving The Minor Documentation Error

  • +
  • #366: added special character support for TextBox2D

  • +
  • #357: Patches: vulnerable code that can lead to RCE

  • +
  • #359: unwanted objects rendering randomly

  • +
  • #343: Adding physics engine integration docs

  • +
  • #312: Adding Physics Integration Docs to FURY’s Website

  • +
  • #353: fix: Minor docs changes

  • +
  • #346: Fix the sdf bug by checking the arguments passed

  • +
  • #310: Rendering bug in SDF actor when not all primitives are defined

  • +
  • #351: Opacity bug fix for point and sphere actors

  • +
  • #335: _opacity argument for point doesn’t seem to work

  • +
  • #345: Fixes the opacity bug for sphere and point actors (unit tests are included)

  • +
  • #350: modelsuzanne to suzanne

  • +
  • #348: Added center forwarding in billboard shaders.

  • +
  • #341: Add Option to generate the documentation without examples

  • +
  • #342: From Travis to Github Actions

  • +
  • #338: From travis (pricing model changed) to github Actions ?

  • +
  • #339: Update Readme information

  • +
  • #340: Pass OAuth token through header

  • +
  • #315: Deprecation notice for authentication via URL query parameters

  • +
  • #337: Add support for clipping side in clip_overflow_text

  • +
  • #308: Clipping overflowing text from the left.

  • +
  • #336: Update UI tutorials.

  • +
  • #334: Added Domino-Simulation-file for Review

  • +
  • #309: Domino Physics Simulation

  • +
  • #333: Unable to set up the project locally for python 32bit system

  • +
  • #332: Fixing UI warnings

  • +
  • #239: Superquadric Slicer

  • +
  • #328: Added cylinder primitive

  • +
  • #318: Cylinder primitive generation

  • +
  • #329: [FIX] Force LUT to be RGB

  • +
  • #286: GSoC blogs for Third Evaluation.

  • +
  • #319: fixed discord icon bug in documentation

  • +
  • #313: Discord icon should appear in doc too

  • +
  • #311: Remove python35 from Travis

  • +
  • #307: Fixed translating and scaling issues on billboard and SDF actors

  • +
  • #274: SDF rendering bug for low scale values

  • +
  • #304: Blogs for the final review

  • +
  • #306: merged basic UI and advanced UI tutorials into one

  • +
  • #297: Update Demos/tutorial

  • +
  • #302: moved physics tutorials to examples under the heading ‘Integrate physics using pybullet’

  • +
  • #298: Wrecking Ball Simulation

  • +
  • #303: FIX vtp reader

  • +
  • #300: BF: Out should be varying and alpha is not passed to shader

  • +
  • #295: Update fetcher

  • +
+
+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ +
+ On this page +
+ +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/release_notes/releasev0.7.1.html b/v0.10.x/release_notes/releasev0.7.1.html new file mode 100644 index 000000000..4a53ebea1 --- /dev/null +++ b/v0.10.x/release_notes/releasev0.7.1.html @@ -0,0 +1,656 @@ + + + + + + + + Release notes v0.7.1 (2021/08/03) — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ + +
+ + +
+
+ +
+ +
+ + +
+ +
+

Release notes v0.7.1 (2021/08/03)#

+
+

Quick Overview#

+
    +
  • FURY paper added.

  • +
  • Fast selection of multiple objects added.

  • +
  • UI refactored.

  • +
  • Tests coverage increased.

  • +
  • New actor (Marker) added.

  • +
  • New primitive (Triangular Prism) added.

  • +
  • Demos added and updated.

  • +
  • Large Documentation Update.

  • +
+
+
+

Details#

+

GitHub stats for 2021/03/13 - 2021/08/03 (tag: v0.7.0)

+

These lists are automatically generated, and may be incomplete or contain duplicates.

+

The following 15 authors contributed 211 commits.

+
    +
  • Amit Chaudhari

  • +
  • Antriksh Misri

  • +
  • Bruno Messias

  • +
  • Daniel S. Katz

  • +
  • Eleftherios Garyfallidis

  • +
  • Gurdit Siyan

  • +
  • Javier Guaje

  • +
  • Jhalak Gupta

  • +
  • LoopThrough-i-j

  • +
  • MIHIR

  • +
  • Praneeth Shetty

  • +
  • Sajag Swami

  • +
  • Serge Koudoro

  • +
  • Hariharan Ayappane

  • +
+

We closed a total of 89 issues, 35 pull requests and 54 regular issues; +this is the full list (generated with the script +tools/github_stats.py):

+

Pull Requests (35):

+
    +
  • PR #475: Gsoc blog 2021

  • +
  • PR #476: Google Summer of Code blog posts

  • +
  • PR #477: added blog posts for GSoC’21

  • +
  • PR #442: added method to wrap overflowing text

  • +
  • PR #441: Added border support in Panel2D

  • +
  • PR #466: two more small bib changes

  • +
  • PR #464: Paper Dan’s Comments

  • +
  • PR #459: extracted Button2D class from elements to core

  • +
  • PR #430: Surface actor colormap fix

  • +
  • PR #456: Updated about documentation

  • +
  • PR #455: Fixed bibtex

  • +
  • PR #454: Added missing DOIs and URLs

  • +
  • PR #451: Typo fix

  • +
  • PR #447: UI refactoring

  • +
  • PR #438: Fast selection of multiple objects in 3D using GPU acceleration

  • +
  • PR #420: added an example about graph-tool and nested stochastic block model

  • +
  • PR #422: This allow to draw markers using shaders

  • +
  • PR #444: Remove deprecated functions

  • +
  • PR #440: added support for URL image in ImageContainer2D

  • +
  • PR #356: Render a video on an actor.

  • +
  • PR #436: [Fix] Update Azure pipeline for windows

  • +
  • PR #434: WIP: added tests for layout module

  • +
  • PR #426: Allows to define the priority of a shader_callback and obtain the vtkEventId

  • +
  • PR #394: Fixed warnings in test_utils.py

  • +
  • PR #415: update sk orcid

  • +
  • PR #413: add nanohub doi

  • +
  • PR #412: fix paper doi

  • +
  • PR #386: FURY paper for Journal of Open Source Software (JOSS)

  • +
  • PR #371: Textbox2d special character support

  • +
  • PR #408: Updating the Missing Parenthesis

  • +
  • PR #406: Removed unused library in FURY tutorial

  • +
  • PR #405: Updating Redirecting Issues in Readme

  • +
  • PR #399: Resolve warnings #317 & and Fix Issue: #355

  • +
  • PR #393: added primitive and actor for triangular prism, added tests too

  • +
  • PR #396: #317 Fixing Warnings during test : test_actors.py

  • +
+

Issues (54):

+
    +
  • #407: UI Textbox background doesn’t resize according to text in it.

  • +
  • #421: Implementing the Resizing of Listbox

  • +
  • #416: Fixing the Resizing Background issue of TextBox2D UI.

  • +
  • #475: Gsoc blog 2021

  • +
  • #476: Google Summer of Code blog posts

  • +
  • #477: added blog posts for GSoC’21

  • +
  • #442: added method to wrap overflowing text

  • +
  • #441: Added border support in Panel2D

  • +
  • #466: two more small bib changes

  • +
  • #464: Paper Dan’s Comments

  • +
  • #445: [WIP] Example to show how to render multiple bonds

  • +
  • #410: added BulletList to UI

  • +
  • #459: extracted Button2D class from elements to core

  • +
  • #429: Colormap not working as intended with surface actor

  • +
  • #430: Surface actor colormap fix

  • +
  • #450: Issue with references related to JOSS review

  • +
  • #456: Updated about documentation

  • +
  • #455: Fixed bibtex

  • +
  • #454: Added missing DOIs and URLs

  • +
  • #453: Add missing DOIs and URLs

  • +
  • #451: Typo fix

  • +
  • #439: [WIP] Space filling model

  • +
  • #447: UI refactoring

  • +
  • #438: Fast selection of multiple objects in 3D using GPU acceleration

  • +
  • #420: added an example about graph-tool and nested stochastic block model

  • +
  • #422: This allow to draw markers using shaders

  • +
  • #444: Remove deprecated functions

  • +
  • #440: added support for URL image in ImageContainer2D

  • +
  • #356: Render a video on an actor.

  • +
  • #436: [Fix] Update Azure pipeline for windows

  • +
  • #434: WIP: added tests for layout module

  • +
  • #403: Creating test for layout module

  • +
  • #411: Added Layout test file

  • +
  • #426: Allows to define the priority of a shader_callback and obtain the vtkEventId

  • +
  • #417: Fixing pep issues

  • +
  • #394: Fixed warnings in test_utils.py

  • +
  • #415: update sk orcid

  • +
  • #414: Duplicate ORCIDs in the JOSS paper

  • +
  • #413: add nanohub doi

  • +
  • #412: fix paper doi

  • +
  • #386: FURY paper for Journal of Open Source Software (JOSS)

  • +
  • #371: Textbox2d special character support

  • +
  • #409: Segmentation Fault When Running Fury Tests

  • +
  • #408: Updating the Missing Parenthesis

  • +
  • #406: Removed unused library in FURY tutorial

  • +
  • #405: Updating Redirecting Issues in Readme

  • +
  • #375: Visuals for some parametric 2D functions

  • +
  • #317: Track and fix warnings during tests.

  • +
  • #355: [Vulnerability Bug] Used blacklisted dangerous function call that can lead to RCE

  • +
  • #399: Resolve warnings #317 & and Fix Issue: #355

  • +
  • #393: added primitive and actor for triangular prism, added tests too

  • +
  • #395: FURY installation conflict

  • +
  • #396: #317 Fixing Warnings during test : test_actors.py

  • +
  • #358: Updated io.py

  • +
+
+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ +
+ On this page +
+ +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/release_notes/releasev0.8.0.html b/v0.10.x/release_notes/releasev0.8.0.html new file mode 100644 index 000000000..8ece440b1 --- /dev/null +++ b/v0.10.x/release_notes/releasev0.8.0.html @@ -0,0 +1,648 @@ + + + + + + + + Release notes v0.8.0 (2022/01/31) — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ + +
+ + +
+
+ +
+ +
+ + +
+ +
+

Release notes v0.8.0 (2022/01/31)#

+
+

Quick Overview#

+
    +
  • New Physically Based Rendering (PBR) added. It includes anisotropic rotation and index of refraction among other material properties.

  • +
  • New Principled BRDF shader unique to FURY added. BRDF stands for bidirectional reflectance distribution function.

  • +
  • VTK 9.1.0 defined as minimum version.

  • +
  • Continuous Integration (CI) platform updated.

  • +
  • New actors added (Rhombicuboctahedron, Pentagonal Prism).

  • +
  • New UI layouts added (Vertical and Horizontal).

  • +
  • New module fury.molecular added.

  • +
  • New module fury.lib added. Module improved loading speed.

  • +
  • Demos added and updated.

  • +
  • Documentation updated.

  • +
+
+
+

Details#

+

GitHub stats for 2021/08/03 - 2022/01/28 (tag: v0.7.1)

+

These lists are automatically generated, and may be incomplete or contain duplicates.

+

The following 12 authors contributed 500 commits.

+
    +
  • Anand Shivam

  • +
  • Antriksh Misri

  • +
  • Bruno Messias

  • +
  • Eleftherios Garyfallidis

  • +
  • Javier Guaje

  • +
  • Marc-Alexandre Côté

  • +
  • Meha Bhalodiya

  • +
  • Praneeth Shetty

  • +
  • PrayasJ

  • +
  • Sajag Swami

  • +
  • Serge Koudoro

  • +
  • Shivam Anand

  • +
+

We closed a total of 81 issues, 34 pull requests and 47 regular issues; +this is the full list (generated with the script +tools/github_stats.py):

+

Pull Requests (34):

+
    +
  • PR #523: Adding Anisotropy and Clear coat to PBR material

  • +
  • PR #536: Remove VTK_9_PLUS flag

  • +
  • PR #535: [ENH] Add missing shaders block

  • +
  • PR #532: Remove and replace vtkactor from docstring

  • +
  • PR #503: devmessias gsoc posts part 2: weeks 09, 10 and 11

  • +
  • PR #534: [FIX] remove update_user_matrix from text3d

  • +
  • PR #527: [FIX] Allow sphere actor to use faces/vertices without casting issues. In addition, update versioning system (versioneer).

  • +
  • PR #509: adding numpy_to_vtk_image_data method to utility

  • +
  • PR #507: Deprecate and rename label to vector_text

  • +
  • PR #524: [WIP] Add debugging CI Tools

  • +
  • PR #521: Snapshot flipping bug fix

  • +
  • PR #520: Added rotation along the axis in Solar System Animations example

  • +
  • PR #518: Pytest patch

  • +
  • PR #519: Principled material

  • +
  • PR #515: Changing how we do things with our test suite.

  • +
  • PR #516: Adding Rhombicuboctahedron actor

  • +
  • PR #514: [FIX] Radio button and checkbox tests

  • +
  • PR #513: [FIX] Mesa installation

  • +
  • PR #506: update tutorial import

  • +
  • PR #504: Update molecular module import

  • +
  • PR #470: Update the way we import external libraries by using only the necessary modules

  • +
  • PR #452: Molecular module

  • +
  • PR #491: Method to process and load sprite sheets

  • +
  • PR #496: Added GSoC blog posts for remaining weeks

  • +
  • PR #498: Fix disk position outside the slider line

  • +
  • PR #488: Fix material docstrings, improved standard parameters and improved materials application support

  • +
  • PR #449: Add python3.9 for our CI’s

  • +
  • PR #493: GSoC blogs 2021

  • +
  • PR #474: Add primitive and actor for pentagonal prism with test

  • +
  • PR #362: Animated Surfaces

  • +
  • PR #433: Peak representation improvements

  • +
  • PR #432: Fine-tuning of the OpenGL state

  • +
  • PR #479: Added Vertical Layout to layout module

  • +
  • PR #480: Added Horizontal Layout to layout module

  • +
+

Issues (47):

+
    +
  • #523: Adding Anisotropy and Clear coat to PBR material

  • +
  • #536: Remove VTK_9_PLUS flag

  • +
  • #535: [ENH] Add missing shaders block

  • +
  • #532: Remove and replace vtkactor from docstring

  • +
  • #503: devmessias gsoc posts part 2: weeks 09, 10 and 11

  • +
  • #534: [FIX] remove update_user_matrix from text3d

  • +
  • #526: Text justification in vtkTextActor3D

  • +
  • #500: Adding a utility function to convert a numpy array to vtkImageData

  • +
  • #527: [FIX] Allow sphere actor to use faces/vertices without casting issues. In addition, update versioning system (versioneer).

  • +
  • #400: Sphere actor does not appear when vertices and faces are used

  • +
  • #509: adding numpy_to_vtk_image_data method to utility

  • +
  • #431: Deprecation warning raised in from utils.numpy_to_vtk_cells

  • +
  • #457: Improve loading speed using partial imports

  • +
  • #468: Remove all vtk calls from tutorials and demos

  • +
  • #507: Deprecate and rename label to vector_text

  • +
  • #524: [WIP] Add debugging CI Tools

  • +
  • #521: Snapshot flipping bug fix

  • +
  • #467: Window snapshot inverts the displayed scene

  • +
  • #520: Added rotation along the axis in Solar System Animations example

  • +
  • #505: want a highlight feature

  • +
  • #518: Pytest patch

  • +
  • #519: Principled material

  • +
  • #515: Changing how we do things with our test suite.

  • +
  • #512: Flocking-simulation using boid rules

  • +
  • #516: Adding Rhombicuboctahedron actor

  • +
  • #514: [FIX] Radio button and checkbox tests

  • +
  • #513: [FIX] Mesa installation

  • +
  • #511: Flocking-simulation using boid rules

  • +
  • #506: update tutorial import

  • +
  • #504: Update molecular module import

  • +
  • #404: Parametric functions- actor, primitives

  • +
  • #470: Update the way we import external libraries by using only the necessary modules

  • +
  • #452: Molecular module

  • +
  • #469: Mismatch in parameter and docstring in manifest_standard() in material module

  • +
  • #491: Method to process and load sprite sheets

  • +
  • #496: Added GSoC blog posts for remaining weeks

  • +
  • #498: Fix disk position outside the slider line

  • +
  • #488: Fix material docstrings, improved standard parameters and improved materials application support

  • +
  • #449: Add python3.9 for our CI’s

  • +
  • #493: GSoC blogs 2021

  • +
  • #474: Add primitive and actor for pentagonal prism with test

  • +
  • #362: Animated Surfaces

  • +
  • #324: Animate a wave function

  • +
  • #433: Peak representation improvements

  • +
  • #432: Fine-tuning of the OpenGL state

  • +
  • #479: Added Vertical Layout to layout module

  • +
  • #480: Added Horizontal Layout to layout module

  • +
+
+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ +
+ On this page +
+ +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/release_notes/releasev0.9.0.html b/v0.10.x/release_notes/releasev0.9.0.html new file mode 100644 index 000000000..b5d88da47 --- /dev/null +++ b/v0.10.x/release_notes/releasev0.9.0.html @@ -0,0 +1,957 @@ + + + + + + + + Release notes v0.9.0 (2023/04/15) — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ + +
+ + +
+
+ +
+ +
+ + +
+ +
+

Release notes v0.9.0 (2023/04/15)#

+
+

Quick Overview#

+
    +
  • New Streaming System added.

  • +
  • Large improvement of Signed Distance Functions actors (SDF).

  • +
  • Continuous Integration (CI) platform updated. Migrate Windows CI from Azure to Github Actions

  • +
  • Migration from setuptools to hatching. versioning system updated also.

  • +
  • New module fury.animation added.

  • +
  • New module fury.gltf added. Module to support glTF 2.0.

  • +
  • Multiple tutorials added and updated.

  • +
  • Documentation updated.

  • +
  • Website updated.

  • +
+
+
+

Details#

+

GitHub stats for 2022/01/31 - 2023/04/14 (tag: v0.8.0)

+

These lists are automatically generated, and may be incomplete or contain duplicates.

+

The following 24 authors contributed 1835 commits.

+
    +
  • Anand Shivam

  • +
  • Antriksh Misri

  • +
  • Bruno Messias

  • +
  • Dwij Raj Hari

  • +
  • Eleftherios Garyfallidis

  • +
  • Filipi Nascimento Silva

  • +
  • Francois Rheault

  • +
  • Frank Cerasoli

  • +
  • Javier Guaje

  • +
  • Johny Daras

  • +
  • Mohamed Agour

  • +
  • Nasim Anousheh

  • +
  • Praneeth Shetty

  • +
  • Rohit Kharsan

  • +
  • Sara Hamza

  • +
  • Serge Koudoro

  • +
  • Siddharth Gautam

  • +
  • Soham Biswas

  • +
  • Sreekar Chigurupati

  • +
  • Tania Castillo

  • +
  • Zhiwen Shi

  • +
  • maharshigor

  • +
  • sailesh

  • +
  • sparshg

  • +
+

We closed a total of 379 issues, 166 pull requests and 213 regular issues; +this is the full list (generated with the script +tools/github_stats.py):

+

Pull Requests (166):

+
    +
  • PR #687: Record keyframe animation as GIF and MP4

  • +
  • PR #782: Add Codespell and update codecov

  • +
  • PR #587: Billboard tutorial

  • +
  • PR #781: Tab customization

  • +
  • PR #779: versions-corrected

  • +
  • PR #741: Remove unneeded multithreading call

  • +
  • PR #778: TabUI collapsing/expanding improvements

  • +
  • PR #777: Remove alias keyword on documentation

  • +
  • PR #771: add one condition in repeat_primitive to handle direction [-1, 0, 0], issue #770

  • +
  • PR #766: Cylinder repeat primitive

  • +
  • PR #769: Merge Demo and examples

  • +
  • PR #767: Update Peak actor shader

  • +
  • PR #677: Cylindrical billboard implementation

  • +
  • PR #765: add instruction about how to get Suzanne model

  • +
  • PR #764: ComboBox2D drop_down_button mouse callback was inside for loop

  • +
  • PR #748: some fixs and ex addition in docstrings in actor.py

  • +
  • PR #754: update viz_roi_contour.py

  • +
  • PR #760: update deprecated function get.data() to get.fdata()

  • +
  • PR #761: add instruction of how to download suzanne model for getting started page

  • +
  • PR #762: update the deprecated get_data() to get_fdata in viz_roi_contour.py in the demo section.

  • +
  • PR #756: Triangle strips 2 Triangles

  • +
  • PR #747: Connected the sliders to the right directions

  • +
  • PR #744: Update initialize management

  • +
  • PR #710: Principled update

  • +
  • PR #688: DrawPanel Update: Moving rotation_slider from DrawShape to DrawPanel

  • +
  • PR #734: Added GSoC’22 Final Report

  • +
  • PR #736: Adding GSoC’22 final report

  • +
  • PR #727: Feature/scientific domains

  • +
  • PR #478: Resolving GridUI caption error

  • +
  • PR #502: Multithreading support and examples

  • +
  • PR #740: Multithreading example simplified and refactored

  • +
  • PR #739: added a check for operating system before executing the tput command through popen in fury/data/fetcher.py update_progressbar() function

  • +
  • PR #737: remove object keyword from class

  • +
  • PR #726: Adding GSoC’22 Final Report

  • +
  • PR #735: Add precommit

  • +
  • PR #728: Fix flipped images in load, save, and snapshot

  • +
  • PR #730: Update CI and add pyproject.toml

  • +
  • PR #729: Fix links in CONTRIBUTING.rst

  • +
  • PR #725: Improve Doc management + quick fix

  • +
  • PR #724: Feature/community page

  • +
  • PR #721: Fix: Color changes on docs pages fixed

  • +
  • PR #723: Update CI’s

  • +
  • PR #722: Fix failing tests due to last numpy release

  • +
  • PR #719: Logo changes

  • +
  • PR #718: Home page mobile friendly

  • +
  • PR #717: Scientific domains enhancement

  • +
  • PR #680: Updating animation tutorials

  • +
  • PR #690: Add Timelines to ShowManager directly

  • +
  • PR #694: Separating the Timeline into Timeline and Animation

  • +
  • PR #712: Fix: segfault created by record method

  • +
  • PR #706: fix: double render call with timeline obj causes a seg fault

  • +
  • PR #700: Adding morphing support in gltf.py

  • +
  • PR #697: Adding week 14 blog

  • +
  • PR #693: Adding Week 15 Blogpost

  • +
  • PR #701: Updating fetch_viz_new_icons to fetch new icons

  • +
  • PR #685: glTF skinning animation implementation

  • +
  • PR #699: Adding Week 16 Blogpost

  • +
  • PR #698: Added blog post for week 14

  • +
  • PR #667: [WIP] Remove initialize call from multiple places

  • +
  • PR #689: GLTF actor colors from material

  • +
  • PR #643: [WIP] Adding ability to load glTF animations

  • +
  • PR #665: Timeline hierarchical transformation and fixing some issues

  • +
  • PR #686: Adding week 13 blog post

  • +
  • PR #684: Adding Week 14 Blogpost

  • +
  • PR #692: Set position and width of the PlaybackPanel

  • +
  • PR #691: Added week 13 post

  • +
  • PR #683: Adding Week 13 Blogpost

  • +
  • PR #682: Adding week 12 blog post

  • +
  • PR #681: Added blog post for week 12

  • +
  • PR #672: Adding Week 12 Blogpost

  • +
  • PR #678: DrawPanel Update: Repositioning the mode_panel and mode_text

  • +
  • PR #661: Improving vector_text

  • +
  • PR #679: DrawPanel Update: Moving repetitive functions to helpers

  • +
  • PR #674: DrawPanel Update: Separating tests to test individual features

  • +
  • PR #675: Week 11 blog post

  • +
  • PR #673: DrawPanel Update: Removing in_progress parameter while drawing shapes

  • +
  • PR #676: Adding week 11 blog post

  • +
  • PR #671: Adding Week 11 Blogpost

  • +
  • PR #623: DrawPanel Feature: Adding Rotation of shape from Center

  • +
  • PR #670: Adding week 10 blog post

  • +
  • PR #666: Adding Week 10 Blogpost

  • +
  • PR #669: Added blog post for week 10

  • +
  • PR #647: Keyframe animations and interpolators

  • +
  • PR #620: Tutorial on making a primitive using polygons and SDF

  • +
  • PR #630: Adding function to export scenes as glTF

  • +
  • PR #663: Adding week 9 blog post

  • +
  • PR #656: Week 8 blog post

  • +
  • PR #662: Week 9 blog post

  • +
  • PR #654: Adding Week 9 Blogpost

  • +
  • PR #659: Adding week 8 blog post

  • +
  • PR #650: Adding Week 8 Blogpost

  • +
  • PR #655: Fix test skybox

  • +
  • PR #645: Fixing ZeroDivisionError thrown by UI sliders when the value_range is zero (0)

  • +
  • PR #648: Adding week 7 blog post

  • +
  • PR #649: Added week 7 blog post

  • +
  • PR #646: Adding Week 7 Blogpost

  • +
  • PR #641: Week 6 blog post

  • +
  • PR #644: Adding week 6 blog post

  • +
  • PR #638: Adding Week 6 Blogpost

  • +
  • PR #639: Migrate Windows from Azure to GHA

  • +
  • PR #634: Prevented calling on_change when slider value is set without user intervention

  • +
  • PR #637: Adding week 5 blog post

  • +
  • PR #632: Bugfix: Visibility issues with ListBox2D

  • +
  • PR #610: Add DPI support for window snapshots

  • +
  • PR #633: Added week 5 blog post

  • +
  • PR #617: Added primitives count to the the Actor’s polydata

  • +
  • PR #624: Adding Week 5 BlogPost

  • +
  • PR #627: Adding week 4 blog post

  • +
  • PR #625: Added week 4 blog post

  • +
  • PR #600: Adding support for importing simple glTF files

  • +
  • PR #622: Adding week 3 blog post

  • +
  • PR #619: Week 3 blog post.

  • +
  • PR #621: Adding Week 4 Blogpost

  • +
  • PR #616: Fixing API limits reached issue in gltf fetcher

  • +
  • PR #611: Adding Week 3 BlogPost

  • +
  • PR #614: Added week 2 blog

  • +
  • PR #615: Added blog post for week 2

  • +
  • PR #607: Adding Week 2 Blog Post

  • +
  • PR #599: Creating DrawPanel UI

  • +
  • PR #606: Added week 1 post

  • +
  • PR #608: Adding week 1 blog post

  • +
  • PR #597: Added an accurate way to get the FPS for the showManager

  • +
  • PR #605: Adding Week1 Blog Post

  • +
  • PR #501: Creating an off_focus hook in TextBox2D

  • +
  • PR #602: Added support for fetching gltf samples

  • +
  • PR #609: Creating a fetcher to fetch new icons

  • +
  • PR #601: Updating author’s name in README

  • +
  • PR #593: Support empty ArraySequence in saving (for empty vtk)

  • +
  • PR #598: Timer id is returned after creating the timer.

  • +
  • PR #581: Keep original dtype for offsets in vtk format

  • +
  • PR #595: changed use_primitive to false by default

  • +
  • PR #589: First blog: GSoC

  • +
  • PR #586: Added my first blog post

  • +
  • PR #594: Fixed multi_samples not being used.

  • +
  • PR #591: Fixed some old tutorials.

  • +
  • PR #590: Adding Pre-GSoC Journey Blog Post

  • +
  • PR #584: Changing dot actor

  • +
  • PR #582: Deprecation of the function shaders.load

  • +
  • PR #580: Update website

  • +
  • PR #437: FURY Streaming System Proposal

  • +
  • PR #574: symmetric parameter for peak

  • +
  • PR #561: Shader API improvements

  • +
  • PR #533: Sphere actor uses repeat_primitive by default

  • +
  • PR #577: Added play/pause buttons

  • +
  • PR #443: Adapt GridLayout to work with UI

  • +
  • PR #570: Function to save screenshots with magnification factor

  • +
  • PR #486: Added x,y,z layouts to the layout module.

  • +
  • PR #547: Cone actor uses repeat_primitive by default

  • +
  • PR #552: Modified Arrow actor to use repeat primitive by default

  • +
  • PR #555: Fixed the rotation matrix in repeat_primitive.

  • +
  • PR #569: Add new example/demo: three-dimensional fractals

  • +
  • PR #572: Fixed the static path in configuration file for docs

  • +
  • PR #571: Fix vertex order in prim_tetrahedron

  • +
  • PR #567: Replace theme in requirements/docs.txt

  • +
  • PR #566: Update Website Footer

  • +
  • PR #551: Fixed #550 : Added necessary alignment between glyph creation and ac…

  • +
  • PR #559: Added simulation for Tesseract

  • +
  • PR #556: Updated code of viz_network_animated to use fury.utils

  • +
  • PR #565: Minor documentation fixes

  • +
  • PR #563: New website changes

  • +
  • PR #564: Record should not make the window appear

  • +
  • PR #557: Check to see if file exists before opening

  • +
  • PR #560: Force mesa update

  • +
  • PR #544: Improve setuptools

  • +
  • PR #542: Re-enabling nearly all under investigation tests

  • +
  • PR #537: Add OpenGL flags for offscreen rendering

  • +
+

Issues (213):

+
    +
  • #713: The docs generation fails with pyData theme v0.11.0

  • +
  • #687: Record keyframe animation as GIF and MP4

  • +
  • #782: Add Codespell and update codecov

  • +
  • #587: Billboard tutorial

  • +
  • #781: Tab customization

  • +
  • #779: versions-corrected

  • +
  • #741: Remove unneeded multithreading call

  • +
  • #776: TabUI collapsing/expanding improvements

  • +
  • #778: TabUI collapsing/expanding improvements

  • +
  • #777: Remove alias keyword on documentation

  • +
  • #770: Directions of arrow actor do not change in repeat_primitive = False method (VTK)

  • +
  • #732: [WIP] integrating latex to fury

  • +
  • #771: add one condition in repeat_primitive to handle direction [-1, 0, 0], issue #770

  • +
  • #766: Cylinder repeat primitive

  • +
  • #769: Merge Demo and examples

  • +
  • #772: test for peak_slicer() cannot pass

  • +
  • #767: Update Peak actor shader

  • +
  • #82: GLTF 2.0

  • +
  • #354: Some Typos & Grammatical Errors to be fixed in WIKI GSOC 2021

  • +
  • #677: Cylindrical billboard implementation

  • +
  • #765: add instruction about how to get Suzanne model

  • +
  • #764: ComboBox2D drop_down_button mouse callback was inside for loop

  • +
  • #748: some fixs and ex addition in docstrings in actor.py

  • +
  • #754: update viz_roi_contour.py

  • +
  • #760: update deprecated function get.data() to get.fdata()

  • +
  • #761: add instruction of how to download suzanne model for getting started page

  • +
  • #762: update the deprecated get_data() to get_fdata in viz_roi_contour.py in the demo section.

  • +
  • #756: Triangle strips 2 Triangles

  • +
  • #708: Strips to triangles

  • +
  • #747: Connected the sliders to the right directions

  • +
  • #745: Getting error in installation

  • +
  • #743: Missing fury.animation

  • +
  • #709: Commented the self.initialize

  • +
  • #744: Update initialize management

  • +
  • #710: Principled update

  • +
  • #688: DrawPanel Update: Moving rotation_slider from DrawShape to DrawPanel

  • +
  • #734: Added GSoC’22 Final Report

  • +
  • #736: Adding GSoC’22 final report

  • +
  • #727: Feature/scientific domains

  • +
  • #463: GridUI throws error when captions are None

  • +
  • #478: Resolving GridUI caption error

  • +
  • #502: Multithreading support and examples

  • +
  • #740: Multithreading example simplified and refactored

  • +
  • #738: Download progress bar tries to use the tput command to determine the width of the terminal to adjust the width of the progress bar, however, when run on windows, this leaves an error message

  • +
  • #739: added a check for operating system before executing the tput command through popen in fury/data/fetcher.py update_progressbar() function

  • +
  • #737: remove object keyword from class

  • +
  • #726: Adding GSoC’22 Final Report

  • +
  • #735: Add precommit

  • +
  • #664: Improve animation module tutorial

  • +
  • #720: fix image load flip issue

  • +
  • #642: Textures are inverted in the tutorials

  • +
  • #728: Fix flipped images in load, save, and snapshot

  • +
  • #730: Update CI and add pyproject.toml

  • +
  • #729: Fix links in CONTRIBUTING.rst

  • +
  • #725: Improve Doc management + quick fix

  • +
  • #724: Feature/community page

  • +
  • #721: Fix: Color changes on docs pages fixed

  • +
  • #316: Build a sphinx theme

  • +
  • #714: Earth coordinates tutorial example upsidedown

  • +
  • #723: Update CI’s

  • +
  • #722: Fix failing tests due to last numpy release

  • +
  • #719: Logo changes

  • +
  • #718: Home page mobile friendly

  • +
  • #717: Scientific domains enhancement

  • +
  • #680: Updating animation tutorials

  • +
  • #716: tensor_slicer function has an issue with sphere argument

  • +
  • #690: Add Timelines to ShowManager directly

  • +
  • #694: Separating the Timeline into Timeline and Animation

  • +
  • #603: UI tests are failing in Ubuntu OS due to a “segmentation error”

  • +
  • #712: Fix: segfault created by record method

  • +
  • #705: [BUG] Segmentation fault error caused by Morph Stress Test

  • +
  • #706: fix: double render call with timeline obj causes a seg fault

  • +
  • #435: Fury/VTK Streaming: webrtc/rtmp

  • +
  • #704: seg fault investigation

  • +
  • #700: Adding morphing support in gltf.py

  • +
  • #697: Adding week 14 blog

  • +
  • #693: Adding Week 15 Blogpost

  • +
  • #701: Updating fetch_viz_new_icons to fetch new icons

  • +
  • #685: glTF skinning animation implementation

  • +
  • #699: Adding Week 16 Blogpost

  • +
  • #698: Added blog post for week 14

  • +
  • #667: [WIP] Remove initialize call from multiple places

  • +
  • #689: GLTF actor colors from material

  • +
  • #643: [WIP] Adding ability to load glTF animations

  • +
  • #665: Timeline hierarchical transformation and fixing some issues

  • +
  • #686: Adding week 13 blog post

  • +
  • #684: Adding Week 14 Blogpost

  • +
  • #692: Set position and width of the PlaybackPanel

  • +
  • #691: Added week 13 post

  • +
  • #683: Adding Week 13 Blogpost

  • +
  • #682: Adding week 12 blog post

  • +
  • #681: Added blog post for week 12

  • +
  • #672: Adding Week 12 Blogpost

  • +
  • #678: DrawPanel Update: Repositioning the mode_panel and mode_text

  • +
  • #661: Improving vector_text

  • +
  • #679: DrawPanel Update: Moving repetitive functions to helpers

  • +
  • #674: DrawPanel Update: Separating tests to test individual features

  • +
  • #675: Week 11 blog post

  • +
  • #673: DrawPanel Update: Removing in_progress parameter while drawing shapes

  • +
  • #676: Adding week 11 blog post

  • +
  • #671: Adding Week 11 Blogpost

  • +
  • #623: DrawPanel Feature: Adding Rotation of shape from Center

  • +
  • #670: Adding week 10 blog post

  • +
  • #666: Adding Week 10 Blogpost

  • +
  • #669: Added blog post for week 10

  • +
  • #419: Controlling Fury windows by HTC VIVE

  • +
  • #647: Keyframe animations and interpolators

  • +
  • #620: Tutorial on making a primitive using polygons and SDF

  • +
  • #630: Adding function to export scenes as glTF

  • +
  • #663: Adding week 9 blog post

  • +
  • #656: Week 8 blog post

  • +
  • #662: Week 9 blog post

  • +
  • #654: Adding Week 9 Blogpost

  • +
  • #659: Adding week 8 blog post

  • +
  • #650: Adding Week 8 Blogpost

  • +
  • #655: Fix test skybox

  • +
  • #645: Fixing ZeroDivisionError thrown by UI sliders when the value_range is zero (0)

  • +
  • #657: Put text next to a roi

  • +
  • #626: Keyframe animation with camera support

  • +
  • #648: Adding week 7 blog post

  • +
  • #649: Added week 7 blog post

  • +
  • #646: Adding Week 7 Blogpost

  • +
  • #641: Week 6 blog post

  • +
  • #644: Adding week 6 blog post

  • +
  • #638: Adding Week 6 Blogpost

  • +
  • #639: Migrate Windows from Azure to GHA

  • +
  • #618: Theme issues when docs compiled with latest sphinx-theme version

  • +
  • #634: Prevented calling on_change when slider value is set without user intervention

  • +
  • #637: Adding week 5 blog post

  • +
  • #632: Bugfix: Visibility issues with ListBox2D

  • +
  • #418: ListBox2D has resizing issues when added into TabUI

  • +
  • #610: Add DPI support for window snapshots

  • +
  • #612: [WIP] Implemented a functional prototype of the keyframes animation API

  • +
  • #613: [WIP] Added three tutorials to test the animation system and the interpolators

  • +
  • #633: Added week 5 blog post

  • +
  • #617: Added primitives count to the the Actor’s polydata

  • +
  • #624: Adding Week 5 BlogPost

  • +
  • #627: Adding week 4 blog post

  • +
  • #625: Added week 4 blog post

  • +
  • #600: Adding support for importing simple glTF files

  • +
  • #622: Adding week 3 blog post

  • +
  • #619: Week 3 blog post.

  • +
  • #621: Adding Week 4 Blogpost

  • +
  • #616: Fixing API limits reached issue in gltf fetcher

  • +
  • #611: Adding Week 3 BlogPost

  • +
  • #614: Added week 2 blog

  • +
  • #615: Added blog post for week 2

  • +
  • #607: Adding Week 2 Blog Post

  • +
  • #599: Creating DrawPanel UI

  • +
  • #606: Added week 1 post

  • +
  • #608: Adding week 1 blog post

  • +
  • #597: Added an accurate way to get the FPS for the showManager

  • +
  • #605: Adding Week1 Blog Post

  • +
  • #501: Creating an off_focus hook in TextBox2D

  • +
  • #602: Added support for fetching gltf samples

  • +
  • #609: Creating a fetcher to fetch new icons

  • +
  • #553: Refresh code of all tutorials and demos

  • +
  • #601: Updating author’s name in README

  • +
  • #593: Support empty ArraySequence in saving (for empty vtk)

  • +
  • #598: Timer id is returned after creating the timer.

  • +
  • #581: Keep original dtype for offsets in vtk format

  • +
  • #588: Fixed Sphere Creation Error on viz_pbr_interactive Tutorial

  • +
  • #596: Segmentation Faults when running Fury demos

  • +
  • #585: Double requirement given for Pillow in default.txt

  • +
  • #595: changed use_primitive to false by default

  • +
  • #589: First blog: GSoC

  • +
  • #525: Implemented vtkBillboardTextActor

  • +
  • #586: Added my first blog post

  • +
  • #594: Fixed multi_samples not being used.

  • +
  • #591: Fixed some old tutorials.

  • +
  • #590: Adding Pre-GSoC Journey Blog Post

  • +
  • #584: Changing dot actor

  • +
  • #582: Deprecation of the function shaders.load

  • +
  • #580: Update website

  • +
  • #575: Button and footer changes in docs

  • +
  • #437: FURY Streaming System Proposal

  • +
  • #574: symmetric parameter for peak

  • +
  • #561: Shader API improvements

  • +
  • #546: No replacement option for Geometry Shaders

  • +
  • #533: Sphere actor uses repeat_primitive by default

  • +
  • #528: Sphere actor needs to use repeat_primitives by default

  • +
  • #577: Added play/pause buttons

  • +
  • #443: Adapt GridLayout to work with UI

  • +
  • #570: Function to save screenshots with magnification factor

  • +
  • #486: Added x,y,z layouts to the layout module.

  • +
  • #547: Cone actor uses repeat_primitive by default

  • +
  • #529: Cone actor needs to use repeat_primitives by default

  • +
  • #530: Arrow actor needs to use repeat_primitives by default

  • +
  • #552: Modified Arrow actor to use repeat primitive by default

  • +
  • #545: Fix some tests in test_material.py

  • +
  • #554: The rotation done by repeat_primitive function is not working as it should.

  • +
  • #555: Fixed the rotation matrix in repeat_primitive.

  • +
  • #573: Segmentation Fault

  • +
  • #569: Add new example/demo: three-dimensional fractals

  • +
  • #572: Fixed the static path in configuration file for docs

  • +
  • #571: Fix vertex order in prim_tetrahedron

  • +
  • #567: Replace theme in requirements/docs.txt

  • +
  • #566: Update Website Footer

  • +
  • #550: Cylinder direction not unique.

  • +
  • #551: Fixed #550 : Added necessary alignment between glyph creation and ac…

  • +
  • #541: Allow offscreen rendering in window.record.

  • +
  • #548: Black window on screen on “window.record”.

  • +
  • #559: Added simulation for Tesseract

  • +
  • #556: Updated code of viz_network_animated to use fury.utils

  • +
  • #565: Minor documentation fixes

  • +
  • #563: New website changes

  • +
  • #564: Record should not make the window appear

  • +
  • #557: Check to see if file exists before opening

  • +
  • #560: Force mesa update

  • +
  • #549: Add time step to brownian animation and velocity components to helica…

  • +
  • #544: Improve setuptools

  • +
  • #542: Re-enabling nearly all under investigation tests

  • +
  • #537: Add OpenGL flags for offscreen rendering

  • +
+
+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ +
+ On this page +
+ +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/search.html b/v0.10.x/search.html new file mode 100644 index 000000000..8aa415ce6 --- /dev/null +++ b/v0.10.x/search.html @@ -0,0 +1,482 @@ + + + + + + Search - FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+

Search

+ + + + + + +
+
+ + + + + +
+ +
+
+
+ +
+ + + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/searchindex.js b/v0.10.x/searchindex.js new file mode 100644 index 000000000..12c5285ac --- /dev/null +++ b/v0.10.x/searchindex.js @@ -0,0 +1 @@ +Search.setIndex({"docnames": ["auto_examples/01_introductory/index", "auto_examples/01_introductory/sg_execution_times", "auto_examples/01_introductory/viz_arrow", "auto_examples/01_introductory/viz_cone", "auto_examples/01_introductory/viz_earth_animation", "auto_examples/01_introductory/viz_earth_coordinates", "auto_examples/01_introductory/viz_gltf", "auto_examples/01_introductory/viz_gltf_animated", "auto_examples/01_introductory/viz_gltf_export", "auto_examples/01_introductory/viz_morphing", "auto_examples/01_introductory/viz_multithread", "auto_examples/01_introductory/viz_picking", "auto_examples/01_introductory/viz_selection", "auto_examples/01_introductory/viz_skinning", "auto_examples/01_introductory/viz_slice", "auto_examples/01_introductory/viz_solar_system", "auto_examples/01_introductory/viz_sphere", "auto_examples/01_introductory/viz_spiky", "auto_examples/01_introductory/viz_surfaces", "auto_examples/01_introductory/viz_texture", "auto_examples/01_introductory/viz_timers", "auto_examples/04_demos/collision-particles", "auto_examples/04_demos/index", "auto_examples/04_demos/sg_execution_times", "auto_examples/04_demos/viz_advanced", "auto_examples/04_demos/viz_animated_surfaces", "auto_examples/04_demos/viz_brownian_motion", "auto_examples/04_demos/viz_bundles", "auto_examples/04_demos/viz_dt_ellipsoids", "auto_examples/04_demos/viz_emwave_animation", "auto_examples/04_demos/viz_fiber_odf", "auto_examples/04_demos/viz_fine_tuning_gl_context", "auto_examples/04_demos/viz_fractals", "auto_examples/04_demos/viz_helical_motion", "auto_examples/04_demos/viz_markers", "auto_examples/04_demos/viz_network", "auto_examples/04_demos/viz_network_animated", "auto_examples/04_demos/viz_pbr_interactive", "auto_examples/04_demos/viz_play_video", "auto_examples/04_demos/viz_roi_contour", "auto_examples/04_demos/viz_tesseract", "auto_examples/07_ui/index", "auto_examples/07_ui/sg_execution_times", "auto_examples/07_ui/viz_buttons", "auto_examples/07_ui/viz_card", "auto_examples/07_ui/viz_card_sprite_sheet", "auto_examples/07_ui/viz_check_boxes", "auto_examples/07_ui/viz_combobox", "auto_examples/07_ui/viz_drawpanel", "auto_examples/07_ui/viz_layout", "auto_examples/07_ui/viz_radio_buttons", "auto_examples/07_ui/viz_shapes", "auto_examples/07_ui/viz_spinbox", "auto_examples/07_ui/viz_tab", "auto_examples/07_ui/viz_ui", "auto_examples/07_ui/viz_ui_listbox", "auto_examples/07_ui/viz_ui_slider", "auto_examples/10_animation/index", "auto_examples/10_animation/sg_execution_times", "auto_examples/10_animation/viz_bezier_interpolator", "auto_examples/10_animation/viz_camera", "auto_examples/10_animation/viz_color_interpolators", "auto_examples/10_animation/viz_custom_interpolator", "auto_examples/10_animation/viz_hierarchical_animation", "auto_examples/10_animation/viz_interpolators", "auto_examples/10_animation/viz_introduction", "auto_examples/10_animation/viz_robot_arm_animation", "auto_examples/10_animation/viz_spline_interpolator", "auto_examples/10_animation/viz_timeline", "auto_examples/10_animation/viz_using_time_equations", "auto_examples/13_shaders/index", "auto_examples/13_shaders/sg_execution_times", "auto_examples/13_shaders/viz_billboard_sdf_spheres", "auto_examples/13_shaders/viz_pbr_spheres", "auto_examples/13_shaders/viz_principled_spheres", "auto_examples/13_shaders/viz_sdf_cylinder", "auto_examples/13_shaders/viz_sdfactor", "auto_examples/13_shaders/viz_shader", "auto_examples/17_pybullet/index", "auto_examples/17_pybullet/sg_execution_times", "auto_examples/17_pybullet/viz_ball_collide", "auto_examples/17_pybullet/viz_brick_wall", "auto_examples/17_pybullet/viz_chain", "auto_examples/17_pybullet/viz_domino", "auto_examples/17_pybullet/viz_wrecking_ball", "auto_examples/20_stream/index", "auto_examples/20_stream/sg_execution_times", "auto_examples/20_stream/viz_interaction", "auto_examples/20_stream/viz_no_interaction", "auto_examples/20_stream/viz_widget", "auto_examples/index", "auto_examples/sg_execution_times", "blog", "community", "fury-pybullet", "getting_started", "index", "installation", "introduction", "posts/2018/2018-09-21-release-announcement", "posts/2018/2018-10-31-release-announcement", "posts/2018/2018-11-26-release-announcement", "posts/2019/2019-03-08-release-announcement", "posts/2019/2019-06-19-brain-art", "posts/2019/2019-08-02-release-announcement", "posts/2019/2019-10-29-release-announcement", "posts/2020/2020-01-05-gsoc", "posts/2020/2020-04-09-release-announcement", "posts/2020/2020-05-30-week-1-lenix", "posts/2020/2020-05-30-week-1-soham", "posts/2020/2020-06-07-week-2-lenix", "posts/2020/2020-06-07-week-2-soham", "posts/2020/2020-06-14-week-3-lenix", "posts/2020/2020-06-14-week-3-soham", "posts/2020/2020-06-21-week-4-lenix", "posts/2020/2020-06-21-week-4-soham", "posts/2020/2020-06-28-week-5-lenix", "posts/2020/2020-06-28-week-5-soham", "posts/2020/2020-07-05-week-6-lenix", "posts/2020/2020-07-05-week-6-soham", "posts/2020/2020-07-12-week-7-soham", "posts/2020/2020-07-13-week-7-lenix", "posts/2020/2020-07-19-week-8-soham", "posts/2020/2020-07-20-release-announcement", "posts/2020/2020-07-20-week-8-lenix", "posts/2020/2020-07-26-week-9-soham", "posts/2020/2020-07-27-week-9-lenix", "posts/2020/2020-08-02-week-10-lenix", "posts/2020/2020-08-02-week-10-soham", "posts/2020/2020-08-09-week-11-lenix", "posts/2020/2020-08-09-week-11-soham", "posts/2020/2020-08-16-week-12-soham", "posts/2020/2020-08-17-week-12-lenix", "posts/2020/2020-08-18-release-announcement", "posts/2020/2020-08-23-week-13-soham", "posts/2020/2020-08-24-final-work-lenix", "posts/2020/2020-08-24-final-work-soham", "posts/2020/2020-08-24-week-13-lenix", "posts/2021/2021-03-09-gsoc", "posts/2021/2021-03-13-release-announcement", "posts/2021/2021-06-08-gsoc-devmessias-1", "posts/2021/2021-06-08-week-1-antriksh", "posts/2021/2021-06-08-week-1-sajag", "posts/2021/2021-06-12-gsoc-devmessias-2", "posts/2021/2021-06-13-week-2-antriksh", "posts/2021/2021-06-14-week-2-sajag", "posts/2021/2021-06-21-gsoc-devmessias-3", "posts/2021/2021-06-21-week-3-antriksh", "posts/2021/2021-06-21-week-3-sajag", "posts/2021/2021-06-28-gsoc-devmessias-4", "posts/2021/2021-06-28-week-4-antriksh", "posts/2021/2021-06-28-week-4-sajag", "posts/2021/2021-07-05-gsoc-devmessias-5", "posts/2021/2021-07-05-week-5-antriksh", "posts/2021/2021-07-05-week-5-sajag", "posts/2021/2021-07-12-gsoc-devmessias-6", "posts/2021/2021-07-12-week-6-antriksh", "posts/2021/2021-07-12-week-6-sajag", "posts/2021/2021-07-19-gsoc-devmessias-7", "posts/2021/2021-07-19-week-7-antriksh", "posts/2021/2021-07-19-week-7-sajag", "posts/2021/2021-07-26-gsoc-devmessias-8", "posts/2021/2021-07-26-week-8-antriksh", "posts/2021/2021-07-26-week-8-sajag", "posts/2021/2021-08-02-gsoc-devmessias-9", "posts/2021/2021-08-02-week-9-antriksh", "posts/2021/2021-08-02-week-9-sajag", "posts/2021/2021-08-03-release-announcement", "posts/2021/2021-08-09-week-10-antriksh", "posts/2021/2021-08-09-week-10-sajag", "posts/2021/2021-08-16-week-11-antriksh", "posts/2021/2021-08-16-week-11-sajag", "posts/2021/2021-08-23-final-work-antriksh", "posts/2021/2021-08-23-final-work-sajag", "posts/2021/2021-08-23-gsoc-devmessias-final-report", "posts/2021/2021-09-08-gsoc-devmessias-10", "posts/2021/2021-16-08-gsoc-devmessias-11", "posts/2022/2022-01-31-release-announcement", "posts/2022/2022-02-01-gsoc", "posts/2022/2022-05-23-first-post-mohamed", "posts/2022/2022-05-24-my-journey-to-gsoc-2022-shivam", "posts/2022/2022-05-25-pre-gsoc-journey-praneeth", "posts/2022/2022-06-08-week-1-mohamed", "posts/2022/2022-06-08-week-1-praneeth", "posts/2022/2022-06-15-week-2-praneeth", "posts/2022/2022-06-20-week1-shivam", "posts/2022/2022-06-22-week-3-praneeth", "posts/2022/2022-06-28-week-2-mohamed", "posts/2022/2022-06-29-week-4-praneeth", "posts/2022/2022-06-29-week2-shivam", "posts/2022/2022-07-04-week-3-mohamed", "posts/2022/2022-07-04-week3-shivam", "posts/2022/2022-07-06-week-5-praneeth", "posts/2022/2022-07-11-week-4-mohamed", "posts/2022/2022-07-12-week4-shivam", "posts/2022/2022-07-13-week-6-praneeth", "posts/2022/2022-07-19-week-5-mohamed", "posts/2022/2022-07-19-week5-shivam", "posts/2022/2022-07-20-week-7-praneeth", "posts/2022/2022-07-25-week-6-mohamed", "posts/2022/2022-07-25-week-6-shivam", "posts/2022/2022-07-27-week-8-praneeth", "posts/2022/2022-08-01-week-7-mohamed", "posts/2022/2022-08-01-week-7-shivam", "posts/2022/2022-08-03-week-9-praneeth", "posts/2022/2022-08-09-week-08-shivam", "posts/2022/2022-08-09-week-8-mohamed", "posts/2022/2022-08-10-week-10-praneeth", "posts/2022/2022-08-16-week-9-mohamed", "posts/2022/2022-08-17-week-09-shivam", "posts/2022/2022-08-17-week-11-praneeth", "posts/2022/2022-08-23-week-10-mohamed", "posts/2022/2022-08-24-week-12-praneeth", "posts/2022/2022-08-25-week-10-shivam", "posts/2022/2022-08-30-week-11-mohamed", "posts/2022/2022-08-31-week-11-shivam", "posts/2022/2022-08-31-week-13-praneeth", "posts/2022/2022-09-07-week-14-praneeth", "posts/2022/2022-09-08-week-12-shivam", "posts/2022/2022-09-14-week-15-praneeth", "posts/2022/2022-09-15-week-13-blog", "posts/2022/2022-09-20-week-13-mohamed", "posts/2022/2022-09-21-week-16-praneeth", "posts/2022/2022-09-28-week-14-mohamed", "posts/2022/2022-09-28-week-14-shivam", "posts/2022/2022-09-7-week-12-mohamed", "posts/2023/2023-01-24-final-report-praneeth", "posts/2023/2023-01-29-final-report-mohamed", "posts/2023/2023-01-29-final-report-shivam", "posts/2023/2023-02-01-gsoc", "posts/2023/2023-04-14-release-announcement", "posts/2023/2023-05-29-week-0-joaodellagli", "posts/2023/2023-06-02-week-0-praneeth", "posts/2023/2023-06-02-week-0-tvcastillod", "posts/2023/2023-06-03-week-1-praneeth", "posts/2023/2023-06-05-week-1-joaodellagli", "posts/2023/2023-06-05-week-1-tvcastillod", "posts/2023/2023-06-11-week-2-praneeth", "posts/2023/2023-06-12-week-2-joaodellagli", "posts/2023/2023-06-12-week-2-tvcastillod", "posts/2023/2023-06-17-week-3-praneeth", "posts/2023/2023-06-19-week-3-joaodellagli", "posts/2023/2023-06-19-week-3-tvcastillod", "posts/2023/2023-06-24-week-4-praneeth", "posts/2023/2023-06-26-week-4-joaodellagli", "posts/2023/2023-06-27-week-4-tvcastillod", "posts/2023/2023-07-01-week-5-praneeth", "posts/2023/2023-07-03-week-5-joaodellagli", "posts/2023/2023-07-03-week-5-tvcastillod", "posts/2023/2023-07-08-week-6-praneeth", "posts/2023/2023-07-10-week-6-joaodellagli", "posts/2023/2023-07-10-week-6-tvcastillod", "posts/2023/2023-07-15-week-7-praneeth", "posts/2023/2023-07-17-week-7-joaodellagli", "posts/2023/2023-07-17-week-7-tvcastillod", "posts/2023/2023-07-22-week-8-praneeth", "posts/2023/2023-07-24-week-8-joaodellagli", "posts/2023/2023-07-25-week-8-tvcastillod", "posts/2023/2023-07-29-week-9-praneeth", "posts/2023/2023-07-31-week-9-joaodellagli", "posts/2023/2023-07-31-week-9-tvcastillod", "posts/2023/2023-08-05-week-10-praneeth", "posts/2023/2023-08-07-week-10-joaodellagli", "posts/2023/2023-08-08-week-10-tvcastillod", "posts/2023/2023-08-12-week-11-praneeth", "posts/2023/2023-08-14-week-11-joaodellagli", "posts/2023/2023-08-16-week-11-tvcastillod", "posts/2023/2023-08-19-week-12-praneeth", "posts/2023/2023-08-21-joaodellagli-final-report", "posts/2023/2023-08-21-week-12-joaodellagli", "posts/2023/2023-08-24-final-report-tvcastillod", "posts/2023/2023-08-24-week-12-tvcastillod", "posts/2023/2023-08-25-final-report-praneeth", "reference/fury", "reference/fury.actor", "reference/fury.actors", "reference/fury.animation", "reference/fury.colormap", "reference/fury.convert", "reference/fury.data", "reference/fury.decorators", "reference/fury.deprecator", "reference/fury.gltf", "reference/fury.io", "reference/fury.layout", "reference/fury.lib", "reference/fury.material", "reference/fury.molecular", "reference/fury.pick", "reference/fury.pkg_info", "reference/fury.primitive", "reference/fury.shaders", "reference/fury.stream", "reference/fury.transform", "reference/fury.ui", "reference/fury.utils", "reference/fury.window", "reference/index", "release-history", "release_notes/releasev0.1.0", "release_notes/releasev0.1.1", "release_notes/releasev0.1.3", "release_notes/releasev0.1.4", "release_notes/releasev0.10.0", "release_notes/releasev0.2.0", "release_notes/releasev0.3.0", "release_notes/releasev0.4.0", "release_notes/releasev0.5.1", "release_notes/releasev0.6.0", "release_notes/releasev0.6.1", "release_notes/releasev0.7.0", "release_notes/releasev0.7.1", "release_notes/releasev0.8.0", "release_notes/releasev0.9.0", "sg_execution_times", "symlink/contributing", "symlink/license"], "filenames": ["auto_examples/01_introductory/index.rst", "auto_examples/01_introductory/sg_execution_times.rst", "auto_examples/01_introductory/viz_arrow.rst", "auto_examples/01_introductory/viz_cone.rst", "auto_examples/01_introductory/viz_earth_animation.rst", "auto_examples/01_introductory/viz_earth_coordinates.rst", "auto_examples/01_introductory/viz_gltf.rst", "auto_examples/01_introductory/viz_gltf_animated.rst", "auto_examples/01_introductory/viz_gltf_export.rst", "auto_examples/01_introductory/viz_morphing.rst", "auto_examples/01_introductory/viz_multithread.rst", "auto_examples/01_introductory/viz_picking.rst", "auto_examples/01_introductory/viz_selection.rst", "auto_examples/01_introductory/viz_skinning.rst", "auto_examples/01_introductory/viz_slice.rst", "auto_examples/01_introductory/viz_solar_system.rst", "auto_examples/01_introductory/viz_sphere.rst", "auto_examples/01_introductory/viz_spiky.rst", "auto_examples/01_introductory/viz_surfaces.rst", "auto_examples/01_introductory/viz_texture.rst", "auto_examples/01_introductory/viz_timers.rst", "auto_examples/04_demos/collision-particles.rst", "auto_examples/04_demos/index.rst", "auto_examples/04_demos/sg_execution_times.rst", "auto_examples/04_demos/viz_advanced.rst", "auto_examples/04_demos/viz_animated_surfaces.rst", "auto_examples/04_demos/viz_brownian_motion.rst", "auto_examples/04_demos/viz_bundles.rst", "auto_examples/04_demos/viz_dt_ellipsoids.rst", "auto_examples/04_demos/viz_emwave_animation.rst", "auto_examples/04_demos/viz_fiber_odf.rst", "auto_examples/04_demos/viz_fine_tuning_gl_context.rst", "auto_examples/04_demos/viz_fractals.rst", "auto_examples/04_demos/viz_helical_motion.rst", "auto_examples/04_demos/viz_markers.rst", "auto_examples/04_demos/viz_network.rst", "auto_examples/04_demos/viz_network_animated.rst", "auto_examples/04_demos/viz_pbr_interactive.rst", "auto_examples/04_demos/viz_play_video.rst", "auto_examples/04_demos/viz_roi_contour.rst", "auto_examples/04_demos/viz_tesseract.rst", "auto_examples/07_ui/index.rst", "auto_examples/07_ui/sg_execution_times.rst", "auto_examples/07_ui/viz_buttons.rst", "auto_examples/07_ui/viz_card.rst", "auto_examples/07_ui/viz_card_sprite_sheet.rst", "auto_examples/07_ui/viz_check_boxes.rst", "auto_examples/07_ui/viz_combobox.rst", "auto_examples/07_ui/viz_drawpanel.rst", "auto_examples/07_ui/viz_layout.rst", "auto_examples/07_ui/viz_radio_buttons.rst", "auto_examples/07_ui/viz_shapes.rst", "auto_examples/07_ui/viz_spinbox.rst", "auto_examples/07_ui/viz_tab.rst", "auto_examples/07_ui/viz_ui.rst", "auto_examples/07_ui/viz_ui_listbox.rst", "auto_examples/07_ui/viz_ui_slider.rst", "auto_examples/10_animation/index.rst", "auto_examples/10_animation/sg_execution_times.rst", "auto_examples/10_animation/viz_bezier_interpolator.rst", "auto_examples/10_animation/viz_camera.rst", "auto_examples/10_animation/viz_color_interpolators.rst", "auto_examples/10_animation/viz_custom_interpolator.rst", "auto_examples/10_animation/viz_hierarchical_animation.rst", "auto_examples/10_animation/viz_interpolators.rst", "auto_examples/10_animation/viz_introduction.rst", "auto_examples/10_animation/viz_robot_arm_animation.rst", "auto_examples/10_animation/viz_spline_interpolator.rst", "auto_examples/10_animation/viz_timeline.rst", "auto_examples/10_animation/viz_using_time_equations.rst", "auto_examples/13_shaders/index.rst", "auto_examples/13_shaders/sg_execution_times.rst", "auto_examples/13_shaders/viz_billboard_sdf_spheres.rst", "auto_examples/13_shaders/viz_pbr_spheres.rst", "auto_examples/13_shaders/viz_principled_spheres.rst", "auto_examples/13_shaders/viz_sdf_cylinder.rst", "auto_examples/13_shaders/viz_sdfactor.rst", "auto_examples/13_shaders/viz_shader.rst", "auto_examples/17_pybullet/index.rst", "auto_examples/17_pybullet/sg_execution_times.rst", "auto_examples/17_pybullet/viz_ball_collide.rst", "auto_examples/17_pybullet/viz_brick_wall.rst", "auto_examples/17_pybullet/viz_chain.rst", "auto_examples/17_pybullet/viz_domino.rst", "auto_examples/17_pybullet/viz_wrecking_ball.rst", "auto_examples/20_stream/index.rst", "auto_examples/20_stream/sg_execution_times.rst", "auto_examples/20_stream/viz_interaction.rst", "auto_examples/20_stream/viz_no_interaction.rst", "auto_examples/20_stream/viz_widget.rst", "auto_examples/index.rst", "auto_examples/sg_execution_times.rst", "blog.rst", "community.rst", "fury-pybullet.rst", "getting_started.rst", "index.rst", "installation.rst", "introduction.rst", "posts/2018/2018-09-21-release-announcement.rst", "posts/2018/2018-10-31-release-announcement.rst", "posts/2018/2018-11-26-release-announcement.rst", "posts/2019/2019-03-08-release-announcement.rst", "posts/2019/2019-06-19-brain-art.rst", "posts/2019/2019-08-02-release-announcement.rst", "posts/2019/2019-10-29-release-announcement.rst", "posts/2020/2020-01-05-gsoc.rst", "posts/2020/2020-04-09-release-announcement.rst", "posts/2020/2020-05-30-week-1-lenix.rst", "posts/2020/2020-05-30-week-1-soham.rst", "posts/2020/2020-06-07-week-2-lenix.rst", "posts/2020/2020-06-07-week-2-soham.rst", "posts/2020/2020-06-14-week-3-lenix.rst", "posts/2020/2020-06-14-week-3-soham.rst", "posts/2020/2020-06-21-week-4-lenix.rst", "posts/2020/2020-06-21-week-4-soham.rst", "posts/2020/2020-06-28-week-5-lenix.rst", "posts/2020/2020-06-28-week-5-soham.rst", "posts/2020/2020-07-05-week-6-lenix.rst", "posts/2020/2020-07-05-week-6-soham.rst", "posts/2020/2020-07-12-week-7-soham.rst", "posts/2020/2020-07-13-week-7-lenix.rst", "posts/2020/2020-07-19-week-8-soham.rst", "posts/2020/2020-07-20-release-announcement.rst", "posts/2020/2020-07-20-week-8-lenix.rst", "posts/2020/2020-07-26-week-9-soham.rst", "posts/2020/2020-07-27-week-9-lenix.rst", "posts/2020/2020-08-02-week-10-lenix.rst", "posts/2020/2020-08-02-week-10-soham.rst", "posts/2020/2020-08-09-week-11-lenix.rst", "posts/2020/2020-08-09-week-11-soham.rst", "posts/2020/2020-08-16-week-12-soham.rst", "posts/2020/2020-08-17-week-12-lenix.rst", "posts/2020/2020-08-18-release-announcement.rst", "posts/2020/2020-08-23-week-13-soham.rst", "posts/2020/2020-08-24-final-work-lenix.rst", "posts/2020/2020-08-24-final-work-soham.rst", "posts/2020/2020-08-24-week-13-lenix.rst", "posts/2021/2021-03-09-gsoc.rst", "posts/2021/2021-03-13-release-announcement.rst", "posts/2021/2021-06-08-gsoc-devmessias-1.rst", "posts/2021/2021-06-08-week-1-antriksh.rst", "posts/2021/2021-06-08-week-1-sajag.rst", "posts/2021/2021-06-12-gsoc-devmessias-2.rst", "posts/2021/2021-06-13-week-2-antriksh.rst", "posts/2021/2021-06-14-week-2-sajag.rst", "posts/2021/2021-06-21-gsoc-devmessias-3.rst", "posts/2021/2021-06-21-week-3-antriksh.rst", "posts/2021/2021-06-21-week-3-sajag.rst", "posts/2021/2021-06-28-gsoc-devmessias-4.rst", "posts/2021/2021-06-28-week-4-antriksh.rst", "posts/2021/2021-06-28-week-4-sajag.rst", "posts/2021/2021-07-05-gsoc-devmessias-5.rst", "posts/2021/2021-07-05-week-5-antriksh.rst", "posts/2021/2021-07-05-week-5-sajag.rst", "posts/2021/2021-07-12-gsoc-devmessias-6.rst", "posts/2021/2021-07-12-week-6-antriksh.rst", "posts/2021/2021-07-12-week-6-sajag.rst", "posts/2021/2021-07-19-gsoc-devmessias-7.rst", "posts/2021/2021-07-19-week-7-antriksh.rst", "posts/2021/2021-07-19-week-7-sajag.rst", "posts/2021/2021-07-26-gsoc-devmessias-8.rst", "posts/2021/2021-07-26-week-8-antriksh.rst", "posts/2021/2021-07-26-week-8-sajag.rst", "posts/2021/2021-08-02-gsoc-devmessias-9.rst", "posts/2021/2021-08-02-week-9-antriksh.rst", "posts/2021/2021-08-02-week-9-sajag.rst", "posts/2021/2021-08-03-release-announcement.rst", "posts/2021/2021-08-09-week-10-antriksh.rst", "posts/2021/2021-08-09-week-10-sajag.rst", "posts/2021/2021-08-16-week-11-antriksh.rst", "posts/2021/2021-08-16-week-11-sajag.rst", "posts/2021/2021-08-23-final-work-antriksh.rst", "posts/2021/2021-08-23-final-work-sajag.rst", "posts/2021/2021-08-23-gsoc-devmessias-final-report.rst", "posts/2021/2021-09-08-gsoc-devmessias-10.rst", "posts/2021/2021-16-08-gsoc-devmessias-11.rst", "posts/2022/2022-01-31-release-announcement.rst", "posts/2022/2022-02-01-gsoc.rst", "posts/2022/2022-05-23-first-post-mohamed.rst", "posts/2022/2022-05-24-my-journey-to-gsoc-2022-shivam.rst", "posts/2022/2022-05-25-pre-gsoc-journey-praneeth.rst", "posts/2022/2022-06-08-week-1-mohamed.rst", "posts/2022/2022-06-08-week-1-praneeth.rst", "posts/2022/2022-06-15-week-2-praneeth.rst", "posts/2022/2022-06-20-week1-shivam.rst", "posts/2022/2022-06-22-week-3-praneeth.rst", "posts/2022/2022-06-28-week-2-mohamed.rst", "posts/2022/2022-06-29-week-4-praneeth.rst", "posts/2022/2022-06-29-week2-shivam.rst", "posts/2022/2022-07-04-week-3-mohamed.rst", "posts/2022/2022-07-04-week3-shivam.rst", "posts/2022/2022-07-06-week-5-praneeth.rst", "posts/2022/2022-07-11-week-4-mohamed.rst", "posts/2022/2022-07-12-week4-shivam.rst", "posts/2022/2022-07-13-week-6-praneeth.rst", "posts/2022/2022-07-19-week-5-mohamed.rst", "posts/2022/2022-07-19-week5-shivam.rst", "posts/2022/2022-07-20-week-7-praneeth.rst", "posts/2022/2022-07-25-week-6-mohamed.rst", "posts/2022/2022-07-25-week-6-shivam.rst", "posts/2022/2022-07-27-week-8-praneeth.rst", "posts/2022/2022-08-01-week-7-mohamed.rst", "posts/2022/2022-08-01-week-7-shivam.rst", "posts/2022/2022-08-03-week-9-praneeth.rst", "posts/2022/2022-08-09-week-08-shivam.rst", "posts/2022/2022-08-09-week-8-mohamed.rst", "posts/2022/2022-08-10-week-10-praneeth.rst", "posts/2022/2022-08-16-week-9-mohamed.rst", "posts/2022/2022-08-17-week-09-shivam.rst", "posts/2022/2022-08-17-week-11-praneeth.rst", "posts/2022/2022-08-23-week-10-mohamed.rst", "posts/2022/2022-08-24-week-12-praneeth.rst", "posts/2022/2022-08-25-week-10-shivam.rst", "posts/2022/2022-08-30-week-11-mohamed.rst", "posts/2022/2022-08-31-week-11-shivam.rst", "posts/2022/2022-08-31-week-13-praneeth.rst", "posts/2022/2022-09-07-week-14-praneeth.rst", "posts/2022/2022-09-08-week-12-shivam.rst", "posts/2022/2022-09-14-week-15-praneeth.rst", "posts/2022/2022-09-15-week-13-blog.rst", "posts/2022/2022-09-20-week-13-mohamed.rst", "posts/2022/2022-09-21-week-16-praneeth.rst", "posts/2022/2022-09-28-week-14-mohamed.rst", "posts/2022/2022-09-28-week-14-shivam.rst", "posts/2022/2022-09-7-week-12-mohamed.rst", "posts/2023/2023-01-24-final-report-praneeth.rst", "posts/2023/2023-01-29-final-report-mohamed.rst", "posts/2023/2023-01-29-final-report-shivam.rst", "posts/2023/2023-02-01-gsoc.rst", "posts/2023/2023-04-14-release-announcement.rst", "posts/2023/2023-05-29-week-0-joaodellagli.rst", "posts/2023/2023-06-02-week-0-praneeth.rst", "posts/2023/2023-06-02-week-0-tvcastillod.rst", "posts/2023/2023-06-03-week-1-praneeth.rst", "posts/2023/2023-06-05-week-1-joaodellagli.rst", "posts/2023/2023-06-05-week-1-tvcastillod.rst", "posts/2023/2023-06-11-week-2-praneeth.rst", "posts/2023/2023-06-12-week-2-joaodellagli.rst", "posts/2023/2023-06-12-week-2-tvcastillod.rst", "posts/2023/2023-06-17-week-3-praneeth.rst", "posts/2023/2023-06-19-week-3-joaodellagli.rst", "posts/2023/2023-06-19-week-3-tvcastillod.rst", "posts/2023/2023-06-24-week-4-praneeth.rst", "posts/2023/2023-06-26-week-4-joaodellagli.rst", "posts/2023/2023-06-27-week-4-tvcastillod.rst", "posts/2023/2023-07-01-week-5-praneeth.rst", "posts/2023/2023-07-03-week-5-joaodellagli.rst", "posts/2023/2023-07-03-week-5-tvcastillod.rst", "posts/2023/2023-07-08-week-6-praneeth.rst", "posts/2023/2023-07-10-week-6-joaodellagli.rst", "posts/2023/2023-07-10-week-6-tvcastillod.rst", "posts/2023/2023-07-15-week-7-praneeth.rst", "posts/2023/2023-07-17-week-7-joaodellagli.rst", "posts/2023/2023-07-17-week-7-tvcastillod.rst", "posts/2023/2023-07-22-week-8-praneeth.rst", "posts/2023/2023-07-24-week-8-joaodellagli.rst", "posts/2023/2023-07-25-week-8-tvcastillod.rst", "posts/2023/2023-07-29-week-9-praneeth.rst", "posts/2023/2023-07-31-week-9-joaodellagli.rst", "posts/2023/2023-07-31-week-9-tvcastillod.rst", "posts/2023/2023-08-05-week-10-praneeth.rst", "posts/2023/2023-08-07-week-10-joaodellagli.rst", "posts/2023/2023-08-08-week-10-tvcastillod.rst", "posts/2023/2023-08-12-week-11-praneeth.rst", "posts/2023/2023-08-14-week-11-joaodellagli.rst", "posts/2023/2023-08-16-week-11-tvcastillod.rst", "posts/2023/2023-08-19-week-12-praneeth.rst", "posts/2023/2023-08-21-joaodellagli-final-report.rst", "posts/2023/2023-08-21-week-12-joaodellagli.rst", "posts/2023/2023-08-24-final-report-tvcastillod.rst", "posts/2023/2023-08-24-week-12-tvcastillod.rst", "posts/2023/2023-08-25-final-report-praneeth.rst", "reference/fury.rst", "reference/fury.actor.rst", "reference/fury.actors.rst", "reference/fury.animation.rst", "reference/fury.colormap.rst", "reference/fury.convert.rst", "reference/fury.data.rst", "reference/fury.decorators.rst", "reference/fury.deprecator.rst", "reference/fury.gltf.rst", "reference/fury.io.rst", "reference/fury.layout.rst", "reference/fury.lib.rst", "reference/fury.material.rst", "reference/fury.molecular.rst", "reference/fury.pick.rst", "reference/fury.pkg_info.rst", "reference/fury.primitive.rst", "reference/fury.shaders.rst", "reference/fury.stream.rst", "reference/fury.transform.rst", "reference/fury.ui.rst", "reference/fury.utils.rst", "reference/fury.window.rst", "reference/index.rst", "release-history.rst", "release_notes/releasev0.1.0.rst", "release_notes/releasev0.1.1.rst", "release_notes/releasev0.1.3.rst", "release_notes/releasev0.1.4.rst", "release_notes/releasev0.10.0.rst", "release_notes/releasev0.2.0.rst", "release_notes/releasev0.3.0.rst", "release_notes/releasev0.4.0.rst", "release_notes/releasev0.5.1.rst", "release_notes/releasev0.6.0.rst", "release_notes/releasev0.6.1.rst", "release_notes/releasev0.7.0.rst", "release_notes/releasev0.7.1.rst", "release_notes/releasev0.8.0.rst", "release_notes/releasev0.9.0.rst", "sg_execution_times.rst", "symlink/contributing.rst", "symlink/license.rst"], "titles": ["Introductory", "Computation times", "Fury Arrow Actor", "Fury Cone Actor", "Texture Sphere Animation", "Earth Coordinate Conversion", "Visualizing a glTF file", "Visualizing a glTF file", "Exporting scene as a glTF file", "Morphing Animation in a glTF", "Multithreading Example", "Simple picking", "Selecting multiple objects", "Skeletal Animation in a glTF file", "Simple volume slicing", "Solar System Animation", "FURY sphere Actor", "Spiky Sphere", "Visualize surfaces", "Sphere Texture", "Using a timer", "Collisions of particles in a box", "Demos", "Computation times", "Advanced interactive visualization", "Animated 2D functions", "Brownian motion", "Visualize bundles and metrics on bundles", "Display Tensor Ellipsoids for DTI using tensor_slicer vs ellipsoid actor", "Electromagnetic Wave Propagation Animation", "Brain Fiber ODF Visualisation", "Fine-tuning the OpenGL state using shader callbacks", "Fractals", "Motion of a charged particle in a combined magnetic and electric field", "Fury Markers", "Visualize Interdisciplinary map of the journals network", "Visualize Networks (Animated version)", "Interactive PBR demo", "Play a video in the 3D world", "Visualization of ROI Surface Rendered with Streamlines", "Tesseract (Hypercube)", "User Interface Elements", "Computation times", "Buttons & Text", "Card", "Card", "Figure and Color Control using Check boxes and Radio Buttons", "ComboBox", "DrawPanel", "Using Layouts with different UI elements", "Sphere Color Control using Radio Buttons", "Simple Shapes", "SpinBox UI", "Tab UI", "User Interfaces", "ListBox", "Cube & Slider Control", "Animation", "Computation times", "Bezier Interpolator", "Keyframe animation: Camera and opacity", "Keyframe Color Interpolators", "Making a custom interpolator", "Keyframe hierarchical Animation", "Keyframe animation", "Keyframe animation introduction", "Arm Robot Animation", "Keyframes Spline Interpolator", "Timeline and setting keyframes", "Keyframe animation", "Shaders", "Computation times", "SDF Impostors on Billboards", "Physically-Based Rendering (PBR) on spheres", "Principled BRDF shader on spheres", "Make a Cylinder using polygons vs SDF", "Visualize SDF Actor", "Varying Color", "Integrate Physics using pybullet", "Computation times", "Ball Collision Simulation", "Brick Wall Simulation", "Chain Simulation", "Domino Physics Simulation", "Wrecking Ball Simulation", "Streaming", "Computation times", "Streaming FURY with user interaction", "Streaming FURY with WebRTC/MJPEG", "Streaming FURY with WebRTC/MJPEG using the Widget Object", "Tutorials", "Computation times", "Blog", "Community", "FURY - pyBullet Integration Guide", "Getting Started", "<no title>", "Installation", "About", "FURY 0.1.0 Released", "FURY 0.1.3 Released", "FURY 0.1.4 Released", "FURY 0.2.0 Released", "Success on Brain Art Competition using FURY", "FURY 0.3.0 Released", "FURY 0.4.0 Released", "Google Summer of Code", "FURY 0.5.1 Released", "Weekly Check-in #1", "Welcome to my GSoC Blog!!!", "First week of coding!!", "First week of coding!!", "Raymarching!!", "ComboBox2D Progress!!", "Raymarching continued", "TextBlock2D Progress!!", "Spherical harmonics", "May the Force be with you!!", "Spherical harmonics, Continued.", "Translation, Reposition, Rotation.", "Orientation, Sizing, Tab UI.", "Multiple SDF primitives.", "ComboBox2D, TextBlock2D, Clipping Overflow.", "FURY 0.6.0 Released", "Improvements in SDF primitives.", "Tab UI, TabPanel2D, Tab UI Tutorial.", "Merging SDF primitives.", "More Shaders!!", "Single Actor, Physics, Scrollbars.", "More Shaders!!", "Chain Simulation, Scrollbar Refactor, Tutorial Update.", "Wrecking Ball Simulation, Scrollbars Update, Physics Tutorials.", "Outline Picker", "FURY 0.6.1 Released", "Part of the Journey is the end unless its Open Source!", "Google Summer of Code 2020 Final Work Product", "Google Summer of Code Final Work Product", "Shader Showcase", "Google Summer of Code", "FURY 0.7.0 Released", "Weekly Check-In #1", "Week #1: Welcome to my weekly Blogs!", "Welcome to my GSoC Blog!", "A Stadia-like system for data visualization", "Week #2: Feature additions in UI and IO modules", "First week of coding!", "Weekly Check-In #3", "Week #3: Adapting GridLayout to work with UI", "Second week of coding!", "SOLID, monkey patching a python issue and network visualization through WebRTC", "Week #4: Adding Tree UI to the UI module", "Third week of coding!", "Weekly Check-In #5", "Week #5: Rebasing all PRs w.r.t the UI restructuring, Tree2D, Bug Fixes", "Fourth week of coding!", "Network layout algorithms using IPC", "Week #6: Bug fixes, Working on Tree2D UI", "Fifth week of coding!", "Weekly Check-In #7", "Week #7: Finalizing the stalling PRs, finishing up Tree2D UI.", "Sixth week of coding!", "Weekly Check-In #8", "Week #8: Code Cleanup, Finishing up open PRs, Continuing work on Tree2D", "Seventh week of coding!", "Week #09: Sphinx custom summary", "Week #9: More Layouts!", "Eighth coding week!", "FURY 0.7.0 Released", "Week#10: Accordion UI, Support for sprite sheet animations", "Ninth coding week!", "Week #11: Finalizing open Pull Requests", "Tenth coding week!", "Google Summer of Code Final Work Product", "Google Summer of Code Final Work Product", "Google Summer of Code 2021 - Final Report - Bruno Messias", "Week #10: SDF Fonts", "Week #11: Removing the flickering effect", "FURY 0.8.0 Released", "Contribute to FURY via Google Summer of Code 2022", "My journey till getting accepted into GSoC22", "My Journey to GSoC 2022", "Pre-GSoC Journey", "Week 1: Implementing a basic Keyframe animation API", "Week 1 - Laying the Foundation of DrawPanel UI", "Week 2 - Improving DrawPanel UI", "Week 1 - A Basic glTF Importer", "Week 3 - Dealing with Problems", "Week 2: Implementing non-linear and color interpolators", "Week 4 - Fixing the Clamping Issue", "Week 2 - Improving Fetcher and Exporting glTF", "Week 3: Redesigning the API, Implementing cubic Bezier Interpolator, and making progress on the GPU side!", "Week 3 - Fixing fetcher, adding tests and docs", "Week 5 - Working on new features", "Week 4: Camera animation, interpolation in GLSL, and a single Timeline!", "Week 4 - Finalizing glTF loader", "Week 6 - Supporting Rotation of the Shapes from the Center", "Week 5: Slerp implementation, documenting the Timeline, and adding unit tests", "Week 5 - Creating PR for glTF exporter and fixing the loader", "Week 7 - Working on Rotation PR and Trying Freehand Drawing", "Week 6: Fixing the Timeline issues and equipping it with more features", "Week 6 - Extracting the animation data", "Week 8 - Working on the polyline feature", "Week 7: Billboard spheres and implementing interpolators using closures", "Week 7 - Fixing bugs in animations", "Week 9 - Grouping and Transforming Shapes", "Week 8 - Fixing animation bugs", "Week 8: Back to the shader-based version of the Timeline", "Week 10 - Understanding Codes and Playing with Animation", "Week 9: Animating primitives of the same actor", "Week 9 - First working skeletal animation prototype", "Week 11 - Creating a base for Freehand Drawing", "Week 10: Supporting hierarchical animating", "Week 12 - Fixing translating issues and updating tests", "Week 10 - Multi-node skinning support", "Week 11: Improving tutorials a little", "Week 11 - Multiple transformations support and adding tests", "Week 13 - Separating tests and fixing bugs", "Week 14 - Updating DrawPanel architecture", "Week 12 - Adding skeleton as actors and fix global transformation", "Week 15 - Highlighting DrawShapes", "Week 13 - Multi-bone skeletal animation support", "Week 13: Keyframes animation is now a bit easier in FURY", "Week 16 - Working with Rotations!", "Week 14: Keyframes animation is now a bit easier in FURY", "Week 14 - Morphing is here!", "Week 12: Adding new tutorials", "Google Summer of Code Final Work Product", "Google Summer of Code Final Work Product", "Google Summer of Code Final Work Product", "Contribute to FURY via Google Summer of Code 2023", "FURY 0.9.0 Released", "The Beginning of Everything - Week 0", "Week 0: Community Bounding Period", "Week 0: Community Bounding Period", "Week 1: Working with SpinBox and TextBox Enhancements", "The FBO Saga - Week 1", "Week 1: Ellipsoid actor implemented with SDF", "Week 2: Tackling Text Justification and Icon Flaw Issues", "Week 2: The Importance of (good) Documentation", "Week 2: Making adjustments to the Ellipsoid Actor", "Week 3: Resolving Combobox Icon Flaw and TextBox Justification", "Week 3: Watch Your Expectations", "Week 3: Working on uncertainty and details of the first PR", "Week 4: Exam Preparations and Reviewing", "Week 4: Nothing is Ever Lost", "Week 4: First draft of the DTI uncertainty visualization", "Week 5: Trying out PRs and Planning Ahead", "Week 5: All Roads Lead to Rome", "Week 5: Preparing the data for the Ellipsoid tutorial", "Week 6: BoundingBox for TextBlock2D!", "Week 6: Things are Starting to Build Up", "Week 6: First draft of the Ellipsoid tutorial", "Week 7: Sowing the seeds for TreeUI", "Week 7: Experimentation Done", "Week 7: Adjustments on the Uncertainty Cones visualization", "Week 8: Another week with TextBlockUI", "Week 8: The Birth of a Versatile API", "Week 8: Working on Ellipsoid Tutorial and exploring SH", "Week 9: TextBlock2D is Finally Merged!", "Week 9: It is Polishing Time!", "Week 9: Tutorial done and polishing DTI uncertainty", "Week 10: Its time for a Spin-Box!", "Week 10: Ready for Review!", "Week 10 : Start of SH implementation experiments", "Week 11: Bye Bye SpinBox", "Week 11: A Refactor is Sometimes Needed", "Week 11 : Adjusting ODF implementation and looking for solutions on issues found", "Week 12: FileDialog Quest Begins!", "Google Summer of Code Final Work Product", "Week 12: Now That is (almost) a Wrap!", "Google Summer of Code Final Work Product", "Week 12 : Experimenting with ODFs implementation", "Google Summer of Code Final Work Product", "fury", "actor", "actors", "animation", "colormap", "convert", "data", "decorators", "deprecator", "gltf", "io", "layout", "lib", "material", "molecular", "pick", "pkg_info", "primitive", "shaders", "stream", "transform", "ui", "utils", "window", "API Reference", "Release History", "Release notes v0.1.0 (2018-09-21)", "Release notes v0.1.1 (2018-10-29)", "Release notes v0.1.2 and v0.1.3 (2018-10-31)", "Release notes v0.1.4 (2018-11-26)", "Release notes v0.10.0 (2024/02/28)", "Release notes v0.2.0 (2019-03-08)", "Release notes v0.3.0 (2019-08-02)", "Release notes v0.4.0 (2019-10-29)", "Release notes v0.5.1 (2020-04-01)", "Release notes v0.6.0 (2020-07-20)", "Release notes v0.6.1 (2020-08-20)", "Release notes v0.7.0 (2021/03/13)", "Release notes v0.7.1 (2021/08/03)", "Release notes v0.8.0 (2022/01/31)", "Release notes v0.9.0 (2023/04/15)", "Computation times", "Contributing", "License"], "terms": {"These": [0, 28, 32, 41, 57, 65, 70, 73, 78, 85, 90, 141, 149, 159, 165, 168, 170, 172, 181, 226, 227, 228, 256, 261, 267, 272, 277, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313], "tutori": [0, 4, 5, 6, 7, 8, 9, 11, 12, 13, 15, 17, 18, 19, 24, 28, 39, 41, 57, 60, 61, 62, 64, 65, 66, 67, 68, 69, 70, 72, 73, 75, 76, 85, 87, 97, 104, 105, 107, 122, 123, 126, 133, 134, 135, 136, 141, 142, 143, 145, 149, 159, 162, 166, 169, 170, 172, 173, 180, 181, 182, 183, 184, 190, 191, 196, 197, 199, 200, 207, 208, 211, 223, 227, 228, 230, 254, 268, 270, 279, 303, 305, 306, 307, 308, 309, 310, 311, 312, 313, 315], "show": [0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 24, 28, 29, 31, 32, 33, 34, 35, 36, 38, 39, 40, 41, 43, 44, 45, 49, 51, 52, 53, 55, 57, 60, 61, 62, 63, 65, 67, 69, 70, 72, 73, 74, 75, 76, 77, 78, 80, 81, 82, 83, 84, 85, 87, 90, 99, 100, 101, 102, 104, 105, 107, 112, 123, 133, 139, 140, 143, 145, 147, 151, 152, 155, 160, 162, 167, 170, 174, 176, 177, 180, 181, 182, 183, 202, 208, 217, 221, 228, 230, 238, 244, 248, 250, 251, 256, 259, 265, 268, 269, 270, 274, 276, 279, 292, 294, 295, 297, 304, 306, 307, 311], "how": [0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 24, 25, 27, 30, 31, 32, 34, 36, 37, 38, 41, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 61, 64, 65, 68, 70, 72, 73, 74, 75, 76, 77, 78, 80, 81, 82, 83, 84, 85, 87, 90, 94, 97, 108, 119, 128, 132, 136, 141, 142, 145, 147, 148, 149, 151, 152, 153, 158, 164, 166, 170, 171, 174, 176, 179, 180, 181, 182, 184, 185, 186, 187, 191, 193, 195, 196, 199, 202, 203, 206, 207, 208, 210, 214, 218, 219, 222, 226, 227, 228, 231, 233, 235, 236, 239, 240, 241, 244, 248, 250, 251, 253, 254, 260, 263, 266, 268, 270, 271, 272, 277, 286, 296, 304, 311, 312, 313, 315], "combin": [0, 22, 23, 30, 72, 90, 114, 122, 125, 131, 136, 210, 213, 228, 237, 282, 296, 314], "timer": [0, 1, 17, 36, 38, 45, 77, 80, 81, 82, 83, 84, 88, 90, 117, 149, 168, 213, 227, 228, 256, 292, 308, 313, 314], "an": [0, 4, 11, 12, 14, 15, 17, 18, 19, 24, 25, 26, 28, 32, 33, 34, 35, 36, 39, 40, 51, 54, 59, 60, 61, 62, 63, 65, 69, 72, 73, 75, 87, 90, 94, 97, 98, 99, 100, 101, 102, 104, 105, 107, 108, 109, 110, 112, 116, 118, 119, 122, 123, 125, 127, 130, 133, 135, 136, 139, 141, 142, 143, 145, 147, 148, 149, 150, 153, 155, 156, 157, 166, 167, 169, 171, 172, 174, 177, 179, 180, 181, 182, 183, 184, 185, 187, 188, 189, 191, 193, 195, 196, 199, 201, 202, 203, 206, 207, 211, 213, 218, 219, 222, 223, 225, 226, 227, 228, 230, 231, 232, 234, 235, 236, 238, 243, 245, 247, 248, 249, 250, 253, 255, 256, 259, 261, 262, 264, 265, 267, 268, 269, 270, 271, 272, 274, 275, 276, 277, 281, 282, 283, 287, 290, 291, 292, 293, 294, 295, 296, 307, 310, 311, 313, 315], "actor": [0, 1, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 46, 50, 52, 53, 54, 56, 57, 59, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 80, 81, 82, 83, 84, 87, 88, 89, 90, 95, 97, 99, 104, 105, 107, 110, 112, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 135, 136, 139, 141, 142, 145, 146, 147, 160, 163, 165, 166, 167, 169, 172, 173, 174, 176, 177, 179, 182, 185, 187, 189, 190, 191, 192, 193, 196, 197, 199, 202, 203, 205, 206, 211, 214, 219, 220, 221, 223, 224, 225, 227, 230, 233, 240, 242, 245, 246, 247, 248, 250, 251, 252, 253, 254, 256, 257, 259, 260, 265, 266, 267, 268, 272, 276, 277, 282, 284, 286, 287, 288, 291, 294, 295, 296, 297, 299, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314], "slice": [0, 1, 24, 28, 30, 90, 94, 251, 274, 275, 314], "data": [0, 4, 5, 6, 7, 8, 9, 13, 14, 15, 18, 19, 24, 27, 30, 35, 36, 37, 39, 43, 44, 45, 46, 47, 48, 50, 51, 52, 53, 54, 55, 56, 59, 64, 65, 75, 77, 88, 89, 90, 95, 106, 135, 138, 142, 150, 151, 154, 155, 160, 172, 173, 174, 178, 179, 180, 181, 185, 186, 189, 193, 194, 197, 205, 206, 208, 220, 226, 227, 228, 229, 231, 236, 242, 244, 245, 247, 251, 254, 257, 260, 266, 270, 271, 272, 274, 276, 277, 282, 283, 285, 287, 291, 292, 295, 297, 307, 313, 316], "slicer": [0, 14, 24, 30, 90, 139, 297, 304, 305, 307, 310], "us": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 13, 14, 15, 16, 17, 18, 19, 21, 22, 23, 24, 25, 26, 27, 29, 30, 32, 33, 34, 35, 36, 37, 40, 41, 42, 43, 45, 47, 48, 51, 52, 53, 54, 55, 56, 57, 60, 61, 62, 63, 64, 65, 67, 68, 69, 70, 71, 72, 73, 74, 76, 77, 80, 81, 82, 83, 84, 85, 86, 87, 88, 94, 95, 97, 98, 108, 110, 113, 115, 116, 117, 118, 119, 125, 126, 127, 129, 130, 132, 135, 136, 140, 141, 142, 143, 144, 145, 146, 147, 148, 150, 151, 152, 153, 156, 158, 159, 160, 162, 164, 166, 168, 170, 171, 172, 173, 174, 175, 176, 179, 180, 181, 182, 183, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 203, 205, 206, 207, 208, 210, 211, 212, 214, 216, 217, 218, 219, 220, 221, 224, 225, 226, 227, 228, 231, 233, 235, 236, 238, 240, 243, 244, 245, 247, 248, 249, 250, 251, 252, 253, 254, 256, 257, 259, 260, 263, 265, 266, 268, 269, 270, 271, 272, 274, 275, 276, 277, 278, 279, 281, 282, 283, 285, 286, 287, 288, 291, 292, 293, 294, 295, 296, 303, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316], "normal": [0, 9, 13, 17, 26, 30, 34, 37, 72, 73, 75, 89, 90, 153, 172, 182, 185, 198, 208, 226, 228, 256, 265, 268, 270, 271, 274, 275, 277, 282, 286, 291, 294, 295, 296, 307], "your": [0, 4, 15, 19, 72, 87, 89, 90, 97, 99, 100, 101, 102, 104, 105, 106, 107, 123, 133, 134, 138, 139, 155, 167, 174, 177, 178, 181, 213, 229, 230, 244, 247, 277, 287, 291, 292, 296, 315], "sphere": [0, 1, 5, 8, 10, 15, 20, 21, 28, 30, 34, 35, 36, 37, 41, 42, 46, 59, 62, 64, 66, 67, 68, 69, 70, 71, 75, 76, 80, 81, 84, 87, 88, 89, 90, 94, 117, 125, 126, 131, 135, 142, 146, 173, 174, 180, 182, 206, 227, 228, 251, 270, 271, 275, 287, 290, 293, 297, 307, 310, 312, 313, 314], "textur": [0, 1, 5, 6, 12, 15, 37, 38, 90, 107, 110, 129, 135, 162, 168, 172, 174, 175, 176, 179, 185, 189, 194, 228, 231, 235, 238, 241, 244, 247, 250, 253, 257, 259, 265, 268, 270, 271, 279, 282, 283, 295, 297, 307, 308, 313, 314], "visual": [0, 1, 4, 9, 13, 14, 15, 17, 19, 22, 23, 30, 31, 37, 38, 44, 45, 46, 50, 56, 59, 60, 67, 70, 71, 72, 73, 74, 75, 81, 83, 84, 87, 89, 90, 94, 98, 99, 100, 101, 102, 104, 105, 106, 107, 116, 123, 126, 127, 133, 135, 138, 139, 140, 145, 151, 152, 155, 156, 158, 167, 172, 173, 174, 176, 177, 178, 181, 182, 187, 188, 199, 218, 222, 226, 227, 229, 230, 231, 233, 234, 236, 239, 242, 248, 251, 257, 260, 263, 268, 273, 274, 275, 276, 287, 296, 303, 304, 307, 310, 311, 314], "gltf": [0, 1, 90, 98, 180, 182, 191, 199, 200, 202, 203, 205, 230, 276, 279, 297, 313, 314], "file": [0, 1, 11, 12, 15, 23, 35, 36, 42, 58, 71, 79, 86, 88, 90, 91, 94, 97, 98, 128, 134, 136, 142, 145, 149, 180, 181, 185, 189, 191, 194, 200, 201, 217, 258, 272, 273, 274, 276, 279, 281, 282, 283, 289, 290, 291, 294, 296, 303, 307, 310, 311, 313, 314, 315], "furi": [0, 1, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 35, 36, 37, 38, 39, 40, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 54, 55, 56, 57, 59, 61, 62, 63, 64, 66, 67, 68, 69, 70, 72, 73, 74, 75, 76, 77, 78, 80, 81, 82, 83, 84, 85, 86, 90, 95, 97, 98, 106, 108, 109, 110, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 124, 125, 126, 127, 128, 129, 130, 132, 134, 135, 136, 137, 138, 140, 141, 142, 143, 146, 147, 155, 158, 161, 162, 165, 166, 169, 171, 172, 173, 174, 179, 180, 181, 182, 183, 184, 185, 187, 191, 201, 202, 207, 208, 218, 225, 226, 227, 228, 231, 233, 235, 241, 243, 246, 248, 250, 253, 254, 256, 257, 259, 266, 268, 270, 272, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 299, 303, 304, 305, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316], "cone": [0, 1, 17, 46, 52, 63, 66, 90, 104, 228, 239, 242, 245, 270, 275, 290, 297, 305, 308, 313, 314], "arrow": [0, 1, 17, 29, 33, 46, 60, 64, 90, 105, 218, 282, 290, 297, 303, 305, 306, 307, 313, 314], "morph": [0, 1, 90, 197, 200, 220, 227, 282, 313, 314], "anim": [0, 1, 5, 7, 17, 20, 22, 23, 26, 33, 40, 58, 59, 61, 62, 68, 98, 99, 100, 101, 102, 104, 105, 106, 107, 123, 133, 138, 139, 155, 157, 158, 160, 167, 170, 172, 173, 174, 177, 178, 179, 185, 187, 190, 194, 196, 197, 199, 202, 206, 213, 214, 215, 218, 224, 225, 226, 227, 229, 230, 282, 296, 297, 307, 308, 310, 312, 313, 314], "export": [0, 1, 90, 97, 185, 191, 194, 313, 314], "scene": [0, 1, 2, 3, 4, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 72, 73, 74, 75, 76, 77, 80, 81, 82, 83, 84, 87, 88, 89, 90, 95, 102, 120, 132, 135, 144, 147, 150, 172, 185, 189, 193, 199, 212, 214, 225, 227, 247, 256, 260, 265, 267, 268, 270, 272, 274, 276, 282, 284, 288, 294, 297, 304, 312, 313, 314], "skelet": [0, 1, 90, 122, 136, 197, 200, 205, 227, 314], "spiki": [0, 1, 90, 307, 314], "surfac": [0, 1, 4, 5, 17, 19, 22, 23, 25, 72, 75, 76, 90, 135, 142, 151, 157, 160, 163, 166, 169, 171, 173, 181, 185, 228, 268, 270, 277, 295, 297, 304, 305, 311, 312, 314], "select": [0, 1, 11, 32, 47, 48, 55, 90, 109, 122, 136, 162, 167, 174, 180, 181, 183, 184, 186, 192, 195, 198, 216, 217, 219, 226, 261, 283, 286, 287, 288, 294, 295, 297, 311, 314], "multipl": [0, 1, 7, 10, 14, 60, 68, 74, 90, 98, 105, 107, 112, 114, 119, 122, 123, 125, 130, 132, 135, 136, 148, 153, 156, 160, 162, 167, 173, 176, 185, 191, 192, 193, 200, 213, 218, 220, 224, 227, 228, 230, 268, 274, 275, 276, 281, 287, 288, 294, 296, 303, 306, 307, 308, 311, 313, 314], "object": [0, 1, 5, 6, 7, 9, 11, 13, 14, 15, 17, 24, 25, 26, 27, 28, 29, 33, 37, 38, 39, 40, 46, 48, 62, 67, 72, 73, 75, 80, 81, 82, 83, 84, 85, 86, 87, 90, 95, 102, 111, 113, 115, 117, 119, 120, 121, 124, 125, 128, 130, 141, 143, 147, 149, 151, 152, 155, 162, 167, 176, 185, 187, 193, 194, 195, 198, 231, 235, 236, 238, 244, 247, 253, 257, 259, 263, 266, 274, 276, 277, 278, 279, 280, 281, 282, 284, 285, 287, 288, 291, 292, 293, 294, 295, 296, 304, 310, 311, 313, 314], "multithread": [0, 1, 90, 98, 176, 296, 313, 314], "exampl": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 71, 72, 73, 74, 75, 76, 77, 79, 80, 81, 82, 83, 84, 86, 87, 88, 89, 90, 91, 97, 104, 105, 107, 108, 110, 117, 122, 123, 129, 130, 133, 135, 136, 137, 140, 143, 145, 147, 148, 149, 150, 152, 153, 155, 162, 168, 171, 173, 174, 176, 185, 191, 197, 202, 203, 209, 211, 219, 250, 252, 256, 262, 265, 268, 270, 272, 274, 276, 277, 279, 280, 281, 288, 290, 291, 292, 293, 295, 296, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315], "simpl": [0, 1, 7, 18, 20, 21, 25, 30, 39, 41, 42, 54, 76, 85, 90, 115, 117, 122, 134, 143, 173, 174, 181, 182, 183, 194, 197, 200, 216, 218, 220, 224, 235, 239, 241, 244, 256, 258, 262, 263, 265, 268, 272, 276, 277, 282, 287, 293, 295, 296, 313, 314], "pick": [0, 1, 12, 14, 35, 90, 123, 132, 135, 180, 271, 272, 294, 297, 308, 314], "earth": [0, 1, 4, 15, 19, 90, 181, 308, 313, 314], "coordin": [0, 1, 11, 24, 25, 26, 27, 29, 33, 40, 76, 90, 94, 113, 114, 117, 142, 148, 153, 172, 173, 179, 185, 250, 265, 270, 271, 274, 275, 277, 282, 284, 287, 288, 290, 293, 294, 295, 308, 313, 314], "convers": [0, 1, 90, 94, 185, 198, 277, 314], "volum": [0, 1, 30, 90, 171, 274, 275, 296, 297, 314], "solar": [0, 1, 90, 308, 312, 314], "system": [0, 1, 17, 24, 65, 87, 89, 90, 94, 113, 117, 123, 129, 134, 135, 137, 140, 146, 155, 158, 159, 172, 174, 175, 176, 179, 181, 183, 185, 203, 207, 220, 227, 230, 243, 249, 274, 292, 308, 309, 310, 312, 313, 314], "01": [1, 4, 5, 10, 17, 21, 32, 37, 71, 82, 84, 86, 227, 228, 268, 272, 274, 298, 313], "59": [1, 10, 37, 304], "821": [1, 272], "total": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 71, 72, 73, 74, 75, 76, 77, 79, 80, 81, 82, 83, 84, 86, 87, 88, 89, 91, 94, 153, 218, 267, 268, 277, 287, 292, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314], "execut": [1, 23, 30, 42, 58, 71, 79, 81, 83, 84, 86, 91, 94, 143, 149, 155, 174, 181, 212, 219, 225, 244, 267, 268, 276, 289, 291, 292, 313, 314], "19": [1, 10, 15, 32, 33, 135, 136, 172, 173, 174, 227, 228, 270, 272], "from": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 15, 16, 17, 18, 19, 20, 21, 23, 24, 25, 26, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 58, 59, 60, 61, 63, 64, 65, 66, 67, 68, 69, 71, 72, 73, 74, 75, 76, 77, 79, 80, 81, 82, 83, 84, 86, 87, 88, 89, 91, 94, 95, 97, 98, 99, 107, 108, 109, 111, 113, 117, 119, 120, 122, 125, 128, 130, 131, 134, 136, 137, 139, 141, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 155, 156, 159, 162, 168, 170, 172, 174, 176, 179, 180, 181, 182, 184, 185, 186, 188, 189, 191, 197, 198, 200, 202, 203, 205, 207, 214, 215, 218, 222, 224, 225, 226, 227, 230, 231, 237, 240, 244, 245, 247, 249, 250, 252, 253, 255, 256, 257, 258, 259, 260, 263, 265, 266, 267, 268, 269, 270, 271, 272, 274, 275, 276, 277, 278, 279, 281, 282, 283, 284, 285, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 299, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316], "auto_exampl": [1, 23, 42, 58, 71, 79, 86, 91, 272], "01_introductori": [1, 314], "mem": [1, 23, 42, 58, 71, 79, 86, 91, 314], "mb": [1, 23, 42, 58, 71, 79, 86, 91, 279, 314], "viz_earth_anim": [1, 4, 314], "py": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 71, 72, 73, 74, 75, 76, 77, 79, 80, 81, 82, 83, 84, 86, 87, 88, 89, 97, 100, 143, 149, 152, 155, 162, 170, 176, 191, 199, 202, 217, 258, 273, 274, 293, 301, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315], "00": [1, 4, 23, 27, 42, 58, 71, 79, 80, 86, 91, 179, 180, 314], "39": [1, 4, 5, 10, 84, 304, 305], "436": [1, 4, 311], "0": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 54, 55, 56, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 71, 72, 73, 74, 75, 76, 77, 79, 80, 81, 82, 83, 84, 86, 87, 88, 89, 91, 93, 94, 95, 97, 119, 126, 144, 159, 172, 179, 185, 194, 218, 226, 227, 228, 235, 238, 241, 244, 255, 256, 259, 263, 265, 268, 270, 271, 272, 274, 275, 276, 277, 279, 281, 282, 283, 284, 286, 287, 288, 290, 291, 292, 293, 294, 295, 296, 298, 307, 309, 311, 314, 315], "viz_solar_system": [1, 15, 309, 314], "31": [1, 4, 10, 15, 27, 60, 226, 228, 270, 298, 305, 313], "865": [1, 15, 303], "viz_earth_coordin": [1, 5, 314], "27": [1, 5, 10, 15, 32, 59, 60, 81, 83, 226, 270, 272, 303, 309], "806": [1, 5, 303], "viz_tim": [1, 20, 314], "05": [1, 10, 17, 20, 21, 37, 135, 136, 172, 173, 174, 226, 227, 228, 270, 272, 274], "984": [1, 20], "viz_multithread": [1, 10, 314], "510": [1, 10], "viz_spiki": [1, 17, 314], "04": [1, 5, 227, 228, 298, 303, 308], "349": [1, 17], "viz_slic": [1, 14, 314], "02": [1, 40, 82, 84, 135, 136, 172, 173, 174, 270, 296, 298, 306, 307], "768": [1, 4, 5, 7, 9, 10, 11, 12, 13, 14, 15, 17, 19, 20, 21, 31, 36, 38, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 81, 82, 83, 84, 94, 237, 240, 272, 276, 303], "viz_select": [1, 12, 314], "308": [1, 12, 310], "viz_skin": [1, 13, 314], "644": [1, 13, 313], "viz_pick": [1, 11, 314], "085": [1, 11], "viz_surfac": [1, 18, 304, 314], "064": [1, 18], "viz_arrow": [1, 2, 314], "000": [1, 23, 42, 58, 71, 79, 91, 126, 277, 314], "viz_con": [1, 3, 314], "viz_gltf": [1, 6, 314], "viz_gltf_anim": [1, 7, 314], "viz_gltf_export": [1, 8, 314], "viz_morph": [1, 9, 314], "viz_spher": [1, 16, 314], "viz_textur": [1, 19, 314], "go": [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 72, 73, 74, 75, 76, 77, 80, 81, 82, 83, 84, 87, 88, 89, 90, 95, 97, 98, 99, 100, 101, 102, 104, 105, 107, 108, 110, 112, 115, 122, 123, 133, 139, 142, 153, 162, 167, 170, 171, 177, 179, 181, 182, 186, 212, 230, 233, 239, 244, 245, 247, 251, 266, 268, 294, 296, 315], "end": [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 72, 73, 74, 75, 76, 77, 80, 81, 82, 83, 84, 87, 88, 89, 97, 119, 128, 132, 136, 137, 142, 162, 170, 171, 179, 180, 181, 185, 188, 194, 226, 243, 244, 246, 248, 253, 259, 268, 276, 290, 291], "download": [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 72, 73, 74, 75, 76, 77, 80, 81, 82, 83, 84, 87, 88, 89, 90, 95, 181, 185, 189, 191, 194, 228, 277, 279, 313], "full": [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 72, 73, 74, 75, 76, 77, 80, 81, 82, 83, 84, 87, 88, 89, 153, 186, 228, 243, 267, 274, 291, 298, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 315], "code": [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 72, 73, 74, 75, 76, 77, 80, 81, 82, 83, 84, 87, 88, 89, 90, 94, 102, 104, 105, 107, 112, 114, 115, 118, 119, 121, 122, 123, 124, 128, 133, 134, 137, 140, 141, 143, 152, 159, 161, 168, 170, 176, 180, 181, 182, 184, 185, 193, 194, 209, 212, 217, 219, 221, 222, 224, 225, 232, 233, 235, 238, 239, 243, 244, 250, 251, 254, 256, 259, 261, 274, 277, 291, 292, 293, 294, 296, 303, 304, 305, 306, 307, 308, 309, 310, 311, 313, 315, 316], "thi": [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 19, 20, 21, 24, 25, 26, 27, 28, 30, 31, 32, 33, 34, 35, 36, 37, 38, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 59, 60, 61, 62, 64, 65, 67, 68, 69, 72, 73, 74, 75, 76, 77, 80, 81, 82, 83, 84, 87, 88, 89, 94, 97, 98, 99, 100, 101, 102, 104, 105, 107, 108, 109, 123, 133, 135, 136, 139, 142, 143, 149, 155, 167, 172, 173, 174, 177, 179, 180, 181, 226, 227, 228, 230, 232, 268, 269, 270, 272, 273, 274, 276, 277, 278, 279, 280, 281, 287, 289, 290, 291, 292, 293, 294, 295, 296, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 315, 316], "import": [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 72, 73, 74, 75, 76, 77, 80, 81, 82, 83, 84, 87, 88, 89, 95, 97, 143, 147, 149, 150, 153, 156, 172, 182, 194, 197, 218, 233, 244, 250, 253, 256, 259, 262, 268, 269, 274, 277, 281, 290, 291, 293, 295, 296, 312, 313, 315], "numpi": [2, 3, 4, 5, 8, 10, 11, 12, 15, 16, 17, 18, 20, 21, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 38, 40, 45, 46, 50, 52, 53, 54, 56, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 72, 73, 74, 75, 76, 80, 81, 82, 83, 84, 87, 88, 89, 94, 95, 97, 98, 143, 160, 171, 179, 269, 274, 277, 278, 282, 290, 291, 293, 295, 296, 307, 312, 313, 315], "np": [2, 3, 4, 5, 8, 10, 11, 12, 15, 16, 17, 18, 20, 21, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 38, 40, 46, 50, 52, 53, 54, 56, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 72, 73, 74, 75, 76, 80, 81, 82, 83, 84, 87, 88, 89, 94, 95, 119, 128, 143, 215, 269, 274, 276, 277, 282, 290, 293, 295, 296], "window": [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 72, 73, 74, 75, 76, 77, 80, 81, 82, 83, 84, 87, 88, 89, 90, 94, 95, 97, 98, 99, 101, 102, 105, 112, 136, 141, 144, 150, 153, 155, 156, 159, 172, 174, 175, 176, 179, 230, 231, 238, 244, 247, 253, 256, 265, 268, 274, 276, 291, 292, 294, 297, 299, 302, 304, 305, 306, 307, 308, 311, 312, 313], "first": [2, 3, 4, 5, 10, 14, 15, 16, 19, 20, 24, 25, 27, 28, 30, 31, 32, 35, 36, 37, 39, 40, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 61, 62, 63, 64, 65, 66, 67, 72, 75, 77, 80, 81, 82, 83, 84, 88, 94, 97, 115, 117, 119, 120, 130, 135, 136, 140, 142, 143, 146, 149, 153, 156, 170, 171, 172, 173, 174, 176, 180, 181, 182, 183, 191, 192, 198, 202, 206, 207, 219, 220, 227, 228, 232, 233, 235, 236, 238, 239, 244, 247, 248, 250, 253, 254, 256, 258, 259, 263, 265, 266, 268, 269, 270, 271, 274, 275, 276, 277, 281, 287, 291, 294, 295, 313, 315], "thing": [2, 3, 16, 72, 94, 122, 130, 143, 149, 153, 156, 159, 162, 168, 181, 183, 186, 192, 201, 207, 216, 222, 226, 233, 235, 236, 238, 239, 247, 256, 261, 266, 268, 312], "you": [2, 3, 4, 5, 6, 9, 13, 14, 15, 16, 17, 19, 21, 24, 27, 28, 30, 31, 32, 34, 35, 36, 37, 39, 43, 44, 45, 46, 47, 48, 50, 51, 52, 53, 54, 55, 56, 59, 60, 65, 68, 72, 75, 77, 87, 88, 89, 95, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 123, 133, 136, 138, 139, 141, 143, 144, 147, 149, 150, 153, 155, 156, 159, 162, 165, 167, 168, 170, 174, 177, 178, 181, 226, 229, 230, 238, 241, 244, 250, 256, 259, 265, 271, 272, 274, 277, 278, 279, 291, 292, 295, 296, 315], "have": [2, 3, 14, 16, 24, 27, 28, 30, 32, 37, 40, 43, 46, 50, 51, 52, 54, 55, 56, 62, 63, 72, 73, 75, 76, 77, 87, 89, 94, 97, 98, 108, 109, 111, 113, 114, 115, 116, 117, 120, 122, 124, 125, 126, 130, 131, 134, 136, 137, 140, 141, 142, 143, 144, 145, 149, 150, 153, 158, 162, 165, 166, 168, 170, 172, 174, 176, 179, 181, 182, 184, 190, 193, 194, 206, 214, 216, 218, 219, 221, 222, 223, 226, 227, 228, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 247, 250, 251, 253, 254, 256, 257, 259, 260, 262, 263, 265, 266, 268, 269, 270, 271, 272, 274, 275, 276, 277, 280, 281, 284, 287, 289, 291, 293, 294, 295, 305, 307, 315], "specifi": [2, 3, 4, 8, 16, 17, 43, 54, 65, 77, 113, 136, 238, 274, 276, 279, 281, 284, 285, 286, 287, 291, 294, 295, 296], "center": [2, 3, 4, 5, 8, 10, 11, 12, 15, 16, 17, 20, 21, 24, 26, 28, 29, 30, 31, 32, 33, 34, 35, 36, 43, 46, 47, 50, 51, 52, 53, 54, 56, 60, 66, 72, 73, 74, 75, 76, 80, 81, 82, 83, 84, 87, 88, 89, 94, 95, 119, 202, 203, 212, 222, 226, 227, 252, 256, 264, 272, 274, 275, 290, 293, 294, 295, 296, 297, 310, 313], "direct": [2, 3, 11, 12, 17, 29, 33, 36, 37, 39, 46, 52, 53, 54, 56, 63, 72, 75, 76, 80, 81, 82, 83, 84, 94, 95, 124, 146, 147, 155, 168, 172, 174, 211, 227, 236, 266, 270, 271, 272, 274, 275, 276, 277, 284, 286, 290, 293, 295, 296, 305, 306, 307, 313, 316], "color": [2, 3, 4, 5, 8, 10, 11, 12, 14, 15, 16, 17, 18, 20, 21, 24, 25, 26, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 39, 40, 41, 42, 43, 47, 49, 51, 52, 54, 56, 57, 58, 59, 60, 63, 66, 68, 70, 71, 72, 73, 74, 75, 76, 80, 81, 82, 83, 84, 87, 88, 89, 90, 94, 95, 101, 115, 122, 125, 130, 133, 173, 176, 182, 185, 189, 190, 192, 193, 199, 211, 217, 219, 224, 227, 228, 235, 236, 238, 241, 244, 247, 266, 270, 271, 274, 275, 276, 277, 282, 286, 287, 290, 291, 294, 295, 296, 297, 302, 304, 305, 306, 307, 308, 309, 313, 314], "": [2, 4, 5, 9, 10, 11, 12, 13, 14, 15, 17, 19, 20, 21, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 40, 43, 44, 45, 46, 47, 51, 52, 54, 60, 62, 63, 65, 68, 72, 73, 74, 75, 77, 82, 84, 87, 88, 94, 95, 97, 108, 109, 113, 115, 119, 120, 122, 128, 130, 131, 135, 136, 140, 141, 143, 144, 146, 147, 148, 149, 150, 153, 155, 156, 158, 159, 161, 162, 164, 165, 166, 167, 168, 171, 172, 173, 174, 176, 179, 180, 181, 182, 185, 186, 189, 190, 191, 194, 197, 199, 202, 205, 207, 208, 209, 212, 213, 214, 218, 220, 221, 223, 224, 225, 226, 227, 232, 234, 235, 243, 261, 264, 267, 268, 270, 272, 274, 276, 277, 278, 286, 287, 288, 289, 291, 292, 293, 294, 295, 296, 310, 311, 312, 313, 315], "zero": [2, 3, 8, 11, 12, 16, 17, 28, 32, 36, 39, 40, 62, 65, 68, 81, 82, 83, 84, 204, 226, 259, 267, 268, 277, 292, 313], "3": [2, 3, 4, 5, 8, 10, 11, 12, 14, 15, 16, 18, 20, 21, 24, 26, 27, 28, 29, 32, 33, 34, 36, 37, 40, 47, 49, 52, 53, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 72, 73, 75, 76, 81, 82, 83, 84, 86, 87, 89, 94, 95, 97, 98, 119, 125, 128, 135, 136, 143, 144, 149, 155, 172, 173, 174, 179, 180, 185, 192, 226, 227, 228, 250, 266, 268, 270, 271, 272, 274, 275, 276, 277, 279, 281, 283, 284, 286, 287, 290, 291, 292, 293, 294, 295, 296, 298, 303, 304, 306, 308, 313, 315], "ident": [2, 3, 218, 274, 282], "i": [2, 3, 4, 5, 10, 11, 12, 14, 15, 16, 17, 18, 19, 21, 22, 24, 25, 26, 27, 28, 29, 30, 32, 33, 34, 35, 36, 37, 38, 39, 40, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 59, 60, 61, 62, 67, 69, 72, 73, 74, 75, 76, 77, 81, 83, 84, 87, 88, 89, 90, 94, 95, 97, 98, 99, 100, 101, 102, 104, 105, 106, 107, 123, 133, 135, 136, 138, 139, 143, 149, 167, 172, 173, 174, 177, 178, 180, 181, 226, 227, 228, 229, 230, 231, 232, 235, 238, 241, 247, 253, 256, 262, 268, 270, 272, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, 289, 290, 291, 292, 293, 294, 295, 296, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 315, 316], "same": [2, 4, 14, 18, 21, 27, 28, 32, 59, 61, 68, 69, 81, 82, 84, 94, 108, 111, 112, 113, 115, 117, 121, 122, 127, 135, 142, 143, 144, 145, 149, 153, 155, 156, 157, 162, 174, 176, 180, 181, 182, 183, 191, 192, 193, 195, 204, 206, 211, 212, 213, 215, 218, 227, 235, 239, 247, 250, 256, 260, 265, 266, 267, 268, 269, 270, 271, 274, 275, 276, 277, 281, 284, 287, 291, 292, 295], "x": [2, 5, 14, 15, 24, 25, 26, 29, 30, 33, 34, 37, 87, 89, 94, 97, 119, 146, 149, 168, 170, 172, 173, 179, 185, 202, 259, 265, 268, 271, 274, 275, 276, 277, 279, 284, 286, 287, 288, 292, 293, 294, 295, 296, 313, 315], "y": [2, 5, 14, 15, 24, 25, 26, 29, 30, 33, 37, 63, 94, 119, 153, 168, 170, 172, 173, 179, 202, 259, 263, 265, 271, 272, 274, 275, 276, 279, 284, 286, 287, 288, 292, 293, 294, 295, 296, 313, 315], "z": [2, 5, 14, 24, 25, 26, 29, 30, 33, 37, 40, 72, 94, 119, 168, 170, 172, 173, 179, 202, 214, 271, 274, 275, 276, 279, 284, 286, 287, 293, 295, 313, 315], "dir": [2, 3, 75, 76, 274], "scale": [2, 4, 5, 10, 11, 12, 14, 15, 21, 25, 26, 28, 30, 31, 32, 34, 46, 53, 54, 56, 59, 60, 61, 63, 64, 65, 66, 68, 69, 72, 73, 74, 75, 76, 81, 82, 83, 84, 88, 94, 115, 124, 153, 179, 182, 201, 203, 205, 211, 213, 214, 217, 219, 227, 228, 236, 240, 249, 250, 255, 256, 258, 259, 263, 264, 265, 266, 270, 271, 272, 274, 275, 276, 282, 287, 290, 294, 296, 297, 309, 310], "arrai": [2, 3, 4, 5, 8, 11, 12, 16, 18, 21, 26, 28, 29, 31, 32, 33, 35, 36, 40, 45, 46, 50, 53, 54, 56, 59, 60, 61, 62, 63, 64, 66, 67, 68, 69, 72, 74, 75, 76, 80, 81, 82, 83, 84, 87, 88, 94, 119, 143, 149, 160, 171, 194, 253, 266, 270, 274, 275, 276, 277, 278, 282, 283, 287, 291, 292, 293, 294, 295, 296, 307, 309, 312], "2": [2, 4, 5, 8, 10, 11, 12, 14, 15, 17, 18, 21, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 35, 36, 37, 39, 40, 46, 54, 59, 60, 61, 62, 63, 64, 66, 67, 68, 69, 72, 73, 74, 75, 77, 81, 82, 83, 84, 94, 95, 97, 107, 115, 119, 121, 132, 135, 136, 145, 146, 149, 155, 172, 173, 174, 180, 181, 226, 227, 228, 230, 259, 263, 268, 270, 272, 274, 275, 276, 277, 279, 281, 282, 284, 286, 290, 292, 293, 294, 295, 296, 298, 300, 303, 305, 307, 308, 310, 312, 313, 315], "1": [2, 3, 4, 5, 6, 8, 10, 11, 12, 14, 15, 16, 17, 18, 19, 21, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 43, 44, 45, 46, 47, 48, 50, 51, 52, 54, 56, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 72, 73, 74, 75, 76, 77, 80, 81, 82, 83, 84, 87, 88, 89, 94, 95, 97, 119, 132, 135, 136, 143, 145, 146, 149, 155, 167, 172, 173, 174, 177, 181, 194, 211, 214, 226, 227, 228, 241, 244, 259, 265, 268, 270, 271, 272, 274, 275, 276, 277, 279, 281, 282, 283, 284, 286, 287, 290, 291, 292, 293, 294, 295, 296, 298, 303, 304, 308, 310, 312, 313, 315], "6": [2, 10, 11, 12, 15, 18, 21, 24, 25, 26, 28, 29, 32, 37, 39, 47, 49, 53, 59, 60, 61, 62, 63, 64, 65, 66, 67, 69, 71, 72, 75, 80, 81, 82, 83, 84, 94, 126, 135, 136, 155, 172, 173, 174, 226, 227, 228, 270, 271, 272, 274, 276, 283, 287, 292, 294, 295, 298, 303, 304, 310, 313, 315], "5": [2, 3, 4, 5, 10, 11, 12, 14, 15, 16, 18, 20, 21, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 44, 45, 46, 47, 49, 53, 54, 56, 59, 60, 61, 63, 64, 66, 67, 69, 72, 73, 74, 75, 77, 79, 80, 81, 82, 83, 84, 87, 88, 89, 94, 95, 97, 123, 135, 136, 144, 146, 149, 155, 172, 173, 174, 181, 226, 227, 228, 250, 265, 270, 271, 272, 274, 276, 277, 282, 286, 287, 290, 292, 293, 294, 295, 298, 303, 304, 308, 313], "The": [2, 3, 4, 10, 12, 14, 15, 16, 17, 20, 24, 25, 26, 28, 29, 30, 31, 32, 33, 35, 36, 37, 38, 39, 49, 54, 59, 61, 62, 63, 64, 65, 72, 73, 74, 75, 77, 84, 89, 94, 95, 97, 98, 99, 100, 101, 102, 104, 105, 107, 108, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 139, 140, 141, 143, 144, 145, 146, 147, 148, 149, 150, 152, 153, 156, 159, 162, 166, 167, 168, 169, 170, 172, 173, 174, 176, 177, 183, 185, 188, 189, 191, 192, 198, 199, 204, 206, 213, 219, 224, 226, 227, 228, 230, 236, 237, 240, 241, 243, 245, 247, 248, 250, 252, 253, 255, 257, 258, 259, 262, 264, 265, 266, 267, 268, 270, 271, 272, 274, 275, 276, 277, 278, 279, 280, 281, 282, 284, 287, 288, 290, 291, 292, 293, 294, 295, 296, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 315], "below": [2, 3, 4, 14, 16, 22, 62, 63, 64, 90, 103, 110, 112, 114, 116, 118, 121, 124, 127, 129, 132, 137, 141, 143, 144, 147, 149, 150, 152, 153, 155, 156, 158, 159, 162, 165, 168, 170, 172, 174, 186, 188, 190, 191, 193, 195, 198, 201, 204, 207, 210, 212, 217, 219, 226, 235, 238, 241, 245, 247, 250, 253, 256, 259, 260, 262, 265, 268, 269, 270, 271, 272, 277, 296], "gener": [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 72, 73, 74, 75, 76, 77, 80, 81, 82, 83, 84, 87, 88, 89, 90, 94, 97, 98, 118, 135, 142, 143, 145, 148, 149, 162, 166, 169, 171, 172, 173, 174, 176, 181, 183, 187, 191, 193, 196, 222, 227, 241, 244, 245, 248, 250, 254, 259, 260, 268, 270, 271, 272, 274, 276, 277, 279, 281, 282, 287, 290, 292, 295, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 315], "repeat": [2, 3, 16, 21, 25, 26, 29, 33, 36, 40, 60, 75, 159, 217, 228, 290, 294, 296, 313], "primit": [2, 3, 16, 17, 24, 28, 32, 40, 75, 76, 88, 107, 110, 114, 123, 135, 139, 167, 180, 185, 187, 189, 190, 197, 206, 224, 227, 228, 274, 282, 295, 297, 307, 308, 309, 310, 311, 312, 313], "arrow_actor": [2, 17, 29, 33, 274], "what": [2, 3, 11, 14, 15, 24, 32, 72, 95, 143, 149, 173, 174, 180, 181, 226, 238, 241, 244, 247, 256, 259, 262, 268, 278, 296], "we": [2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 24, 26, 27, 28, 30, 31, 32, 35, 36, 37, 39, 40, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 72, 73, 74, 75, 76, 77, 80, 81, 82, 83, 84, 87, 88, 89, 94, 95, 97, 98, 99, 100, 101, 102, 104, 105, 107, 109, 110, 115, 117, 118, 119, 120, 121, 123, 125, 126, 128, 132, 133, 134, 136, 139, 140, 141, 142, 143, 146, 147, 149, 152, 155, 162, 166, 167, 170, 172, 174, 176, 177, 181, 182, 183, 184, 185, 187, 188, 189, 190, 191, 194, 198, 200, 201, 202, 203, 205, 206, 207, 212, 213, 214, 215, 216, 217, 218, 219, 220, 222, 224, 226, 227, 228, 230, 232, 233, 237, 238, 239, 240, 241, 243, 244, 246, 247, 248, 249, 252, 254, 255, 256, 257, 258, 259, 262, 265, 267, 268, 270, 272, 274, 277, 282, 289, 290, 293, 294, 296, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 315], "did": [2, 3, 179, 180, 293], "time": [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 72, 73, 74, 75, 76, 77, 80, 81, 82, 83, 84, 87, 88, 89, 94, 110, 120, 121, 128, 137, 142, 143, 149, 150, 151, 152, 153, 155, 156, 159, 164, 169, 171, 172, 174, 175, 179, 180, 181, 182, 185, 186, 187, 190, 193, 194, 195, 197, 198, 199, 201, 206, 207, 213, 214, 216, 219, 222, 225, 226, 227, 231, 235, 237, 239, 240, 241, 243, 244, 246, 247, 249, 250, 253, 255, 256, 260, 262, 263, 265, 266, 268, 269, 270, 271, 272, 274, 276, 277, 278, 292, 294, 296, 313, 315], "random": [2, 3, 5, 10, 12, 20, 21, 26, 27, 34, 35, 36, 52, 60, 76, 81, 82, 83, 84, 88, 89, 94, 95, 247, 253, 259, 270, 271, 274, 277, 293, 295, 296], "cen2": [2, 3, 16], "rand": [2, 3, 5, 12, 20, 21, 26, 27, 35, 36, 52, 76, 81, 82, 83, 84, 88, 94, 95, 274, 295, 296], "dir2": [2, 3], "cols2": [2, 3, 16], "arrow_actor2": 2, "ad": [2, 3, 8, 11, 12, 13, 14, 16, 25, 27, 31, 35, 36, 37, 45, 48, 54, 59, 61, 62, 63, 64, 65, 66, 67, 68, 69, 81, 82, 83, 95, 99, 100, 101, 102, 104, 105, 107, 110, 112, 113, 114, 116, 118, 119, 121, 122, 123, 124, 126, 133, 135, 136, 139, 141, 142, 143, 144, 147, 153, 156, 159, 160, 162, 163, 164, 165, 166, 167, 168, 169, 170, 172, 173, 174, 177, 179, 181, 182, 184, 185, 187, 188, 189, 193, 194, 195, 197, 198, 199, 200, 201, 202, 203, 204, 210, 211, 212, 213, 214, 216, 221, 223, 224, 226, 227, 228, 230, 238, 240, 256, 257, 264, 268, 270, 272, 274, 276, 277, 287, 294, 296, 303, 304, 307, 308, 309, 310, 311, 312, 313], "our": [2, 3, 16, 24, 30, 32, 35, 36, 37, 40, 60, 65, 68, 72, 73, 74, 75, 77, 84, 94, 98, 99, 100, 101, 102, 104, 105, 106, 107, 109, 123, 128, 133, 138, 139, 143, 146, 167, 174, 177, 178, 181, 183, 200, 203, 215, 218, 220, 229, 230, 232, 240, 243, 259, 267, 268, 281, 287, 290, 312, 315], "add": [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 24, 25, 26, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 59, 60, 61, 63, 65, 66, 67, 68, 72, 73, 74, 75, 76, 77, 80, 81, 82, 83, 84, 87, 88, 89, 94, 95, 101, 102, 104, 105, 112, 113, 114, 115, 116, 118, 119, 130, 131, 141, 144, 147, 150, 153, 156, 157, 165, 168, 170, 172, 174, 179, 183, 185, 188, 189, 190, 192, 193, 196, 198, 199, 202, 217, 219, 220, 221, 223, 227, 228, 248, 256, 259, 265, 268, 272, 274, 275, 276, 282, 287, 291, 294, 295, 296, 297, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 315], "interact": [2, 3, 6, 7, 8, 9, 10, 11, 12, 13, 14, 16, 19, 21, 22, 23, 25, 27, 28, 29, 30, 31, 32, 34, 35, 39, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 72, 73, 74, 75, 76, 77, 80, 81, 82, 83, 84, 85, 86, 88, 89, 90, 98, 108, 109, 113, 143, 149, 155, 160, 174, 183, 192, 199, 226, 256, 277, 292, 294, 296, 303, 304, 314], "fals": [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 24, 25, 27, 28, 29, 30, 31, 32, 34, 35, 36, 37, 38, 39, 40, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 72, 73, 74, 75, 76, 77, 80, 81, 82, 83, 84, 87, 88, 89, 94, 95, 146, 149, 159, 238, 244, 273, 274, 275, 276, 278, 280, 281, 282, 283, 287, 290, 291, 292, 294, 295, 296, 313], "size": [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 72, 73, 74, 75, 76, 77, 80, 81, 82, 83, 84, 87, 88, 89, 94, 95, 111, 113, 115, 117, 122, 130, 136, 141, 143, 149, 150, 152, 153, 162, 172, 181, 183, 186, 194, 234, 250, 252, 255, 258, 264, 265, 266, 267, 270, 271, 272, 274, 275, 276, 277, 279, 282, 284, 290, 292, 294, 295, 296, 297, 306, 309], "600": [2, 3, 14, 16, 18, 19, 25, 26, 27, 28, 29, 31, 33, 34, 35, 38, 39, 40, 46, 49, 51, 53, 72, 73, 74, 75, 80, 185, 189, 191, 228, 274, 313], "record": [2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 72, 73, 74, 75, 76, 77, 80, 81, 82, 83, 84, 87, 88, 89, 153, 156, 158, 159, 162, 174, 214, 221, 227, 271, 276, 281, 297, 305, 313], "out_path": [2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 72, 73, 74, 75, 76, 77, 80, 81, 82, 83, 84, 87, 88, 89, 296], "png": [2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 72, 73, 74, 75, 76, 77, 80, 81, 82, 83, 84, 87, 88, 89, 98, 194, 278, 279, 283, 294, 296, 303], "run": [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 72, 73, 74, 75, 76, 77, 80, 81, 82, 83, 84, 87, 88, 89, 94, 99, 100, 101, 102, 104, 105, 107, 123, 133, 139, 143, 144, 167, 176, 177, 179, 181, 191, 197, 230, 233, 256, 259, 292, 293, 307, 311, 313, 315], "script": [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 72, 73, 74, 75, 76, 77, 80, 81, 82, 83, 84, 87, 88, 89, 97, 189, 263, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 315], "minut": [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 72, 73, 74, 75, 76, 77, 80, 81, 82, 83, 84, 87, 88, 89, 181], "052": 2, "second": [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 72, 73, 74, 75, 76, 77, 80, 81, 82, 83, 84, 87, 88, 89, 94, 97, 111, 115, 117, 119, 128, 135, 136, 140, 145, 155, 170, 172, 173, 174, 176, 180, 186, 206, 219, 235, 245, 250, 253, 256, 259, 265, 268, 271, 276, 277, 287, 292, 296, 315], "jupyt": [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 72, 73, 74, 75, 76, 77, 80, 81, 82, 83, 84, 87, 88, 89, 90, 98, 146, 155, 174, 292], "notebook": [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 72, 73, 74, 75, 76, 77, 80, 81, 82, 83, 84, 87, 88, 89, 90, 155, 174], "ipynb": [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 72, 73, 74, 75, 76, 77, 80, 81, 82, 83, 84, 87, 88, 89, 155], "python": [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 72, 73, 74, 75, 76, 77, 80, 81, 82, 83, 84, 87, 88, 89, 90, 97, 98, 99, 100, 101, 102, 104, 105, 106, 107, 108, 109, 123, 133, 135, 136, 138, 139, 140, 143, 145, 151, 152, 160, 162, 166, 167, 168, 170, 172, 173, 174, 177, 178, 179, 180, 181, 185, 190, 193, 194, 226, 227, 228, 229, 230, 235, 257, 260, 268, 270, 272, 277, 283, 287, 292, 296, 300, 304, 307, 308, 309, 310, 315, 316], "sourc": [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 72, 73, 74, 75, 76, 77, 80, 81, 82, 83, 84, 87, 88, 89, 90, 98, 99, 100, 101, 102, 104, 105, 106, 107, 123, 131, 133, 135, 136, 138, 139, 143, 151, 155, 167, 174, 177, 178, 179, 181, 182, 229, 230, 265, 270, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 311, 315, 316], "galleri": [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 72, 73, 74, 75, 76, 77, 80, 81, 82, 83, 84, 87, 88, 89, 90, 153, 174, 305, 314], "sphinx": [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 72, 73, 74, 75, 76, 77, 80, 81, 82, 83, 84, 87, 88, 89, 90, 174, 305, 313, 315], "cone_actor1": 3, "height": [3, 17, 29, 33, 46, 52, 63, 66, 75, 82, 84, 94, 95, 111, 115, 122, 136, 149, 156, 173, 179, 235, 238, 244, 256, 267, 274, 276, 284, 290, 292, 294, 295, 296, 297], "here": [3, 9, 10, 11, 12, 13, 14, 15, 17, 18, 21, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 39, 43, 49, 54, 60, 62, 65, 75, 76, 81, 83, 94, 95, 99, 100, 101, 102, 104, 105, 107, 110, 113, 115, 117, 119, 120, 122, 123, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 139, 143, 147, 149, 155, 167, 168, 172, 173, 174, 177, 181, 185, 186, 191, 194, 207, 209, 210, 213, 218, 219, 220, 226, 228, 230, 232, 234, 235, 236, 238, 244, 245, 247, 249, 254, 256, 257, 259, 261, 263, 265, 266, 270, 272, 277, 278, 293, 315], "re": [3, 9, 13, 16, 24, 31, 87, 88, 122, 149, 159, 181, 220, 265, 294, 295, 304, 307, 308, 313, 315], "vtkconesourc": 3, "cone_actor2": 3, "use_primit": [3, 10, 16, 72, 274, 313], "055": 3, "In": [4, 5, 6, 7, 8, 9, 10, 12, 13, 14, 15, 17, 19, 21, 24, 26, 27, 28, 32, 33, 34, 37, 43, 54, 59, 62, 63, 64, 68, 72, 73, 74, 75, 76, 80, 81, 82, 83, 84, 87, 89, 94, 97, 112, 113, 117, 119, 128, 130, 131, 136, 137, 141, 142, 143, 145, 147, 148, 149, 150, 151, 153, 155, 156, 162, 170, 172, 173, 174, 176, 179, 180, 181, 184, 185, 198, 213, 233, 235, 238, 243, 247, 255, 256, 257, 267, 268, 270, 272, 274, 275, 289, 296, 312], "itertool": [4, 5, 15, 17, 20, 21, 25, 28, 29, 31, 33, 40, 80, 81, 82, 83, 84, 94], "io": [4, 5, 15, 18, 19, 28, 37, 45, 77, 95, 161, 172, 174, 194, 297, 307, 311], "util": [4, 5, 11, 12, 15, 17, 18, 21, 25, 26, 29, 30, 31, 32, 33, 36, 37, 39, 40, 46, 50, 52, 66, 72, 73, 75, 77, 81, 82, 83, 84, 94, 95, 99, 101, 147, 170, 173, 183, 189, 228, 240, 243, 267, 272, 275, 297, 299, 302, 303, 304, 307, 312, 313], "fetch_viz_model": [4, 77, 95, 297], "fetch_viz_textur": [4, 5, 15, 19, 297], "read_viz_model": [4, 77, 297], "read_viz_textur": [4, 5, 15, 19, 297], "creat": [4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 15, 17, 18, 19, 20, 21, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 35, 36, 37, 38, 39, 40, 41, 43, 44, 45, 46, 47, 48, 49, 50, 52, 53, 54, 55, 56, 59, 61, 62, 63, 65, 66, 67, 69, 70, 72, 75, 76, 77, 81, 82, 83, 84, 85, 89, 90, 95, 98, 103, 108, 109, 110, 111, 114, 115, 117, 119, 122, 125, 126, 127, 128, 131, 132, 135, 136, 137, 145, 146, 147, 148, 149, 150, 152, 153, 154, 155, 156, 159, 160, 162, 164, 166, 168, 169, 170, 171, 172, 173, 174, 176, 180, 181, 183, 184, 185, 186, 187, 189, 191, 192, 194, 195, 200, 201, 203, 204, 205, 207, 209, 212, 215, 216, 217, 218, 219, 222, 224, 226, 227, 228, 231, 236, 238, 239, 240, 246, 247, 248, 249, 251, 252, 257, 264, 265, 266, 268, 270, 271, 274, 277, 279, 282, 285, 287, 291, 292, 294, 295, 296, 303, 308, 309, 311, 313, 315], "start": [4, 5, 7, 9, 10, 11, 12, 13, 14, 15, 17, 19, 20, 21, 24, 25, 26, 28, 29, 30, 31, 32, 33, 35, 36, 37, 38, 40, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 72, 73, 74, 75, 76, 77, 80, 81, 82, 83, 84, 87, 88, 89, 94, 97, 108, 109, 114, 115, 122, 126, 131, 132, 134, 135, 140, 141, 152, 158, 162, 163, 165, 176, 179, 180, 181, 183, 184, 185, 186, 188, 190, 192, 193, 194, 195, 201, 203, 204, 205, 206, 207, 210, 212, 213, 218, 219, 222, 224, 226, 233, 234, 236, 237, 238, 239, 240, 241, 242, 248, 249, 251, 254, 256, 257, 265, 267, 268, 270, 277, 291, 292, 296, 297, 306, 307, 313], "next": [4, 5, 15, 17, 19, 20, 21, 25, 28, 29, 31, 32, 33, 38, 39, 40, 53, 75, 80, 81, 82, 83, 84, 94, 97, 143, 159, 179, 180, 181, 238, 250, 253, 276, 277, 294, 313, 315], "load": [4, 5, 14, 15, 18, 19, 24, 28, 30, 37, 72, 77, 149, 172, 177, 179, 181, 185, 194, 197, 200, 224, 248, 274, 282, 283, 290, 294, 297, 307, 312, 313], "each": [4, 5, 11, 12, 13, 15, 17, 21, 24, 26, 28, 29, 30, 31, 32, 33, 34, 35, 36, 38, 40, 43, 54, 60, 61, 62, 63, 65, 67, 73, 74, 75, 81, 83, 84, 94, 108, 109, 117, 119, 120, 122, 128, 142, 143, 147, 149, 150, 155, 162, 170, 172, 176, 179, 181, 184, 185, 186, 190, 193, 198, 206, 213, 218, 220, 222, 226, 228, 234, 235, 250, 253, 256, 266, 267, 268, 270, 271, 272, 274, 275, 276, 277, 279, 282, 284, 287, 291, 292, 294, 295, 304], "For": [4, 6, 21, 25, 27, 28, 29, 32, 39, 64, 65, 72, 73, 74, 75, 77, 87, 89, 94, 97, 99, 100, 101, 102, 104, 105, 107, 117, 123, 125, 133, 139, 143, 155, 160, 162, 165, 167, 174, 177, 184, 192, 195, 201, 219, 222, 223, 230, 231, 233, 235, 236, 237, 239, 244, 247, 250, 253, 266, 268, 270, 271, 272, 276, 277, 279, 280, 281, 291, 293, 295, 296, 298], "one": [4, 10, 12, 15, 25, 28, 31, 32, 35, 36, 37, 39, 54, 60, 61, 67, 69, 74, 75, 94, 113, 114, 115, 117, 125, 134, 143, 147, 148, 151, 155, 170, 172, 179, 180, 181, 186, 187, 202, 206, 220, 225, 227, 231, 235, 236, 238, 239, 244, 248, 250, 253, 256, 259, 263, 265, 266, 267, 268, 269, 270, 271, 272, 274, 275, 276, 277, 287, 290, 291, 292, 293, 294, 295, 296, 304, 307, 310, 313, 315], "anoth": [4, 20, 37, 64, 65, 67, 115, 127, 149, 150, 181, 189, 193, 198, 203, 208, 227, 228, 232, 239, 241, 244, 247, 250, 253, 256, 259, 262, 263, 265, 267, 268, 269, 272, 277, 315], "moon": [4, 15, 181], "collect": [4, 169, 179, 226, 231, 292], "github": [4, 19, 62, 97, 98, 99, 100, 101, 102, 104, 105, 106, 107, 123, 133, 138, 139, 149, 161, 167, 170, 177, 178, 179, 180, 185, 189, 228, 229, 230, 279, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 315], "load_imag": [4, 5, 15, 19, 45, 144, 297, 307], "imag": [4, 5, 14, 19, 24, 27, 28, 32, 37, 38, 45, 106, 110, 138, 143, 144, 149, 152, 153, 158, 168, 170, 172, 174, 178, 185, 194, 228, 229, 231, 245, 247, 256, 260, 268, 270, 271, 272, 274, 277, 279, 282, 283, 292, 294, 295, 296, 297, 303, 304, 307, 311, 313], "earth_filenam": 4, "1_earth_8k": [4, 15, 19], "jpg": [4, 5, 15, 19, 37, 279, 283, 294], "earth_imag": [4, 5], "dataset": [4, 5, 14, 15, 19, 24, 27, 28, 30, 35, 36, 37, 39, 43, 44, 45, 46, 47, 48, 50, 51, 52, 53, 54, 55, 56, 77, 88, 152, 248, 268], "alreadi": [4, 5, 15, 19, 28, 30, 31, 35, 37, 43, 44, 45, 46, 47, 48, 50, 51, 52, 53, 54, 55, 56, 64, 72, 77, 88, 130, 143, 147, 149, 155, 174, 179, 182, 183, 195, 199, 202, 213, 227, 228, 236, 239, 248, 250, 251, 256, 259, 268, 272, 279, 287, 292, 295, 315], "place": [4, 5, 15, 19, 28, 30, 35, 37, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 63, 66, 72, 77, 88, 108, 109, 113, 147, 150, 153, 156, 165, 172, 218, 259, 274, 281, 284, 294, 307, 313], "If": [4, 5, 9, 13, 14, 15, 19, 24, 28, 30, 32, 35, 37, 39, 43, 44, 45, 46, 47, 48, 50, 51, 52, 53, 54, 55, 56, 59, 72, 77, 87, 88, 89, 95, 106, 115, 120, 134, 138, 143, 149, 150, 152, 156, 159, 172, 178, 181, 182, 198, 199, 206, 214, 229, 235, 238, 244, 259, 264, 268, 272, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, 294, 295, 296, 315], "want": [4, 5, 9, 13, 14, 15, 17, 19, 24, 27, 28, 30, 32, 35, 37, 43, 44, 45, 46, 47, 48, 50, 51, 52, 53, 54, 55, 56, 63, 65, 72, 75, 77, 88, 89, 132, 143, 155, 158, 174, 179, 180, 181, 183, 185, 186, 226, 239, 247, 250, 251, 256, 259, 260, 282, 290, 291, 292, 293, 296, 312, 315], "fetch": [4, 5, 15, 19, 24, 28, 30, 35, 37, 43, 44, 45, 46, 47, 48, 50, 51, 52, 53, 54, 55, 56, 77, 88, 162, 172, 226, 228, 248, 279, 304, 313, 315], "again": [4, 5, 9, 15, 19, 28, 30, 35, 37, 43, 44, 45, 46, 47, 48, 50, 51, 52, 53, 54, 55, 56, 65, 72, 77, 88, 172, 179, 180, 181, 186, 219, 226, 241, 244, 247, 269, 278, 315], "pleas": [4, 5, 15, 19, 24, 28, 30, 35, 37, 39, 43, 44, 45, 46, 47, 48, 50, 51, 52, 53, 54, 55, 56, 77, 88, 98, 315], "remov": [4, 5, 10, 15, 19, 28, 30, 31, 32, 35, 37, 43, 44, 45, 46, 47, 48, 50, 51, 52, 53, 54, 55, 56, 77, 82, 88, 100, 105, 107, 122, 155, 156, 160, 162, 173, 174, 182, 204, 216, 217, 226, 227, 267, 274, 276, 277, 280, 281, 291, 294, 295, 296, 297, 301, 304, 305, 306, 307, 310, 311, 312, 313, 315], "folder": [4, 5, 15, 19, 28, 30, 35, 36, 37, 43, 44, 45, 46, 47, 48, 50, 51, 52, 53, 54, 55, 56, 77, 88, 252, 272, 279, 292, 294, 307, 315], "user": [4, 5, 15, 17, 19, 20, 24, 28, 30, 35, 37, 42, 43, 44, 45, 46, 47, 48, 50, 51, 52, 53, 55, 56, 65, 70, 77, 85, 86, 88, 89, 94, 98, 109, 113, 115, 116, 121, 124, 126, 132, 134, 135, 136, 137, 142, 143, 145, 149, 150, 153, 155, 172, 174, 176, 184, 186, 192, 199, 216, 219, 221, 225, 226, 231, 234, 235, 248, 256, 258, 261, 262, 264, 265, 268, 269, 272, 277, 281, 292, 294, 313, 314, 315], "skoudoro": [4, 5, 15, 19, 24, 28, 30, 35, 37, 43, 44, 45, 46, 47, 48, 50, 51, 52, 53, 54, 55, 56, 77, 88], "texture_on_spher": [4, 5, 15, 19, 297], "earth_actor": [4, 5, 15], "newli": [4, 8, 15, 153, 182, 199, 228], "Then": [4, 15, 20, 24, 30, 35, 36, 37, 43, 51, 54, 61, 63, 65, 72, 75, 94, 179, 181, 182, 183, 184, 189, 192, 195, 201, 204, 206, 207, 212, 217, 226, 251, 270, 274, 275, 295, 315], "do": [4, 5, 21, 28, 32, 63, 75, 81, 94, 98, 143, 180, 181, 226, 227, 228, 235, 238, 247, 250, 253, 259, 265, 268, 269, 274, 277, 294, 312, 313], "moon_filenam": 4, "8k": [4, 15], "moon_imag": 4, "moon_actor": 4, "both": [4, 16, 24, 27, 28, 39, 66, 80, 94, 114, 116, 117, 125, 137, 153, 173, 174, 179, 182, 190, 193, 199, 202, 210, 219, 228, 237, 248, 251, 252, 256, 259, 274, 275, 281, 283, 284, 290, 294, 296], "exist": [4, 19, 32, 59, 110, 112, 118, 125, 128, 141, 156, 159, 181, 183, 192, 199, 202, 226, 250, 256, 257, 260, 268, 272, 276, 279, 294, 313], "alter": [4, 208, 272], "posit": [4, 5, 8, 11, 14, 15, 18, 21, 24, 25, 26, 27, 28, 29, 30, 32, 33, 35, 36, 37, 40, 43, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 60, 61, 63, 65, 66, 67, 68, 69, 72, 75, 80, 81, 82, 83, 84, 88, 94, 95, 111, 113, 117, 119, 143, 147, 149, 155, 158, 170, 173, 174, 176, 183, 184, 186, 188, 192, 193, 195, 198, 199, 204, 210, 211, 212, 215, 223, 226, 227, 234, 240, 252, 253, 255, 265, 267, 270, 272, 274, 275, 276, 278, 279, 281, 284, 287, 288, 290, 291, 292, 293, 294, 295, 296, 297, 306, 307, 312, 313], "correctli": [4, 5, 84, 94, 122, 131, 153, 185, 218, 237, 240, 245, 271, 307, 315], "comparison": [4, 75, 234, 251, 260, 268, 270, 304], "setposit": [4, 12, 14, 15, 53, 54, 56, 63, 65, 66, 80, 81, 82, 83, 84, 94, 274, 297], "setscal": [4, 5, 15], "rotat": [4, 5, 10, 15, 20, 28, 31, 37, 38, 40, 52, 54, 56, 63, 64, 66, 68, 73, 75, 81, 82, 83, 94, 120, 121, 124, 136, 160, 168, 173, 177, 183, 192, 193, 196, 199, 202, 203, 204, 205, 217, 219, 226, 227, 228, 253, 268, 270, 271, 274, 276, 282, 284, 286, 294, 296, 297, 312, 313], "align": [4, 11, 14, 15, 24, 30, 37, 43, 54, 56, 72, 75, 94, 125, 194, 218, 234, 243, 249, 252, 261, 265, 271, 272, 284, 294, 297, 303, 313], "25": [4, 5, 10, 14, 15, 29, 34, 37, 39, 43, 46, 54, 60, 64, 73, 74, 80, 226, 227, 228, 270, 293, 308], "90": [4, 5, 10, 15, 28, 29, 33, 64, 66, 69, 81, 83, 185, 295, 305], "showmanag": [4, 5, 7, 9, 10, 11, 12, 13, 14, 15, 17, 20, 21, 24, 25, 26, 28, 29, 30, 31, 32, 33, 36, 37, 38, 40, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 76, 77, 80, 81, 82, 83, 84, 87, 88, 89, 94, 95, 221, 223, 225, 227, 256, 260, 268, 288, 291, 292, 297, 307, 313], "class": [4, 15, 17, 24, 28, 38, 111, 141, 144, 145, 147, 150, 151, 153, 156, 159, 170, 172, 173, 180, 182, 183, 191, 193, 195, 199, 200, 202, 226, 227, 228, 235, 237, 240, 247, 256, 259, 265, 268, 269, 274, 275, 276, 277, 281, 282, 284, 285, 287, 288, 291, 292, 294, 296, 303, 307, 311, 313], "interfac": [4, 5, 15, 17, 24, 42, 98, 109, 136, 172, 195, 226, 231, 234, 238, 272, 277, 296, 314], "between": [4, 5, 15, 17, 21, 32, 35, 36, 39, 46, 53, 59, 64, 65, 73, 74, 75, 76, 80, 81, 83, 84, 87, 89, 94, 117, 119, 136, 146, 155, 172, 173, 174, 176, 179, 183, 188, 195, 198, 210, 226, 227, 242, 243, 248, 253, 255, 266, 268, 270, 274, 275, 276, 279, 283, 286, 287, 292, 293, 294, 296, 313], "interactor": [4, 5, 15, 17, 99, 153, 156, 244, 253, 256, 288, 296, 299], "showm": [4, 5, 7, 9, 10, 11, 12, 13, 15, 17, 20, 21, 25, 26, 28, 29, 31, 33, 36, 40, 47, 48, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 76, 77, 80, 81, 82, 83, 84, 87, 88, 89, 94, 95, 268, 291, 292, 296], "900": [4, 5, 7, 9, 10, 13, 14, 15, 17, 19, 20, 21, 24, 30, 31, 36, 38, 40, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 80, 81, 82, 83, 84, 94, 276], "reset_camera": [4, 5, 7, 9, 10, 11, 12, 13, 14, 15, 17, 18, 19, 20, 21, 24, 26, 27, 28, 29, 30, 31, 32, 33, 36, 37, 38, 46, 50, 54, 56, 59, 60, 61, 62, 63, 64, 66, 67, 69, 77, 80, 81, 82, 83, 84, 88, 94, 95, 296, 297], "order_transpar": [4, 5, 7, 9, 10, 11, 12, 13, 15, 17, 20, 21, 26, 28, 29, 31, 33, 36, 37, 38, 40, 59, 60, 61, 62, 63, 64, 66, 67, 69, 80, 81, 82, 83, 84, 88, 94, 276, 296, 308], "true": [4, 5, 6, 7, 9, 10, 11, 12, 13, 15, 17, 19, 20, 21, 24, 25, 26, 27, 28, 29, 30, 32, 33, 35, 36, 37, 38, 40, 44, 45, 46, 47, 49, 53, 54, 55, 56, 59, 60, 61, 62, 63, 64, 66, 67, 68, 69, 72, 75, 77, 80, 81, 82, 83, 84, 87, 88, 94, 115, 149, 193, 240, 244, 274, 275, 276, 277, 278, 280, 281, 282, 283, 287, 288, 290, 291, 292, 293, 294, 295, 296], "let": [4, 5, 10, 11, 12, 14, 15, 17, 20, 21, 24, 26, 27, 28, 31, 32, 33, 35, 36, 37, 40, 43, 44, 45, 51, 52, 54, 65, 72, 73, 74, 76, 77, 95, 97, 98, 146, 149, 155, 231, 241, 243, 244, 247, 253, 259, 265, 291, 308], "focu": [4, 15, 111, 114, 115, 126, 127, 140, 149, 152, 155, 196, 234, 237, 246, 249, 255, 261, 262, 264, 266, 270, 272, 294], "can": [4, 6, 9, 10, 12, 13, 14, 15, 17, 21, 24, 25, 27, 28, 30, 31, 32, 33, 34, 35, 36, 37, 40, 43, 51, 53, 54, 56, 59, 60, 61, 64, 65, 68, 72, 73, 74, 76, 87, 88, 89, 94, 95, 97, 99, 100, 101, 102, 103, 104, 105, 107, 111, 113, 115, 117, 119, 120, 121, 122, 123, 125, 126, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 139, 141, 142, 143, 146, 147, 148, 149, 150, 151, 152, 153, 155, 159, 162, 167, 168, 170, 172, 173, 174, 176, 177, 179, 180, 181, 182, 183, 184, 187, 188, 189, 190, 191, 193, 194, 195, 197, 198, 200, 201, 202, 204, 207, 210, 212, 217, 219, 222, 226, 227, 228, 230, 231, 235, 236, 237, 238, 239, 240, 241, 242, 243, 245, 247, 248, 249, 250, 251, 254, 256, 257, 258, 259, 260, 261, 263, 266, 267, 268, 269, 270, 271, 272, 274, 275, 276, 277, 278, 279, 283, 284, 288, 291, 292, 293, 294, 295, 296, 310, 311, 315], "determin": [4, 15, 17, 26, 40, 46, 72, 94, 115, 120, 156, 240, 243, 267, 270, 282, 295, 296, 313], "durat": [4, 15, 17, 38, 80, 81, 82, 83, 84, 94, 227, 276, 296, 297], "counter": [4, 5, 10, 15, 17, 20, 21, 25, 29, 31, 32, 33, 36, 40, 80, 81, 82, 83, 84, 94, 193, 264, 267, 286, 293, 295], "avoid": [4, 12, 15, 17, 20, 21, 32, 114, 143, 155, 162, 174, 176, 265, 270, 272, 277, 287, 307], "global": [4, 15, 17, 20, 21, 24, 25, 26, 29, 30, 32, 33, 37, 40, 45, 52, 53, 54, 77, 80, 81, 82, 83, 84, 94, 147, 156, 188, 215, 228, 273, 277, 280], "variabl": [4, 15, 17, 20, 21, 24, 25, 26, 29, 30, 33, 35, 40, 54, 72, 75, 76, 77, 81, 83, 94, 95, 115, 118, 185, 206, 247, 254, 268, 269, 270, 274, 289, 294], "count": [4, 5, 10, 15, 17, 20, 21, 25, 29, 31, 33, 40, 80, 81, 82, 83, 84, 94, 159, 190, 227, 282, 295, 313], "set_camera": [4, 5, 8, 15, 18, 25, 26, 27, 28, 29, 33, 36, 40, 46, 50, 54, 56, 64, 68, 69, 80, 81, 82, 83, 84, 88, 296, 297], "ensur": [4, 9, 30, 32, 234, 237, 240, 243, 252, 255, 258, 261, 264, 272, 274, 284, 287, 296], "camera": [4, 5, 6, 8, 9, 10, 15, 25, 26, 27, 29, 32, 33, 36, 38, 40, 46, 50, 56, 57, 58, 63, 64, 65, 66, 69, 72, 75, 81, 83, 84, 90, 173, 179, 185, 187, 189, 194, 199, 225, 227, 228, 268, 274, 276, 282, 291, 295, 296, 297, 313, 314], "optim": [4, 110, 117, 119, 163, 173, 179, 190, 206, 227, 241, 270, 287], "24": [4, 10, 25, 174, 176, 226, 228, 244, 270, 272, 287, 290, 293, 295, 304, 305, 313], "4": [4, 6, 8, 10, 12, 14, 15, 17, 18, 20, 21, 24, 25, 26, 27, 28, 29, 32, 33, 40, 44, 45, 49, 54, 56, 59, 60, 61, 62, 63, 64, 66, 67, 75, 76, 77, 81, 82, 83, 84, 87, 89, 94, 97, 116, 119, 133, 135, 136, 146, 147, 149, 155, 159, 172, 173, 174, 209, 226, 227, 228, 235, 238, 250, 259, 266, 268, 270, 271, 272, 274, 275, 276, 277, 281, 282, 283, 287, 290, 292, 293, 294, 295, 296, 298, 303, 304, 307, 309, 313], "34": [4, 10, 287, 312], "focal_point": [4, 8, 18, 25, 26, 27, 28, 29, 33, 40, 80, 81, 83, 88, 296], "view_up": [4, 8, 25, 26, 27, 29, 33, 40, 80, 81, 83, 88, 276, 296], "bloomington": 4, "IN": [4, 316], "home": [4, 98, 246, 279, 313], "headquart": 4, "3175": 4, "025": [4, 274], "radiu": [4, 15, 17, 21, 33, 51, 53, 54, 60, 63, 66, 72, 75, 80, 81, 82, 84, 94, 173, 274, 287, 290, 293, 294], "002": [4, 29, 33], "sphere_actor": [4, 5, 10, 20, 21, 35, 36, 88, 274], "blue_medium": 4, "also": [4, 14, 15, 18, 24, 25, 27, 28, 30, 31, 32, 34, 36, 46, 60, 61, 62, 64, 65, 72, 75, 80, 94, 97, 99, 100, 101, 102, 104, 105, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 125, 126, 128, 130, 131, 132, 133, 134, 135, 136, 137, 139, 140, 141, 142, 143, 144, 145, 147, 149, 150, 153, 155, 156, 159, 165, 167, 168, 171, 172, 173, 176, 177, 179, 180, 181, 182, 184, 185, 187, 188, 190, 192, 194, 195, 198, 199, 202, 205, 206, 213, 215, 216, 218, 219, 226, 227, 228, 230, 233, 236, 238, 239, 241, 242, 243, 244, 245, 247, 248, 249, 250, 251, 253, 254, 256, 257, 259, 260, 262, 263, 265, 266, 268, 269, 270, 271, 272, 276, 277, 281, 287, 294, 296, 313, 315], "text": [4, 5, 10, 11, 14, 24, 25, 26, 28, 29, 30, 33, 37, 40, 41, 42, 47, 53, 55, 80, 81, 82, 83, 84, 90, 95, 115, 122, 136, 162, 165, 170, 172, 174, 181, 207, 226, 227, 234, 240, 249, 252, 255, 258, 264, 267, 272, 274, 283, 294, 296, 297, 303, 307, 308, 310, 311, 312, 313, 314, 315], "text_actor": 4, "text_3d": [4, 5, 297], "indiana": 4, "42": [4, 10, 27, 304, 309], "03": [4, 86, 226, 250, 270, 272, 274, 290, 298, 305, 312], "white": [4, 5, 27, 270, 274, 296, 303], "004": [4, 33], "model": [4, 6, 7, 9, 13, 72, 73, 74, 75, 76, 77, 95, 109, 111, 112, 114, 116, 132, 135, 142, 145, 148, 151, 154, 155, 157, 163, 171, 173, 174, 179, 182, 185, 189, 191, 194, 197, 202, 205, 209, 213, 215, 218, 220, 224, 268, 270, 279, 282, 286, 287, 310, 311, 313], "satellit": [4, 181], "circl": [4, 34, 43, 48, 51, 54, 183, 226, 294], "satellite_filenam": 4, "satellite_obj": 4, "obj": [4, 11, 14, 24, 30, 31, 37, 77, 95, 98, 179, 278, 283, 292, 294, 313], "load_polydata": [4, 18, 77, 95, 297], "satellite_actor": 4, "get_actor_from_polydata": [4, 18, 297], "75": [4, 10, 14, 24, 30, 37, 47, 283, 303, 307], "005": [4, 5, 29, 33], "timer_callback": [4, 5, 7, 9, 13, 15, 17, 20, 21, 25, 26, 29, 31, 32, 33, 36, 38, 40, 45, 77, 80, 81, 82, 83, 84, 94, 296], "function": [4, 5, 10, 14, 15, 18, 22, 23, 24, 26, 28, 29, 30, 31, 32, 33, 35, 36, 37, 38, 40, 45, 54, 55, 62, 64, 66, 69, 72, 74, 75, 76, 82, 84, 90, 94, 95, 97, 98, 111, 118, 125, 130, 132, 141, 142, 147, 151, 157, 159, 163, 168, 170, 172, 173, 175, 177, 182, 183, 185, 189, 190, 191, 192, 194, 195, 196, 197, 198, 199, 202, 203, 205, 212, 214, 216, 217, 218, 221, 226, 227, 230, 235, 237, 238, 239, 240, 241, 242, 243, 245, 247, 250, 253, 254, 256, 257, 258, 259, 260, 263, 265, 266, 268, 269, 270, 271, 272, 274, 276, 277, 280, 281, 284, 287, 290, 291, 292, 293, 294, 295, 296, 303, 304, 305, 307, 308, 310, 311, 312, 313, 314, 315], "statement": [4, 72], "when": [4, 11, 12, 21, 25, 27, 29, 31, 33, 37, 53, 54, 55, 59, 62, 63, 72, 73, 76, 115, 130, 132, 143, 144, 149, 150, 153, 158, 159, 162, 172, 174, 176, 179, 181, 182, 186, 187, 189, 193, 194, 198, 199, 204, 212, 216, 223, 225, 226, 227, 233, 237, 238, 240, 241, 243, 247, 249, 252, 253, 255, 256, 257, 259, 264, 265, 267, 268, 270, 271, 272, 274, 276, 277, 279, 281, 287, 294, 296, 304, 305, 306, 307, 310, 311, 312, 313, 315], "certain": [4, 15, 53, 65, 144, 147, 150, 153, 168, 228, 246, 258, 276, 284, 292], "event": [4, 11, 15, 24, 31, 37, 77, 88, 109, 141, 149, 150, 153, 156, 159, 181, 183, 184, 186, 192, 195, 198, 201, 226, 227, 256, 276, 288, 291, 292, 294, 296, 307, 308, 316], "happen": [4, 15, 21, 27, 39, 149, 155, 174, 198, 201, 207, 216, 218, 226, 235, 238, 244, 247, 253, 271, 296, 315], "base": [4, 5, 18, 28, 37, 59, 62, 64, 65, 66, 67, 69, 70, 71, 74, 75, 76, 81, 82, 83, 84, 90, 94, 97, 98, 110, 111, 115, 116, 117, 118, 122, 124, 126, 127, 135, 136, 153, 157, 162, 166, 172, 173, 174, 177, 179, 180, 181, 182, 185, 192, 193, 202, 211, 223, 225, 226, 227, 228, 231, 234, 245, 247, 248, 249, 252, 255, 256, 257, 258, 259, 261, 263, 266, 267, 268, 270, 271, 272, 274, 275, 276, 277, 279, 281, 282, 284, 286, 287, 288, 292, 294, 295, 296, 297, 308, 310, 312, 314], "so": [4, 14, 15, 17, 24, 27, 28, 32, 35, 36, 37, 40, 47, 54, 60, 67, 72, 74, 81, 83, 94, 95, 98, 111, 113, 114, 115, 116, 117, 118, 119, 122, 127, 128, 129, 130, 131, 132, 134, 136, 141, 144, 150, 153, 154, 156, 159, 162, 168, 169, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 190, 191, 192, 193, 195, 197, 201, 202, 206, 210, 214, 216, 217, 218, 219, 220, 222, 223, 226, 227, 238, 239, 242, 244, 248, 250, 251, 253, 254, 257, 260, 263, 266, 268, 270, 271, 274, 275, 292, 293, 296, 315], "continu": [4, 21, 36, 62, 72, 117, 120, 122, 125, 130, 135, 147, 153, 156, 170, 172, 177, 180, 182, 198, 217, 219, 227, 230, 237, 239, 245, 252, 254, 257, 258, 261, 266, 271, 272, 312, 313], "while": [4, 10, 28, 53, 109, 111, 113, 114, 116, 117, 118, 119, 120, 122, 128, 130, 137, 144, 179, 181, 185, 186, 188, 189, 190, 191, 194, 198, 202, 210, 212, 216, 218, 219, 220, 221, 222, 226, 227, 228, 233, 237, 238, 240, 245, 252, 254, 264, 267, 268, 272, 276, 277, 294, 295, 303, 313], "less": [4, 21, 40, 149, 150, 152, 155, 179, 198, 207, 244, 247, 270, 271, 287, 296], "than": [4, 12, 14, 27, 28, 114, 118, 126, 135, 143, 152, 153, 155, 156, 159, 162, 172, 174, 181, 194, 198, 203, 206, 207, 209, 221, 238, 244, 252, 253, 255, 257, 259, 269, 270, 274, 277, 281, 287, 292, 293, 295, 296, 307], "450": [4, 25, 54, 95, 294, 311], "def": [4, 5, 7, 9, 10, 11, 12, 13, 14, 15, 17, 20, 21, 24, 25, 26, 28, 29, 30, 31, 32, 33, 36, 37, 38, 40, 43, 45, 46, 47, 50, 52, 53, 54, 55, 56, 62, 66, 69, 77, 80, 81, 82, 83, 84, 89, 94, 119, 128, 149, 268, 269, 276, 281, 291, 292], "_obj": [4, 5, 7, 9, 12, 13, 15, 17, 20, 21, 25, 26, 29, 32, 33, 36, 38, 40, 43, 45, 54, 80, 81, 82, 83, 84, 94, 294], "_event": [4, 5, 7, 9, 12, 13, 15, 17, 20, 21, 24, 25, 26, 29, 30, 32, 33, 36, 38, 40, 77, 80, 81, 82, 83, 84, 94, 291], "cnt": [4, 5, 14, 15, 17, 20, 21, 25, 29, 31, 33, 40, 80, 81, 82, 83, 84, 94, 282], "render": [4, 5, 7, 9, 10, 11, 12, 13, 15, 17, 20, 21, 22, 23, 24, 25, 26, 28, 29, 30, 31, 32, 33, 36, 37, 38, 40, 44, 45, 46, 53, 64, 65, 70, 71, 75, 76, 77, 80, 81, 82, 83, 84, 87, 90, 95, 97, 98, 102, 110, 112, 114, 116, 117, 118, 119, 121, 124, 125, 127, 128, 130, 131, 132, 135, 136, 143, 145, 148, 150, 151, 155, 162, 170, 171, 172, 174, 177, 181, 191, 197, 206, 209, 210, 220, 221, 223, 228, 231, 235, 238, 241, 244, 247, 250, 253, 256, 259, 262, 265, 268, 270, 274, 282, 286, 287, 292, 294, 296, 297, 303, 304, 307, 310, 311, 312, 313, 314, 316], "azimuth": [4, 5, 10, 17, 20, 21, 26, 28, 31, 32, 38, 46, 50, 54, 56, 77, 160, 293, 296, 297], "300": [4, 15, 20, 24, 26, 28, 29, 30, 36, 43, 44, 45, 47, 49, 52, 53, 54, 55, 83, 87, 294, 296, 310], "679": [4, 217, 226, 313], "314": 4, "35": [4, 10, 24, 28, 30, 60, 73, 84, 274, 290, 308, 311], "zoom": [4, 5, 12, 14, 18, 21, 24, 26, 28, 33, 39, 260, 296, 297], "1500": [4, 49], "550": [4, 33, 95, 313], "575": [4, 5, 313], "180": [4, 5, 17, 28, 43, 44, 45, 52, 54, 63, 66, 294, 307], "rm": [4, 10, 32, 296, 297], "750": [4, 54], "8": [4, 10, 11, 15, 21, 25, 26, 28, 30, 33, 35, 36, 39, 40, 44, 45, 47, 49, 53, 54, 62, 63, 64, 66, 67, 72, 73, 74, 75, 76, 81, 83, 84, 87, 89, 97, 135, 136, 146, 172, 173, 174, 179, 180, 226, 227, 228, 259, 268, 270, 272, 274, 276, 277, 287, 290, 291, 292, 295, 296, 298, 303, 304, 305, 308, 309, 313, 315], "10000": [4, 12, 34, 81, 149, 274], "1100": 4, "07": [4, 5, 23, 135, 136, 172, 173, 174, 226, 227, 228, 250, 268, 270, 272, 277, 298, 309], "exit": [4, 5, 10, 15, 17, 20, 21, 25, 26, 29, 31, 33, 36, 38, 40, 80, 81, 82, 83, 84, 94, 296, 297, 308], "watch": [4, 5, 15, 179, 181], "new": [4, 5, 14, 15, 18, 19, 28, 32, 62, 70, 72, 73, 74, 75, 87, 90, 94, 109, 113, 119, 120, 123, 126, 132, 133, 135, 136, 137, 139, 140, 142, 146, 149, 155, 162, 163, 167, 172, 174, 176, 177, 179, 180, 181, 183, 186, 190, 191, 195, 198, 199, 201, 202, 204, 206, 211, 215, 216, 217, 218, 219, 223, 226, 227, 228, 230, 236, 237, 239, 240, 242, 246, 248, 249, 251, 254, 256, 259, 261, 264, 265, 267, 268, 270, 272, 274, 279, 281, 282, 285, 291, 292, 293, 294, 295, 296, 303, 305, 307, 308, 309, 310, 311, 312, 313, 315], "take": [4, 5, 15, 26, 37, 40, 62, 64, 65, 72, 75, 98, 137, 143, 149, 150, 155, 159, 162, 165, 172, 179, 181, 186, 189, 199, 203, 220, 225, 228, 233, 237, 247, 253, 254, 256, 259, 263, 265, 266, 268, 270, 271, 274, 275, 276, 279, 291, 294, 295, 296, 315], "add_timer_callback": [4, 5, 7, 9, 13, 15, 17, 20, 21, 25, 26, 29, 31, 32, 33, 36, 38, 40, 45, 77, 80, 81, 82, 83, 84, 94, 296, 297], "specif": [5, 12, 24, 28, 31, 62, 72, 81, 82, 83, 84, 97, 115, 119, 122, 128, 130, 134, 136, 140, 141, 143, 149, 150, 152, 158, 162, 172, 174, 181, 198, 225, 226, 227, 234, 235, 245, 247, 256, 260, 264, 266, 268, 270, 271, 272, 276, 277, 279, 290, 291, 294, 296, 315, 316], "locat": [5, 37, 64, 84, 143, 149, 170], "math": [5, 32, 36, 116, 118, 148, 169, 171, 179, 239, 270, 293], "16k": 5, "resolut": [5, 17, 29, 30, 33, 46, 63, 66, 72, 75, 88, 143, 237, 258, 265, 270, 274, 290, 296, 305], "maximum": [5, 72, 87, 150, 207, 252, 259, 270, 274, 275, 276, 277, 282, 292, 294, 296], "detail": [5, 28, 72, 75, 90, 95, 109, 117, 120, 135, 136, 142, 147, 150, 153, 155, 156, 159, 162, 172, 173, 174, 211, 233, 239, 245, 253, 254, 256, 257, 259, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 274, 277, 292, 315], "earth_fil": 5, "1_earth_16k": [5, 15], "opt": [5, 174, 271], "homebrew": 5, "caskroom": 5, "miniforg": 5, "env": 5, "py311": 5, "lib": [5, 18, 24, 43, 44, 46, 47, 50, 51, 52, 53, 54, 55, 56, 143, 155, 170, 174, 176, 177, 297, 312], "python3": [5, 312, 315], "11": [5, 10, 15, 46, 50, 58, 73, 74, 135, 136, 172, 173, 174, 180, 181, 226, 227, 228, 270, 272, 295, 298, 303, 304, 312, 313], "site": [5, 180], "packag": [5, 36, 97, 98, 101, 166, 174, 181, 273, 277, 281, 289, 302, 315], "pil": [5, 194], "3186": 5, "decompressionbombwarn": 5, "131220000": 5, "pixel": [5, 43, 54, 75, 179, 198, 278, 294, 295, 296], "exce": [5, 226, 276, 287], "limit": [5, 74, 87, 135, 136, 148, 159, 189, 191, 198, 199, 228, 246, 250, 253, 294, 305, 313, 316], "89478485": 5, "could": [5, 32, 64, 65, 69, 74, 113, 129, 132, 134, 146, 149, 152, 153, 160, 162, 164, 165, 174, 176, 179, 180, 181, 183, 184, 195, 201, 210, 218, 222, 226, 235, 238, 241, 244, 247, 253, 256, 257, 259, 262, 265, 268, 269, 271, 290, 295, 315], "decompress": 5, "bomb": 5, "attack": 5, "warn": [5, 235, 244, 273, 281, 304, 309, 310, 311, 312], "make": [5, 11, 12, 13, 15, 17, 24, 27, 32, 43, 51, 54, 57, 58, 59, 63, 64, 66, 67, 69, 70, 71, 90, 97, 98, 109, 112, 113, 114, 115, 116, 118, 119, 121, 124, 126, 127, 129, 132, 136, 137, 141, 142, 145, 149, 151, 153, 154, 155, 156, 165, 166, 168, 171, 172, 173, 174, 175, 179, 180, 181, 184, 185, 192, 193, 196, 198, 199, 201, 202, 206, 207, 219, 221, 222, 227, 233, 235, 236, 238, 240, 241, 242, 243, 244, 245, 248, 250, 251, 253, 254, 255, 256, 257, 258, 260, 261, 263, 264, 265, 266, 267, 268, 270, 271, 272, 276, 277, 278, 291, 294, 295, 307, 313, 314, 315], "sure": [5, 13, 24, 63, 109, 112, 113, 114, 116, 118, 121, 124, 126, 127, 129, 132, 137, 222, 226, 239, 261, 263, 266, 271, 276, 277, 315], "orient": [5, 11, 30, 53, 54, 56, 72, 81, 82, 83, 84, 94, 117, 119, 128, 130, 136, 236, 270, 274, 275, 276, 277, 290, 293, 294, 295], "chang": [5, 11, 12, 14, 15, 20, 21, 24, 29, 30, 31, 33, 40, 46, 53, 59, 60, 61, 63, 67, 69, 72, 75, 77, 81, 117, 122, 128, 134, 137, 144, 149, 150, 154, 155, 159, 162, 168, 170, 172, 174, 176, 179, 181, 182, 183, 184, 185, 186, 187, 188, 192, 195, 199, 202, 206, 223, 226, 227, 233, 239, 240, 242, 246, 250, 255, 256, 258, 259, 261, 262, 264, 265, 268, 269, 270, 272, 274, 275, 277, 281, 291, 294, 295, 296, 303, 304, 306, 307, 309, 310, 311, 312, 313, 315], "defin": [5, 7, 9, 12, 13, 15, 17, 20, 21, 26, 28, 30, 32, 33, 35, 36, 37, 40, 45, 46, 53, 64, 65, 72, 73, 74, 75, 76, 77, 81, 82, 83, 84, 88, 94, 119, 143, 149, 150, 172, 174, 177, 219, 226, 236, 246, 250, 253, 254, 256, 268, 270, 271, 274, 279, 282, 285, 291, 294, 295, 310, 311, 312], "convert": [5, 45, 117, 143, 150, 153, 172, 185, 188, 194, 198, 199, 202, 226, 228, 264, 276, 277, 282, 294, 295, 297, 312], "geograph": [5, 36, 293], "latitud": [5, 274, 290, 293], "longitud": [5, 274, 290, 293], "degre": [5, 67, 80, 81, 82, 94, 109, 116, 185, 187, 202, 233, 263, 276, 277, 294], "radian": [5, 94, 294], "spheric": [5, 30, 64, 94, 114, 126, 135, 196, 227, 254, 257, 260, 263, 270, 271, 274, 276, 293], "lastli": [5, 19, 94, 181, 240, 271], "cartesian": [5, 293], "latlong_coordin": 5, "lat": 5, "lon": 5, "degrees_to_radian": 5, "pi": [5, 15, 25, 29, 66, 69, 82, 119, 259, 286, 293], "phi": [5, 35, 36, 37, 46, 50, 72, 73, 74, 263, 266, 271, 274, 290, 293], "theta": [5, 35, 36, 37, 46, 50, 72, 73, 74, 263, 266, 270, 271, 274, 275, 290, 293], "now": [5, 10, 14, 24, 28, 30, 31, 32, 35, 36, 37, 40, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 62, 63, 64, 65, 66, 67, 68, 72, 73, 74, 75, 77, 81, 82, 83, 84, 94, 95, 115, 119, 120, 122, 126, 127, 128, 130, 131, 134, 136, 141, 146, 149, 151, 152, 153, 155, 158, 159, 161, 162, 164, 165, 170, 174, 175, 176, 181, 183, 184, 185, 188, 189, 190, 192, 193, 194, 196, 197, 200, 202, 206, 209, 212, 214, 216, 218, 224, 227, 233, 236, 238, 239, 242, 244, 247, 251, 253, 254, 255, 258, 259, 262, 265, 266, 268, 270, 271, 272, 293, 315], "sin": [5, 15, 25, 29, 32, 33, 40, 66, 69, 82, 119, 276, 293], "co": [5, 15, 25, 32, 33, 40, 66, 69, 77, 82, 119, 259, 276, 293, 315], "flip": [5, 111, 185, 282, 307, 312, 313], "return": [5, 12, 15, 21, 24, 25, 26, 27, 28, 29, 30, 32, 36, 37, 40, 46, 53, 62, 64, 65, 66, 69, 72, 75, 76, 94, 95, 115, 119, 149, 189, 194, 203, 224, 226, 227, 238, 239, 241, 244, 267, 268, 270, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 313], "some": [5, 10, 11, 15, 24, 26, 27, 30, 31, 32, 33, 35, 36, 37, 39, 40, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 61, 62, 64, 65, 73, 74, 75, 76, 80, 81, 82, 83, 84, 90, 94, 95, 110, 111, 112, 113, 119, 120, 122, 128, 130, 132, 140, 143, 144, 146, 147, 149, 150, 151, 152, 153, 155, 156, 158, 159, 162, 164, 165, 168, 170, 172, 174, 176, 179, 180, 181, 182, 183, 184, 185, 187, 188, 190, 192, 193, 194, 196, 198, 201, 202, 203, 205, 206, 207, 208, 210, 211, 212, 214, 216, 217, 218, 219, 221, 222, 225, 226, 227, 231, 233, 235, 238, 239, 240, 241, 242, 244, 245, 246, 247, 249, 250, 253, 254, 256, 257, 258, 259, 260, 262, 263, 265, 266, 267, 268, 269, 270, 271, 272, 274, 284, 307, 309, 310, 311, 313], "sever": [5, 54, 135, 143, 146, 149, 150, 174, 223, 240, 254, 257, 260, 266, 268, 270, 272, 306], "big": [5, 181, 250, 259, 268], "citi": 5, "around": [5, 12, 15, 26, 28, 32, 63, 82, 94, 147, 150, 169, 179, 180, 181, 186, 188, 192, 195, 202, 206, 216, 219, 221, 226, 231, 250, 253, 259, 264, 267, 268, 272, 274, 276, 286, 287, 288, 293, 295, 296], "locationon": 5, "40": [5, 10, 26, 46, 47, 48, 53, 60, 66, 73, 74, 80, 294, 304], "730610": 5, "73": [5, 10, 305], "935242": 5, "york": 5, "u": [5, 15, 28, 32, 37, 40, 72, 73, 74, 75, 81, 82, 83, 97, 98, 106, 120, 135, 136, 138, 158, 162, 178, 179, 180, 182, 212, 228, 229, 243, 259, 264, 267, 270], "locationtwo": 5, "916668": 5, "116": [5, 309], "383331": 5, "beij": 5, "china": 5, "locationthre": 5, "48": [5, 10, 25, 270, 287, 304], "864716": 5, "349014": 5, "pari": 5, "franc": 5, "set": [5, 6, 8, 9, 13, 14, 15, 18, 19, 24, 27, 28, 30, 31, 32, 39, 44, 45, 46, 47, 49, 50, 53, 54, 56, 57, 58, 60, 63, 65, 66, 67, 69, 72, 73, 74, 75, 80, 81, 82, 83, 84, 87, 88, 90, 95, 115, 125, 130, 136, 155, 159, 173, 181, 182, 185, 187, 193, 195, 196, 197, 201, 204, 206, 208, 211, 214, 218, 222, 225, 227, 228, 231, 232, 235, 238, 244, 247, 256, 258, 259, 261, 265, 267, 268, 269, 270, 271, 272, 274, 275, 276, 277, 281, 282, 287, 290, 291, 292, 294, 295, 296, 308, 310, 313, 314, 315], "radii": [5, 10, 11, 12, 15, 16, 20, 21, 35, 36, 37, 46, 50, 59, 62, 66, 72, 73, 74, 80, 81, 82, 84, 87, 88, 89, 94, 173, 274, 287], "indic": [5, 28, 35, 36, 82, 84, 94, 132, 189, 191, 275, 276, 279, 282, 287, 288, 290, 294, 295], "its": [5, 10, 14, 15, 21, 24, 27, 30, 46, 47, 50, 60, 63, 69, 75, 81, 83, 94, 97, 111, 115, 119, 122, 125, 130, 131, 141, 142, 148, 150, 153, 156, 162, 180, 181, 183, 195, 198, 211, 213, 220, 222, 227, 235, 236, 237, 238, 240, 242, 243, 244, 245, 247, 248, 249, 250, 251, 253, 256, 259, 262, 267, 268, 270, 271, 272, 274, 275, 276, 277, 281, 291, 294, 296, 316], "nyc_actor": 5, "n40": 5, "7128": 5, "n": [5, 11, 28, 32, 34, 82, 89, 91, 149, 172, 174, 187, 259, 268, 274, 275, 276, 277, 287, 290, 292, 293, 294, 295, 315], "74": [5, 10], "0060": 5, "w": [5, 29, 40, 94, 149, 150, 172, 174, 274, 277, 283, 292, 295], "paris_actor": 5, "n48": 5, "8566": 5, "3522": 5, "e": [5, 24, 25, 29, 33, 49, 64, 68, 72, 94, 95, 97, 99, 100, 101, 102, 104, 105, 107, 123, 133, 139, 153, 167, 168, 172, 173, 177, 219, 220, 226, 227, 228, 230, 247, 259, 268, 270, 271, 274, 275, 276, 277, 279, 284, 287, 294, 295, 296, 308, 315], "beijing_actor": 5, "n39": 5, "9042": 5, "4074": 5, "06": [5, 27, 29, 33, 135, 136, 172, 173, 174, 226, 227, 228, 270, 272], "85": [5, 10, 15, 46, 305], "which": [5, 7, 11, 12, 14, 15, 24, 25, 26, 27, 28, 29, 31, 32, 33, 35, 36, 37, 38, 39, 40, 50, 54, 62, 65, 68, 72, 75, 81, 83, 84, 87, 88, 89, 94, 97, 110, 114, 115, 117, 119, 120, 122, 125, 127, 129, 130, 131, 132, 134, 135, 136, 137, 140, 141, 142, 143, 144, 145, 146, 147, 149, 150, 151, 152, 153, 154, 155, 156, 159, 162, 165, 166, 168, 169, 170, 171, 172, 173, 174, 179, 181, 182, 183, 184, 185, 186, 187, 188, 191, 192, 193, 195, 198, 199, 201, 202, 203, 206, 207, 208, 210, 212, 216, 217, 219, 221, 222, 226, 227, 231, 233, 234, 235, 237, 239, 240, 242, 245, 247, 248, 249, 250, 252, 253, 254, 255, 256, 257, 258, 259, 265, 266, 267, 268, 270, 271, 272, 274, 275, 276, 277, 281, 284, 287, 288, 290, 291, 292, 293, 294, 295, 296, 315], "act": [5, 26, 122, 208, 226, 274, 294, 295], "angl": [5, 15, 29, 33, 40, 53, 54, 56, 119, 168, 226, 239, 270, 271, 274, 275, 277, 293, 294, 295, 296, 297], "fly": [5, 162], "over": [5, 75, 87, 108, 124, 126, 134, 180, 236, 243, 248, 268, 271, 282, 294, 315], "7": [5, 10, 15, 18, 25, 26, 28, 36, 37, 40, 60, 61, 63, 66, 72, 82, 83, 84, 97, 135, 136, 155, 172, 173, 174, 194, 226, 227, 228, 270, 272, 274, 275, 277, 292, 294, 295, 298, 300, 303, 305, 312, 313, 315], "200": [5, 11, 12, 17, 20, 24, 25, 28, 30, 33, 36, 40, 47, 49, 50, 51, 52, 54, 55, 56, 69, 181, 251, 292, 294], "015": [5, 23, 36], "pitch": [5, 28, 293, 296, 297], "250": [5, 14, 47, 49, 53, 54, 63, 135, 308], "350": [5, 54, 294, 310], "985": 5, "425": [5, 303], "525": [5, 180, 313], "011": 5, "700": [5, 58, 80, 228, 313], "820": [5, 252, 272, 303], "930": 5, "1000": [5, 21, 31, 36, 38, 44, 45, 46, 66, 88, 89, 253, 259], "initi": [5, 6, 7, 9, 10, 13, 15, 24, 25, 26, 29, 31, 33, 38, 39, 40, 45, 54, 59, 61, 62, 63, 64, 65, 66, 68, 69, 81, 83, 84, 95, 99, 110, 114, 115, 116, 141, 153, 159, 172, 173, 179, 195, 206, 227, 234, 244, 255, 256, 258, 259, 261, 264, 265, 267, 268, 270, 272, 277, 284, 288, 292, 293, 294, 296, 297, 299, 307, 313], "displai": [6, 7, 11, 14, 18, 22, 23, 24, 26, 27, 29, 30, 33, 39, 40, 54, 72, 75, 80, 81, 82, 83, 90, 97, 153, 160, 162, 168, 169, 173, 192, 193, 226, 228, 231, 236, 242, 248, 251, 257, 260, 270, 272, 274, 275, 288, 292, 294, 297, 312, 314], "fetch_gltf": [6, 7, 8, 9, 13, 189, 297], "read_viz_gltf": [6, 7, 8, 9, 13, 297], "setbackground": 6, "retriev": [6, 7, 9, 13, 247, 259, 270, 271, 272, 288, 291], "duck": [6, 194], "filenam": [6, 7, 8, 9, 13, 15, 19, 274, 279, 282, 283, 291, 294, 296], "get": [6, 7, 8, 9, 11, 13, 14, 18, 21, 24, 25, 28, 31, 32, 37, 38, 40, 46, 53, 59, 72, 75, 80, 81, 83, 94, 97, 108, 109, 135, 143, 155, 174, 180, 181, 226, 227, 228, 231, 241, 247, 250, 253, 256, 259, 262, 265, 268, 269, 270, 274, 276, 277, 278, 281, 282, 284, 287, 289, 290, 292, 294, 295, 296, 307, 313], "method": [6, 7, 9, 12, 13, 14, 24, 27, 30, 32, 40, 46, 47, 53, 57, 59, 61, 68, 72, 75, 80, 81, 82, 83, 84, 90, 94, 111, 113, 115, 117, 120, 122, 131, 132, 135, 136, 143, 144, 146, 147, 149, 150, 151, 153, 155, 156, 158, 159, 162, 172, 174, 176, 179, 182, 183, 185, 188, 189, 194, 201, 206, 210, 211, 212, 221, 224, 227, 228, 235, 238, 240, 241, 244, 247, 265, 268, 270, 272, 274, 275, 276, 277, 281, 285, 287, 292, 295, 296, 307, 311, 312, 313], "note": [6, 9, 12, 13, 25, 27, 29, 43, 53, 54, 59, 62, 67, 99, 100, 101, 102, 104, 105, 107, 123, 133, 139, 167, 177, 179, 213, 230, 253, 265, 274, 275, 276, 277, 278, 281, 287, 292, 293, 295, 296, 298, 315], "alwai": [6, 60, 63, 72, 94, 115, 117, 119, 120, 122, 125, 128, 143, 147, 179, 180, 199, 274, 315], "manual": [6, 64, 65, 94, 136, 156, 186, 189, 195, 201, 204, 214, 216, 266, 270, 271, 315], "polydata": [6, 18, 77, 132, 185, 189, 190, 203, 227, 283, 295, 297, 307, 313], "appli": [6, 9, 13, 14, 15, 18, 21, 31, 49, 75, 80, 81, 82, 83, 84, 94, 128, 149, 179, 181, 182, 183, 185, 193, 198, 203, 205, 213, 215, 218, 220, 222, 228, 237, 240, 253, 256, 259, 268, 270, 274, 275, 282, 283, 284, 286, 290, 291, 292, 295, 296, 297], "materi": [6, 37, 73, 74, 139, 177, 180, 189, 224, 282, 297, 310, 312, 313, 316], "afterward": [6, 238], "experiment": [6, 97, 263, 268, 306], "smooth": [6, 32, 65, 75, 158, 171, 173, 174, 182, 192, 231, 247, 253, 261, 268, 270, 272, 274], "mesh": [6, 72, 75, 181, 185, 205, 213, 228, 270, 282, 293], "apply_norm": [6, 9, 13, 282], "gltf_obj": [6, 7, 8, 9, 13], "all": [6, 8, 9, 11, 12, 14, 15, 17, 24, 28, 30, 31, 35, 36, 37, 43, 46, 50, 51, 52, 54, 55, 56, 61, 64, 65, 67, 72, 75, 76, 77, 80, 81, 82, 83, 84, 90, 94, 97, 98, 102, 104, 105, 107, 109, 115, 117, 119, 123, 128, 133, 134, 136, 137, 139, 141, 142, 143, 149, 150, 152, 155, 159, 162, 163, 167, 168, 170, 171, 172, 173, 177, 179, 180, 181, 186, 188, 189, 190, 191, 193, 194, 195, 196, 197, 198, 200, 201, 206, 207, 208, 212, 215, 220, 222, 223, 224, 226, 227, 228, 230, 231, 232, 235, 240, 252, 253, 255, 256, 259, 262, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 279, 282, 287, 289, 290, 294, 295, 296, 310, 312, 313, 314, 315, 316], "list": [6, 8, 15, 25, 26, 27, 28, 30, 31, 39, 45, 46, 47, 50, 53, 54, 55, 59, 60, 67, 73, 74, 82, 84, 94, 106, 113, 136, 138, 142, 149, 152, 155, 156, 178, 179, 180, 181, 185, 203, 229, 266, 270, 273, 274, 276, 277, 279, 281, 282, 283, 284, 286, 291, 292, 293, 294, 295, 296, 298, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 315, 316], "setactivecamera": 6, "1280": [6, 8], "720": [6, 8, 76, 77, 89, 95, 290, 313], "135": [6, 307], "interpolationtest": [7, 194], "main_timelin": [7, 193], "contain": [7, 12, 14, 15, 21, 24, 26, 28, 30, 32, 40, 54, 60, 62, 64, 66, 67, 72, 94, 97, 98, 99, 106, 125, 136, 138, 141, 142, 150, 153, 178, 185, 191, 193, 194, 220, 226, 228, 229, 258, 272, 273, 276, 277, 281, 282, 283, 286, 287, 289, 291, 292, 293, 295, 296, 297, 299, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313], "timelin": [7, 9, 13, 57, 58, 59, 61, 64, 66, 67, 69, 90, 140, 182, 185, 187, 190, 197, 200, 202, 203, 208, 218, 220, 221, 223, 224, 225, 296, 297, 313, 314], "main_anim": [7, 282, 297], "No": [7, 9, 13, 65, 121, 124, 127, 129, 157, 163, 166, 168, 169, 170, 171, 184, 188, 191, 194, 200, 204, 209, 210, 213, 215, 217, 219, 220, 224, 238, 243, 277, 313], "need": [7, 9, 13, 14, 15, 18, 24, 27, 28, 31, 32, 35, 36, 37, 39, 43, 44, 45, 46, 47, 48, 50, 51, 52, 53, 54, 55, 56, 59, 60, 62, 64, 65, 67, 69, 72, 74, 75, 87, 89, 94, 95, 97, 110, 113, 118, 122, 130, 132, 134, 136, 140, 143, 144, 145, 147, 149, 150, 152, 153, 155, 156, 159, 162, 170, 172, 174, 191, 194, 199, 203, 205, 206, 213, 215, 218, 220, 223, 226, 227, 228, 231, 235, 236, 238, 239, 241, 242, 244, 245, 247, 248, 249, 250, 251, 253, 254, 256, 257, 259, 262, 263, 266, 267, 268, 269, 270, 271, 272, 276, 277, 278, 290, 294, 295, 296, 307, 310, 313], "separ": [7, 9, 13, 60, 94, 115, 117, 122, 128, 131, 136, 155, 170, 174, 184, 189, 190, 195, 202, 223, 226, 227, 240, 249, 267, 268, 270, 279, 287, 292, 303, 313], "updat": [7, 9, 10, 11, 12, 13, 15, 18, 24, 25, 26, 29, 30, 32, 38, 40, 45, 60, 64, 65, 77, 81, 83, 84, 94, 100, 101, 104, 105, 107, 109, 117, 119, 123, 128, 133, 136, 139, 143, 149, 150, 152, 153, 155, 156, 157, 159, 160, 162, 163, 165, 166, 167, 168, 169, 170, 172, 173, 174, 176, 177, 186, 192, 195, 199, 201, 204, 210, 216, 221, 223, 226, 227, 228, 230, 232, 235, 238, 240, 243, 247, 252, 253, 255, 257, 258, 259, 261, 264, 265, 267, 268, 272, 274, 276, 277, 282, 288, 292, 294, 295, 296, 297, 301, 302, 303, 305, 306, 307, 308, 309, 310, 311, 312, 313, 315], "update_anim": [7, 276, 297], "10": [7, 10, 11, 14, 15, 17, 18, 20, 21, 28, 29, 32, 33, 34, 36, 38, 40, 48, 52, 53, 54, 55, 56, 59, 60, 63, 64, 65, 67, 68, 72, 74, 75, 80, 81, 82, 83, 84, 94, 126, 135, 136, 139, 155, 172, 173, 174, 181, 226, 227, 228, 256, 268, 270, 272, 274, 277, 281, 290, 292, 294, 295, 296, 298, 307, 310, 312, 313], "156": [7, 307], "paramet": [8, 15, 28, 30, 36, 37, 40, 55, 65, 72, 73, 74, 80, 81, 82, 83, 84, 89, 94, 95, 115, 120, 152, 158, 200, 216, 226, 228, 242, 245, 254, 257, 263, 265, 267, 268, 269, 270, 273, 274, 275, 276, 277, 278, 279, 281, 282, 283, 284, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 304, 307, 308, 309, 310, 312, 313], "later": [8, 40, 60, 61, 63, 122, 128, 142, 149, 180, 188, 189, 233, 236, 239, 241, 242, 244, 253, 265, 267, 268, 270, 271, 281, 291], "cube": [8, 11, 12, 17, 18, 26, 32, 37, 40, 41, 42, 46, 61, 66, 69, 90, 112, 114, 121, 125, 130, 135, 179, 194, 271, 279, 283, 297, 303, 308, 314], "boxtextur": [8, 194, 279], "box_actor": [8, 21, 75, 84, 274, 275], "45": [8, 10, 14, 15, 25, 39, 51, 54, 304], "21": [8, 10, 25, 135, 136, 172, 173, 174, 179, 226, 298, 304, 309, 311], "12": [8, 10, 12, 16, 25, 28, 33, 64, 66, 72, 75, 135, 136, 155, 172, 173, 174, 194, 226, 227, 228, 259, 268, 270, 272, 274, 290, 295, 303, 312, 313], "export_scen": [8, 297], "read": [8, 14, 32, 35, 36, 38, 111, 113, 114, 115, 117, 119, 120, 122, 125, 128, 130, 131, 134, 136, 143, 146, 149, 151, 155, 160, 169, 171, 179, 180, 181, 183, 185, 194, 200, 228, 235, 278, 279, 282, 292, 296], "120": [8, 24, 30, 46, 65, 68, 69, 194, 307], "look": [9, 27, 32, 72, 110, 111, 115, 118, 122, 126, 127, 128, 130, 131, 132, 143, 147, 149, 152, 153, 155, 170, 171, 180, 181, 185, 189, 194, 201, 202, 207, 210, 217, 219, 220, 234, 236, 243, 247, 253, 254, 256, 259, 261, 263, 264, 265, 268, 270, 271, 274, 315], "khronoo": 9, "sampl": [9, 38, 185, 189, 194, 197, 203, 235, 247, 271, 276, 279, 296, 313], "choos": [9, 13, 17, 27, 30, 47, 53, 54, 87, 89, 132, 143, 174, 242, 248, 277, 279, 288, 294], "morphstresstest": [9, 194], "addition": [9, 13, 72, 237, 240, 248, 249, 252, 258, 270, 271], "might": [9, 13, 59, 62, 65, 72, 199, 226, 248, 263, 267, 270, 271, 272, 277, 315], "work": [9, 12, 13, 27, 32, 72, 87, 88, 97, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 119, 120, 122, 124, 125, 126, 127, 128, 129, 130, 131, 132, 134, 137, 140, 141, 142, 144, 146, 149, 150, 153, 155, 157, 158, 159, 161, 163, 165, 168, 170, 171, 174, 176, 179, 180, 181, 182, 183, 184, 185, 186, 188, 189, 190, 193, 194, 197, 199, 203, 204, 206, 207, 210, 212, 213, 215, 216, 217, 219, 231, 233, 235, 236, 237, 238, 239, 240, 241, 243, 244, 245, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, 259, 261, 262, 263, 264, 265, 266, 267, 269, 271, 274, 292, 293, 306, 308, 309, 310, 311, 313, 315], "intend": [9, 13, 28, 75, 170, 192, 203, 205, 207, 213, 216, 236, 270, 272, 274, 311], "morph_timelin": 9, "name": [9, 13, 15, 17, 24, 25, 26, 33, 40, 46, 62, 68, 75, 135, 136, 140, 149, 172, 173, 174, 179, 181, 189, 193, 194, 206, 214, 226, 227, 228, 233, 248, 256, 268, 270, 272, 273, 274, 275, 276, 277, 279, 281, 282, 287, 290, 291, 292, 293, 294, 295, 296, 307, 309, 313, 315, 316], "It": [9, 13, 14, 18, 25, 27, 31, 40, 62, 72, 99, 117, 122, 130, 134, 135, 143, 150, 153, 158, 166, 168, 170, 171, 173, 174, 176, 177, 179, 180, 181, 182, 194, 195, 198, 201, 207, 212, 213, 218, 223, 226, 227, 228, 231, 232, 237, 240, 245, 250, 251, 256, 265, 266, 268, 271, 272, 274, 276, 277, 281, 287, 290, 294, 299, 312, 315], "store": [9, 13, 25, 26, 27, 32, 39, 46, 47, 65, 75, 81, 83, 87, 94, 95, 149, 151, 155, 158, 185, 194, 198, 200, 206, 221, 226, 228, 231, 268, 271, 277, 279, 287, 292, 294], "anim_0": [9, 13], "anim_1": [9, 13], "etc": [9, 13, 24, 35, 94, 115, 136, 170, 179, 181, 186, 228, 253, 277, 279, 287, 294, 308], "morph_anim": [9, 282, 297], "thewav": 9, "call": [9, 11, 12, 13, 15, 17, 20, 27, 29, 33, 38, 47, 54, 64, 77, 81, 83, 94, 130, 145, 146, 147, 149, 162, 166, 174, 176, 180, 181, 190, 195, 198, 199, 201, 216, 226, 231, 240, 241, 242, 244, 256, 265, 268, 274, 275, 276, 281, 287, 289, 291, 292, 293, 296, 304, 311, 312, 313, 315], "update_morph": [9, 282, 297], "onc": [9, 27, 32, 54, 60, 68, 94, 119, 120, 121, 122, 131, 155, 168, 180, 181, 184, 195, 206, 208, 209, 212, 226, 227, 243, 266, 269, 272, 276, 294, 296, 307, 315], "move": [9, 12, 14, 21, 24, 26, 32, 33, 36, 63, 65, 82, 94, 115, 119, 120, 125, 128, 176, 179, 181, 198, 207, 212, 215, 217, 222, 226, 235, 238, 243, 253, 277, 294, 306, 310, 313, 315], "initialis": [9, 13, 26, 43, 44, 45, 46, 50, 51, 52, 54, 55, 56, 76, 77, 282, 307], "timestamp": [9, 59, 60, 62, 64, 65, 67, 155, 213, 215, 218, 228, 276, 282], "fit": [9, 25, 98, 143, 162, 239, 250, 253, 270, 271, 294, 296, 316], "perfectli": [9, 75, 162, 188, 213, 259, 265, 270], "manag": [9, 10, 11, 12, 13, 14, 28, 37, 38, 43, 44, 45, 51, 52, 53, 55, 61, 62, 63, 67, 69, 76, 77, 81, 82, 83, 107, 108, 109, 133, 141, 146, 149, 150, 155, 156, 158, 164, 174, 175, 180, 183, 186, 187, 189, 192, 193, 194, 195, 198, 207, 216, 222, 224, 226, 233, 238, 241, 243, 244, 246, 250, 253, 254, 256, 258, 262, 267, 268, 271, 288, 292, 294, 296, 305, 306, 307, 309, 313, 315], "option": [9, 10, 13, 27, 32, 46, 47, 50, 68, 72, 87, 89, 94, 97, 111, 115, 122, 126, 132, 136, 156, 164, 179, 185, 193, 196, 211, 221, 226, 227, 237, 250, 255, 256, 257, 258, 265, 266, 274, 275, 276, 277, 278, 279, 281, 282, 283, 284, 286, 287, 288, 290, 291, 292, 295, 296, 297, 307, 308, 310, 313, 315], "plai": [9, 13, 22, 23, 35, 64, 67, 68, 72, 90, 168, 170, 172, 186, 190, 199, 219, 226, 227, 272, 276, 294, 296, 297, 313, 314], "auto": [9, 13, 156, 272, 277], "20": [9, 10, 13, 14, 15, 17, 21, 26, 27, 28, 29, 32, 33, 40, 46, 54, 56, 60, 61, 63, 64, 67, 75, 82, 109, 174, 180, 181, 226, 227, 228, 270, 274, 276, 290, 292, 294, 295, 296, 298, 304, 307, 310], "165": [9, 307], "goal": [10, 35, 36, 38, 65, 97, 141, 142, 145, 147, 151, 154, 166, 172, 173, 174, 226, 227, 228, 232, 235, 236, 243, 268, 272], "demo": [10, 21, 23, 32, 36, 38, 65, 74, 78, 127, 129, 132, 135, 137, 139, 167, 172, 173, 177, 210, 228, 252, 256, 270, 272, 307, 310, 311, 312, 313, 314], "differ": [10, 11, 12, 14, 20, 24, 28, 32, 37, 41, 42, 46, 47, 53, 57, 61, 65, 72, 73, 74, 75, 81, 83, 87, 90, 94, 113, 115, 116, 117, 119, 122, 125, 132, 134, 135, 141, 142, 147, 149, 151, 153, 155, 162, 172, 174, 176, 182, 183, 186, 188, 190, 193, 197, 201, 203, 204, 206, 217, 219, 221, 222, 226, 228, 238, 247, 248, 249, 250, 253, 256, 259, 263, 265, 266, 268, 270, 271, 274, 275, 278, 279, 293, 295, 296, 314], "thread": [10, 143, 149, 174, 176, 292, 296], "particular": [10, 94, 111, 119, 128, 130, 150, 156, 172, 187, 316], "main": [10, 24, 44, 45, 61, 64, 66, 73, 87, 88, 89, 111, 113, 114, 115, 116, 120, 124, 127, 131, 143, 147, 149, 150, 153, 155, 172, 174, 193, 200, 203, 206, 226, 227, 235, 237, 238, 248, 255, 257, 259, 270, 271, 272, 274, 275, 276, 282, 294, 297, 315], "A": [10, 22, 27, 29, 32, 33, 36, 38, 40, 44, 45, 46, 50, 60, 62, 65, 72, 75, 81, 90, 91, 94, 106, 131, 136, 138, 140, 142, 144, 147, 149, 150, 162, 168, 172, 174, 175, 178, 181, 199, 206, 226, 228, 229, 231, 237, 268, 270, 274, 275, 276, 277, 278, 279, 282, 286, 287, 289, 290, 291, 292, 294, 295, 296, 316], "b": [10, 29, 30, 36, 39, 109, 146, 149, 174, 241, 244, 245, 270, 274, 275, 277, 281, 286, 287, 290, 295, 315], "print": [10, 18, 24, 25, 27, 95, 97, 149, 180, 183, 244, 296], "c": [10, 15, 29, 72, 75, 97, 99, 100, 101, 102, 104, 105, 107, 123, 133, 139, 149, 155, 167, 168, 174, 177, 179, 180, 194, 207, 230, 270, 274, 275, 277, 279, 296, 315, 316], "element": [10, 14, 37, 42, 43, 44, 45, 46, 50, 51, 52, 54, 55, 56, 72, 76, 77, 94, 109, 111, 113, 115, 117, 125, 136, 141, 144, 147, 150, 153, 155, 156, 162, 165, 172, 183, 184, 198, 201, 207, 219, 226, 227, 237, 240, 243, 249, 258, 268, 270, 272, 274, 277, 282, 284, 287, 292, 293, 296, 297, 303, 308, 311, 314], "9": [10, 15, 26, 59, 60, 63, 64, 67, 72, 73, 74, 75, 84, 94, 97, 135, 136, 139, 155, 172, 173, 174, 177, 182, 185, 194, 226, 227, 228, 257, 270, 272, 274, 277, 284, 291, 294, 295, 298, 303, 308, 309, 310, 312, 315], "13": [10, 15, 67, 72, 81, 83, 135, 136, 155, 158, 174, 226, 227, 228, 298, 305, 311, 313], "14": [10, 37, 42, 60, 67, 135, 136, 155, 172, 173, 174, 226, 228, 277, 295, 304, 310, 313], "15": [10, 14, 24, 33, 45, 46, 54, 56, 59, 60, 67, 69, 80, 84, 174, 226, 228, 272, 298, 303, 305, 306, 307, 309, 311], "16": [10, 15, 23, 32, 36, 37, 40, 46, 50, 60, 72, 75, 97, 135, 136, 158, 172, 173, 174, 226, 227, 270, 272, 274, 284, 292, 294, 295, 313], "17": [10, 25, 32, 67, 72, 87, 158, 161, 174, 226, 228, 268, 270, 272, 295, 304, 306], "18": [10, 23, 24, 25, 27, 30, 32, 46, 54, 59, 80, 81, 83, 161, 174, 180, 294, 305, 308], "22": [10, 15, 63, 164, 175, 226, 272, 304, 313], "23": [10, 37, 60, 95, 135, 136, 175, 176, 227, 270, 295, 303, 304], "26": [10, 73, 74, 81, 83, 84, 135, 136, 149, 172, 173, 174, 298, 304], "28": [10, 84, 135, 136, 149, 172, 173, 174, 227, 228, 295, 298, 304, 312], "29": [10, 60, 226, 228, 268, 272, 295, 298, 304, 307], "30": [10, 11, 15, 21, 25, 26, 27, 46, 50, 54, 55, 56, 60, 63, 77, 80, 81, 82, 83, 84, 135, 136, 180, 227, 274, 276, 294, 304], "32": [10, 37, 73, 74, 75, 181, 259, 268, 304, 306], "33": [10, 15, 43, 54, 149, 292, 296], "36": [10, 290, 295, 305], "37": [10, 61, 304, 310], "38": [10, 24, 30], "41": [10, 15, 37, 304], "43": [10, 304], "44": [10, 37, 290, 294, 295, 304], "46": [10, 81, 83, 304], "47": [10, 304, 312], "49": [10, 53, 60, 304, 307], "50": [10, 11, 15, 21, 28, 39, 43, 46, 47, 48, 50, 51, 54, 64, 80, 276, 287, 292, 294, 304], "51": [10, 308], "52": [10, 27, 304], "53": [10, 39, 305], "54": [10, 303, 307, 311], "55": [10, 14, 24, 27, 30, 44, 45, 304], "56": [10, 27, 304], "57": [10, 81, 83, 84, 270, 275, 304], "58": [10, 15, 304], "60": [10, 15, 25, 64, 126, 274, 296, 304, 308], "61": [10, 304, 310], "62": [10, 305], "63": [10, 305], "64": [10, 37, 61, 179], "65": [10, 305], "66": [10, 15, 43, 54, 306], "67": [10, 305], "68": [10, 37, 61, 305], "69": [10, 305], "70": [10, 15, 66], "71": [10, 307], "72": [10, 283, 296, 305], "76": [10, 27, 307, 314], "77": [10, 37, 307], "78": [10, 80], "79": [10, 81, 83, 305], "80": [10, 27, 181, 305], "81": [10, 27, 307, 312], "82": [10, 313], "83": [10, 305], "84": [10, 305], "86": [10, 37, 305], "87": [10, 28, 305], "88": [10, 305], "89": [10, 80, 305, 311], "91": [10, 279, 305], "92": [10, 306], "93": 10, "94": [10, 53, 306], "95": [10, 37, 179], "96": [10, 306], "97": [10, 27, 306], "98": [10, 12, 27, 306, 310], "99": [10, 83, 194, 307], "ui": [10, 11, 14, 15, 20, 21, 24, 25, 26, 28, 29, 30, 32, 33, 37, 40, 41, 42, 43, 44, 45, 46, 47, 48, 50, 51, 54, 55, 56, 77, 80, 81, 82, 83, 84, 90, 95, 99, 107, 109, 111, 113, 115, 117, 122, 123, 128, 130, 131, 132, 133, 134, 135, 136, 137, 141, 162, 165, 167, 172, 177, 180, 181, 182, 188, 201, 204, 207, 219, 226, 227, 234, 237, 240, 243, 249, 258, 259, 262, 267, 268, 269, 272, 284, 295, 297, 299, 303, 305, 307, 308, 309, 310, 311, 312, 313, 314], "prepar": [10, 35, 36, 53, 179, 181, 234, 253, 254, 264, 270, 272, 296, 303, 307], "draw": [10, 32, 48, 51, 54, 147, 151, 170, 172, 174, 175, 176, 180, 183, 186, 201, 204, 206, 207, 212, 226, 235, 238, 274, 294, 311, 313], "xyz": [10, 11, 20, 21, 25, 61, 75, 94, 193, 227, 276, 277, 288, 290, 295], "100": [10, 11, 12, 15, 20, 28, 33, 36, 43, 45, 46, 49, 51, 52, 54, 56, 62, 74, 83, 117, 126, 181, 247, 251, 255, 274, 276, 278, 279, 283, 292, 294, 295, 306], "usual": [10, 14, 17, 28, 31, 68, 73, 188, 226, 231, 247, 256, 274, 277, 296], "block": [10, 55, 75, 77, 95, 115, 143, 146, 149, 159, 174, 291, 294, 311, 312], "messag": [10, 11, 14, 20, 21, 24, 25, 26, 29, 30, 33, 43, 54, 77, 80, 81, 82, 83, 84, 95, 149, 235, 281, 294, 297, 313], "reset": [10, 32, 296], "tb": [10, 20, 21, 25, 26, 29, 33, 40, 77, 80, 81, 82, 83, 84, 95], "textblock2d": [10, 11, 14, 20, 21, 24, 25, 26, 29, 30, 33, 37, 40, 43, 47, 53, 54, 55, 77, 80, 81, 82, 83, 84, 95, 111, 113, 120, 136, 183, 226, 240, 252, 255, 261, 267, 272, 297, 303, 308], "bold": [10, 20, 21, 24, 25, 26, 29, 30, 33, 274, 294, 297], "resetcamera": 10, "consol": 10, "print_count": 10, "rang": [10, 15, 25, 26, 29, 32, 34, 36, 37, 38, 40, 60, 61, 63, 73, 74, 81, 82, 83, 84, 94, 207, 261, 268, 272, 274, 275, 277, 286, 287, 290, 295], "rcounter": 10, "d": [10, 29, 34, 40, 136, 140, 169, 174, 270, 274, 275, 293, 294], "up": [10, 14, 20, 21, 26, 27, 28, 32, 39, 43, 54, 60, 72, 73, 74, 75, 84, 94, 143, 172, 179, 180, 181, 227, 238, 241, 244, 247, 253, 265, 268, 272, 276, 281, 294, 295, 296, 304, 310, 315], "str": [10, 11, 14, 20, 21, 25, 35, 36, 73, 74, 81, 82, 83, 84, 88, 273, 274, 275, 276, 277, 278, 279, 281, 282, 283, 284, 285, 289, 290, 291, 292, 294, 295, 296, 305], "sleep": [10, 89, 149, 292], "is_don": [10, 296, 297], "break": [10, 14, 38, 134, 155, 174, 239, 268], "rotate_camera": 10, "lock_curr": [10, 296, 297], "release_curr": [10, 296, 297], "els": [10, 11, 13, 15, 24, 25, 30, 32, 36, 38, 40, 46, 48, 53, 72, 75, 87, 89, 94, 115, 227, 274, 275, 277, 280, 294], "ax": [10, 11, 17, 25, 28, 80, 81, 82, 83, 84, 125, 172, 236, 275, 293, 296, 297, 303], "increas": [10, 11, 12, 26, 27, 36, 40, 72, 75, 81, 82, 83, 84, 94, 102, 104, 105, 107, 117, 123, 133, 143, 167, 222, 295, 296, 304, 305, 306, 307, 308, 309, 310, 311], "add_remove_ax": 10, "current_ax": 10, "none": [10, 12, 14, 17, 30, 36, 38, 54, 59, 62, 77, 149, 194, 267, 273, 274, 275, 276, 277, 278, 279, 281, 282, 283, 284, 287, 289, 290, 291, 292, 294, 295, 296, 313], "pass": [10, 28, 40, 75, 76, 77, 89, 94, 115, 116, 118, 124, 147, 149, 151, 153, 158, 159, 160, 172, 180, 181, 216, 226, 243, 244, 247, 250, 253, 254, 256, 257, 258, 259, 260, 265, 266, 268, 269, 270, 271, 274, 281, 292, 294, 295, 310, 313, 315], "thread_a": 10, "target": [10, 35, 36, 87, 88, 228, 276, 282], "thread_b": 10, "thread_c": 10, "loop": [10, 14, 32, 60, 69, 89, 94, 173, 199, 226, 227, 256, 268, 274, 276, 282, 294, 297, 313], "wait": [10, 87, 146, 149, 179, 239, 242, 296, 297], "finish": [10, 120, 122, 125, 134, 140, 153, 165, 168, 172, 174, 182, 190, 191, 211, 233, 245, 250, 253, 254, 259, 265, 296], "join": [10, 14, 35, 36, 45, 72, 75, 88, 95, 99, 100, 101, 102, 104, 105, 106, 107, 123, 133, 138, 139, 167, 177, 178, 180, 226, 229, 230], "present": [11, 14, 33, 94, 147, 149, 150, 156, 174, 176, 226, 238, 250, 256, 259, 265, 266, 268, 270, 272, 287], "3d": [11, 12, 14, 22, 23, 24, 26, 30, 32, 34, 37, 39, 40, 72, 75, 76, 90, 98, 99, 100, 101, 102, 104, 105, 106, 107, 109, 120, 123, 133, 138, 139, 141, 146, 152, 167, 168, 172, 173, 174, 177, 178, 181, 223, 226, 227, 228, 229, 230, 235, 253, 256, 268, 270, 274, 275, 277, 278, 283, 284, 288, 293, 295, 307, 308, 311, 314], "world": [11, 12, 22, 23, 24, 27, 75, 81, 83, 90, 94, 117, 128, 179, 180, 231, 268, 274, 275, 288, 314], "ar": [11, 12, 14, 15, 17, 24, 25, 27, 28, 29, 30, 32, 33, 34, 36, 37, 43, 44, 45, 46, 47, 48, 50, 51, 52, 53, 54, 55, 56, 60, 62, 65, 67, 68, 72, 73, 75, 81, 83, 84, 87, 94, 95, 97, 98, 99, 100, 101, 102, 104, 105, 106, 107, 108, 110, 113, 117, 118, 123, 124, 127, 128, 129, 130, 131, 132, 133, 135, 136, 137, 138, 139, 141, 143, 144, 147, 149, 150, 152, 153, 155, 156, 158, 159, 162, 165, 167, 168, 170, 172, 173, 174, 177, 178, 179, 181, 182, 193, 194, 198, 200, 206, 208, 212, 216, 217, 218, 223, 226, 227, 228, 229, 230, 231, 233, 235, 237, 238, 242, 243, 245, 247, 252, 253, 256, 257, 260, 263, 266, 267, 268, 269, 270, 271, 272, 274, 275, 276, 277, 279, 281, 283, 284, 287, 288, 289, 291, 293, 294, 295, 296, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 315, 316], "part": [11, 12, 32, 65, 72, 74, 94, 106, 117, 126, 136, 138, 140, 142, 143, 172, 178, 180, 181, 199, 206, 216, 226, 227, 228, 229, 231, 232, 233, 239, 241, 244, 250, 251, 254, 256, 258, 259, 262, 263, 266, 268, 272, 274, 277, 289, 294, 312, 315], "singl": [11, 12, 37, 60, 63, 68, 81, 114, 117, 119, 120, 122, 125, 135, 136, 150, 160, 187, 188, 190, 199, 227, 244, 252, 253, 256, 257, 265, 274, 276, 282, 283, 284, 287, 288, 294, 295, 296, 304, 309], "like": [11, 12, 14, 19, 24, 40, 72, 94, 102, 104, 105, 107, 109, 122, 123, 128, 133, 134, 136, 137, 139, 141, 142, 144, 147, 153, 155, 159, 167, 170, 171, 174, 177, 180, 185, 202, 208, 209, 217, 218, 219, 223, 227, 228, 230, 231, 236, 238, 244, 247, 250, 258, 263, 265, 268, 270, 271, 272, 281, 294, 295, 296, 315], "bundl": [11, 12, 22, 23, 24, 90, 314], "few": [11, 12, 94, 112, 122, 124, 136, 148, 150, 156, 170, 180, 181, 185, 206, 207, 210, 215, 243, 246, 258, 272, 277, 303], "reduc": [11, 12, 155, 179, 225, 274], "speed": [11, 12, 26, 40, 64, 98, 148, 177, 179, 196, 199, 227, 241, 276, 294, 296, 297, 312], "thei": [11, 24, 28, 35, 36, 54, 72, 73, 75, 94, 131, 136, 142, 144, 153, 156, 159, 162, 168, 170, 174, 180, 181, 182, 185, 200, 202, 206, 207, 212, 216, 222, 226, 227, 228, 231, 235, 250, 253, 256, 259, 262, 268, 270, 271, 272, 274, 294, 295, 315], "150": [11, 12, 43, 46, 47, 49, 50, 53, 54, 56, 287, 292, 307], "dtype": [11, 12, 18, 26, 35, 36, 81, 83, 84, 88, 274, 277, 297, 305, 313], "bool": [11, 274, 275, 276, 277, 278, 281, 282, 283, 287, 288, 290, 291, 292, 294, 295, 296], "panel": [11, 14, 15, 24, 30, 37, 43, 49, 60, 67, 68, 125, 136, 141, 150, 153, 156, 165, 172, 183, 186, 190, 192, 196, 212, 216, 217, 226, 227, 243, 276, 294], "panel2d": [11, 14, 15, 24, 30, 37, 43, 49, 54, 113, 141, 144, 147, 150, 153, 156, 159, 172, 183, 192, 226, 267, 272, 297, 303, 311], "400": [11, 15, 31, 37, 43, 46, 47, 49, 51, 54, 55, 56, 87, 88, 294, 312], "right": [11, 14, 15, 24, 27, 30, 32, 37, 43, 53, 54, 56, 63, 87, 144, 146, 148, 150, 153, 162, 172, 179, 185, 226, 236, 239, 240, 241, 250, 266, 271, 274, 294, 295, 296, 306, 313, 315, 316], "text_block": [11, 294, 297], "left": [11, 14, 24, 27, 30, 43, 54, 56, 120, 148, 153, 185, 186, 188, 226, 240, 256, 274, 294, 295, 296, 310], "click": [11, 14, 43, 53, 54, 109, 123, 136, 149, 172, 181, 183, 186, 188, 195, 198, 201, 226, 256, 294, 303, 308], "add_el": [11, 14, 15, 24, 30, 37, 43, 53, 54, 294, 297], "build": [11, 12, 31, 35, 36, 72, 75, 98, 109, 113, 155, 174, 181, 264, 270, 292, 294, 303, 307, 313, 315], "mani": [11, 12, 20, 24, 27, 28, 32, 54, 106, 109, 138, 143, 150, 153, 171, 178, 180, 181, 198, 226, 229, 231, 256, 274, 275, 277, 288, 293, 303, 315], "label_actor": 11, "vector_text": [11, 25, 28, 60, 61, 73, 74, 211, 214, 227, 297, 312, 313], "test": [11, 30, 96, 102, 104, 105, 107, 111, 113, 114, 122, 123, 124, 126, 132, 133, 134, 136, 140, 141, 142, 143, 144, 145, 147, 150, 152, 155, 156, 157, 159, 160, 161, 162, 163, 164, 167, 172, 173, 174, 175, 182, 183, 184, 185, 188, 189, 190, 192, 193, 194, 197, 198, 199, 201, 202, 203, 206, 207, 210, 213, 218, 220, 221, 223, 226, 227, 228, 233, 235, 236, 243, 252, 254, 255, 258, 260, 262, 264, 265, 266, 268, 272, 279, 280, 281, 292, 296, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 315], "made": [11, 17, 28, 36, 73, 75, 84, 126, 130, 140, 141, 142, 143, 144, 146, 148, 149, 151, 152, 154, 160, 164, 169, 174, 179, 180, 181, 182, 185, 190, 195, 202, 206, 208, 226, 236, 237, 238, 239, 240, 242, 244, 245, 247, 248, 249, 250, 251, 258, 261, 263, 265, 268, 270, 271, 272, 274, 306], "sqrt": [11, 15, 25, 32, 36], "fury_actor": 11, "access": [11, 12, 14, 19, 24, 94, 98, 121, 126, 135, 136, 140, 149, 171, 173, 174, 184, 287, 292, 295, 296, 307, 309], "memori": [11, 12, 87, 143, 146, 149, 152, 155, 158, 164, 174, 175, 176, 198, 206, 235, 270, 277, 292, 296], "vertic": [11, 12, 17, 18, 21, 25, 26, 28, 29, 30, 32, 33, 40, 53, 54, 56, 75, 81, 82, 83, 84, 94, 119, 128, 162, 165, 166, 168, 170, 172, 177, 185, 190, 202, 205, 227, 228, 251, 270, 274, 275, 282, 284, 288, 290, 291, 293, 294, 295, 296, 307, 312], "vertices_from_actor": [11, 12, 21, 25, 26, 29, 33, 36, 40, 81, 82, 83, 84, 94, 297], "num_vertic": [11, 12, 21, 81, 82, 83, 84, 94], "shape": [11, 12, 14, 17, 21, 24, 27, 28, 30, 32, 36, 41, 42, 48, 49, 55, 76, 81, 82, 83, 84, 90, 94, 135, 182, 183, 184, 186, 188, 189, 192, 194, 198, 212, 216, 217, 219, 222, 226, 236, 266, 270, 271, 274, 275, 276, 277, 282, 283, 284, 287, 290, 293, 294, 295, 296, 297, 307, 313, 314], "num_object": [11, 12, 81, 82, 83, 84, 94], "vcolor": [11, 12, 21, 29, 33, 46, 50], "colors_from_actor": [11, 12, 21, 29, 33, 46, 50, 297], "pickm": 11, "pickingmanag": [11, 274, 297], "callback": [11, 12, 14, 15, 17, 20, 22, 23, 24, 30, 32, 36, 38, 40, 43, 45, 50, 54, 56, 77, 80, 81, 82, 83, 84, 90, 109, 111, 113, 117, 123, 130, 131, 136, 149, 150, 159, 162, 168, 172, 182, 183, 185, 192, 201, 213, 223, 225, 228, 253, 256, 265, 268, 276, 285, 291, 292, 294, 296, 305, 308, 313, 314], "left_click_callback": [11, 14, 294, 297], "event_po": [11, 12, 14], "event_posit": [11, 12, 288, 297], "iren": [11, 12, 14, 176, 288, 292, 294, 296, 297], "picked_info": 11, "vertex_index": 11, "vertex": [11, 17, 40, 75, 77, 135, 179, 193, 195, 205, 206, 215, 220, 223, 227, 228, 270, 274, 282, 286, 288, 291, 295, 313], "calcul": [11, 15, 17, 32, 64, 72, 75, 81, 83, 84, 94, 117, 119, 151, 153, 162, 183, 186, 188, 195, 196, 198, 206, 207, 212, 215, 216, 218, 222, 226, 227, 234, 239, 242, 245, 247, 249, 250, 254, 256, 259, 263, 267, 268, 270, 274, 275, 276, 282, 284, 286, 294, 295, 296], "index": [11, 37, 54, 55, 73, 82, 84, 94, 97, 149, 177, 194, 228, 244, 282, 286, 287, 294, 312], "object_index": [11, 12, 81, 83, 84, 94, 119, 128], "int": [11, 12, 21, 24, 25, 30, 35, 36, 38, 45, 81, 82, 83, 84, 88, 94, 149, 185, 194, 198, 268, 274, 276, 277, 278, 279, 281, 282, 283, 284, 287, 288, 290, 291, 292, 294, 295, 296], "floor": [11, 198], "find": [11, 24, 75, 95, 110, 132, 145, 149, 156, 169, 176, 179, 181, 183, 195, 211, 214, 216, 218, 225, 227, 240, 241, 244, 246, 247, 249, 250, 259, 262, 265, 266, 267, 268, 270, 272, 294, 296, 315], "correspond": [11, 15, 27, 28, 35, 36, 37, 46, 54, 75, 81, 83, 94, 119, 125, 136, 173, 236, 247, 254, 263, 266, 270, 271, 275, 277, 287, 295], "sec": [11, 12, 21, 81, 82, 83, 84, 94, 119, 128], "color_add": 11, "uint8": [11, 12, 143, 274, 295], "tell": [11, 12, 17, 87, 158, 256, 268, 274, 281], "modifi": [11, 25, 119, 141, 147, 149, 183, 185, 189, 191, 192, 194, 195, 201, 202, 222, 223, 226, 237, 263, 277, 282, 293, 294, 303, 313], "update_actor": [11, 12, 21, 25, 26, 29, 33, 36, 40, 46, 50, 81, 82, 83, 84, 297, 310], "face_index": [11, 12], "face": [11, 12, 17, 28, 30, 32, 72, 109, 111, 113, 115, 117, 119, 120, 122, 125, 127, 128, 129, 130, 131, 134, 147, 155, 179, 181, 183, 194, 195, 203, 208, 238, 240, 246, 250, 252, 267, 271, 274, 275, 288, 290, 295, 312], "info": [11, 12, 106, 138, 145, 151, 155, 178, 225, 229, 315], "id": [11, 94, 227, 274, 294, 295, 313], "po": [11, 25, 32, 36, 59, 60, 62, 73, 74, 75, 80, 81, 82, 83, 84, 94, 128, 274, 279], "round": [11, 24, 30, 73, 74, 81, 82, 83, 84, 198, 259, 274, 290], "bind": [11, 12, 168, 170, 172, 206, 213, 235, 238, 247, 282], "addobserv": [11, 14], "leftbuttonpressev": [11, 14, 292], "appear": [11, 12, 24, 60, 111, 149, 176, 181, 226, 227, 228, 240, 252, 264, 265, 266, 271, 277, 295, 296, 310, 312, 313], "1024": [11, 12, 76, 77, 95], "save": [11, 12, 14, 18, 24, 35, 136, 143, 155, 159, 189, 190, 221, 268, 276, 278, 279, 282, 283, 290, 296, 304, 305, 307, 313, 315], "current": [11, 12, 24, 37, 38, 62, 77, 94, 95, 97, 108, 109, 110, 113, 114, 115, 118, 119, 122, 126, 127, 128, 130, 131, 132, 135, 136, 140, 141, 143, 147, 150, 153, 156, 159, 169, 171, 172, 173, 180, 181, 183, 184, 190, 197, 198, 200, 201, 207, 216, 217, 226, 228, 236, 238, 241, 243, 246, 247, 250, 253, 255, 257, 259, 260, 263, 267, 268, 270, 271, 272, 276, 277, 279, 281, 282, 292, 294, 296, 315], "framebuff": [11, 12, 140, 231, 235, 238, 244, 247, 250, 259, 268, 292], "nonetheless": 12, "too": [12, 43, 54, 114, 142, 147, 162, 180, 181, 185, 186, 192, 194, 226, 254, 270, 281, 310, 311], "abl": [12, 14, 17, 24, 32, 59, 63, 109, 111, 112, 113, 114, 116, 117, 118, 119, 120, 122, 125, 128, 130, 131, 132, 134, 135, 136, 148, 150, 157, 166, 173, 175, 181, 188, 190, 191, 192, 195, 200, 206, 209, 226, 227, 228, 235, 241, 244, 257, 271, 292], "more": [12, 14, 24, 27, 28, 31, 35, 36, 37, 39, 64, 72, 75, 87, 88, 89, 94, 95, 112, 114, 117, 118, 119, 122, 135, 136, 142, 143, 149, 153, 155, 158, 159, 160, 162, 163, 164, 166, 168, 172, 173, 174, 181, 182, 186, 195, 196, 198, 202, 205, 206, 207, 209, 210, 211, 215, 221, 223, 225, 227, 233, 235, 239, 242, 244, 248, 249, 250, 251, 253, 254, 256, 257, 259, 261, 264, 266, 268, 269, 270, 271, 272, 274, 276, 277, 278, 287, 291, 292, 294, 295, 296, 307, 311, 315], "addit": [12, 24, 28, 32, 34, 62, 89, 140, 141, 143, 148, 149, 150, 151, 172, 174, 176, 219, 227, 233, 242, 250, 253, 257, 266, 268, 270, 271, 276, 277, 294, 296, 304, 312, 313, 315], "summari": [12, 27, 247, 254], "thousand": [12, 174, 175, 176, 227], "rectangular": 12, "box": [12, 22, 23, 25, 26, 29, 30, 33, 40, 41, 42, 50, 53, 54, 60, 63, 66, 75, 81, 82, 83, 84, 90, 94, 105, 115, 122, 136, 160, 169, 170, 173, 181, 188, 192, 194, 195, 216, 222, 226, 249, 252, 255, 256, 258, 270, 272, 279, 284, 287, 290, 294, 295, 297, 303, 306, 307, 308, 309, 314], "hover": 12, "mous": [12, 14, 109, 131, 136, 149, 183, 186, 188, 198, 201, 210, 226, 256, 294, 313], "transpar": [12, 39, 274, 275, 276, 278, 296, 304, 305, 308], "everyth": [12, 24, 30, 63, 65, 67, 94, 109, 115, 121, 126, 134, 155, 162, 170, 176, 179, 184, 185, 188, 204, 218, 222, 223, 226, 233, 244, 245, 248, 261, 294, 315], "behind": [12, 116, 118, 119, 144, 160, 172, 174, 239, 240, 256, 262, 268], "num_cub": 12, "50000": 12, "keep": [12, 25, 26, 29, 54, 83, 84, 94, 97, 120, 128, 130, 136, 157, 179, 181, 183, 201, 203, 206, 216, 222, 228, 233, 236, 239, 241, 245, 248, 256, 263, 274, 291, 296, 313, 315], "track": [12, 24, 26, 27, 39, 52, 54, 81, 82, 83, 84, 94, 120, 128, 149, 201, 228, 274, 292, 294, 297, 311, 315], "number": [12, 25, 26, 28, 29, 43, 54, 72, 75, 83, 87, 94, 117, 149, 160, 173, 179, 187, 235, 236, 244, 257, 259, 264, 267, 268, 270, 274, 275, 276, 277, 279, 281, 283, 287, 290, 292, 294, 295, 296, 315], "triangl": [12, 17, 18, 25, 28, 32, 34, 72, 75, 166, 179, 185, 189, 194, 197, 227, 228, 270, 274, 275, 282, 290, 295, 313], "everi": [12, 15, 17, 20, 24, 25, 26, 29, 30, 32, 33, 36, 37, 38, 40, 59, 77, 80, 108, 109, 132, 134, 159, 195, 225, 226, 228, 235, 250, 268, 274, 275, 277, 284, 292, 295, 296, 315], "quad": [12, 48, 202, 212, 226, 294], "ha": [12, 14, 17, 20, 26, 31, 36, 44, 45, 54, 60, 62, 64, 68, 75, 94, 95, 97, 110, 118, 120, 134, 141, 143, 145, 149, 150, 151, 152, 153, 154, 155, 156, 162, 171, 172, 176, 179, 181, 185, 194, 203, 213, 221, 222, 225, 226, 227, 228, 231, 235, 247, 256, 259, 260, 264, 265, 270, 272, 274, 276, 277, 280, 281, 290, 291, 294, 295, 296, 304, 313], "num_fac": 12, "cube_actor": [12, 18, 274], "2d": [12, 22, 23, 34, 72, 90, 98, 109, 141, 152, 173, 174, 180, 194, 199, 226, 238, 253, 256, 268, 271, 274, 275, 283, 284, 288, 294, 295, 296, 308, 311, 314], "rgba": [12, 235, 238, 268, 274, 278, 290, 295, 296, 307], "255": [12, 14, 18, 28, 34, 46, 50, 76, 268, 274, 277, 295, 308], "ones": [12, 15, 65, 68, 69, 72, 82, 84, 143, 169, 256, 265, 277], "198": [12, 307], "texa": 12, "texture_2d": [12, 297], "astyp": [12, 82, 84], "selm": 12, "selectionmanag": [12, 274, 297], "selectable_off": [12, 288, 297], "hover_callback": 12, "region": [12, 28, 268, 270], "inform": [12, 15, 35, 37, 80, 82, 84, 88, 94, 95, 97, 128, 149, 151, 155, 174, 181, 224, 226, 228, 236, 243, 254, 257, 259, 266, 270, 271, 272, 276, 277, 279, 287, 291, 292, 295, 296, 310], "node": [12, 32, 35, 36, 150, 153, 155, 156, 162, 172, 174, 176, 185, 200, 205, 218, 228, 255, 278, 282], "kei": [12, 15, 24, 32, 35, 36, 46, 47, 53, 65, 67, 73, 74, 88, 149, 184, 195, 226, 234, 268, 274, 276, 282, 293, 294], "help": [12, 15, 31, 37, 53, 62, 64, 75, 82, 94, 109, 113, 119, 120, 125, 131, 132, 135, 136, 137, 140, 141, 148, 157, 164, 165, 168, 171, 175, 181, 182, 198, 202, 207, 226, 227, 241, 243, 255, 268, 270, 272, 288, 293, 294, 315], "divid": [12, 32, 72, 73, 172, 226, 268, 296], "color_chang": 12, "add_iren_callback": [12, 256, 268, 296, 297], "skin": [13, 200, 203, 205, 209, 215, 218, 220, 224, 282, 313], "riggedfigur": [13, 194, 218], "well": [13, 27, 30, 72, 117, 130, 141, 143, 144, 147, 153, 155, 156, 159, 165, 182, 184, 194, 204, 206, 209, 212, 219, 223, 227, 228, 231, 233, 238, 241, 244, 247, 250, 256, 257, 259, 265, 268, 270, 271, 276, 296], "skin_timelin": 13, "skin_anim": [13, 282, 297], "after": [13, 14, 15, 17, 19, 20, 24, 31, 38, 45, 53, 63, 65, 81, 82, 83, 87, 94, 97, 110, 112, 113, 114, 120, 122, 124, 125, 127, 128, 134, 135, 143, 144, 150, 153, 155, 156, 158, 159, 168, 169, 172, 173, 174, 179, 180, 181, 185, 188, 191, 192, 193, 201, 203, 204, 205, 207, 216, 218, 219, 222, 226, 234, 238, 241, 243, 244, 247, 249, 250, 252, 253, 255, 256, 258, 259, 261, 262, 264, 265, 268, 269, 270, 272, 277, 280, 292, 294, 309, 313, 315], "process": [13, 24, 29, 37, 65, 75, 87, 88, 89, 94, 98, 115, 117, 136, 146, 149, 150, 155, 168, 172, 174, 176, 181, 198, 234, 247, 253, 256, 257, 258, 259, 261, 265, 266, 267, 268, 272, 283, 291, 294, 312], "bone": [13, 218, 228, 277, 282], "transform": [13, 14, 24, 27, 48, 72, 75, 114, 168, 173, 181, 186, 187, 188, 191, 195, 198, 200, 203, 205, 208, 209, 213, 220, 226, 227, 228, 253, 256, 270, 272, 274, 275, 276, 282, 295, 297, 307, 313], "length": [13, 24, 27, 28, 30, 37, 49, 54, 59, 66, 69, 115, 227, 236, 274, 275, 276, 279, 282, 290, 293, 294, 295, 297], "initialise_skin": 13, "befor": [13, 15, 28, 32, 72, 87, 94, 109, 110, 115, 119, 122, 131, 141, 147, 149, 150, 152, 153, 156, 158, 159, 162, 174, 179, 180, 181, 200, 203, 206, 218, 234, 241, 254, 263, 265, 266, 268, 270, 272, 291, 294, 296, 313], "won": [13, 94, 103, 134, 180, 199, 206, 292, 304], "t": [13, 14, 24, 25, 28, 29, 48, 59, 60, 61, 62, 66, 68, 69, 72, 75, 82, 87, 89, 94, 111, 113, 114, 115, 117, 119, 122, 134, 136, 140, 141, 143, 144, 147, 149, 150, 152, 155, 159, 160, 162, 168, 171, 172, 174, 176, 179, 180, 181, 182, 183, 185, 186, 189, 190, 192, 193, 195, 196, 197, 198, 199, 200, 203, 206, 207, 209, 210, 211, 212, 213, 214, 215, 216, 217, 219, 220, 221, 222, 224, 225, 226, 234, 238, 241, 243, 244, 246, 247, 250, 253, 258, 259, 262, 265, 266, 268, 270, 271, 272, 274, 276, 277, 287, 292, 295, 297, 303, 304, 310, 311, 315], "initialize_skin": [13, 282, 297], "update_skin": [13, 282, 297], "o": [14, 34, 35, 36, 45, 72, 75, 87, 88, 89, 95, 159, 176, 268, 274, 313], "nibabel": [14, 30, 281, 295], "nib": [14, 30], "dipi": [14, 18, 24, 27, 28, 30, 39, 97, 99, 103, 245, 254, 266, 270, 274, 277, 279, 299, 304], "fetch_bundles_2_subject": [14, 24, 27], "fname_t1": 14, "path": [14, 15, 26, 33, 35, 36, 37, 38, 45, 59, 69, 72, 75, 88, 95, 199, 227, 228, 247, 250, 252, 268, 272, 273, 276, 279, 282, 283, 291, 294, 296, 313], "expandus": 14, "exp_bundles_and_map": [14, 24], "bundles_2_subject": [14, 24], "subj_1": [14, 24, 27], "t1_warp": 14, "nii": [14, 28, 30], "gz": [14, 24, 28, 30, 43, 44, 46, 47, 50, 51, 52, 53, 54, 55, 56, 296], "img": [14, 54, 294, 297], "get_fdata": [14, 30, 39, 313], "affin": [14, 24, 27, 30, 39, 274, 275, 295, 304], "hold": [14, 24, 63, 72, 149, 150, 193, 195, 206, 208, 226, 256, 294, 296], "background": [14, 26, 28, 31, 73, 74, 76, 82, 115, 183, 217, 219, 226, 234, 249, 250, 252, 255, 258, 267, 272, 277, 278, 294, 296, 297, 303, 311], "higher": [14, 21, 25, 29, 126, 259, 270, 274, 276, 281, 291, 294], "would": [14, 19, 24, 54, 62, 64, 68, 74, 102, 104, 105, 107, 110, 115, 120, 122, 123, 129, 131, 133, 134, 136, 137, 139, 141, 144, 147, 150, 153, 156, 159, 167, 177, 179, 181, 183, 184, 186, 198, 212, 219, 222, 226, 227, 230, 231, 235, 236, 238, 240, 241, 244, 248, 253, 256, 259, 260, 265, 267, 268, 269, 271, 272, 276, 294, 315], "see": [14, 24, 27, 28, 31, 32, 62, 64, 65, 73, 74, 75, 87, 97, 98, 103, 109, 111, 113, 115, 117, 119, 120, 122, 125, 128, 130, 131, 141, 143, 144, 146, 147, 148, 149, 150, 152, 153, 155, 156, 158, 159, 162, 165, 168, 170, 174, 179, 181, 188, 194, 195, 198, 201, 204, 207, 210, 211, 212, 217, 220, 222, 226, 233, 236, 238, 242, 250, 254, 256, 259, 261, 263, 266, 269, 270, 271, 275, 277, 281, 291, 293, 296, 313], "mean": [14, 24, 26, 32, 36, 65, 81, 82, 83, 84, 87, 94, 136, 141, 147, 150, 153, 168, 170, 172, 179, 231, 241, 244, 270, 274, 276, 284, 286, 295, 315], "std": [14, 181], "value_rang": [14, 204, 226, 274, 277, 313], "resampl": 14, "matrix": [14, 27, 30, 40, 75, 81, 83, 94, 119, 120, 183, 203, 205, 213, 215, 218, 220, 236, 242, 245, 253, 257, 270, 274, 275, 277, 282, 293, 295, 313], "default": [14, 24, 25, 26, 28, 29, 33, 40, 56, 60, 61, 62, 67, 75, 77, 89, 94, 97, 109, 111, 130, 136, 159, 170, 228, 231, 258, 274, 275, 276, 277, 278, 279, 281, 282, 283, 284, 285, 286, 287, 288, 290, 291, 292, 294, 295, 296, 307, 313], "behavior": [14, 31, 135, 141, 143, 146, 149, 152, 174, 176, 237, 250, 252, 258, 264, 287, 291, 292, 296, 308], "middl": [14, 30, 274, 294, 305], "last": [14, 37, 114, 117, 118, 119, 127, 156, 162, 168, 170, 179, 181, 182, 183, 186, 188, 205, 207, 214, 215, 222, 226, 235, 239, 240, 249, 263, 268, 271, 276, 281, 293, 294, 295, 296, 313, 315], "dimens": [14, 171, 274, 277, 283, 284, 290, 292, 295, 296], "slice_actor": 14, "axial": [14, 15, 30], "ani": [14, 18, 32, 62, 64, 65, 94, 98, 99, 100, 101, 102, 104, 105, 107, 113, 114, 117, 119, 120, 122, 123, 125, 128, 130, 131, 133, 134, 136, 137, 139, 141, 143, 144, 147, 150, 153, 155, 156, 162, 167, 172, 174, 177, 179, 180, 181, 182, 183, 193, 197, 198, 201, 206, 212, 213, 219, 222, 226, 227, 228, 230, 234, 237, 241, 243, 244, 246, 248, 250, 257, 261, 262, 267, 268, 271, 274, 276, 277, 279, 295, 296, 315, 316], "given": [14, 31, 38, 110, 127, 128, 137, 172, 179, 228, 239, 259, 268, 270, 274, 275, 276, 277, 278, 279, 281, 282, 285, 287, 291, 292, 293, 294, 295, 296, 313, 315], "howev": [14, 17, 24, 27, 28, 30, 72, 87, 89, 112, 114, 118, 135, 143, 146, 155, 176, 185, 189, 194, 213, 215, 228, 235, 240, 246, 252, 258, 259, 262, 264, 265, 266, 267, 268, 270, 271, 272, 278, 296, 313, 316], "copi": [14, 21, 24, 25, 26, 29, 33, 40, 140, 143, 181, 192, 217, 274, 281, 287, 291, 295], "slice_actor2": 14, "sagitt": [14, 30], "plane": [14, 19, 24, 38, 40, 81, 83, 84, 274, 277, 284, 293], "order": [14, 17, 28, 30, 59, 62, 63, 64, 66, 68, 75, 94, 109, 115, 116, 128, 136, 141, 147, 156, 164, 168, 172, 202, 211, 214, 215, 228, 251, 254, 257, 263, 266, 270, 271, 274, 275, 277, 287, 289, 295, 296, 305, 307, 308, 313], "uncom": [14, 39, 87, 88, 296], "line": [14, 15, 21, 24, 26, 27, 29, 33, 35, 36, 39, 40, 48, 54, 56, 59, 87, 88, 97, 106, 136, 138, 143, 155, 160, 173, 178, 180, 181, 183, 186, 192, 195, 197, 198, 207, 210, 217, 226, 229, 235, 238, 239, 240, 244, 254, 256, 258, 265, 268, 270, 275, 276, 277, 294, 295, 296, 297, 304, 307, 312], "otherwis": [14, 32, 72, 235, 250, 264, 274, 276, 277, 279, 281, 283, 285, 290, 291, 294, 295, 296, 316], "screenshot": [14, 24, 72, 168, 172, 296, 313], "follow": [14, 24, 25, 26, 28, 30, 32, 33, 37, 39, 60, 61, 62, 65, 68, 72, 82, 84, 87, 88, 94, 97, 99, 100, 101, 102, 104, 105, 107, 119, 120, 123, 125, 128, 130, 131, 133, 134, 136, 139, 143, 146, 149, 167, 174, 176, 177, 187, 190, 191, 193, 196, 197, 200, 226, 227, 228, 230, 233, 237, 247, 253, 259, 267, 268, 271, 274, 276, 279, 281, 283, 295, 297, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 315, 316], "command": [14, 72, 94, 97, 99, 100, 101, 102, 104, 105, 107, 123, 133, 139, 167, 177, 181, 230, 291, 292, 297, 313, 315], "possibl": [14, 27, 28, 31, 32, 37, 50, 72, 75, 94, 110, 115, 117, 118, 136, 147, 149, 150, 152, 158, 176, 181, 183, 227, 245, 251, 256, 257, 258, 259, 270, 271, 274, 277, 281, 291, 293, 315, 316], "prefer": [14, 60, 72, 289], "non": [14, 32, 60, 173, 174, 179, 193, 227, 228, 247, 270, 286, 303], "standard": [14, 28, 77, 133, 180, 181, 256, 268, 270, 272, 274, 275, 277, 286, 291, 293, 295, 309, 312], "wai": [14, 24, 27, 28, 37, 63, 68, 72, 73, 75, 97, 98, 111, 115, 132, 136, 140, 143, 146, 147, 149, 150, 153, 159, 170, 172, 176, 181, 182, 185, 190, 195, 201, 206, 211, 216, 217, 219, 221, 223, 225, 227, 228, 232, 233, 236, 241, 244, 248, 250, 256, 259, 266, 268, 269, 270, 271, 274, 275, 277, 278, 295, 312, 313, 315, 316], "hsv": [14, 61, 187, 193, 227, 276, 277], "fname_fa": 14, "fa_1x1x1": 14, "notic": [14, 37, 72, 122, 155, 158, 171, 179, 191, 194, 218, 222, 252, 272, 292, 310, 316], "min": [14, 27, 32, 204, 270, 274, 277, 282, 294], "max": [14, 25, 27, 28, 32, 87, 179, 181, 204, 270, 274, 277, 282, 294], "lut": [14, 295, 310], "colormap_lookup_t": [14, 27, 274, 275, 297], "scale_rang": [14, 27, 277], "hue_rang": [14, 27, 277], "saturation_rang": [14, 27, 277], "becaus": [14, 24, 28, 37, 72, 75, 115, 117, 120, 122, 128, 131, 140, 143, 147, 149, 152, 155, 156, 159, 171, 172, 174, 176, 181, 186, 195, 198, 201, 203, 206, 207, 216, 221, 237, 241, 245, 254, 257, 259, 268, 270, 277, 293], "lookup": [14, 274, 275, 277], "tabl": [14, 194, 274, 275, 277], "interpol": [14, 35, 36, 57, 58, 60, 65, 69, 73, 90, 173, 179, 182, 196, 199, 200, 203, 206, 209, 213, 215, 225, 227, 274, 277, 282, 286, 295, 297, 313, 314], "fa_actor": 14, "lookup_colormap": [14, 27, 274, 275], "clear": [14, 27, 28, 72, 73, 75, 112, 181, 234, 242, 272, 274, 286, 296, 297, 312], "slices_lut": 14, "abil": [14, 154, 169, 171, 174, 185, 199, 221, 224, 227, 228, 277, 313], "voxel": [14, 24, 28, 270, 274, 275, 295], "requir": [14, 24, 27, 28, 32, 36, 72, 81, 83, 94, 97, 100, 109, 111, 113, 143, 147, 148, 150, 153, 162, 173, 179, 181, 182, 186, 195, 201, 207, 212, 215, 219, 221, 226, 228, 235, 237, 241, 248, 254, 256, 257, 261, 262, 264, 265, 266, 270, 271, 272, 277, 292, 294, 301, 304, 307, 313, 315], "area": [14, 24, 113, 136, 207, 231, 247, 288], "pipelin": [14, 24, 105, 110, 174, 179, 247, 270, 296, 306, 308, 311], "therefor": [14, 24, 27, 73, 94, 109, 113, 115, 117, 120, 136, 140, 143, 149, 155, 174, 249, 270, 274, 295], "don": [14, 24, 72, 75, 87, 89, 140, 143, 172, 182, 193, 220, 226, 244, 266, 268, 315], "recommend": [14, 24, 62, 97, 143, 151, 171, 276, 315], "appropri": [14, 24, 75, 81, 94, 130, 173, 187, 254, 271, 294], "allow": [14, 24, 28, 32, 65, 72, 75, 87, 113, 115, 120, 136, 143, 146, 147, 149, 152, 153, 156, 165, 172, 174, 175, 187, 193, 208, 214, 223, 225, 227, 228, 236, 239, 242, 250, 259, 261, 264, 265, 268, 272, 277, 288, 292, 294, 296, 305, 307, 311, 312, 313, 315], "show_m": [14, 24, 30, 37], "1200": [14, 24, 30], "ll": [14, 15, 24, 31, 32, 40, 43, 54, 56, 88, 140, 142, 143, 145, 148, 149, 151, 152, 154, 155, 156, 157, 158, 160, 161, 163, 164, 166, 169, 171, 175, 180, 189, 191, 197, 203, 215, 232], "label_posit": 14, "label_valu": 14, "result_posit": 14, "result_valu": 14, "panel_pick": 14, "125": [14, 307], "opac": [14, 20, 24, 30, 35, 37, 39, 57, 58, 68, 72, 75, 87, 88, 89, 90, 95, 227, 236, 274, 275, 276, 290, 294, 295, 297, 304, 310, 314], "disabl": [14, 28, 94, 205, 273, 296, 309], "_ev": 14, "geteventposit": 14, "picker": 14, "j": [14, 21, 73, 74, 81, 82, 84, 166, 167, 181, 270, 272, 275, 287, 292, 311], "k": [14, 29, 32, 68, 81, 84, 97, 99, 100, 101, 102, 104, 105, 106, 107, 123, 133, 138, 139, 167, 177, 178, 229, 230, 259, 274, 275, 293, 295], "getpointijk": 14, "format": [14, 73, 77, 95, 98, 165, 170, 173, 180, 181, 185, 186, 194, 228, 235, 238, 275, 276, 277, 279, 283, 294, 313], "8f": 14, "setinterpol": 14, "By": [14, 26, 27, 37, 56, 89, 94, 181, 234, 274, 277, 295], "becom": [14, 159, 204, 216, 220], "easi": [14, 24, 27, 32, 65, 72, 74, 98, 140, 143, 153, 174, 176, 182, 184, 186, 195, 222, 239, 259, 268, 276], "effici": [14, 72, 119, 135, 140, 153, 174, 182, 186, 210, 226, 266, 270, 272, 274, 277], "project": [14, 30, 40, 99, 100, 101, 102, 104, 105, 106, 107, 108, 109, 112, 113, 114, 116, 117, 118, 121, 123, 124, 126, 127, 129, 132, 133, 135, 136, 137, 138, 139, 140, 143, 167, 172, 173, 174, 177, 178, 179, 180, 181, 185, 199, 226, 227, 228, 229, 230, 232, 233, 234, 235, 238, 239, 241, 244, 247, 250, 251, 253, 259, 268, 269, 270, 272, 274, 275, 277, 293, 296, 297, 307, 310, 315], "perspect": [14, 134, 296], "parallel": [14, 33, 83, 143, 174, 270, 296], "associ": [14, 59, 75, 144, 149, 159, 182, 186, 226, 234, 245, 257, 268, 270, 271, 274, 275, 276, 277, 287, 295], "show_m_mosa": 14, "left_click_callback_mosa": 14, "two": [14, 15, 21, 28, 35, 36, 43, 46, 49, 53, 54, 60, 62, 65, 67, 72, 75, 87, 94, 97, 117, 132, 134, 142, 145, 149, 153, 155, 156, 170, 172, 173, 174, 176, 181, 182, 190, 193, 199, 202, 206, 208, 209, 215, 216, 219, 224, 226, 227, 228, 231, 243, 250, 256, 257, 265, 272, 277, 287, 290, 293, 294, 311, 315], "nest": [14, 311], "grid": [14, 25, 27, 28, 30, 38, 49, 147, 156, 162, 171, 173, 270, 271, 275, 284, 294, 295, 297, 304, 305], "column": [14, 277, 283, 293], "row": [14, 277, 283, 295], "adjust": [14, 24, 153, 233, 234, 237, 240, 242, 245, 248, 255, 257, 258, 261, 263, 270, 271, 272, 295, 313], "those": [14, 37, 59, 65, 72, 131, 146, 149, 155, 174, 181, 215, 234, 246, 250, 253, 256, 263, 268, 271, 277, 292, 294], "col": [14, 46, 61, 77], "border": [14, 72, 144, 147, 159, 165, 172, 188, 192, 212, 216, 217, 219, 226, 256, 268, 272, 294, 311], "slice_mosa": 14, "abov": [14, 17, 27, 32, 60, 63, 64, 83, 94, 97, 112, 114, 117, 118, 121, 124, 125, 137, 146, 148, 149, 193, 206, 211, 212, 222, 223, 226, 227, 247, 250, 266, 268, 270, 277, 316], "down": [14, 25, 29, 32, 43, 54, 81, 82, 83, 84, 94, 136, 179, 239, 272, 274, 294], "button": [14, 15, 24, 41, 42, 90, 109, 136, 150, 184, 199, 226, 227, 294, 305, 312, 313, 314], "drag": [14, 150, 165, 172, 186, 195, 201, 226, 294], "out": [14, 59, 62, 64, 75, 77, 109, 112, 113, 114, 115, 116, 118, 119, 120, 121, 122, 124, 126, 127, 128, 129, 130, 131, 132, 137, 141, 143, 150, 153, 157, 159, 162, 168, 172, 179, 181, 182, 183, 186, 188, 191, 194, 201, 203, 205, 206, 210, 213, 214, 215, 216, 219, 220, 225, 232, 235, 238, 240, 244, 247, 249, 250, 253, 259, 263, 265, 266, 268, 269, 271, 272, 274, 276, 277, 281, 284, 294, 296, 298, 310, 316], "scroll": [14, 113, 130, 179, 294, 303], "wheel": [14, 63, 98], "manipul": [15, 19, 33, 75, 115, 153, 160, 186, 187, 195, 206, 287], "simul": [15, 21, 26, 27, 37, 73, 78, 79, 90, 115, 119, 120, 122, 125, 128, 136, 160, 173, 227, 228, 268, 303, 304, 309, 310, 312, 313, 314], "orbit": [15, 181], "motion": [15, 22, 23, 59, 69, 82, 90, 160, 173, 199, 207, 227, 276, 310, 314], "read_viz_icon": [15, 43, 54, 297, 307], "paus": [15, 67, 68, 199, 227, 276, 294, 297, 313], "pause_button": 15, "button2d": [15, 43, 54, 156, 226, 297, 311], "icon_fnam": [15, 43, 54, 294], "squar": [15, 34, 40, 43, 49, 54, 179, 271, 284, 290, 294, 297, 306, 308], "fname": [15, 43, 54, 276, 278, 279, 283, 296], "pause2": 15, "start_button": 15, "play3": 15, "relev": [15, 122, 155, 172, 237, 254], "planet": 15, "includ": [15, 43, 44, 45, 46, 47, 50, 51, 52, 53, 54, 55, 56, 72, 74, 77, 95, 98, 106, 108, 109, 116, 126, 135, 138, 141, 142, 144, 145, 159, 165, 168, 177, 178, 190, 227, 229, 237, 240, 243, 246, 250, 258, 268, 270, 272, 281, 296, 310, 312, 315, 316], "rel": [15, 66, 94, 156, 159, 162, 188, 227, 268, 274, 296, 315], "planets_data": 15, "8k_mercuri": 15, "earth_dai": 15, "8k_venus_surfac": 15, "243": [15, 309], "8k_mar": 15, "jupit": 15, "8k_saturn": 15, "8k_saturn_ring_alpha": 15, "2k_uranu": 15, "2k_neptun": 15, "8k_sun": 15, "http": [15, 24, 28, 35, 37, 38, 43, 44, 45, 46, 47, 48, 50, 51, 52, 53, 54, 55, 56, 62, 64, 74, 87, 88, 89, 97, 99, 100, 101, 102, 104, 105, 107, 123, 133, 136, 139, 143, 146, 149, 161, 167, 170, 174, 177, 230, 277, 278, 291, 292, 293, 296, 306, 315], "raw": [15, 28, 37, 44, 45, 48, 143], "githubusercont": [15, 28, 37, 44, 45, 48], "com": [15, 28, 37, 38, 44, 45, 48, 74, 97, 136, 149, 170, 277, 292, 293, 315], "gl": [15, 28, 37, 44, 45, 48, 97, 98, 99, 100, 101, 102, 104, 105, 107, 123, 133, 135, 136, 139, 140, 146, 149, 155, 158, 161, 164, 167, 168, 170, 172, 173, 174, 175, 176, 177, 179, 180, 183, 184, 226, 227, 228, 230, 268, 270, 272, 296, 307, 310, 315], "master": [15, 28, 37, 45, 48, 271, 304, 307, 310, 315], "0d66dc62768c43d763d3288ce67128aaed27715b11b0529162dc4117f710e26f": 15, "2_no_clouds_8k": 15, "5cf740c72287af7b3accf080c3951944adcb1617083b918537d08cbd9f2c5465": 15, "5_night_8k": 15, "df443f3e20c7724803690a350d9f6fdb36ad8ebc011b0345fb519a8b321f680a": 15, "ppm": 15, "34ce9ad183d7c7b11e2f682d7ebb84c803e661be09e01adb887175ae60c58156": 15, "5df6a384e407bd0d5f18176b7db96aae1eea3cfcfe570ddce0d34b4f0e493668": 15, "masonri": 15, "bmp": [15, 19, 283], "045e30b2abfeae6318c2cf955040c4a37e6de595ace809ce6766d397c0ee205d": 15, "moon_8k": 15, "7397a6c2ce0348e148c66ebefe078467ddb9d0370ff5e63434d0451477624839": 15, "5c8bd885ae3571c6ba2cd34b3446b9c6d767e314bf0ee8c1d5c147cadd388fc3": 15, "9bc21a50577ed8ac734cda91058724c7a741c19427aa276224ce349351432c5b": 15, "4cc52149924abc6ae507d63032f994e1d42a55cb82c09e002d1a567ff66c23e": 15, "0d39a4a490c87c3edabe00a3881a29bb3418364178c79c534fe0986e97e09853": 15, "f1f826933c9ff87d64ecf0518d6256b8ed990b003722794f67e96e3d2b876ae4": 15, "d15239d46f82d3ea13d2b260b5b29b2a382f42f2916dae0694d0387b1204a09d": 15, "cb42ea82709741d28b0af44d8b283cbc6dbd0c521a7f0e1e1e010ade00977df6": 15, "f22b1cfb306ddce72a7e3b628668a0175b745038ce6268557cb2f7f1bdf98b9d": 15, "7dd1dac926101b5d7b7f2e952e53acf209421b5cce57c03168bce0aad675998a": 15, "cloud": [15, 127, 231, 268, 274], "85043336e023c4c9394cfd6d48d257a5564b4f895bfcec01c70e4898cc77f003": 15, "To": [15, 17, 19, 25, 27, 28, 32, 44, 45, 47, 49, 53, 54, 63, 68, 72, 77, 94, 95, 97, 98, 99, 100, 101, 102, 104, 105, 107, 110, 114, 121, 123, 133, 139, 143, 149, 155, 156, 159, 162, 167, 174, 177, 185, 194, 195, 198, 204, 206, 212, 217, 226, 230, 232, 234, 237, 238, 240, 247, 248, 249, 252, 255, 258, 261, 264, 265, 266, 267, 270, 271, 272, 277, 281, 282, 294, 315], "advantag": [15, 146, 149, 165, 228, 256], "previous": [15, 37, 72, 125, 128, 134, 153, 159, 170, 172, 183, 192, 210, 212, 226, 256, 265, 267, 272, 277], "structur": [15, 18, 24, 32, 35, 147, 150, 155, 173, 174, 180, 185, 187, 239, 244, 248, 251, 267, 268, 270, 271, 272, 284, 287, 296, 307], "auxiliari": 15, "respect": [15, 21, 73, 75, 82, 84, 94, 109, 111, 115, 136, 141, 150, 170, 185, 188, 217, 226, 236, 274, 282, 292, 294, 295, 307], "properti": [15, 37, 53, 60, 65, 68, 73, 75, 76, 115, 119, 143, 149, 153, 174, 177, 186, 187, 192, 193, 199, 211, 223, 226, 227, 228, 237, 240, 249, 267, 268, 270, 272, 274, 275, 276, 277, 282, 286, 287, 292, 294, 296, 303, 304, 312], "init_planet": 15, "planet_data": 15, "dict": [15, 50, 62, 67, 273, 276, 277, 282, 283, 286, 293, 294, 296, 307], "dictionari": [15, 24, 46, 47, 60, 64, 95, 149, 197, 224, 277, 279, 282, 286, 293, 294], "planet_actor": 15, "planet_fil": 15, "planet_imag": 15, "map": [15, 22, 23, 24, 27, 28, 37, 50, 72, 75, 90, 173, 175, 176, 179, 228, 266, 270, 271, 274, 275, 277, 279, 283, 293, 314], "assign": [15, 28, 59, 60, 108, 110, 114, 118, 126, 127, 129, 132, 183, 214, 274, 276, 277, 287, 295], "planet_actor_list": 15, "mercury_actor": 15, "venus_actor": 15, "mars_actor": 15, "jupiter_actor": 15, "saturn_actor": 15, "saturn_rings_actor": 15, "uranus_actor": 15, "neptune_actor": 15, "sun_actor": 15, "gravit": 15, "constant": [15, 64, 72, 117, 149, 183, 297], "g": [15, 24, 39, 94, 95, 228, 270, 272, 274, 275, 277, 279, 286, 287, 290, 295, 296, 315], "central": [15, 72, 75, 270], "mass": [15, 83, 94], "sun": [15, 309], "graviti": [15, 81, 82, 83, 84, 136, 179], "multipli": [15, 119, 183, 270, 293, 295], "togeth": [15, 24, 72, 74, 94, 204, 219, 226, 237, 250, 253, 261], "miu": 15, "g_expon": 15, "float_pow": 15, "g_constant": 15, "673": [15, 216, 226, 313], "m_expon": 15, "1073741824": 15, "power": [15, 22, 32, 72, 90, 98, 181, 227], "m_constant": 15, "989": 15, "get_orbit_period": 15, "get_orbital_posit": 15, "orbit_period": 15, "axi": [15, 21, 25, 26, 28, 29, 32, 33, 35, 36, 40, 63, 75, 82, 84, 88, 94, 119, 172, 185, 202, 271, 274, 275, 284, 293, 294, 295, 296, 312], "should": [15, 18, 62, 63, 65, 89, 94, 143, 144, 146, 147, 149, 153, 155, 158, 162, 172, 174, 190, 191, 201, 222, 228, 235, 238, 239, 240, 241, 242, 259, 262, 263, 265, 271, 274, 275, 276, 277, 279, 282, 283, 286, 290, 291, 292, 294, 295, 296, 308, 310, 313, 315], "rotate_axi": 15, "funtction": 15, "better": [15, 27, 28, 46, 50, 56, 64, 69, 75, 81, 83, 84, 98, 110, 134, 135, 137, 143, 149, 151, 155, 158, 174, 179, 181, 182, 221, 233, 249, 250, 251, 253, 257, 259, 263, 268, 270, 271], "update_planet_posit": 15, "r_planet": 15, "pos_planet": 15, "calculate_path": 15, "planet_track": 15, "saturn": 15, "ring": [15, 51, 54, 56, 294], "r_time": 15, "taken": [15, 26, 268, 270, 294], "dai": [15, 110, 116, 137, 144, 181, 240, 247, 250, 253], "itself": [15, 59, 63, 72, 147, 150, 153, 172, 223, 226, 235, 238, 240, 265], "p_data": 15, "saturn_r": 15, "sun_data": 15, "rplanet": 15, "orbit_actor": 15, "linewidth": [15, 21, 26, 27, 29, 33, 36, 40, 274, 275, 287, 297, 304], "control": [15, 31, 34, 41, 42, 54, 59, 60, 61, 64, 67, 68, 72, 75, 82, 84, 90, 125, 136, 152, 174, 179, 181, 182, 188, 190, 193, 196, 199, 211, 227, 235, 236, 259, 262, 268, 269, 274, 276, 290, 294, 313, 314], "valu": [15, 24, 25, 28, 29, 30, 32, 33, 37, 40, 45, 47, 49, 50, 52, 53, 54, 55, 56, 59, 60, 62, 64, 65, 67, 72, 73, 74, 81, 82, 83, 84, 94, 95, 115, 116, 119, 136, 149, 155, 172, 173, 182, 194, 198, 199, 204, 206, 207, 208, 218, 224, 241, 244, 250, 255, 256, 257, 259, 261, 264, 265, 266, 267, 268, 270, 271, 272, 274, 275, 276, 277, 278, 279, 282, 283, 284, 286, 287, 289, 291, 293, 294, 295, 296, 297, 307, 310, 313, 315], "p_actor": 15, "zip": [15, 29, 90, 277], "pos_saturn": 15, "2000": [15, 81, 82, 94], "perform": [15, 28, 37, 40, 43, 46, 53, 54, 72, 75, 81, 83, 87, 89, 94, 98, 118, 126, 135, 139, 140, 141, 143, 147, 149, 152, 155, 172, 174, 187, 206, 208, 226, 236, 270, 287, 292, 310], "action": [15, 43, 54, 139, 143, 172, 174, 226, 230, 246, 249, 267, 303, 310, 313], "start_anim": 15, "i_ren": [15, 43, 45, 54, 294], "_button": [15, 43, 54, 294], "pause_anim": 15, "destroy_tim": [15, 20, 296, 297], "on_left_mouse_button_click": [15, 43, 54, 294, 297], "viz_solar_system_anim": 15, "vtksourc": [16, 189, 191, 295], "prim_sphere_actor": 16, "vtkspheresourc": 16, "vtk_sphere_actor": 16, "067": 16, "spike": 17, "point": [17, 25, 29, 32, 33, 37, 40, 59, 62, 64, 72, 75, 76, 94, 130, 143, 150, 155, 159, 162, 168, 170, 174, 181, 183, 186, 187, 188, 190, 195, 197, 198, 204, 206, 207, 210, 219, 222, 226, 231, 244, 246, 247, 250, 253, 256, 259, 265, 266, 268, 269, 271, 272, 275, 276, 277, 290, 293, 295, 296, 297, 310], "evenli": [17, 274, 284], "distribut": [17, 26, 30, 74, 98, 172, 177, 231, 235, 268, 269, 270, 274, 281, 284, 312, 316], "connect": [17, 24, 35, 40, 59, 75, 78, 80, 81, 82, 83, 84, 87, 89, 90, 117, 173, 179, 253, 263, 268, 272, 295, 313], "prim_spher": [17, 28, 297], "provid": [17, 24, 27, 28, 32, 37, 39, 59, 61, 65, 72, 98, 109, 115, 135, 136, 141, 144, 147, 153, 159, 172, 180, 199, 231, 234, 237, 246, 249, 272, 274, 276, 277, 281, 284, 287, 288, 290, 291, 292, 293, 294, 295, 296, 307, 316], "symmetric362": [17, 30, 290], "gen_fac": [17, 290], "green": [17, 39, 46, 47, 50, 53, 174, 274, 294], "point_actor": [17, 274], "point_radiu": [17, 33, 274], "vector": [17, 27, 62, 75, 94, 119, 174, 206, 207, 236, 257, 271, 274, 276, 277, 290, 293, 295, 296], "perpendicular": [17, 296], "whether": [17, 72, 162, 181, 207, 212, 216, 222, 231, 267, 274, 276, 277, 287, 290, 294, 296, 315, 316], "repres": [17, 18, 32, 33, 35, 36, 75, 147, 155, 170, 173, 174, 231, 256, 257, 270, 271, 274, 275, 277, 281, 287, 290, 292, 294, 295, 296], "curv": [17, 33, 173, 187, 203, 274, 276, 295], "normals_from_v_f": [17, 297], "light": [17, 37, 72, 73, 75, 77, 112, 114, 116, 179, 185, 206, 214, 225, 228, 266, 270, 286, 291], "bounc": [17, 207], "them": [17, 24, 28, 30, 32, 35, 36, 37, 39, 43, 46, 48, 49, 50, 51, 52, 54, 55, 56, 61, 63, 72, 75, 76, 77, 82, 110, 111, 113, 118, 119, 120, 125, 136, 137, 142, 150, 155, 156, 162, 169, 173, 174, 179, 180, 182, 183, 188, 189, 190, 193, 195, 199, 203, 206, 210, 217, 219, 222, 226, 228, 231, 233, 234, 235, 243, 257, 258, 259, 268, 270, 271, 276, 278, 287, 294, 304, 315], "get_actor_from_primit": [17, 32, 297], "primitive_color": 17, "primitive_actor": 17, "backface_cul": [17, 295], "small": [17, 65, 142, 143, 145, 162, 169, 181, 210, 248, 266, 268, 270, 271, 291, 306, 311], "fun": [17, 179, 180], "millisecond": [17, 20, 25, 26, 29, 33, 36, 40, 77, 87, 292], "applic": [17, 20, 72, 106, 138, 143, 155, 174, 178, 181, 184, 227, 229, 238, 241, 247, 250, 268, 270, 292, 295, 312], "been": [17, 20, 28, 43, 44, 45, 46, 50, 51, 52, 54, 55, 56, 64, 69, 76, 77, 97, 98, 109, 111, 120, 124, 126, 140, 143, 144, 148, 150, 153, 154, 155, 156, 158, 161, 162, 172, 174, 179, 180, 181, 203, 213, 227, 231, 233, 238, 256, 264, 267, 270, 272, 274, 277, 289, 291, 294], "getproperti": [17, 20, 75, 95], "setopac": [17, 20, 95], "instead": [17, 19, 32, 60, 65, 87, 115, 128, 146, 150, 153, 168, 179, 185, 186, 193, 198, 199, 202, 203, 206, 208, 210, 211, 214, 215, 219, 221, 222, 223, 227, 257, 271, 272, 276, 281, 292, 296], "other": [17, 18, 21, 24, 28, 62, 64, 66, 67, 72, 75, 87, 89, 109, 113, 117, 119, 132, 134, 141, 142, 143, 144, 147, 149, 150, 151, 153, 154, 155, 156, 159, 162, 165, 166, 170, 174, 177, 179, 181, 182, 183, 184, 185, 186, 187, 190, 191, 199, 202, 203, 206, 209, 211, 221, 223, 236, 237, 240, 242, 243, 244, 248, 249, 250, 254, 257, 258, 259, 264, 265, 270, 274, 277, 287, 291, 295, 296, 312, 316], "geometr": [17, 32, 51, 55, 72, 75, 226], "vtk": [18, 24, 45, 77, 94, 95, 97, 101, 108, 109, 112, 115, 131, 132, 135, 136, 139, 140, 143, 145, 146, 147, 149, 151, 155, 160, 171, 172, 173, 174, 176, 177, 179, 180, 182, 201, 202, 206, 207, 208, 219, 228, 231, 235, 238, 244, 247, 259, 268, 273, 274, 275, 278, 282, 283, 286, 291, 292, 295, 296, 302, 304, 305, 307, 308, 309, 310, 312, 313], "idea": [18, 98, 106, 110, 114, 118, 127, 130, 131, 135, 136, 138, 149, 155, 171, 178, 179, 180, 181, 182, 184, 186, 222, 229, 232, 236, 242, 247, 248, 251, 253, 257, 262, 265, 266, 269, 270, 275, 308], "save_polydata": [18, 297], "empti": [18, 277, 282, 292, 293, 313, 315], "my_polydata": 18, "my_vertic": 18, "type": [18, 34, 94, 98, 136, 142, 149, 153, 154, 155, 172, 173, 174, 181, 185, 194, 228, 237, 238, 248, 256, 269, 273, 274, 275, 276, 277, 278, 279, 281, 282, 283, 284, 286, 287, 288, 290, 291, 292, 293, 294, 295, 296, 307], "mention": [18, 60, 120, 147, 179, 181, 186, 206, 210, 211, 221, 222, 223, 226, 227, 235, 239, 256, 266, 271, 307], "int64": 18, "my_triangl": 18, "i8": 18, "set_polydata_vertic": [18, 297], "set_polydata_triangl": [18, 297], "vtkmodul": [18, 37], "vtkcommondatamodel": 18, "vtkpolydata": [18, 151, 154, 173, 283, 295], "0x2a2cf7340": 18, "0x13816ca00": 18, "file_nam": [18, 283, 294], "my_cub": 18, "cube_polydata": 18, "cube_vertic": 18, "get_polydata_vertic": [18, 297], "set_polydata_color": [18, 297], "get_polydata_color": [18, 297], "jpeg": [19, 279, 283, 292, 294], "avail": [19, 24, 27, 35, 36, 85, 88, 90, 94, 98, 99, 100, 101, 102, 104, 105, 107, 110, 112, 114, 115, 118, 121, 123, 124, 127, 129, 132, 133, 137, 139, 141, 143, 149, 155, 161, 167, 170, 172, 174, 177, 179, 230, 247, 253, 268, 272, 274, 287, 292, 296], "470": [19, 312], "level": [20, 32, 179, 181, 235, 239, 270, 271, 274, 277, 286], "insid": [20, 21, 26, 30, 75, 87, 140, 147, 149, 150, 153, 155, 164, 170, 172, 174, 176, 190, 193, 200, 202, 207, 221, 228, 231, 235, 241, 244, 250, 253, 254, 256, 265, 268, 270, 271, 276, 292, 296, 313], "timer_id": [20, 296], "destroi": [20, 84], "replac": [20, 72, 77, 94, 102, 105, 130, 136, 172, 219, 225, 250, 280, 281, 291, 294, 304, 306, 307, 312, 313], "faster": [20, 75, 76, 110, 122, 135, 169, 179, 206, 227], "demonstr": [21, 25, 27, 30, 37, 43, 46, 47, 48, 50, 51, 52, 53, 54, 56, 59, 77, 94, 125, 127, 129, 134, 136, 147, 148, 153, 168, 172, 173, 227], "collid": [21, 181, 274, 284, 309], "wall": [21, 78, 79, 84, 90, 119, 122, 128, 131, 136, 314], "veloc": [21, 33, 36, 160, 173, 179, 313], "simplic": [21, 181, 268, 270], "forc": [21, 36, 80, 81, 82, 83, 84, 130, 136, 146, 150, 155, 172, 174, 223, 276, 310, 313], "edg": [21, 34, 35, 36, 40, 75, 88, 155, 174, 217, 277], "box_edg": 21, "box_lx": 21, "box_li": 21, "box_lz": 21, "edge1": 21, "edge2": 21, "edge3": 21, "edge4": 21, "edge5": 21, "lower": [21, 25, 72, 118, 226, 240, 276, 281, 294], "num_particl": [21, 26], "ndindex": 21, "distanc": [21, 27, 32, 36, 40, 72, 75, 76, 98, 123, 148, 173, 174, 175, 179, 183, 198, 230, 270, 274, 276, 287, 294, 296, 308, 313], "linalg": [21, 24, 27], "norm": [21, 26, 30, 274, 275, 293], "vel_mag_i": 21, "vel": 21, "vel_mag_j": 21, "equal": [21, 26, 64, 65, 94, 122, 173, 271, 274, 275, 281, 295], "sum": [21, 122, 181, 250, 253, 268, 287, 293], "dt": [21, 25, 62], "where": [21, 27, 29, 63, 68, 75, 94, 97, 109, 119, 122, 128, 136, 143, 145, 147, 149, 155, 162, 173, 174, 181, 183, 185, 188, 204, 215, 220, 223, 232, 233, 234, 235, 243, 263, 264, 270, 271, 272, 274, 275, 277, 278, 279, 286, 287, 289, 293, 294, 295, 296, 315], "randomli": [21, 36, 60, 268, 310], "step": [21, 26, 31, 35, 36, 39, 52, 61, 62, 64, 72, 75, 80, 81, 82, 83, 84, 94, 97, 110, 112, 117, 126, 127, 128, 140, 160, 173, 179, 206, 227, 241, 244, 247, 248, 253, 254, 256, 268, 272, 276, 277, 294, 308, 313, 315], "With": [21, 24, 28, 37, 72, 89, 98, 115, 125, 132, 136, 137, 149, 153, 162, 194, 246, 265, 268, 270, 315], "streamtub": [21, 24, 27, 297, 307], "box_cent": 21, "box_direct": 21, "box_color": 21, "line_actor": [21, 33], "no_vertices_per_spher": 21, "len": [21, 25, 26, 28, 29, 33, 35, 36, 40, 45, 80, 88, 274, 292], "initial_vertic": [21, 25, 26, 29, 33], "reset_clipping_rang": [21, 24, 36, 39, 46, 50, 54, 56, 296, 297], "simple_collis": 21, "128": [21, 25, 27, 286, 307], "bunch": [22, 51, 54, 55, 77, 90], "app": [22, 35, 90], "marker": [22, 23, 31, 65, 90, 140, 146, 147, 167, 174, 175, 297, 311, 314, 315], "interdisciplinari": [22, 23, 90, 314], "journal": [22, 23, 90, 270, 275, 279, 311, 314], "network": [22, 23, 88, 90, 140, 144, 146, 158, 174, 176, 268, 307, 310, 314], "roi": [22, 23, 28, 90, 251, 274, 303, 313, 314], "streamlin": [22, 23, 24, 90, 103, 234, 274, 275, 277, 295, 307, 314], "charg": [22, 23, 90, 268, 314], "particl": [22, 23, 26, 90, 160, 173, 309, 314], "magnet": [22, 23, 29, 90, 270, 275, 314], "electr": [22, 23, 29, 90, 314], "field": [22, 23, 29, 90, 123, 174, 247, 270, 274, 275, 277, 294, 295, 308, 314], "brownian": [22, 23, 90, 160, 173, 310, 313, 314], "video": [22, 23, 90, 108, 109, 149, 174, 181, 193, 214, 227, 276, 292, 296, 311, 314], "fine": [22, 23, 90, 140, 143, 146, 166, 174, 183, 185, 188, 213, 222, 235, 238, 259, 269, 312, 314], "tune": [22, 23, 90, 140, 146, 166, 232, 312, 314], "opengl": [22, 23, 90, 97, 110, 140, 143, 146, 174, 176, 179, 180, 231, 235, 244, 247, 253, 268, 291, 292, 296, 312, 313, 314], "state": [22, 23, 65, 90, 140, 146, 147, 153, 155, 174, 181, 199, 227, 235, 276, 291, 294, 296, 307, 312, 314], "shader": [22, 23, 71, 72, 75, 76, 77, 98, 103, 108, 110, 112, 118, 121, 126, 132, 133, 135, 140, 148, 172, 174, 176, 177, 179, 182, 193, 196, 201, 202, 208, 212, 219, 223, 225, 227, 228, 231, 233, 239, 244, 247, 250, 253, 257, 259, 260, 265, 266, 268, 270, 271, 274, 279, 297, 307, 309, 310, 311, 312, 313, 314], "electromagnet": [22, 23, 90, 310, 314], "wave": [22, 23, 33, 90, 157, 312, 314], "propag": [22, 23, 90, 141, 153, 156, 198, 237, 240, 310, 314], "metric": [22, 23, 72, 75, 90, 271, 314], "tesseract": [22, 23, 90, 228, 313, 314], "hypercub": [22, 23, 90, 314], "collis": [22, 23, 78, 79, 81, 90, 98, 131, 136, 314], "advanc": [22, 23, 90, 98, 150, 233, 287, 310, 314], "brain": [22, 23, 28, 90, 251, 270, 314], "fiber": [22, 23, 90, 270, 275, 304, 314], "odf": [22, 23, 90, 104, 139, 233, 254, 257, 260, 263, 274, 275, 305, 310, 314], "visualis": [22, 23, 90, 142, 314], "fractal": [22, 23, 90, 313, 314], "version": [22, 23, 89, 90, 143, 146, 149, 152, 172, 174, 177, 179, 181, 182, 184, 193, 202, 207, 227, 228, 230, 247, 259, 261, 267, 268, 270, 274, 277, 281, 287, 289, 291, 292, 294, 296, 304, 307, 309, 312, 313, 314, 315], "tensor": [22, 23, 90, 233, 236, 242, 245, 248, 251, 257, 260, 270, 274, 277, 297, 303, 314], "ellipsoid": [22, 23, 76, 90, 126, 135, 233, 242, 245, 246, 250, 254, 275, 297, 303, 310, 314], "dti": [22, 23, 90, 233, 251, 257, 274, 275, 303, 314], "tensor_slic": [22, 23, 90, 236, 248, 251, 270, 297, 313, 314], "v": [22, 23, 25, 32, 40, 70, 71, 90, 143, 202, 218, 274, 277, 293, 314, 315], "pbr": [22, 23, 70, 71, 90, 177, 310, 312, 314], "543": 23, "04_demo": [23, 314], "viz_dt_ellipsoid": [23, 28, 314], "08": [23, 33, 135, 136, 172, 173, 174, 226, 227, 228, 270, 272, 298, 306, 310, 312], "555": [23, 28, 179, 313], "viz_network_anim": [23, 36, 228, 313, 314], "viz_pbr_interact": [23, 37, 313, 314], "974": [23, 37], "viz_advanc": [23, 24, 314], "viz_animated_surfac": [23, 25, 314], "viz_brownian_mot": [23, 26, 314], "viz_bundl": [23, 27, 314], "viz_emwave_anim": [23, 29, 314], "viz_fiber_odf": [23, 30, 314], "viz_fine_tuning_gl_context": [23, 31, 314], "viz_fract": [23, 32, 314], "viz_helical_mot": [23, 33, 314], "viz_mark": [23, 34, 314], "viz_network": [23, 35, 314], "viz_play_video": [23, 38, 314], "viz_roi_contour": [23, 39, 313, 314], "viz_tesseract": [23, 40, 314], "thin": [24, 173], "capabl": [24, 30, 121, 127, 128, 129, 135, 137, 171, 227, 228, 262, 274], "toolkit": [24, 231], "framework": [24, 108, 127, 135, 235, 272], "tailor": 24, "diffus": [24, 28, 245, 248, 251, 270, 274, 275, 286, 303], "modul": [24, 25, 26, 28, 29, 30, 32, 33, 37, 65, 72, 73, 74, 75, 90, 94, 139, 141, 143, 145, 147, 149, 153, 154, 155, 156, 157, 160, 163, 164, 165, 166, 168, 169, 170, 172, 173, 174, 176, 177, 223, 227, 228, 230, 265, 269, 274, 277, 280, 287, 290, 297, 303, 304, 310, 311, 312, 313, 315], "wa": [24, 74, 98, 109, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 124, 125, 126, 127, 128, 129, 130, 131, 132, 134, 135, 136, 137, 141, 143, 144, 145, 147, 148, 149, 150, 151, 152, 153, 155, 156, 157, 158, 159, 160, 162, 166, 168, 171, 173, 174, 176, 179, 180, 181, 182, 183, 184, 185, 186, 188, 189, 191, 192, 194, 195, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 212, 215, 216, 218, 219, 222, 226, 227, 231, 232, 234, 235, 236, 237, 239, 240, 242, 243, 246, 248, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 276, 277, 278, 281, 292, 295, 296, 313, 315], "fvtk": [24, 304], "still": [24, 72, 97, 119, 122, 130, 132, 136, 149, 153, 156, 159, 174, 179, 181, 191, 195, 203, 205, 212, 213, 215, 223, 236, 245, 250, 251, 252, 256, 259, 260, 262, 266, 268, 270, 271, 272, 281], "backward": [24, 304, 307], "compat": [24, 98, 107, 123, 139, 174, 175, 176, 207, 237, 246, 258, 267, 272, 303, 304, 307, 308, 310], "comprehens": [24, 268, 272], "fetcher": [24, 36, 77, 88, 185, 226, 297, 307, 310, 313], "read_bundles_2_subject": [24, 27], "disk": [24, 51, 54, 179, 277, 278, 294, 297, 312], "open": [24, 89, 97, 98, 99, 100, 101, 102, 104, 105, 106, 107, 123, 133, 136, 138, 139, 140, 141, 146, 149, 153, 155, 167, 172, 174, 177, 178, 181, 182, 227, 229, 230, 237, 263, 268, 272, 290, 294, 303, 311, 313, 315], "dialog": [24, 128, 136, 294, 303, 307], "snapshot": [24, 297, 306, 312, 313], "slider": [24, 30, 35, 37, 41, 42, 49, 90, 162, 187, 190, 199, 204, 219, 222, 226, 227, 262, 268, 294, 306, 307, 312, 313, 314], "input": [24, 27, 37, 62, 69, 72, 75, 199, 203, 264, 274, 275, 277, 281, 294, 295, 296], "oper": [24, 72, 94, 119, 136, 176, 185, 235, 238, 241, 256, 313], "fa": [24, 27, 28], "t1": [24, 62, 276], "lineslider2d": [24, 30, 37, 49, 53, 54, 56, 125, 190, 240, 297, 307], "widget": [24, 30, 85, 86, 90, 99, 109, 136, 172, 176, 201, 207, 272, 297, 299, 303, 304, 314], "tar": [24, 43, 44, 46, 47, 50, 51, 52, 53, 54, 55, 56], "digit": [24, 43, 44, 46, 47, 50, 51, 52, 53, 54, 55, 56], "washington": [24, 43, 44, 46, 47, 50, 51, 52, 53, 54, 55, 56], "edu": [24, 43, 44, 46, 47, 50, 51, 52, 53, 54, 55, 56, 277, 293], "researchwork": [24, 43, 44, 46, 47, 50, 51, 52, 53, 54, 55, 56], "bitstream": [24, 43, 44, 46, 47, 50, 51, 52, 53, 54, 55, 56], "handl": [24, 37, 43, 44, 46, 47, 50, 51, 52, 53, 54, 55, 56, 60, 61, 64, 68, 75, 94, 115, 117, 119, 170, 181, 182, 185, 192, 194, 195, 204, 207, 223, 226, 227, 260, 264, 265, 267, 268, 270, 271, 272, 276, 294, 297, 306, 313], "1773": [24, 43, 44, 46, 47, 50, 51, 52, 53, 54, 55, 56], "38477": 24, "97756fbef11ce2df31f1bedf1fc7aac7": 24, "output": [24, 72, 77, 112, 118, 121, 124, 127, 129, 132, 135, 137, 173, 181, 212, 219, 244, 252, 256, 259, 268, 283, 289, 295, 296], "af": 24, "arcuat": 24, "fasciculu": 24, "subject": [24, 181, 227], "cst": [24, 27], "cc_1": 24, "bring": [24, 72, 94, 119], "ra": [24, 274], "1mm": [24, 274], "extend": [24, 32, 181, 234, 258, 272], "design": [24, 72, 74, 94, 108, 120, 122, 134, 136, 150, 156, 170, 179, 187, 242, 244, 265, 272, 274, 275, 293], "decid": [24, 25, 29, 33, 108, 109, 114, 117, 122, 125, 127, 128, 129, 130, 131, 135, 136, 141, 144, 147, 148, 150, 153, 154, 156, 162, 166, 172, 179, 183, 185, 188, 189, 191, 200, 215, 237, 244, 248, 255, 259, 262, 267, 268, 272, 295, 296], "space": [24, 27, 61, 72, 75, 76, 114, 142, 145, 154, 168, 171, 172, 173, 179, 194, 272, 274, 276, 277, 287, 293, 295, 311], "world_coord": [24, 288], "nativ": [24, 27, 128, 136, 169, 274, 275, 307], "back": [24, 94, 119, 122, 179, 181, 191, 194, 227, 244, 250, 259, 296, 315], "invers": [24, 179, 213, 282], "transform_streamlin": [24, 27], "inv": [24, 27], "stream_actor": [24, 27], "image_actor_z": 24, "ey": [24, 296], "slicer_opac": 24, "origin": [24, 26, 32, 59, 60, 65, 75, 94, 119, 131, 185, 198, 203, 207, 222, 228, 231, 244, 250, 259, 265, 273, 274, 277, 278, 282, 295, 313, 315], "display_ext": [24, 28, 30, 274, 275, 297], "image_actor_x": 24, "x_midpoint": 24, "image_actor_i": 24, "y_midpoint": 24, "image_actor": [24, 274], "ahead": [24, 181, 232, 234, 261, 264, 272], "line_slider_z": [24, 30], "min_valu": [24, 30, 37, 53, 54, 56, 294], "max_valu": [24, 30, 37, 53, 54, 56, 294], "initial_valu": [24, 30, 37, 53, 54, 56, 294], "text_templ": [24, 30, 37, 53, 54, 56, 294], "0f": [24, 30], "140": [24, 30, 46, 307], "line_slider_x": [24, 30, 53, 54], "line_slider_i": [24, 30, 53, 54], "opacity_slid": 24, "write": [24, 30, 98, 134, 136, 143, 148, 149, 152, 155, 170, 180, 182, 213, 225, 262, 265, 282, 292], "regist": [24, 30, 32, 37, 156, 315], "change_slice_z": [24, 30], "change_slice_x": [24, 30], "change_slice_i": [24, 30], "change_opac": 24, "on_chang": [24, 30, 32, 37, 46, 47, 50, 52, 53, 54, 55, 56, 199, 294, 297, 313], "label": [24, 28, 30, 37, 39, 43, 47, 53, 54, 61, 73, 74, 122, 125, 165, 174, 175, 176, 266, 270, 294, 296, 297, 304, 312, 315], "identifi": [24, 119, 149, 219, 226, 234, 240, 242, 246, 258, 264, 267, 272], "build_label": [24, 30], "font_siz": [24, 30, 32, 37, 40, 46, 47, 50, 53, 54, 55, 80, 81, 82, 83, 84, 95, 274, 294, 297], "font_famili": [24, 30, 46, 50, 274, 294, 297], "arial": [24, 30, 46, 50, 274, 294], "justif": [24, 30, 47, 53, 249, 272, 274, 294, 297, 303, 312], "ital": [24, 30, 274, 294, 297], "shadow": [24, 30, 179, 274, 294, 297], "background_color": [24, 30, 294, 297], "line_slider_label_z": [24, 30], "line_slider_label_x": [24, 30], "line_slider_label_i": [24, 30], "opacity_slider_label": 24, "1030": [24, 30], "screen": [24, 27, 30, 54, 75, 97, 176, 201, 235, 238, 240, 247, 250, 253, 256, 265, 268, 279, 294, 296, 313], "properli": [24, 30, 109, 113, 130, 150, 182, 185, 212, 222, 247, 260, 265, 268, 271, 272], "solut": [24, 30, 110, 115, 143, 144, 146, 147, 149, 152, 156, 162, 174, 234, 237, 241, 244, 247, 250, 259, 264, 267, 268, 270, 271, 272, 274, 292], "issu": [24, 30, 97, 98, 109, 111, 113, 114, 115, 117, 119, 120, 121, 122, 124, 125, 127, 128, 129, 130, 131, 134, 135, 136, 140, 143, 144, 150, 153, 155, 162, 174, 176, 180, 181, 182, 183, 185, 186, 187, 189, 194, 195, 198, 202, 203, 205, 206, 208, 210, 211, 214, 216, 219, 220, 221, 223, 226, 227, 234, 235, 238, 240, 243, 244, 246, 249, 250, 252, 253, 255, 257, 258, 259, 260, 263, 264, 265, 267, 268, 269, 270, 271, 272, 281, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 315], "re_align": [24, 30, 37, 294, 297], "getsiz": [24, 30, 37], "win_callback": [24, 30, 37, 296], "size_old": [24, 30, 37], "size_chang": [24, 30, 37], "final": [24, 30, 31, 32, 35, 36, 37, 54, 60, 65, 72, 73, 74, 75, 94, 110, 122, 128, 131, 134, 137, 141, 149, 150, 153, 157, 165, 176, 179, 196, 202, 211, 235, 242, 244, 247, 249, 250, 253, 257, 259, 261, 262, 263, 265, 266, 267, 269, 271, 274, 276, 277, 294, 295, 303, 310, 313], "add_window_callback": [24, 30, 37, 296, 297, 307], "bundles_and_3_slic": 24, "del": [24, 30], "302": [24, 310], "necessari": [25, 26, 28, 29, 32, 33, 37, 72, 73, 74, 75, 82, 84, 120, 122, 128, 143, 149, 174, 237, 239, 249, 251, 254, 268, 270, 292, 294, 296, 312, 313, 315], "colormap": [25, 30, 35, 36, 39, 61, 88, 99, 173, 193, 199, 253, 256, 268, 270, 271, 274, 275, 295, 297, 299, 304, 308, 311], "being": [25, 36, 75, 84, 97, 112, 114, 130, 137, 147, 148, 149, 156, 162, 179, 187, 204, 206, 208, 211, 214, 223, 225, 227, 238, 241, 244, 247, 256, 259, 265, 268, 271, 272, 276, 294, 295, 304, 307, 313], "plot": [25, 26, 29, 33, 247, 253, 268, 277, 303], "kindli": [25, 29], "onli": [25, 27, 32, 37, 59, 60, 62, 64, 65, 68, 72, 115, 128, 130, 137, 147, 148, 150, 153, 155, 156, 160, 168, 172, 174, 176, 179, 187, 189, 197, 199, 201, 206, 209, 226, 227, 243, 253, 256, 257, 259, 265, 266, 267, 268, 270, 271, 272, 274, 275, 276, 277, 292, 294, 295, 296, 312], "update_surfac": 25, "equat": [25, 62, 270, 275], "cmap_nam": 25, "viridi": [25, 253, 268, 277], "f": [25, 45, 149, 166, 266, 277, 291], "eval": [25, 28, 270, 274, 275], "vstack": [25, 27], "m_v": 25, "ab": [25, 28, 35, 72, 88], "create_colormap": [25, 297, 310], "usag": [25, 94, 98, 151, 181, 241, 243, 248, 262, 265, 268, 270], "float": [25, 26, 43, 54, 72, 75, 77, 172, 198, 259, 265, 268, 269, 274, 275, 276, 277, 282, 283, 284, 286, 287, 290, 291, 292, 294, 295, 296], "begin": [25, 26, 29, 32, 33, 65, 66, 157, 174, 237, 272], "program": [25, 75, 77, 135, 179, 180, 206, 212, 219, 232, 233, 235, 238, 244, 253, 255, 256, 262, 263, 264, 268, 272, 274, 291, 308], "amount": [25, 65, 72, 88, 143, 225, 227, 236, 245, 248, 257, 270, 274, 292], "increment": [25, 29, 33, 267, 294, 297], "iter": [25, 36, 38, 40, 81, 82, 83, 94, 172, 253, 277, 292, 293], "lower_xbound": 25, "bound": [25, 115, 136, 169, 173, 181, 186, 188, 192, 195, 216, 222, 226, 249, 252, 255, 258, 263, 270, 271, 272, 274, 284, 287, 294, 295, 303, 307, 308], "upper_xbound": 25, "upper": [25, 240], "lower_ybound": 25, "upper_ybound": 25, "npoint": [25, 29], "high": [25, 29, 30, 72, 98, 143, 202, 270, 274, 281, 283, 284, 296], "qualiti": [25, 29, 72, 102, 104, 105, 107, 123, 133, 236, 248, 251, 259, 260, 270, 283, 296, 304, 305, 306, 307, 308, 309], "slow": [25, 29, 81, 82, 83, 84, 94, 148, 206, 227, 274], "elev": [25, 32, 296, 297], "linspac": [25, 29, 73], "meshgrid": 25, "reshap": [25, 40, 81, 82, 83, 84, 94, 128, 185, 194, 295, 307], "obtain": [25, 28, 245, 254, 260, 266, 270, 277, 287, 311], "create_surfac": 25, "colormap_nam": 25, "surf": 25, "no_vertices_per_point": [25, 26, 29, 33], "eq1": 25, "eq2": 25, "eq3": 25, "eq4": 25, "variou": [25, 30, 48, 80, 82, 84, 94, 117, 119, 136, 142, 162, 181, 183, 184, 185, 186, 201, 212, 222, 228, 243, 267, 272], "hot": 25, "plasma": [25, 277], "ocean": [25, 181], "append": [25, 35, 36, 40, 43, 45, 54, 81, 82, 83, 84, 88, 113, 189, 291, 294], "configur": [25, 26, 29, 30, 33, 40, 72, 155, 313], "individu": [25, 28, 75, 81, 83, 84, 94, 119, 125, 128, 144, 147, 153, 172, 179, 182, 184, 190, 216, 222, 226, 268, 270, 271, 272, 274, 275, 294, 313], "t_actor": 25, "grid_ui": [25, 28], "gridui": [25, 28, 102, 160, 260, 297, 304, 313], "caption": [25, 28, 274, 294, 305, 313], "caption_offset": [25, 28, 274, 294], "dim": [25, 28, 194, 274, 284, 290, 294, 295], "cell_pad": [25, 28, 274, 284, 294], "aspect_ratio": [25, 274, 284, 294, 295], "rotation_axi": [25, 294], "titl": [25, 29, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 76, 109, 153, 172, 181, 274, 294, 296, 297, 307], "form": [25, 62, 72, 81, 162, 179, 205, 220, 235, 247, 274, 275, 276, 284, 289, 290, 294, 295, 316], "update_surface_actor_color": [25, 297], "pedesi": 26, "suspend": 26, "medium": [26, 29, 143, 149], "exhibit": [26, 267], "scipi": [26, 97, 120, 307], "stat": [26, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313], "descript": [26, 29, 33, 39, 40, 94, 135, 136, 159, 162, 172, 173, 174, 226, 227, 228, 245, 250, 270, 272, 289, 291, 315], "total_tim": 26, "discret": [26, 72, 256, 270, 287], "via": [26, 77, 98, 113, 119, 142, 151, 154, 166, 268, 270, 275, 293, 296, 310], "time_step": 26, "num_total_step": 26, "counter_step": 26, "delta": [26, 270, 275], "whose": [26, 33, 72, 173, 274, 279, 284, 287, 294], "varianc": [26, 242, 245, 270, 274, 275], "path_thick": 26, "thick": [26, 274, 275, 287], "asarrai": [26, 28], "tile": 26, "path_actor": 26, "update_path": 26, "rv": 26, "l_particl": 26, "_": [26, 28, 32, 36, 38, 46, 63, 81, 83, 84, 170, 250, 270, 277, 293], "container_actor": 26, "235": [26, 308], "list_particl": 26, "p": [26, 34, 72, 80, 81, 82, 83, 84, 87, 88, 94, 128, 149, 174, 180, 194, 268, 270, 271, 274, 275, 279, 293], "253": [26, 308], "dix": 27, "subj_id": 27, "cg": 27, "fraction": [27, 28, 271, 274, 294], "anisotropi": [27, 28, 37, 73, 271, 286, 295, 312], "cingulum": 27, "bundle_n": 27, "176": [27, 71, 73, 307], "118": [27, 307], "113": 27, "bundle1": 27, "mai": [27, 40, 60, 65, 68, 75, 94, 136, 159, 174, 180, 212, 226, 228, 238, 250, 256, 257, 268, 274, 281, 289, 295, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 315, 316], "wonder": [27, 113], "knew": [27, 179, 180], "veri": [27, 68, 72, 117, 118, 119, 120, 143, 150, 152, 159, 168, 170, 172, 179, 180, 181, 194, 198, 206, 227, 270, 271], "just": [27, 31, 32, 40, 54, 75, 98, 143, 144, 147, 149, 156, 159, 174, 179, 181, 185, 188, 192, 209, 212, 219, 222, 223, 226, 235, 236, 238, 244, 259, 263, 266, 268, 276, 280, 291, 292, 294, 295, 315], "close": [27, 87, 108, 109, 146, 149, 211, 233, 249, 272, 277, 287, 296, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 315], "camera_info": [27, 296, 297], "focal": [27, 60, 193, 276, 296], "view": [27, 60, 89, 179, 181, 199, 276, 277, 293, 296], "activ": [27, 53, 94, 130, 134, 137, 184, 201, 226, 250, 253, 272, 276, 294, 305], "237": [27, 308], "115": [27, 58, 62, 307], "138": [27, 308], "112": [27, 306], "127": [27, 308], "stream_actor2": 27, "scalar": [27, 185, 274, 276, 282, 295], "bar": [27, 274, 294, 296, 313], "scalar_bar": [27, 297], "bundle2": 27, "hue": 27, "red": [27, 29, 33, 46, 47, 50, 53, 80, 274, 296], "satur": 27, "lut_cmap": 27, "stream_actor3": 27, "bar2": 27, "bundle3": 27, "orang": [27, 47, 53], "stream_actor4": 27, "bundle4": 27, "blue": [27, 29, 33, 39, 46, 47, 50, 53, 80, 151, 219, 274, 277, 287, 294, 296], "black": [27, 181, 250, 303, 313], "stream_actor5": 27, "bar3": 27, "bundle5": 27, "case": [27, 32, 37, 43, 54, 62, 72, 75, 94, 110, 113, 119, 137, 153, 155, 162, 173, 174, 181, 186, 204, 207, 243, 249, 250, 256, 265, 266, 268, 270, 272, 276, 277, 287, 294, 295, 307], "per": [27, 59, 72, 114, 188, 207, 266, 270, 274, 275, 276, 278, 283, 295, 296], "insert": [27, 40, 291, 294], "rgb": [27, 47, 194, 271, 274, 275, 276, 277, 286, 287, 290, 294, 295, 296, 303, 310], "stream_actor6": 27, "bundle6": 27, "drawn": [27, 72, 147, 170, 183, 238, 274, 275, 294, 295], "width": [27, 34, 95, 111, 115, 122, 136, 149, 183, 227, 235, 238, 244, 256, 274, 276, 284, 294, 295, 296, 297, 313], "regardless": 27, "realism": 27, "enabl": [27, 28, 65, 84, 98, 105, 135, 142, 154, 249, 261, 268, 272, 273, 276, 296, 304, 306, 313], "depth_cu": [27, 274, 304], "shrink": [27, 255, 274], "scheme": [27, 32], "best": [27, 62, 137, 150, 181, 186, 265, 274, 315], "stream_actor7": 27, "bundle7": 27, "shade": [27, 72, 74, 77, 129, 135, 182, 228, 274, 286], "fake_tub": [27, 36, 40, 274, 304], "stream_actor8": 27, "bundle8": 27, "fulli": [27, 94, 98, 250, 272, 274, 275, 277], "challeng": [27, 110, 112, 117, 118, 155, 179, 232, 234, 237, 240, 243, 246, 255, 259, 264, 267, 272], "techniqu": [27, 28, 65, 72, 75, 116, 129, 132, 162, 198, 231, 233, 246, 268, 270, 292], "stream_actor9": 27, "bundle9": 27, "yet": [27, 119, 122, 165, 169, 172, 180, 190, 199, 203, 232, 236, 244, 259, 268], "much": [27, 28, 72, 110, 120, 135, 181, 185, 186, 227, 239, 241, 254, 266, 274, 296], "geometri": [27, 32, 63, 75, 76, 108, 110, 135, 196, 202, 223, 225, 227, 228, 270, 274, 290, 291, 313], "computation": [27, 135, 270], "expens": [27, 135, 143, 174], "larg": [27, 28, 36, 107, 123, 133, 139, 140, 143, 148, 153, 167, 187, 194, 230, 231, 236, 270, 277, 307, 308, 309, 310, 311, 313], "approxim": [27, 30, 43, 44, 45, 46, 47, 50, 51, 52, 53, 54, 55, 56, 270, 274, 275], "describ": [27, 28, 37, 94, 97, 141, 147, 150, 155, 174, 226, 238, 241, 247, 250, 266, 268, 269, 270, 273, 275, 276, 277, 279, 294, 296, 308], "stream_actor10": 27, "bundle10": 27, "691": [27, 313], "load_nifti": 28, "_fa": 28, "_color_fa": 28, "fetch_viz_dmri": [28, 30, 297], "read_viz_dmri": [28, 30, 297], "dmri": [28, 30, 270, 279], "fodf": [28, 30], "767ca3e4cd296e78421d83c32201b30be2d859c332210812140caac1b93d492b": 28, "slice_evec": 28, "8843ecf3224cb8e3315b7251d1e303409a17d7137d3498a8833853c4603c6cc2": 28, "slice_ev": 28, "3096b190b1146dd0eaddfecc0b4fbbd901f4933692add46a83f637f28b22122d": 28, "roi_evec": 28, "89e569858a897e72c852a8f05bbce0b21c1ca726e55508087a2da5a38c212a17": 28, "roi_ev": 28, "f53c68cccabf97f1326e93840a8b5ce2e767d66d692ffd955ca747fff14ec781": 28, "whole_brain_evec": 28, "8a894f6ab404240e65451fa6d10fb5d74e2d0bdcb2a56ad6bea38215bf787248": 28, "whole_brain_ev": 28, "47a73bbe68196381ed790f80f48e46ac07b699b506973ffa45a95a33023c7a77": 28, "express": [28, 30, 94, 180, 270, 274, 275, 280, 281, 316], "eigenvalu": [28, 270, 274, 275], "eigenvector": [28, 270, 274, 275, 277], "decomposit": 28, "water": [28, 270], "within": [28, 37, 72, 73, 94, 112, 114, 118, 121, 125, 134, 135, 136, 153, 181, 234, 268, 272, 294, 296], "must": [28, 31, 60, 62, 63, 65, 68, 94, 125, 143, 149, 155, 172, 174, 176, 227, 238, 271, 274, 276, 279, 285, 286, 287, 291, 294, 316], "repulsionn": 28, "724": [28, 251, 313], "repulsion100": [28, 30, 290], "As": [28, 72, 103, 111, 114, 120, 126, 136, 141, 142, 143, 149, 153, 155, 156, 162, 165, 170, 181, 182, 183, 185, 186, 188, 189, 190, 195, 200, 205, 206, 207, 210, 212, 213, 215, 216, 219, 222, 226, 227, 231, 235, 238, 239, 240, 241, 242, 249, 250, 252, 254, 256, 259, 262, 264, 265, 266, 268, 270, 271, 272, 276], "__init__": [28, 38, 149, 273, 274, 275, 276, 277, 281, 282, 284, 287, 288, 292, 294, 296, 297], "self": [28, 32, 38, 149, 284, 294, 313], "sphere100": 28, "readi": [28, 35, 36, 37, 72, 94, 119, 124, 131, 170, 176, 209, 211, 227, 239, 241, 242, 253, 254, 256, 258, 259, 261, 265, 268, 271, 272, 315], "overlap": [28, 217], "evec": [28, 270, 274, 275], "tensor_slice_100": 28, "result": [28, 31, 35, 36, 40, 64, 74, 118, 119, 143, 144, 149, 150, 152, 174, 180, 181, 185, 198, 212, 237, 239, 240, 250, 253, 255, 256, 259, 260, 266, 267, 268, 270, 271, 272, 275, 279, 285, 291, 295, 296], "roll": [28, 94, 206, 293, 296, 297], "tensor_slice_100_zoom": 28, "redefin": [28, 296], "repulsion200": [28, 290], "repulsion724": [28, 290], "revert": [28, 264], "purpos": [28, 72, 73, 74, 98, 144, 150, 151, 172, 242, 248, 254, 316], "helper": [28, 37, 62, 84, 153, 202, 217, 226, 253, 258, 297, 313], "facilit": [28, 264, 272, 277], "correct": [28, 32, 54, 65, 153, 176, 189, 216, 218, 222, 236, 239, 242, 251, 252, 253, 260, 263, 266, 267, 268, 271, 272, 282, 295, 296, 305, 307, 313], "get_param": 28, "valid_mask": 28, "nonzero": 28, "ndarrai": [28, 38, 62, 228, 269, 274, 275, 276, 277, 278, 282, 283, 287, 290, 291, 293, 294, 295, 296], "rearrang": 28, "fevec": 28, "feval": 28, "tensor_slice_sdf": 28, "thu": [28, 113, 117, 155, 176, 248, 293], "raymarch": [28, 76, 126, 135, 233, 236, 239, 246, 254, 257], "smoother": [28, 40, 72, 185, 201, 228, 249, 274], "sinc": [28, 60, 62, 64, 65, 69, 72, 75, 76, 94, 97, 108, 110, 124, 126, 134, 148, 149, 179, 180, 185, 194, 203, 206, 227, 231, 233, 239, 245, 251, 252, 254, 261, 262, 263, 266, 267, 270, 271, 281, 296], "polygon": [28, 70, 71, 72, 76, 90, 126, 132, 135, 211, 270, 274, 295, 297, 313, 314], "sdf": [28, 70, 71, 88, 90, 112, 114, 127, 135, 139, 174, 230, 233, 239, 242, 246, 254, 257, 297, 303, 308, 310, 313, 314], "tensor_slice_sdf_zoom": 28, "One": [28, 143, 146, 147, 149, 155, 171, 174, 176, 180, 228, 234, 244, 247, 259, 268, 270, 277, 282, 293], "implement": [28, 32, 72, 74, 75, 94, 108, 109, 110, 111, 112, 114, 115, 116, 117, 118, 119, 120, 121, 122, 125, 129, 131, 132, 134, 135, 136, 137, 141, 142, 143, 145, 146, 147, 148, 149, 150, 151, 156, 157, 159, 160, 162, 169, 171, 173, 174, 176, 179, 180, 181, 183, 193, 195, 198, 199, 201, 203, 204, 206, 207, 211, 214, 215, 217, 219, 220, 222, 223, 224, 227, 228, 231, 233, 234, 235, 237, 238, 239, 243, 244, 245, 247, 249, 250, 253, 254, 256, 257, 259, 260, 262, 267, 268, 272, 274, 277, 291, 292, 293, 298, 303, 308, 311, 313], "meval": 28, "mevec": 28, "sphere200": 28, "sphere724": 28, "tensor_100": 28, "tensor_200": 28, "tensor_724": 28, "tensor_sdf": 28, "560": [28, 48, 313], "tensor_comparison": 28, "magnif": [28, 174, 296, 313], "interest": [28, 32, 73, 74, 106, 127, 138, 144, 150, 151, 168, 178, 180, 227, 229, 235, 247, 250, 259, 273], "tensor_roi": 28, "data_shap": 28, "tensor_roi_100": 28, "try": [28, 39, 77, 98, 109, 117, 122, 130, 132, 134, 135, 137, 142, 145, 146, 148, 156, 160, 169, 171, 179, 181, 186, 187, 192, 197, 201, 202, 208, 211, 214, 215, 219, 223, 226, 227, 235, 239, 247, 249, 250, 253, 259, 260, 265, 268, 272, 315], "longer": 28, "contrast": [28, 235], "without": [28, 32, 81, 83, 89, 97, 98, 119, 146, 149, 151, 155, 159, 174, 176, 195, 199, 201, 219, 228, 236, 238, 239, 240, 244, 247, 259, 261, 268, 271, 274, 276, 277, 278, 284, 296, 303, 310, 312, 313, 315, 316], "compromis": [28, 72, 98, 172, 236, 270], "tensor_roi_sdf": 28, "fact": [28, 180, 238], "although": [28, 74, 143, 148, 149, 174, 233, 243, 248, 258, 264, 265, 267], "low": [28, 30, 87, 89, 143, 174, 179, 235, 259, 264, 268, 274, 277, 283, 310], "whole": [28, 150, 162, 172, 179, 181, 251, 255, 262, 265, 268], "exact": [28, 181, 296], "184512": 28, "nois": [28, 135, 179, 242, 245, 268, 270, 274, 275], "fil": 28, "elem": 28, "compress": [28, 283], "tensor_whole_brain_sdf": 28, "linearli": [29, 67, 276], "polar": [29, 293], "sinusoid": 29, "through": [29, 65, 73, 74, 75, 87, 94, 98, 108, 110, 112, 115, 134, 135, 136, 146, 173, 174, 179, 180, 181, 182, 222, 231, 234, 235, 238, 255, 258, 261, 268, 270, 271, 292, 294, 310, 313, 315], "homogen": [29, 277, 293, 295], "isotrop": [29, 286], "dissipationless": 29, "vacuum": 29, "oscil": [29, 82], "orthogon": [29, 236], "phase": [29, 33, 268, 272], "wavenumb": 29, "abscissa": 29, "angular": [29, 33, 270, 275], "frequenc": [29, 33], "update_coordin": [29, 33], "ang_frq": 29, "phase_angl": [29, 33], "800": [29, 32, 33, 43, 50, 51, 52, 53, 54, 55, 56, 87, 303], "wavelength": 29, "incre_tim": [29, 33], "angular_frq": [29, 33], "yellow": [29, 47, 53, 217, 219], "tip_length": [29, 33, 274, 290], "tip_radiu": [29, 33, 274, 290], "012": [29, 33], "shaft_radiu": [29, 33, 274, 290], "pt": [29, 33, 274, 294, 295], "wave_actor1": 29, "xx": 29, "yy": 29, "zz": 29, "pts2": 29, "colors2": 29, "wave_actor2": 29, "vertices2": 29, "vcolors2": 29, "no_vertices_per_point2": 29, "initial_vertices2": 29, "160": [29, 64, 307], "time_incr": 29, "viz_emwav": 29, "524": [29, 312], "viewer": [30, 228], "odf_slic": [30, 260, 263, 270, 271, 297, 304, 310], "get_spher": 30, "reconst": [30, 39], "shm": [30, 39], "sh_to_sf_matrix": 30, "fetch_viz_icon": [30, 43, 44, 45, 46, 47, 50, 51, 52, 53, 54, 55, 56, 297], "fix_winding_ord": [30, 275, 297], "harmon": [30, 114, 126, 135, 254, 257, 260, 263, 270, 274], "sh": [30, 149, 266, 270, 271, 274, 275], "coeffici": [30, 80, 135, 266, 270, 271, 274, 275, 286], "fodf_img": 30, "grid_shap": 30, "12kb": [30, 43, 44, 45, 46, 47, 50, 51, 52, 53, 54, 55, 56], "icon": [30, 43, 44, 45, 46, 47, 48, 50, 51, 52, 53, 54, 55, 56, 165, 172, 184, 201, 226, 234, 272, 279, 294, 303, 307, 310, 313], "sf": [30, 274, 275], "b_low": 30, "onto": [30, 235, 270, 293], "sphere_low": 30, "return_inv": 30, "radial_scal": [30, 274, 275], "global_cm": [30, 274, 275], "odf_actor_z": 30, "b_matrix": [30, 270, 274, 275], "coron": 30, "odf_actor_i": 30, "odf_actor_x": 30, "dynam": [30, 81, 110, 117, 135, 155, 172, 174, 227, 233, 255, 256, 258, 272, 275, 294, 307], "sphere_high": 30, "fix": [30, 84, 94, 110, 111, 113, 115, 117, 120, 121, 123, 128, 130, 131, 142, 146, 147, 149, 150, 159, 162, 164, 169, 172, 174, 175, 176, 179, 180, 181, 184, 185, 186, 187, 189, 193, 194, 198, 202, 206, 211, 214, 215, 220, 221, 222, 225, 226, 227, 228, 234, 240, 250, 252, 258, 259, 265, 266, 267, 270, 272, 276, 277, 300, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313], "three": [30, 32, 54, 60, 81, 83, 109, 115, 136, 151, 154, 155, 168, 173, 174, 176, 179, 226, 253, 255, 256, 259, 268, 272, 277, 295, 313], "clockwis": [30, 275, 286, 293, 295], "wind": [30, 295, 307], "awai": [30, 179, 295, 296], "b_high": 30, "combobox": [30, 41, 42, 90, 111, 113, 115, 123, 125, 136, 234, 237, 272, 294, 308, 314], "dure": [30, 64, 69, 94, 103, 113, 117, 134, 135, 137, 140, 141, 147, 156, 162, 172, 173, 179, 180, 194, 214, 231, 232, 233, 237, 243, 248, 252, 255, 257, 267, 272, 296, 307, 311], "sphere_dict": 30, "combobox2d": [30, 47, 53, 109, 111, 115, 117, 120, 136, 240, 258, 272, 297, 303, 308, 313], "item": [30, 46, 47, 53, 59, 113, 264, 267, 272, 274, 276, 277, 294, 297], "combo": [30, 122, 136, 294], "slice_along_axi": [30, 275, 297], "yaxi": [30, 275], "xaxi": [30, 275], "change_spher": 30, "selected_text": [30, 47, 53, 294, 297], "update_spher": [30, 275, 297], "odf_slicer_3d": 30, "238": [30, 308], "sometim": [31, 136, 149, 174, 217, 219, 292], "about": [31, 35, 64, 72, 82, 84, 88, 94, 95, 97, 106, 109, 117, 120, 138, 142, 143, 149, 151, 155, 160, 166, 168, 170, 171, 174, 178, 181, 182, 185, 187, 195, 198, 200, 210, 222, 225, 226, 229, 231, 233, 236, 241, 243, 244, 245, 247, 249, 253, 256, 260, 262, 263, 266, 268, 269, 271, 272, 279, 281, 287, 292, 296, 307, 311, 313, 315], "special": [31, 37, 111, 119, 173, 174, 265, 268, 310, 311, 316], "effect": [31, 73, 74, 83, 103, 122, 132, 135, 152, 155, 170, 172, 174, 179, 253, 256, 259, 265, 268, 274, 291], "shader_apply_effect": [31, 297], "remove_observer_from_actor": [31, 297], "proce": [31, 94, 239, 266], "actor_no_depth_test": 31, "marker_opac": [31, 274], "actor_normal_blend": 31, "actor_add_blend": 31, "actor_sub_blend": 31, "actor_mul_blend": 31, "enter": [31, 181, 294, 315], "topic": [31, 108, 130, 160, 225, 271, 272], "pre": [31, 141, 176, 226, 266, 270, 294, 313], "built": [31, 94, 176, 180, 228], "gl_function": 31, "instanc": [31, 65, 94, 135, 143, 150, 155, 156, 174, 176, 204, 267, 272, 292, 294, 296], "context": [31, 143, 149, 174, 176, 231, 238, 244, 273, 292, 296], "gl_set_normal_blend": [31, 297], "composit": [31, 226, 256], "id_observ": [31, 291], "gl_reset_blend": [31, 297], "gl_disable_blend": [31, 297], "gl_disable_depth": [31, 297], "gl_enable_depth": [31, 297], "gl_set_additive_blend": [31, 297], "gl_set_subtractive_blend": [31, 297], "gl_set_multiplicative_blend": [31, 297], "no_depth_test": 31, "086": 31, "similar": [32, 46, 94, 110, 119, 120, 150, 179, 182, 184, 207, 217, 222, 226, 253, 263, 268, 274, 277, 315], "recurs": [32, 153], "sierpinski": 32, "tetrahedron": [32, 290, 307], "tetrix": 32, "menger": 32, "spong": 32, "moselei": 32, "snowflak": 32, "hardcod": 32, "repeat_primit": [32, 228, 274, 297, 313], "ground": 32, "rule": [32, 140, 141, 156, 181, 232, 312], "comput": [32, 37, 39, 72, 73, 75, 98, 109, 114, 135, 140, 143, 155, 174, 179, 180, 181, 186, 190, 227, 231, 233, 238, 270, 274, 284, 286, 295, 307], "depth": [32, 72, 172, 235, 274, 276, 296], "prevent": [32, 130, 149, 156, 265, 313], "infinit": [32, 172], "assum": [32, 143, 271, 274, 275, 281, 294], "smaller": [32, 75, 181, 194, 270, 271], "ideal": [32, 110, 147, 250, 253, 256, 259, 268], "alloc": [32, 235, 238, 241, 277], "upfront": 32, "achiev": [32, 59, 98, 116, 119, 121, 122, 128, 132, 135, 140, 143, 146, 149, 150, 174, 226, 267, 268], "binari": [32, 122, 185, 228, 274, 279, 283, 316], "tree": [32, 153, 172, 243, 255, 256], "ari": 32, "formula": [32, 118, 254, 270, 293], "found": [32, 35, 88, 94, 115, 117, 119, 120, 122, 125, 128, 130, 131, 134, 135, 136, 152, 168, 172, 173, 174, 175, 176, 181, 182, 188, 190, 191, 201, 203, 207, 219, 223, 226, 227, 228, 240, 245, 247, 251, 254, 256, 259, 260, 267, 268, 270, 272, 277, 278, 279, 281, 289, 293, 295, 296], "represent": [32, 40, 72, 75, 135, 142, 143, 148, 152, 154, 160, 169, 172, 173, 174, 228, 270, 274, 287, 312], "sub": [32, 66, 109, 111, 113, 115, 117, 119, 120, 122, 125, 128, 130, 131, 134, 135, 136, 150, 153, 168, 172, 173, 179, 181, 226, 227, 228, 268, 270, 272, 276, 294, 303], "child": [32, 63, 94, 153, 162, 172, 228, 240, 276, 282], "skip": [32, 277, 279, 280, 281], "frac": [32, 259, 268], "entri": [32, 277, 281], "leaf": 32, "exactli": [32, 72, 147, 179, 181, 235, 239, 247, 250, 259, 262, 270, 271], "overhead": 32, "classic": 32, "natur": [32, 33, 98, 153, 168, 255], "dimension": [32, 40, 173, 275, 313], "extens": [32, 105, 279, 283, 291, 294, 297, 306, 307], "At": [32, 94, 179, 183, 227, 228, 235, 240, 253, 272, 281], "offset": [32, 94, 117, 147, 153, 252, 255, 272, 277, 282, 284, 294, 295, 303, 313], "prim_tetrahedron": [32, 297, 313], "gen_cent": 32, "dist": [32, 72, 315], "idx": [32, 45, 81, 83, 84, 292], "halv": 32, "divis": [32, 198, 265, 268], "depend": [32, 33, 66, 69, 72, 73, 100, 105, 143, 149, 156, 162, 164, 168, 174, 181, 186, 195, 226, 227, 248, 252, 257, 267, 268, 270, 271, 274, 276, 287, 295, 301, 303, 304, 306], "pretti": [32, 181, 239, 253, 256, 268], "bounds_min": 32, "bounds_max": 32, "corner": [32, 144, 150, 153, 162, 172, 185, 207, 226, 240, 294, 295], "accord": [32, 37, 81, 83, 149, 171, 182, 183, 184, 186, 212, 227, 240, 249, 255, 274, 277, 284, 294, 295, 296, 311, 315], "consid": [32, 147, 181, 183, 199, 210, 249, 267, 270, 274, 275, 276, 277, 287, 293, 295], "side": [32, 75, 153, 162, 187, 227, 231, 259, 265, 274, 284, 290, 294, 296, 310], "prim_box": [32, 297], "think": [32, 72, 143, 153, 171, 181, 183, 212, 222, 231, 233, 259, 260], "quit": [32, 112, 117, 118, 120, 130, 135, 143, 148, 171, 176, 218, 261, 266, 270], "koch": 32, "showmgr": 32, "nice": [32, 185], "my": [32, 111, 113, 114, 115, 117, 119, 120, 122, 125, 128, 130, 131, 134, 135, 136, 137, 140, 143, 145, 146, 147, 148, 149, 151, 152, 153, 154, 155, 156, 157, 160, 161, 162, 163, 164, 165, 166, 168, 169, 170, 171, 172, 173, 174, 175, 176, 181, 182, 183, 184, 185, 188, 190, 194, 201, 207, 210, 219, 222, 226, 227, 228, 231, 232, 233, 234, 236, 237, 238, 239, 240, 241, 243, 244, 245, 246, 247, 248, 250, 251, 253, 255, 256, 257, 258, 259, 260, 261, 262, 263, 265, 266, 267, 268, 269, 270, 271, 272, 313], "machin": [32, 143, 181, 278, 305, 315], "lag": [32, 140, 199, 227], "bump": [32, 303, 307], "switch": [32, 35, 136, 141, 172, 181, 186, 226, 240, 282, 294], "radiobutton": [32, 50, 130, 297, 309], "shape_choos": 32, "pad": [32, 46, 50, 237, 274, 284, 294, 297], "checked_label": [32, 46, 50, 53, 294], "choose_shap": 32, "radio": [32, 41, 42, 90, 136, 294, 309, 312, 314], "basic": [32, 75, 110, 118, 125, 127, 131, 145, 147, 179, 180, 181, 183, 186, 227, 228, 233, 250, 251, 253, 265, 268, 290, 294, 307, 310], "movement": [32, 75, 201, 255, 268, 294], "littl": [32, 36, 143, 144, 211, 227, 259, 262, 315], "mode": [32, 36, 81, 82, 83, 84, 87, 115, 134, 183, 184, 194, 197, 198, 217, 226, 228, 249, 272, 276, 277, 279, 282, 287, 294, 296], "document": [32, 37, 98, 104, 105, 107, 108, 112, 117, 123, 130, 131, 133, 134, 135, 136, 137, 139, 141, 142, 143, 144, 145, 146, 151, 155, 161, 164, 167, 171, 174, 175, 177, 180, 181, 182, 185, 202, 223, 227, 230, 235, 242, 247, 259, 264, 267, 268, 272, 300, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 316], "193": [32, 307], "tend": [33, 247], "acceler": [33, 244, 311], "antiparallel": 33, "along": [33, 38, 75, 111, 115, 119, 147, 153, 162, 172, 179, 180, 183, 184, 185, 188, 192, 199, 210, 212, 216, 217, 219, 232, 236, 274, 275, 276, 281, 284, 293, 294, 312], "helic": [33, 160, 173, 287], "under": [33, 83, 97, 98, 106, 108, 109, 138, 141, 178, 181, 226, 227, 228, 229, 234, 257, 268, 270, 272, 277, 310, 313], "influenc": 33, "radius_particl": 33, "initial_veloc": 33, "09": [33, 136, 172, 173, 174, 226, 227, 228, 298, 308, 312], "acc": 33, "due": [33, 108, 109, 117, 130, 135, 150, 153, 155, 173, 174, 181, 188, 189, 198, 216, 217, 218, 246, 252, 259, 264, 272, 313], "color_arrow": 33, "color_particl": 33, "charge_actor": 33, "m1": 33, "m2": 33, "coor_1": 33, "coor_2": 33, "coor": 33, "cyan": 33, "There": [34, 68, 97, 113, 125, 130, 131, 132, 136, 143, 173, 179, 181, 194, 197, 222, 228, 245, 260, 263, 271, 272, 274, 277, 278, 307], "nine": 34, "diamond": 34, "pentagon": [34, 177, 274, 290, 312], "hexagon": [34, 130], "heptagon": 34, "cross": [34, 117, 296], "plu": [34, 287], "marker_symbol": 34, "h": [34, 149, 270, 274, 283, 287, 292], "s6": [34, 274], "choic": [34, 62, 77, 221, 259, 265, 274, 287, 294], "uniform": [34, 75, 77, 89, 118, 182, 190, 193, 206, 208, 214, 225, 253, 259, 266, 270], "nodes_actor": [34, 274], "edge_width": [34, 274], "edge_color": [34, 274], "valid": [34, 216, 264, 272, 276, 287, 294], "nodes_3d_actor": [34, 274], "ones_lik": 34, "137": [34, 307], "overview": [35, 122, 257], "complex": [35, 36, 65, 88, 117, 147, 181, 186, 199, 222, 231, 235, 264, 267, 270, 272], "shown": [35, 54, 55, 94, 118, 121, 126, 132, 137, 173, 186, 219, 226, 268, 269, 281, 287, 294], "citat": [35, 36, 303], "pjoin": [35, 36, 88], "cmap": [35, 36, 88, 277, 305], "fetch_viz_wiki_nw": [35, 36, 88, 297], "categories_fil": [35, 36, 88], "edges_fil": [35, 36, 88], "positions_fil": [35, 36, 88], "sort": [35, 36, 88, 150, 172, 180, 272, 276, 296], "wiki_nw": [35, 88], "paper": [35, 88, 151, 166, 167, 169, 171, 173, 266, 311], "arxiv": [35, 88], "org": [35, 62, 64, 74, 87, 88, 99, 100, 101, 102, 104, 105, 107, 109, 113, 115, 117, 119, 120, 122, 123, 125, 128, 130, 131, 133, 134, 139, 143, 146, 149, 167, 174, 177, 230, 277, 291, 292, 293], "0711": [35, 88], "3199": [35, 88], "loadtxt": [35, 36, 88], "categori": [35, 36, 73, 88, 103, 234], "attribut": [35, 36, 65, 75, 150, 156, 172, 193, 194, 227, 228, 236, 240, 276, 277, 288, 291, 296, 304, 307, 315], "category2index": [35, 36, 88], "enumer": [35, 36, 40, 45, 73, 81, 83, 84, 88], "uniqu": [35, 36, 88, 176, 177, 292, 312, 313], "index2categori": [35, 36, 88], "categorycolor": [35, 88], "distinguishable_colormap": [35, 36, 61, 88, 297], "nb_color": [35, 36, 61, 88, 277], "OF": [35, 316], "cours": [35, 74, 108, 174, 179, 180, 247], "edgesposit": [35, 88], "edgescolor": [35, 88], "averag": [35, 36, 88, 282], "lines_actor": [35, 36, 88], "creation": [35, 36, 75, 186, 192, 195, 226, 227, 233, 236, 262, 270, 272, 291, 313], "journal_network": 35, "improv": [35, 72, 98, 107, 108, 118, 123, 126, 128, 135, 136, 139, 140, 143, 145, 146, 148, 149, 152, 155, 158, 159, 164, 174, 175, 177, 180, 181, 195, 199, 206, 208, 211, 226, 227, 228, 230, 231, 233, 234, 236, 243, 246, 247, 249, 257, 261, 268, 270, 296, 305, 307, 308, 310, 312, 313, 315], "interactivi": 35, "809": [35, 303], "algorithm": [36, 75, 76, 110, 112, 114, 117, 119, 122, 127, 135, 148, 158, 166, 169, 171, 173, 174, 176, 179, 180, 236, 241, 270, 274, 277, 287, 307], "layout": [36, 41, 42, 90, 140, 141, 144, 146, 147, 156, 158, 162, 168, 170, 172, 174, 176, 177, 274, 297, 306, 307, 311, 312, 313, 314], "simpler": [36, 75, 81, 225, 235, 238, 306], "displac": [36, 119, 198, 228], "compute_bound": [36, 297], "heurist": 36, "vertices_count": 36, "networkx": 36, "nx": [36, 37], "view_siz": 36, "random_geometric_graph": 36, "arang": [36, 82, 84], "category_color": 36, "endpoint": 36, "edges_color": 36, "lod": [36, 40, 274], "new_layout_tim": 36, "edges_list": 36, "max_iter": 36, "vertex_initial_posit": 36, "500": [36, 37, 43, 51, 53, 54, 55, 82, 84, 89, 291, 312], "viscos": 36, "alpha": [36, 119, 142, 174, 270, 274, 281, 310], "0005": [36, 82, 84], "deltat": 36, "sphere_geometri": 36, "geometry_length": 36, "iterationcount": 36, "nonloc": 36, "repulst": 36, "vertex1": 36, "vertex2": 36, "x1": [36, 275], "y1": [36, 275], "z1": [36, 275], "x2": [36, 275], "y2": [36, 275], "z2": [36, 275], "rx": 36, "ry": 36, "rz": 36, "fx": 36, "fy": 36, "fz": 36, "attract": 36, "vfrom": 36, "vto": 36, "_timer": 36, "spheres_posit": 36, "edges_posit": 36, "bit": [36, 117, 131, 134, 153, 168, 169, 171, 180, 181, 188, 222, 227, 259, 266, 267, 268, 270, 272, 315], "farther": [36, 268], "max_iteract": 36, "multi_sampl": [36, 227, 276, 296, 313], "viz_animated_network": 36, "physic": [37, 70, 71, 74, 79, 80, 81, 82, 84, 94, 98, 109, 115, 117, 119, 120, 125, 130, 133, 136, 177, 179, 228, 286, 293, 303, 309, 310, 312, 314], "fetch_viz_cubemap": [37, 297], "read_viz_cubemap": [37, 297], "load_cubemap_textur": [37, 297], "normals_from_actor": [37, 73, 297], "tangents_from_direction_of_anisotropi": [37, 73, 297], "tangents_to_actor": [37, 73, 297], "change_slice_metal": 37, "pbr_param": 37, "metal": [37, 73, 74, 228, 286], "change_slice_rough": 37, "rough": [37, 73, 74, 171, 228, 286], "change_slice_anisotropi": 37, "change_slice_anisotropy_direction_x": 37, "doa": 37, "tangent": [37, 62, 73, 203, 209, 276, 295], "change_slice_anisotropy_direction_i": 37, "change_slice_anisotropy_direction_z": 37, "change_slice_anisotropy_rot": 37, "anisotropy_rot": [37, 73, 286], "change_slice_coat_strength": 37, "coat_strength": [37, 73, 286], "change_slice_coat_rough": 37, "coat_rough": [37, 73, 286], "change_slice_base_ior": 37, "base_ior": [37, 73, 286], "change_slice_coat_ior": 37, "coat_ior": [37, 73, 286], "least": [37, 62, 152, 175, 179, 180, 235, 245], "reposit": [37, 136, 188, 216, 226, 252, 259, 272, 313], "resiz": [37, 48, 111, 113, 115, 141, 144, 150, 153, 156, 159, 162, 172, 183, 226, 240, 243, 249, 252, 267, 272, 292, 294, 297, 311, 313], "control_panel": 37, "skybox": [37, 179, 279, 296, 297, 313], "repositori": [37, 113, 115, 117, 119, 120, 122, 125, 128, 130, 131, 134, 143, 174, 185, 189, 194, 197, 279, 287, 289], "cubemap": [37, 271], "12b1ce6c91aa3aaf258a8a5944df739a6c1cc76e89d4d7119d1f795a30fc1bf2": 37, "ny": [37, 279], "e18fe2206b63d3df2c879f5e0b9937a61d99734b6c43ac288226c58d2418d23": 37, "nz": 37, "00dddd1b715d5877af2a74c014ff6e47891f07435b471d213cd0673a8c47f2b2": 37, "px": [37, 279], "bf20acd6817c9e7073e485bbe2d2ce56dacff73c021c2b613ba072ba2df2b754": 37, "16f0d692af0b80e46929d8d8a7e596123c76729cc5eb7dfd1c9184b115dd143a": 37, "pz": 37, "b850b5e882889df26be9289d7c25ba30524b37e56bc2075b968a83197ad977f3": 37, "compos": [37, 54, 190, 199, 227, 268, 270, 287, 290, 294], "extract": [37, 142, 145, 156, 159, 185, 205, 228, 271, 276, 282, 292, 309, 311], "plausibl": [37, 73], "popul": [37, 244, 247, 294], "vtkrenderingopengl2": 37, "vtkopenglactor": 37, "0x2a1ad4b90": 37, "0x2a19ccb20": 37, "manifest_pbr": [37, 73, 297], "setup": [37, 82, 100, 156, 241, 244, 247, 252, 256, 259, 265, 268, 272, 301, 315], "1920": [37, 40], "1080": [37, 40], "easili": [37, 115, 135, 136, 143, 150, 153, 172, 174, 226, 227, 270], "And": [37, 65, 74, 124, 143, 179, 187, 193, 202, 206, 227, 244, 256, 268, 270, 276], "slider_label_metal": 37, "slider_label_rough": 37, "slider_label_anisotropi": 37, "slider_label_anisotropy_rot": 37, "slider_label_anisotropy_direction_x": 37, "slider_label_anisotropy_direction_i": 37, "slider_label_anisotropy_direction_z": 37, "slider_label_coat_strength": 37, "coat": [37, 73, 286, 312], "strength": [37, 73, 286], "slider_label_coat_rough": 37, "slider_label_base_ior": 37, "ior": [37, 73], "slider_label_coat_ior": 37, "slider_slice_metal": 37, "195": [37, 307, 310], "1f": [37, 53, 54, 56, 294], "slider_slice_rough": 37, "slider_slice_anisotropi": 37, "slider_slice_anisotropy_rot": 37, "slider_slice_coat_strength": 37, "slider_slice_coat_rough": 37, "cover": [37, 164, 188, 199, 212, 268], "slider_slice_anisotropy_direction_x": 37, "slider_slice_anisotropy_direction_i": 37, "slider_slice_anisotropy_direction_z": 37, "refract": [37, 73, 177, 286, 312], "slider_slice_base_ior": 37, "02f": [37, 73], "slider_slice_coat_ior": 37, "handler": [37, 279, 285, 291], "consequ": [37, 155, 174, 258, 259, 267], "captur": [37, 201, 226, 250, 253, 268], "window_callback": 37, "rectangl": [38, 51, 54, 172, 183, 219, 226, 249, 294, 297, 308], "cv2": 38, "videocaptur": 38, "wrap": [38, 72, 162, 165, 234, 261, 265, 294, 311], "opencv": [38, 221], "fp": [38, 72, 81, 82, 83, 84, 126, 179, 202, 227, 276, 313], "cap_prop_fp": 38, "frame": [38, 65, 72, 87, 94, 105, 118, 168, 231, 270, 274, 276, 292, 296, 306], "cap_prop_frame_count": 38, "yield": [38, 267, 277], "get_fram": 38, "isfram": 38, "dur": 38, "cvtcolor": 38, "color_bgr2rgb": 38, "releas": [38, 87, 126, 158, 195, 281, 292, 294, 296, 297], "videoplay": 38, "video_gener": 38, "current_video_fram": 38, "initialize_scen": 38, "show_manag": [38, 43, 44, 45, 46, 49, 50, 51, 52, 54, 55, 56, 59, 265], "1st": [38, 272], "plane_actor": 38, "isinst": 38, "texture_upd": [38, 297], "interv": [38, 94, 149, 243, 256, 292], "frame_dur": 38, "video_url": 38, "commondatastorag": 38, "googleapi": 38, "gtv": 38, "bucket": 38, "bigbuckbunni": 38, "mp4": [38, 221, 227, 276, 313], "vp": 38, "581": [38, 313], "probabilist": 39, "csa": 39, "corpu": 39, "callosum": 39, "seed": [39, 272], "default_spher": 39, "read_stanford_label": 39, "peaks_from_model": [39, 274], "csaodfmodel": 39, "local": [39, 89, 181, 207, 274, 289, 294, 310, 315], "localtrack": 39, "thresholdtissueclassifi": 39, "thresholdstoppingcriterion": 39, "except": [39, 64, 77, 119, 143, 213, 266, 281], "importerror": 39, "stopping_criterion": 39, "local_track": 39, "line_color": [39, 297], "complet": [39, 99, 100, 101, 102, 104, 105, 107, 109, 115, 118, 122, 123, 124, 126, 128, 130, 133, 139, 144, 150, 167, 177, 180, 184, 195, 204, 230, 234, 235, 237, 240, 243, 246, 249, 250, 252, 255, 257, 258, 259, 271, 274, 279, 315], "refer": [39, 60, 81, 82, 83, 84, 94, 148, 168, 172, 180, 184, 186, 188, 195, 210, 215, 226, 231, 266, 272, 275, 277, 287, 292, 294, 296, 311], "hardi_img": 39, "gtab": 39, "labels_img": 39, "white_matt": 39, "csa_model": 39, "sh_order": 39, "csa_peak": 39, "relative_peak_threshold": 39, "min_separation_angl": 39, "mask": [39, 274], "classifi": [39, 247], "gfa": [39, 271], "seed_mask": 39, "seeds_from_mask": 39, "densiti": [39, 231, 247, 259, 268, 270], "step_siz": 39, "streamlines_actor": 39, "r": [39, 97, 119, 150, 172, 174, 265, 270, 271, 274, 275, 277, 286, 287, 290, 293, 295, 296, 315], "decim": [39, 73, 74, 294], "surface_opac": 39, "surface_color": 39, "seedroi_actor": 39, "contour_from_roi": [39, 297], "pop": [39, 61, 63, 162], "contour_from_roi_tutori": 39, "689": [39, 224, 228, 313], "four": [40, 59], "unfold": 40, "eight": 40, "wirefram": [40, 72, 295], "p_color": 40, "e_color": 40, "dtheta": 40, "4d": [40, 274, 275, 295], "verts4d": 40, "verts3d": 40, "altern": [40, 110, 112, 114, 118, 135, 181, 248, 274, 281, 308], "rotate4d": 40, "xy": [40, 72, 77, 265, 274, 284, 293, 295], "zw": 40, "imaginari": [40, 277], "rotation4d_xi": 40, "rotation4d_zw": 40, "projected_marix": 40, "vert": [40, 290, 295], "rotated_3d": 40, "dot": [40, 67, 75, 197, 215, 278, 283, 295, 296, 297, 313], "proj_mat4d": 40, "projeced_mat3d": 40, "proj": 40, "connect_point": 40, "len_vert": 40, "point_vert": 40, "no_vertic": 40, "initial_vert": 40, "lines_vert": 40, "initial_lin": 40, "950": 40, "109": [40, 61, 86, 87, 306], "drawpanel": [41, 42, 90, 188, 216, 222, 226, 279, 297, 313, 314], "card": [41, 42, 90, 168, 170, 172, 272, 294, 314], "spinbox": [41, 42, 90, 249, 272, 297, 314], "listbox": [41, 42, 49, 54, 90, 294, 297, 306, 311, 314], "figur": [41, 42, 53, 90, 115, 119, 120, 122, 128, 130, 132, 141, 153, 157, 162, 179, 182, 191, 203, 205, 206, 213, 215, 218, 220, 235, 247, 250, 253, 259, 265, 266, 268, 271, 272, 278, 297, 314], "check": [41, 42, 52, 53, 90, 97, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 124, 125, 126, 127, 128, 129, 130, 131, 132, 134, 135, 136, 137, 145, 148, 149, 151, 154, 155, 156, 157, 160, 163, 166, 169, 171, 172, 173, 174, 179, 180, 181, 207, 210, 216, 219, 232, 236, 238, 239, 241, 242, 243, 250, 256, 264, 267, 268, 271, 274, 276, 279, 287, 292, 294, 295, 296, 298, 310, 313, 314, 315], "tab": [41, 42, 90, 115, 122, 133, 136, 181, 294, 297, 303, 309, 313, 314], "931": [42, 45], "07_ui": [42, 314], "viz_card_sprite_sheet": [42, 45, 314], "viz_button": [42, 43, 314], "viz_card": [42, 44, 314], "viz_check_box": [42, 46, 314], "viz_combobox": [42, 47, 314], "viz_drawpanel": [42, 48, 314], "viz_layout": [42, 49, 314], "viz_radio_button": [42, 50, 314], "viz_shap": [42, 51, 314], "viz_spinbox": [42, 52, 314], "viz_tab": [42, 53, 314], "viz_ui": [42, 54, 305, 307, 314], "viz_ui_listbox": [42, 55, 314], "viz_ui_slid": [42, 56, 314], "api": [43, 46, 50, 51, 52, 54, 55, 56, 94, 98, 115, 130, 133, 135, 136, 156, 159, 162, 174, 179, 180, 181, 185, 187, 189, 191, 208, 211, 227, 228, 231, 235, 250, 253, 259, 262, 265, 268, 269, 303, 304, 308, 309, 313], "icomoon": [43, 44, 46, 47, 50, 51, 52, 53, 54, 55, 56, 279], "38478": [43, 44, 46, 47, 50, 51, 52, 53, 54, 55, 56], "bc1feea6f58ba3601d6a0b029eb8dfc5f352e21f2a16ba41099a96aa3f5a4735": [43, 44, 46, 47, 50, 51, 52, 53, 54, 55, 56], "put": [43, 54, 72, 75, 233, 277, 313, 315], "integ": [43, 54, 198, 268, 274, 277, 287, 294], "me": [43, 54, 108, 109, 110, 115, 117, 119, 126, 127, 128, 131, 134, 137, 140, 141, 148, 149, 151, 157, 162, 171, 179, 180, 181, 182, 185, 188, 198, 207, 210, 235, 238, 240, 244, 245, 250, 253, 255, 256, 259, 262, 265, 266, 268, 269], "text2": [43, 54], "percentag": [43, 54, 276, 294], "button_exampl": [43, 54], "stop2": [43, 54], "icon_fil": [43, 54], "second_button_exampl": [43, 54], "change_text_callback": [43, 54], "force_rend": [43, 45, 54], "change_icon_callback": [43, 54], "next_icon": [43, 54, 294, 297], "on_left_mouse_button_press": [43, 54, 294, 297], "current_s": [43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 54, 55, 56, 76, 77], "071": [43, 53], "img_url": [44, 45], "commun": [44, 45, 98, 99, 100, 101, 102, 104, 105, 106, 107, 123, 133, 138, 139, 140, 141, 155, 167, 174, 175, 176, 177, 178, 179, 181, 229, 230, 250, 268, 270, 272, 313], "asset": [44, 45], "logo": [44, 45, 174, 313], "bodi": [44, 45, 63, 81, 82, 117, 172, 270, 294, 297], "free": [44, 45, 94, 98, 99, 100, 101, 102, 104, 105, 106, 107, 123, 133, 138, 139, 141, 143, 167, 174, 177, 178, 180, 181, 228, 229, 230, 316], "unifi": [44, 45, 98, 181, 272, 316], "softwar": [44, 45, 97, 98, 99, 100, 101, 102, 104, 105, 106, 107, 108, 109, 123, 133, 135, 136, 138, 139, 167, 172, 173, 177, 178, 179, 180, 181, 221, 223, 226, 227, 228, 229, 230, 268, 270, 272, 303, 311, 316], "librari": [44, 45, 74, 78, 87, 89, 90, 97, 98, 99, 100, 101, 102, 104, 105, 106, 107, 123, 133, 138, 139, 141, 142, 143, 155, 167, 168, 177, 178, 180, 181, 185, 229, 230, 231, 235, 272, 283, 307, 311, 312], "scientif": [44, 45, 98, 99, 100, 101, 102, 104, 105, 106, 107, 123, 133, 138, 139, 167, 173, 174, 177, 178, 182, 229, 230, 231, 252, 270, 272, 275, 287, 303, 313], "card2d": [44, 45, 144, 165, 168, 170, 172, 297, 303], "image_path": [44, 45, 294], "title_text": [44, 45, 294], "body_text": [44, 45, 294], "image_scal": [44, 45, 294], "bg_color": [44, 45, 294, 296, 297], "294": [44, 45, 136, 267, 272, 303], "bg_opac": [44, 45, 294], "border_width": [44, 45, 159, 294, 297], "border_color": [44, 45, 294, 297], "card_ui": [44, 45], "257": 44, "sprite": [45, 170, 172, 283, 303, 312], "sheet": [45, 170, 172, 173, 283, 287, 312], "load_sprite_sheet": [45, 297], "save_imag": [45, 297, 307], "tempfil": 45, "temporarydirectori": 45, "intemporarydirectori": 45, "target_fp": 45, "frame_tim": 45, "sprite_sheet": 45, "unittest": [45, 315], "fury_sprit": 45, "current_sprite_idx": 45, "vtk_sprite": 45, "delai": [45, 168, 268, 315], "_evt": 45, "set_img": [45, 294, 297], "getrenderwindow": [45, 247], "getinteractor": 45, "getinteractorstyl": 45, "vtkimagedata": [45, 172, 274, 283, 295, 312], "sprite_to_vtk": 45, "tdir": 45, "sprite_path": 45, "compression_qu": [45, 283], "as_vtktyp": [45, 283], "checkbox": [46, 125, 130, 136, 297, 307, 309, 312], "visibl": [46, 53, 56, 192, 222, 231, 238, 267, 272, 274, 275, 282, 294, 296, 313], "360": [46, 50, 52, 69, 294], "symmetr": [46, 274, 275, 313], "uncheck": [46, 53, 294], "sym_diff": [46, 53], "l1": [46, 53], "l2": [46, 53], "symmetric_differ": [46, 53], "set_figure_visibl": [46, 53], "figure_dict": [46, 53], "setvis": [46, 53, 54, 56, 274, 297], "invis": [46, 53], "update_color": 46, "color_arrai": [46, 295], "toggl": [46, 54, 184, 226, 227, 267, 294, 297], "toggle_color": [46, 50], "elif": [46, 53], "check_box": 46, "color_toggl": [46, 50], "viz_checkbox": 46, "vertical_justif": [47, 53, 237, 274, 294, 297], "top": [47, 53, 56, 63, 113, 135, 153, 168, 179, 185, 201, 264, 272, 274, 294, 295], "rock": [47, 53], "violet": [47, 53], "indigo": [47, 53], "compon": [47, 66, 72, 75, 109, 111, 113, 115, 120, 122, 128, 130, 131, 134, 136, 141, 190, 226, 227, 231, 234, 240, 249, 255, 261, 264, 267, 272, 282, 293, 294, 295, 303, 313], "color_combobox": [47, 53], "placehold": [47, 53, 150, 172, 289, 294], "chosen": [47, 74, 174, 180, 226, 268, 277], "change_color": [47, 53], "whenev": [47, 112, 181, 184, 186, 188, 192, 199, 204, 217, 219, 226, 256, 276], "combobox_ui": 47, "050": 47, "fetch_viz_new_icon": [48, 226, 297, 313], "new_icon": 48, "press": [48, 149, 174, 181, 195, 294, 296], "cd859f244df1ba719c65c869c3faf6b8563abf82f457730adbfbd7ca72ddb7bc": 48, "5896bdc9ff9b3d1054134d7d9a854677ce9fa4e64f494f156bb2e3f0e863f207": 48, "delet": [48, 155, 174, 183, 184, 226, 254, 279, 308, 315], "937c46c25bc38b62021b01c97a4ee3cde5f7c8c4a6d0db75bf4e4cace2af1226": 48, "476e00a0a5373e1ccda4af8e7c9158e0ac9b46b540ce410c6ea47d97f364a0cd": 48, "08a914c5dc7997cb944b8c5fbb958951f80b715cfe04ff4f47a73f9d08c4b14b": 48, "fb2210b0393eca8a5dd2b8f034dae386bbb47eb95bb1cac2a97de807ee195adf": 48, "8d1ac2bb7c5baa34e68578daad85f64ef824be7bcb828cac18e52833d4cbf4c9": 48, "e6d833b6d958129e12ff0f6087282ce92cd43c6dafce03f185746ecca89e42a9": 48, "polylin": [48, 186, 192, 195, 198, 204, 207, 219, 222, 226, 274], "cff12b8de48fc19da5d5f0ea7ff2d23dd942d05468e19522e7c7beb72f0ff66": 48, "7afe65ebae0c0d0556393b979148ae15fc3e037d126cd1da4a296f4e25f5b4aa": 48, "5fd43f1c2d37bf9af05d9fc591172684ac51ba236980cd1b0795b0225b9247e2": 48, "a2da0cb963401c174919e1d8028aa6f0cb260a736fd26421db5ab08e9f3c4fdf": 48, "ff49ddf9df24729f4f6345c30c88de0a11e5b12b2f2ff28375ef9762fe5f8995": 48, "a2d850cdba8f332da9cd7b7c9459cbda587c18af0d3c12ca68d6e6a864ef54bb": 48, "54618fdc4589f0a039d531c07a110ed9bc57a256bb15a3b5429cf60e950887c3": 48, "cd573f5e4bf4a91a3b21f6124a95ffb3c036f926f8fec1fd0180f5d27d8f48c0": 48, "drawing_canva": 48, "650": [48, 54, 313], "isn": [48, 117, 180, 192, 222, 250, 268], "canva": [48, 183, 184, 186, 188, 201, 227, 278, 294], "current_mod": [48, 294, 297], "draw_shap": [48, 294, 297], "shape_typ": [48, 294], "current_posit": [48, 294], "275": [48, 136, 309], "shape_list": 48, "063": 48, "gridlayout": [49, 141, 144, 150, 153, 156, 170, 172, 297, 313], "cell": [49, 274, 284, 295, 306], "arrang": [49, 141, 226, 274], "fashion": [49, 156, 172, 284, 286], "panel_1": 49, "panel_2": 49, "listbox_1": 49, "listbox2d": [49, 54, 55, 122, 128, 136, 243, 267, 272, 297, 307, 308, 313], "third": [49, 53, 113, 115, 135, 136, 143, 148, 149, 174, 221, 235, 259, 268, 271, 310], "listbox_2": 49, "rect_grid": 49, "position_offset": [49, 284], "square_grid": 49, "cell_shap": [49, 274, 284, 294], "diagonal_grid": 49, "diagon": [49, 270, 274, 284, 293], "ui_layout": 49, "059": 49, "121": [50, 307], "rect": [51, 54, 274, 284, 294], "rectangle2d": [51, 54, 115, 144, 147, 159, 172, 183, 212, 219, 226, 297], "solid": [51, 54, 75, 174, 268], "disk2d": [51, 54, 188, 198, 226, 297, 307], "outer_radiu": [51, 54, 294, 297], "inner": [51, 54, 274, 294], "inner_radiu": [51, 54, 294, 297], "068": 51, "min_val": [52, 294], "max_val": [52, 294], "initial_v": [52, 294], "hook": [52, 150, 199, 227, 313], "previou": [52, 75, 109, 120, 122, 136, 142, 147, 150, 155, 180, 181, 190, 193, 210, 227, 232, 243, 254, 258, 263, 264, 267, 276, 277, 282, 294], "decrement": [52, 294, 297], "previous_valu": [52, 53, 54, 56, 294, 297], "rotate_con": 52, "change_in_valu": 52, "083": 52, "tab_ui": 53, "tabui": [53, 125, 240, 272, 297, 313], "nb_tab": [53, 294], "draggabl": [53, 294], "content": [53, 153, 172, 249, 252, 272, 274, 284, 294, 295, 296], "ring_slid": [53, 54, 56], "ringslider2d": [53, 54, 56, 125, 195, 226, 255, 297], "horizont": [53, 54, 56, 136, 165, 168, 170, 172, 177, 274, 284, 294, 296, 312], "text_align": [53, 56, 294], "cube_x": [53, 54], "cube_i": [53, 54], "rotate_cub": [53, 54, 56], "previous_angl": [53, 54, 56], "rotation_angl": [53, 54, 56], "rotatex": [53, 54, 56], "translate_cube_x": [53, 54], "translate_cube_i": [53, 54], "on_collaps": 53, "task": [53, 72, 108, 109, 110, 112, 114, 116, 118, 119, 121, 124, 126, 129, 131, 132, 135, 136, 137, 141, 144, 147, 150, 152, 153, 155, 156, 159, 165, 168, 170, 172, 173, 174, 183, 191, 226, 234, 240, 243, 246, 253, 256, 258, 260, 262, 265, 267, 272], "collaps": [53, 125, 150, 153, 294, 313], "hide_actor": 53, "active_tab_idx": 53, "set_vis": [53, 54, 55, 56, 237, 240, 272, 294, 297, 303], "sm": 53, "viz": [53, 99, 181, 277, 299, 304, 307], "imagecontainer2d": [54, 297, 303, 311], "img_path": [54, 294], "home3": 54, "circular": [54, 56, 147, 149, 150, 153, 156, 162, 172, 292], "linear": [54, 56, 60, 61, 64, 67, 122, 190, 196, 206, 227, 235, 238, 259, 268, 270, 274, 276], "740": [54, 313], "similarli": [54, 56, 308], "translat": [54, 56, 60, 62, 66, 67, 75, 94, 136, 149, 182, 184, 186, 188, 203, 204, 205, 206, 213, 216, 217, 222, 226, 227, 228, 238, 247, 282, 297, 310], "range_slider_x": 54, "rangeslid": [54, 107, 297, 307], "line_width": [54, 294, 297], "handle_sid": [54, 294], "range_slider_cent": [54, 294, 297], "value_slider_cent": [54, 294, 297], "range_precis": [54, 294], "value_precis": [54, 294], "range_slider_i": 54, "fill": [54, 142, 145, 154, 171, 173, 227, 232, 272, 277, 287, 289, 311], "hide": [54, 55, 150, 221, 228, 276, 294, 296, 297, 304], "hide_all_exampl": [54, 55], "multiselect": [54, 55, 162, 294], "display_el": [54, 55], "090": 54, "welcome_text": 55, "welcom": [55, 98, 111, 113, 115, 117, 119, 120, 122, 125, 128, 130, 131, 134, 135, 136, 145, 148, 151, 154, 157, 160, 163, 166, 169, 171, 172, 173, 174, 231, 238, 244, 253, 315], "bye_text": 55, "bye": [55, 272], "fury_text": [55, 60], "listbox_exampl": 55, "viz_listbox": 55, "077": 55, "five": [56, 139, 181, 310], "bottom": [56, 144, 150, 153, 172, 185, 264, 272, 274, 294, 295], "630": [56, 197, 228, 313], "hor_line_slider_text_top": 56, "230": 56, "hor_line_slider_text_bottom": 56, "ver_line_slider_text_left": 56, "ver_line_slider_text_right": 56, "translate_cube_v": 56, "translate_cube_hor": 56, "viz_slid": 56, "079": 56, "keyfram": [57, 58, 90, 179, 185, 190, 193, 196, 200, 202, 203, 206, 208, 225, 227, 276, 313, 314], "introduct": [57, 58, 90, 180, 227, 314], "spline": [57, 58, 60, 64, 90, 187, 199, 209, 227, 274, 276, 314], "arm": [57, 58, 90, 211, 227, 314], "robot": [57, 58, 90, 94, 119, 211, 227, 314], "hierarch": [57, 58, 66, 90, 172, 208, 214, 220, 227, 228, 276, 313, 314], "bezier": [57, 58, 90, 227, 276, 314], "custom": [57, 58, 69, 77, 84, 90, 135, 150, 162, 168, 170, 179, 199, 200, 202, 209, 215, 227, 235, 250, 256, 258, 261, 274, 276, 280, 291, 294, 295, 296, 313, 314], "10_anim": [58, 314], "viz_camera": [58, 60, 314], "585": [58, 60, 313], "viz_custom_interpol": [58, 62, 314], "viz_bezier_interpol": [58, 59, 314], "viz_color_interpol": [58, 61, 314], "viz_hierarchical_anim": [58, 63, 314], "viz_interpol": [58, 64, 65, 314], "viz_introduct": [58, 65, 314], "viz_robot_arm_anim": [58, 66, 314], "viz_spline_interpol": [58, 67, 314], "viz_timelin": [58, 68, 314], "viz_using_time_equ": [58, 69, 314], "cubic_bezier_interpol": [59, 297], "wide": [59, 109, 274, 284], "quaternion": [59, 64, 81, 83, 94, 120, 190, 193, 202, 227, 276, 293], "destin": [59, 231], "departur": 59, "cp": 59, "keyframe_1": 59, "out_cp": [59, 276], "keyframe_2": 59, "in_cp": [59, 276], "pts_actor": 59, "cps_actor": 59, "cline_actor": 59, "add_actor": [59, 60, 61, 62, 64, 65, 67, 68, 69, 276, 297], "consist": [59, 64, 65, 84, 195, 201, 221, 226, 233, 251, 254, 271, 272, 277, 294], "depart": 59, "set_posit": [59, 60, 62, 63, 64, 65, 66, 68, 276, 294, 297], "set_position_interpol": [59, 60, 62, 64, 67, 69, 276, 297], "add_anim": [59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 276, 296, 297], "viz_keyframe_animation_bezier_1": 59, "set_position_keyfram": [59, 60, 67, 68, 276, 297], "in_control_point": 59, "out_control_point": 59, "vis_point": 59, "vis_cp": 59, "playback": [59, 60, 67, 68, 182, 190, 196, 223, 227, 276, 294], "playback_panel": [59, 60, 61, 66, 67, 68, 193, 276, 297], "viz_keyframe_animation_bezier_2": 59, "212": [59, 307], "explain": [60, 61, 65, 98, 136, 137, 140, 141, 166, 181, 196, 202, 211, 214, 225, 227, 231, 235, 248, 254, 265, 268, 270, 281, 315], "cameraanim": [60, 297], "cubic_spline_interpol": [60, 64, 297], "But": [60, 115, 146, 149, 153, 155, 174, 176, 179, 181, 186, 189, 198, 206, 214, 215, 227, 238, 247, 268, 295], "why": [60, 64, 72, 113, 149, 150, 181, 183, 198, 227, 235, 238, 244, 248, 259, 268, 271], "ask": [60, 149, 180, 181, 182, 183, 219, 254, 268], "detect": [60, 94, 117, 136, 148, 173, 256], "text_anim": 60, "set_opac": [60, 275, 276, 297], "set_scal": [60, 276, 297], "cubic": [60, 64, 84, 187, 209, 227, 274, 276], "done": [60, 63, 64, 68, 69, 94, 109, 113, 115, 120, 121, 122, 124, 134, 135, 136, 147, 149, 150, 153, 159, 162, 169, 171, 172, 173, 174, 202, 203, 207, 216, 219, 221, 227, 235, 250, 256, 258, 259, 262, 265, 266, 268, 269, 270, 271, 296, 303, 313, 315], "camera_anim": 60, "camera_posit": 60, "camera_focal_posit": 60, "set_camera_foc": 60, "set_camera_focal_keyfram": 60, "set_focal_keyfram": [60, 276, 297], "set_focal_interpol": [60, 276, 297], "animat": 60, "viz_keyframe_animation_camera": 60, "hsv_color_interpol": [61, 297], "lab_color_interpol": [61, 297], "step_interpol": [61, 297], "xyz_color_interpol": [61, 297], "cubes_po": 61, "static": [61, 66, 141, 168, 172, 199, 255, 256, 258, 260, 272, 276, 294, 313], "linear_text": 61, "lab_text": 61, "lab": [61, 181, 187, 193, 227, 276, 277], "hsv_text": 61, "xyz_text": 61, "step_text": 61, "list_of_actor": 61, "anim_linear_color": 61, "anim_lab_color": 61, "anim_hsv_color": 61, "anim_xyz_color": 61, "anim_step_color": 61, "distinguish": [61, 190, 277, 293], "set_color": [61, 276, 297], "set_color_interpol": [61, 69, 276, 297], "viz_keyframe_animation_color": 61, "argument": [62, 69, 89, 94, 115, 116, 136, 225, 276, 281, 290, 293, 294, 310, 313], "khrono": [62, 180, 185, 189, 197, 231, 279, 291], "gltftutori": 62, "gltftutorial_007_anim": 62, "html": [62, 87, 97, 143, 149, 181, 291, 293, 315], "cubicsplin": [62, 203], "previouspoint": 62, "previoustang": 62, "nextpoint": 62, "nexttang": 62, "interpolationvalu": 62, "t2": 62, "t3": 62, "tan_cubic_spline_interpol": [62, 297], "interpolated_valu": 62, "ok": [62, 155, 250], "spline_interpol": [62, 67, 297], "closur": [62, 199, 227], "get_timestamps_from_keyfram": [62, 297], "in_tang": [62, 276], "out_tang": [62, 276], "incomplet": [62, 120, 130, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313], "behaviour": [62, 278], "deal": [62, 143, 149, 155, 226, 238, 250, 256, 259, 265, 266, 267, 268], "miss": [62, 135, 182, 212, 213, 243, 244, 265, 266, 268, 303, 304, 307, 311, 312, 313], "zeros_lik": 62, "get_previous_timestamp": [62, 297], "get_next_timestamp": [62, 297], "surround": [62, 147], "t0": [62, 276], "get_time_tau": [62, 297], "time_delta": 62, "setter": [62, 144, 261, 264, 272, 303], "custom_field": 62, "p0": 62, "tan_0": 62, "p1": 62, "tan_1": 62, "3051798": 62, "640117": 62, "motion_path_r": [62, 69, 276, 297], "keyframe_data": 62, "in_tan": 62, "out_tan": 62, "viz_keyframe_custom_interpol": 62, "road": [63, 244, 268], "construct": [63, 143, 145, 174, 210, 227, 272, 275, 277, 292, 295], "car": 63, "body_actor": 63, "car_anim": 63, "wheel_cent": 63, "wheel_direct": 63, "wheel_posit": 63, "cylind": [63, 66, 70, 71, 82, 84, 90, 94, 95, 125, 131, 139, 290, 297, 310, 313, 314], "cap": [63, 75, 82, 84, 94, 268, 274, 276, 290], "wheels_anim": 63, "wheel_anim": 63, "set_rot": [63, 64, 276, 297], "radar": 63, "shaft": [63, 66, 274, 290], "radar_shaft": 63, "radar_shaft_anim": 63, "radar_anim": 63, "add_child_anim": [63, 66, 276, 297], "relat": [63, 109, 115, 130, 146, 149, 150, 152, 153, 155, 156, 159, 169, 174, 181, 185, 206, 231, 234, 235, 236, 237, 242, 249, 254, 256, 258, 259, 260, 263, 265, 267, 268, 269, 270, 271, 272, 277, 291, 294, 296, 311], "attach": [63, 68, 94, 131, 193, 235, 238, 244, 247], "matter": [63, 270, 272, 277], "viz_keyframe_hierarchical_anim": 63, "102": [63, 306], "minim": [64, 196], "respons": [64, 68, 81, 83, 128, 130, 141, 149, 155, 174, 196, 227, 244, 268, 272, 276, 292, 296], "interpolation_funct": 64, "feed": [64, 181], "44434": 64, "ve": [64, 69, 140, 143, 146, 149, 152, 155, 161, 164, 169, 174, 175, 176, 179, 200, 233, 272], "set_": [64, 68], "_interpol": 64, "slerp": [64, 190, 193, 203, 206, 225, 227, 297], "reed": 64, "en": [64, 74, 174, 293], "wikipedia": [64, 74, 247, 256, 268, 293], "wiki": [64, 74, 106, 138, 178, 180, 229, 231, 279, 291, 293, 313], "viz_keyframe_interpol": 64, "101": [64, 306], "care": [65, 143, 237, 272], "simpli": [65, 94, 120, 156, 238, 268, 270], "anyth": [65, 95, 179, 226, 227, 236, 242, 247, 277, 287, 315], "temperatur": [65, 276], "simplifi": [65, 89, 146, 225, 239, 261, 313], "encod": [65, 87, 89, 228, 269, 270, 271, 279, 281, 285, 291, 292, 293], "almost": [65, 124, 147, 150, 159, 162, 170, 179, 180, 185, 202, 208, 258, 260, 268, 270, 276], "quick": [65, 162, 172, 192, 204, 209, 218], "viz_keyframe_animation_introduct": 65, "set_actor_origin": [66, 297], "main_arm": 66, "sub_arm": 66, "joint_1": 66, "joint_2": 66, "main_arm_anim": 66, "child_arm_anim": 66, "drill_anim": 66, "joint": [66, 82, 84, 130, 136, 215, 270, 282], "rot_main_arm": 66, "rot_sub_arm": 66, "rot_dril": 66, "drill": 66, "evalu": [66, 69, 72, 119, 128, 131, 135, 136, 172, 173, 174, 199, 243, 276, 280, 292, 295, 310], "set_rotation_interpol": [66, 69, 276, 297], "is_evalu": [66, 69, 276], "observ": [66, 69, 94, 134, 135, 172, 272, 277, 285, 291, 295], "parent": [66, 94, 153, 156, 180, 190, 193, 220, 226, 228, 234, 276, 282], "viz_robot_arm": 66, "107": [66, 306], "position_keyfram": 67, "pos_dot": 67, "sphere_linear": 67, "linear_anim": 67, "linear_interpol": [67, 297], "larger": [67, 255, 264, 272, 296], "sphere_splin": 67, "spline_anim": 67, "5th": [67, 82, 84, 117, 270, 275], "reflect": [67, 74, 129, 177, 185, 276, 286, 312], "viz_keyframe_animation_splin": 67, "216": [67, 71, 77, 308], "hi": [68, 134, 140, 141, 142, 143, 155, 180], "learn": [68, 112, 143, 169, 171, 179, 180, 181, 184, 210, 231, 233, 250, 256, 259, 265, 268, 277], "stop": [68, 87, 88, 89, 97, 173, 227, 235, 238, 276, 292, 294, 297], "playbackpanel": [68, 190, 193, 199, 221, 227, 297, 313], "accordingli": [68, 94, 150, 172, 183, 234, 257, 294], "support": [68, 77, 81, 83, 95, 97, 99, 100, 101, 102, 104, 105, 107, 112, 113, 114, 116, 118, 121, 123, 124, 126, 133, 134, 135, 136, 137, 139, 144, 147, 150, 156, 158, 160, 162, 165, 167, 170, 172, 174, 177, 182, 189, 191, 193, 194, 197, 203, 204, 205, 209, 214, 224, 226, 227, 228, 230, 268, 270, 274, 275, 277, 283, 291, 294, 296, 304, 307, 310, 311, 312, 313, 315], "_keyfram": 68, "That": [68, 149, 179, 181, 221, 239, 244, 247, 250, 259, 263, 268, 271], "earlier": [68, 150, 153, 160, 219, 222, 238, 281], "viz_keyframe_animation_timelin": 68, "pos_ev": 69, "color_ev": 69, "rotation_ev": 69, "scale_ev": 69, "extra": [69, 94, 142, 166, 181, 204, 249, 296], "doe": [69, 136, 149, 150, 156, 182, 190, 194, 206, 213, 215, 221, 222, 235, 236, 268, 270, 271, 276, 277, 279, 287, 307, 309, 312], "set_interpol": [69, 276, 297], "viz_keyframe_animation_evalu": 69, "intern": [70, 90, 130, 170, 181, 192, 213, 221, 226, 270, 275], "convent": [70, 90, 94, 135, 256, 287, 293], "principl": [70, 71, 90, 98, 149, 177, 226, 286, 312, 313, 314], "brdf": [70, 71, 90, 98, 177, 312, 314], "vari": [70, 71, 90, 201, 252, 257, 310, 314], "impostor": [70, 71, 90, 146, 174, 202, 314], "billboard": [70, 71, 90, 107, 175, 196, 206, 208, 221, 223, 225, 227, 238, 247, 250, 253, 265, 268, 270, 297, 307, 310, 313, 314], "540": [71, 240, 243], "13_shader": [71, 314], "viz_principled_spher": [71, 74, 314], "608": [71, 74, 313], "viz_billboard_sdf_spher": [71, 72, 314], "333": [71, 72, 310], "viz_shad": [71, 77, 314], "viz_sdf_cylind": [71, 75, 314], "208": [71, 75, 309], "viz_pbr_spher": [71, 73, 314], "viz_sdfactor": [71, 76, 314], "engin": [72, 73, 78, 90, 98, 109, 115, 117, 125, 133, 136, 144, 179, 180, 181, 182, 270, 296, 309, 310], "quadrilater": [72, 270], "come": [72, 143, 179, 235, 238, 244, 259, 294], "cost": [72, 235, 259, 268, 274], "decreas": [72, 185, 295, 296, 309], "real": [72, 89, 121, 150, 172, 174, 179, 181, 187, 202, 231, 259, 263, 268, 270, 277, 297], "most": [72, 108, 114, 122, 131, 156, 157, 174, 181, 183, 198, 207, 216, 226, 228, 233, 236, 251, 254, 260, 262, 266, 298], "becam": [72, 186, 281], "popular": [72, 277], "game": [72, 98, 180, 182], "quota": 72, "sign": [72, 75, 76, 98, 123, 174, 175, 230, 270, 308, 313], "mathemat": [72, 75, 118, 270], "boundari": [72, 75, 184, 186, 226, 234, 237, 264, 272, 294], "outsid": [72, 156, 312], "neg": [72, 284, 296], "hart1996": [72, 75], "word": [72, 117, 119], "either": [72, 94, 98, 111, 150, 156, 170, 221, 226, 228, 231, 259, 267, 270, 279, 287], "definit": [72, 80, 82, 84, 94, 111, 236, 239, 242, 245, 254, 266, 268, 270, 271], "exemplifi": 72, "suitabl": [72, 174, 214, 266, 272], "compose_shad": [72, 75, 297], "import_fury_shad": [72, 75, 297], "represent_actor_as_wirefram": [72, 297], "glyph": [72, 105, 170, 233, 254, 257, 260, 266, 270, 271, 274, 290, 295, 305, 306, 313], "spheres_actor": 72, "recent": [72, 143, 166, 169, 261, 267, 298], "viz_regular_spher": 72, "explor": [72, 129, 135, 152, 243, 246, 249, 254, 266, 270, 271, 272], "understand": [72, 74, 108, 110, 112, 116, 117, 118, 120, 121, 128, 135, 142, 145, 147, 148, 151, 153, 171, 173, 180, 181, 185, 226, 231, 234, 239, 244, 247, 250, 257, 262, 263, 266, 268, 271], "interconnect": 72, "viz_low_res_wirefram": 72, "clean": [72, 75, 97, 124, 162, 218, 224, 250, 256, 259, 262, 315], "viz_hi_res_wirefram": 72, "evid": 72, "directli": [72, 128, 170, 172, 179, 199, 206, 208, 219, 223, 227, 228, 231, 253, 256, 266, 270, 272, 275, 276, 278, 313], "impact": [72, 249], "luckili": 72, "deliv": 72, "known": [72, 173, 181, 226, 233, 268], "suit": [72, 181, 267, 312], "instruct": [72, 182, 235, 256, 268, 305, 308, 313], "billboards_actor": 72, "viz_billboards_wirefram": 72, "know": [72, 94, 98, 141, 143, 180, 181, 182, 184, 228, 231, 233, 239, 256, 266, 268], "sd_sphere": 72, "frag": [72, 75], "sphere_radiu": 72, "const": 72, "sphere_dist": 72, "sdsphere": [72, 270], "sdf_eval": 72, "fragoutput0": [72, 75, 77, 271], "vec4": [72, 75, 77, 268, 282], "discard": [72, 75, 216, 315], "declar": [72, 235, 238, 256, 268, 274, 291], "fs_dec": [72, 75, 274], "fs_impl": [72, 274], "viz_billboards_circl": 72, "even": [72, 134, 135, 149, 155, 156, 159, 179, 205, 227, 239, 256, 257, 259, 261, 265, 268, 270, 271, 276, 315, 316], "essenti": [72, 145, 174, 228, 238, 244, 264, 272, 279, 287, 294], "gradient": 72, "deriv": [72, 265, 270, 275, 293, 316], "central_diffs_norm": [72, 75], "central_diff": [72, 75], "sd_sphere_norm": 72, "vec3": [72, 75, 77, 271, 282], "blinn": [72, 75, 179, 270], "phong": [72, 75, 179, 270, 286], "illumin": [72, 75, 270, 277], "blinn_phong_model": [72, 75], "fragment": [72, 75, 77, 135, 227, 250, 253, 259, 265, 266, 268, 270, 274, 286, 291], "smoothstep": 72, "antialias": [72, 75, 297], "absolut": [72, 153, 172, 294], "compens": [72, 270], "abs_dist": 72, "absdist": 72, "centraldiffsnorm": [72, 75], "0001": [72, 75], "attenu": 72, "factor": [72, 227, 250, 270, 274, 275, 284, 287, 294, 296, 313], "light_attenu": 72, "lightattenu": [72, 75], "blinnphongillummodel": [72, 75], "lightcolor0": [72, 75, 206, 211, 214], "diffusecolor": [72, 75], "specularpow": [72, 75], "specularcolor": [72, 75], "ambientcolor": [72, 75], "frag_output": 72, "recreat": 72, "viz_billboards_spher": 72, "hart": [72, 75], "john": [72, 75], "trace": [72, 75, 97, 98, 207], "rai": [72, 75, 98, 108, 110, 112, 114, 135, 270], "implicit": [72, 75, 235], "1996": [72, 75], "527": [72, 75, 312], "545": [72, 75, 313], "aim": [73, 98, 143, 144, 147, 156, 237, 241, 243], "graphic": [73, 98, 136, 174, 179, 180, 231, 233, 238, 241, 268, 270, 275], "conduct": [73, 140, 141, 303], "dielectr": [73, 286], "illustr": [73, 251, 277], "showcas": [73, 74, 97, 117, 122, 125, 126, 135, 169, 262], "subset": [73, 187, 190], "constrain": [73, 270, 272], "material_param": [73, 74], "produc": [73, 74, 149, 176, 270, 279, 287], "num_valu": 73, "mp": 73, "param": [73, 284], "interpret": [73, 74, 134, 155, 174, 277], "guid": [73, 74, 255], "l": [73, 263, 270, 274, 275, 287, 295, 296], "affect": [73, 202, 216, 252, 258, 271, 272], "num": 73, "ior_param": 73, "iorp": 73, "bidirect": [74, 177, 312], "bidirectional_reflectance_distribution_funct": 74, "introduc": [74, 180, 237, 243, 249, 261, 264, 272, 291], "brent": 74, "burlei": 74, "siggraph": [74, 174], "2012": 74, "blog": [74, 114, 123, 130, 131, 135, 136, 147, 148, 150, 153, 164, 165, 166, 171, 172, 173, 174, 181, 213, 227, 308, 309, 310, 311, 312, 313, 315], "selfshadow": 74, "public": [74, 179, 315], "s2012": 74, "strictli": [74, 171], "merl": 74, "www": [74, 149, 174, 277, 278, 293], "exchang": [74, 232], "research": [74, 98, 117, 151, 152, 166, 168, 169, 180, 186, 244], "databas": 74, "moreov": [74, 135, 277], "carefulli": [74, 249], "blend": [74, 250, 253, 268, 296], "layer": [74, 110, 286], "give": [74, 97, 143, 155, 158, 174, 176, 181, 207, 212, 219, 227, 228, 247, 251, 256, 269, 270, 271, 275, 277, 281, 293, 296, 307], "intuit": 74, "usabl": [74, 235], "subsurfac": [74, 286], "specular": [74, 206, 286], "specular_tint": [74, 286], "anisotrop": [74, 177, 286, 312], "sheen": [74, 286], "sheen_tint": [74, 286], "clearcoat": [74, 286], "clearcoat_gloss": [74, 286], "manifest_principl": [74, 297], "tint": [74, 286], "gloss": [74, 286], "henc": [75, 94, 117, 120, 130, 136, 199, 276], "attribute_to_actor": [75, 297], "shader_to_actor": [75, 77, 212, 297], "cylinders_8": 75, "cylinders_16": 75, "cylinders_32": 75, "viz_poly_cylind": 75, "setrepresentationtowirefram": 75, "viz_poly_cylinder_geom": 75, "march": [75, 108, 110, 112, 114, 135, 270], "intersect": 75, "link": [75, 84, 94, 135, 136, 147, 151, 155, 172, 173, 174, 189, 226, 227, 228, 252, 270, 272, 291, 293, 303, 304, 305, 313], "rep_direct": 75, "rep_cent": 75, "rep_radii": 75, "rep_height": 75, "vs_dec": [75, 274], "vertexmcvsoutput": 75, "centermcvsoutput": [75, 270], "directionvsoutput": 75, "heightvsoutput": 75, "radiusvsoutput": 75, "vs_impl": [75, 274], "vertexmc": [75, 77], "templat": [75, 164, 257, 291, 294, 305], "decl_cod": [75, 77, 291], "impl_cod": [75, 77, 291], "occupi": [75, 136, 162, 272, 277], "fs_vars_dec": 75, "mat4": 75, "mcvcmatrix": 75, "vec_to_vec_rot_mat": 75, "glsl": [75, 112, 118, 179, 187, 190, 206, 227, 291], "sd_cylind": 75, "sdf_map": 75, "sdcylind": 75, "rot": 75, "vec2vecrotmat": [75, 271], "cast_rai": 75, "ray_march": 75, "piec": [75, 155, 262, 268], "sdf_cylinder_frag_impl": 75, "ro": 75, "rd": 75, "ld": 75, "castrai": 75, "shortest": 76, "rate": [76, 105, 118, 168, 270, 274, 306], "compar": [76, 122, 149, 179, 181, 236, 248, 279, 281], "tradit": [76, 126, 270], "sdfactor": 76, "toru": [76, 112, 126, 135, 274], "capsul": [76, 310], "074": 76, "add_shader_callback": [77, 297], "utah": [77, 219], "teapot": 77, "fib": [77, 95, 283], "ply": [77, 95, 283], "stl": [77, 95, 283], "xml": [77, 95, 283], "get_polymapper_from_polydata": [77, 95, 297], "get_actor_from_polymapp": [77, 95, 297], "mapper": [77, 151], "getmapp": [77, 291], "vtkshader": 77, "vertex_shader_code_decl": 77, "myvertexvc": 77, "vertex_shader_code_impl": 77, "fragment_shader_code_decl": 77, "fragment_shader_code_impl": 77, "vec2": [77, 265, 268, 282], "iresolut": 77, "uv": [77, 228], "xyx": 77, "pot": 77, "shader_callback": [77, 311], "_caller": [77, 291], "calldata": [77, 291], "setuniformf": 77, "valueerror": 77, "textblock": [77, 81, 82, 83, 160, 261, 264, 294], "hello": [77, 95, 109, 111, 113, 115, 117, 119, 120, 122, 125, 128, 130, 131, 134, 180, 181, 231, 232, 233, 238, 241, 247, 250, 253, 256, 259, 262, 265, 269, 274, 296], "ball": [78, 79, 81, 90, 119, 130, 136, 142, 148, 154, 173, 287, 310, 314], "domino": [78, 79, 90, 310, 314], "chain": [78, 79, 90, 131, 136, 226, 287, 314], "brick": [78, 79, 84, 90, 119, 122, 125, 128, 131, 136, 314], "wreck": [78, 79, 90, 119, 130, 136, 310, 314], "656": 313, "17_pybullet": [79, 314], "viz_chain": [79, 82, 314], "372": 310, "viz_brick_wal": [79, 81, 314], "258": [81, 308], "viz_wrecking_bal": [79, 84, 314], "026": [], "viz_ball_collid": [79, 80, 314], "viz_domino": [79, 83, 314], "pybullet": [80, 81, 82, 83, 84, 115, 117, 119, 125, 128, 130, 136, 309, 310], "confirm": [80, 131], "client": [80, 81, 83, 87, 88, 94, 143, 149, 174, 297], "red_radiu": 80, "blue_radiu": 80, "red_ball_actor": 80, "red_ball_col": 80, "createcollisionshap": [80, 81, 82, 83, 84, 94], "geom_spher": [80, 81, 84, 94], "red_bal": 80, "createmultibodi": [80, 81, 82, 83, 84, 94], "basemass": [80, 81, 83, 84, 94], "basecollisionshapeindex": [80, 81, 83, 84, 94], "baseposit": [80, 81, 82, 83, 84, 94], "baseorient": [80, 81, 82, 83, 84, 94], "blue_ball_actor": 80, "blue_ball_col": 80, "blue_bal": 80, "restitut": [80, 81, 83, 84, 94], "changedynam": [80, 81, 83, 84, 94], "sync": [80, 82, 84, 115, 117, 128, 243], "sync_actor": [80, 81, 82], "multibodi": [80, 81, 82, 83, 84, 94, 128], "orn": [80, 81, 82, 83, 84, 94, 128], "getbasepositionandorient": [80, 81, 82, 83, 84, 94, 128], "orn_deg": [80, 81, 82, 94], "geteulerfromquaternion": [80, 81, 82, 94], "setorient": [80, 81, 82, 94], "apply_forc": [80, 81, 83, 84, 94], "red_po": 80, "red_orn": 80, "blue_po": 80, "blue_orn": 80, "applyexternalforc": [80, 81, 83, 84, 94], "forceobj": [80, 81, 83, 84, 94], "40000": 80, "posobj": [80, 81, 83, 84, 94], "flag": [80, 81, 83, 84, 87, 94, 144, 159, 162, 172, 212, 258, 277, 294, 297, 312, 313, 315], "world_fram": [80, 81, 83, 84, 94], "getcontactpoint": 80, "contact": 80, "stepsimul": [80, 81, 82, 83, 84, 94], "558": 80, "beign": 81, "thrown": [81, 117, 226, 313], "gui": [81, 83, 94, 141, 144, 147, 150, 153, 156, 159, 162, 165, 168, 170, 181, 276], "si": [81, 94], "unit": [81, 94, 98, 142, 145, 199, 202, 223, 227, 243, 277, 290, 295, 305, 310], "setgrav": [81, 82, 83, 84, 94], "easier": [81, 83, 98, 119, 134, 149, 153, 172, 176, 202, 227, 235, 238, 261, 264, 277, 315], "tweak": [81, 83, 122, 144, 148, 153, 172, 237, 255, 256, 258, 265, 272], "ball_radiu": [81, 84], "ball_color": [81, 84], "ball_mass": [81, 84], "ball_posit": 81, "ball_orient": 81, "base_s": [81, 83], "base_color": [81, 83], "base_posit": [81, 83], "base_orient": [81, 83], "wall_height": [81, 84], "wall_width": 81, "brick_mass": 81, "brick_siz": [81, 84, 94], "ball_actor": [81, 84, 94], "ball_col": [81, 94], "multi": [81, 82, 94, 203, 224, 228, 270, 294], "friction": [81, 82, 84, 94, 130], "lateralfrict": [81, 83, 84, 94], "base_actor": [81, 82, 83, 84], "base_col": [81, 83, 84], "geom_box": [81, 82, 83, 84], "halfext": [81, 82, 83, 84], "half": [81, 83, 179, 181], "actual": [81, 83, 115, 141, 144, 147, 159, 181, 195, 201, 213, 216, 252, 268, 276, 277, 278], "nb_brick": [81, 84, 94], "brick_cent": [81, 84, 94, 128], "brick_direct": [81, 84, 94], "brick_orn": [81, 84, 94, 128], "brick_color": [81, 84, 94], "brick_col": [81, 84, 94], "int8": [81, 83], "logic": [81, 84, 112, 150], "center_po": [81, 83, 84, 94], "brick_actor": [81, 84], "base_po": [81, 83, 84], "ball_po": [81, 94], "major": [81, 83, 99, 100, 101, 102, 104, 105, 107, 110, 113, 117, 119, 120, 122, 123, 124, 125, 128, 130, 131, 133, 134, 139, 142, 145, 162, 167, 177, 230, 243, 246, 251, 261, 264, 268, 277, 281, 295], "accur": [81, 83, 118, 227, 272, 303, 313], "3x3": [81, 83, 94, 236, 256, 257], "sync_brick": [81, 84, 94, 128], "rot_mat": [81, 82, 83, 84, 94, 128], "getmatrixfromquaternion": [81, 82, 83, 84, 94, 128], "getdifferencequaternion": [81, 82, 83, 84, 94, 128], "inaccur": 81, "approach": [81, 114, 121, 132, 135, 143, 150, 158, 174, 183, 186, 198, 204, 207, 208, 212, 221, 222, 227, 243, 250, 253, 259, 260, 267, 268, 270, 272, 292], "avg": [81, 82, 83, 84], "fpss": [81, 82, 83, 84], "nsim": [81, 82, 83, 84], "680": [81, 82, 83, 84, 227, 313], "frame_r": [81, 82, 83, 84, 296, 297], "ball_orn": [81, 94], "130": [81, 82, 84, 307], "n_link": [82, 84, 94], "dx_link": [82, 84], "segment": [82, 84, 131, 218, 260, 276, 303, 311, 313], "link_mass": [82, 84, 94], "base_mass": [82, 84, 94], "joint_frict": [82, 84], "rad": [82, 294], "link_shap": [82, 84], "geom_cylind": [82, 84], "collisionframeposit": [82, 84], "base_shap": [82, 84, 94], "visualshapeid": [82, 84, 94], "linkcollisionshapeindic": [82, 84, 94], "linkvisualshapeindic": [82, 84, 94], "linkposit": [82, 84, 94], "linkorient": [82, 84, 94], "linkinertialframeposit": [82, 84, 94], "linkinertialframeorn": [82, 84, 94], "jointtyp": [82, 84, 94], "joint_spher": [82, 84], "linkdirect": [82, 84, 94], "link_radii": [82, 84], "link_height": [82, 84, 94], "rope_actor": [82, 84, 94], "rope": [82, 84, 94, 130], "linkmass": [82, 84, 94], "linkinertialframeorient": [82, 84, 94], "linkparentindic": [82, 84, 94], "linkjointtyp": [82, 84, 94], "linkjointaxi": [82, 84, 94], "traceback": [], "devel": [], "doc": [87, 94, 97, 115, 136, 143, 155, 173, 179, 180, 183, 197, 200, 228, 250, 274, 291, 293, 296, 304, 305, 306, 307, 310, 313, 315], "examples_revamp": 314, "systemerror": [], "stiff": [82, 130], "among": [82, 119, 130, 177, 221, 267, 312], "friction_vec": [82, 84], "control_mod": [82, 84], "position_control": [82, 84], "getnumjoint": [82, 84, 94], "setjointmotorcontrolmultidof": [82, 84], "targetposit": [82, 84], "targetveloc": [82, 84], "positiongain": [82, 84], "velocitygain": [82, 84], "constraint": [82, 84, 117], "root_robe_c": [82, 84], "createconstraint": [82, 84], "joint_fix": [82, 84], "traj": 82, "inject": 82, "amplitude_x": 82, "amplitude_i": 82, "freq": 82, "coupl": [82, 117, 122, 130, 141, 144, 245], "sync_joint": [82, 94], "actor_list": [82, 84, 94], "getlinkst": [82, 84, 94], "offer": [82, 84, 143, 146, 255, 272, 274], "4th": [82, 84, 115], "freq_sim": 82, "240": [82, 136, 308], "trajectori": 82, "ux": [82, 155, 174], "pivot": [82, 195], "getquaternionfromeul": 82, "changeconstraint": 82, "jointchildframeorient": 82, "maxforc": 82, "seri": [83, 98, 106, 138, 178, 181, 229, 296, 304, 315], "physicsclientid": 83, "number_of_domino": 83, "domino_mass": 83, "domino_s": 83, "domino_cent": 83, "domino_direct": 83, "domino_orn": 83, "domino_color": 83, "domino_col": 83, "centers_list": 83, "domino_actor": 83, "sync_domino": 83, "domino1_po": 83, "domino1_orn": 83, "110": [83, 306], "handi": 84, "wall_length": 84, "wall_breadth": 84, "cylindr": [84, 313], "nxnxn": [84, 131], "int16": [84, 277], "desir": [84, 94, 115, 174, 212, 237, 247, 267, 268, 274, 277, 283, 284, 296], "hing": 84, "ball_shap": 84, "173": 307, "base_orn": 84, "brick_vertic": 84, "brick_sec": 84, "chain_vertic": 84, "chain_sec": 84, "sync_chain": 84, "tool": [84, 106, 128, 138, 140, 149, 152, 155, 178, 181, 229, 247, 259, 261, 265, 268, 271, 287, 297, 303, 305, 306, 307, 308, 309, 310, 311, 312, 313, 315], "server": [85, 87, 88, 89, 90, 94, 97, 143, 149, 174, 297], "turn": [85, 90, 114, 156, 194, 238, 253, 259, 264, 265, 267, 268, 272, 274, 294], "webrtc": [85, 86, 87, 90, 140, 143, 155, 174, 292, 313, 314], "mjpeg": [85, 86, 87, 90, 174, 292, 314], "155": [86, 307], "20_stream": [86, 314], "stream": [86, 140, 143, 146, 155, 174, 175, 176, 230, 297, 313, 314], "viz_widget": [86, 89, 314], "648": [86, 89, 313], "viz_no_interact": [86, 88, 314], "397": [86, 88, 303], "viz_interact": [86, 87, 314], "serv": [87, 274, 287], "web": [87, 89, 174, 315], "browser": [87, 89, 97, 162, 174, 292], "robust": [87, 89, 237], "live": [87, 89, 98, 274], "latenc": [87, 89, 143], "ngrok": [87, 143, 174], "instal": [87, 89, 98, 99, 100, 101, 102, 104, 105, 107, 123, 133, 139, 155, 167, 177, 198, 230, 277, 304, 305, 307, 308, 311, 312, 313, 315], "aiortc": [87, 89, 164], "pip": [87, 89, 97, 98, 99, 100, 101, 102, 104, 105, 107, 123, 133, 139, 167, 177, 230, 306, 315], "ffmpeg": [87, 89], "linux": [87, 89, 97, 98, 143, 308], "apt": [87, 89], "libavdevic": [87, 89], "dev": [87, 89, 97, 181, 315], "libavfilt": [87, 89], "libopu": [87, 89], "libvpx": [87, 89], "pkg": [87, 89], "config": [87, 89], "brew": [87, 89], "opu": [87, 89], "multiprocess": [87, 88, 146, 149, 155, 174, 292], "sy": [87, 149, 279, 285, 291], "furystreamcli": [87, 88, 149, 297], "furystreaminteract": [87, 149, 297], "maco": [87, 88, 89, 97, 104, 143, 152, 158, 174, 198, 305], "set_start_method": [87, 88], "spawn": [87, 88], "webrtc_avail": 87, "web_serv": [87, 297], "web_server_raw_arrai": [87, 88, 297], "__name__": [87, 88], "__main__": [87, 88], "use_raw_arrai": [87, 88, 292], "rawarrai": [87, 140, 146, 149, 292], "sharedmemori": [87, 146, 149, 152, 155, 292], "featur": [87, 105, 113, 115, 121, 123, 124, 125, 126, 132, 136, 140, 141, 153, 163, 165, 168, 170, 172, 173, 174, 175, 176, 179, 181, 195, 198, 202, 204, 210, 211, 216, 217, 222, 226, 227, 237, 238, 249, 252, 254, 255, 261, 262, 264, 268, 270, 272, 274, 275, 298, 303, 306, 308, 312, 313], "share": [87, 111, 113, 115, 117, 119, 120, 122, 125, 128, 134, 136, 145, 146, 148, 149, 151, 154, 155, 157, 158, 160, 163, 166, 169, 171, 174, 232, 265, 292], "version_info": 87, "window_s": [87, 88, 89], "max_window_s": [87, 149, 292], "sent": [87, 166, 179, 197, 206, 208], "ms_stream": [87, 292], "ms_interact": [87, 292], "send": [87, 94, 99, 100, 101, 102, 104, 105, 107, 123, 133, 139, 140, 154, 167, 177, 190, 198, 206, 208, 227, 230, 287, 315], "queue": [87, 149, 292], "max_queue_s": [87, 292], "stream_interact": 87, "arg": [87, 88, 97, 281, 290, 292], "img_manag": [87, 88], "image_buff": [87, 88, 292], "info_buff": [87, 88, 155, 292], "circular_queu": [87, 292], "head_tail_buff": [87, 292], "buffer": [87, 143, 149, 168, 194, 200, 227, 228, 231, 235, 277, 279, 282, 285, 291, 292, 297], "_buffer": 87, "8000": [87, 89, 143, 292], "localhost": [87, 89, 292], "image_buffer_nam": [87, 292], "info_buffer_nam": [87, 292], "head_tail_buffer_nam": [87, 292], "buffer_nam": [87, 292], "m": [87, 88, 140, 142, 143, 146, 149, 155, 157, 169, 172, 179, 180, 232, 233, 236, 239, 245, 251, 260, 263, 266, 270, 272, 274, 276, 287, 290, 292, 315], "url": [87, 89, 144, 172, 174, 191, 228, 279, 292, 294, 297, 310, 311], "htttp": 87, "wise": [87, 143], "kill": [87, 146, 149], "resourc": [87, 135, 143, 146, 149, 152, 155, 158, 159, 174, 257, 276, 292], "cleanup": [87, 88, 149, 172, 292, 297], "streamer": [88, 140, 146], "milesecond": [88, 292], "port": [89, 292], "greater": [89, 247, 252, 271, 281, 292, 296], "asyncio": [89, 176, 185, 292], "platform": [89, 177, 230, 312, 313], "time_sleep": 89, "environ": [89, 120, 143, 162, 174, 268], "wsl": 89, "async": [89, 146, 149, 292], "await": [89, 265], "get_event_loop": 89, "run_until_complet": 89, "ifram": [89, 292], "auto_examples_python": 90, "auto_examples_jupyt": 90, "211": [93, 307, 311], "star": [93, 99, 100, 101, 102, 104, 105, 107, 123, 133, 139, 167, 177, 230, 290, 307, 308], "157": [93, 307], "fork": [93, 143, 146, 181, 315], "4570": [], "commit": [93, 136, 140, 143, 146, 149, 152, 155, 158, 256, 289, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 315], "serg": [99, 100, 101, 102, 104, 105, 106, 107, 123, 133, 134, 138, 139, 143, 167, 177, 178, 185, 194, 211, 221, 229, 230, 272, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313], "koudoro": [102, 104, 105, 107, 123, 133, 139, 143, 167, 177, 185, 230, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313], "1013": [], "95193": [], "74418": [], "eleftherio": [102, 104, 105, 107, 123, 133, 139, 167, 177, 230, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313], "garyfallidi": [102, 104, 105, 107, 123, 133, 139, 167, 177, 230, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313], "551": 313, "19591": [], "14918": [], "agour": [230, 313], "391": [], "17046": [], "9922": [], "ganimtron": [139, 226, 310], "317": 311, "6514": [], "3222": [], "guaj": [105, 107, 133, 139, 167, 177, 230, 306, 307, 309, 310, 311, 312, 313], "304": 310, "22426": [], "18194": [], "xtanion": [223, 228], "248": [136, 308], "12502": [], "4316": [], "devmessia": [146, 149, 155, 312], "15264": [], "8814": [], "nibba2018": [], "7847": [], "3452": [], "suntzunami": [], "5747": [], "2968": [], "antrikshmisri": [], "3789": [], "1159": [], "tvcastillod": 270, "4490": [], "2093": [], "ranveer": [], "aggarw": [], "3661": [], "893": [], "lenixlobo": [107, 135, 307], "12722": [], "11226": [], "joaodel": [], "1577": [], "325": [], "marc": [102, 107, 123, 177, 304, 307, 308, 312], "alexandr": [102, 107, 123, 177, 304, 307, 308, 312], "cote": [], "5234": [], "3227": [], "mlraglin": [], "1348": [], "320": [], "karandeep": [], "singh": [], "juneja": [], "2547": [], "455": 311, "maharshi": 303, "gor": 303, "1986": 277, "1227": [], "ariel": [104, 305], "rokem": [104, 305], "652": [], "857": [], "filipinascimento": [], "1832": [], "828": 303, "david": [102, 103, 270, 304], "reagan": [102, 304], "711": [], "272": [136, 309], "nasimanousheh": [], "576": [234, 237, 240, 303], "paulnicolashunt": [], "266": 308, "saransh0905": [], "625": 313, "310": 310, "kakashihataka": [], "245": 308, "148": 307, "tushar5526": [], "1923": [], "1651": [], "clarkszw": [], "matthew": [], "brett": [], "277": 309, "642": 313, "chrls98": [], "1039": [], "609": [226, 313], "sassafrass6": [], "186": [304, 307], "106": 306, "sreekarchigurupati": [], "40174": [], "910": [], "namanbansalcod": [], "frheault": [], "kesshijordan": [], "467": 312, "252": [136, 309], "ibrahimani": [107, 307], "327": [], "131": 307, "etienn": [105, 107, 306, 307], "st": [105, 107, 306, 307], "ong": [105, 107, 306, 307], "632": 313, "380": [], "sanjaymarreddi": [], "377": [], "149": [270, 275], "sitek": [104, 305], "sparshg": [230, 313], "omar": [], "ocegueda": [], "964": [], "mehabhalodiya": 164, "181": 307, "amit": [167, 311], "chaudhari1": [], "jhlegarreta": [], "bago": [], "amirbekian": [], "103": 306, "189": 307, "robinroy03": [], "126": 307, "gregori": [], "lee": [], "122": 307, "rkharsan": [], "254": 308, "albai": [], "stefan": [], "van": [171, 173, 287], "der": [171, 173, 287], "walt": [], "415": 311, "lidonohu": [], "316": 313, "prayasj": [177, 312], "guillaumefaveli": [], "lej0hn": [], "ghoshbishakh": [], "yash": [], "sherri": [], "alexand": [], "gauvin": [], "haran2001": [139, 310], "relativisticmechan": [], "sarasaadoun": [], "197": 308, "179": 307, "dwijrajhari": [], "samuel": [], "jean": 166, "christoph": 293, "nguyen": [], "jiri": [], "borovec": [], "chencheng0630": [107, 307], "147": [270, 307], "scott": [104, 305], "trinkl": [104, 305], "gautamgottipati": [], "jhalak27": [], "184": 307, "151": 307, "marsco": [], "aju100": [139, 310], "yaroslav": [], "halchenko": [], "devmodi154": [], "dependabot": 303, "bot": [303, 305], "pietroastolfi": [], "iamansoni": [], "16bitmood": [], "shadow2121": [], "loopthrough": [167, 311], "danielskatz": [], "jakob": [], "wasserth": [], "sailesh": [230, 313], "2209": [], "offici": [94, 113, 115, 117, 119, 120, 122, 125, 128, 130, 131, 134, 137, 143, 146, 179, 180, 181, 270, 275, 315], "driven": [94, 98, 315], "statu": [94, 194, 246, 253, 294, 315], "unless": [94, 136, 277, 294, 295, 296], "shutdown": 94, "gravity_x": 94, "gravity_i": 94, "gravity_z": 94, "criterion": 94, "fulfil": 94, "snippet": [94, 119, 128, 141, 151], "lateral_frict": 94, "damp": 94, "inertial_po": 94, "inertial_orn": 94, "coeff": 94, "linkindex": 94, "extern": [94, 136, 140, 268, 282, 312], "applyexternaltorqu": 94, "Not": [94, 181, 236, 239, 242, 254, 263, 265, 309], "explicitli": [94, 130, 198, 295, 304], "pair": [94, 244, 247, 255, 268, 272, 293], "enablecol": 94, "setcollisionfilterpair": 94, "feel": [94, 179, 181], "section": [94, 185, 246, 250, 252, 268, 272, 277, 291, 303, 310, 313], "rotatewxyz": 94, "said": [94, 113, 115, 117, 119, 122, 125, 136, 155, 180, 182, 239, 256, 265, 268], "procedur": [94, 117], "firstli": [94, 122, 170, 181, 222, 240], "nb_object": 94, "object_cent": 94, "object_direct": 94, "object_orient": 94, "object_color": 94, "object_collis": 94, "further": [94, 119, 130, 134, 150, 235, 251, 255, 257, 264, 265, 270, 272, 277, 315], "brick_actor_singl": 94, "getdifferencefromquarternion": 94, "tupl": [94, 274, 275, 276, 277, 279, 281, 284, 286, 287, 288, 289, 290, 292, 293, 294, 295, 296], "subtract": [94, 119, 296], "gimbal": 94, "lock": [94, 149, 292, 296, 297], "lead": [94, 156, 250, 259, 267, 268, 272, 287, 310, 311, 315], "unwant": [94, 310], "spin": [94, 125, 128, 272, 296], "experienc": [94, 179, 231, 244], "advis": [94, 115, 179, 182, 316], "urdf": 94, "root": [94, 234, 240, 259, 267, 268, 272, 315], "hierarchi": [94, 220, 228], "freedom": 94, "regular": [94, 183, 274, 280, 281, 290, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313], "inerti": 94, "princip": [94, 270, 275, 277], "inertia": 94, "nb_link": 94, "suppos": [94, 111, 130, 155, 174, 250, 271], "linkheight": 94, "linkradii": 94, "queri": [94, 160, 181, 310], "suzann": [95, 194, 310, 313], "blender": [95, 179, 180, 181, 218, 223], "directori": [95, 97, 166, 279, 289, 291, 294, 296, 315], "path_suzann": 95, "soon": [97, 132, 147, 150, 159, 162, 172, 227, 239, 242, 268], "life": [97, 134, 143, 179, 180, 238], "decemb": [97, 180], "31st": 97, "2019": [97, 298, 307], "mandatori": [97, 149, 164, 179, 292], "aiohttp": [97, 185, 292], "pygltflib": [97, 185, 194, 282], "matplotlib": [97, 170, 253, 268, 271, 273, 274, 275, 277, 278, 305], "termin": [97, 99, 100, 101, 102, 104, 105, 107, 123, 133, 139, 167, 177, 180, 230, 296, 313], "forg": [97, 99, 100, 101, 102, 104, 105, 107, 123, 133, 139, 167, 177, 230], "channel": [97, 224, 226, 274, 277, 278, 282, 296], "latest": [97, 250, 259, 309, 313], "clone": [97, 181, 315], "repo": [97, 112, 181, 315], "git": [97, 180, 289, 315], "txt": [97, 100, 301, 307, 313, 315], "enjoi": [97, 106, 134, 138, 144, 178, 229], "get_info": [97, 297, 304], "pytest": [97, 144, 174, 312, 315], "svv": [97, 315], "test_actor": [97, 306, 311], "test_my_function_nam": 97, "headless": 97, "xvfb": 97, "osx": [97, 304, 305], "xquartz": 97, "1920x1080x24": 97, "null": [97, 244], "bat": 97, "makefil": 97, "readm": [97, 101, 302, 303, 304, 305, 307, 308, 310, 311, 313, 315], "md": [97, 315], "upload_to_gh": 97, "page": [97, 98, 180, 181, 231, 246, 247, 256, 268, 270, 293, 313, 315], "rst": [97, 165, 304, 308, 313, 315], "congratul": [97, 103, 181], "minimalist": [98, 181, 219], "har": 98, "gpu": [98, 135, 143, 147, 174, 179, 187, 206, 227, 259, 268, 274, 311], "precis": [98, 259, 268, 270], "clariti": [98, 240, 246], "address": [98, 153, 159, 162, 163, 168, 237, 240, 243, 248, 249, 251, 252, 254, 255, 257, 258, 260, 263, 264, 267, 268, 269, 271, 272], "grow": [98, 137, 227], "necess": [98, 243], "ecosystem": 98, "cgi": 98, "imageri": 98, "deploi": 98, "everydai": 98, "practic": [98, 155, 174, 179, 181, 233, 268], "clearli": [98, 181, 244], "written": [98, 117, 155, 174, 181, 231, 316], "good": [98, 120, 140, 143, 149, 150, 166, 169, 171, 174, 179, 181, 182, 212, 213, 219, 231, 236, 250, 253, 254, 256, 257, 259, 262, 265, 268, 316], "underli": [98, 150, 171], "collabor": [98, 140, 174, 237], "hope": [98, 244, 245, 250, 254, 259, 266], "fail": [98, 103, 159, 162, 198, 228, 238, 252, 258, 271, 289, 304, 305, 313, 315], "develop": [98, 99, 100, 101, 102, 104, 105, 107, 113, 123, 133, 134, 139, 140, 141, 143, 155, 167, 174, 175, 176, 177, 226, 227, 230, 233, 241, 243, 256, 261, 264, 268, 270, 272, 308, 315], "team": [98, 109, 137, 142, 146, 149, 157, 163, 170, 231, 243, 277], "discord": [98, 99, 100, 101, 102, 104, 105, 106, 107, 123, 133, 138, 139, 167, 177, 178, 180, 181, 229, 230, 310], "chat": 98, "room": 98, "cinemat": 98, "multiplatform": 98, "mac": [98, 304], "super": [98, 227], "integr": [98, 109, 115, 117, 125, 135, 136, 137, 146, 152, 174, 177, 180, 185, 202, 206, 207, 212, 219, 228, 230, 241, 258, 261, 264, 268, 272, 300, 310, 312, 313], "btdf": 98, "latex": [98, 170, 313], "font": [98, 115, 162, 168, 170, 174, 176, 240, 249, 255, 272, 294], "bsd": 98, "who": [98, 103, 137, 143, 155, 174, 247, 277], "involv": [98, 108, 116, 118, 126, 129, 135, 148, 172, 179, 231, 234, 240, 241, 244, 247, 261, 267, 268, 272], "typo": [98, 149, 164, 225, 305, 311, 313], "request": [98, 109, 130, 131, 134, 135, 136, 137, 140, 149, 152, 164, 171, 172, 173, 174, 180, 194, 202, 206, 226, 227, 234, 237, 240, 249, 261, 268, 270, 272, 277, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313], "happi": [99, 100, 101, 102, 104, 105, 107, 123, 133, 139, 167, 177, 179, 180, 181, 230, 256], "announc": [99, 100, 101, 102, 104, 105, 107, 109, 123, 133, 139, 167, 177, 179, 180, 230, 232, 315], "highlight": [99, 100, 101, 102, 104, 105, 107, 123, 133, 139, 167, 177, 216, 217, 226, 230, 243, 312, 315], "split": [99, 299], "upgrad": [99, 100, 101, 102, 104, 105, 107, 123, 133, 139, 167, 177, 196, 230, 315], "conda": [99, 100, 101, 102, 104, 105, 107, 123, 133, 139, 167, 177, 230], "question": [99, 100, 101, 102, 104, 105, 107, 123, 133, 139, 167, 177, 179, 180, 181, 184, 186, 230, 292], "suggest": [99, 100, 101, 102, 104, 105, 107, 112, 117, 119, 123, 133, 139, 154, 157, 164, 167, 177, 185, 190, 198, 200, 201, 203, 207, 215, 219, 222, 223, 230, 233, 241, 254, 260, 265, 267, 271, 274, 277], "mail": [99, 100, 101, 102, 104, 105, 106, 107, 123, 133, 138, 139, 149, 167, 177, 178, 179, 181, 229, 230, 315], "On": [99, 100, 101, 102, 104, 105, 107, 123, 133, 137, 139, 167, 170, 177, 230, 248], "behalf": [99, 100, 101, 102, 104, 105, 107, 123, 133, 139, 167, 177, 230], "mainten": [100, 101, 133, 139, 167, 177, 230, 254, 300, 301, 302, 315], "codecov": [101, 302, 313], "travi": [101, 139, 300, 302, 304, 305, 306, 310, 315], "stereo": [102, 296, 304], "coverag": [102, 104, 105, 107, 123, 133, 161, 167, 304, 305, 306, 307, 308, 309, 311], "thank": [102, 104, 105, 107, 111, 113, 115, 117, 119, 120, 122, 123, 125, 128, 130, 131, 133, 134, 137, 139, 167, 177, 230, 231, 244, 266, 277], "contributor": [102, 104, 105, 107, 123, 130, 133, 136, 139, 167, 177, 180, 181, 182, 185, 230, 232, 233, 246, 250, 253, 256, 257, 265, 266, 269, 315, 316], "jon": [102, 107, 304, 307], "haitz": [102, 107, 304, 307], "legarreta": [102, 107, 304, 307], "gorro\u00f1o": [102, 107, 304, 307], "c\u00f4t\u00e9": [102, 107, 123, 177, 304, 307, 308, 312], "ohbm": 103, "brainart": 103, "melpomen": 103, "realli": [103, 113, 143, 144, 150, 231, 244, 256, 259, 268, 315], "beauti": [103, 253, 259], "experi": [103, 110, 112, 119, 134, 142, 169, 171, 181, 182, 185, 186, 207, 232, 244, 250, 256, 257, 259, 266, 270, 274], "appveyor": [104, 105, 305, 306], "ci": [104, 159, 161, 162, 174, 177, 230, 303, 305, 308, 312, 313], "guillaum": [104, 305], "faveli": [104, 305], "kevin": [104, 305], "prashil": [104, 305], "anti": [105, 170, 179, 276, 296, 306], "alias": [105, 170, 179, 276, 296, 306], "nose": [105, 306, 307], "azur": [105, 230, 306, 308, 311, 313], "javier": [105, 107, 133, 139, 167, 177, 190, 202, 230, 306, 307, 309, 310, 311, 312, 313], "particip": [106, 138, 141, 178, 180, 181, 229, 232, 241, 254], "2020": [106, 131, 134, 136, 137, 172, 173, 174, 298, 310], "umbrella": [106, 108, 109, 138, 178, 181, 229, 294], "foundat": [106, 108, 109, 135, 136, 138, 172, 173, 178, 179, 181, 226, 227, 228, 229, 268, 270, 272], "graph": [106, 138, 140, 152, 155, 174, 178, 229, 268, 311], "talk": [106, 138, 143, 178, 180, 181, 182, 229, 236, 241, 244, 247, 250, 253, 259, 262, 268, 269], "drop": [106, 136, 138, 178, 181, 229, 294], "Be": [106, 138, 178, 229], "contour_from_label": [107, 297, 307], "huge": [107, 123, 143, 181, 307, 308], "secur": [107, 265, 307], "md5": [107, 307], "sha256": [107, 307], "devanshu": [107, 307], "modi": [107, 307], "filipi": [107, 143, 174, 182, 187, 190, 202, 206, 230, 231, 247, 250, 268, 269, 307, 313], "nascimento": [107, 143, 174, 230, 231, 307, 313], "silva": [107, 230, 307, 313], "gottipati": [107, 307], "gautam": [107, 230, 307, 313], "liam": [107, 123, 307, 308], "donohu": [107, 123, 307, 308], "marssi": [107, 307], "naman": [107, 123, 307, 308], "bansal": [107, 123, 307, 308], "nasim": [107, 133, 230, 307, 309, 313], "saransh": [107, 307], "jain": [107, 307], "shreya": [107, 307], "bhujbal": [107, 307], "soham": [107, 109, 123, 133, 136, 137, 139, 230, 267, 272, 307, 308, 309, 310, 313], "biswa": [107, 109, 123, 133, 136, 139, 230, 307, 308, 309, 310, 313], "vivek": [107, 133, 307, 309], "choudhari": [107, 133, 307, 309], "hei": [108, 110, 112, 114, 116, 118, 121, 124, 126, 127, 129, 132, 137], "everyon": [108, 109, 110, 121, 124, 126, 137, 140, 141, 184, 231, 233, 241, 247, 250, 253, 256, 259, 262, 265, 268, 269], "summer": [108, 134, 137, 140, 141, 142, 179, 181, 194, 231, 232, 311], "psf": [108, 181], "am": [108, 109, 113, 115, 117, 119, 120, 122, 130, 131, 132, 134, 141, 153, 156, 165, 179, 180, 181, 185, 212, 226, 233, 235, 239, 241, 243, 250, 256, 259, 265, 268, 269, 315], "lenix": [108, 123, 133, 135, 139, 308, 309, 310], "lobo": [108, 123, 133, 135, 139, 308, 309, 310], "undergradu": 108, "student": [108, 109, 140, 141, 181], "india": [108, 109], "univers": [108, 109, 179], "pandem": [108, 109], "outbreak": [108, 109], "head": [108, 109, 149, 292, 297, 310], "earli": [108, 109, 142, 180, 227, 245], "had": [108, 109, 110, 111, 115, 117, 119, 122, 128, 130, 131, 134, 136, 141, 142, 143, 144, 147, 148, 149, 150, 153, 156, 159, 162, 166, 170, 171, 179, 180, 181, 182, 183, 184, 185, 188, 194, 195, 197, 198, 201, 203, 205, 206, 208, 209, 210, 212, 213, 215, 216, 219, 222, 231, 232, 233, 244, 245, 246, 250, 253, 254, 256, 258, 259, 262, 266, 267, 268, 271, 272], "confer": [108, 109, 270], "meet": [108, 109, 112, 131, 140, 141, 142, 144, 147, 148, 150, 153, 154, 156, 157, 159, 162, 163, 166, 168, 170, 171, 173, 174, 182, 183, 191, 199, 200, 201, 202, 203, 205, 214, 215, 218, 231, 232, 233, 237, 238, 239, 240, 242, 246, 248, 251, 253, 256, 257, 262, 270, 275, 315], "mentor": [108, 109, 110, 112, 113, 115, 117, 118, 119, 120, 127, 130, 131, 134, 136, 137, 140, 141, 142, 143, 145, 147, 148, 149, 151, 154, 157, 161, 162, 163, 164, 166, 171, 173, 175, 180, 182, 185, 186, 188, 201, 207, 210, 219, 222, 231, 233, 236, 238, 241, 244, 245, 246, 247, 248, 250, 251, 253, 255, 256, 259, 262, 265, 266, 267, 268, 269, 271, 272], "schedul": 108, "wednesdai": [108, 109, 200, 247], "coher": 108, "entir": [108, 109, 117, 143, 239, 272], "lot": [108, 116, 118, 126, 135, 140, 143, 147, 149, 152, 155, 159, 162, 179, 180, 181, 182, 190, 201, 206, 207, 225, 235], "theoret": 108, "concept": [108, 117, 136, 180, 181, 244, 268], "spent": [108, 110, 116, 120, 146, 149, 152, 164, 181, 240, 259, 262, 265, 268], "theori": [108, 160, 171, 174, 316], "2nd": [109, 114], "year": [109, 141, 143, 179, 180, 181, 232, 308, 315], "pursu": [109, 179, 180, 181], "bachelor": [109, 179, 180, 181], "tech": 109, "scienc": [109, 233], "institut": [109, 142, 180], "kolkata": 109, "organ": [109, 140, 143, 149, 174, 179, 180, 181, 251, 287], "sci": [109, 141], "fi": [109, 141], "countri": [109, 143], "lockdown": 109, "were": [109, 112, 113, 114, 115, 116, 117, 119, 120, 122, 125, 127, 129, 130, 132, 135, 136, 141, 144, 147, 149, 153, 156, 159, 162, 165, 166, 168, 169, 170, 172, 173, 174, 179, 180, 181, 183, 185, 194, 198, 203, 204, 207, 210, 212, 216, 217, 218, 219, 227, 237, 238, 239, 249, 252, 257, 258, 259, 264, 265, 267, 268, 269, 271, 272, 281, 296], "core": [109, 142, 149, 153, 156, 163, 227, 258, 259, 272, 292, 297, 311], "discuss": [109, 118, 127, 128, 130, 131, 140, 142, 143, 145, 146, 149, 153, 155, 156, 161, 164, 171, 173, 175, 182, 185, 186, 188, 199, 201, 202, 203, 205, 214, 219, 226, 227, 232, 237, 238, 240, 242, 243, 245, 246, 248, 249, 251, 257, 259, 268, 272, 293], "deadlin": 109, "ourselv": [109, 170], "progress": [109, 111, 117, 119, 120, 122, 125, 128, 130, 131, 134, 135, 145, 148, 151, 154, 157, 160, 163, 166, 169, 171, 174, 232, 240, 241, 246, 250, 252, 256, 261, 264, 267, 271, 279, 294, 313], "remain": [109, 120, 124, 126, 147, 153, 162, 165, 168, 172, 174, 226, 237, 243, 258, 264, 265, 312], "pull": [109, 130, 131, 135, 136, 140, 146, 149, 152, 172, 173, 174, 180, 226, 227, 234, 237, 240, 249, 261, 268, 270, 272, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313], "pend": [109, 120, 130, 243, 251], "review": [109, 110, 141, 147, 150, 163, 164, 165, 168, 175, 180, 182, 211, 221, 226, 228, 233, 234, 236, 239, 242, 246, 248, 250, 251, 252, 253, 254, 256, 257, 258, 259, 264, 265, 267, 269, 270, 271, 272, 287, 310, 311, 315], "date": [109, 135, 136, 172, 173, 174, 226, 227, 228, 250, 270, 272], "focus": [109, 119, 131, 155, 174, 225, 236, 237, 240, 246, 252, 259, 265, 267, 268, 269], "skeleton": [109, 111, 228], "pr": [109, 110, 113, 119, 121, 128, 130, 132, 136, 137, 140, 141, 142, 143, 144, 145, 146, 147, 149, 150, 154, 156, 157, 158, 160, 161, 163, 164, 165, 166, 168, 169, 170, 171, 172, 174, 175, 176, 180, 181, 182, 185, 187, 189, 190, 191, 193, 194, 195, 196, 201, 202, 204, 206, 207, 208, 210, 211, 212, 214, 216, 217, 218, 220, 221, 222, 223, 224, 226, 227, 228, 233, 234, 236, 237, 239, 240, 241, 243, 244, 245, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 267, 268, 269, 270, 271, 272, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313], "doubl": [109, 123, 136, 148, 235, 239, 270, 271, 275, 287, 294, 295, 303, 306, 308, 313], "unabl": [109, 181, 271, 309, 310], "thankfulli": [109, 128, 130, 261, 269], "successfulli": [109, 111, 113, 136, 180, 181, 188, 207, 212, 219, 224, 243, 258, 259, 264, 272, 296], "cheer": [109, 137, 265], "volumetr": [110, 127], "stack": [110, 165, 168, 172, 219, 284], "Such": 110, "prior": [110, 127, 181, 201, 207, 247, 253, 268, 316], "directx": 110, "fur": [110, 135], "minor": [110, 121, 140, 144, 153, 159, 162, 175, 239, 245, 268, 269, 270, 281, 310, 313], "bug": [110, 113, 114, 115, 121, 124, 126, 131, 132, 146, 147, 152, 162, 172, 174, 175, 176, 180, 184, 185, 194, 210, 226, 228, 256, 259, 265, 292, 303, 304, 306, 307, 309, 310, 311, 312, 313], "noth": [110, 168, 181, 198, 226, 235], "weekli": [111, 112, 113, 115, 117, 119, 120, 122, 125, 128, 130, 131, 134, 135, 136, 142, 145, 148, 151, 154, 157, 160, 163, 166, 169, 171, 172, 173, 174, 182, 183, 227, 237, 239, 241, 242, 244, 247, 248, 250, 253, 256, 257, 259, 262, 265, 309], "far": [111, 113, 115, 150, 154, 169, 250, 259], "apart": [111, 113, 117, 119, 120, 122, 125, 130, 131, 136, 137, 168, 268], "regard": [111, 113, 115, 117, 120, 122, 125, 128, 130, 131, 134, 159, 162, 181, 240, 249, 259, 262, 271], "proper": [111, 130, 131, 149, 159, 181, 182, 207, 234, 255, 266, 272], "problem": [111, 115, 117, 119, 120, 122, 125, 128, 130, 136, 141, 143, 147, 148, 153, 156, 162, 174, 206, 215, 225, 226, 227, 233, 237, 240, 245, 254, 255, 256, 258, 259, 260, 262, 265, 266, 267, 268, 271, 272, 274, 305, 307], "doesn": [111, 141, 147, 149, 152, 179, 212, 213, 244, 247, 287, 295, 304, 310, 311, 315], "scrollbar": [111, 113, 115, 136, 156, 237, 240, 243, 249, 267, 272, 294, 303], "hopefulli": [111, 113, 150, 153, 156, 159, 162, 168, 170, 172, 254, 263], "excit": [112, 119, 181, 232, 256], "got": [112, 116, 141, 142, 153, 170, 180, 182, 187, 198, 202, 213, 215, 216, 220, 223, 232, 233, 241, 256, 257, 259, 268, 271, 289], "proceed": [112, 270], "branch": [112, 114, 118, 121, 124, 141, 189, 191, 228, 270, 271, 304, 315], "deform": [112, 114, 228, 270], "rid": 112, "slightli": [112, 141], "realist": [112, 114, 228], "thevtk": 112, "confus": [112, 113, 116, 131, 216, 219, 240, 268], "doubt": [112, 181], "immedi": [112, 238, 243], "affili": 113, "countless": 113, "debug": [113, 157, 198, 212, 216, 258, 291, 312], "session": [113, 194, 244, 255, 268, 272], "friendli": [113, 136, 261, 313], "manner": [113, 274, 284], "wrote": [113, 122, 179, 191, 209], "summar": [113, 231], "gif": [113, 114, 116, 174, 214, 221, 227, 276, 313], "unfortun": [113, 134, 135, 153, 155, 174, 259, 267], "didn": [113, 141, 144, 153, 159, 160, 162, 171, 172, 179, 180, 181, 186, 196, 199, 200, 209, 210, 211, 212, 213, 214, 215, 216, 217, 219, 220, 221, 224, 225, 234, 238, 241, 243, 246, 247, 250, 258, 259, 262, 268, 271], "prioriti": [113, 153, 258, 264, 291, 294, 311], "overshoot": 113, "runtim": [113, 134, 136, 152, 172, 176, 182, 228, 281], "reason": [113, 143, 162, 172, 176, 181, 185, 198, 199, 227, 235, 236, 238, 240, 241, 244, 262, 268, 270, 271, 287], "misplac": 113, "wasn": [113, 114, 122, 153, 168, 179, 181, 183, 186, 192, 195, 197, 198, 212, 241, 243, 244, 253, 265, 268, 272], "post": [114, 130, 143, 149, 154, 155, 165, 174, 181, 219, 226, 227, 228, 253, 256, 259, 265, 268, 270, 272, 311, 312, 313, 315], "slight": [114, 202, 238], "solv": [114, 115, 122, 135, 140, 141, 143, 146, 149, 155, 180, 181, 186, 187, 204, 206, 208, 212, 215, 223, 259, 268, 270, 271, 310], "suspect": 114, "possibli": [114, 147], "long": [114, 122, 150, 153, 194, 295], "simultan": [114, 261, 268, 270, 272, 288], "rather": [114, 118, 148, 169, 171, 259, 272, 274, 293], "highli": [114, 117, 119, 150], "benefici": [114, 142, 145], "realiz": [114, 130, 181, 268, 272], "caus": [114, 140, 143, 150, 152, 176, 185, 187, 203, 215, 218, 234, 237, 240, 252, 272, 313, 316], "lambertian": 114, "eventu": [114, 116, 124, 179, 250], "vtktextactor": [115, 117, 240, 294], "text_scale_mode_non": 115, "text_scale_mode_prop": 115, "text_scale_mode_viewport": 115, "mainli": [115, 119, 122, 130, 131, 133, 139, 167, 177, 226, 230, 256, 257, 265, 267], "couldn": [115, 141, 150, 153, 162, 179, 190, 215, 271], "tri": [115, 117, 132, 134, 145, 148, 151, 156, 160, 179, 180, 181, 183, 185, 186, 188, 190, 192, 195, 198, 206, 207, 208, 210, 212, 215, 217, 222, 223, 226, 228, 245, 256, 259, 262, 266, 268, 271, 313], "maintain": [115, 168, 187, 190, 193, 202, 206, 294], "abstract": [115, 155, 292, 294], "expos": [115, 244, 277, 279, 285, 291], "vtkviewport": [115, 120], "position2": [115, 240], "cannot": [115, 172, 194, 235, 238, 281, 288, 313], "inconsist": [115, 240, 249], "agre": 115, "irrespect": 115, "constructor": [115, 147, 159, 172, 277], "someth": [115, 120, 122, 147, 150, 179, 181, 212, 222, 226, 233, 235, 238, 241, 242, 244, 247, 254, 256, 259, 262, 265, 266, 271, 277, 280, 294, 315], "plan": [115, 119, 121, 128, 146, 187, 189, 231, 233, 234, 235, 237, 238, 240, 241, 242, 243, 244, 247, 248, 250, 251, 253, 256, 259, 261, 267, 269, 272], "getposition2": 115, "upto": [116, 309], "mileston": [116, 264], "toward": [116, 246, 267, 293, 294, 296], "occlus": [116, 296], "complic": [116, 118, 136, 159, 162, 172, 192, 244, 247, 256, 259, 262, 295], "hood": [116, 118], "took": [117, 128, 130, 181, 184, 201, 207, 216, 240, 243, 245, 249, 252, 266, 272], "terminologi": [117, 171], "nevertheless": 117, "rigid": [117, 170, 270], "backend": 117, "frontend": 117, "rest": [117, 148, 180, 245], "un": [117, 119], "confid": [117, 272], "restrict": [118, 179, 186, 294], "expect": [118, 120, 122, 126, 135, 162, 179, 180, 182, 203, 206, 242, 253, 260, 266, 270, 271, 274, 276, 279, 283, 296], "poor": [118, 149], "6th": 119, "period": [119, 128, 134, 135, 137, 140, 141, 169, 171, 181, 270, 272, 276, 281, 292], "own": [119, 148, 150, 180, 181, 250, 253, 291, 294, 296], "jump": [119, 179, 277], "quickli": [119, 226], "transln_vector": 119, "preserv": 119, "gamma": [119, 296], "beta": [119, 281], "get_r": 119, "new_po": 119, "quadrup": 119, "haven": [119, 153, 259, 262, 268], "7th": [120, 181], "thought": [120, 143, 180, 181, 183, 186, 219, 222, 238, 251, 256, 259, 265, 268], "fortun": [120, 140, 141, 146, 147, 149, 150, 152, 159, 176, 234, 243, 246, 253, 257, 262], "_add_to_scen": 120, "inherit": [120, 145, 168, 170, 240], "eager": 120, "clearer": [121, 261], "merg": [121, 124, 127, 131, 135, 146, 147, 150, 153, 156, 158, 161, 162, 163, 165, 168, 169, 170, 171, 172, 176, 180, 185, 189, 191, 193, 194, 196, 197, 198, 211, 212, 216, 217, 218, 224, 226, 227, 228, 239, 242, 243, 251, 252, 257, 263, 264, 265, 268, 269, 270, 272, 291, 307, 310, 313, 315], "8th": 122, "refactor": [122, 136, 152, 159, 167, 170, 174, 184, 250, 253, 254, 262, 267, 268, 269, 272, 303, 310, 311, 313], "aid": [122, 272], "Its": [122, 272], "workaround": [122, 145, 156, 235, 247, 259, 268], "broke": 122, "weird": [122, 131, 252], "month": [122, 135, 181, 241, 259, 268], "anymor": [122, 256], "charact": [122, 136, 174, 176, 181, 264, 294, 310, 311, 315], "search": [122, 169, 179, 181, 204, 219, 238, 268, 296], "extrem": 122, "rhombocuboctahedron": [123, 308], "vtk9": [123, 308], "melina": [123, 133, 308, 309], "raglin": [123, 133, 308, 309], "tushar": [123, 139, 308, 310], "past": [124, 140, 148, 149, 152, 155, 238, 296, 315], "codebas": [124, 126, 148, 150, 216, 243], "sdf_actor": [124, 126], "9th": 125, "uncontrol": [125, 128], "mismatch": [125, 312], "gsoc": [126, 127, 131, 132, 134, 135, 136, 137, 140, 164, 165, 166, 171, 172, 173, 174, 179, 185, 227, 231, 241, 248, 250, 253, 254, 256, 263, 265, 266, 269, 303, 309, 310, 311, 312, 313], "THe": 126, "tremend": [126, 227], "despit": [126, 132, 182, 267], "went": [126, 137, 179, 180, 181, 184, 204, 234, 259, 269], "smoothli": [126, 137, 143, 179, 252, 261], "immers": [127, 135, 181, 277], "Being": [127, 258, 265], "10th": 128, "3rd": 128, "todai": [128, 134, 137, 199, 202, 244, 247, 250, 256, 259, 265, 269], "futur": [128, 147, 149, 150, 153, 156, 159, 172, 184, 243, 256, 268, 270, 272, 277, 315], "conveni": 128, "standalon": [128, 130, 136, 303], "discontinu": 128, "gooch": [129, 135], "11th": 130, "lack": [130, 135, 136, 153, 156, 159, 173, 181, 228, 236, 238, 268, 272], "awar": 130, "kept": [130, 180, 222, 227], "wrong": [130, 140, 143, 152, 153, 181, 247], "brows": [130, 134], "forum": [130, 160, 179, 219], "mind": [130, 181, 183, 233, 259, 262, 265], "prism": [130, 167, 177, 274, 290, 308, 311, 312], "brief": [130, 147, 243, 247, 315], "glimps": [130, 232], "fellow": [130, 136, 182, 232, 248, 250, 253, 256, 266], "12th": 131, "smash": 131, "he": [131, 180, 181, 182, 226, 247], "probabl": [131, 144, 147, 152, 153, 155, 156, 158, 182, 233, 247, 253, 259, 270], "formal": [131, 263], "silhouett": 132, "inbuilt": 132, "across": [133, 140, 149, 174, 176, 179, 180, 278, 309], "anousheh": [133, 230, 309, 313], "mark": [134, 137, 264, 315], "altogeth": 134, "grown": 134, "person": [134, 155, 174], "especi": [134, 272], "immens": [134, 137, 255], "mentorship": 134, "love": [134, 179, 181], "contribut": [134, 137, 140, 179, 180, 181, 182, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313], "semest": [134, 180, 243], "filemenu": [134, 267], "submiss": [134, 242], "organis": [135, 136, 142, 172, 173, 226, 227, 228, 268, 270, 272, 294], "overwhelm": [135, 180], "stun": 135, "spheremap": 135, "toon": [135, 137], "bias": 135, "leverag": 135, "hardwar": 135, "devot": 135, "unsatisfactori": 135, "distort": [135, 152, 155, 174, 250, 268], "priorit": 135, "hand": [135, 141, 170, 172, 180, 248, 256], "flexibl": [135, 291], "hair": 135, "benchmark": [135, 193, 202], "multisdf": 135, "296": 135, "familiar": [135, 137, 179], "267": [135, 308], "websit": [135, 136, 161, 165, 172, 173, 174, 180, 181, 226, 227, 228, 230, 246, 259, 268, 270, 272, 303, 310, 313, 315], "week": [135, 136, 149, 155, 172, 173, 174, 226, 227, 228, 268, 270, 272, 303, 312, 313], "outlin": [135, 170], "commonli": 136, "tradition": 136, "textbox": [136, 258, 264, 272, 294, 311], "term": [136, 144, 180, 181, 247, 281], "246": [136, 308], "navig": [136, 143], "aren": [136, 219, 303], "231": [136, 308], "overflow": [136, 150, 156, 165, 258, 264, 267, 272, 294, 307, 308, 310, 311], "listboxitem2d": [136, 297, 307], "filemenu2d": [136, 272, 297, 303], "tackl": [136, 240, 258, 269, 272], "modif": [136, 140, 143, 174, 206, 234, 237, 281, 316], "accept": [136, 180, 181, 227, 276, 281], "clip": [136, 186, 187, 212, 291, 294, 296, 308, 310], "268": [136, 308], "exhaust": 136, "287": [136, 309], "1xjcg1tl5zrjzdyi8v76leyzt_maxgp0kob7ozixksta": 136, "edit": [136, 179, 223, 264, 294, 315], "usp": [136, 140], "hard": [136, 150, 152, 176, 179, 198, 211, 213, 214], "aspect": [136, 153, 155, 156, 174, 212, 264, 272, 274, 284, 294, 295], "285": [136, 303], "filesystem": 136, "rewritten": [136, 277], "intact": 136, "281": [136, 309], "286": [136, 310], "clippingoverflow": 136, "tabpanel2d": [136, 297], "scrollbarsupd": 136, "journei": [136, 226, 227, 228, 231, 232, 256, 272, 313], "itsopen": 136, "googl": [137, 143, 162, 181, 232, 311], "opportun": [137, 231, 232, 233, 243, 252, 315], "programm": 137, "member": [137, 142, 157, 163, 165, 294], "throughout": [137, 244], "2021": [138, 149, 172, 173, 180, 298, 312, 313], "migrat": [139, 230, 310, 313], "charl": [139, 310], "poirier": [139, 310], "sajag": [139, 142, 167, 173, 177, 310, 311, 312], "swami": [139, 142, 167, 173, 177, 310, 311, 312], "pietro": [139, 310], "astolfi": [139, 310], "sanjai": [139, 310], "marreddi": [139, 310], "aman": [139, 310], "soni": [139, 310], "bruno": [140, 167, 177, 182, 230, 244, 247, 256, 259, 311, 312, 313], "messia": [140, 167, 177, 230, 311, 312, 313], "ph": 140, "brazil": 140, "bond": [140, 141, 148, 151, 160, 173, 287, 311], "paragraph": 140, "propos": [140, 141, 143, 146, 179, 180, 181, 248, 265, 266, 313, 315], "internet": [140, 149, 155, 174, 179], "spec": 140, "hous": [140, 179], "discov": [140, 143, 146, 164, 181, 185, 202, 211, 234, 237, 255], "432": [140, 146, 164, 174, 175, 312], "422": [140, 146, 147, 311], "antriksh": [141, 167, 172, 177, 230, 272, 303, 311, 312, 313], "misri": [141, 167, 172, 177, 230, 303, 311, 312, 313], "mit": 141, "pune": 141, "primari": [141, 147, 172, 179, 272], "stretch": [141, 142, 172, 173, 174, 226, 228, 268, 272], "seen": [141, 224, 226, 268, 270, 290, 315], "movi": 141, "guardian": 141, "galaxi": 141, "hinder": [141, 246], "introductori": [141, 214, 225], "compli": 141, "windowresizeev": [141, 150, 159, 172], "invok": [141, 150, 153, 176, 192, 223, 274, 292], "partial": [141, 190, 212, 265, 271, 312, 315], "functool": [141, 265], "sophomor": 142, "indian": [142, 180, 181], "technologi": [142, 180, 181], "roorke": [142, 180], "shall": [142, 154, 200, 268, 316], "protein": [142, 145, 154, 157, 173, 287], "richardson": [142, 173, 287], "aka": [142, 154], "ribbon": [142, 145, 148, 151, 157, 160, 163, 169, 172, 173, 297], "diagram": [142, 145, 173], "molecular": [142, 151, 154, 157, 160, 163, 166, 169, 173, 177, 297, 312], "expand": [142, 150, 153, 290, 313], "stick": [142, 148, 154, 173, 297], "wire": [142, 173], "pipe": [142, 149, 173], "plank": [142, 173], "acquaint": [142, 232], "learnt": 142, "vision": 142, "pars": [142, 145], "pdb": [142, 145], "pdbx": [142, 145], "pro": [142, 185], "con": [142, 185], "upon": [142, 163, 264, 272], "docstr": [142, 164, 189, 191, 280, 303, 307, 312, 313, 315], "syntax": [142, 199], "colleg": [142, 180, 181, 194, 201], "courtesi": [142, 157], "covid": 142, "backbon": [142, 173], "1mb0": 142, "carbon": 142, "vtkproteinribbonfilt": [142, 145, 148, 151, 157, 173], "prove": [142, 145, 171, 181, 255], "au": [142, 145, 148, 151, 154, 157, 160, 163, 166, 169, 171], "revoir": [142, 145, 148, 151, 154, 157, 160, 163, 166, 169, 171], "437": [143, 146, 149, 155, 164, 175, 176, 313], "phd": 143, "cheapest": 143, "price": [143, 259, 310], "convinc": [143, 152], "brazilian": 143, "friend": [143, 179, 180], "budget": 143, "scenario": [143, 146, 147, 149, 174, 243, 268], "resid": [143, 174], "bandwidth": [143, 174, 262, 265, 268, 269], "circumv": [143, 174], "gil": [143, 155, 174], "alon": [143, 174, 259], "enough": [143, 149, 174, 179, 180, 247, 259, 268], "cpu": [143, 227, 259], "uncoupl": [143, 174], "believ": [143, 179], "protocol": [143, 149, 174], "myriad": 143, "hangout": 143, "econom": 143, "hardest": 143, "webserv": [143, 292], "technic": [143, 183], "kind": [143, 155, 173, 174, 181, 207, 212, 231, 250, 268, 270, 294], "unnecessari": [143, 155, 173], "duplic": [143, 149, 290, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 315], "economi": 143, "trick": [143, 182, 250], "older": [143, 182, 261, 267, 272], "stage": [143, 227, 233, 245, 251, 261, 265, 268], "saw": [143, 146, 182], "l101": 143, "raw_arr_buff": 143, "new_data": 143, "explan": [143, 244, 251], "bad": [143, 265, 268], "demystifi": 143, "sharedctyp": 143, "stupend": 143, "memoryview": 143, "memview": 143, "arr_buff": 143, "arr_buffer_uint8": 143, "new_data_uint8": 143, "cast": [143, 312], "rescu": 143, "arr_uint8_repr": 143, "ctypeslib": 143, "as_arrai": 143, "behav": [143, 174, 176, 205, 276, 294], "spawm": [143, 146], "sai": [143, 179, 182, 268, 280, 294, 315], "uniti": [144, 179, 181], "unreal": [144, 181], "customiz": [144, 147, 237], "css": [144, 147], "getter": [144, 261, 264, 272, 303], "watcher": [144, 147, 150, 172, 303], "monitor": [144, 150, 155, 172, 174], "fatal": 144, "error": [144, 181, 185, 186, 189, 194, 212, 216, 219, 235, 238, 252, 259, 267, 270, 275, 279, 281, 285, 291, 300, 307, 310, 313], "sideeffect": 144, "wherein": [144, 162, 172], "faulthandl": 144, "suppress": 144, "adapt": [144, 156, 172, 223, 313], "preview": [145, 148, 153, 209, 213, 218, 220, 224], "3pgk": 145, "space_filling_model": 145, "myself": [145, 250, 251, 259, 268], "atom": [145, 151, 160, 173, 287], "biopython": 145, "vtkmoleculereaderbas": 145, "unsuccess": [145, 151, 154, 160, 181], "endeavour": 145, "maker": 146, "helio": [146, 155, 158, 161, 174], "hour": [146, 181, 247], "071dab85": 146, "unrel": 146, "subprocess": [146, 149], "popen": [146, 149, 313], "shell": [146, 149], "unlink": [146, 149], "flawless": 146, "issue38119": [146, 292], "cpython": [146, 149], "21516": [146, 149], "monkei": [146, 174, 292], "patch": [146, 174, 292, 310, 312], "meanwhil": [146, 149, 152, 251, 264], "resource_track": [146, 149, 292], "38119": [146, 149], "revolv": [147, 150, 267], "redesign": [147, 227], "cellshap": 147, "filedialog2d": 147, "briefli": [147, 231], "job": [147, 247, 268], "studi": [147, 164, 193, 244], "contour": [147, 304], "meant": [147, 153, 281], "tax": 147, "million": [147, 174], "interestingli": 147, "tripl": [148, 287], "presenc": 148, "interatom": [148, 287], "intrigu": 148, "molecul": [148, 151, 160, 169, 173, 270, 297], "ethan": 148, "ethen": 148, "ethyn": 148, "vtkmolecul": [148, 151, 287], "vtksimplebondperceiv": [148, 151, 173, 287], "vtkmoleculemapp": [148, 151], "vtkperiodict": [148, 151, 287], "great": [148, 181, 183, 186, 219, 231, 233], "crucial": 148, "utilis": 148, "predict": [148, 247, 274, 275], "resolv": [148, 150, 160, 170, 212, 217, 226, 234, 237, 243, 249, 252, 255, 258, 267, 272, 303, 304, 311, 313], "extent": 148, "inabl": 148, "blob": [149, 170, 185], "b1e985": 149, "l20": 149, "mess": [149, 181], "obviou": [149, 162, 248], "mayb": [149, 180, 256, 259, 266, 271, 295], "socket": 149, "abc": [149, 292], "genericimagebuffermanag": [149, 297], "create_mem_resourc": [149, 292, 297], "imagebuffermanag": [149, 292], "load_mem_resourc": [149, 292, 297], "sketch": [149, 175], "abstractmethod": 149, "num_buff": [149, 292], "use_shared_mem": [149, 292], "imagebuffermang": 149, "440a39d427822096679ba384c7d1d9a362dab061": 149, "l491": 149, "info_buffer_s": 149, "_use_shared_mem": 149, "omit": 149, "next_buffer_index": [149, 292, 297], "info_buffer_repr": 149, "buffer_index": [149, 292, 297], "write_into": [149, 292, 297], "np_arr": [149, 292], "buffer_s": 149, "get_current_fram": [149, 292, 297], "image_buffer_repr": 149, "get_jpeg": [149, 292, 297], "image_encod": 149, "tobyt": 149, "async_get_jpeg": [149, 292, 297], "rawarrayimagebuffermanag": [149, 297], "sharedmemimagebuffermanag": [149, 297], "dry": 149, "readabl": [149, 221, 225, 239], "circularqueu": [149, 292], "violat": 149, "tail": [149, 292, 297], "busi": [149, 316], "get_lock": 149, "peculiar": [149, 258], "358402e": 149, "weel": [149, 292], "ctrl": [149, 195, 226, 292], "test_stream": 149, "steam": 149, "app_async": 149, "problemat": [149, 162], "mitig": [149, 259, 268], "event_id": [149, 292], "mouse_mov": [149, 292], "mouse_weel": [149, 292], "anywher": 149, "chose": [149, 150, 181], "situat": [149, 267], "realpython": 149, "shared_memori": 149, "shm_a": 149, "command_str": [149, 292, 297], "shm_b": 149, "stdout": 149, "stderr": 149, "nstdout": 149, "nstderr": 149, "l776": 149, "l112": 149, "l296": 149, "souli": 149, "apr": 149, "towardsdatasci": 149, "9062272e6bdc": 149, "jun": 149, "corrupt": [149, 176], "archiv": [149, 181, 289], "msg22935": 149, "388287": 149, "tracker": 149, "msg388287": 149, "bpo": 149, "shmem": 149, "vinay0410": 149, "stuff": [150, 157, 168, 174, 176, 179, 181], "led": [150, 179, 181, 208, 245, 252, 258, 267, 272], "meantim": 150, "primarili": [150, 156, 172, 189], "trigger": [150, 172, 183, 186, 256, 291], "ambigu": 150, "unmonitor": 150, "automat": [150, 162, 176, 179, 188, 193, 198, 226, 237, 249, 252, 258, 266, 270, 272, 274, 276, 294, 295, 296, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 315], "accordion": [150, 172], "treenode2d": [150, 153, 159, 165], "children": [150, 156, 162, 172], "chow": 150, "panle2d": 150, "retain": [150, 172, 316], "fourth": [151, 295], "chemic": [151, 173], "obelisk": [151, 287], "molecular_viz_vtk": 151, "potenti": [151, 256, 272], "vtkpdbreader": 151, "endeavor": [151, 272], "confound": 151, "8c670c2": 152, "fall": 152, "silent": 152, "troublesom": 152, "4086": 152, "byte": [152, 277, 282, 292], "independ": [152, 226, 227, 240, 243, 247, 249, 272, 304], "multidimensionalbuff": [152, 292], "max_siz": [152, 292], "uniformtool": 152, "424": [152, 182], "characterist": 152, "usefulli": 152, "group": [152, 180, 185, 195, 212, 217, 219, 226, 227, 274, 276, 279, 291, 303], "scientist": 152, "minimum": [152, 155, 174, 177, 207, 227, 259, 276, 277, 282, 294, 312], "embed": [152, 155, 174, 279], "pymd": [152, 155, 174], "perfect": [152, 179, 226], "heliospr": 152, "submodul": 153, "conflict": [153, 170, 258, 272, 311, 315], "reveal": [153, 265], "brainstorm": 153, "annoi": 153, "attent": [153, 179, 181, 238, 253, 262, 264, 267], "beyond": [153, 184, 234, 256, 258, 272], "secondli": 153, "fluid": 153, "gone": 153, "guess": [153, 179, 250], "fifth": 154, "calott": [154, 173], "cpk": [154, 287], "mid": 154, "proteinribbonfilt": [154, 297], "hashtag": [155, 174], "social": [155, 174], "insight": [155, 174, 272], "epidem": [155, 174], "spread": [155, 174, 235], "kuramoto": [155, 174], "di": [155, 174], "diseas": [155, 174], "recomput": [155, 174], "shouldn": [155, 162, 213, 272], "wrapper": [155, 174], "rememb": [155, 179, 315], "unfeas": 155, "hundr": [155, 174, 175, 176, 227], "cugraph": [155, 158, 174], "forceatla": [155, 174], "networkdraw": 155, "weight": [155, 213, 228, 247, 270, 282], "consum": [155, 169, 172, 179, 198, 281, 292], "shmmanagermultiarrai": 155, "pain": 155, "inter": [155, 176], "networklayoutipcservercalc": 155, "networklayoutipcrend": 155, "bore": 155, "_check_and_sync": 155, "mde": [155, 174], "l180": 155, "test_mde_layout": 155, "l43": 155, "until": [155, 175, 179, 247, 253, 272, 281], "atla": [155, 168, 170, 176], "viz_helios_md": 155, "anchor": [155, 274, 294, 297], "forceatlas2": [155, 158, 174], "cuda": [155, 174], "flicker": [155, 174], "a94e22dbc2854ec87b8c934f6cabdf48931dc279": 155, "flaw": [156, 198, 234, 250, 272, 303], "restructur": [156, 172, 202, 225, 261], "indirectli": [156, 249, 258], "circularli": 156, "add_to_scen": [156, 274, 276, 294, 297], "exceed": [156, 189, 207], "came": [156, 179, 180, 183, 184, 247, 258], "till": [156, 180, 181, 227], "sixth": [157, 270], "generalis": [157, 209], "452": [157, 163, 166, 169, 171, 173, 312], "362": [157, 163, 169, 173, 290, 312], "grate": [157, 232], "ipc": [158, 174, 175, 176], "ipclayout": [158, 175], "evolut": 158, "record_posit": 158, "seem": [158, 162, 169, 171, 176, 183, 218, 219, 222, 235, 238, 244, 247, 250, 258, 259, 268, 310], "mostli": [159, 214], "indent": 159, "feedback": [159, 163, 171, 233, 236, 239, 242, 245, 248, 254, 267], "443": [159, 162, 172, 313], "comment": [159, 162, 248, 257, 260, 280, 307, 310, 311, 313], "442": [159, 162, 311], "reus": [159, 239, 274], "has_bord": [159, 294], "wast": [159, 182, 219, 222], "seventh": 160, "add_atom": [160, 297], "462": [160, 163, 169, 173], "discours": [160, 219], "gap": [160, 198], "vtkproperti": 160, "backfacecul": 160, "frontfacecul": 160, "onlin": [161, 174, 277], "tomorrow": [161, 164, 175], "besid": [162, 176, 207, 227, 257, 270], "windowsresizeev": 162, "ignor": [162, 274, 284, 304], "leav": [162, 256, 259, 262, 268, 277, 313, 315], "redon": 162, "is_ui": [162, 297], "wouldn": 162, "mistak": 162, "wrap_overflow": [162, 297], "freetyp": [162, 165, 168, 170, 176], "desktop": 162, "bitmap": [162, 175], "hihgli": 162, "inspir": [162, 179, 180, 181], "difficult": [162, 195, 198, 219, 254, 269], "fortunalt": 162, "eighth": 163, "thursdai": [163, 244, 247], "474": [164, 175, 312], "tree2d": [165, 168, 172, 303], "mobil": [165, 313], "pose": [165, 213, 228, 264, 272, 282], "troubl": [165, 262], "accordion2d": [165, 168, 172], "spinbox2d": [165, 172], "ninth": 166, "optimis": 166, "solvent": [166, 171, 173], "exclud": [166, 173, 277], "se": 166, "bioconda": 166, "msm": 166, "michel": 166, "sanner": 166, "arthur": 166, "olson": 166, "claud": 166, "spehner": 166, "475": [166, 173, 311], "fast": [166, 167, 198, 268, 270, 311], "triangular": [167, 274, 290, 295, 311], "chaudhari": [167, 311], "daniel": [167, 311], "katz": [167, 311], "gurdit": [167, 311], "siyan": [167, 311], "jhalak": [167, 311], "gupta": [167, 311], "mihir": [167, 311], "praneeth": [167, 177, 181, 182, 185, 226, 230, 272, 303, 311, 312, 313], "shetti": [167, 177, 181, 226, 230, 272, 303, 311, 312, 313], "hariharan": [167, 311], "ayappan": [167, 311], "revers": 168, "chunk": [168, 172], "tenth": 169, "archaic": 169, "tad": 169, "intimid": 169, "never": [169, 179, 226, 231, 238], "domain": [169, 252, 303, 313], "reckon": 169, "brought": [170, 181], "email": [170, 179, 180], "string": [170, 206, 228, 274, 275, 277, 279, 281, 282, 283, 285, 286, 287, 291, 292, 293, 294, 296], "3a4fdea8d23207d67431973fe5df1811605c4132": 170, "artist": 170, "l94": 170, "raster": [170, 180], "patheffectrender": 170, "submit": [170, 233, 239, 241, 246, 251], "gist": 170, "eleventh": 171, "waal": [171, 173, 287], "492": [171, 173], "alien": 171, "fruit": 171, "understood": [171, 250], "vtkmarchingcub": 171, "earliest": 171, "sa": [171, 173], "256": [171, 259, 268, 307, 308], "cool": [171, 277], "lai": [172, 226, 267, 274, 284], "480": [172, 174, 312], "479": [172, 312], "486": [172, 313], "460": [172, 243, 303], "themselv": [172, 268], "487": 172, "vtkactor2d": [172, 294], "stall": 172, "491": [172, 312], "398": [172, 240, 243, 272, 303], "ratio": [172, 274, 284, 294, 295, 296, 297], "446": [172, 243], "wathcer": 172, "448": [172, 303], "entiti": [172, 179], "compris": 172, "obvious": 172, "heavi": [172, 206, 259, 274, 291], "pattern": [172, 289], "441": [172, 311], "477": [172, 311], "494": 172, "rebas": [172, 224, 234, 237, 243, 252, 267, 272], "schemat": 173, "polypeptid": 173, "\u03b1": 173, "coil": 173, "\u03b2": 173, "strand": 173, "repetit": [173, 226, 313], "strip": [173, 274, 277, 313], "unclear": 173, "filter": [173, 256, 268, 274], "substanc": 173, "typic": [173, 272], "tube": [173, 274, 287, 304], "vtkopenglmoleculemapp": 173, "chemistri": [173, 287], "proport": [173, 179], "triangul": [173, 274, 290], "macromolecular": 173, "euclidean": [173, 276], "dong": 173, "xu": 173, "yang": 173, "zhang": 173, "miscellan": 173, "emwav": 173, "493": [173, 312], "genesi": 173, "misc": 173, "vdw": [173, 287], "effort": [174, 272], "stadia": 174, "cheap": [174, 270], "reach": [174, 179, 191, 247, 256, 264, 313], "concurr": [174, 176], "emploi": [174, 243, 272], "transfer": 174, "latter": [174, 202], "smothli": 174, "gave": [174, 179, 180, 181, 270], "intel": 174, "hd": 174, "3000": 174, "tun": 174, "finer": 174, "superactor": 174, "host": [174, 292], "heliosnetwork": 174, "consumpt": 174, "489": [174, 176], "476": [174, 311], "tbd": 174, "fake": 174, "demvessia": 174, "demvessiass": 174, "rougier": 174, "2018": [174, 231, 298, 304], "book": [174, 180], "2007": [174, 270, 275], "acm": 174, "san": 174, "diego": 174, "california": 174, "doi": [174, 311], "1145": 174, "1281500": 174, "1281665": 174, "484": 175, "pack": [176, 259, 268], "glyp": [176, 271], "fortunelli": 176, "woke": [176, 180], "viz_huge_amount_of_label": 176, "viz_billboad_label": 176, "tricki": 176, "acrro": 176, "timeinterv": 176, "imposs": [176, 227], "approcach": 176, "strang": [176, 194], "mousewheelforwardev": 176, "mousewheelbackwardev": 176, "glitch": 176, "prfuri": 176, "grant": 176, "stand": [177, 312, 315], "rhombicuboctahedron": [177, 290, 297, 307, 312], "anand": [177, 228, 230, 312, 313], "shivam": [177, 180, 182, 199, 202, 223, 228, 230, 312, 313], "meha": [177, 312], "bhalodiya": [177, 312], "moham": [179, 197, 198, 200, 203, 207, 215, 227, 230, 313], "egypt": 179, "2023": [179, 231, 250, 272, 298, 303], "tanta": 179, "2008": [179, 277], "pc": [179, 297], "128mb": 179, "ram": 179, "ran": [179, 182], "xp": 179, "2013": 179, "answer": [179, 181, 213, 215, 247], "english": 179, "arab": 179, "peopl": [179, 231], "speak": 179, "sens": [179, 235], "amaz": [179, 181], "lucki": 179, "2009": 179, "beg": 179, "touch": [179, 264, 272], "sight": [179, 263], "interior": 179, "poli": [179, 192, 202], "human": [179, 277], "curiou": 179, "cryengin": 179, "udk": 179, "terrain": 179, "pyramid": [179, 274, 308], "languag": [179, 180, 181], "harvard": 179, "cs50": 179, "competit": 179, "heard": [179, 180, 181], "senior": [179, 180], "hit": 179, "fog": 179, "taught": 179, "professor": 179, "v1": [179, 276, 277], "pyopengl": 179, "pygam": 179, "pyglm": 179, "disappoint": [179, 181], "publicli": 179, "scratch": [179, 181, 237, 249], "walk": 179, "sound": 179, "intens": [179, 259, 262, 265, 268, 269, 286], "player": [179, 227], "bilinear": 179, "sequenc": [179, 252, 277, 287, 288, 293, 296], "mummyisland": 179, "recogn": [179, 272, 315], "anki": 179, "godot": [179, 181], "glanc": [179, 236, 258], "lumin": 179, "hors": 179, "felt": [179, 180, 181], "fxaa": 179, "fire": 179, "gaussian": [179, 256, 259, 268], "train": 179, "postpon": [179, 182], "bother": 179, "match": [179, 199, 236, 261, 265, 270, 271, 272, 277, 279], "552": [179, 313], "mission": 179, "pm": [179, 180, 181], "cairo": 179, "timezon": 179, "whatsoev": 179, "dashboard": 179, "stori": 179, "promot": [179, 316], "spam": 179, "conclus": 179, "celebr": 179, "shortli": 179, "receiv": [179, 180, 181, 233, 239, 245, 248, 254, 257, 263, 294], "ever": 179, "2024": [180, 298, 316], "product": [180, 246, 296, 316], "industri": 180, "iit": 180, "teach": 180, "compet": 180, "hackathon": 180, "lost": 180, "enjoy": 180, "enthusiast": 180, "told": [180, 185, 250, 253, 254, 256, 263, 266, 268], "motiv": [180, 181, 250], "octob": 180, "hactoberfest": 180, "him": [180, 182], "shortlist": 180, "android": 180, "kotlin": 180, "hadn": 180, "brush": 180, "remark": [180, 181, 232], "ucsc": 180, "lectur": 180, "victor": [180, 268, 303], "gordon": [180, 270], "straight": 180, "loader": [180, 185, 228], "gltfreader": 180, "forgot": [180, 238], "examin": [180, 272, 277], "somehow": 180, "april": 180, "520": [180, 312], "533": [180, 228, 313], "547": [180, 228, 313], "556": [180, 228, 313], "559": [180, 228, 313], "anxiou": 180, "18th": 180, "reject": [180, 181], "morn": 180, "profil": 180, "dad": 180, "night": 180, "refresh": [180, 181, 294, 313], "shout": 180, "numfocu": 180, "moment": [180, 249, 270], "bless": 180, "gsoc22": [181, 227], "lesson": 181, "javascript": 181, "struggl": [181, 228, 238, 244], "twice": [181, 218, 304], "laptop": 181, "cousin": 181, "brother": 181, "enquir": 181, "academ": 181, "greet": 181, "flood": 181, "whatev": [181, 262, 296], "vacat": [181, 194], "gameplai": 181, "youtub": 181, "brackei": 181, "grab": [181, 207, 294], "ie": [181, 183, 215, 282, 295], "rigidbodi": 181, "replic": [181, 293], "gigabyt": 181, "2g": 181, "megabyt": 181, "inr": 181, "unknown": [181, 198], "playlist": 181, "lightweight": 181, "satisfi": [181, 243], "spend": [181, 186, 214, 259], "surpris": 181, "wherea": 181, "bulki": 181, "mini": 181, "gdscript": 181, "resembl": 181, "drown": 181, "hacktoberfest": 181, "girlscript": 181, "gssoc": 181, "guidanc": [181, 244, 267], "interview": 181, "flow": 181, "consider": [181, 243, 264, 272], "p5": 181, "creativ": 181, "attempt": [181, 264, 267, 303], "rais": [181, 186, 189, 204, 274, 279, 281, 291, 312], "old": [181, 199, 225, 227, 259, 268, 281, 313], "beginn": [181, 214], "analysi": [181, 237, 258, 270, 272, 275], "comfort": 181, "fascin": 181, "hasn": 181, "engag": 181, "newbi": 181, "skill": [181, 233], "disengag": 181, "energi": 181, "enthusiasm": 181, "arriv": 181, "anxieti": 181, "peak": [181, 271, 297, 304, 310, 312, 313], "alarm": 181, "remind": [181, 182], "straightforward": [182, 256, 268], "verifi": [182, 183, 279, 315], "filip": 182, "attend": [182, 250], "604": 182, "movabl": 183, "unintention": 183, "599": [183, 184, 226, 313], "scan": 183, "actor2d": [183, 219, 297], "cleaner": [184, 278], "aris": [184, 186, 267, 270, 272, 316], "deselect": [184, 195, 226, 294, 297], "keyboard": [184, 294], "shortcut": 184, "clamp": [184, 186, 212, 226, 294], "met": [185, 316], "panda3d": 185, "pyrend": 185, "dataclass": 185, "json": [185, 189, 191, 228, 307], "accident": 185, "darker": 185, "602": [185, 228, 313], "asynchron": [185, 228], "var": 185, "typeerror": [185, 281], "subscript": 185, "weren": [185, 189, 203, 207, 212, 238], "gimp": 185, "vtktextur": [185, 201, 247, 274, 283], "get_accessor_data": 185, "prototyp": [186, 192, 210, 228, 313], "alongsid": [186, 294], "quadrant": 186, "li": [186, 274], "th": [187, 276], "612": [187, 313], "613": [187, 313], "seek": [187, 276, 294, 297], "matric": [187, 205, 208, 209, 211, 213, 282], "dig": [187, 235], "newer": 187, "b\u00e9zier": [187, 227, 276], "disappear": [187, 259, 268], "phew": 188, "tediou": 188, "parallelli": 188, "sem": 188, "exam": [188, 246, 272], "off": [188, 198, 222, 267, 274, 296], "aabb": 188, "enhanc": [188, 192, 210, 227, 237, 255, 272, 313], "get_polydata_triangl": [189, 297], "basetextur": 189, "compositetimelin": [190, 193], "617": [190, 227, 313], "mergeabl": [190, 191], "616": [191, 228, 313], "upcom": [192, 232, 234, 237, 243, 246, 251], "left_mouse_click": [192, 226], "sub_timelin": 193, "actors_list": 193, "add_timelin": 193, "unbound": 193, "travel": 194, "load_io": 194, "pallet": 194, "glb": [194, 228], "bufferview": [194, 282], "khronoosgroup": 194, "boxinterleav": 194, "ye": 194, "speculartest": 194, "animatedcub": 194, "normaltangentmirrortest": 194, "animatedtriangl": 194, "specglossvsmetalrough": 194, "nonetyp": 194, "basecolortextur": [194, 282], "cesiummilktruck": 194, "vc": 194, "waterbottl": 194, "animatedmorphcub": [194, 224], "sponza": 194, "scifihelmet": 194, "iridescencemetallicspher": 194, "corset": 194, "texturelinearinterpolationtest": 194, "simplemesh": 194, "lantern": 194, "texturetransformmultitest": 194, "texturesettingstest": 194, "lightspunctuallamp": 194, "damagedhelmet": 194, "cesiumman": [194, 220], "barramundifish": 194, "metalroughspheresnotextur": 194, "environmenttest": 194, "mosquitoinamb": 194, "boxtexturednonpoweroftwo": 194, "brainstem": [194, 224, 228], "simplemorph": 194, "orientationtest": 194, "boxanim": 194, "stainedglasslamp": 194, "texturetransformtest": 194, "clearcoattest": 194, "iridescencelamp": 194, "dragonattenu": 194, "recursiveskeleton": 194, "riggedsimpl": [194, 213, 215], "textureencodingtest": 194, "2cylinderengin": 194, "normaltangenttest": 194, "iridescencedielectricspher": 194, "texturecoordinatetest": 194, "alphablendmodetest": 194, "trianglewithoutindic": 194, "multiuvtest": 194, "boomboxwithax": 194, "20with": 194, "20space": 194, "sheencloth": 194, "toycar": 194, "materialsvariantssho": 194, "iridescentdishwithol": 194, "vertexcolortest": 194, "sheenchair": 194, "fox": [194, 224, 228], "antiquecamera": 194, "transmissiontest": 194, "transmissionroughnesstest": 194, "boxvertexcolor": 194, "reciprocatingsaw": 194, "morphprimitivestest": 194, "metalroughspher": 194, "gearboxassi": 194, "twosidedplan": 194, "buggi": 194, "simplesparseaccessor": 194, "unlittest": 194, "simpleskin": [194, 209, 213], "flighthelmet": [194, 279], "unicod": 194, "e2": 194, "9d": 194, "a4": 194, "bbtest": 194, "avocado": 194, "glamvelvetsofa": 194, "boombox": 194, "emissivestrengthtest": 194, "attenuationtest": 194, "animatedmorphspher": [194, 224], "iridescencesuzann": 194, "pil_imag": 194, "uri": [194, 282], "glb2gltf": 194, "investig": [195, 198, 201, 205, 223, 231, 234, 235, 237, 240, 252, 268, 272, 278, 313], "preced": [195, 276], "631": [196, 227], "626": [196, 197, 200, 313], "finalis": 197, "permit": [197, 278, 316], "reli": [197, 235, 241, 248, 249, 250, 254, 256, 258, 267, 268], "623": [198, 201, 204, 210, 212, 216, 226, 313], "ubuntu": [198, 304, 308, 313], "on_value_chang": 199, "on_moving_slid": 199, "634": [199, 227, 313], "643": [199, 218, 220, 224, 228, 313], "custominterpol": 199, "mousemoveev": [201, 296], "prop": [201, 276, 282, 294, 295], "mipmapon": 201, "interpolateon": 201, "settl": 201, "reopen": 201, "freehand": [201, 204, 207, 212, 226], "tracer": 201, "rotation_slid": [201, 222, 226, 313], "647": [202, 227, 313], "euler": [202, 276, 293], "renam": [202, 274, 281, 304, 309, 312], "draft": [202, 227, 239, 250, 259, 265, 268, 270, 272], "linearinterpol": 203, "smoothen": [203, 210], "645": [204, 207, 226, 313], "zerodivsionerror": 204, "653": [204, 210, 212, 216, 226], "tr": [205, 282], "invertbindmatric": 205, "globaltransformmatric": 205, "ago": [206, 241], "bigger": [206, 216, 259], "slower": 206, "unbind": 206, "compact": 206, "160k": 206, "encount": [206, 234, 237, 240, 243, 246, 248, 252, 257, 258, 267], "vtkimagetrac": [207, 210], "imagesourc": 207, "pure": [207, 219], "architectur": [207, 226], "partialactor": [208, 211], "imit": 210, "drawback": [210, 257, 271], "overcom": [210, 237, 272], "promis": 210, "drawshap": [212, 217, 222, 226, 297, 313], "analyz": [212, 296], "overlapp": 212, "nearer": 212, "throw": [212, 281, 313], "analyse_snapshot": 212, "inversebindmatrix": 213, "short": [213, 256, 289], "undo": 213, "extrus": [214, 274], "irrad": 215, "invert": [215, 307, 312, 313], "skin_mat": 215, "harder": [216, 238], "674": [216, 226, 313], "redund": [216, 222, 272], "in_progress": [216, 226, 313], "mode_panel": [217, 226, 313], "mode_text": [217, 226, 313], "678": [217, 226, 313], "duplicaci": 217, "brighter": [217, 219], "fault": [218, 303, 311, 313], "impress": 218, "elimin": 218, "get_valu": [218, 276, 297], "get_skin_timelin": [218, 224], "grei": [219, 287], "skinmatrix": 220, "inversebindpos": 220, "bonedeform": 220, "currentbonetransform": 220, "parentbonetransform": 220, "parti": 221, "665": [221, 227, 313], "common": [222, 236, 270, 282], "688": [222, 226, 313], "694": [223, 227, 313], "685": [224, 228, 313], "getconsum": 225, "scene_idx": 225, "frustum": [225, 290, 297, 308], "eras": 226, "depict": 226, "wysiwyg": 226, "695": 226, "doodl": 226, "696": 226, "701": [226, 313], "zerodivisionerror": [226, 267, 272, 313], "2022": [226, 227, 228, 270, 298, 313], "abouagour": 227, "rewind": 227, "blank": 227, "transit": [227, 261], "bottleneck": 227, "690": [227, 313], "687": [227, 313], "changer": 227, "inevit": 227, "692": [227, 313], "massiv": 227, "cleanest": 227, "660": 227, "702": 227, "extrud": 227, "661": [227, 313], "594": [227, 313], "597": [227, 313], "591": [79, 82, 227, 313, 314], "598": [227, 313], "equip": 227, "base64": 228, "bin": [228, 279, 282], "timlelin": 228, "though": [228, 259, 265, 268, 270, 271], "condit": [228, 247, 267, 276, 292, 313, 316], "account": [228, 233, 237, 270, 295, 315], "frequent": 228, "estim": [228, 231, 245, 247, 268, 270, 275], "khronosgroup": [228, 279, 291], "setuptool": [230, 313], "hatch": [230, 313], "dwij": [230, 303, 313], "raj": [230, 303, 313], "hari": [230, 303, 313], "francoi": [230, 313], "rheault": [230, 313], "frank": [230, 313], "cerasoli": [230, 313], "johni": [230, 313], "dara": [230, 313], "rohit": [230, 313], "kharsan": [230, 313], "sara": [230, 313], "hamza": [230, 313], "siddharth": [230, 313], "sreekar": [230, 313], "chigurupati": [230, 313], "tania": [230, 233, 250, 270, 303, 313], "castillo": [230, 233, 270, 303, 313], "zhiwen": [230, 313], "shi": [230, 313], "maharshigor": [230, 303, 313], "honour": 231, "profession": 231, "guidelin": [231, 233], "kernel": [231, 235, 247, 256, 259, 268], "webgl": 231, "kde": [231, 247, 250, 253, 256, 259, 262, 265, 268, 303], "macro": 231, "spatial": 231, "benefit": [231, 296], "fbo": [231, 238, 241, 244, 247, 268], "devic": 231, "renderbuff": 231, "thrill": 232, "catch": [232, 243, 281], "regul": 232, "excel": [232, 293], "virtual": 232, "air": 232, "stai": 232, "breakthrough": 232, "hardi": [233, 270], "former": [233, 265], "meticul": 234, "categor": 234, "499": [234, 264, 272, 303], "spinboxui": [234, 258, 261, 264, 272, 294, 303], "rectifi": [234, 267, 272], "devis": [234, 272], "appeal": 234, "signific": [234, 237, 238, 264, 265, 272], "790": [234, 237, 272, 303], "blogpost": [235, 238, 241, 244, 247, 250, 253, 256, 259, 262, 265, 268, 269, 270, 303, 313], "inde": 235, "stencil": 235, "vtktextureobject": [235, 238], "allocate2d": [235, 238], "create2d": 235, "create2dfromraw": 235, "nor": [235, 276, 316], "anyon": [235, 247], "color_textur": [235, 238], "setdatatyp": [235, 238], "vtk_unsigned_char": [235, 238, 244], "datatyp": [235, 238], "unsign": [235, 238, 259, 268, 291], "char": [235, 238, 259], "setinternalformat": [235, 238], "vtk_rgba": [235, 238], "setformat": [235, 238], "setminificationfilt": [235, 238], "minfilt": [235, 238], "setmagnificationfilt": [235, 238], "magfilt": [235, 238], "allocate3d": [235, 238], "wish": [235, 244, 247, 250, 256, 262, 269], "encapsul": [235, 268, 272], "palat": 235, "strict": [235, 279, 285, 291, 316], "expend": 235, "wors": 235, "accomplish": [235, 243, 253], "forward": [235, 238, 243, 310], "luck": [235, 244, 250, 256, 262, 269], "791": [236, 239, 246, 248, 250, 251, 257, 270, 303], "3x1": 236, "aros": [237, 240, 255], "unexpect": [237, 272, 308], "furthermor": 237, "562": [237, 303], "731": [237, 303], "author": [237, 252, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 315], "portion": [237, 272, 289], "dedic": [237, 246, 250, 255, 259, 290], "stakehold": 237, "everybodi": 238, "admit": 238, "framebufferobject": 238, "textureobject": 238, "caught": 238, "setcontext": [238, 241, 244], "vtk_rgb": 238, "spot": 238, "assert": [238, 306], "nullptr": 238, "vtkerrormacro": 238, "push": [238, 315], "realis": [238, 241, 259, 265], "offscreen": [238, 253, 256, 265, 268, 296, 313], "uncertainti": [239, 251, 274, 275, 303], "double_con": [239, 274, 297], "dti_uncertainti": 239, "boundingbox": [240, 272], "settextscalemodetonon": 240, "settextscalemodetoprop": 240, "position1": 240, "misalign": [240, 265, 272], "ongo": [240, 246, 261, 268, 272], "803": [240, 249, 256, 267, 272, 303], "occasion": [240, 264], "malfunct": [240, 272], "cardui": [240, 243, 272], "segreg": 240, "numpy_to_vtk_image_data": [240, 243, 297, 312], "supposedli": [241, 244], "stuck": 241, "appar": [241, 244, 247], "createfbo": 241, "getfboindex": [241, 244], "glgenframebuff": 241, "getcontext": 241, "conclud": [241, 249], "gonna": 241, "addon": 241, "783": [241, 244], "wip": [242, 248, 303, 307, 311, 312, 313], "articl": [242, 315], "amidst": 243, "notabl": [243, 267], "dive": [243, 244, 250], "success": [243, 244, 253, 296], "revisit": [243, 272], "restart": [243, 276, 297], "decis": [243, 249], "obstacl": [243, 248], "eagerli": 243, "comeback": 243, "intric": [244, 267], "recal": [244, 259], "numba": 244, "vtkopenglframebufferobject": 244, "setoffscreenrend": 244, "populateframebuff": 244, "suffer": [244, 250, 256], "getnumberofcolorattach": 244, "synchron": 244, "someon": 244, "torment": 244, "proof": 244, "bumpier": 244, "810": [245, 248, 256, 270, 303], "estimate_sigma": [245, 270], "design_matrix": [245, 270], "tensor_predict": [245, 270], "signal": [245, 247, 270, 274, 275], "refin": [245, 264], "bval": 245, "bvec": 245, "readjust": 245, "812": [246, 303], "roadblock": [246, 261], "bumpi": 247, "simplest": 247, "dug": 247, "deep": [247, 287, 291, 295], "vtkwindowtoimagefilt": [247, 259], "windowtoimagefilt": [247, 268, 297], "setinput": 247, "setinputconnect": 247, "getoutputport": 247, "settextur": 247, "statist": [247, 268, 270], "parametr": [247, 260, 311, 312], "fundament": 247, "infer": 247, "finit": 247, "econometr": 247, "parzen": 247, "rosenblatt": 247, "emanuel": 247, "murrai": 247, "credit": [247, 315], "famou": 247, "margin": [247, 296], "naiv": [247, 270], "bay": 247, "accuraci": [247, 270], "sentenc": 247, "greener": 247, "clarifi": 248, "auto_font_scal": [249, 261, 294, 297], "justifi": [249, 270], "joaodellagli": 250, "graduat": 250, "capston": 250, "polish": [250, 256, 262, 263, 270], "600x600": 250, "modular": [250, 268], "delic": 250, "ruin": 250, "failur": [250, 252, 258], "804": [250, 253, 268], "818": [251, 260, 270, 303], "difficulti": [251, 252], "improp": [252, 267], "814": [252, 303], "769": [252, 272, 313], "redirect": [252, 311], "spoiler": 253, "recap": 253, "sigma": [253, 256, 259, 265, 268, 270, 274, 275, 281], "worth": [253, 265], "window_to_textur": [253, 268], "texture_to_actor": [253, 268], "colormap_to_textur": [253, 268], "flatten": [253, 277], "onscreen": [253, 256, 265], "ponder": 253, "preprocess": 254, "revis": [254, 268], "deeper": [254, 255, 263, 266, 271], "forese": 254, "goe": [254, 294], "delv": [255, 272], "stem": 255, "began": [255, 272], "seamlessli": [255, 261], "treeui": [255, 267, 272], "debat": 256, "tradeoff": 256, "hidden": 256, "prefix": 256, "effectmanag": [256, 265, 268], "onscreen_manag": 256, "kde_actor": [256, 265], "inferno": [256, 268, 274, 275, 277], "laplacian": [256, 268], "hint": [256, 262, 265, 269], "laplac": 256, "sudden": 256, "grayscal": [256, 268, 274], "blur": [256, 259, 268], "shadertoi": 257, "unlik": 257, "trivial": [257, 293], "textbox2d": [258, 297, 310, 311, 313], "test_el": 258, "thorough": [258, 264, 272], "invest": [259, 262], "front": 259, "renorm": 259, "mondai": 259, "tuesdai": 259, "realiti": 259, "rethink": 259, "guarante": [259, 268], "scikit": [259, 268, 277], "tophat": [259, 268], "epanechnikov": [259, 268], "exponenti": [259, 268], "cosin": [259, 268], "trickier": 259, "fidel": 259, "sum_": [259, 268], "report": [259, 265, 268, 281, 296, 303, 313], "gem": [259, 268], "chapter": 259, "ara": [259, 268], "pranckevi\u010diu": [259, 268], "noisi": [259, 268], "13x13": 259, "shift": [261, 264, 267, 272, 292], "dynamic_bbox": [261, 294, 297], "830": [261, 264, 272, 303], "filedialog": [261, 264, 272], "checkout": [261, 315], "832": [261, 267, 272], "sail": 261, "entail": 261, "826": [262, 268, 269], "crash": [262, 264, 268, 304], "m_l": 263, "incorpor": [263, 270], "critic": 264, "emerg": [264, 267, 272], "symbol": [264, 287], "risk": 264, "invalid": 264, "concern": [264, 272], "838": 264, "res_factor": 265, "tex_coord": 265, "normalizedvertexmcvsoutput": 265, "screentextur": 265, "gl_fragcoord": 265, "vulner": [265, 310, 311], "em": [265, 268], "kde_effect": [265, 268], "gain": 265, "shorten": 265, "misus": 265, "l_m": 266, "basi": [266, 270], "literatur": 266, "descoteaux": 266, "descoteaux07": [266, 270], "curvatur": [266, 270], "relationship": [266, 270], "overal": [267, 294], "systemat": 267, "fairli": [267, 270], "methodologi": 267, "slot": [267, 294], "occur": [267, 307], "ascertain": 267, "misposit": [267, 272], "refrain": 267, "sole": [267, 272], "outcom": 267, "sought": 267, "viabl": 267, "nearli": [267, 313], "jo\u00e3o": 268, "dell": [268, 303], "agli": [268, 303], "floriano": 268, "escal": 268, "juli": [268, 309], "vital": 268, "abbrevi": 268, "storag": 268, "unsuccessfulli": 268, "enclos": 268, "vtkrenderwindowinteractor": [268, 296], "callback_funct": 268, "pass_shader_uniforms_to_f": 268, "renderev": 268, "gk_": 268, "textbf": 268, "gk": 268, "p_": 268, "sigma_": [268, 270], "dove": 268, "underflow": 268, "\u00e8ffectmanag": 268, "hid": 268, "door": 268, "explicit": 268, "varieti": 268, "culmin": [268, 272], "six": [268, 271], "sde": 268, "float_to_rgba": 268, "bitenc": 268, "65536": 268, "16777216": 268, "enc": 268, "fract": 268, "yzww": 268, "xxxy": 268, "849": 268, "850": 268, "style": [269, 277, 279, 296, 297, 307, 315], "union": [269, 270], "tunion": 269, "typedhint": 269, "reson": [270, 275], "invas": 270, "neuroscientist": 270, "measur": [270, 275], "biolog": 270, "tissu": 270, "reconstruct": 270, "methodolog": 270, "establish": [270, 287], "amplif": 270, "incorrect": 270, "lambda": [270, 276], "tensormatrix": 270, "scalevsoutput": 270, "scfactor": 270, "converg": 270, "001": 270, "assess": 270, "perturb": [270, 275], "mpa": 270, "basser": [270, 275], "suscept": 270, "dwi": [270, 275], "inher": [270, 272], "quantiti": 270, "premis": 270, "particularli": 270, "covari": [270, 275], "approx": 270, "eta": 270, "varepsilon_1": 270, "tan": [270, 275], "main_dir_uncertainti": [270, 297], "opunion": 270, "sdcone": 270, "semitranspar": 270, "tournier": 270, "pdf": 270, "sensit": [270, 277], "1997": [270, 275], "quantifi": [270, 275], "mr": [270, 275], "ismrm": [270, 275], "vol": [270, 275], "1740": [270, 275], "koai": [270, 275], "pierpaoli": [270, 275], "medicin": [270, 275], "societi": [270, 275], "141": [270, 275], "donald": 270, "fernando": 270, "calamant": 270, "gadian": 270, "alan": 270, "connelli": 270, "mri": 270, "deconvolut": 270, "neuroimag": 270, "1176": 270, "1185": 270, "2004": 270, "kindlmann": 270, "superquadr": [270, 290, 297, 307, 308, 310], "eurograph": 270, "ieee": 270, "tcvg": 270, "154": [270, 307], "impl": 271, "equit": 271, "peak_valu": 271, "uniformli": 271, "tempor": 271, "precalcul": 271, "mipmap": 271, "4x15": 271, "texel": 271, "grai": 271, "sampler": [271, 282], "accordionui": 272, "colorpickerui": 272, "numer": [272, 279, 295], "substanti": [272, 315], "suffic": 272, "scalabl": 272, "span": 272, "underw": 272, "rigor": 272, "distinct": [272, 277], "letter": [272, 315], "baselin": 272, "alphabet": 272, "upward": 272, "defer": 272, "nuanc": 272, "justificaiton": 272, "837": [272, 303], "scrollbarui": 272, "rewrit": 272, "816": 272, "role": 272, "assist": 272, "flash": 272, "broken": [272, 303], "consolid": 272, "toml": [272, 313], "filedialogui": 272, "encompass": 272, "undergo": 272, "approv": 272, "narrow": [272, 315], "cautiou": 272, "sow": 272, "textblockui": 272, "quest": 272, "init": [273, 294, 297], "verbos": [273, 296, 315], "pkg_path": [273, 289], "warnings_origin": 273, "pad_x_neg": 274, "pad_x_po": 274, "pad_y_neg": 274, "pad_y_po": 274, "pad_z_neg": 274, "pad_z_po": 274, "addposit": [274, 297], "getbound": [274, 297], "getcent": [274, 297], "getlength": [274, 297], "getposit": [274, 297], "getvis": [274, 297], "newinst": [274, 297], "shallowcopi": [274, 297], "kwarg": [274, 276, 281, 292, 293], "vtkprop3d": [274, 284, 295], "borrow": 274, "shallow": [274, 291, 295], "elsewher": 274, "remove_from_scen": [274, 276, 297], "picking_tol": 274, "cut": 274, "vtklookupt": [274, 275], "nearest": 274, "neighbor": [274, 284], "toler": [274, 287], "vtkcellpick": 274, "imageactor": [274, 297], "subdivis": 274, "precomput": 274, "butterfli": 274, "surface_actor": 274, "binar": 274, "contour_assembli": 274, "vtkassembli": 274, "tube_sid": 274, "lod_point": 274, "lod_points_s": 274, "spline_subdiv": 274, "replace_strip": 274, "colour": [274, 295], "trilinear": [274, 295], "opaqu": [274, 275, 296], "lodactor": [274, 297], "straighter": 274, "curvier": 274, "approx_polygon_track": 274, "boolean": [274, 294], "cue": 274, "lookup_t": [274, 277], "colorbar": 274, "vtkscalarbaractor": 274, "colorx": 274, "colori": 274, "colorz": 274, "suppli": 274, "4x4": [274, 275], "amplitud": [274, 275], "plain": 274, "n_coeff": [274, 275], "n_vertic": [274, 275], "odfsliceractor": [274, 297], "scalar_color": 274, "sphere_valu": 274, "color_fa": 274, "tensor_actor": 274, "peaks_dir": [274, 275], "peaks_valu": 274, "dec": [274, 277], "peak_actor": 274, "magnitud": 274, "peakactor": [274, 297], "peak_dir": 274, "dot_siz": 274, "dot_actor": 274, "deprec": [274, 277, 291, 297, 303, 304, 307, 308, 309, 310, 311, 312, 313], "expireddeprecationerror": [274, 291, 297], "coral": 274, "facet": 274, "sector": [274, 290], "repeat_sourc": [274, 297], "cylinder_actor": 274, "rinner": 274, "router": 274, "cresolut": 274, "rresolut": 274, "outer": [274, 294], "perimet": 274, "radial": 274, "disk_actor": 274, "sq_actor": 274, "rect_actor": 274, "tip": [274, 290], "cone_actor": 274, "tprism_actor": 274, "rcoh_actor": 274, "pent_actor": 274, "actor_pentagon": 274, "octagon": [274, 290, 308], "oct_actor": 274, "frustum_actor": 274, "spq_actor": 274, "gs_prog": 274, "bb_type": 274, "cylindrical_x": 274, "cylindrical_i": 274, "billboard_actor": 274, "align_cent": 274, "array_lik": [274, 277, 293], "text3d": [274, 312], "7777777777777777": [274, 284, 294, 295], "necessarili": [274, 276, 277, 296], "pad_x": [274, 284], "pad_i": [274, 284], "tightest": [274, 284], "nb_row": [274, 283, 284, 295], "nb_col": [274, 283, 284, 295], "pic": 274, "vtkimageactor": 274, "interp": 274, "texture_actor": 274, "arr": [274, 278, 283, 291, 292, 295, 296], "viz_video_on_plan": 274, "earthactor": 274, "vtktexturedactor": 274, "edge_opac": 274, "tensor_ellipsoid": [274, 297], "deviat": [274, 275], "vtkactor": [275, 276, 282, 287, 291, 294, 295, 312], "x_indic": 275, "y_indic": 275, "z_indic": 275, "inclus": 275, "slice_index": 275, "zaxi": 275, "rgb_standard": [275, 277], "cross_sect": [275, 297], "display_cross_sect": [275, 297], "global_opac": [275, 295, 297], "high_rang": [275, 297], "is_rang": [275, 297], "low_rang": [275, 297], "max_cent": [275, 297], "min_cent": [275, 297], "epsilon_1": 275, "add_static_actor": [276, 297], "add_to_scene_at": [276, 297], "add_update_callback": [276, 297], "callabl": [276, 277, 281, 290, 291, 294], "child_anim": [276, 297], "current_timestamp": [276, 297], "get_color": [276, 297], "get_current_valu": [276, 297], "attrib": 276, "get_keyfram": [276, 297], "get_opac": [276, 297], "get_posit": [276, 297], "get_rot": [276, 297], "as_quat": 276, "get_scal": [276, 297], "is_inside_scene_at": [276, 297], "is_interpolat": [276, 297], "interpolat": 276, "safe": 276, "opposit": [276, 295, 296], "parent_anim": [276, 282, 297], "remove_actor": [276, 297], "remove_anim": [276, 296, 297], "remove_from_scene_at": [276, 297], "set_color_keyfram": [276, 297], "timestamp_1": 276, "color_1": 276, "timestamp_2": 276, "color_2": 276, "color_keyfram": 276, "spline_degre": 276, "1x3": 276, "1x1": 276, "pos_fun": 276, "set_keyfram": [276, 297], "update_interpol": 276, "reiniti": 276, "key_frames_simpl": 276, "key_frames_bezi": 276, "pos_keyfram": 276, "set_opacity_interpol": [276, 297], "set_opacity_keyfram": [276, 297], "opacity_1": 276, "opacity_2": 276, "set_scale_keyfram": [276, 297], "position_1": 276, "position_2": 276, "set_rotation_as_vector": [276, 297], "set_scale_interpol": [276, 297], "scale_1": 276, "scale_2": 276, "scale_keyfram": 276, "static_actor": [276, 297], "update_dur": [276, 297], "update_motion_path": [276, 297], "vtkcamera": [276, 282], "get_foc": [276, 297], "get_view_up": [276, 297], "set_foc": [276, 297], "focal_1": 276, "focal_po": 276, "set_view_up": [276, 297], "set_view_up_interpol": [276, 297], "set_view_up_keyfram": [276, 297], "view_up_1": 276, "view_up_2": 276, "current_tim": [276, 294, 297], "include_last": 276, "include_first": 276, "tau": 276, "v0": [276, 298, 315], "consecut": [276, 292], "rgb2space": 276, "space2rgb": 276, "has_playback_panel": [276, 297], "max_peel": [276, 296], "show_panel": 276, "peel": [276, 296], "seek_perc": [276, 297], "percent": 276, "lookupt": [277, 297], "na": 277, "nd": 277, "boi": 277, "undirect": 277, "glu": 277, "mobiu": 277, "crosscap": 277, "roman": 277, "steiner": 277, "homeomorph": 277, "pinkal": 277, "singular": 277, "visit": 277, "brown": 277, "cad": 277, "rp2color": 277, "cagatai": 277, "demiralp": 277, "matlab": [277, 293], "boys_standard": 277, "maptlotlib": 277, "pyplot": 277, "jet": 277, "accent": 277, "often": [277, 315], "mislead": 277, "bg": 277, "maxim": 277, "perceptu": 277, "percept": 277, "farthest": 277, "greedi": 277, "rbg": 277, "75862069": 277, "03448276": 277, "89655172": 277, "17241379": 277, "tim": 277, "holi": 277, "mathwork": 277, "matlabcentr": 277, "fileexchang": 277, "29702": 277, "2010": 277, "feb": 277, "2011": 277, "hexadecim": [277, 307, 308], "hexcod": 277, "hash": [277, 289, 315], "ffffff": 277, "denot": 277, "stride": [277, 282, 297], "multidimension": [277, 292], "instanti": 277, "__new__": 277, "fortran": 277, "transpos": 277, "c_contigu": 277, "owndata": 277, "writeabl": 277, "flat": [277, 286, 297], "todo": [277, 294], "flatit": 277, "items": [277, 297], "nbyte": [277, 297], "ndim": [277, 297], "contigu": 277, "impli": [277, 316], "ctype": [277, 297], "unchang": 277, "garbag": 277, "alia": [277, 313], "keyword": [277, 281, 293, 307, 313], "0e": 277, "nan": 277, "5e": 277, "323": 277, "int_": 277, "d50": 277, "d55": 277, "d65": 277, "d75": 277, "NOT": [277, 316], "grdevic": 277, "convertcolor": 277, "cie": 277, "xyzcolor": 277, "apertur": 277, "srgb": 277, "iec": 277, "61966": 277, "1999": 277, "colorspac": 277, "fig": 278, "dpi": [278, 283, 296, 313], "flip_up_down": 278, "inch": [278, 283, 296], "matlplotlib": 278, "safest": 278, "savefig": 278, "icar": 278, "univ": 278, "lille1": 278, "fr": 278, "drupal": 278, "1141": 278, "tostring_argb": 278, "stabl": 278, "bytes_or_buff": [279, 285, 291], "decod": [279, 285, 291], "__str__": [279, 285, 291], "repr": [279, 285, 291], "getdefaultencod": [279, 285, 291], "total_length": 279, "progressbar": 279, "fsrc": 279, "fdst": 279, "16384": 279, "stored_sha256": 279, "sha": [279, 307], "checksum": 279, "data_s": 279, "log": [279, 296], "fetchererror": 279, "draco": 279, "fetech": 279, "informationinterdisciplinari": 279, "suffix_typ": 279, "ext": [279, 304, 315], "suffix": 279, "skybox_0": 279, "skybox_1": 279, "nc": 279, "negc": 279, "skybox_posx": 279, "skybox_negi": 279, "skybox_right": 279, "skybox_front": 279, "infin": 279, "model_nam": 279, "compil": [280, 281, 313], "func": [280, 281, 290], "markup": 280, "doctest": [280, 281, 315], "have_amodul": 280, "have_bmodul": 280, "scope": [280, 315], "nipi": 281, "copyright": [281, 308, 315, 316], "licens": [281, 315], "runtimeerror": 281, "expir": 281, "deprecationwarn": [281, 304], "version_str": 281, "pkg_version_str": 281, "__version__": [281, 315], "version_cmp": 281, "0dev": 281, "version_compar": 281, "warn_class": 281, "error_class": 281, "decor": [281, 297, 307], "warning_class": 281, "old_nam": 281, "new_nam": 281, "arg_in_kwarg": 281, "signatur": 281, "thereof": 281, "relax": 281, "astropi": 281, "sig": 281, "apply_morph_vertic": [282, 297], "apply_skin_matrix": [282, 297], "joint_matric": 282, "actor_index": 282, "skinnig": 282, "join_matric": 282, "generate_tmatrix": [282, 297], "transf": 282, "ransform": 282, "get_acc_data": [282, 297], "acc_id": 282, "accessor": 282, "buffer_arrai": 282, "get_anim": [282, 297], "get_buff_arrai": [282, 297], "buff_id": 282, "d_type": 282, "byte_length": 282, "byte_offset": 282, "byte_strid": 282, "out_arr": 282, "get_joint_actor": [282, 297], "with_transform": 282, "get_materi": [282, 297], "mat_id": 282, "get_matrix_from_sampl": [282, 297], "anim_channel": 282, "gltflib": 282, "get_morph_data": [282, 297], "mesh_id": 282, "get_sampler_data": [282, 297], "node_id": 282, "transform_typ": 282, "sampler_data": 282, "get_skin_data": [282, 297], "skin_id": 282, "joint_nod": 282, "inv_bind_matrix": 282, "get_textur": [282, 297], "tex_id": 282, "atextur": 282, "inspect_scen": [282, 297], "scene_id": 282, "load_camera": [282, 297], "camera_id": 282, "transform_mat": 282, "load_mesh": [282, 297], "root_anim": 282, "transverse_anim": [282, 297], "bone_id": 282, "parent_bone_deform": 282, "parent_bone_transform": 282, "transverse_bon": [282, 297], "channel_nam": 282, "transverse_channel": [282, 297], "transverse_nod": [282, 297], "nextnode_id": 282, "is_joint": 282, "gltf2": 282, "tcoord": [282, 291, 295], "topologi": 282, "prim": [282, 307], "comp_typ": 282, "accssor_typ": 282, "objecomp_typ": 282, "byteoffset": 282, "interpolate_on": 283, "mipmap_on": 283, "tif": 283, "tiff": 283, "use_pillow": 283, "pillow": [283, 313], "compression_typ": 283, "deflat": 283, "lzw": 283, "imageio": 283, "vtp": [283, 310], "color_array_nam": 283, "sheet_path": 283, "compute_posit": [284, 297], "_actor": 284, "lie": 284, "compute_s": [284, 297], "get_cells_shap": [284, 297], "glossi": 286, "anisotropic_direct": 286, "scatter": 286, "principled_param": 286, "ambient_level": 286, "ambient_color": 286, "diffuse_level": 286, "diffuse_color": 286, "specular_level": 286, "specular_color": 286, "specular_pow": 286, "gouraud": 286, "ambient": 286, "atomic_numb": [287, 297], "coord": [287, 288, 290, 294], "atom_nam": 287, "residue_seq": 287, "helix": 287, "is_hetatm": 287, "residu": 287, "heteroatom": 287, "total_num_atom": [287, 297], "total_num_bond": [287, 297], "eg": 287, "coval": 287, "atom_color": [287, 297], "atomicnumb": 287, "element_nam": [287, 297], "insensit": 287, "atomic_radiu": [287, 297], "radius_typ": 287, "\u00e5": 287, "atomic_symbol": [287, 297], "atomic_num": 287, "x_coord": 287, "y_coord": 287, "z_coord": 287, "atom1_index": 287, "atom2_index": 287, "bond_ord": 287, "errat": 287, "atom_index": 287, "belong": [287, 294], "whom": 287, "atom_num": 287, "atom_coordin": 287, "bond_index": 287, "molecule1": 287, "molecule2": 287, "valenc": 287, "hybrid": 287, "aromat": 287, "colormod": 287, "molecule_actor": 287, "corei": 287, "paul": 287, "amino": 287, "acid": 287, "peptid": 287, "instrument": 287, "1953": 287, "621": [287, 313], "627": [287, 313], "atom_scale_factor": 287, "bond_thick": 287, "multiple_bond": 287, "dark": 287, "turner": 287, "chem": 287, "educ": 287, "1971": 287, "407": [287, 307, 311], "rubbon": 287, "anatomi": 287, "taxonomi": 287, "1981": 287, "167": [287, 307], "339": [287, 310], "bbox_actor": 287, "disp_xi": 288, "sc": 288, "pickable_off": [288, 297], "pickable_on": [288, 297], "selectable_on": [288, 297], "update_selection_typ": [288, 297], "commit_hash": 289, "substitut": [289, 291, 316], "archive_subst_hash": 289, "truncat": 289, "hash_from": 289, "hash_str": 289, "func_arg": 290, "big_vertic": 290, "big_triangl": 290, "big_color": 290, "have_tiled_vert": 290, "big_cent": 290, "symmetric642": 290, "symmetric724": 290, "sphere_nam": 290, "pyramid_vert": 290, "icosahedron": [290, 307], "icosahedron_vertic": 290, "icosahedron_mesh": 290, "glsl_code": 291, "shader_fil": 291, "glslang": 291, "reimplement": 291, "shader_typ": 291, "valuepass": 291, "keep_default": 291, "replace_first": 291, "replace_al": 291, "shaders_in_vtk": 291, "prim_id": 291, "tag": [291, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 315], "caller": 291, "updateshaderev": 291, "vtkcommand": 291, "nightli": 291, "classvtkobject": 291, "func_call1": 291, "func_call2": 291, "removeobserv": 291, "test_valu": 291, "callbacklow": 291, "callbackhigh": 291, "999": 291, "callbackmean": 291, "id_mean": 291, "renderwindow": [291, 296, 297], "overrid": 291, "attr_nam": 291, "whithout_iren_start": 292, "streamclient": 292, "vtkinteractor": 292, "use_asyncio": 292, "streaminteract": 292, "showmmanag": 292, "stream_client": 292, "imagemanag": 292, "render_aft": 292, "dequeu": [292, 297], "cqueue_event_id": 292, "mouse_id": 292, "left_btn_press": 292, "left_btn_releas": 292, "middle_btn_press": 292, "middle_btn_releas": 292, "right_btn_press": 292, "right_btn_releas": 292, "cqueue_index_info": 292, "user_timestamp": 292, "cqueue": 292, "index_info": 292, "unord": 292, "leftbuttonreleaseev": 292, "middlebuttonpressev": 292, "middlebuttonreleaseev": 292, "rightbuttonpressev": 292, "rightbuttonreleaseev": 292, "rtc_server": 292, "image_buffer_manag": 292, "provides_mjpeg": 292, "broadcast": 292, "videostream": 292, "webrtcserv": 292, "recv": [292, 297], "videofram": 292, "queue_head_tail_buff": 292, "queue_buff": 292, "provides_webrtc": 292, "ms_jpeg": 292, "run_app": 292, "queue_head_tail_buffer_nam": 292, "queue_buffer_nam": 292, "avoid_unlink_shared_mem": 292, "image_buffers_nam": 292, "get_start_end": [292, 297], "enqueu": [292, 297], "set_head_tail": [292, 297], "is_unlock": [292, 297], "unlock": [292, 297], "setinterv": 292, "interval_tim": 292, "stackoverflow": 292, "3393612": 292, "queue_siz": 292, "return_ifram": [292, 297], "div": 292, "run_command": [292, 297], "ai": 293, "aj": 293, "ak": 293, "sxyz": 293, "gohlk": 293, "lfd": 293, "uci": 293, "yaw": [293, 296, 297], "syxz": 293, "allclos": 293, "34786452": 293, "383436184": 293, "_axes2tupl": 293, "inclin": 293, "imagin": 293, "south": 293, "north": 293, "west": 293, "east": 293, "posterior": 293, "anterior": 293, "zenith": 293, "equival": [293, 295], "nomenclatur": 293, "spherical_coordinate_system": 293, "mathworld": 293, "wolfram": 293, "sphericalcoordin": 293, "hypotenus": 293, "q": 293, "deliber": 293, "sph2cart": 293, "unusu": 293, "0lethetamathrm": 293, "lepi": 293, "pilephimathrm": 293, "tran": 293, "quat": 293, "rotation_mat": 293, "259": [293, 308], "966": 293, "866": [293, 303], "scale_mat": 293, "left_button_drag": [294, 297], "_panel2d_object": 294, "left_button_press": [294, 297], "panel2d_object": 294, "window_size_chang": 294, "remove_el": [294, 297], "update_border_coord": [294, 297], "update_el": [294, 297], "content_panel": [294, 297], "title_bold": [294, 297], "title_color": [294, 297], "title_font_s": [294, 297], "title_ital": [294, 297], "active_color": [294, 297], "inactive_color": 294, "startup_tab_id": 294, "inact": 294, "uncollaps": 294, "startup": 294, "tab_idx": 294, "collapse_tab_ui": [294, 297], "_tab_comp": 294, "_sub_compon": 294, "select_tab_callback": [294, 297], "update_tab": [294, 297], "imagedata": [294, 297], "vtktexturedactor2d": 294, "rotation_spe": 294, "anticlockwise_rotation_x": [294, 297], "anticlockwise_rotation_i": [294, 297], "clockwise_rotation_x": [294, 297], "clockwise_rotation_i": [294, 297], "key_press_callback": [294, 297], "istyl": 294, "_what": 294, "left_click_callback2": [294, 297], "left_release_callback": [294, 297], "left_release_callback2": [294, 297], "mouse_move_callback": [294, 297], "mouse_move_callback2": [294, 297], "on_left_mouse_button_releas": [294, 297], "on_left_mouse_double_click": [294, 297], "on_left_mouse_button_drag": [294, 297], "on_right_mouse_button_press": [294, 297], "on_right_mouse_button_releas": [294, 297], "on_right_mouse_button_click": [294, 297], "on_right_mouse_double_click": [294, 297], "on_right_mouse_button_drag": [294, 297], "on_middle_mouse_button_press": [294, 297], "on_middle_mouse_button_releas": [294, 297], "on_middle_mouse_button_click": [294, 297], "on_middle_mouse_double_click": [294, 297], "on_middle_mouse_button_drag": [294, 297], "on_key_press": [294, 297], "add_callback": [294, 297], "event_typ": 294, "vtkprop": 294, "handle_ev": [294, 297], "left_button_click_callback": [294, 297], "left_button_release_callback": [294, 297], "middle_button_click_callback": [294, 297], "middle_button_release_callback": [294, 297], "right_button_click_callback": [294, 297], "right_button_release_callback": [294, 297], "italicis": 294, "auto_font_sc": 294, "cal_size_from_messag": [294, 297], "famili": 294, "update_align": [294, 297], "update_bounding_box": [294, 297], "overlai": 294, "iconnam": 294, "next_icon_id": [294, 297], "cycl": [294, 298], "set_icon": [294, 297], "set_icon_by_nam": [294, 297], "icon_nam": 294, "cursor": 294, "beforehand": 294, "window_left": [294, 297], "window_right": [294, 297], "caret_po": [294, 297], "caret": 294, "add_charact": [294, 297], "edit_mod": [294, 297], "handle_charact": [294, 297], "key_char": 294, "key_press": [294, 297], "_textbox_object": 294, "textboxself": 294, "custominteractorstyl": [294, 296], "left_move_left": [294, 297], "ward": 294, "left_move_right": [294, 297], "move_caret_left": [294, 297], "move_caret_right": [294, 297], "move_left": [294, 297], "move_right": [294, 297], "remove_charact": [294, 297], "render_text": [294, 297], "show_caret": 294, "right_move_left": [294, 297], "right_move_right": [294, 297], "set_messag": [294, 297], "showable_text": [294, 297], "chop": 294, "width_set_text": [294, 297], "newlin": 294, "slide": 294, "default_color": [294, 297], "unpress": 294, "bottom_y_posit": [294, 297], "format_text": [294, 297], "handle_move_callback": [294, 297], "_vtkactor": 294, "_slider": 294, "handle_release_callback": [294, 297], "left_x_posit": [294, 297], "right_x_posit": [294, 297], "top_y_posit": [294, 297], "track_click_callback": [294, 297], "bottom_disk_ratio": [294, 297], "bottom_disk_valu": [294, 297], "coord_to_ratio": [294, 297], "disk_numb": 294, "left_disk_ratio": [294, 297], "left_disk_valu": [294, 297], "ratio_to_coord": [294, 297], "ratio_to_valu": [294, 297], "right_disk_ratio": [294, 297], "right_disk_valu": [294, 297], "top_disk_ratio": [294, 297], "top_disk_valu": [294, 297], "value_to_ratio": [294, 297], "slider_inner_radiu": 294, "slider_outer_radiu": 294, "handle_inner_radiu": 294, "handle_outer_radiu": 294, "mid_track_radiu": [294, 297], "move_handl": [294, 297], "click_posit": 294, "range_slid": [294, 297], "value_slid": [294, 297], "range_slider_handle_move_callback": [294, 297], "_element": 294, "adjac": 294, "selection_text_color": 294, "selection_bg_color": 294, "menu_text_color": 294, "selected_color": 294, "unselected_color": 294, "scroll_bar_active_color": 294, "scroll_bar_inactive_color": 294, "menu_opac": 294, "reverse_scrol": 294, "line_spac": 294, "menu": 294, "selection_box": [294, 297], "drop_down_button": [294, 297, 313], "drop_down_menu": [294, 297, 303], "unselect": 294, "append_item": [294, 297], "menu_toggle_callback": [294, 297], "_combobox": 294, "select_option_callback": [294, 297], "listboxitem": 294, "selected_text_index": [294, 297], "text_color": 294, "background_opac": 294, "castabl": 294, "clear_select": [294, 297], "down_button_callback": [294, 297], "_list_box": 294, "scroll_click_callback": [294, 297], "_rect_obj": 294, "scroll_drag_callback": [294, 297], "rect_obj": 294, "scroll_release_callback": [294, 297], "range_select": 294, "multi_select": 294, "up_button_callback": [294, 297], "update_scrollbar": [294, 297], "list_box": 294, "left_button_click": [294, 297], "_list_box_item": 294, "directory_path": 294, "extension1": 294, "extension2": 294, "directory_click_callback": [294, 297], "get_all_file_nam": [294, 297], "all_file_nam": 294, "get_directory_nam": [294, 297], "current_directori": 294, "directory_nam": 294, "get_file_nam": [294, 297], "scroll_callback": [294, 297], "_filemenu_item": 294, "set_slot_color": [294, 297], "cal_bounding_box": [294, 297], "clamp_posit": [294, 297], "new_cent": 294, "is_select": [294, 297], "left_button_releas": [294, 297], "selection_chang": [294, 297], "update_shape_posit": [294, 297], "center_posit": 294, "is_dragg": 294, "draggbl": 294, "cal_min_boundary_dist": [294, 297], "clamp_mouse_posit": [294, 297], "mouse_posit": 294, "handle_mouse_click": [294, 297], "handle_mouse_drag": [294, 297], "resize_shap": [294, 297], "show_rotation_slid": [294, 297], "update_button_icon": [294, 297], "update_shape_select": [294, 297], "selected_shap": 294, "current_time_str": [294, 297], "hh": 294, "mm": 294, "ss": [294, 297], "final_tim": [294, 297], "play_onc": [294, 297], "body_color": 294, "maintain_aspect": 294, "title_box": [294, 297], "body_box": [294, 297], "panel_color": 294, "max_column": 294, "max_lin": 294, "decrement_callback": [294, 297], "increment_callback": [294, 297], "textbox_update_valu": [294, 297], "validate_valu": [294, 297], "wrap_width": 294, "overflow_postfix": 294, "postfix": 294, "mid_ptr": 294, "vtk_object": 295, "inp": 295, "vtkalgorithmoutput": 295, "poly_mapp": 295, "polydatamapp": [295, 297], "poly_data": 295, "vtk_point": 295, "vtkpoint": 295, "vtk_color": 295, "vtkdataarrai": 295, "unsigned_char": 295, "rgb_arrai": 295, "is_coord": 295, "vtk_cell": 295, "vtkcellarrai": 295, "vtk_imag": 295, "input_arrai": 295, "1d": 295, "color_is_scalar": 295, "line_polydata": 295, "nx3": 295, "nx2": 295, "field_nam": 295, "as_vtk": 295, "field_data": 295, "array_typ": 295, "vtkarraytyp": 295, "primitives_count": 295, "array_nam": 295, "vtkpolydatamapp": 295, "prim_count": 295, "mx3": 295, "nx4": 295, "cull": 295, "backfac": 295, "active_scalar": 295, "transformed_act": 295, "aff": 295, "transformed_pt": 295, "routin": 295, "contrari": 295, "largest": 295, "cell_width": 295, "cell_height": 295, "vtkobject": 295, "norm_arrai": 295, "veric": 295, "ccw": 295, "new_triangl": 295, "corrected_triangl": 295, "as_vtk_typ": 295, "all_arrai": 295, "pts_len": 295, "polici": 295, "predefin": 295, "vtkopenglrender": 296, "vtkrender": 296, "setviewup": 296, "camera_direct": [296, 297], "viewplanenorm": 296, "obliqu": 296, "dolli": [296, 297], "fxaa_off": [296, 297], "fxaa_on": [296, 297], "get_camera": [296, 297], "last_render_tim": [296, 297], "proj_typ": 296, "reset_camera_tight": [296, 297], "margin_factor": 296, "tightli": 296, "rm_all": [296, 297], "gamma_correct": 296, "rescal": 296, "png_magnifi": 296, "interactor_styl": 296, "occlusion_ratio": 296, "magnifi": 296, "vtkinteractorstyl": 296, "trackbal": 296, "vtkinteractorstyletrackballcamera": 296, "vtkinteractorstyleimag": 296, "sequenti": 296, "crystaley": 296, "anaglyph": 296, "glass": 296, "interlac": 296, "checkerboard": 296, "aliaz": 296, "ration": 296, "vtkrenderwindow": 296, "iren_callback": 296, "acquir": 296, "play_ev": [296, 297], "play_events_from_fil": [296, 297], "record_ev": [296, 297], "temporari": 296, "record_events_to_fil": [296, 297], "release_lock": [296, 297], "save_screenshot": [296, 297], "200x200": 296, "400x400": 296, "desired_fp": 296, "cam_po": 296, "cam_foc": 296, "cam_view": 296, "path_numb": 296, "n_frame": 296, "az_ang": 296, "screen_clip": 296, "az_angl": 296, "win": 296, "render_window": 296, "stealth": 296, "im": 296, "find_object": 296, "strel": 296, "colors_found": 296, "reportsnapshot": 296, "renwin": 296, "stereo_typ": 296, "gl_state": 296, "vtkopenglst": 296, "enable_warn": 297, "disable_warn": 297, "peak_slic": [297, 304, 313], "triangularpr": 297, "pentagonalpr": 297, "octagonalpr": 297, "uncertainty_con": 297, "get_values_from_keyfram": 297, "lerp": 297, "euclidean_dist": 297, "color_interpol": 297, "cc": 297, "boys2rgb": 297, "orient2rgb": 297, "get_cmap": 297, "hex_to_rgb": 297, "rgb2hsv": 297, "hsv2rgb": 297, "xyz_from_rgb": 297, "rgb_from_xyz": 297, "xyz2rgb": 297, "rgb2xyz": 297, "get_xyz_coord": 297, "xyz2lab": 297, "lab2xyz": 297, "rgb2lab": 297, "lab2rgb": 297, "matplotlib_figure_to_numpi": 297, "data_dir": 297, "update_progressbar": [297, 313], "copyfileobj_withprogress": 297, "check_sha": 297, "fetch_data": 297, "list_gltf_sample_model": 297, "skip_r": 297, "doctest_skip_pars": 297, "argsdeprecationwarn": 297, "_leading_whit": 297, "cmp_pkg_version": 297, "is_bad_vers": 297, "deprecate_with_vers": 297, "deprecated_param": 297, "write_scen": 297, "write_nod": 297, "write_mesh": 297, "write_camera": 297, "get_prim": 297, "write_materi": 297, "write_accessor": 297, "write_bufferview": 297, "write_buff": 297, "load_text": 297, "horizontallayout": 297, "verticallayout": 297, "xlayout": 297, "ylayout": 297, "zlayout": 297, "idtypearrai": 297, "floatarrai": 297, "doublearrai": 297, "stringarrai": 297, "unsignedchararrai": 297, "algorithmoutput": 297, "renderwindowinteractor": 297, "interactoreventrecord": 297, "interactorstyl": 297, "proppick": 297, "pointpick": 297, "cellpick": 297, "worldpointpick": 297, "hardwareselector": 297, "polydatamapper2d": 297, "assembli": 297, "datasetmapp": 297, "texturedactor2d": 297, "textactor": 297, "textactor3d": 297, "property2d": 297, "vectortext": 297, "scalarbaractor": 297, "openglrender": 297, "interactorstyleimag": 297, "interactorstyletrackballactor": 297, "interactorstyletrackballcamera": 297, "interactorstyleus": 297, "cleanpolydata": 297, "polydatanorm": 297, "contourfilt": 297, "tubefilt": 297, "glyph3d": 297, "trianglefilt": 297, "splinefilt": 297, "transformpolydatafilt": 297, "renderlargeimag": 297, "loopsubdivisionfilt": 297, "butterflysubdivisionfilt": 297, "outlinefilt": 297, "linearextrusionfilt": 297, "texturemaptoplan": 297, "spheresourc": 297, "cylindersourc": 297, "arrowsourc": 297, "conesourc": 297, "disksourc": 297, "texturedspheresourc": 297, "regularpolygonsourc": 297, "dataobject": 297, "cellarrai": 297, "polyvertex": 297, "unstructuredgrid": 297, "datasetattribut": 297, "matrix4x4": 297, "matrix3x3": 297, "imageflip": 297, "imagereslic": 297, "imagemaptocolor": 297, "imagereader2factori": 297, "pngreader": 297, "bmpreader": 297, "jpegread": 297, "tiffread": 297, "plyread": 297, "stlreader": 297, "objread": 297, "mniobjectread": 297, "polydataread": 297, "xmlpolydataread": 297, "pngwriter": 297, "bmpwriter": 297, "jpegwrit": 297, "tiffwrit": 297, "plywrit": 297, "stlwriter": 297, "mniobjectwrit": 297, "polydatawrit": 297, "xmlpolydatawrit": 297, "simplebondperceiv": 297, "periodict": 297, "openglmoleculemapp": 297, "vtk_version": 297, "manifest_standard": [297, 312], "ptabl": 297, "add_bond": 297, "get_atomic_numb": 297, "set_atomic_numb": 297, "get_atomic_posit": 297, "set_atomic_posit": 297, "get_bond_ord": 297, "set_bond_ord": 297, "get_all_atomic_numb": 297, "get_all_bond_ord": 297, "get_all_atomic_posit": 297, "deep_copy_molecul": 297, "compute_bond": 297, "sphere_cpk": 297, "ball_stick": 297, "bounding_box": 297, "pkg_info": 297, "pkg_commit_hash": 297, "faces_from_sphere_vertic": 297, "repeat_primitive_funct": 297, "prim_squar": 297, "prim_superquadr": 297, "prim_icosahedron": 297, "prim_rhombicuboctahedron": 297, "prim_star": 297, "prim_triangularpr": 297, "prim_pentagonalpr": 297, "prim_octagonalpr": 297, "prim_frustum": 297, "prim_cylind": 297, "prim_arrow": 297, "prim_con": 297, "shaders_dir": 297, "load_shad": 297, "replace_shader_in_actor": 297, "async_app": 297, "callback_stream_cli": 297, "interaction_callback": 297, "_cqueue_event_id": 297, "_cqueue_index_info": 297, "_cqueue": 297, "set_weel": 297, "set_mous": 297, "set_mouse_click": 297, "get_app": 297, "rtcserver": 297, "genericmultidimensionalbuff": 297, "rawarraymultidimensionalbuff": 297, "sharedmemmultidimensionalbuff": 297, "genericcircularqueu": 297, "arraycircularqueu": 297, "sharedmemcircularqueu": 297, "intervaltimerthread": 297, "intervaltim": 297, "remove_shm_from_resource_track": 297, "check_port_is_avail": 297, "_tuple2ax": 297, "euler_matrix": 297, "sphere2cart": 297, "cart2spher": 297, "apply_transform": 297, "transform_from_matrix": 297, "linedoubleslider2d": [297, 307], "clip_overflow": 297, "check_overflow": 297, "cal_bounding_box_2d": 297, "rotate_2d": 297, "set_input": 297, "numpy_to_vtk_point": 297, "numpy_to_vtk_color": 297, "numpy_to_vtk_cel": [297, 312], "map_coordinates_3d_4d": 297, "lines_to_vtk_polydata": 297, "get_polydata_lin": 297, "get_polydata_tcoord": 297, "get_polydata_norm": 297, "get_polydata_tang": 297, "get_polydata_field": 297, "add_polydata_numeric_field": 297, "set_polydata_primitives_count": 297, "get_polydata_primitives_count": 297, "primitives_count_to_actor": 297, "primitives_count_from_actor": 297, "set_polydata_norm": 297, "set_polydata_tang": 297, "set_polydata_tcoord": 297, "update_polydata_norm": 297, "apply_affine_to_actor": 297, "apply_affin": 297, "asbyt": 297, "vtk_matrix_to_numpi": 297, "numpy_to_vtk_matrix": 297, "get_bounding_box_s": 297, "get_grid_cells_posit": 297, "shallow_copi": 297, "rgb_to_vtk": 297, "normalize_v3": 297, "triangle_ord": 297, "change_vertices_ord": 297, "tangents_from_actor": 297, "array_from_actor": 297, "normals_to_actor": 297, "get_bound": 297, "color_check": 297, "analyze_scen": 297, "analyze_snapshot": 297, "enable_stereo": 297, "gl_get_current_st": 297, "gl_enable_blend": 297, "gl_set_additive_blending_white_background": 297, "release_context": 297, "382": [303, 310], "joao": 303, "robin": 303, "129": [303, 307], "github_stat": [303, 305, 306, 307, 308, 309, 310, 311, 312, 313], "861": 303, "863": 303, "horizon": 303, "dep": 303, "845": 303, "847": 303, "848": 303, "852": 303, "846": 303, "844": 303, "843": 303, "842": 303, "839": 303, "840": 303, "841": 303, "831": 303, "833": 303, "836": 303, "834": 303, "829": 303, "827": 303, "822": 303, "823": 303, "817": 303, "819": 303, "815": 303, "811": 303, "807": 303, "805": 303, "week3": 303, "feat": 303, "week2": 303, "802": 303, "801": 303, "799": 303, "798": 303, "overload": 303, "797": 303, "796": 303, "week1": [303, 313], "792": 303, "789": 303, "788": 303, "week0": 303, "629": 303, "864": 303, "825": 303, "824": 303, "592": 303, "222": 303, "808": 303, "sponsor": 303, "402": 303, "794": 303, "dropdown": 303, "787": 303, "tractographi": 303, "remot": [303, 315], "cluster": 303, "774": 303, "github_tool": [304, 315], "nf": [304, 307, 308], "filterwarn": 304, "codaci": 304, "rank": 304, "tensorsliceractor": 304, "enforc": 304, "enh": [304, 310, 312], "exercis": 304, "peaksliceractor": 304, "peaks_slic": [304, 310], "elementwis": 304, "numpy_vtk": 304, "badg": 304, "honor": 304, "miniconda": [304, 306], "voxsz": 304, "vtk6": 304, "sphinx_galleri": 304, "reorient": 304, "sierra": 304, "ananoda": 304, "164": [305, 307, 309], "x64": 305, "test_order_transpar": 305, "169": [306, 308], "104": [306, 307], "105": 306, "npt_assert_equ": 306, "153": 307, "227": 307, "210": 307, "225": 307, "223": 307, "218": 307, "220": 307, "213": [307, 313], "215": 307, "207": 307, "206": 307, "203": 307, "namanb009": 307, "windowtitlefix": 307, "204": 307, "190": 307, "201": 307, "192": 307, "194": 307, "182": 307, "177": 307, "191": 307, "sep": 307, "132": 307, "163": 307, "spell": 307, "145": 307, "144": 307, "restructuredtext": 307, "143": 307, "139": 307, "136": 307, "134": 307, "124": 307, "python2": 307, "pickl": 307, "events_count": 307, "serial": 307, "152": 307, "219": 307, "217": 307, "133": 307, "214": 307, "187": 307, "te": 307, "209": 307, "202": 307, "199": 307, "175": 307, "185": 307, "170": 307, "rhombi": 307, "171": 307, "178": 307, "188": 307, "166": [307, 313], "183": 307, "star2d": 307, "tests_primit": 307, "174": 307, "108": 307, "172": 307, "162": 307, "168": 307, "158": 307, "expans": 307, "161": 307, "sha2": 307, "sha3": 307, "146": 307, "142": 307, "markdown": 307, "117": 307, "123": 307, "119": 307, "241": 308, "265": 308, "262": 308, "263": 308, "233": 308, "261": 308, "249": 308, "ssl": 308, "certif": 308, "244": 308, "264": 308, "247": 308, "hang": 308, "251": 308, "226": 308, "utiltii": 308, "288": 309, "292": 309, "289": 309, "284": 309, "283": 309, "282": 309, "279": 309, "solarsystem": 309, "273": 309, "276": 309, "19th": 309, "260": 309, "270": 309, "236": 309, "205": 309, "269": 309, "242": 309, "271": 309, "280": 309, "278": 309, "388": 310, "389": 310, "asymmetr": 310, "370": 310, "385": 310, "387": 310, "383": 310, "376": 310, "phenomena": 310, "374": 310, "373": 310, "368": 310, "343": 310, "353": 310, "346": 310, "351": 310, "modelsuzann": 310, "348": 310, "341": 310, "342": 310, "340": 310, "oauth": 310, "token": 310, "header": 310, "337": 310, "clip_overflow_text": 310, "336": 310, "334": 310, "332": 310, "328": 310, "329": 310, "319": 310, "311": 310, "python35": 310, "307": 310, "306": 310, "303": 310, "reader": 310, "bf": 310, "295": 310, "364": 310, "379": [310, 313], "361": 310, "352": 310, "369": 310, "363": 310, "366": 310, "357": 310, "rce": [310, 311], "359": 310, "312": 310, "335": 310, "_opac": 310, "345": 310, "338": 310, "315": 310, "authent": 310, "309": 310, "32bit": 310, "239": 310, "318": 310, "313": 310, "274": 310, "297": 310, "298": 310, "466": 311, "bib": 311, "464": 311, "dan": 311, "459": 311, "430": 311, "456": 311, "bibtex": 311, "454": 311, "451": 311, "447": 311, "438": 311, "420": 311, "stochast": 311, "444": 311, "440": [311, 315], "356": 311, "434": 311, "426": 311, "vtkeventid": 311, "394": 311, "test_util": 311, "sk": 311, "orcid": 311, "413": 311, "nanohub": 311, "412": 311, "386": 311, "joss": 311, "371": 311, "408": 311, "parenthesi": 311, "406": 311, "unus": 311, "405": 311, "399": 311, "355": 311, "393": 311, "396": 311, "421": 311, "416": 311, "445": 311, "410": 311, "bulletlist": 311, "429": 311, "453": 311, "439": 311, "403": 311, "411": 311, "417": 311, "pep": [311, 315], "414": 311, "409": 311, "375": 311, "blacklist": 311, "danger": 311, "395": 311, "358": 311, "523": 312, "536": 312, "vtk_9_plu": 312, "535": 312, "532": 312, "503": 312, "534": 312, "update_user_matrix": 312, "509": 312, "507": 312, "521": 312, "518": 312, "519": 312, "515": 312, "516": 312, "514": 312, "513": 312, "mesa": [312, 313], "506": 312, "504": 312, "496": 312, "498": 312, "488": 312, "449": 312, "433": 312, "526": 312, "vtktextactor3d": 312, "431": 312, "457": 312, "468": 312, "505": 312, "512": 312, "flock": 312, "boid": 312, "511": 312, "404": 312, "469": 312, "324": 312, "1835": 313, "782": 313, "codespel": 313, "587": 313, "781": 313, "779": 313, "741": 313, "unneed": 313, "778": 313, "777": 313, "771": 313, "770": 313, "766": 313, "767": 313, "677": 313, "765": 313, "764": 313, "748": 313, "ex": 313, "754": 313, "760": 313, "fdata": 313, "761": 313, "762": 313, "get_data": 313, "756": 313, "747": 313, "744": 313, "710": 313, "734": 313, "736": 313, "727": 313, "478": 313, "502": 313, "739": 313, "tput": 313, "737": 313, "726": 313, "735": 313, "precommit": 313, "728": 313, "730": 313, "pyproject": 313, "729": 313, "725": 313, "721": 313, "723": 313, "722": 313, "719": 313, "718": 313, "717": 313, "712": 313, "segfault": 313, "706": 313, "seg": 313, "697": 313, "693": 313, "699": 313, "698": 313, "667": 313, "686": 313, "684": 313, "683": 313, "682": 313, "681": 313, "672": 313, "675": 313, "676": 313, "671": 313, "670": 313, "666": 313, "669": 313, "620": 313, "663": 313, "662": 313, "654": 313, "659": 313, "655": 313, "649": 313, "646": 313, "641": 313, "638": 313, "639": 313, "gha": 313, "intervent": 313, "637": 313, "bugfix": [313, 315], "610": 313, "633": 313, "624": 313, "622": 313, "619": 313, "611": 313, "614": 313, "615": 313, "607": 313, "606": 313, "605": 313, "501": 313, "off_focu": 313, "601": 313, "593": 313, "arraysequ": 313, "595": 313, "589": 313, "586": 313, "590": 313, "584": 313, "582": 313, "580": 313, "574": 313, "561": 313, "577": 313, "570": 313, "569": 313, "572": 313, "571": 313, "567": 313, "theme": 313, "566": 313, "footer": 313, "ac": 313, "565": 313, "563": 313, "564": 313, "557": 313, "544": 313, "542": 313, "537": 313, "713": 313, "pydata": 313, "776": 313, "732": 313, "772": 313, "354": 313, "grammat": 313, "708": 313, "745": 313, "743": 313, "709": 313, "463": 313, "738": 313, "664": 313, "714": 313, "upsidedown": 313, "716": 313, "603": 313, "705": 313, "stress": 313, "435": 313, "rtmp": 313, "704": 313, "419": 313, "htc": 313, "vive": 313, "657": 313, "618": 313, "418": 313, "553": 313, "588": 313, "596": 313, "vtkbillboardtextactor": 313, "546": 313, "528": 313, "529": 313, "530": 313, "test_materi": 313, "554": 313, "573": 313, "541": 313, "548": 313, "549": 313, "helica": 313, "greatli": 315, "appreci": 315, "troubleshoot": 315, "reproduc": [315, 316], "whoever": 315, "pep8": 315, "volunt": 315, "your_name_her": 315, "flake8": 315, "virtualenv": 315, "pypi": 315, "outstand": 315, "shortlog": 315, "nse": 315, "mailmap": 315, "release0": 315, "release_not": 315, "autom": 315, "cd": 315, "histori": 315, "uncommit": 315, "skim": 315, "vx": 315, "forget": 315, "strongli": 315, "editor": 315, "incident": [315, 316], "resum": 315, "g58ad5f7": 315, "58ad5f7": 315, "twine": 315, "upload": 315, "extran": 315, "dfx": 315, "sdist": 315, "bdist_wheel": 315, "trunk": 315, "maint": 315, "upstream": 315, "rw": 315, "strategi": 315, "spuriou": 315, "fear": 315, "trembl": 315, "reserv": 316, "redistribut": 316, "disclaim": 316, "neither": 316, "endors": 316, "permiss": 316, "BY": 316, "THE": 316, "holder": 316, "AND": 316, "AS": 316, "OR": 316, "warranti": 316, "BUT": 316, "TO": 316, "merchant": 316, "FOR": 316, "NO": 316, "BE": 316, "liabl": 316, "indirect": 316, "exemplari": 316, "consequenti": 316, "damag": 316, "procur": 316, "servic": 316, "loss": 316, "profit": 316, "interrupt": 316, "ON": 316, "liabil": 316, "contract": 316, "tort": 316, "neglig": 316, "IF": 316, "SUCH": 316, "473": 84}, "objects": {"": [[273, 0, 0, "-", "fury"]], "fury": [[274, 0, 0, "-", "actor"], [275, 0, 0, "-", "actors"], [276, 0, 0, "-", "animation"], [277, 0, 0, "-", "colormap"], [278, 0, 0, "-", "convert"], [279, 0, 0, "-", "data"], [280, 0, 0, "-", "decorators"], [281, 0, 0, "-", "deprecator"], [273, 5, 1, "", "disable_warnings"], [273, 5, 1, "", "enable_warnings"], [273, 5, 1, "", "get_info"], [282, 0, 0, "-", "gltf"], [283, 0, 0, "-", "io"], [284, 0, 0, "-", "layout"], [285, 0, 0, "-", "lib"], [286, 0, 0, "-", "material"], [287, 0, 0, "-", "molecular"], [288, 0, 0, "-", "pick"], [289, 0, 0, "-", "pkg_info"], [290, 0, 0, "-", "primitive"], [291, 0, 0, "-", "shaders"], [292, 0, 0, "-", "stream"], [293, 0, 0, "-", "transform"], [294, 0, 0, "-", "ui"], [295, 0, 0, "-", "utils"], [296, 0, 0, "-", "window"]], "fury.actor": [[274, 1, 1, "", "Container"], [274, 5, 1, "", "arrow"], [274, 5, 1, "", "axes"], [274, 5, 1, "", "billboard"], [274, 5, 1, "", "box"], [274, 5, 1, "", "cone"], [274, 5, 1, "", "contour_from_label"], [274, 5, 1, "", "contour_from_roi"], [274, 5, 1, "", "cube"], [274, 5, 1, "", "cylinder"], [274, 5, 1, "", "disk"], [274, 5, 1, "", "dot"], [274, 5, 1, "", "dots"], [274, 5, 1, "", "ellipsoid"], [274, 5, 1, "", "figure"], [274, 5, 1, "", "frustum"], [274, 5, 1, "", "grid"], [274, 5, 1, "", "label"], [274, 5, 1, "", "line"], [274, 5, 1, "", "markers"], [274, 5, 1, "", "octagonalprism"], [274, 5, 1, "", "odf_slicer"], [274, 5, 1, "", "peak"], [274, 5, 1, "", "peak_slicer"], [274, 5, 1, "", "pentagonalprism"], [274, 5, 1, "", "point"], [274, 5, 1, "", "rectangle"], [274, 5, 1, "", "rhombicuboctahedron"], [274, 5, 1, "", "scalar_bar"], [274, 5, 1, "", "sdf"], [274, 5, 1, "", "slicer"], [274, 5, 1, "", "sphere"], [274, 5, 1, "", "square"], [274, 5, 1, "", "streamtube"], [274, 5, 1, "", "superquadric"], [274, 5, 1, "", "surface"], [274, 5, 1, "", "tensor_slicer"], [274, 5, 1, "", "text_3d"], [274, 5, 1, "", "texture"], [274, 5, 1, "", "texture_2d"], [274, 5, 1, "", "texture_on_sphere"], [274, 5, 1, "", "texture_update"], [274, 5, 1, "", "triangularprism"], [274, 5, 1, "", "uncertainty_cone"], [274, 5, 1, "", "vector_text"]], "fury.actor.Container": [[274, 2, 1, "", "AddPosition"], [274, 2, 1, "", "GetBounds"], [274, 2, 1, "", "GetCenter"], [274, 2, 1, "", "GetLength"], [274, 2, 1, "", "GetPosition"], [274, 2, 1, "", "GetVisibility"], [274, 2, 1, "", "NewInstance"], [274, 2, 1, "", "SetPosition"], [274, 2, 1, "", "SetVisibility"], [274, 2, 1, "", "ShallowCopy"], [274, 2, 1, "", "__init__"], [274, 2, 1, "", "add"], [274, 2, 1, "", "add_to_scene"], [274, 3, 1, "", "anchor"], [274, 2, 1, "", "clear"], [274, 4, 1, "", "items"], [274, 3, 1, "", "padding"], [274, 2, 1, "", "remove_from_scene"], [274, 2, 1, "", "update"]], "fury.actors": [[275, 0, 0, "-", "odf_slicer"], [275, 0, 0, "-", "peak"], [275, 0, 0, "-", "tensor"]], "fury.actors.odf_slicer": [[275, 1, 1, "", "OdfSlicerActor"]], "fury.actors.odf_slicer.OdfSlicerActor": [[275, 2, 1, "", "__init__"], [275, 2, 1, "", "display"], [275, 2, 1, "", "display_extent"], [275, 2, 1, "", "set_opacity"], [275, 2, 1, "", "slice_along_axis"], [275, 2, 1, "", "update_sphere"]], "fury.actors.peak": [[275, 1, 1, "", "PeakActor"]], "fury.actors.peak.PeakActor": [[275, 2, 1, "", "__init__"], [275, 4, 1, "", "cross_section"], [275, 2, 1, "", "display_cross_section"], [275, 2, 1, "", "display_extent"], [275, 4, 1, "", "global_opacity"], [275, 4, 1, "", "high_ranges"], [275, 4, 1, "", "is_range"], [275, 4, 1, "", "linewidth"], [275, 4, 1, "", "low_ranges"], [275, 4, 1, "", "max_centers"], [275, 4, 1, "", "min_centers"]], "fury.actors.tensor": [[275, 5, 1, "", "double_cone"], [275, 5, 1, "", "main_dir_uncertainty"], [275, 5, 1, "", "tensor_ellipsoid"]], "fury.animation": [[276, 0, 0, "-", "animation"], [276, 0, 0, "-", "helpers"], [276, 0, 0, "-", "interpolator"], [276, 0, 0, "-", "timeline"]], "fury.animation.animation": [[276, 1, 1, "", "Animation"], [276, 1, 1, "", "CameraAnimation"]], "fury.animation.animation.Animation": [[276, 2, 1, "", "__init__"], [276, 4, 1, "id0", "actors"], [276, 2, 1, "", "add"], [276, 2, 1, "", "add_actor"], [276, 2, 1, "", "add_child_animation"], [276, 2, 1, "", "add_static_actor"], [276, 2, 1, "", "add_to_scene"], [276, 2, 1, "", "add_to_scene_at"], [276, 2, 1, "", "add_update_callback"], [276, 4, 1, "", "child_animations"], [276, 4, 1, "", "current_timestamp"], [276, 4, 1, "", "duration"], [276, 2, 1, "", "get_color"], [276, 2, 1, "", "get_current_value"], [276, 2, 1, "", "get_keyframes"], [276, 2, 1, "", "get_opacity"], [276, 2, 1, "", "get_position"], [276, 2, 1, "", "get_rotation"], [276, 2, 1, "", "get_scale"], [276, 2, 1, "", "get_value"], [276, 2, 1, "", "is_inside_scene_at"], [276, 2, 1, "", "is_interpolatable"], [276, 3, 1, "", "length"], [276, 4, 1, "id2", "loop"], [276, 3, 1, "", "motion_path_res"], [276, 4, 1, "", "parent_animation"], [276, 2, 1, "", "remove_actor"], [276, 2, 1, "", "remove_actors"], [276, 2, 1, "", "remove_animations"], [276, 2, 1, "", "remove_from_scene"], [276, 2, 1, "", "remove_from_scene_at"], [276, 2, 1, "", "set_color"], [276, 2, 1, "", "set_color_interpolator"], [276, 2, 1, "", "set_color_keyframes"], [276, 2, 1, "", "set_interpolator"], [276, 2, 1, "", "set_keyframe"], [276, 2, 1, "", "set_keyframes"], [276, 2, 1, "", "set_opacity"], [276, 2, 1, "", "set_opacity_interpolator"], [276, 2, 1, "", "set_opacity_keyframes"], [276, 2, 1, "", "set_position"], [276, 2, 1, "", "set_position_interpolator"], [276, 2, 1, "", "set_position_keyframes"], [276, 2, 1, "", "set_rotation"], [276, 2, 1, "", "set_rotation_as_vector"], [276, 2, 1, "", "set_rotation_interpolator"], [276, 2, 1, "", "set_scale"], [276, 2, 1, "", "set_scale_interpolator"], [276, 2, 1, "", "set_scale_keyframes"], [276, 4, 1, "", "static_actors"], [276, 4, 1, "", "timeline"], [276, 2, 1, "", "update_animation"], [276, 2, 1, "", "update_duration"], [276, 2, 1, "", "update_motion_path"]], "fury.animation.animation.CameraAnimation": [[276, 2, 1, "", "__init__"], [276, 4, 1, "id3", "camera"], [276, 2, 1, "", "get_focal"], [276, 2, 1, "", "get_view_up"], [276, 3, 1, "", "length"], [276, 3, 1, "", "loop"], [276, 3, 1, "", "motion_path_res"], [276, 2, 1, "", "set_focal"], [276, 2, 1, "", "set_focal_interpolator"], [276, 2, 1, "", "set_focal_keyframes"], [276, 2, 1, "", "set_view_up"], [276, 2, 1, "", "set_view_up_interpolator"], [276, 2, 1, "", "set_view_up_keyframes"], [276, 2, 1, "", "update_animation"]], "fury.animation.helpers": [[276, 5, 1, "", "euclidean_distances"], [276, 5, 1, "", "get_next_timestamp"], [276, 5, 1, "", "get_previous_timestamp"], [276, 5, 1, "", "get_time_tau"], [276, 5, 1, "", "get_timestamps_from_keyframes"], [276, 5, 1, "", "get_values_from_keyframes"], [276, 5, 1, "", "lerp"]], "fury.animation.interpolator": [[276, 5, 1, "", "color_interpolator"], [276, 5, 1, "", "cubic_bezier_interpolator"], [276, 5, 1, "", "cubic_spline_interpolator"], [276, 5, 1, "", "hsv_color_interpolator"], [276, 5, 1, "", "lab_color_interpolator"], [276, 5, 1, "", "linear_interpolator"], [276, 5, 1, "", "slerp"], [276, 5, 1, "", "spline_interpolator"], [276, 5, 1, "", "step_interpolator"], [276, 5, 1, "", "tan_cubic_spline_interpolator"], [276, 5, 1, "", "xyz_color_interpolator"]], "fury.animation.timeline": [[276, 1, 1, "", "Timeline"]], "fury.animation.timeline.Timeline": [[276, 2, 1, "", "__init__"], [276, 2, 1, "", "add_animation"], [276, 2, 1, "", "add_to_scene"], [276, 4, 1, "id4", "animations"], [276, 4, 1, "", "current_timestamp"], [276, 4, 1, "", "duration"], [276, 4, 1, "", "has_playback_panel"], [276, 3, 1, "", "length"], [276, 4, 1, "id5", "loop"], [276, 2, 1, "", "pause"], [276, 4, 1, "", "paused"], [276, 2, 1, "", "play"], [276, 3, 1, "", "playback_panel"], [276, 4, 1, "", "playing"], [276, 2, 1, "", "record"], [276, 2, 1, "", "remove_from_scene"], [276, 2, 1, "", "restart"], [276, 2, 1, "", "seek"], [276, 2, 1, "", "seek_percent"], [276, 4, 1, "", "speed"], [276, 2, 1, "", "stop"], [276, 4, 1, "", "stopped"], [276, 2, 1, "", "update"], [276, 2, 1, "", "update_duration"]], "fury.colormap": [[277, 3, 1, "id0", "T"], [277, 3, 1, "id15", "base"], [277, 5, 1, "", "boys2rgb"], [277, 5, 1, "", "cc"], [277, 5, 1, "", "colormap_lookup_table"], [277, 5, 1, "", "create_colormap"], [277, 3, 1, "id14", "ctypes"], [277, 3, 1, "id2", "data"], [277, 5, 1, "", "distinguishable_colormap"], [277, 3, 1, "id3", "dtype"], [277, 3, 1, "id4", "flags"], [277, 3, 1, "id5", "flat"], [277, 5, 1, "", "get_cmap"], [277, 5, 1, "", "get_xyz_coords"], [277, 5, 1, "", "hex_to_rgb"], [277, 5, 1, "", "hsv2rgb"], [277, 3, 1, "id6", "imag"], [277, 3, 1, "id9", "itemsize"], [277, 5, 1, "", "lab2rgb"], [277, 5, 1, "", "lab2xyz"], [277, 5, 1, "", "line_colors"], [277, 3, 1, "id10", "nbytes"], [277, 3, 1, "id11", "ndim"], [277, 5, 1, "", "orient2rgb"], [277, 3, 1, "id7", "real"], [277, 5, 1, "", "rgb2hsv"], [277, 5, 1, "", "rgb2lab"], [277, 5, 1, "", "rgb2xyz"], [277, 5, 1, "", "rgb_from_xyz"], [277, 3, 1, "id12", "shape"], [277, 3, 1, "id8", "size"], [277, 5, 1, "", "ss"], [277, 3, 1, "id13", "strides"], [277, 5, 1, "", "xyz2lab"], [277, 5, 1, "", "xyz2rgb"], [277, 5, 1, "", "xyz_from_rgb"]], "fury.convert": [[278, 5, 1, "", "matplotlib_figure_to_numpy"]], "fury.data": [[279, 5, 1, "", "DATA_DIR"], [279, 0, 0, "-", "fetcher"]], "fury.data.fetcher": [[279, 5, 1, "", "check_sha"], [279, 5, 1, "", "copyfileobj_withprogress"], [279, 5, 1, "", "fetch_data"], [279, 5, 1, "", "fetch_gltf"], [279, 5, 1, "", "fetch_viz_cubemaps"], [279, 5, 1, "", "fetch_viz_dmri"], [279, 5, 1, "", "fetch_viz_icons"], [279, 5, 1, "", "fetch_viz_models"], [279, 5, 1, "", "fetch_viz_new_icons"], [279, 5, 1, "", "fetch_viz_textures"], [279, 5, 1, "", "fetch_viz_wiki_nw"], [279, 5, 1, "", "list_gltf_sample_models"], [279, 5, 1, "", "read_viz_cubemap"], [279, 5, 1, "", "read_viz_dmri"], [279, 5, 1, "", "read_viz_gltf"], [279, 5, 1, "", "read_viz_icons"], [279, 5, 1, "", "read_viz_models"], [279, 5, 1, "", "read_viz_textures"], [279, 5, 1, "", "update_progressbar"]], "fury.decorators": [[280, 5, 1, "", "SKIP_RE"], [280, 5, 1, "", "doctest_skip_parser"]], "fury.deprecator": [[281, 1, 1, "", "ArgsDeprecationWarning"], [281, 1, 1, "", "ExpiredDeprecationError"], [281, 5, 1, "", "_LEADING_WHITE"], [281, 5, 1, "", "cmp_pkg_version"], [281, 5, 1, "", "deprecate_with_version"], [281, 5, 1, "", "deprecated_params"], [281, 5, 1, "", "is_bad_version"]], "fury.deprecator.ArgsDeprecationWarning": [[281, 2, 1, "", "__init__"]], "fury.deprecator.ExpiredDeprecationError": [[281, 2, 1, "", "__init__"]], "fury.gltf": [[282, 5, 1, "", "export_scene"], [282, 5, 1, "", "get_prim"], [282, 1, 1, "", "glTF"], [282, 5, 1, "", "write_accessor"], [282, 5, 1, "", "write_buffer"], [282, 5, 1, "", "write_bufferview"], [282, 5, 1, "", "write_camera"], [282, 5, 1, "", "write_material"], [282, 5, 1, "", "write_mesh"], [282, 5, 1, "", "write_node"], [282, 5, 1, "", "write_scene"]], "fury.gltf.glTF": [[282, 2, 1, "", "__init__"], [282, 2, 1, "", "actors"], [282, 2, 1, "", "apply_morph_vertices"], [282, 2, 1, "", "apply_skin_matrix"], [282, 2, 1, "", "generate_tmatrix"], [282, 2, 1, "", "get_acc_data"], [282, 2, 1, "", "get_animations"], [282, 2, 1, "", "get_buff_array"], [282, 2, 1, "", "get_joint_actors"], [282, 2, 1, "", "get_materials"], [282, 2, 1, "", "get_matrix_from_sampler"], [282, 2, 1, "", "get_morph_data"], [282, 2, 1, "", "get_sampler_data"], [282, 2, 1, "", "get_skin_data"], [282, 2, 1, "", "get_texture"], [282, 2, 1, "", "initialize_skin"], [282, 2, 1, "", "inspect_scene"], [282, 2, 1, "", "load_camera"], [282, 2, 1, "", "load_mesh"], [282, 2, 1, "", "main_animation"], [282, 2, 1, "", "morph_animation"], [282, 2, 1, "", "skin_animation"], [282, 2, 1, "", "transverse_animations"], [282, 2, 1, "", "transverse_bones"], [282, 2, 1, "", "transverse_channels"], [282, 2, 1, "", "transverse_node"], [282, 2, 1, "", "update_morph"], [282, 2, 1, "", "update_skin"]], "fury.io": [[283, 5, 1, "", "load_cubemap_texture"], [283, 5, 1, "", "load_image"], [283, 5, 1, "", "load_polydata"], [283, 5, 1, "", "load_sprite_sheet"], [283, 5, 1, "", "load_text"], [283, 5, 1, "", "save_image"], [283, 5, 1, "", "save_polydata"]], "fury.layout": [[284, 1, 1, "", "GridLayout"], [284, 1, 1, "", "HorizontalLayout"], [284, 1, 1, "", "Layout"], [284, 1, 1, "", "VerticalLayout"], [284, 1, 1, "", "XLayout"], [284, 1, 1, "", "YLayout"], [284, 1, 1, "", "ZLayout"]], "fury.layout.GridLayout": [[284, 2, 1, "", "__init__"], [284, 2, 1, "", "compute_positions"], [284, 2, 1, "", "compute_sizes"], [284, 2, 1, "", "get_cells_shape"]], "fury.layout.HorizontalLayout": [[284, 2, 1, "", "__init__"], [284, 2, 1, "", "compute_positions"]], "fury.layout.Layout": [[284, 2, 1, "", "__init__"], [284, 2, 1, "", "apply"], [284, 2, 1, "", "compute_positions"]], "fury.layout.VerticalLayout": [[284, 2, 1, "", "__init__"], [284, 2, 1, "", "compute_positions"]], "fury.layout.XLayout": [[284, 2, 1, "", "__init__"], [284, 2, 1, "", "apply"], [284, 2, 1, "", "compute_positions"], [284, 2, 1, "", "get_cells_shape"]], "fury.layout.YLayout": [[284, 2, 1, "", "__init__"], [284, 2, 1, "", "apply"], [284, 2, 1, "", "compute_positions"], [284, 2, 1, "", "get_cells_shape"]], "fury.layout.ZLayout": [[284, 2, 1, "", "__init__"], [284, 2, 1, "", "apply"], [284, 2, 1, "", "compute_positions"], [284, 2, 1, "", "get_cells_shape"]], "fury.lib": [[285, 3, 1, "", "Actor"], [285, 3, 1, "", "Actor2D"], [285, 3, 1, "", "AlgorithmOutput"], [285, 3, 1, "", "ArrowSource"], [285, 3, 1, "", "Assembly"], [285, 3, 1, "", "BMPReader"], [285, 3, 1, "", "BMPWriter"], [285, 3, 1, "", "ButterflySubdivisionFilter"], [285, 3, 1, "", "Camera"], [285, 3, 1, "", "CellArray"], [285, 3, 1, "", "CellPicker"], [285, 3, 1, "", "CleanPolyData"], [285, 3, 1, "", "Command"], [285, 3, 1, "", "ConeSource"], [285, 3, 1, "", "ContourFilter"], [285, 3, 1, "", "CylinderSource"], [285, 3, 1, "id0", "DataObject"], [285, 3, 1, "", "DataSetAttributes"], [285, 3, 1, "", "DataSetMapper"], [285, 3, 1, "", "DiskSource"], [285, 3, 1, "", "DoubleArray"], [285, 3, 1, "", "FloatArray"], [285, 3, 1, "", "Follower"], [285, 3, 1, "", "Glyph3D"], [285, 3, 1, "", "HardwareSelector"], [285, 3, 1, "", "IdTypeArray"], [285, 3, 1, "", "ImageActor"], [285, 3, 1, "", "ImageData"], [285, 3, 1, "", "ImageFlip"], [285, 3, 1, "", "ImageMapToColors"], [285, 3, 1, "", "ImageReader2Factory"], [285, 3, 1, "", "ImageReslice"], [285, 3, 1, "", "InteractorEventRecorder"], [285, 3, 1, "", "InteractorStyle"], [285, 3, 1, "", "InteractorStyleImage"], [285, 3, 1, "", "InteractorStyleTrackballActor"], [285, 3, 1, "", "InteractorStyleTrackballCamera"], [285, 3, 1, "", "InteractorStyleUser"], [285, 3, 1, "", "JPEGReader"], [285, 3, 1, "", "JPEGWriter"], [285, 3, 1, "", "LODActor"], [285, 3, 1, "", "LinearExtrusionFilter"], [285, 3, 1, "", "LookupTable"], [285, 3, 1, "", "LoopSubdivisionFilter"], [285, 3, 1, "", "MNIObjectReader"], [285, 3, 1, "", "MNIObjectWriter"], [285, 3, 1, "", "Matrix3x3"], [285, 3, 1, "", "Matrix4x4"], [285, 3, 1, "", "Molecule"], [285, 3, 1, "", "OBJReader"], [285, 3, 1, "", "OpenGLMoleculeMapper"], [285, 3, 1, "", "OpenGLRenderer"], [285, 3, 1, "", "OutlineFilter"], [285, 3, 1, "", "PLYReader"], [285, 3, 1, "", "PLYWriter"], [285, 3, 1, "", "PNGReader"], [285, 3, 1, "", "PNGWriter"], [285, 3, 1, "", "PeriodicTable"], [285, 3, 1, "", "PointPicker"], [285, 3, 1, "", "Points"], [285, 3, 1, "", "PolyData"], [285, 3, 1, "", "PolyDataMapper"], [285, 3, 1, "", "PolyDataMapper2D"], [285, 3, 1, "", "PolyDataNormals"], [285, 3, 1, "", "PolyDataReader"], [285, 3, 1, "", "PolyDataWriter"], [285, 3, 1, "", "PolyVertex"], [285, 3, 1, "", "Polygon"], [285, 3, 1, "", "PropPicker"], [285, 3, 1, "", "Property2D"], [285, 3, 1, "", "ProteinRibbonFilter"], [285, 3, 1, "", "RegularPolygonSource"], [285, 3, 1, "", "RenderLargeImage"], [285, 3, 1, "", "RenderWindow"], [285, 3, 1, "", "RenderWindowInteractor"], [285, 3, 1, "", "Renderer"], [285, 3, 1, "", "STLReader"], [285, 3, 1, "", "STLWriter"], [285, 3, 1, "", "ScalarBarActor"], [285, 3, 1, "", "Shader"], [285, 3, 1, "", "SimpleBondPerceiver"], [285, 3, 1, "", "Skybox"], [285, 3, 1, "", "SphereSource"], [285, 3, 1, "", "SplineFilter"], [285, 3, 1, "", "StringArray"], [285, 3, 1, "", "TIFFReader"], [285, 3, 1, "", "TIFFWriter"], [285, 3, 1, "", "TextActor"], [285, 3, 1, "", "TextActor3D"], [285, 3, 1, "", "Texture"], [285, 3, 1, "", "TextureMapToPlane"], [285, 3, 1, "", "TexturedActor2D"], [285, 3, 1, "", "TexturedSphereSource"], [285, 3, 1, "", "Transform"], [285, 3, 1, "", "TransformPolyDataFilter"], [285, 3, 1, "", "TriangleFilter"], [285, 3, 1, "", "TubeFilter"], [285, 3, 1, "", "UnsignedCharArray"], [285, 3, 1, "", "UnstructuredGrid"], [285, 5, 1, "", "VTK_VERSION"], [285, 3, 1, "", "VectorText"], [285, 3, 1, "", "Volume"], [285, 3, 1, "", "WindowToImageFilter"], [285, 3, 1, "", "WorldPointPicker"], [285, 3, 1, "", "XMLPolyDataReader"], [285, 3, 1, "", "XMLPolyDataWriter"]], "fury.material": [[286, 5, 1, "", "manifest_pbr"], [286, 5, 1, "", "manifest_principled"], [286, 5, 1, "", "manifest_standard"]], "fury.molecular": [[287, 1, 1, "", "Molecule"], [287, 1, 1, "", "PTable"], [287, 5, 1, "", "add_atom"], [287, 5, 1, "", "add_bond"], [287, 5, 1, "", "ball_stick"], [287, 5, 1, "", "bounding_box"], [287, 5, 1, "", "compute_bonding"], [287, 5, 1, "", "deep_copy_molecule"], [287, 5, 1, "", "get_all_atomic_numbers"], [287, 5, 1, "", "get_all_atomic_positions"], [287, 5, 1, "", "get_all_bond_orders"], [287, 5, 1, "", "get_atomic_number"], [287, 5, 1, "", "get_atomic_position"], [287, 5, 1, "", "get_bond_order"], [287, 5, 1, "", "ribbon"], [287, 5, 1, "", "set_atomic_number"], [287, 5, 1, "", "set_atomic_position"], [287, 5, 1, "", "set_bond_order"], [287, 5, 1, "", "sphere_cpk"], [287, 5, 1, "", "stick"]], "fury.molecular.Molecule": [[287, 2, 1, "", "__init__"], [287, 4, 1, "", "total_num_atoms"], [287, 4, 1, "", "total_num_bonds"]], "fury.molecular.PTable": [[287, 2, 1, "", "__init__"], [287, 2, 1, "", "atom_color"], [287, 2, 1, "", "atomic_number"], [287, 2, 1, "", "atomic_radius"], [287, 2, 1, "", "atomic_symbol"], [287, 2, 1, "", "element_name"]], "fury.pick": [[288, 1, 1, "", "PickingManager"], [288, 1, 1, "", "SelectionManager"]], "fury.pick.PickingManager": [[288, 2, 1, "", "__init__"], [288, 2, 1, "", "event_position"], [288, 2, 1, "", "pick"], [288, 2, 1, "", "pickable_off"], [288, 2, 1, "", "pickable_on"]], "fury.pick.SelectionManager": [[288, 2, 1, "", "__init__"], [288, 2, 1, "", "event_position"], [288, 2, 1, "id0", "pick"], [288, 2, 1, "id1", "select"], [288, 2, 1, "", "selectable_off"], [288, 2, 1, "", "selectable_on"], [288, 2, 1, "", "update_selection_type"]], "fury.pkg_info": [[289, 5, 1, "", "pkg_commit_hash"]], "fury.primitive": [[290, 5, 1, "", "faces_from_sphere_vertices"], [290, 5, 1, "", "prim_arrow"], [290, 5, 1, "", "prim_box"], [290, 5, 1, "", "prim_cone"], [290, 5, 1, "", "prim_cylinder"], [290, 5, 1, "", "prim_frustum"], [290, 5, 1, "", "prim_icosahedron"], [290, 5, 1, "", "prim_octagonalprism"], [290, 5, 1, "", "prim_pentagonalprism"], [290, 5, 1, "", "prim_rhombicuboctahedron"], [290, 5, 1, "", "prim_sphere"], [290, 5, 1, "", "prim_square"], [290, 5, 1, "", "prim_star"], [290, 5, 1, "", "prim_superquadric"], [290, 5, 1, "", "prim_tetrahedron"], [290, 5, 1, "", "prim_triangularprism"], [290, 5, 1, "", "repeat_primitive"], [290, 5, 1, "", "repeat_primitive_function"]], "fury.shaders": [[291, 0, 0, "-", "base"]], "fury.shaders.base": [[291, 5, 1, "", "SHADERS_DIR"], [291, 5, 1, "", "add_shader_callback"], [291, 5, 1, "", "attribute_to_actor"], [291, 5, 1, "", "compose_shader"], [291, 5, 1, "", "import_fury_shader"], [291, 5, 1, "", "load"], [291, 5, 1, "", "load_shader"], [291, 5, 1, "", "replace_shader_in_actor"], [291, 5, 1, "", "shader_apply_effects"], [291, 5, 1, "", "shader_to_actor"]], "fury.stream": [[292, 0, 0, "-", "client"], [292, 0, 0, "-", "constants"], [292, 0, 0, "-", "server"], [292, 0, 0, "-", "tools"], [292, 0, 0, "-", "widget"]], "fury.stream.client": [[292, 1, 1, "", "FuryStreamClient"], [292, 1, 1, "", "FuryStreamInteraction"], [292, 5, 1, "", "callback_stream_client"], [292, 5, 1, "", "interaction_callback"]], "fury.stream.client.FuryStreamClient": [[292, 2, 1, "", "__init__"], [292, 2, 1, "", "cleanup"], [292, 2, 1, "", "start"], [292, 2, 1, "", "stop"]], "fury.stream.client.FuryStreamInteraction": [[292, 2, 1, "", "__init__"], [292, 2, 1, "", "cleanup"], [292, 2, 1, "", "start"], [292, 2, 1, "", "stop"]], "fury.stream.constants": [[292, 5, 1, "", "_CQUEUE"], [292, 5, 1, "", "_CQUEUE_EVENT_IDs"], [292, 5, 1, "", "_CQUEUE_INDEX_INFO"]], "fury.stream.server": [[292, 0, 0, "-", "async_app"], [292, 0, 0, "-", "main"]], "fury.stream.server.async_app": [[292, 5, 1, "", "get_app"], [292, 5, 1, "", "pcs"], [292, 5, 1, "", "set_mouse"], [292, 5, 1, "", "set_mouse_click"], [292, 5, 1, "", "set_weel"]], "fury.stream.server.main": [[292, 1, 1, "", "RTCServer"], [292, 5, 1, "", "web_server"], [292, 5, 1, "", "web_server_raw_array"]], "fury.stream.server.main.RTCServer": [[292, 2, 1, "", "__init__"], [292, 2, 1, "", "recv"], [292, 2, 1, "", "release"]], "fury.stream.tools": [[292, 1, 1, "", "ArrayCircularQueue"], [292, 1, 1, "", "GenericCircularQueue"], [292, 1, 1, "", "GenericImageBufferManager"], [292, 1, 1, "", "GenericMultiDimensionalBuffer"], [292, 1, 1, "", "IntervalTimer"], [292, 1, 1, "", "IntervalTimerThreading"], [292, 1, 1, "", "RawArrayImageBufferManager"], [292, 1, 1, "", "RawArrayMultiDimensionalBuffer"], [292, 1, 1, "", "SharedMemCircularQueue"], [292, 1, 1, "", "SharedMemImageBufferManager"], [292, 1, 1, "", "SharedMemMultiDimensionalBuffer"], [292, 5, 1, "", "remove_shm_from_resource_tracker"]], "fury.stream.tools.ArrayCircularQueue": [[292, 2, 1, "", "__init__"], [292, 2, 1, "", "cleanup"], [292, 2, 1, "", "create_mem_resource"], [292, 2, 1, "", "dequeue"], [292, 2, 1, "", "enqueue"], [292, 2, 1, "", "load_mem_resource"]], "fury.stream.tools.GenericCircularQueue": [[292, 2, 1, "", "__init__"], [292, 2, 1, "", "cleanup"], [292, 2, 1, "", "create_mem_resource"], [292, 2, 1, "", "dequeue"], [292, 2, 1, "", "enqueue"], [292, 4, 1, "", "head"], [292, 2, 1, "", "load_mem_resource"], [292, 2, 1, "", "set_head_tail"], [292, 4, 1, "", "tail"]], "fury.stream.tools.GenericImageBufferManager": [[292, 2, 1, "", "__init__"], [292, 2, 1, "", "async_get_jpeg"], [292, 4, 1, "", "buffer_index"], [292, 2, 1, "", "cleanup"], [292, 2, 1, "", "create_mem_resource"], [292, 2, 1, "", "get_current_frame"], [292, 2, 1, "", "get_jpeg"], [292, 2, 1, "", "load_mem_resource"], [292, 4, 1, "", "next_buffer_index"], [292, 2, 1, "", "write_into"]], "fury.stream.tools.GenericMultiDimensionalBuffer": [[292, 2, 1, "", "__init__"], [292, 4, 1, "", "buffer"], [292, 2, 1, "", "cleanup"], [292, 2, 1, "", "create_mem_resource"], [292, 2, 1, "", "get_start_end"], [292, 2, 1, "", "load_mem_resource"]], "fury.stream.tools.IntervalTimer": [[292, 2, 1, "", "__init__"], [292, 2, 1, "", "start"], [292, 2, 1, "", "stop"]], "fury.stream.tools.IntervalTimerThreading": [[292, 2, 1, "", "__init__"], [292, 2, 1, "", "start"], [292, 2, 1, "", "stop"]], "fury.stream.tools.RawArrayImageBufferManager": [[292, 2, 1, "", "__init__"], [292, 2, 1, "", "cleanup"], [292, 2, 1, "", "create_mem_resource"], [292, 2, 1, "", "load_mem_resource"]], "fury.stream.tools.RawArrayMultiDimensionalBuffer": [[292, 2, 1, "", "__init__"], [292, 2, 1, "", "cleanup"], [292, 2, 1, "", "create_mem_resource"], [292, 2, 1, "", "load_mem_resource"]], "fury.stream.tools.SharedMemCircularQueue": [[292, 2, 1, "", "__init__"], [292, 2, 1, "", "cleanup"], [292, 2, 1, "", "create_mem_resource"], [292, 2, 1, "", "dequeue"], [292, 2, 1, "", "enqueue"], [292, 2, 1, "", "is_unlocked"], [292, 2, 1, "", "load_mem_resource"], [292, 2, 1, "", "lock"], [292, 2, 1, "", "unlock"]], "fury.stream.tools.SharedMemImageBufferManager": [[292, 2, 1, "", "__init__"], [292, 2, 1, "", "cleanup"], [292, 2, 1, "", "create_mem_resource"], [292, 2, 1, "", "load_mem_resource"]], "fury.stream.tools.SharedMemMultiDimensionalBuffer": [[292, 2, 1, "", "__init__"], [292, 2, 1, "", "cleanup"], [292, 2, 1, "", "create_mem_resource"], [292, 2, 1, "", "load_mem_resource"]], "fury.stream.widget": [[292, 1, 1, "", "Widget"], [292, 5, 1, "", "check_port_is_available"]], "fury.stream.widget.Widget": [[292, 2, 1, "", "__init__"], [292, 2, 1, "", "cleanup"], [292, 4, 1, "", "command_string"], [292, 2, 1, "", "display"], [292, 2, 1, "", "return_iframe"], [292, 2, 1, "", "run_command"], [292, 2, 1, "", "start"], [292, 2, 1, "", "stop"], [292, 4, 1, "", "url"]], "fury.transform": [[293, 5, 1, "", "_TUPLE2AXES"], [293, 5, 1, "", "apply_transformation"], [293, 5, 1, "", "cart2sphere"], [293, 5, 1, "", "euler_matrix"], [293, 5, 1, "", "rotate"], [293, 5, 1, "", "scale"], [293, 5, 1, "", "sphere2cart"], [293, 5, 1, "", "transform_from_matrix"], [293, 5, 1, "", "translate"]], "fury.ui": [[294, 0, 0, "-", "containers"], [294, 0, 0, "-", "core"], [294, 0, 0, "-", "elements"], [294, 0, 0, "-", "helpers"]], "fury.ui.containers": [[294, 1, 1, "", "GridUI"], [294, 1, 1, "", "ImageContainer2D"], [294, 1, 1, "", "Panel2D"], [294, 1, 1, "", "TabPanel2D"], [294, 1, 1, "", "TabUI"]], "fury.ui.containers.GridUI": [[294, 3, 1, "", "ANTICLOCKWISE_ROTATION_X"], [294, 3, 1, "", "ANTICLOCKWISE_ROTATION_Y"], [294, 3, 1, "", "CLOCKWISE_ROTATION_X"], [294, 3, 1, "", "CLOCKWISE_ROTATION_Y"], [294, 2, 1, "", "__init__"], [294, 2, 1, "", "key_press_callback"], [294, 2, 1, "", "left_click_callback"], [294, 2, 1, "", "left_click_callback2"], [294, 2, 1, "", "left_release_callback"], [294, 2, 1, "", "left_release_callback2"], [294, 2, 1, "", "mouse_move_callback"], [294, 2, 1, "", "mouse_move_callback2"], [294, 2, 1, "", "resize"]], "fury.ui.containers.ImageContainer2D": [[294, 2, 1, "", "__init__"], [294, 3, 1, "", "img"], [294, 2, 1, "", "resize"], [294, 2, 1, "", "scale"], [294, 2, 1, "", "set_img"], [294, 3, 1, "", "size"]], "fury.ui.containers.Panel2D": [[294, 2, 1, "", "__init__"], [294, 2, 1, "", "add_element"], [294, 3, 1, "", "alignment"], [294, 4, 1, "", "border_color"], [294, 4, 1, "", "border_width"], [294, 4, 1, "", "color"], [294, 2, 1, "", "left_button_dragged"], [294, 2, 1, "", "left_button_pressed"], [294, 4, 1, "", "opacity"], [294, 2, 1, "", "re_align"], [294, 2, 1, "", "remove_element"], [294, 2, 1, "", "resize"], [294, 2, 1, "", "set_visibility"], [294, 2, 1, "", "update_border_coords"], [294, 2, 1, "", "update_element"]], "fury.ui.containers.TabPanel2D": [[294, 2, 1, "", "__init__"], [294, 2, 1, "", "add_element"], [294, 4, 1, "", "color"], [294, 3, 1, "", "content_panel"], [294, 2, 1, "", "remove_element"], [294, 2, 1, "", "resize"], [294, 3, 1, "", "text_block"], [294, 4, 1, "", "title"], [294, 4, 1, "", "title_bold"], [294, 4, 1, "", "title_color"], [294, 4, 1, "", "title_font_size"], [294, 4, 1, "", "title_italic"], [294, 2, 1, "", "update_element"]], "fury.ui.containers.TabUI": [[294, 2, 1, "", "__init__"], [294, 2, 1, "", "add_element"], [294, 2, 1, "", "collapse_tab_ui"], [294, 2, 1, "", "left_button_dragged"], [294, 2, 1, "", "left_button_pressed"], [294, 2, 1, "", "remove_element"], [294, 2, 1, "", "select_tab_callback"], [294, 3, 1, "", "tabs"], [294, 2, 1, "", "update_element"], [294, 2, 1, "", "update_tabs"]], "fury.ui.core": [[294, 1, 1, "", "Button2D"], [294, 1, 1, "", "Disk2D"], [294, 1, 1, "", "Rectangle2D"], [294, 1, 1, "", "TextBlock2D"], [294, 1, 1, "", "UI"]], "fury.ui.core.Button2D": [[294, 2, 1, "", "__init__"], [294, 4, 1, "", "color"], [294, 2, 1, "", "next_icon"], [294, 2, 1, "", "next_icon_id"], [294, 2, 1, "", "resize"], [294, 2, 1, "", "scale"], [294, 2, 1, "", "set_icon"], [294, 2, 1, "", "set_icon_by_name"]], "fury.ui.core.Disk2D": [[294, 2, 1, "", "__init__"], [294, 4, 1, "", "color"], [294, 4, 1, "", "inner_radius"], [294, 4, 1, "", "opacity"], [294, 4, 1, "", "outer_radius"]], "fury.ui.core.Rectangle2D": [[294, 2, 1, "", "__init__"], [294, 4, 1, "", "color"], [294, 4, 1, "", "height"], [294, 4, 1, "", "opacity"], [294, 2, 1, "", "resize"], [294, 4, 1, "", "width"]], "fury.ui.core.TextBlock2D": [[294, 2, 1, "", "__init__"], [294, 3, 1, "", "actor"], [294, 4, 1, "id4", "auto_font_scale"], [294, 4, 1, "", "background_color"], [294, 3, 1, "", "bg_color"], [294, 4, 1, "id5", "bold"], [294, 2, 1, "", "cal_size_from_message"], [294, 4, 1, "id6", "color"], [294, 4, 1, "id7", "dynamic_bbox"], [294, 4, 1, "id8", "font_family"], [294, 4, 1, "id9", "font_size"], [294, 4, 1, "id10", "italic"], [294, 4, 1, "id11", "justification"], [294, 4, 1, "id12", "message"], [294, 3, 1, "", "position"], [294, 2, 1, "", "resize"], [294, 4, 1, "id13", "shadow"], [294, 3, 1, "", "size"], [294, 2, 1, "", "update_alignment"], [294, 2, 1, "", "update_bounding_box"], [294, 4, 1, "id14", "vertical_justification"]], "fury.ui.core.UI": [[294, 2, 1, "", "__init__"], [294, 4, 1, "", "actors"], [294, 2, 1, "", "add_callback"], [294, 2, 1, "", "add_to_scene"], [294, 4, 1, "id0", "center"], [294, 2, 1, "", "handle_events"], [294, 2, 1, "", "key_press_callback"], [294, 2, 1, "", "left_button_click_callback"], [294, 2, 1, "", "left_button_release_callback"], [294, 2, 1, "", "middle_button_click_callback"], [294, 2, 1, "", "middle_button_release_callback"], [294, 2, 1, "", "mouse_move_callback"], [294, 3, 1, "", "on_key_press"], [294, 3, 1, "", "on_left_mouse_button_clicked"], [294, 3, 1, "", "on_left_mouse_button_dragged"], [294, 3, 1, "", "on_left_mouse_button_pressed"], [294, 3, 1, "", "on_left_mouse_button_released"], [294, 3, 1, "", "on_left_mouse_double_clicked"], [294, 3, 1, "", "on_middle_mouse_button_clicked"], [294, 3, 1, "", "on_middle_mouse_button_dragged"], [294, 3, 1, "", "on_middle_mouse_button_pressed"], [294, 3, 1, "", "on_middle_mouse_button_released"], [294, 3, 1, "", "on_middle_mouse_double_clicked"], [294, 3, 1, "", "on_right_mouse_button_clicked"], [294, 3, 1, "", "on_right_mouse_button_dragged"], [294, 3, 1, "", "on_right_mouse_button_pressed"], [294, 3, 1, "", "on_right_mouse_button_released"], [294, 3, 1, "", "on_right_mouse_double_clicked"], [294, 4, 1, "id2", "position"], [294, 2, 1, "", "right_button_click_callback"], [294, 2, 1, "", "right_button_release_callback"], [294, 2, 1, "", "set_visibility"], [294, 4, 1, "id3", "size"]], "fury.ui.elements": [[294, 1, 1, "", "Card2D"], [294, 1, 1, "", "Checkbox"], [294, 1, 1, "", "ComboBox2D"], [294, 1, 1, "", "DrawPanel"], [294, 1, 1, "", "DrawShape"], [294, 1, 1, "", "FileMenu2D"], [294, 1, 1, "", "LineDoubleSlider2D"], [294, 1, 1, "", "LineSlider2D"], [294, 1, 1, "", "ListBox2D"], [294, 1, 1, "", "ListBoxItem2D"], [294, 1, 1, "", "Option"], [294, 1, 1, "", "PlaybackPanel"], [294, 1, 1, "", "RadioButton"], [294, 1, 1, "", "RangeSlider"], [294, 1, 1, "", "RingSlider2D"], [294, 1, 1, "", "SpinBox"], [294, 1, 1, "", "TextBox2D"]], "fury.ui.elements.Card2D": [[294, 2, 1, "", "__init__"], [294, 4, 1, "", "body"], [294, 3, 1, "", "body_box"], [294, 4, 1, "", "color"], [294, 3, 1, "", "image"], [294, 2, 1, "", "left_button_dragged"], [294, 2, 1, "", "left_button_pressed"], [294, 2, 1, "", "resize"], [294, 4, 1, "", "title"], [294, 3, 1, "", "title_box"]], "fury.ui.elements.Checkbox": [[294, 2, 1, "", "__init__"], [294, 4, 1, "", "font_size"], [294, 3, 1, "", "labels"], [294, 3, 1, "", "options"], [294, 4, 1, "id17", "padding"]], "fury.ui.elements.ComboBox2D": [[294, 2, 1, "", "__init__"], [294, 2, 1, "", "append_item"], [294, 3, 1, "", "drop_down_button"], [294, 3, 1, "", "drop_down_menu"], [294, 2, 1, "", "left_button_dragged"], [294, 2, 1, "", "left_button_pressed"], [294, 2, 1, "", "menu_toggle_callback"], [294, 2, 1, "", "resize"], [294, 2, 1, "", "select_option_callback"], [294, 4, 1, "", "selected_text"], [294, 4, 1, "", "selected_text_index"], [294, 3, 1, "", "selection_box"], [294, 2, 1, "", "set_visibility"]], "fury.ui.elements.DrawPanel": [[294, 2, 1, "", "__init__"], [294, 2, 1, "", "cal_min_boundary_distance"], [294, 2, 1, "", "clamp_mouse_position"], [294, 4, 1, "", "current_mode"], [294, 2, 1, "", "draw_shape"], [294, 2, 1, "", "handle_mouse_click"], [294, 2, 1, "", "handle_mouse_drag"], [294, 2, 1, "", "left_button_dragged"], [294, 2, 1, "", "left_button_pressed"], [294, 2, 1, "", "resize"], [294, 2, 1, "", "resize_shape"], [294, 2, 1, "", "show_rotation_slider"], [294, 2, 1, "", "update_button_icons"], [294, 2, 1, "", "update_shape_selection"]], "fury.ui.elements.DrawShape": [[294, 2, 1, "", "__init__"], [294, 2, 1, "", "cal_bounding_box"], [294, 4, 1, "", "center"], [294, 2, 1, "", "clamp_position"], [294, 4, 1, "", "is_selected"], [294, 2, 1, "", "left_button_dragged"], [294, 2, 1, "", "left_button_pressed"], [294, 2, 1, "", "left_button_released"], [294, 2, 1, "", "remove"], [294, 2, 1, "", "resize"], [294, 2, 1, "", "rotate"], [294, 2, 1, "", "selection_change"], [294, 2, 1, "", "update_shape_position"]], "fury.ui.elements.FileMenu2D": [[294, 2, 1, "", "__init__"], [294, 2, 1, "", "directory_click_callback"], [294, 3, 1, "", "extensions"], [294, 2, 1, "", "get_all_file_names"], [294, 2, 1, "", "get_directory_names"], [294, 2, 1, "", "get_file_names"], [294, 3, 1, "", "listbox"], [294, 2, 1, "", "resize"], [294, 2, 1, "", "scroll_callback"], [294, 2, 1, "", "set_slot_colors"]], "fury.ui.elements.LineDoubleSlider2D": [[294, 2, 1, "", "__init__"], [294, 3, 1, "", "active_color"], [294, 4, 1, "", "bottom_disk_ratio"], [294, 4, 1, "", "bottom_disk_value"], [294, 4, 1, "", "bottom_y_position"], [294, 2, 1, "", "coord_to_ratio"], [294, 3, 1, "", "default_color"], [294, 2, 1, "", "format_text"], [294, 2, 1, "", "handle_move_callback"], [294, 2, 1, "", "handle_release_callback"], [294, 3, 1, "", "handles"], [294, 4, 1, "", "left_disk_ratio"], [294, 4, 1, "", "left_disk_value"], [294, 4, 1, "", "left_x_position"], [294, 3, 1, "", "length"], [294, 3, 1, "", "line_width"], [294, 2, 1, "", "ratio_to_coord"], [294, 2, 1, "", "ratio_to_value"], [294, 4, 1, "", "right_disk_ratio"], [294, 4, 1, "", "right_disk_value"], [294, 4, 1, "", "right_x_position"], [294, 2, 1, "", "set_position"], [294, 3, 1, "", "shape"], [294, 3, 1, "", "text"], [294, 4, 1, "", "top_disk_ratio"], [294, 4, 1, "", "top_disk_value"], [294, 4, 1, "", "top_y_position"], [294, 3, 1, "", "track"], [294, 2, 1, "", "update"], [294, 2, 1, "", "value_to_ratio"]], "fury.ui.elements.LineSlider2D": [[294, 2, 1, "", "__init__"], [294, 3, 1, "", "active_color"], [294, 4, 1, "", "bottom_y_position"], [294, 3, 1, "", "default_color"], [294, 2, 1, "", "format_text"], [294, 3, 1, "", "handle"], [294, 2, 1, "", "handle_move_callback"], [294, 2, 1, "", "handle_release_callback"], [294, 4, 1, "", "left_x_position"], [294, 3, 1, "", "length"], [294, 3, 1, "", "line_width"], [294, 4, 1, "", "ratio"], [294, 4, 1, "", "right_x_position"], [294, 2, 1, "", "set_position"], [294, 3, 1, "", "shape"], [294, 3, 1, "", "text"], [294, 4, 1, "", "top_y_position"], [294, 3, 1, "", "track"], [294, 2, 1, "", "track_click_callback"], [294, 2, 1, "", "update"], [294, 4, 1, "", "value"]], "fury.ui.elements.ListBox2D": [[294, 2, 1, "", "__init__"], [294, 2, 1, "", "clear_selection"], [294, 2, 1, "", "down_button_callback"], [294, 3, 1, "", "on_change"], [294, 2, 1, "", "resize"], [294, 2, 1, "", "scroll_click_callback"], [294, 2, 1, "", "scroll_drag_callback"], [294, 2, 1, "", "scroll_release_callback"], [294, 2, 1, "", "select"], [294, 2, 1, "", "up_button_callback"], [294, 2, 1, "", "update"], [294, 2, 1, "", "update_scrollbar"]], "fury.ui.elements.ListBoxItem2D": [[294, 2, 1, "", "__init__"], [294, 2, 1, "", "deselect"], [294, 4, 1, "", "element"], [294, 2, 1, "", "left_button_clicked"], [294, 2, 1, "", "resize"], [294, 2, 1, "", "select"]], "fury.ui.elements.Option": [[294, 2, 1, "", "__init__"], [294, 2, 1, "", "deselect"], [294, 3, 1, "", "font_size"], [294, 3, 1, "", "label"], [294, 2, 1, "", "select"], [294, 2, 1, "", "toggle"]], "fury.ui.elements.PlaybackPanel": [[294, 2, 1, "", "__init__"], [294, 4, 1, "", "current_time"], [294, 4, 1, "", "current_time_str"], [294, 4, 1, "", "final_time"], [294, 2, 1, "", "hide"], [294, 2, 1, "", "loop"], [294, 2, 1, "", "pause"], [294, 2, 1, "", "play"], [294, 2, 1, "", "play_once"], [294, 2, 1, "", "show"], [294, 4, 1, "", "speed"], [294, 2, 1, "", "stop"], [294, 4, 1, "", "width"]], "fury.ui.elements.RadioButton": [[294, 2, 1, "", "__init__"], [294, 3, 1, "", "labels"], [294, 3, 1, "", "options"], [294, 3, 1, "", "padding"]], "fury.ui.elements.RangeSlider": [[294, 2, 1, "", "__init__"], [294, 3, 1, "", "range_slider"], [294, 3, 1, "", "range_slider_center"], [294, 2, 1, "", "range_slider_handle_move_callback"], [294, 3, 1, "", "value_slider"], [294, 3, 1, "", "value_slider_center"]], "fury.ui.elements.RingSlider2D": [[294, 2, 1, "", "__init__"], [294, 3, 1, "", "active_color"], [294, 4, 1, "", "angle"], [294, 3, 1, "", "default_color"], [294, 2, 1, "", "format_text"], [294, 3, 1, "", "handle"], [294, 2, 1, "", "handle_move_callback"], [294, 2, 1, "", "handle_release_callback"], [294, 4, 1, "id15", "mid_track_radius"], [294, 2, 1, "", "move_handle"], [294, 4, 1, "id16", "previous_value"], [294, 4, 1, "", "ratio"], [294, 3, 1, "", "text"], [294, 3, 1, "", "track"], [294, 2, 1, "", "track_click_callback"], [294, 2, 1, "", "update"], [294, 4, 1, "", "value"]], "fury.ui.elements.SpinBox": [[294, 2, 1, "", "__init__"], [294, 2, 1, "", "decrement"], [294, 2, 1, "", "decrement_callback"], [294, 2, 1, "", "increment"], [294, 2, 1, "", "increment_callback"], [294, 2, 1, "", "resize"], [294, 2, 1, "", "textbox_update_value"], [294, 2, 1, "", "validate_value"], [294, 4, 1, "", "value"]], "fury.ui.elements.TextBox2D": [[294, 2, 1, "", "__init__"], [294, 3, 1, "", "actor"], [294, 2, 1, "", "add_character"], [294, 3, 1, "", "caret_pos"], [294, 2, 1, "", "edit_mode"], [294, 2, 1, "", "handle_character"], [294, 3, 1, "", "height"], [294, 3, 1, "", "init"], [294, 2, 1, "", "key_press"], [294, 2, 1, "", "left_button_press"], [294, 2, 1, "", "left_move_left"], [294, 2, 1, "", "left_move_right"], [294, 2, 1, "", "move_caret_left"], [294, 2, 1, "", "move_caret_right"], [294, 2, 1, "", "move_left"], [294, 2, 1, "", "move_right"], [294, 2, 1, "", "remove_character"], [294, 2, 1, "", "render_text"], [294, 2, 1, "", "right_move_left"], [294, 2, 1, "", "right_move_right"], [294, 2, 1, "", "set_message"], [294, 2, 1, "", "showable_text"], [294, 3, 1, "", "text"], [294, 3, 1, "", "width"], [294, 2, 1, "", "width_set_text"], [294, 3, 1, "", "window_left"], [294, 3, 1, "", "window_right"]], "fury.ui.helpers": [[294, 5, 1, "", "cal_bounding_box_2d"], [294, 5, 1, "", "check_overflow"], [294, 5, 1, "", "clip_overflow"], [294, 5, 1, "", "rotate_2d"], [294, 5, 1, "", "wrap_overflow"]], "fury.utils": [[295, 5, 1, "", "add_polydata_numeric_field"], [295, 5, 1, "", "apply_affine"], [295, 5, 1, "", "apply_affine_to_actor"], [295, 5, 1, "", "array_from_actor"], [295, 5, 1, "", "asbytes"], [295, 5, 1, "", "change_vertices_order"], [295, 5, 1, "", "color_check"], [295, 5, 1, "", "colors_from_actor"], [295, 5, 1, "", "compute_bounds"], [295, 5, 1, "", "fix_winding_order"], [295, 5, 1, "", "get_actor_from_polydata"], [295, 5, 1, "", "get_actor_from_polymapper"], [295, 5, 1, "", "get_actor_from_primitive"], [295, 5, 1, "", "get_bounding_box_sizes"], [295, 5, 1, "", "get_bounds"], [295, 5, 1, "", "get_grid_cells_position"], [295, 5, 1, "", "get_polydata_colors"], [295, 5, 1, "", "get_polydata_field"], [295, 5, 1, "", "get_polydata_lines"], [295, 5, 1, "", "get_polydata_normals"], [295, 5, 1, "", "get_polydata_primitives_count"], [295, 5, 1, "", "get_polydata_tangents"], [295, 5, 1, "", "get_polydata_tcoord"], [295, 5, 1, "", "get_polydata_triangles"], [295, 5, 1, "", "get_polydata_vertices"], [295, 5, 1, "", "get_polymapper_from_polydata"], [295, 5, 1, "", "is_ui"], [295, 5, 1, "", "lines_to_vtk_polydata"], [295, 5, 1, "", "map_coordinates_3d_4d"], [295, 5, 1, "", "normalize_v3"], [295, 5, 1, "", "normals_from_actor"], [295, 5, 1, "", "normals_from_v_f"], [295, 5, 1, "", "normals_to_actor"], [295, 5, 1, "", "numpy_to_vtk_cells"], [295, 5, 1, "", "numpy_to_vtk_colors"], [295, 5, 1, "", "numpy_to_vtk_image_data"], [295, 5, 1, "", "numpy_to_vtk_matrix"], [295, 5, 1, "", "numpy_to_vtk_points"], [295, 5, 1, "", "primitives_count_from_actor"], [295, 5, 1, "", "primitives_count_to_actor"], [295, 5, 1, "", "remove_observer_from_actor"], [295, 5, 1, "", "repeat_sources"], [295, 5, 1, "", "represent_actor_as_wireframe"], [295, 5, 1, "", "rgb_to_vtk"], [295, 5, 1, "", "rotate"], [295, 5, 1, "", "set_actor_origin"], [295, 5, 1, "", "set_input"], [295, 5, 1, "", "set_polydata_colors"], [295, 5, 1, "", "set_polydata_normals"], [295, 5, 1, "", "set_polydata_primitives_count"], [295, 5, 1, "", "set_polydata_tangents"], [295, 5, 1, "", "set_polydata_tcoords"], [295, 5, 1, "", "set_polydata_triangles"], [295, 5, 1, "", "set_polydata_vertices"], [295, 5, 1, "", "shallow_copy"], [295, 5, 1, "", "tangents_from_actor"], [295, 5, 1, "", "tangents_from_direction_of_anisotropy"], [295, 5, 1, "", "tangents_to_actor"], [295, 5, 1, "", "triangle_order"], [295, 5, 1, "", "update_actor"], [295, 5, 1, "", "update_polydata_normals"], [295, 5, 1, "", "update_surface_actor_colors"], [295, 5, 1, "", "vertices_from_actor"], [295, 5, 1, "", "vtk_matrix_to_numpy"]], "fury.window": [[296, 1, 1, "", "Scene"], [296, 1, 1, "", "ShowManager"], [296, 5, 1, "", "analyze_scene"], [296, 5, 1, "", "analyze_snapshot"], [296, 5, 1, "", "antialiasing"], [296, 5, 1, "", "enable_stereo"], [296, 5, 1, "", "gl_disable_blend"], [296, 5, 1, "", "gl_disable_depth"], [296, 5, 1, "", "gl_enable_blend"], [296, 5, 1, "", "gl_enable_depth"], [296, 5, 1, "", "gl_get_current_state"], [296, 5, 1, "", "gl_reset_blend"], [296, 5, 1, "", "gl_set_additive_blending"], [296, 5, 1, "", "gl_set_additive_blending_white_background"], [296, 5, 1, "", "gl_set_multiplicative_blending"], [296, 5, 1, "", "gl_set_normal_blending"], [296, 5, 1, "", "gl_set_subtractive_blending"], [296, 5, 1, "", "record"], [296, 5, 1, "", "release_context"], [296, 5, 1, "", "show"], [296, 5, 1, "", "snapshot"]], "fury.window.Scene": [[296, 2, 1, "", "__init__"], [296, 2, 1, "", "add"], [296, 2, 1, "", "azimuth"], [296, 2, 1, "", "background"], [296, 2, 1, "", "camera"], [296, 2, 1, "", "camera_direction"], [296, 2, 1, "", "camera_info"], [296, 2, 1, "", "clear"], [296, 2, 1, "", "dolly"], [296, 2, 1, "", "elevation"], [296, 2, 1, "", "fxaa_off"], [296, 2, 1, "", "fxaa_on"], [296, 2, 1, "", "get_camera"], [296, 4, 1, "", "last_render_time"], [296, 2, 1, "", "pitch"], [296, 2, 1, "", "projection"], [296, 2, 1, "", "reset_camera"], [296, 2, 1, "", "reset_camera_tight"], [296, 2, 1, "", "reset_clipping_range"], [296, 2, 1, "", "rm"], [296, 2, 1, "", "rm_all"], [296, 2, 1, "", "roll"], [296, 2, 1, "", "set_camera"], [296, 2, 1, "", "size"], [296, 2, 1, "", "skybox"], [296, 2, 1, "", "yaw"], [296, 2, 1, "", "zoom"]], "fury.window.ShowManager": [[296, 2, 1, "", "__init__"], [296, 2, 1, "", "add_animation"], [296, 2, 1, "", "add_iren_callback"], [296, 2, 1, "", "add_timer_callback"], [296, 2, 1, "", "add_window_callback"], [296, 4, 1, "", "animations"], [296, 2, 1, "", "destroy_timer"], [296, 2, 1, "", "destroy_timers"], [296, 2, 1, "", "exit"], [296, 4, 1, "", "frame_rate"], [296, 2, 1, "", "initialize"], [296, 3, 1, "", "iren"], [296, 2, 1, "", "is_done"], [296, 2, 1, "", "lock"], [296, 2, 1, "", "lock_current"], [296, 2, 1, "", "play_events"], [296, 2, 1, "", "play_events_from_file"], [296, 2, 1, "", "record_events"], [296, 2, 1, "", "record_events_to_file"], [296, 2, 1, "", "release_current"], [296, 2, 1, "", "release_lock"], [296, 2, 1, "", "remove_animation"], [296, 2, 1, "", "render"], [296, 2, 1, "", "save_screenshot"], [296, 3, 1, "", "scene"], [296, 2, 1, "", "start"], [296, 3, 1, "", "style"], [296, 4, 1, "", "timelines"], [296, 2, 1, "", "wait"], [296, 3, 1, "", "window"]]}, "objtypes": {"0": "py:module", "1": "py:class", "2": "py:method", "3": "py:attribute", "4": "py:property", "5": "py:function"}, "objnames": {"0": ["py", "module", "Python module"], "1": ["py", "class", "Python class"], "2": ["py", "method", "Python method"], "3": ["py", "attribute", "Python attribute"], "4": ["py", "property", "Python property"], "5": ["py", "function", "Python function"]}, "titleterms": {"introductori": [0, 90], "comput": [1, 23, 42, 58, 71, 79, 86, 91, 314], "time": [1, 23, 42, 58, 71, 79, 86, 91, 259, 261, 314], "furi": [2, 3, 16, 34, 53, 60, 65, 87, 88, 89, 94, 99, 100, 101, 102, 103, 104, 105, 107, 123, 133, 139, 149, 152, 164, 167, 175, 176, 177, 178, 221, 223, 229, 230, 273], "arrow": [2, 274], "actor": [2, 3, 16, 28, 60, 76, 94, 128, 208, 218, 228, 236, 239, 270, 274, 275, 285], "cone": [3, 254, 274], "textur": [4, 19, 274, 285], "sphere": [4, 16, 17, 19, 50, 53, 60, 65, 72, 73, 74, 202, 274], "anim": [4, 9, 13, 15, 25, 29, 36, 57, 60, 63, 64, 65, 66, 67, 69, 90, 168, 181, 182, 193, 200, 203, 205, 207, 208, 209, 211, 220, 221, 223, 228, 276], "earth": 5, "coordin": 5, "convers": 5, "visual": [6, 7, 18, 24, 27, 28, 35, 36, 39, 76, 143, 149, 245, 254, 270], "gltf": [6, 7, 8, 9, 13, 62, 185, 189, 194, 197, 228, 282], "file": [6, 7, 8, 13, 62, 228], "export": [8, 189, 197, 228], "scene": [8, 59, 94, 228, 296], "morph": [9, 224, 228], "multithread": 10, "exampl": [10, 94], "simpl": [11, 14, 51, 94, 228], "pick": [11, 288], "select": [12, 54], "multipl": [12, 94, 121, 215], "object": [12, 89, 94, 135, 136, 172, 173, 174, 226, 227, 228, 268, 270, 272], "skelet": [13, 209, 220, 228], "volum": [14, 27, 285], "slice": 14, "render": [14, 27, 39, 72, 73, 94, 285], "from": [14, 27, 62, 195, 228], "t1": 14, "specif": [14, 27], "valu": [14, 27], "rang": [14, 54], "fa": 14, "your": [14, 27, 241], "colormap": [14, 27, 277], "creat": [14, 60, 64, 68, 94, 197, 210], "mosaic": 14, "solar": 15, "system": [15, 143, 149, 152], "spiki": 17, "surfac": [18, 39, 274], "us": [20, 28, 31, 46, 49, 50, 59, 75, 78, 89, 90, 103, 149, 155, 202], "timer": [20, 94], "collis": [21, 80, 94, 117], "particl": [21, 33], "box": [21, 46, 261, 274], "demo": [22, 37, 90], "advanc": 24, "interact": [24, 37, 87], "2d": 25, "function": [25, 135], "brownian": 26, "motion": [26, 33], "bundl": 27, "metric": 27, "show": [27, 46, 47, 48, 50, 54, 56, 94, 296], "everi": 27, "streamlin": [27, 39], "an": [27, 64], "orient": [27, 120], "color": [27, 46, 50, 53, 61, 77, 187], "point": [27, 274, 285], "default": [27, 64], "differ": [27, 49, 143], "add": 27, "depth": 27, "cue": 27, "fake": 27, "tube": 27, "combin": [27, 33], "displai": 28, "tensor": [28, 275], "ellipsoid": [28, 236, 239, 248, 251, 257, 270, 274], "dti": [28, 245, 260, 270], "tensor_slic": [28, 274], "v": [28, 75], "qualiti": 28, "comparison": 28, "larger": 28, "amount": 28, "data": [28, 62, 143, 200, 248, 279], "electromagnet": 29, "wave": 29, "propag": 29, "brain": [30, 103], "fiber": 30, "odf": [30, 266, 270, 271], "visualis": 30, "fine": 31, "tune": 31, "opengl": 31, "state": 31, "shader": [31, 70, 74, 90, 127, 129, 137, 206, 285, 291], "callback": [31, 47, 94], "fractal": 32, "charg": 33, "magnet": 33, "electr": 33, "field": 33, "marker": [34, 274], "interdisciplinari": 35, "map": 35, "journal": 35, "network": [35, 36, 149, 152, 155], "version": [36, 206], "pbr": [37, 73, 228], "plai": [38, 207], "video": 38, "3d": [38, 179], "world": 38, "roi": 39, "tesseract": 40, "hypercub": 40, "user": [41, 54, 87, 90], "interfac": [41, 54, 90], "element": [41, 49, 90, 294], "button": [43, 46, 50, 54], "text": [43, 54, 60, 237], "card": [44, 45], "figur": [46, 274], "control": [46, 50, 53, 56], "check": [46, 108, 140, 146, 152, 158, 161], "radio": [46, 50], "manag": [46, 47, 48, 50, 54, 56, 94], "combobox": [47, 53, 240], "drawpanel": [48, 183, 184, 217, 294], "layout": [49, 149, 152, 155, 165, 284], "ui": [49, 52, 53, 120, 125, 144, 147, 150, 153, 156, 159, 168, 183, 184, 294], "shape": [51, 54, 195, 204], "spinbox": [52, 234, 264, 294], "tab": [53, 120, 125], "slider": [53, 54, 56], "cube": [53, 54, 56, 274], "index": 53, "0": [53, 99, 100, 101, 102, 104, 105, 107, 123, 133, 139, 167, 177, 230, 231, 232, 233, 299, 303, 304, 305, 306, 308, 310, 312, 313], "checkbox": [53, 294], "For": 53, "cylind": [53, 75, 274], "1": [53, 99, 100, 101, 107, 108, 133, 140, 141, 152, 182, 183, 185, 234, 235, 236, 299, 300, 301, 302, 307, 309, 311], "2": [53, 102, 144, 184, 187, 189, 237, 238, 239, 301, 304], "imag": 54, "panel": 54, "menu": 54, "listbox": 55, "bezier": [59, 190], "interpol": [59, 61, 62, 64, 67, 187, 190, 193, 202, 276], "posit": [59, 62, 64], "cubic": [59, 62, 190], "curv": 59, "paramet": 59, "set": [59, 61, 62, 64, 68, 94], "keyfram": [59, 60, 61, 62, 63, 64, 65, 67, 68, 69, 182, 221, 223], "A": [59, 143, 146, 155, 179, 185, 265], "more": [59, 127, 129, 165, 199], "complex": 59, "camera": [60, 193, 285], "opac": 60, "The": [60, 155, 179, 180, 181, 231, 235, 238, 256, 269], "plan": [60, 246], "main": [60, 292], "timelin": [60, 68, 135, 136, 172, 173, 174, 193, 196, 199, 206, 226, 227, 228, 268, 270, 272, 276], "ad": [60, 94, 150, 191, 196, 215, 218, 225], "static": [60, 228], "50": 60, "make": [62, 75, 190, 239], "custom": [62, 164], "implement": [62, 155, 182, 187, 190, 196, 202, 236, 263, 266, 270, 271, 315], "spline": [62, 67], "same": [62, 208], "one": 62, "you": [62, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 124, 125, 126, 127, 128, 129, 130, 131, 132, 134, 137, 142, 145, 146, 148, 151, 152, 154, 157, 160, 163, 166, 169, 171, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 234, 237, 240, 246, 249, 252, 255, 258, 261, 264, 267], "get": [62, 95, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 124, 125, 126, 127, 128, 129, 130, 131, 132, 134, 137, 140, 141, 144, 145, 146, 147, 148, 150, 151, 152, 153, 154, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 168, 169, 170, 171, 175, 176, 179, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 233, 234, 236, 237, 239, 240, 242, 243, 245, 246, 248, 249, 251, 252, 254, 255, 257, 258, 260, 261, 263, 264, 266, 267, 271, 315], "hierarch": [63, 211], "what": [64, 65, 68, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 124, 125, 126, 127, 128, 129, 130, 131, 132, 134, 137, 140, 141, 142, 144, 145, 146, 147, 148, 150, 151, 152, 153, 154, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 168, 169, 170, 171, 175, 176, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 233, 234, 235, 236, 237, 239, 240, 242, 243, 245, 246, 248, 249, 250, 251, 252, 254, 255, 257, 258, 260, 261, 263, 264, 266, 267, 271], "i": [64, 65, 68, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 124, 125, 126, 127, 128, 129, 130, 131, 132, 134, 137, 140, 141, 142, 144, 145, 146, 147, 148, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 168, 169, 170, 171, 175, 176, 179, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 233, 234, 236, 237, 239, 240, 242, 243, 244, 245, 246, 248, 249, 250, 251, 252, 254, 255, 257, 258, 259, 260, 261, 263, 264, 265, 266, 267, 269, 271], "ar": [64, 250], "environ": 64, "chang": [64, 94], "singl": [64, 94, 128, 193], "properti": [64, 94], "introduct": [65, 135], "exactli": 65, "translat": [65, 119, 212, 293], "arm": 66, "robot": 66, "wrap": [67, 269], "up": [67, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 124, 125, 126, 127, 128, 129, 130, 131, 132, 134, 137, 140, 141, 142, 144, 145, 146, 147, 148, 150, 151, 152, 153, 154, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 168, 169, 170, 171, 175, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 233, 234, 236, 237, 239, 240, 242, 243, 245, 246, 248, 249, 250, 251, 252, 254, 255, 257, 258, 260, 261, 263, 264, 266, 267, 271], "sdf": [72, 75, 76, 121, 124, 126, 175, 236, 270, 274], "impostor": 72, "billboard": [72, 202, 274], "tradit": 72, "refer": [72, 75, 174, 270, 297], "physic": [73, 78, 83, 90, 128, 131], "base": [73, 206, 210, 291], "principl": 74, "brdf": 74, "polygon": [75, 285], "vari": 77, "integr": [78, 90, 94], "pybullet": [78, 90, 94], "ball": [80, 84, 94, 117, 131], "simul": [80, 81, 82, 83, 84, 94, 117, 130, 131], "brick": [81, 94, 117], "wall": [81, 94, 117], "sync": [81, 83, 94], "chain": [82, 94, 130], "domino": [83, 94], "wreck": [84, 94, 131], "stream": [85, 87, 88, 89, 90, 149, 152, 292], "note": [87, 89, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313], "webrtc": [88, 89, 149, 152], "mjpeg": [88, 89], "widget": [89, 292], "tutori": [90, 125, 130, 131, 214, 225, 248, 251, 257, 260], "blog": [92, 108, 109, 141, 142, 226, 228, 268, 270, 272], "commun": [93, 108, 109, 142, 182, 185, 231, 232, 233], "join": 93, "u": 93, "contributor": 93, "guid": 94, "rigid": 94, "bodi": 94, "dynam": 94, "necessari": 94, "import": [94, 155, 185, 228, 238], "connect": 94, "mode": 94, "disconnect": 94, "graviti": 94, "applic": 94, "forc": [94, 117], "torqu": 94, "enabl": 94, "creation": 94, "initi": 94, "joint": 94, "start": [95, 250, 263, 315], "instal": 97, "depend": 97, "pypi": 97, "conda": 97, "via": [97, 178, 229], "sourc": [97, 134, 180], "test": [97, 149, 191, 196, 212, 215, 216], "run": 97, "offscreen": 97, "popul": 97, "our": 97, "document": [97, 196, 238, 315], "folder": 97, "structur": 97, "build": [97, 250], "about": [98, 179, 180, 235], "overview": [98, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313], "statement": 98, "need": [98, 265, 315], "mission": 98, "featur": [98, 144, 192, 199, 201, 315], "architectur": [98, 217], "licens": [98, 316], "credit": 98, "bug": [98, 149, 153, 156, 203, 205, 216, 315], "report": [98, 174, 315], "support": [98, 168, 195, 211, 213, 215, 220], "releas": [99, 100, 101, 102, 104, 105, 107, 123, 133, 139, 167, 177, 230, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 315], "3": [100, 104, 146, 147, 186, 190, 191, 240, 241, 242, 301, 305], "4": [101, 105, 150, 188, 193, 194, 243, 244, 245, 302, 306], "success": 103, "art": 103, "competit": 103, "googl": [106, 135, 136, 138, 172, 173, 174, 178, 226, 227, 228, 229, 268, 270, 272], "summer": [106, 135, 136, 138, 172, 173, 174, 178, 226, 227, 228, 229, 268, 270, 272], "code": [106, 110, 111, 135, 136, 138, 145, 148, 149, 151, 154, 155, 157, 160, 162, 163, 166, 169, 171, 172, 173, 174, 178, 179, 207, 226, 227, 228, 229, 268, 270, 272], "5": [107, 152, 153, 192, 196, 197, 246, 247, 248, 307], "weekli": [108, 140, 141, 146, 152, 158, 161, 226, 228, 268, 270, 272], "welcom": [108, 109, 141, 142], "my": [108, 109, 141, 142, 179, 180, 235], "gsoc": [108, 109, 142, 180, 181, 226, 228, 232, 233, 268, 270, 272], "did": [108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 124, 125, 126, 127, 128, 129, 130, 131, 132, 134, 137, 140, 141, 142, 144, 145, 146, 147, 148, 150, 151, 152, 153, 154, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 168, 169, 170, 171, 175, 176, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 233, 234, 236, 237, 239, 240, 242, 243, 245, 246, 248, 249, 250, 251, 252, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 269, 271], "do": [108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 124, 125, 126, 127, 128, 129, 130, 131, 132, 134, 137, 140, 141, 142, 144, 145, 146, 147, 148, 150, 151, 152, 153, 154, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 168, 169, 170, 171, 175, 176, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 233, 234, 236, 237, 239, 240, 242, 243, 245, 246, 248, 249, 251, 252, 254, 255, 257, 258, 260, 261, 263, 264, 266, 267, 271, 315], "dure": [108, 109, 142, 182, 185], "bond": [108, 109, 142, 182, 185, 231, 232, 233], "period": [108, 109, 142, 182, 185, 231, 232, 233], "come": [108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 124, 125, 126, 127, 128, 129, 130, 131, 132, 134, 137, 140, 141, 142, 144, 145, 146, 147, 148, 150, 151, 152, 153, 154, 156, 157, 158, 160, 161, 162, 163, 164, 165, 166, 168, 169, 170, 171, 175, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 233, 234, 236, 237, 239, 240, 242, 243, 245, 246, 248, 249, 251, 252, 254, 255, 257, 258, 260, 261, 263, 264, 266, 267, 271], "next": [108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 124, 125, 126, 127, 128, 129, 130, 131, 132, 134, 137, 140, 141, 142, 144, 145, 146, 147, 148, 150, 151, 152, 153, 154, 155, 156, 157, 158, 160, 161, 162, 163, 164, 165, 166, 168, 169, 170, 171, 175, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 233, 234, 235, 236, 237, 239, 240, 242, 243, 245, 246, 248, 249, 251, 252, 254, 255, 257, 258, 260, 261, 263, 264, 266, 267, 269, 271], "week": [108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 124, 125, 126, 127, 128, 129, 130, 131, 132, 134, 137, 140, 141, 142, 144, 145, 146, 147, 148, 150, 151, 152, 153, 154, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 168, 169, 170, 171, 175, 176, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 269, 271], "first": [110, 111, 145, 179, 209, 242, 245, 251], "thi": [110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 124, 125, 126, 127, 128, 129, 130, 131, 132, 134, 137, 140, 141, 144, 145, 146, 147, 148, 150, 151, 152, 153, 154, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 168, 169, 170, 171, 175, 176, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 231, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 271], "stuck": [110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 124, 125, 126, 127, 128, 129, 130, 131, 132, 134, 137, 140, 141, 144, 145, 146, 147, 148, 150, 151, 152, 153, 154, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 168, 169, 170, 171, 175, 176, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 233, 234, 236, 237, 239, 240, 242, 243, 245, 246, 248, 249, 251, 252, 254, 255, 257, 258, 260, 261, 263, 264, 266, 267, 271], "anywher": [110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 124, 125, 126, 127, 128, 129, 130, 131, 132, 134, 137, 140, 141, 144, 145, 146, 147, 148, 150, 151, 152, 153, 154, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 168, 169, 170, 171, 175, 176, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 233, 234, 236, 237, 239, 240, 242, 243, 245, 246, 248, 249, 251, 252, 254, 255, 257, 258, 260, 261, 263, 264, 266, 267, 271], "raymarch": [112, 114], "combobox2d": [113, 122, 294], "progress": [113, 115, 136, 172, 173, 190, 226, 227, 228, 268, 270, 272], "continu": [114, 118, 162], "textblock2d": [115, 122, 249, 258, 294], "spheric": [116, 118], "harmon": [116, 118], "mai": 117, "reposit": 119, "rotat": [119, 195, 198, 222, 293, 295], "size": 120, "primit": [121, 124, 126, 208, 290], "clip": 122, "overflow": 122, "6": [123, 133, 156, 195, 199, 200, 249, 250, 251, 308, 309], "improv": [124, 184, 189, 214], "tabpanel2d": [125, 294], "merg": [126, 258], "scrollbar": [128, 130, 131], "refactor": [130, 149, 265], "updat": [130, 131, 212, 217], "outlin": 132, "picker": 132, "part": 134, "journei": [134, 179, 180, 181], "end": 134, "unless": 134, "its": 134, "open": [134, 162, 170, 180], "dialog": 134, "save": 134, "2020": [135, 307, 308, 309], "final": [135, 136, 159, 170, 172, 173, 174, 194, 226, 227, 228, 258, 268, 270, 272], "work": [135, 136, 143, 147, 156, 162, 172, 173, 192, 198, 201, 209, 222, 226, 227, 228, 234, 242, 257, 268, 270, 272], "product": [135, 136, 172, 173, 226, 227, 228, 268, 270, 272], "propos": [135, 136, 172, 173, 174, 226, 227, 228, 268, 270, 272], "unsubmit": 135, "complet": [135, 136, 172, 173, 174, 226, 227, 228, 268, 270, 272], "other": [135, 136, 172, 173, 226, 227, 228, 268, 272, 315], "modifi": [136, 227], "showcas": 137, "7": [139, 158, 159, 167, 198, 202, 203, 252, 253, 254, 310, 311], "In": [140, 146, 152, 158, 161], "stadia": 143, "like": 143, "how": [143, 155, 256, 259, 262, 265, 269], "doe": 143, "share": 143, "between": 143, "process": 143, "multiprocess": 143, "rawarrai": 143, "insid": 143, "oper": 143, "addit": 144, "io": [144, 283], "modul": [144, 150, 275, 276, 279, 291, 292, 294], "python": [146, 149, 155], "core": [146, 294], "issu": [146, 149, 188, 199, 212, 237, 266], "adapt": 147, "gridlayout": [147, 284], "second": 148, "solid": 149, "monkei": 149, "patch": 149, "through": 149, "abstract": [149, 174, 268, 270], "class": 149, "namedtupl": 149, "grant": 149, "immut": 149, "avoid": 149, "silent": 149, "most": [149, 155], "relev": 149, "helio": [149, 152, 164, 175, 176], "ref": 149, "tree": 150, "third": 151, "gl": 152, "pr": [152, 153, 159, 162, 197, 198, 242, 246], "437": 152, "superactor": 152, "rebas": 153, "all": [153, 247], "w": 153, "r": 153, "t": 153, "restructur": 153, "tree2d": [153, 156, 159, 162], "fix": [153, 156, 188, 191, 197, 199, 203, 205, 212, 216, 218, 315], "fourth": 154, "algorithm": 155, "ipc": 155, "problem": [155, 186, 235, 238, 241, 244, 247, 250], "block": 155, "behavior": 155, "why": 155, "thread": 155, "good": [155, 238], "solut": [155, 266], "have": 155, "b": 155, "result": 155, "step": [155, 269], "summari": [155, 164], "pull": [155, 170, 228, 315], "request": [155, 170, 228, 315], "fifth": 157, "stall": 159, "finish": [159, 162], "sixth": 160, "8": [161, 162, 177, 201, 205, 206, 255, 256, 257, 312], "cleanup": 162, "seventh": 163, "09": [164, 299], "sphinx": 164, "9": [165, 204, 208, 209, 230, 258, 259, 260, 313], "eighth": 166, "10": [168, 175, 207, 211, 213, 261, 262, 263, 300, 301, 303, 306], "accordion": 168, "sprite": 168, "sheet": 168, "ninth": 169, "11": [170, 176, 210, 214, 215, 264, 265, 266, 302], "tenth": 171, "2021": [174, 310, 311], "bruno": 174, "messia": 174, "font": 175, "remov": 176, "flicker": 176, "effect": 176, "contribut": [178, 229, 315], "2022": [178, 180, 312], "till": 179, "accept": 179, "gsoc22": 179, "littl": [179, 214], "myself": [179, 180], "experi": [179, 263, 271], "develop": [179, 181], "game": [179, 181], "dai": [179, 180], "got": 179, "intro": [180, 181], "pre": 181, "begin": [181, 231, 267], "program": 181, "interest": 181, "opensourc": 181, "21": [181, 299], "22": 181, "basic": [182, 185], "api": [182, 190, 256, 297], "lai": 183, "foundat": 183, "deal": 186, "non": 187, "linear": 187, "clamp": 188, "fetcher": [189, 191, 228, 279], "redesign": 190, "gpu": 190, "side": 190, "doc": 191, "new": [192, 225], "glsl": 193, "loader": [194, 197], "center": 195, "slerp": [196, 276], "unit": 196, "try": [198, 246], "freehand": [198, 210], "draw": [198, 210], "equip": 199, "extract": 200, "polylin": 201, "closur": 202, "group": 204, "transform": [204, 215, 218, 285, 293], "back": 206, "understand": 207, "prototyp": 209, "12": [212, 218, 225, 267, 269, 271], "multi": [213, 220], "node": 213, "skin": [213, 228], "13": [216, 220, 221, 310], "separ": 216, "14": [217, 223, 224], "skeleton": 218, "global": 218, "15": [219, 313], "highlight": 219, "drawshap": [219, 294], "bone": 220, "now": [221, 223, 269], "bit": [221, 223], "easier": [221, 223], "16": 222, "here": 224, "load": [228, 291], "model": 228, "skine": 228, "emiss": 228, "materi": [228, 286], "indic": 228, "khrono": 228, "sampl": 228, "2023": [229, 232, 233, 313], "everyth": 231, "so": [231, 256, 259, 262, 265, 269], "project": 231, "": [231, 238, 241, 244, 247, 250, 253, 256, 259, 262, 265, 269], "goal": [231, 238, 241, 244, 247, 250, 253, 256, 259, 262, 265], "bound": [232, 233], "textbox": [234, 240], "enhanc": 234, "fbo": 235, "saga": 235, "past": 235, "current": 235, "tackl": 237, "justif": [237, 240], "icon": [237, 240], "flaw": [237, 240], "last": [238, 241, 244, 247, 250, 253, 256, 259, 262, 265, 269], "effort": [238, 241, 244, 247, 253, 256, 259, 262, 265, 269], "where": [238, 241, 244, 247, 250], "wa": [238, 241, 244, 247, 250, 253], "adjust": [239, 254, 266], "resolv": 240, "watch": 241, "expect": 241, "uncertainti": [242, 245, 254, 260, 270], "detail": [242, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313], "exam": 243, "prepar": [243, 248], "review": [243, 262], "noth": 244, "ever": 244, "lost": 244, "draft": [245, 251], "out": 246, "ahead": 246, "road": 247, "lead": 247, "rome": 247, "boundingbox": 249, "thing": 250, "sow": 252, "seed": 252, "treeui": 252, "experiment": 253, "done": [253, 260], "hard": 253, "anoth": 255, "textblockui": 255, "birth": 256, "versatil": 256, "go": [256, 259, 262, 265, 269], "explor": 257, "sh": [257, 263], "It": 259, "polish": [259, 260], "Its": 261, "spin": 261, "readi": 262, "bye": 264, "sometim": 265, "look": 266, "found": 266, "filedialog": 267, "quest": 267, "That": 269, "almost": 269, "get_info": 273, "enable_warn": 273, "disable_warn": 273, "contain": [274, 294], "slicer": 274, "contour_from_roi": 274, "contour_from_label": 274, "streamtub": 274, "line": 274, "scalar_bar": 274, "ax": 274, "odf_slic": [274, 275], "peak_slic": 274, "peak": [274, 275], "dot": 274, "disk": 274, "squar": 274, "rectangl": 274, "triangularpr": 274, "rhombicuboctahedron": 274, "pentagonalpr": 274, "octagonalpr": 274, "frustum": 274, "superquadr": 274, "vector_text": 274, "label": 274, "text_3d": 274, "grid": 274, "texture_upd": 274, "texture_on_spher": 274, "texture_2d": 274, "uncertainty_con": 274, "odfsliceractor": 275, "peakactor": 275, "tensor_ellipsoid": 275, "double_con": 275, "main_dir_uncertainti": 275, "helper": [276, 294], "cameraanim": 276, "get_previous_timestamp": 276, "get_next_timestamp": 276, "get_timestamps_from_keyfram": 276, "get_values_from_keyfram": 276, "get_time_tau": 276, "lerp": 276, "euclidean_dist": 276, "spline_interpol": 276, "cubic_spline_interpol": 276, "step_interpol": 276, "linear_interpol": 276, "cubic_bezier_interpol": 276, "color_interpol": 276, "hsv_color_interpol": 276, "lab_color_interpol": 276, "xyz_color_interpol": 276, "tan_cubic_spline_interpol": 276, "colormap_lookup_t": 277, "cc": 277, "ss": 277, "boys2rgb": 277, "orient2rgb": 277, "line_color": 277, "get_cmap": 277, "create_colormap": 277, "distinguishable_colormap": 277, "hex_to_rgb": 277, "rgb2hsv": 277, "hsv2rgb": 277, "xyz_from_rgb": 277, "rgb_from_xyz": 277, "xyz2rgb": 277, "rgb2xyz": 277, "get_xyz_coord": 277, "xyz2lab": 277, "lab2xyz": 277, "rgb2lab": 277, "lab2rgb": 277, "convert": 278, "matplotlib_figure_to_numpi": 278, "data_dir": 279, "update_progressbar": 279, "copyfileobj_withprogress": 279, "check_sha": 279, "fetch_data": 279, "fetch_gltf": 279, "fetch_viz_cubemap": 279, "fetch_viz_icon": 279, "fetch_viz_new_icon": 279, "fetch_viz_wiki_nw": 279, "fetch_viz_model": 279, "fetch_viz_dmri": 279, "fetch_viz_textur": 279, "read_viz_cubemap": 279, "read_viz_icon": 279, "read_viz_model": 279, "read_viz_textur": 279, "read_viz_dmri": 279, "read_viz_gltf": 279, "list_gltf_sample_model": 279, "decor": 280, "skip_r": 280, "doctest_skip_pars": 280, "deprec": 281, "expireddeprecationerror": 281, "argsdeprecationwarn": 281, "_leading_whit": 281, "cmp_pkg_version": 281, "is_bad_vers": 281, "deprecate_with_vers": 281, "deprecated_param": 281, "export_scen": 282, "write_scen": 282, "write_nod": 282, "write_mesh": 282, "write_camera": 282, "get_prim": 282, "write_materi": 282, "write_accessor": 282, "write_bufferview": 282, "write_buff": 282, "load_cubemap_textur": 283, "load_imag": 283, "load_text": 283, "save_imag": 283, "load_polydata": 283, "save_polydata": 283, "load_sprite_sheet": 283, "horizontallayout": 284, "verticallayout": 284, "xlayout": 284, "ylayout": 284, "zlayout": 284, "lib": 285, "command": 285, "lookupt": 285, "idtypearrai": 285, "floatarrai": 285, "doublearrai": 285, "stringarrai": 285, "unsignedchararrai": 285, "algorithmoutput": 285, "skybox": 285, "actor2d": 285, "renderwindow": 285, "renderwindowinteractor": 285, "interactoreventrecord": 285, "windowtoimagefilt": 285, "interactorstyl": 285, "proppick": 285, "pointpick": 285, "cellpick": 285, "worldpointpick": 285, "hardwareselector": 285, "imageactor": 285, "polydatamapp": 285, "polydatamapper2d": 285, "assembli": 285, "datasetmapp": 285, "texturedactor2d": 285, "follow": 285, "textactor": 285, "textactor3d": 285, "property2d": 285, "vectortext": 285, "lodactor": 285, "scalarbaractor": 285, "openglrender": 285, "interactorstyleimag": 285, "interactorstyletrackballactor": 285, "interactorstyletrackballcamera": 285, "interactorstyleus": 285, "cleanpolydata": 285, "polydatanorm": 285, "contourfilt": 285, "tubefilt": 285, "glyph3d": 285, "trianglefilt": 285, "splinefilt": 285, "transformpolydatafilt": 285, "renderlargeimag": 285, "loopsubdivisionfilt": 285, "butterflysubdivisionfilt": 285, "outlinefilt": 285, "linearextrusionfilt": 285, "texturemaptoplan": 285, "spheresourc": 285, "cylindersourc": 285, "arrowsourc": 285, "conesourc": 285, "disksourc": 285, "texturedspheresourc": 285, "regularpolygonsourc": 285, "polydata": 285, "imagedata": 285, "dataobject": 285, "cellarrai": 285, "polyvertex": 285, "unstructuredgrid": 285, "molecul": [285, 287], "datasetattribut": 285, "matrix4x4": 285, "matrix3x3": 285, "imageflip": 285, "imagereslic": 285, "imagemaptocolor": 285, "imagereader2factori": 285, "pngreader": 285, "bmpreader": 285, "jpegread": 285, "tiffread": 285, "plyread": 285, "stlreader": 285, "objread": 285, "mniobjectread": 285, "polydataread": 285, "xmlpolydataread": 285, "pngwriter": 285, "bmpwriter": 285, "jpegwrit": 285, "tiffwrit": 285, "plywrit": 285, "stlwriter": 285, "mniobjectwrit": 285, "polydatawrit": 285, "xmlpolydatawrit": 285, "simplebondperceiv": 285, "proteinribbonfilt": 285, "periodict": 285, "openglmoleculemapp": 285, "vtk_version": 285, "manifest_pbr": 286, "manifest_principl": 286, "manifest_standard": 286, "molecular": 287, "ptabl": 287, "add_atom": 287, "add_bond": 287, "get_atomic_numb": 287, "set_atomic_numb": 287, "get_atomic_posit": 287, "set_atomic_posit": 287, "get_bond_ord": 287, "set_bond_ord": 287, "get_all_atomic_numb": 287, "get_all_bond_ord": 287, "get_all_atomic_posit": 287, "deep_copy_molecul": 287, "compute_bond": 287, "sphere_cpk": 287, "ball_stick": 287, "stick": 287, "ribbon": 287, "bounding_box": 287, "pickingmanag": 288, "selectionmanag": 288, "pkg_info": 289, "pkg_commit_hash": 289, "faces_from_sphere_vertic": 290, "repeat_primitive_funct": 290, "repeat_primit": 290, "prim_squar": 290, "prim_box": 290, "prim_spher": 290, "prim_superquadr": 290, "prim_tetrahedron": 290, "prim_icosahedron": 290, "prim_rhombicuboctahedron": 290, "prim_star": 290, "prim_triangularpr": 290, "prim_pentagonalpr": 290, "prim_octagonalpr": 290, "prim_frustum": 290, "prim_cylind": 290, "prim_arrow": 290, "prim_con": 290, "shaders_dir": 291, "compose_shad": 291, "import_fury_shad": 291, "load_shad": 291, "shader_to_actor": 291, "replace_shader_in_actor": 291, "add_shader_callback": 291, "shader_apply_effect": 291, "attribute_to_actor": 291, "client": 292, "constant": 292, "server": 292, "async_app": 292, "tool": 292, "furystreamcli": 292, "furystreaminteract": 292, "callback_stream_cli": 292, "interaction_callback": 292, "_cqueue_event_id": 292, "_cqueue_index_info": 292, "_cqueue": 292, "pc": 292, "set_weel": 292, "set_mous": 292, "set_mouse_click": 292, "get_app": 292, "rtcserver": 292, "web_server_raw_arrai": 292, "web_serv": 292, "genericmultidimensionalbuff": 292, "rawarraymultidimensionalbuff": 292, "sharedmemmultidimensionalbuff": 292, "genericcircularqueu": 292, "arraycircularqueu": 292, "sharedmemcircularqueu": 292, "genericimagebuffermanag": 292, "rawarrayimagebuffermanag": 292, "sharedmemimagebuffermanag": 292, "intervaltimerthread": 292, "intervaltim": 292, "remove_shm_from_resource_track": 292, "check_port_is_avail": 292, "_tuple2ax": 293, "euler_matrix": 293, "sphere2cart": 293, "cart2spher": 293, "scale": 293, "apply_transform": 293, "transform_from_matrix": 293, "panel2d": 294, "tabui": 294, "imagecontainer2d": 294, "gridui": 294, "rectangle2d": 294, "disk2d": 294, "button2d": 294, "textbox2d": 294, "lineslider2d": 294, "linedoubleslider2d": 294, "ringslider2d": 294, "rangeslid": 294, "option": 294, "radiobutton": 294, "listbox2d": 294, "listboxitem2d": 294, "filemenu2d": 294, "playbackpanel": 294, "card2d": 294, "clip_overflow": 294, "wrap_overflow": 294, "check_overflow": 294, "cal_bounding_box_2d": 294, "rotate_2d": 294, "util": 295, "remove_observer_from_actor": 295, "set_input": 295, "numpy_to_vtk_point": 295, "numpy_to_vtk_color": 295, "numpy_to_vtk_cel": 295, "numpy_to_vtk_image_data": 295, "map_coordinates_3d_4d": 295, "lines_to_vtk_polydata": 295, "get_polydata_lin": 295, "get_polydata_triangl": 295, "get_polydata_vertic": 295, "get_polydata_tcoord": 295, "get_polydata_norm": 295, "get_polydata_tang": 295, "get_polydata_color": 295, "get_polydata_field": 295, "add_polydata_numeric_field": 295, "set_polydata_primitives_count": 295, "get_polydata_primitives_count": 295, "primitives_count_to_actor": 295, "primitives_count_from_actor": 295, "set_polydata_triangl": 295, "set_polydata_vertic": 295, "set_polydata_norm": 295, "set_polydata_tang": 295, "set_polydata_color": 295, "set_polydata_tcoord": 295, "update_polydata_norm": 295, "get_polymapper_from_polydata": 295, "get_actor_from_polymapp": 295, "get_actor_from_polydata": 295, "get_actor_from_primit": 295, "repeat_sourc": 295, "apply_affine_to_actor": 295, "apply_affin": 295, "asbyt": 295, "vtk_matrix_to_numpi": 295, "numpy_to_vtk_matrix": 295, "get_bounding_box_s": 295, "get_grid_cells_posit": 295, "shallow_copi": 295, "rgb_to_vtk": 295, "normalize_v3": 295, "normals_from_v_f": 295, "tangents_from_direction_of_anisotropi": 295, "triangle_ord": 295, "change_vertices_ord": 295, "fix_winding_ord": 295, "vertices_from_actor": 295, "colors_from_actor": 295, "normals_from_actor": 295, "tangents_from_actor": 295, "array_from_actor": 295, "normals_to_actor": 295, "tangents_to_actor": 295, "compute_bound": 295, "update_actor": 295, "get_bound": 295, "represent_actor_as_wirefram": 295, "update_surface_actor_color": 295, "color_check": 295, "is_ui": 295, "set_actor_origin": 295, "window": 296, "showmanag": 296, "record": 296, "antialias": 296, "snapshot": 296, "analyze_scen": 296, "analyze_snapshot": 296, "enable_stereo": 296, "gl_get_current_st": 296, "gl_reset_blend": 296, "gl_enable_depth": 296, "gl_disable_depth": 296, "gl_enable_blend": 296, "gl_disable_blend": 296, "gl_set_additive_blend": 296, "gl_set_additive_blending_white_background": 296, "gl_set_normal_blend": 296, "gl_set_multiplicative_blend": 296, "gl_set_subtractive_blend": 296, "release_context": 296, "histori": 298, "v0": [299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313], "2018": [299, 300, 301, 302], "quick": [299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313], "29": [300, 306], "31": [301, 312], "26": 302, "2024": 303, "02": [303, 305], "28": 303, "2019": [304, 305, 306], "03": [304, 310, 311], "08": [304, 305, 309, 311], "04": [307, 313], "01": [307, 312], "07": 308, "20": [308, 309], "type": 315, "write": 315, "submit": 315, "feedback": 315, "guidelin": 315, "publish": 315, "checklist": 315, "befor": 315, "stuff": 315}, "envversion": {"sphinx.domains.c": 3, "sphinx.domains.changeset": 1, "sphinx.domains.citation": 1, "sphinx.domains.cpp": 9, "sphinx.domains.index": 1, "sphinx.domains.javascript": 3, "sphinx.domains.math": 2, "sphinx.domains.python": 4, "sphinx.domains.rst": 2, "sphinx.domains.std": 2, "sphinx.ext.intersphinx": 1, "sphinx.ext.viewcode": 1, "sphinx": 60}, "alltitles": {"Introductory": [[0, "introductory"], [90, "introductory"]], "Computation times": [[1, "computation-times"], [23, "computation-times"], [42, "computation-times"], [58, "computation-times"], [71, "computation-times"], [79, "computation-times"], [86, "computation-times"], [91, "computation-times"], [314, "computation-times"]], "Fury Arrow Actor": [[2, "fury-arrow-actor"]], "Fury Cone Actor": [[3, "fury-cone-actor"]], "Texture Sphere Animation": [[4, "texture-sphere-animation"]], "Earth Coordinate Conversion": [[5, "earth-coordinate-conversion"]], "Visualizing a glTF file": [[6, "visualizing-a-gltf-file"], [7, "visualizing-a-gltf-file"]], "Exporting scene as a glTF file": [[8, "exporting-scene-as-a-gltf-file"]], "Morphing Animation in a glTF": [[9, "morphing-animation-in-a-gltf"]], "Multithreading Example": [[10, "multithreading-example"]], "Simple picking": [[11, "simple-picking"]], "Selecting multiple objects": [[12, "selecting-multiple-objects"]], "Skeletal Animation in a glTF file": [[13, "skeletal-animation-in-a-gltf-file"]], "Simple volume slicing": [[14, "simple-volume-slicing"]], "Render slices from T1 with a specific value range": [[14, "render-slices-from-t1-with-a-specific-value-range"]], "Render slices from FA with your colormap": [[14, "render-slices-from-fa-with-your-colormap"]], "Create a mosaic": [[14, "create-a-mosaic"]], "Solar System Animation": [[15, "solar-system-animation"]], "FURY sphere Actor": [[16, "fury-sphere-actor"]], "Spiky Sphere": [[17, "spiky-sphere"]], "Visualize surfaces": [[18, "visualize-surfaces"]], "Sphere Texture": [[19, "sphere-texture"]], "Using a timer": [[20, "using-a-timer"]], "Collisions of particles in a box": [[21, "collisions-of-particles-in-a-box"]], "Demos": [[22, "demos"], [90, "demos"]], "Advanced interactive visualization": [[24, "advanced-interactive-visualization"]], "Animated 2D functions": [[25, "animated-2d-functions"]], "Brownian motion": [[26, "brownian-motion"]], "Visualize bundles and metrics on bundles": [[27, "visualize-bundles-and-metrics-on-bundles"]], "Show every streamline with an orientation color": [[27, "show-every-streamline-with-an-orientation-color"]], "Show every point with a value from a volume with default colormap": [[27, "show-every-point-with-a-value-from-a-volume-with-default-colormap"]], "Show every point with a value from a volume with your colormap": [[27, "show-every-point-with-a-value-from-a-volume-with-your-colormap"]], "Show every bundle with a specific color": [[27, "show-every-bundle-with-a-specific-color"]], "Show every streamline of a bundle with a different color": [[27, "show-every-streamline-of-a-bundle-with-a-different-color"]], "Show every point of every streamline with a different color": [[27, "show-every-point-of-every-streamline-with-a-different-color"]], "Add depth cues to streamline rendering": [[27, "add-depth-cues-to-streamline-rendering"]], "Render streamlines as fake tubes": [[27, "render-streamlines-as-fake-tubes"]], "Combine depth cues with fake tubes": [[27, "combine-depth-cues-with-fake-tubes"]], "Render streamlines as tubes": [[27, "render-streamlines-as-tubes"]], "Display Tensor Ellipsoids for DTI using tensor_slicer vs ellipsoid actor": [[28, "display-tensor-ellipsoids-for-dti-using-tensor-slicer-vs-ellipsoid-actor"]], "Using tensor_slicer actor": [[28, "using-tensor-slicer-actor"]], "Using ellipsoid actor": [[28, "using-ellipsoid-actor"]], "Visual quality comparison": [[28, "visual-quality-comparison"]], "Visualize a larger amount of data": [[28, "visualize-a-larger-amount-of-data"]], "Electromagnetic Wave Propagation Animation": [[29, "electromagnetic-wave-propagation-animation"]], "Brain Fiber ODF Visualisation": [[30, "brain-fiber-odf-visualisation"]], "Fine-tuning the OpenGL state using shader callbacks": [[31, "fine-tuning-the-opengl-state-using-shader-callbacks"]], "Fractals": [[32, "fractals"]], "Motion of a charged particle in a combined magnetic and electric field": [[33, "motion-of-a-charged-particle-in-a-combined-magnetic-and-electric-field"]], "Fury Markers": [[34, "fury-markers"]], "Visualize Interdisciplinary map of the journals network": [[35, "visualize-interdisciplinary-map-of-the-journals-network"]], "Visualize Networks (Animated version)": [[36, "visualize-networks-animated-version"]], "Interactive PBR demo": [[37, "interactive-pbr-demo"]], "Play a video in the 3D world": [[38, "play-a-video-in-the-3d-world"]], "Visualization of ROI Surface Rendered with Streamlines": [[39, "visualization-of-roi-surface-rendered-with-streamlines"]], "Tesseract (Hypercube)": [[40, "tesseract-hypercube"]], "User Interface Elements": [[41, "user-interface-elements"], [90, "user-interface-elements"]], "Buttons & Text": [[43, "buttons-text"]], "Card": [[44, "card"], [45, "card"]], "Figure and Color Control using Check boxes and Radio Buttons": [[46, "figure-and-color-control-using-check-boxes-and-radio-buttons"]], "Show Manager": [[46, "show-manager"], [47, "show-manager"], [48, "show-manager"], [50, "show-manager"], [54, "show-manager"], [56, "show-manager"]], "ComboBox": [[47, "combobox"], [47, "id1"]], "Callbacks": [[47, "callbacks"]], "DrawPanel": [[48, "drawpanel"], [294, "drawpanel"]], "Using Layouts with different UI elements": [[49, "using-layouts-with-different-ui-elements"]], "Sphere Color Control using Radio Buttons": [[50, "sphere-color-control-using-radio-buttons"]], "Sphere and Radio Buttons": [[50, "sphere-and-radio-buttons"]], "Simple Shapes": [[51, "simple-shapes"]], "SpinBox UI": [[52, "spinbox-ui"]], "Tab UI": [[53, "tab-ui"]], "Slider Controls for a Cube for Tab Index 0": [[53, "slider-controls-for-a-cube-for-tab-index-0"]], "CheckBoxes For Cylinder and Sphere for Tab Index 1": [[53, "checkboxes-for-cylinder-and-sphere-for-tab-index-1"]], "Color Combobox for Fury for Tab Index 2": [[53, "color-combobox-for-fury-for-tab-index-2"]], "User Interfaces": [[54, "user-interfaces"]], "Shapes": [[54, "shapes"]], "Image": [[54, "image"]], "Panel with buttons and text": [[54, "panel-with-buttons-and-text"]], "Cube and sliders": [[54, "cube-and-sliders"], [56, "cube-and-sliders"]], "Range Slider": [[54, "range-slider"]], "Select menu": [[54, "select-menu"]], "ListBox": [[55, "listbox"]], "Cube & Slider Control": [[56, "cube-slider-control"]], "Animation": [[57, "animation"], [90, "animation"], [276, "id1"]], "Bezier Interpolator": [[59, "bezier-interpolator"]], "Position interpolation using cubic Bezier curve": [[59, "position-interpolation-using-cubic-bezier-curve"]], "Cubic Bezier curve parameters": [[59, "cubic-bezier-curve-parameters"]], "Setting Cubic Bezier keyframes": [[59, "setting-cubic-bezier-keyframes"]], "A more complex scene scene": [[59, "a-more-complex-scene-scene"]], "Keyframe animation: Camera and opacity": [[60, "keyframe-animation-camera-and-opacity"]], "The Plan": [[60, "the-plan"]], "Creating the main Timeline and adding static actors to it": [[60, "creating-the-main-timeline-and-adding-static-actors-to-it"]], "Creating \u201cFURY\u201d text": [[60, "creating-fury-text"]], "Creating and animating 50 Spheres": [[60, "creating-and-animating-50-spheres"]], "Animating the camera": [[60, "animating-the-camera"]], "Keyframe Color Interpolators": [[61, "keyframe-color-interpolators"]], "Setting color keyframes": [[61, "setting-color-keyframes"]], "Making a custom interpolator": [[62, "making-a-custom-interpolator"]], "Implementing a custom interpolator": [[62, "implementing-a-custom-interpolator"]], "Cubic spline keyframes data same as the one you get from glTF file.": [[62, "cubic-spline-keyframes-data-same-as-the-one-you-get-from-gltf-file"]], "Setting position keyframes": [[62, "setting-position-keyframes"], [64, "setting-position-keyframes"]], "Keyframe hierarchical Animation": [[63, "keyframe-hierarchical-animation"]], "Keyframe animation": [[64, "keyframe-animation"], [69, "keyframe-animation"]], "What is an Animation": [[64, "what-is-an-animation"]], "What are the interpolators": [[64, "what-are-the-interpolators"]], "Creating the environment": [[64, "creating-the-environment"]], "Creating an Animation": [[64, "creating-an-animation"]], "Changing the default interpolator for a single property": [[64, "changing-the-default-interpolator-for-a-single-property"]], "Keyframe animation introduction": [[65, "keyframe-animation-introduction"]], "Animations in FURY": [[65, "animations-in-fury"]], "What exactly is a keyframe": [[65, "what-exactly-is-a-keyframe"]], "What is Keyframe Animation": [[65, "what-is-keyframe-animation"]], "Translating a sphere": [[65, "translating-a-sphere"]], "Arm Robot Animation": [[66, "arm-robot-animation"]], "Keyframes Spline Interpolator": [[67, "keyframes-spline-interpolator"]], "Wrapping animations up!": [[67, "wrapping-animations-up"]], "Timeline and setting keyframes": [[68, "timeline-and-setting-keyframes"]], "What is Timeline?": [[68, "what-is-timeline"]], "Creating a Timeline": [[68, "creating-a-timeline"]], "Setting Keyframes": [[68, "setting-keyframes"]], "Shaders": [[70, "shaders"], [90, "shaders"]], "SDF Impostors on Billboards": [[72, "sdf-impostors-on-billboards"]], "Traditional sphere rendering": [[72, "traditional-sphere-rendering"]], "SDF sphere rendering": [[72, "sdf-sphere-rendering"]], "References": [[72, "references"], [75, "references"], [174, "references"], [270, "references"]], "Physically-Based Rendering (PBR) on spheres": [[73, "physically-based-rendering-pbr-on-spheres"]], "Principled BRDF shader on spheres": [[74, "principled-brdf-shader-on-spheres"]], "Make a Cylinder using polygons vs SDF": [[75, "make-a-cylinder-using-polygons-vs-sdf"]], "Cylinder using polygons": [[75, "cylinder-using-polygons"]], "Cylinder using SDF": [[75, "cylinder-using-sdf"]], "Visualize SDF Actor": [[76, "visualize-sdf-actor"]], "Varying Color": [[77, "varying-color"]], "Integrate Physics using pybullet": [[78, "integrate-physics-using-pybullet"], [90, "integrate-physics-using-pybullet"]], "Ball Collision Simulation": [[80, "ball-collision-simulation"], [94, "ball-collision-simulation"]], "Brick Wall Simulation": [[81, "brick-wall-simulation"], [94, "brick-wall-simulation"]], "Syncing Bricks": [[81, "syncing-bricks"]], "Chain Simulation": [[82, "chain-simulation"], [94, "chain-simulation"]], "Domino Physics Simulation": [[83, "domino-physics-simulation"]], "Syncing Dominoes": [[83, "syncing-dominoes"]], "Wrecking Ball Simulation": [[84, "wrecking-ball-simulation"], [94, "wrecking-ball-simulation"]], "Streaming": [[85, "streaming"], [90, "streaming"]], "Streaming FURY with user interaction": [[87, "streaming-fury-with-user-interaction"]], "Notes": [[87, "notes"], [89, "notes"]], "Streaming FURY with WebRTC/MJPEG": [[88, "streaming-fury-with-webrtc-mjpeg"]], "Streaming FURY with WebRTC/MJPEG using the Widget Object": [[89, "streaming-fury-with-webrtc-mjpeg-using-the-widget-object"]], "Tutorials": [[90, "tutorials"]], "Blog": [[92, "blog"]], "Community": [[93, "community"]], "Join Us!": [[93, "join-us"]], "Contributors": [[93, "contributors"]], "FURY - pyBullet Integration Guide": [[94, "fury-pybullet-integration-guide"]], "Simple Rigid Body Dynamics": [[94, "simple-rigid-body-dynamics"]], "Necessary Imports": [[94, "necessary-imports"]], "Connection Mode": [[94, "connection-mode"]], "Disconnection": [[94, "disconnection"]], "Setting Gravity": [[94, "setting-gravity"]], "Creating Objects": [[94, "creating-objects"]], "Changing Object Dynamics": [[94, "changing-object-dynamics"]], "Adding objects to the scene": [[94, "adding-objects-to-the-scene"]], "Application of Force/Torque": [[94, "application-of-force-torque"]], "Enabling collision": [[94, "enabling-collision"]], "Creation of Show Manager": [[94, "creation-of-show-manager"]], "Syncing properties of actors": [[94, "syncing-properties-of-actors"]], "Creation of Timer Callback": [[94, "creation-of-timer-callback"]], "Initiating the simulation": [[94, "initiating-the-simulation"]], "Rendering multiple objects by a single actor": [[94, "rendering-multiple-objects-by-a-single-actor"]], "Rendering objects in FURY": [[94, "rendering-objects-in-fury"]], "Render Pybullet Objects": [[94, "render-pybullet-objects"]], "Syncing objects": [[94, "syncing-objects"]], "Rendering Joints": [[94, "rendering-joints"]], "Examples": [[94, "examples"]], "Brick Wall Simulation(Single Actor)": [[94, "brick-wall-simulation-single-actor"]], "Domino Simulation": [[94, "domino-simulation"]], "Getting Started": [[95, "getting-started"]], "Installation": [[97, "installation"]], "Dependencies": [[97, "dependencies"]], "Installation with PyPi": [[97, "installation-with-pypi"]], "Installation with Conda": [[97, "installation-with-conda"]], "Installation via Source": [[97, "installation-via-source"]], "Test the Installation": [[97, "test-the-installation"]], "Running the Tests": [[97, "running-the-tests"]], "Running the Tests Offscreen": [[97, "running-the-tests-offscreen"]], "Populating our Documentation": [[97, "populating-our-documentation"]], "Folder Structure": [[97, "folder-structure"]], "Building the documentation": [[97, "building-the-documentation"]], "About": [[98, "about"]], "Overview": [[98, "overview"]], "Statement of Need": [[98, "statement-of-need"]], "Mission Statement": [[98, "mission-statement"]], "Features": [[98, "features"]], "Architecture": [[98, "architecture"]], "License": [[98, "license"], [316, "license"]], "Credits": [[98, "credits"]], "Bug reports and support": [[98, "bug-reports-and-support"]], "FURY 0.1.0 Released": [[99, "fury-0-1-0-released"]], "FURY 0.1.3 Released": [[100, "fury-0-1-3-released"]], "FURY 0.1.4 Released": [[101, "fury-0-1-4-released"]], "FURY 0.2.0 Released": [[102, "fury-0-2-0-released"]], "Success on Brain Art Competition using FURY": [[103, "success-on-brain-art-competition-using-fury"]], "FURY 0.3.0 Released": [[104, "fury-0-3-0-released"]], "FURY 0.4.0 Released": [[105, "fury-0-4-0-released"]], "Google Summer of Code": [[106, "google-summer-of-code"], [138, "google-summer-of-code"]], "FURY 0.5.1 Released": [[107, "fury-0-5-1-released"]], "Weekly Check-in #1": [[108, "weekly-check-in-1"]], "Welcome to my GSoC Blog!!!": [[108, "welcome-to-my-gsoc-blog"], [109, "welcome-to-my-gsoc-blog"]], "What did you do during the Community Bonding Period?": [[108, "what-did-you-do-during-the-community-bonding-period"], [109, "what-did-you-do-during-the-community-bonding-period"], [142, "what-did-you-do-during-the-community-bonding-period"], [182, "what-did-you-do-during-the-community-bonding-period"], [185, "what-did-you-do-during-the-community-bonding-period"]], "What is coming up next week?": [[108, "what-is-coming-up-next-week"], [109, "what-is-coming-up-next-week"], [110, "what-is-coming-up-next-week"], [111, "what-is-coming-up-next-week"], [112, "what-is-coming-up-next-week"], [113, "what-is-coming-up-next-week"], [114, "what-is-coming-up-next-week"], [115, "what-is-coming-up-next-week"], [116, "what-is-coming-up-next-week"], [117, "what-is-coming-up-next-week"], [118, "what-is-coming-up-next-week"], [119, "what-is-coming-up-next-week"], [120, "what-is-coming-up-next-week"], [121, "what-is-coming-up-next-week"], [122, "what-is-coming-up-next-week"], [124, "what-is-coming-up-next-week"], [125, "what-is-coming-up-next-week"], [126, "what-is-coming-up-next-week"], [127, "what-is-coming-up-next-week"], [128, "what-is-coming-up-next-week"], [129, "what-is-coming-up-next-week"], [130, "what-is-coming-up-next-week"], [131, "what-is-coming-up-next-week"], [132, "what-is-coming-up-next-week"], [134, "what-is-coming-up-next-week"], [137, "what-is-coming-up-next-week"], [142, "what-is-coming-up-next-week"], [145, "what-is-coming-up-next-week"], [148, "what-is-coming-up-next-week"], [151, "what-is-coming-up-next-week"], [152, "what-is-coming-up-next-week"], [154, "what-is-coming-up-next-week"], [157, "what-is-coming-up-next-week"], [160, "what-is-coming-up-next-week"], [162, "what-is-coming-up-next-week"], [163, "what-is-coming-up-next-week"], [165, "what-is-coming-up-next-week"], [166, "what-is-coming-up-next-week"], [168, "what-is-coming-up-next-week"], [169, "what-is-coming-up-next-week"], [170, "what-is-coming-up-next-week"], [171, "what-is-coming-up-next-week"], [182, "what-is-coming-up-next-week"], [185, "what-is-coming-up-next-week"], [187, "what-is-coming-up-next-week"], [189, "what-is-coming-up-next-week"], [190, "what-is-coming-up-next-week"], [191, "what-is-coming-up-next-week"], [193, "what-is-coming-up-next-week"], [194, "what-is-coming-up-next-week"], [196, "what-is-coming-up-next-week"], [197, "what-is-coming-up-next-week"], [199, "what-is-coming-up-next-week"], [200, "what-is-coming-up-next-week"], [202, "what-is-coming-up-next-week"], [203, "what-is-coming-up-next-week"], [205, "what-is-coming-up-next-week"], [206, "what-is-coming-up-next-week"], [208, "what-is-coming-up-next-week"], [209, "what-is-coming-up-next-week"], [211, "what-is-coming-up-next-week"], [213, "what-is-coming-up-next-week"], [214, "what-is-coming-up-next-week"], [215, "what-is-coming-up-next-week"], [218, "what-is-coming-up-next-week"], [220, "what-is-coming-up-next-week"], [221, "what-is-coming-up-next-week"], [223, "what-is-coming-up-next-week"], [224, "what-is-coming-up-next-week"], [225, "what-is-coming-up-next-week"]], "First week of coding!!": [[110, "first-week-of-coding"], [111, "first-week-of-coding"]], "What did you do this week?": [[110, "what-did-you-do-this-week"], [111, "what-did-you-do-this-week"], [112, "what-did-you-do-this-week"], [113, "what-did-you-do-this-week"], [114, "what-did-you-do-this-week"], [115, "what-did-you-do-this-week"], [116, "what-did-you-do-this-week"], [117, "what-did-you-do-this-week"], [118, "what-did-you-do-this-week"], [119, "what-did-you-do-this-week"], [120, "what-did-you-do-this-week"], [121, "what-did-you-do-this-week"], [122, "what-did-you-do-this-week"], [124, "what-did-you-do-this-week"], [125, "what-did-you-do-this-week"], [126, "what-did-you-do-this-week"], [127, "what-did-you-do-this-week"], [128, "what-did-you-do-this-week"], [129, "what-did-you-do-this-week"], [130, "what-did-you-do-this-week"], [131, "what-did-you-do-this-week"], [132, "what-did-you-do-this-week"], [134, "what-did-you-do-this-week"], [137, "what-did-you-do-this-week"], [145, "what-did-you-do-this-week"], [146, "what-did-you-do-this-week"], [148, "what-did-you-do-this-week"], [151, "what-did-you-do-this-week"], [152, "what-did-you-do-this-week"], [154, "what-did-you-do-this-week"], [157, "what-did-you-do-this-week"], [160, "what-did-you-do-this-week"], [163, "what-did-you-do-this-week"], [166, "what-did-you-do-this-week"], [169, "what-did-you-do-this-week"], [171, "what-did-you-do-this-week"], [182, "what-did-you-do-this-week"], [183, "what-did-you-do-this-week"], [184, "what-did-you-do-this-week"], [185, "what-did-you-do-this-week"], [186, "what-did-you-do-this-week"], [187, "what-did-you-do-this-week"], [188, "what-did-you-do-this-week"], [189, "what-did-you-do-this-week"], [190, "what-did-you-do-this-week"], [191, "what-did-you-do-this-week"], [192, "what-did-you-do-this-week"], [193, "what-did-you-do-this-week"], [194, "what-did-you-do-this-week"], [195, "what-did-you-do-this-week"], [196, "what-did-you-do-this-week"], [197, "what-did-you-do-this-week"], [198, "what-did-you-do-this-week"], [199, "what-did-you-do-this-week"], [200, "what-did-you-do-this-week"], [201, "what-did-you-do-this-week"], [202, "what-did-you-do-this-week"], [203, "what-did-you-do-this-week"], [204, "what-did-you-do-this-week"], [205, "what-did-you-do-this-week"], [206, "what-did-you-do-this-week"], [207, "what-did-you-do-this-week"], [208, "what-did-you-do-this-week"], [209, "what-did-you-do-this-week"], [210, "what-did-you-do-this-week"], [211, "what-did-you-do-this-week"], [212, "what-did-you-do-this-week"], [213, "what-did-you-do-this-week"], [214, "what-did-you-do-this-week"], [215, "what-did-you-do-this-week"], [216, "what-did-you-do-this-week"], [217, "what-did-you-do-this-week"], [218, "what-did-you-do-this-week"], [219, "what-did-you-do-this-week"], [220, "what-did-you-do-this-week"], [221, "what-did-you-do-this-week"], [222, "what-did-you-do-this-week"], [223, "what-did-you-do-this-week"], [224, "what-did-you-do-this-week"], [225, "what-did-you-do-this-week"], [234, "what-did-you-do-this-week"], [237, "what-did-you-do-this-week"], [240, "what-did-you-do-this-week"], [246, "what-did-you-do-this-week"], [249, "what-did-you-do-this-week"], [252, "what-did-you-do-this-week"], [255, "what-did-you-do-this-week"], [258, "what-did-you-do-this-week"], [261, "what-did-you-do-this-week"], [264, "what-did-you-do-this-week"], [267, "what-did-you-do-this-week"]], "Did you get stuck anywhere?": [[110, "did-you-get-stuck-anywhere"], [111, "did-you-get-stuck-anywhere"], [112, "did-you-get-stuck-anywhere"], [113, "did-you-get-stuck-anywhere"], [114, "did-you-get-stuck-anywhere"], [115, "did-you-get-stuck-anywhere"], [116, "did-you-get-stuck-anywhere"], [117, "did-you-get-stuck-anywhere"], [118, "did-you-get-stuck-anywhere"], [119, "did-you-get-stuck-anywhere"], [120, "did-you-get-stuck-anywhere"], [121, "did-you-get-stuck-anywhere"], [122, "did-you-get-stuck-anywhere"], [124, "did-you-get-stuck-anywhere"], [125, "did-you-get-stuck-anywhere"], [126, "did-you-get-stuck-anywhere"], [127, "did-you-get-stuck-anywhere"], [128, "did-you-get-stuck-anywhere"], [129, "did-you-get-stuck-anywhere"], [130, "did-you-get-stuck-anywhere"], [131, "did-you-get-stuck-anywhere"], [132, "did-you-get-stuck-anywhere"], [134, "did-you-get-stuck-anywhere"], [137, "did-you-get-stuck-anywhere"], [145, "did-you-get-stuck-anywhere"], [148, "did-you-get-stuck-anywhere"], [151, "did-you-get-stuck-anywhere"], [152, "did-you-get-stuck-anywhere"], [154, "did-you-get-stuck-anywhere"], [157, "did-you-get-stuck-anywhere"], [160, "did-you-get-stuck-anywhere"], [163, "did-you-get-stuck-anywhere"], [166, "did-you-get-stuck-anywhere"], [169, "did-you-get-stuck-anywhere"], [171, "did-you-get-stuck-anywhere"], [182, "did-you-get-stuck-anywhere"], [183, "did-you-get-stuck-anywhere"], [184, "did-you-get-stuck-anywhere"], [185, "did-you-get-stuck-anywhere"], [186, "did-you-get-stuck-anywhere"], [187, "did-you-get-stuck-anywhere"], [188, "did-you-get-stuck-anywhere"], [189, "did-you-get-stuck-anywhere"], [190, "did-you-get-stuck-anywhere"], [191, "did-you-get-stuck-anywhere"], [192, "did-you-get-stuck-anywhere"], [193, "did-you-get-stuck-anywhere"], [194, "did-you-get-stuck-anywhere"], [195, "did-you-get-stuck-anywhere"], [196, "did-you-get-stuck-anywhere"], [197, "did-you-get-stuck-anywhere"], [198, "did-you-get-stuck-anywhere"], [199, "did-you-get-stuck-anywhere"], [200, "did-you-get-stuck-anywhere"], [201, "did-you-get-stuck-anywhere"], [202, "did-you-get-stuck-anywhere"], [203, "did-you-get-stuck-anywhere"], [204, "did-you-get-stuck-anywhere"], [205, "did-you-get-stuck-anywhere"], [206, "did-you-get-stuck-anywhere"], [207, "did-you-get-stuck-anywhere"], [208, "did-you-get-stuck-anywhere"], [209, "did-you-get-stuck-anywhere"], [210, "did-you-get-stuck-anywhere"], [211, "did-you-get-stuck-anywhere"], [212, "did-you-get-stuck-anywhere"], [213, "did-you-get-stuck-anywhere"], [214, "did-you-get-stuck-anywhere"], [215, "did-you-get-stuck-anywhere"], [216, "did-you-get-stuck-anywhere"], [217, "did-you-get-stuck-anywhere"], [218, "did-you-get-stuck-anywhere"], [219, "did-you-get-stuck-anywhere"], [220, "did-you-get-stuck-anywhere"], [221, "did-you-get-stuck-anywhere"], [222, "did-you-get-stuck-anywhere"], [223, "did-you-get-stuck-anywhere"], [224, "did-you-get-stuck-anywhere"], [225, "did-you-get-stuck-anywhere"], [234, "did-you-get-stuck-anywhere"], [237, "did-you-get-stuck-anywhere"], [240, "did-you-get-stuck-anywhere"], [246, "did-you-get-stuck-anywhere"], [249, "did-you-get-stuck-anywhere"], [252, "did-you-get-stuck-anywhere"], [255, "did-you-get-stuck-anywhere"], [258, "did-you-get-stuck-anywhere"], [261, "did-you-get-stuck-anywhere"], [264, "did-you-get-stuck-anywhere"], [267, "did-you-get-stuck-anywhere"]], "Raymarching!!": [[112, "raymarching"]], "ComboBox2D Progress!!": [[113, "combobox2d-progress"]], "Raymarching continued": [[114, "raymarching-continued"]], "TextBlock2D Progress!!": [[115, "textblock2d-progress"]], "Spherical harmonics": [[116, "spherical-harmonics"]], "May the Force be with you!!": [[117, "may-the-force-be-with-you"]], "Ball Collision Simulation:": [[117, "ball-collision-simulation"]], "Brick Wall Simulation:": [[117, "brick-wall-simulation"]], "Spherical harmonics, Continued.": [[118, "spherical-harmonics-continued"]], "Translation, Reposition, Rotation.": [[119, "translation-reposition-rotation"]], "Translation:": [[119, "translation"]], "Rotation:": [[119, "rotation"]], "Reposition:": [[119, "reposition"]], "Orientation, Sizing, Tab UI.": [[120, "orientation-sizing-tab-ui"]], "Multiple SDF primitives.": [[121, "multiple-sdf-primitives"]], "ComboBox2D, TextBlock2D, Clipping Overflow.": [[122, "combobox2d-textblock2d-clipping-overflow"]], "FURY 0.6.0 Released": [[123, "fury-0-6-0-released"]], "Improvements in SDF primitives.": [[124, "improvements-in-sdf-primitives"]], "Tab UI, TabPanel2D, Tab UI Tutorial.": [[125, "tab-ui-tabpanel2d-tab-ui-tutorial"]], "Merging SDF primitives.": [[126, "merging-sdf-primitives"]], "More Shaders!!": [[127, "more-shaders"], [129, "more-shaders"]], "Single Actor, Physics, Scrollbars.": [[128, "single-actor-physics-scrollbars"]], "Chain Simulation, Scrollbar Refactor, Tutorial Update.": [[130, "chain-simulation-scrollbar-refactor-tutorial-update"]], "Wrecking Ball Simulation, Scrollbars Update, Physics Tutorials.": [[131, "wrecking-ball-simulation-scrollbars-update-physics-tutorials"]], "Outline Picker": [[132, "outline-picker"]], "FURY 0.6.1 Released": [[133, "fury-0-6-1-released"]], "Part of the Journey is the end unless its Open Source!": [[134, "part-of-the-journey-is-the-end-unless-its-open-source"]], "Open Dialog:": [[134, "open-dialog"]], "Save Dialog:": [[134, "save-dialog"]], "Google Summer of Code 2020 Final Work Product": [[135, "google-summer-of-code-2020-final-work-product"]], "Introduction": [[135, "introduction"]], "Proposed Objectives": [[135, "proposed-objectives"], [136, "proposed-objectives"], [172, "proposed-objectives"], [173, "proposed-objectives"], [174, "proposed-objectives"], [226, "proposed-objectives"], [227, "proposed-objectives"], [228, "proposed-objectives"], [268, "proposed-objectives"], [270, "proposed-objectives"], [272, "proposed-objectives"]], "Unsubmitted Functionalities": [[135, "unsubmitted-functionalities"]], "Objectives Completed": [[135, "objectives-completed"], [136, "objectives-completed"], [172, "objectives-completed"], [173, "objectives-completed"], [174, "objectives-completed"], [226, "objectives-completed"], [227, "objectives-completed"], [228, "objectives-completed"], [268, "objectives-completed"], [270, "objectives-completed"], [272, "objectives-completed"]], "Other Objectives": [[135, "other-objectives"], [136, "other-objectives"], [172, "other-objectives"], [173, "other-objectives"], [226, "other-objectives"], [227, "other-objectives"], [228, "other-objectives"], [268, "other-objectives"], [272, "other-objectives"]], "Timeline": [[135, "timeline"], [136, "timeline"], [172, "timeline"], [173, "timeline"], [174, "timeline"], [226, "timeline"], [227, "timeline"], [228, "timeline"], [268, "timeline"], [270, "timeline"], [272, "timeline"], [276, "timeline"]], "Google Summer of Code Final Work Product": [[136, "google-summer-of-code-final-work-product"], [172, "google-summer-of-code-final-work-product"], [173, "google-summer-of-code-final-work-product"], [226, "google-summer-of-code-final-work-product"], [227, "google-summer-of-code-final-work-product"], [228, "google-summer-of-code-final-work-product"], [268, "google-summer-of-code-final-work-product"], [270, "google-summer-of-code-final-work-product"], [272, "google-summer-of-code-final-work-product"]], "Modified Objectives": [[136, "modified-objectives"], [227, "modified-objectives"]], "Objectives in Progress": [[136, "objectives-in-progress"], [172, "objectives-in-progress"], [173, "objectives-in-progress"], [226, "objectives-in-progress"], [227, "objectives-in-progress"], [228, "objectives-in-progress"], [268, "objectives-in-progress"], [270, "objectives-in-progress"], [272, "objectives-in-progress"]], "Shader Showcase": [[137, "shader-showcase"]], "FURY 0.7.0 Released": [[139, "fury-0-7-0-released"], [167, "fury-0-7-0-released"]], "Weekly Check-In #1": [[140, "weekly-check-in-1"]], "What did I do this week?": [[140, "what-did-i-do-this-week"], [141, "what-did-i-do-this-week"], [144, "what-did-i-do-this-week"], [147, "what-did-i-do-this-week"], [150, "what-did-i-do-this-week"], [153, "what-did-i-do-this-week"], [156, "what-did-i-do-this-week"], [158, "what-did-i-do-this-week"], [159, "what-did-i-do-this-week"], [161, "what-did-i-do-this-week"], [162, "what-did-i-do-this-week"], [164, "what-did-i-do-this-week"], [165, "what-did-i-do-this-week"], [168, "what-did-i-do-this-week"], [170, "what-did-i-do-this-week"], [175, "what-did-i-do-this-week"], [176, "what-did-i-do-this-week"], [233, "what-did-i-do-this-week"], [236, "what-did-i-do-this-week"], [239, "what-did-i-do-this-week"], [242, "what-did-i-do-this-week"], [243, "what-did-i-do-this-week"], [245, "what-did-i-do-this-week"], [248, "what-did-i-do-this-week"], [251, "what-did-i-do-this-week"], [254, "what-did-i-do-this-week"], [257, "what-did-i-do-this-week"], [260, "what-did-i-do-this-week"], [263, "what-did-i-do-this-week"], [266, "what-did-i-do-this-week"], [271, "what-did-i-do-this-week"]], "Did I get stuck anywhere?": [[140, "did-i-get-stuck-anywhere"], [141, "did-i-get-stuck-anywhere"], [144, "did-i-get-stuck-anywhere"], [146, "did-i-get-stuck-anywhere"], [147, "did-i-get-stuck-anywhere"], [150, "did-i-get-stuck-anywhere"], [153, "did-i-get-stuck-anywhere"], [156, "did-i-get-stuck-anywhere"], [158, "did-i-get-stuck-anywhere"], [159, "did-i-get-stuck-anywhere"], [161, "did-i-get-stuck-anywhere"], [162, "did-i-get-stuck-anywhere"], [164, "did-i-get-stuck-anywhere"], [165, "did-i-get-stuck-anywhere"], [168, "did-i-get-stuck-anywhere"], [170, "did-i-get-stuck-anywhere"], [175, "did-i-get-stuck-anywhere"], [176, "did-i-get-stuck-anywhere"], [233, "did-i-get-stuck-anywhere"], [236, "did-i-get-stuck-anywhere"], [239, "did-i-get-stuck-anywhere"], [242, "did-i-get-stuck-anywhere"], [243, "did-i-get-stuck-anywhere"], [245, "did-i-get-stuck-anywhere"], [248, "did-i-get-stuck-anywhere"], [251, "did-i-get-stuck-anywhere"], [254, "did-i-get-stuck-anywhere"], [257, "did-i-get-stuck-anywhere"], [260, "did-i-get-stuck-anywhere"], [263, "did-i-get-stuck-anywhere"], [266, "did-i-get-stuck-anywhere"], [271, "did-i-get-stuck-anywhere"]], "What is coming up next?": [[140, "what-is-coming-up-next"], [141, "what-is-coming-up-next"], [144, "what-is-coming-up-next"], [146, "what-is-coming-up-next"], [147, "what-is-coming-up-next"], [150, "what-is-coming-up-next"], [153, "what-is-coming-up-next"], [156, "what-is-coming-up-next"], [158, "what-is-coming-up-next"], [161, "what-is-coming-up-next"], [164, "what-is-coming-up-next"], [175, "what-is-coming-up-next"], [183, "what-is-coming-up-next"], [184, "what-is-coming-up-next"], [186, "what-is-coming-up-next"], [188, "what-is-coming-up-next"], [192, "what-is-coming-up-next"], [195, "what-is-coming-up-next"], [198, "what-is-coming-up-next"], [201, "what-is-coming-up-next"], [204, "what-is-coming-up-next"], [207, "what-is-coming-up-next"], [210, "what-is-coming-up-next"], [212, "what-is-coming-up-next"], [216, "what-is-coming-up-next"], [217, "what-is-coming-up-next"], [219, "what-is-coming-up-next"], [222, "what-is-coming-up-next"], [233, "what-is-coming-up-next"], [234, "what-is-coming-up-next"], [236, "what-is-coming-up-next"], [237, "what-is-coming-up-next"], [239, "what-is-coming-up-next"], [240, "what-is-coming-up-next"], [242, "what-is-coming-up-next"], [243, "what-is-coming-up-next"], [245, "what-is-coming-up-next"], [246, "what-is-coming-up-next"], [248, "what-is-coming-up-next"], [249, "what-is-coming-up-next"], [251, "what-is-coming-up-next"], [252, "what-is-coming-up-next"], [254, "what-is-coming-up-next"], [255, "what-is-coming-up-next"], [257, "what-is-coming-up-next"], [258, "what-is-coming-up-next"], [260, "what-is-coming-up-next"], [261, "what-is-coming-up-next"], [263, "what-is-coming-up-next"], [264, "what-is-coming-up-next"], [266, "what-is-coming-up-next"], [267, "what-is-coming-up-next"], [271, "what-is-coming-up-next"]], "Week #1: Welcome to my weekly Blogs!": [[141, "week-1-welcome-to-my-weekly-blogs"]], "Welcome to my GSoC Blog!": [[142, "welcome-to-my-gsoc-blog"]], "A Stadia-like system for data visualization": [[143, "a-stadia-like-system-for-data-visualization"]], "How does it works?": [[143, "how-does-it-works"]], "Sharing data between process": [[143, "sharing-data-between-process"]], "multiprocessing RawArray": [[143, "multiprocessing-rawarray"]], "Multiprocessing inside of different Operating Systems": [[143, "multiprocessing-inside-of-different-operating-systems"]], "Week #2: Feature additions in UI and IO modules": [[144, "week-2-feature-additions-in-ui-and-io-modules"]], "First week of coding!": [[145, "first-week-of-coding"]], "Weekly Check-In #3": [[146, "weekly-check-in-3"]], "A python-core issue": [[146, "a-python-core-issue"]], "Week #3: Adapting GridLayout to work with UI": [[147, "week-3-adapting-gridlayout-to-work-with-ui"]], "Second week of coding!": [[148, "second-week-of-coding"]], "SOLID, monkey patching a python issue and network visualization through WebRTC": [[149, "solid-monkey-patching-a-python-issue-and-network-visualization-through-webrtc"]], "Streaming System": [[149, "streaming-system"]], "Code Refactoring": [[149, "code-refactoring"]], "Abstract class and SOLID": [[149, "abstract-class-and-solid"]], "Using namedtuples to grant immutability and to avoid silent bugs": [[149, "using-namedtuples-to-grant-immutability-and-to-avoid-silent-bugs"]], "Testing": [[149, "testing"]], "Most relevant bugs": [[149, "most-relevant-bugs"]], "Network Layout (Helios-FURY)": [[149, "network-layout-helios-fury"]], "Refs:": [[149, "refs"]], "Week #4: Adding Tree UI to the UI module": [[150, "week-4-adding-tree-ui-to-the-ui-module"]], "Third week of coding!": [[151, "third-week-of-coding"]], "Weekly Check-In #5": [[152, "weekly-check-in-5"]], "fury-gl/fury PR#437: WebRTC streaming system for FURY": [[152, "fury-gl-fury-pr-437-webrtc-streaming-system-for-fury"]], "fury-gl/helios PR 1: Network Layout and SuperActors": [[152, "fury-gl-helios-pr-1-network-layout-and-superactors"]], "Week #5: Rebasing all PRs w.r.t the UI restructuring, Tree2D, Bug Fixes": [[153, "week-5-rebasing-all-prs-w-r-t-the-ui-restructuring-tree2d-bug-fixes"]], "Fourth week of coding!": [[154, "fourth-week-of-coding"]], "Network layout algorithms using IPC": [[155, "network-layout-algorithms-using-ipc"]], "The problem: network layout algorithm implementations with a blocking behavior": [[155, "the-problem-network-layout-algorithm-implementations-with-a-blocking-behavior"]], "Why is using the python threading is not a good solution?": [[155, "why-is-using-the-python-threading-is-not-a-good-solution"]], "IPC using python": [[155, "ipc-using-python"]], "How have I implemented the code for A and B?": [[155, "how-have-i-implemented-the-code-for-a-and-b"]], "Results": [[155, "results"]], "Next steps": [[155, "next-steps"]], "Summary of most important pull-requests:": [[155, "summary-of-most-important-pull-requests"]], "Week #6: Bug fixes, Working on Tree2D UI": [[156, "week-6-bug-fixes-working-on-tree2d-ui"]], "Fifth week of coding!": [[157, "fifth-week-of-coding"]], "Weekly Check-In #7": [[158, "weekly-check-in-7"]], "Week #7: Finalizing the stalling PRs, finishing up Tree2D UI.": [[159, "week-7-finalizing-the-stalling-prs-finishing-up-tree2d-ui"]], "Sixth week of coding!": [[160, "sixth-week-of-coding"]], "Weekly Check-In #8": [[161, "weekly-check-in-8"]], "Week #8: Code Cleanup, Finishing up open PRs, Continuing work on Tree2D": [[162, "week-8-code-cleanup-finishing-up-open-prs-continuing-work-on-tree2d"]], "Seventh week of coding!": [[163, "seventh-week-of-coding"]], "Week #09: Sphinx custom summary": [[164, "week-09-sphinx-custom-summary"]], "FURY/Helios": [[164, "fury-helios"], [175, "fury-helios"], [176, "fury-helios"]], "FURY": [[164, "fury"], [175, "fury"], [176, "fury"]], "Week #9: More Layouts!": [[165, "week-9-more-layouts"]], "Eighth coding week!": [[166, "eighth-coding-week"]], "Week#10: Accordion UI, Support for sprite sheet animations": [[168, "week-10-accordion-ui-support-for-sprite-sheet-animations"]], "Ninth coding week!": [[169, "ninth-coding-week"]], "Week #11: Finalizing open Pull Requests": [[170, "week-11-finalizing-open-pull-requests"]], "Tenth coding week!": [[171, "tenth-coding-week"]], "Google Summer of Code 2021 - Final Report - Bruno Messias": [[174, "google-summer-of-code-2021-final-report-bruno-messias"]], "Abstract": [[174, "abstract"], [268, "abstract"], [270, "abstract"]], "Week #10: SDF Fonts": [[175, "week-10-sdf-fonts"]], "Week #11: Removing the flickering effect": [[176, "week-11-removing-the-flickering-effect"]], "FURY 0.8.0 Released": [[177, "fury-0-8-0-released"]], "Contribute to FURY via Google Summer of Code 2022": [[178, "contribute-to-fury-via-google-summer-of-code-2022"]], "My journey till getting accepted into GSoC22": [[179, "my-journey-till-getting-accepted-into-gsoc22"]], "A Little About Myself": [[179, "a-little-about-myself"]], "My first coding experience": [[179, "my-first-coding-experience"]], "Developing a 3D game": [[179, "developing-a-3d-game"]], "My journey to GSoC22": [[179, "my-journey-to-gsoc22"]], "The day I got accepted": [[179, "the-day-i-got-accepted"]], "My Journey to GSoC 2022": [[180, "my-journey-to-gsoc-2022"]], "About Myself": [[180, "about-myself"]], "Intro to Open-Source and GSoC": [[180, "intro-to-open-source-and-gsoc"]], "The Day": [[180, "the-day"]], "Pre-GSoC Journey": [[181, "pre-gsoc-journey"]], "The Beginning of Programming": [[181, "the-beginning-of-programming"]], "Interest in Game Development and Animation": [[181, "interest-in-game-development-and-animation"]], "Intro to Opensource": [[181, "intro-to-opensource"]], "GSoC - 21": [[181, "gsoc-21"]], "GSoC - 22": [[181, "gsoc-22"]], "Week 1: Implementing a basic Keyframe animation API": [[182, "week-1-implementing-a-basic-keyframe-animation-api"]], "Week 1 - Laying the Foundation of DrawPanel UI": [[183, "week-1-laying-the-foundation-of-drawpanel-ui"]], "Week 2 - Improving DrawPanel UI": [[184, "week-2-improving-drawpanel-ui"]], "Week 1 - A Basic glTF Importer": [[185, "week-1-a-basic-gltf-importer"]], "Week 3 - Dealing with Problems": [[186, "week-3-dealing-with-problems"]], "Week 2: Implementing non-linear and color interpolators": [[187, "week-2-implementing-non-linear-and-color-interpolators"]], "Week 4 - Fixing the Clamping Issue": [[188, "week-4-fixing-the-clamping-issue"]], "Week 2 - Improving Fetcher and Exporting glTF": [[189, "week-2-improving-fetcher-and-exporting-gltf"]], "Week 3: Redesigning the API, Implementing cubic Bezier Interpolator, and making progress on the GPU side!": [[190, "week-3-redesigning-the-api-implementing-cubic-bezier-interpolator-and-making-progress-on-the-gpu-side"]], "Week 3 - Fixing fetcher, adding tests and docs": [[191, "week-3-fixing-fetcher-adding-tests-and-docs"]], "Week 5 - Working on new features": [[192, "week-5-working-on-new-features"]], "Week 4: Camera animation, interpolation in GLSL, and a single Timeline!": [[193, "week-4-camera-animation-interpolation-in-glsl-and-a-single-timeline"]], "Week 4 - Finalizing glTF loader": [[194, "week-4-finalizing-gltf-loader"]], "Week 6 - Supporting Rotation of the Shapes from the Center": [[195, "week-6-supporting-rotation-of-the-shapes-from-the-center"]], "Week 5: Slerp implementation, documenting the Timeline, and adding unit tests": [[196, "week-5-slerp-implementation-documenting-the-timeline-and-adding-unit-tests"]], "Week 5 - Creating PR for glTF exporter and fixing the loader": [[197, "week-5-creating-pr-for-gltf-exporter-and-fixing-the-loader"]], "Week 7 - Working on Rotation PR and Trying Freehand Drawing": [[198, "week-7-working-on-rotation-pr-and-trying-freehand-drawing"]], "Week 6: Fixing the Timeline issues and equipping it with more features": [[199, "week-6-fixing-the-timeline-issues-and-equipping-it-with-more-features"]], "Week 6 - Extracting the animation data": [[200, "week-6-extracting-the-animation-data"]], "Week 8 - Working on the polyline feature": [[201, "week-8-working-on-the-polyline-feature"]], "Week 7: Billboard spheres and implementing interpolators using closures": [[202, "week-7-billboard-spheres-and-implementing-interpolators-using-closures"]], "Week 7 - Fixing bugs in animations": [[203, "week-7-fixing-bugs-in-animations"]], "Week 9 - Grouping and Transforming Shapes": [[204, "week-9-grouping-and-transforming-shapes"]], "Week 8 - Fixing animation bugs": [[205, "week-8-fixing-animation-bugs"]], "Week 8: Back to the shader-based version of the Timeline": [[206, "week-8-back-to-the-shader-based-version-of-the-timeline"]], "Week 10 - Understanding Codes and Playing with Animation": [[207, "week-10-understanding-codes-and-playing-with-animation"]], "Week 9: Animating primitives of the same actor": [[208, "week-9-animating-primitives-of-the-same-actor"]], "Week 9 - First working skeletal animation prototype": [[209, "week-9-first-working-skeletal-animation-prototype"]], "Week 11 - Creating a base for Freehand Drawing": [[210, "week-11-creating-a-base-for-freehand-drawing"]], "Week 10: Supporting hierarchical animating": [[211, "week-10-supporting-hierarchical-animating"]], "Week 12 - Fixing translating issues and updating tests": [[212, "week-12-fixing-translating-issues-and-updating-tests"]], "Week 10 - Multi-node skinning support": [[213, "week-10-multi-node-skinning-support"]], "Week 11: Improving tutorials a little": [[214, "week-11-improving-tutorials-a-little"]], "Week 11 - Multiple transformations support and adding tests": [[215, "week-11-multiple-transformations-support-and-adding-tests"]], "Week 13 - Separating tests and fixing bugs": [[216, "week-13-separating-tests-and-fixing-bugs"]], "Week 14 - Updating DrawPanel architecture": [[217, "week-14-updating-drawpanel-architecture"]], "Week 12 - Adding skeleton as actors and fix global transformation": [[218, "week-12-adding-skeleton-as-actors-and-fix-global-transformation"]], "Week 15 - Highlighting DrawShapes": [[219, "week-15-highlighting-drawshapes"]], "Week 13 - Multi-bone skeletal animation support": [[220, "week-13-multi-bone-skeletal-animation-support"]], "Week 13: Keyframes animation is now a bit easier in FURY": [[221, "week-13-keyframes-animation-is-now-a-bit-easier-in-fury"]], "Week 16 - Working with Rotations!": [[222, "week-16-working-with-rotations"]], "Week 14: Keyframes animation is now a bit easier in FURY": [[223, "week-14-keyframes-animation-is-now-a-bit-easier-in-fury"]], "Week 14 - Morphing is here!": [[224, "week-14-morphing-is-here"]], "Week 12: Adding new tutorials": [[225, "week-12-adding-new-tutorials"]], "GSoC Weekly Blogs": [[226, "gsoc-weekly-blogs"], [268, "gsoc-weekly-blogs"], [270, "gsoc-weekly-blogs"], [272, "gsoc-weekly-blogs"]], "Loading Static glTF models": [[228, "loading-static-gltf-models"]], "Exporting Scene as a glTF": [[228, "exporting-scene-as-a-gltf"]], "Simple Actor Animations": [[228, "simple-actor-animations"]], "Morphing in glTF": [[228, "morphing-in-gltf"]], "Skeletal Animations (Skining)": [[228, "skeletal-animations-skining"]], "PBR and emission materials in glTF": [[228, "pbr-and-emission-materials-in-gltf"]], "Skinning for models with no indices": [[228, "skinning-for-models-with-no-indices"]], "Fetcher for importing glTF files from Khronos-glTF-Samples": [[228, "fetcher-for-importing-gltf-files-from-khronos-gltf-samples"]], "Other Pull Requests": [[228, "other-pull-requests"]], "GSoC weekly blogs": [[228, "gsoc-weekly-blogs"]], "Contribute to FURY via Google Summer of Code 2023": [[229, "contribute-to-fury-via-google-summer-of-code-2023"]], "FURY 0.9.0 Released": [[230, "fury-0-9-0-released"]], "The Beginning of Everything - Week 0": [[231, "the-beginning-of-everything-week-0"]], "So it begins\u2026": [[231, "so-it-begins"]], "The Community Bonding Period": [[231, "the-community-bonding-period"]], "The Project\u2019s Goal": [[231, "the-project-s-goal"]], "This Week\u2019s Goal": [[231, "this-week-s-goal"]], "Week 0: Community Bounding Period": [[232, "week-0-community-bounding-period"], [233, "week-0-community-bounding-period"]], "GSoC 2023: Community Bonding Period": [[232, "gsoc-2023-community-bonding-period"], [233, "gsoc-2023-community-bonding-period"]], "Week 1: Working with SpinBox and TextBox Enhancements": [[234, "week-1-working-with-spinbox-and-textbox-enhancements"]], "The FBO Saga - Week 1": [[235, "the-fbo-saga-week-1"]], "This Past Week": [[235, "this-past-week"]], "My Current Problems": [[235, "my-current-problems"]], "What About Next Week?": [[235, "what-about-next-week"]], "Week 1: Ellipsoid actor implemented with SDF": [[236, "week-1-ellipsoid-actor-implemented-with-sdf"]], "Week 2: Tackling Text Justification and Icon Flaw Issues": [[237, "week-2-tackling-text-justification-and-icon-flaw-issues"]], "Week 2: The Importance of (good) Documentation": [[238, "week-2-the-importance-of-good-documentation"]], "This Last Week\u2019s Effort": [[238, "this-last-week-s-effort"], [241, "this-last-week-s-effort"]], "Where the Problem Was": [[238, "where-the-problem-was"], [241, "where-the-problem-was"], [244, "where-the-problem-was"], [247, "where-the-problem-was"], [250, "where-the-problem-was"]], "This Week\u2019s Goals": [[238, "this-week-s-goals"], [241, "this-week-s-goals"], [244, "this-week-s-goals"], [247, "this-week-s-goals"], [250, "this-week-s-goals"], [253, "this-week-s-goals"], [256, "this-week-s-goals"], [259, "this-week-s-goals"], [262, "this-week-s-goals"], [265, "this-week-s-goals"]], "Week 2: Making adjustments to the Ellipsoid Actor": [[239, "week-2-making-adjustments-to-the-ellipsoid-actor"]], "Week 3: Resolving Combobox Icon Flaw and TextBox Justification": [[240, "week-3-resolving-combobox-icon-flaw-and-textbox-justification"]], "Week 3: Watch Your Expectations": [[241, "week-3-watch-your-expectations"]], "Week 3: Working on uncertainty and details of the first PR": [[242, "week-3-working-on-uncertainty-and-details-of-the-first-pr"]], "Week 4: Exam Preparations and Reviewing": [[243, "week-4-exam-preparations-and-reviewing"]], "Week 4: Nothing is Ever Lost": [[244, "week-4-nothing-is-ever-lost"]], "Last Week\u2019s Effort": [[244, "last-week-s-effort"], [247, "last-week-s-effort"], [253, "last-week-s-effort"], [256, "last-week-s-effort"], [259, "last-week-s-effort"], [262, "last-week-s-effort"], [265, "last-week-s-effort"], [269, "last-week-s-effort"]], "Week 4: First draft of the DTI uncertainty visualization": [[245, "week-4-first-draft-of-the-dti-uncertainty-visualization"]], "Week 5: Trying out PRs and Planning Ahead": [[246, "week-5-trying-out-prs-and-planning-ahead"]], "Week 5: All Roads Lead to Rome": [[247, "week-5-all-roads-lead-to-rome"]], "Week 5: Preparing the data for the Ellipsoid tutorial": [[248, "week-5-preparing-the-data-for-the-ellipsoid-tutorial"]], "Week 6: BoundingBox for TextBlock2D!": [[249, "week-6-boundingbox-for-textblock2d"]], "Week 6: Things are Starting to Build Up": [[250, "week-6-things-are-starting-to-build-up"]], "What I did Last Week": [[250, "what-i-did-last-week"]], "Week 6: First draft of the Ellipsoid tutorial": [[251, "week-6-first-draft-of-the-ellipsoid-tutorial"]], "Week 7: Sowing the seeds for TreeUI": [[252, "week-7-sowing-the-seeds-for-treeui"]], "Week 7: Experimentation Done": [[253, "week-7-experimentation-done"]], "Was it Hard?": [[253, "was-it-hard"]], "Week 7: Adjustments on the Uncertainty Cones visualization": [[254, "week-7-adjustments-on-the-uncertainty-cones-visualization"]], "Week 8: Another week with TextBlockUI": [[255, "week-8-another-week-with-textblockui"]], "Week 8: The Birth of a Versatile API": [[256, "week-8-the-birth-of-a-versatile-api"]], "So how did it go?": [[256, "so-how-did-it-go"], [259, "so-how-did-it-go"], [262, "so-how-did-it-go"], [265, "so-how-did-it-go"], [269, "so-how-did-it-go"]], "Week 8: Working on Ellipsoid Tutorial and exploring SH": [[257, "week-8-working-on-ellipsoid-tutorial-and-exploring-sh"]], "Week 9: TextBlock2D is Finally Merged!": [[258, "week-9-textblock2d-is-finally-merged"]], "Week 9: It is Polishing Time!": [[259, "week-9-it-is-polishing-time"]], "Week 9: Tutorial done and polishing DTI uncertainty": [[260, "week-9-tutorial-done-and-polishing-dti-uncertainty"]], "Week 10: Its time for a Spin-Box!": [[261, "week-10-its-time-for-a-spin-box"]], "Week 10: Ready for Review!": [[262, "week-10-ready-for-review"]], "Week 10 : Start of SH implementation experiments": [[263, "week-10-start-of-sh-implementation-experiments"]], "Week 11: Bye Bye SpinBox": [[264, "week-11-bye-bye-spinbox"]], "Week 11: A Refactor is Sometimes Needed": [[265, "week-11-a-refactor-is-sometimes-needed"]], "Week 11 : Adjusting ODF implementation and looking for solutions on issues found": [[266, "week-11-adjusting-odf-implementation-and-looking-for-solutions-on-issues-found"]], "Week 12: FileDialog Quest Begins!": [[267, "week-12-filedialog-quest-begins"]], "Week 12: Now That is (almost) a Wrap!": [[269, "week-12-now-that-is-almost-a-wrap"]], "The Next Steps": [[269, "the-next-steps"]], "Ellipsoid actor implemented with SDF": [[270, "ellipsoid-actor-implemented-with-sdf"]], "DTI uncertainty visualization": [[270, "dti-uncertainty-visualization"]], "ODF actor implemented with SDF": [[270, "odf-actor-implemented-with-sdf"]], "Week 12 : Experimenting with ODFs implementation": [[271, "week-12-experimenting-with-odfs-implementation"]], "fury": [[273, "module-fury"]], "get_info": [[273, "get-info"]], "enable_warnings": [[273, "enable-warnings"]], "disable_warnings": [[273, "disable-warnings"]], "actor": [[274, "module-fury.actor"]], "Container": [[274, "container"]], "slicer": [[274, "slicer"]], "surface": [[274, "surface"]], "contour_from_roi": [[274, "contour-from-roi"]], "contour_from_label": [[274, "contour-from-label"]], "streamtube": [[274, "streamtube"]], "line": [[274, "line"]], "scalar_bar": [[274, "scalar-bar"]], "axes": [[274, "axes"]], "odf_slicer": [[274, "odf-slicer"]], "tensor_slicer": [[274, "tensor-slicer"]], "peak_slicer": [[274, "peak-slicer"]], "peak": [[274, "peak"]], "dot": [[274, "dot"]], "dots": [[274, "dots"]], "point": [[274, "point"]], "sphere": [[274, "sphere"]], "cylinder": [[274, "cylinder"]], "disk": [[274, "disk"]], "square": [[274, "square"]], "rectangle": [[274, "rectangle"]], "box": [[274, "box"]], "cube": [[274, "cube"]], "arrow": [[274, "arrow"]], "cone": [[274, "cone"]], "triangularprism": [[274, "triangularprism"]], "rhombicuboctahedron": [[274, "rhombicuboctahedron"]], "pentagonalprism": [[274, "pentagonalprism"]], "octagonalprism": [[274, "octagonalprism"]], "frustum": [[274, "frustum"]], "superquadric": [[274, "superquadric"]], "billboard": [[274, "billboard"]], "vector_text": [[274, "vector-text"]], "label": [[274, "label"]], "text_3d": [[274, "text-3d"]], "grid": [[274, "grid"]], "figure": [[274, "figure"]], "texture": [[274, "texture"]], "texture_update": [[274, "texture-update"]], "texture_on_sphere": [[274, "texture-on-sphere"]], "texture_2d": [[274, "texture-2d"]], "sdf": [[274, "sdf"]], "markers": [[274, "markers"]], "ellipsoid": [[274, "ellipsoid"]], "uncertainty_cone": [[274, "uncertainty-cone"]], "actors": [[275, "module-fury.actors"]], "Module: actors.odf_slicer": [[275, "module-fury.actors.odf_slicer"]], "Module: actors.peak": [[275, "module-fury.actors.peak"]], "Module: actors.tensor": [[275, "module-fury.actors.tensor"]], "OdfSlicerActor": [[275, "odfsliceractor"]], "PeakActor": [[275, "peakactor"]], "tensor_ellipsoid": [[275, "tensor-ellipsoid"]], "double_cone": [[275, "double-cone"]], "main_dir_uncertainty": [[275, "main-dir-uncertainty"]], "animation": [[276, "module-fury.animation"]], "Module: animation.animation": [[276, "module-fury.animation.animation"]], "Module: animation.helpers": [[276, "module-fury.animation.helpers"]], "Module: animation.interpolator": [[276, "module-fury.animation.interpolator"]], "Module: animation.timeline": [[276, "module-fury.animation.timeline"]], "CameraAnimation": [[276, "cameraanimation"]], "get_previous_timestamp": [[276, "get-previous-timestamp"]], "get_next_timestamp": [[276, "get-next-timestamp"]], "get_timestamps_from_keyframes": [[276, "get-timestamps-from-keyframes"]], "get_values_from_keyframes": [[276, "get-values-from-keyframes"]], "get_time_tau": [[276, "get-time-tau"]], "lerp": [[276, "lerp"]], "euclidean_distances": [[276, "euclidean-distances"]], "spline_interpolator": [[276, "spline-interpolator"]], "cubic_spline_interpolator": [[276, "cubic-spline-interpolator"]], "step_interpolator": [[276, "step-interpolator"]], "linear_interpolator": [[276, "linear-interpolator"]], "cubic_bezier_interpolator": [[276, "cubic-bezier-interpolator"]], "slerp": [[276, "slerp"]], "color_interpolator": [[276, "color-interpolator"]], "hsv_color_interpolator": [[276, "hsv-color-interpolator"]], "lab_color_interpolator": [[276, "lab-color-interpolator"]], "xyz_color_interpolator": [[276, "xyz-color-interpolator"]], "tan_cubic_spline_interpolator": [[276, "tan-cubic-spline-interpolator"]], "colormap": [[277, "module-fury.colormap"]], "colormap_lookup_table": [[277, "colormap-lookup-table"]], "cc": [[277, "cc"]], "ss": [[277, "ss"]], "boys2rgb": [[277, "boys2rgb"]], "orient2rgb": [[277, "orient2rgb"]], "line_colors": [[277, "line-colors"]], "get_cmap": [[277, "get-cmap"]], "create_colormap": [[277, "create-colormap"]], "distinguishable_colormap": [[277, "distinguishable-colormap"]], "hex_to_rgb": [[277, "hex-to-rgb"]], "rgb2hsv": [[277, "rgb2hsv"]], "hsv2rgb": [[277, "hsv2rgb"]], "xyz_from_rgb": [[277, "xyz-from-rgb"]], "rgb_from_xyz": [[277, "rgb-from-xyz"]], "xyz2rgb": [[277, "xyz2rgb"]], "rgb2xyz": [[277, "rgb2xyz"]], "get_xyz_coords": [[277, "get-xyz-coords"]], "xyz2lab": [[277, "xyz2lab"]], "lab2xyz": [[277, "lab2xyz"]], "rgb2lab": [[277, "rgb2lab"]], "lab2rgb": [[277, "lab2rgb"]], "convert": [[278, "module-fury.convert"]], "matplotlib_figure_to_numpy": [[278, "matplotlib-figure-to-numpy"]], "data": [[279, "module-fury.data"]], "Module: data.fetcher": [[279, "module-fury.data.fetcher"]], "DATA_DIR": [[279, "data-dir"]], "update_progressbar": [[279, "update-progressbar"]], "copyfileobj_withprogress": [[279, "copyfileobj-withprogress"]], "check_sha": [[279, "check-sha"]], "fetch_data": [[279, "fetch-data"]], "fetch_gltf": [[279, "fetch-gltf"]], "fetch_viz_cubemaps": [[279, "fetch-viz-cubemaps"]], "fetch_viz_icons": [[279, "fetch-viz-icons"]], "fetch_viz_new_icons": [[279, "fetch-viz-new-icons"]], "fetch_viz_wiki_nw": [[279, "fetch-viz-wiki-nw"]], "fetch_viz_models": [[279, "fetch-viz-models"]], "fetch_viz_dmri": [[279, "fetch-viz-dmri"]], "fetch_viz_textures": [[279, "fetch-viz-textures"]], "read_viz_cubemap": [[279, "read-viz-cubemap"]], "read_viz_icons": [[279, "read-viz-icons"]], "read_viz_models": [[279, "read-viz-models"]], "read_viz_textures": [[279, "read-viz-textures"]], "read_viz_dmri": [[279, "read-viz-dmri"]], "read_viz_gltf": [[279, "read-viz-gltf"]], "list_gltf_sample_models": [[279, "list-gltf-sample-models"]], "decorators": [[280, "module-fury.decorators"]], "SKIP_RE": [[280, "skip-re"]], "doctest_skip_parser": [[280, "doctest-skip-parser"]], "deprecator": [[281, "module-fury.deprecator"]], "ExpiredDeprecationError": [[281, "expireddeprecationerror"]], "ArgsDeprecationWarning": [[281, "argsdeprecationwarning"]], "_LEADING_WHITE": [[281, "leading-white"]], "cmp_pkg_version": [[281, "cmp-pkg-version"]], "is_bad_version": [[281, "is-bad-version"]], "deprecate_with_version": [[281, "deprecate-with-version"]], "deprecated_params": [[281, "deprecated-params"]], "gltf": [[282, "module-fury.gltf"]], "glTF": [[282, "id1"]], "export_scene": [[282, "export-scene"]], "write_scene": [[282, "write-scene"]], "write_node": [[282, "write-node"]], "write_mesh": [[282, "write-mesh"]], "write_camera": [[282, "write-camera"]], "get_prim": [[282, "get-prim"]], "write_material": [[282, "write-material"]], "write_accessor": [[282, "write-accessor"]], "write_bufferview": [[282, "write-bufferview"]], "write_buffer": [[282, "write-buffer"]], "io": [[283, "module-fury.io"]], "load_cubemap_texture": [[283, "load-cubemap-texture"]], "load_image": [[283, "load-image"]], "load_text": [[283, "load-text"]], "save_image": [[283, "save-image"]], "load_polydata": [[283, "load-polydata"]], "save_polydata": [[283, "save-polydata"]], "load_sprite_sheet": [[283, "load-sprite-sheet"]], "layout": [[284, "module-fury.layout"]], "Layout": [[284, "id1"]], "GridLayout": [[284, "gridlayout"]], "HorizontalLayout": [[284, "horizontallayout"]], "VerticalLayout": [[284, "verticallayout"]], "XLayout": [[284, "xlayout"]], "YLayout": [[284, "ylayout"]], "ZLayout": [[284, "zlayout"]], "lib": [[285, "module-fury.lib"]], "Command": [[285, "command"]], "LookupTable": [[285, "lookuptable"]], "Points": [[285, "points"]], "IdTypeArray": [[285, "idtypearray"]], "FloatArray": [[285, "floatarray"]], "DoubleArray": [[285, "doublearray"]], "StringArray": [[285, "stringarray"]], "UnsignedCharArray": [[285, "unsignedchararray"]], "AlgorithmOutput": [[285, "algorithmoutput"]], "Renderer": [[285, "renderer"]], "Skybox": [[285, "skybox"]], "Volume": [[285, "volume"]], "Actor2D": [[285, "actor2d"]], "Actor": [[285, "actor"]], "RenderWindow": [[285, "renderwindow"]], "RenderWindowInteractor": [[285, "renderwindowinteractor"]], "InteractorEventRecorder": [[285, "interactoreventrecorder"]], "WindowToImageFilter": [[285, "windowtoimagefilter"]], "InteractorStyle": [[285, "interactorstyle"]], "PropPicker": [[285, "proppicker"]], "PointPicker": [[285, "pointpicker"]], "CellPicker": [[285, "cellpicker"]], "WorldPointPicker": [[285, "worldpointpicker"]], "HardwareSelector": [[285, "hardwareselector"]], "ImageActor": [[285, "imageactor"]], "PolyDataMapper": [[285, "polydatamapper"]], "PolyDataMapper2D": [[285, "polydatamapper2d"]], "Assembly": [[285, "assembly"]], "DataSetMapper": [[285, "datasetmapper"]], "Texture": [[285, "texture"]], "TexturedActor2D": [[285, "texturedactor2d"]], "Follower": [[285, "follower"]], "TextActor": [[285, "textactor"]], "TextActor3D": [[285, "textactor3d"]], "Property2D": [[285, "property2d"]], "Camera": [[285, "camera"]], "VectorText": [[285, "vectortext"]], "LODActor": [[285, "lodactor"]], "ScalarBarActor": [[285, "scalarbaractor"]], "OpenGLRenderer": [[285, "openglrenderer"]], "Shader": [[285, "shader"]], "InteractorStyleImage": [[285, "interactorstyleimage"]], "InteractorStyleTrackballActor": [[285, "interactorstyletrackballactor"]], "InteractorStyleTrackballCamera": [[285, "interactorstyletrackballcamera"]], "InteractorStyleUser": [[285, "interactorstyleuser"]], "CleanPolyData": [[285, "cleanpolydata"]], "PolyDataNormals": [[285, "polydatanormals"]], "ContourFilter": [[285, "contourfilter"]], "TubeFilter": [[285, "tubefilter"]], "Glyph3D": [[285, "glyph3d"]], "TriangleFilter": [[285, "trianglefilter"]], "SplineFilter": [[285, "splinefilter"]], "TransformPolyDataFilter": [[285, "transformpolydatafilter"]], "RenderLargeImage": [[285, "renderlargeimage"]], "LoopSubdivisionFilter": [[285, "loopsubdivisionfilter"]], "ButterflySubdivisionFilter": [[285, "butterflysubdivisionfilter"]], "OutlineFilter": [[285, "outlinefilter"]], "LinearExtrusionFilter": [[285, "linearextrusionfilter"]], "TextureMapToPlane": [[285, "texturemaptoplane"]], "SphereSource": [[285, "spheresource"]], "CylinderSource": [[285, "cylindersource"]], "ArrowSource": [[285, "arrowsource"]], "ConeSource": [[285, "conesource"]], "DiskSource": [[285, "disksource"]], "TexturedSphereSource": [[285, "texturedspheresource"]], "RegularPolygonSource": [[285, "regularpolygonsource"]], "PolyData": [[285, "polydata"]], "ImageData": [[285, "imagedata"]], "DataObject": [[285, "dataobject"], [285, "id1"]], "CellArray": [[285, "cellarray"]], "PolyVertex": [[285, "polyvertex"]], "UnstructuredGrid": [[285, "unstructuredgrid"]], "Polygon": [[285, "polygon"]], "Molecule": [[285, "molecule"], [287, "molecule"]], "DataSetAttributes": [[285, "datasetattributes"]], "Transform": [[285, "transform"]], "Matrix4x4": [[285, "matrix4x4"]], "Matrix3x3": [[285, "matrix3x3"]], "ImageFlip": [[285, "imageflip"]], "ImageReslice": [[285, "imagereslice"]], "ImageMapToColors": [[285, "imagemaptocolors"]], "ImageReader2Factory": [[285, "imagereader2factory"]], "PNGReader": [[285, "pngreader"]], "BMPReader": [[285, "bmpreader"]], "JPEGReader": [[285, "jpegreader"]], "TIFFReader": [[285, "tiffreader"]], "PLYReader": [[285, "plyreader"]], "STLReader": [[285, "stlreader"]], "OBJReader": [[285, "objreader"]], "MNIObjectReader": [[285, "mniobjectreader"]], "PolyDataReader": [[285, "polydatareader"]], "XMLPolyDataReader": [[285, "xmlpolydatareader"]], "PNGWriter": [[285, "pngwriter"]], "BMPWriter": [[285, "bmpwriter"]], "JPEGWriter": [[285, "jpegwriter"]], "TIFFWriter": [[285, "tiffwriter"]], "PLYWriter": [[285, "plywriter"]], "STLWriter": [[285, "stlwriter"]], "MNIObjectWriter": [[285, "mniobjectwriter"]], "PolyDataWriter": [[285, "polydatawriter"]], "XMLPolyDataWriter": [[285, "xmlpolydatawriter"]], "SimpleBondPerceiver": [[285, "simplebondperceiver"]], "ProteinRibbonFilter": [[285, "proteinribbonfilter"]], "PeriodicTable": [[285, "periodictable"]], "OpenGLMoleculeMapper": [[285, "openglmoleculemapper"]], "VTK_VERSION": [[285, "vtk-version"]], "material": [[286, "module-fury.material"]], "manifest_pbr": [[286, "manifest-pbr"]], "manifest_principled": [[286, "manifest-principled"]], "manifest_standard": [[286, "manifest-standard"]], "molecular": [[287, "module-fury.molecular"]], "PTable": [[287, "ptable"]], "add_atom": [[287, "add-atom"]], "add_bond": [[287, "add-bond"]], "get_atomic_number": [[287, "get-atomic-number"]], "set_atomic_number": [[287, "set-atomic-number"]], "get_atomic_position": [[287, "get-atomic-position"]], "set_atomic_position": [[287, "set-atomic-position"]], "get_bond_order": [[287, "get-bond-order"]], "set_bond_order": [[287, "set-bond-order"]], "get_all_atomic_numbers": [[287, "get-all-atomic-numbers"]], "get_all_bond_orders": [[287, "get-all-bond-orders"]], "get_all_atomic_positions": [[287, "get-all-atomic-positions"]], "deep_copy_molecule": [[287, "deep-copy-molecule"]], "compute_bonding": [[287, "compute-bonding"]], "sphere_cpk": [[287, "sphere-cpk"]], "ball_stick": [[287, "ball-stick"]], "stick": [[287, "stick"]], "ribbon": [[287, "ribbon"]], "bounding_box": [[287, "bounding-box"]], "pick": [[288, "module-fury.pick"]], "PickingManager": [[288, "pickingmanager"]], "SelectionManager": [[288, "selectionmanager"]], "pkg_info": [[289, "module-fury.pkg_info"]], "pkg_commit_hash": [[289, "pkg-commit-hash"]], "primitive": [[290, "module-fury.primitive"]], "faces_from_sphere_vertices": [[290, "faces-from-sphere-vertices"]], "repeat_primitive_function": [[290, "repeat-primitive-function"]], "repeat_primitive": [[290, "repeat-primitive"]], "prim_square": [[290, "prim-square"]], "prim_box": [[290, "prim-box"]], "prim_sphere": [[290, "prim-sphere"]], "prim_superquadric": [[290, "prim-superquadric"]], "prim_tetrahedron": [[290, "prim-tetrahedron"]], "prim_icosahedron": [[290, "prim-icosahedron"]], "prim_rhombicuboctahedron": [[290, "prim-rhombicuboctahedron"]], "prim_star": [[290, "prim-star"]], "prim_triangularprism": [[290, "prim-triangularprism"]], "prim_pentagonalprism": [[290, "prim-pentagonalprism"]], "prim_octagonalprism": [[290, "prim-octagonalprism"]], "prim_frustum": [[290, "prim-frustum"]], "prim_cylinder": [[290, "prim-cylinder"]], "prim_arrow": [[290, "prim-arrow"]], "prim_cone": [[290, "prim-cone"]], "shaders": [[291, "module-fury.shaders"]], "Module: shaders.base": [[291, "module-fury.shaders.base"]], "SHADERS_DIR": [[291, "shaders-dir"]], "compose_shader": [[291, "compose-shader"]], "import_fury_shader": [[291, "import-fury-shader"]], "load_shader": [[291, "load-shader"]], "load": [[291, "load"]], "shader_to_actor": [[291, "shader-to-actor"]], "replace_shader_in_actor": [[291, "replace-shader-in-actor"]], "add_shader_callback": [[291, "add-shader-callback"]], "shader_apply_effects": [[291, "shader-apply-effects"]], "attribute_to_actor": [[291, "attribute-to-actor"]], "stream": [[292, "module-fury.stream"]], "Module: stream.client": [[292, "module-fury.stream.client"]], "Module: stream.constants": [[292, "module-fury.stream.constants"]], "Module: stream.server": [[292, "module-fury.stream.server"]], "Module: stream.server.async_app": [[292, "module-fury.stream.server.async_app"]], "Module: stream.server.main": [[292, "module-fury.stream.server.main"]], "Module: stream.tools": [[292, "module-fury.stream.tools"]], "Module: stream.widget": [[292, "module-fury.stream.widget"]], "FuryStreamClient": [[292, "furystreamclient"]], "FuryStreamInteraction": [[292, "furystreaminteraction"]], "callback_stream_client": [[292, "callback-stream-client"]], "interaction_callback": [[292, "interaction-callback"]], "_CQUEUE_EVENT_IDs": [[292, "cqueue-event-ids"]], "_CQUEUE_INDEX_INFO": [[292, "cqueue-index-info"]], "_CQUEUE": [[292, "cqueue"]], "pcs": [[292, "pcs"]], "set_weel": [[292, "set-weel"]], "set_mouse": [[292, "set-mouse"]], "set_mouse_click": [[292, "set-mouse-click"]], "get_app": [[292, "get-app"]], "RTCServer": [[292, "rtcserver"]], "web_server_raw_array": [[292, "web-server-raw-array"]], "web_server": [[292, "web-server"]], "GenericMultiDimensionalBuffer": [[292, "genericmultidimensionalbuffer"]], "RawArrayMultiDimensionalBuffer": [[292, "rawarraymultidimensionalbuffer"]], "SharedMemMultiDimensionalBuffer": [[292, "sharedmemmultidimensionalbuffer"]], "GenericCircularQueue": [[292, "genericcircularqueue"]], "ArrayCircularQueue": [[292, "arraycircularqueue"]], "SharedMemCircularQueue": [[292, "sharedmemcircularqueue"]], "GenericImageBufferManager": [[292, "genericimagebuffermanager"]], "RawArrayImageBufferManager": [[292, "rawarrayimagebuffermanager"]], "SharedMemImageBufferManager": [[292, "sharedmemimagebuffermanager"]], "IntervalTimerThreading": [[292, "intervaltimerthreading"]], "IntervalTimer": [[292, "intervaltimer"]], "remove_shm_from_resource_tracker": [[292, "remove-shm-from-resource-tracker"]], "Widget": [[292, "widget"]], "check_port_is_available": [[292, "check-port-is-available"]], "transform": [[293, "module-fury.transform"]], "_TUPLE2AXES": [[293, "tuple2axes"]], "euler_matrix": [[293, "euler-matrix"]], "sphere2cart": [[293, "sphere2cart"]], "cart2sphere": [[293, "cart2sphere"]], "translate": [[293, "translate"]], "rotate": [[293, "rotate"], [295, "rotate"]], "scale": [[293, "scale"]], "apply_transformation": [[293, "apply-transformation"]], "transform_from_matrix": [[293, "transform-from-matrix"]], "ui": [[294, "module-fury.ui"]], "Module: ui.containers": [[294, "module-fury.ui.containers"]], "Module: ui.core": [[294, "module-fury.ui.core"]], "Module: ui.elements": [[294, "module-fury.ui.elements"]], "Module: ui.helpers": [[294, "module-fury.ui.helpers"]], "Panel2D": [[294, "panel2d"]], "TabPanel2D": [[294, "tabpanel2d"]], "TabUI": [[294, "tabui"]], "ImageContainer2D": [[294, "imagecontainer2d"]], "GridUI": [[294, "gridui"]], "UI": [[294, "id1"]], "Rectangle2D": [[294, "rectangle2d"]], "Disk2D": [[294, "disk2d"]], "TextBlock2D": [[294, "textblock2d"]], "Button2D": [[294, "button2d"]], "TextBox2D": [[294, "textbox2d"]], "LineSlider2D": [[294, "lineslider2d"]], "LineDoubleSlider2D": [[294, "linedoubleslider2d"]], "RingSlider2D": [[294, "ringslider2d"]], "RangeSlider": [[294, "rangeslider"]], "Option": [[294, "option"]], "Checkbox": [[294, "checkbox"]], "RadioButton": [[294, "radiobutton"]], "ComboBox2D": [[294, "combobox2d"]], "ListBox2D": [[294, "listbox2d"]], "ListBoxItem2D": [[294, "listboxitem2d"]], "FileMenu2D": [[294, "filemenu2d"]], "DrawShape": [[294, "drawshape"]], "PlaybackPanel": [[294, "playbackpanel"]], "Card2D": [[294, "card2d"]], "SpinBox": [[294, "spinbox"]], "clip_overflow": [[294, "clip-overflow"]], "wrap_overflow": [[294, "wrap-overflow"]], "check_overflow": [[294, "check-overflow"]], "cal_bounding_box_2d": [[294, "cal-bounding-box-2d"]], "rotate_2d": [[294, "rotate-2d"]], "utils": [[295, "module-fury.utils"]], "remove_observer_from_actor": [[295, "remove-observer-from-actor"]], "set_input": [[295, "set-input"]], "numpy_to_vtk_points": [[295, "numpy-to-vtk-points"]], "numpy_to_vtk_colors": [[295, "numpy-to-vtk-colors"]], "numpy_to_vtk_cells": [[295, "numpy-to-vtk-cells"]], "numpy_to_vtk_image_data": [[295, "numpy-to-vtk-image-data"]], "map_coordinates_3d_4d": [[295, "map-coordinates-3d-4d"]], "lines_to_vtk_polydata": [[295, "lines-to-vtk-polydata"]], "get_polydata_lines": [[295, "get-polydata-lines"]], "get_polydata_triangles": [[295, "get-polydata-triangles"]], "get_polydata_vertices": [[295, "get-polydata-vertices"]], "get_polydata_tcoord": [[295, "get-polydata-tcoord"]], "get_polydata_normals": [[295, "get-polydata-normals"]], "get_polydata_tangents": [[295, "get-polydata-tangents"]], "get_polydata_colors": [[295, "get-polydata-colors"]], "get_polydata_field": [[295, "get-polydata-field"]], "add_polydata_numeric_field": [[295, "add-polydata-numeric-field"]], "set_polydata_primitives_count": [[295, "set-polydata-primitives-count"]], "get_polydata_primitives_count": [[295, "get-polydata-primitives-count"]], "primitives_count_to_actor": [[295, "primitives-count-to-actor"]], "primitives_count_from_actor": [[295, "primitives-count-from-actor"]], "set_polydata_triangles": [[295, "set-polydata-triangles"]], "set_polydata_vertices": [[295, "set-polydata-vertices"]], "set_polydata_normals": [[295, "set-polydata-normals"]], "set_polydata_tangents": [[295, "set-polydata-tangents"]], "set_polydata_colors": [[295, "set-polydata-colors"]], "set_polydata_tcoords": [[295, "set-polydata-tcoords"]], "update_polydata_normals": [[295, "update-polydata-normals"]], "get_polymapper_from_polydata": [[295, "get-polymapper-from-polydata"]], "get_actor_from_polymapper": [[295, "get-actor-from-polymapper"]], "get_actor_from_polydata": [[295, "get-actor-from-polydata"]], "get_actor_from_primitive": [[295, "get-actor-from-primitive"]], "repeat_sources": [[295, "repeat-sources"]], "apply_affine_to_actor": [[295, "apply-affine-to-actor"]], "apply_affine": [[295, "apply-affine"]], "asbytes": [[295, "asbytes"]], "vtk_matrix_to_numpy": [[295, "vtk-matrix-to-numpy"]], "numpy_to_vtk_matrix": [[295, "numpy-to-vtk-matrix"]], "get_bounding_box_sizes": [[295, "get-bounding-box-sizes"]], "get_grid_cells_position": [[295, "get-grid-cells-position"]], "shallow_copy": [[295, "shallow-copy"]], "rgb_to_vtk": [[295, "rgb-to-vtk"]], "normalize_v3": [[295, "normalize-v3"]], "normals_from_v_f": [[295, "normals-from-v-f"]], "tangents_from_direction_of_anisotropy": [[295, "tangents-from-direction-of-anisotropy"]], "triangle_order": [[295, "triangle-order"]], "change_vertices_order": [[295, "change-vertices-order"]], "fix_winding_order": [[295, "fix-winding-order"]], "vertices_from_actor": [[295, "vertices-from-actor"]], "colors_from_actor": [[295, "colors-from-actor"]], "normals_from_actor": [[295, "normals-from-actor"]], "tangents_from_actor": [[295, "tangents-from-actor"]], "array_from_actor": [[295, "array-from-actor"]], "normals_to_actor": [[295, "normals-to-actor"]], "tangents_to_actor": [[295, "tangents-to-actor"]], "compute_bounds": [[295, "compute-bounds"]], "update_actor": [[295, "update-actor"]], "get_bounds": [[295, "get-bounds"]], "represent_actor_as_wireframe": [[295, "represent-actor-as-wireframe"]], "update_surface_actor_colors": [[295, "update-surface-actor-colors"]], "color_check": [[295, "color-check"]], "is_ui": [[295, "is-ui"]], "set_actor_origin": [[295, "set-actor-origin"]], "window": [[296, "module-fury.window"]], "Scene": [[296, "scene"]], "ShowManager": [[296, "showmanager"]], "show": [[296, "show"]], "record": [[296, "record"]], "antialiasing": [[296, "antialiasing"]], "snapshot": [[296, "snapshot"]], "analyze_scene": [[296, "analyze-scene"]], "analyze_snapshot": [[296, "analyze-snapshot"]], "enable_stereo": [[296, "enable-stereo"]], "gl_get_current_state": [[296, "gl-get-current-state"]], "gl_reset_blend": [[296, "gl-reset-blend"]], "gl_enable_depth": [[296, "gl-enable-depth"]], "gl_disable_depth": [[296, "gl-disable-depth"]], "gl_enable_blend": [[296, "gl-enable-blend"]], "gl_disable_blend": [[296, "gl-disable-blend"]], "gl_set_additive_blending": [[296, "gl-set-additive-blending"]], "gl_set_additive_blending_white_background": [[296, "gl-set-additive-blending-white-background"]], "gl_set_normal_blending": [[296, "gl-set-normal-blending"]], "gl_set_multiplicative_blending": [[296, "gl-set-multiplicative-blending"]], "gl_set_subtractive_blending": [[296, "gl-set-subtractive-blending"]], "release_context": [[296, "release-context"]], "API Reference": [[297, "api-reference"]], "Release History": [[298, "release-history"]], "Release notes v0.1.0 (2018-09-21)": [[299, "release-notes-v0-1-0-2018-09-21"]], "Quick Overview": [[299, "quick-overview"], [300, "quick-overview"], [301, "quick-overview"], [302, "quick-overview"], [303, "quick-overview"], [304, "quick-overview"], [305, "quick-overview"], [306, "quick-overview"], [307, "quick-overview"], [308, "quick-overview"], [309, "quick-overview"], [310, "quick-overview"], [311, "quick-overview"], [312, "quick-overview"], [313, "quick-overview"]], "Release notes v0.1.1 (2018-10-29)": [[300, "release-notes-v0-1-1-2018-10-29"]], "Release notes v0.1.2 and v0.1.3 (2018-10-31)": [[301, "release-notes-v0-1-2-and-v0-1-3-2018-10-31"]], "Release notes v0.1.4 (2018-11-26)": [[302, "release-notes-v0-1-4-2018-11-26"]], "Release notes v0.10.0 (2024/02/28)": [[303, "release-notes-v0-10-0-2024-02-28"]], "Details": [[303, "details"], [304, "details"], [305, "details"], [306, "details"], [307, "details"], [308, "details"], [309, "details"], [310, "details"], [311, "details"], [312, "details"], [313, "details"]], "Release notes v0.2.0 (2019-03-08)": [[304, "release-notes-v0-2-0-2019-03-08"]], "Release notes v0.3.0 (2019-08-02)": [[305, "release-notes-v0-3-0-2019-08-02"]], "Release notes v0.4.0 (2019-10-29)": [[306, "release-notes-v0-4-0-2019-10-29"]], "Release notes v0.5.1 (2020-04-01)": [[307, "release-notes-v0-5-1-2020-04-01"]], "Release notes v0.6.0 (2020-07-20)": [[308, "release-notes-v0-6-0-2020-07-20"]], "Release notes v0.6.1 (2020-08-20)": [[309, "release-notes-v0-6-1-2020-08-20"]], "Release notes v0.7.0 (2021/03/13)": [[310, "release-notes-v0-7-0-2021-03-13"]], "Release notes v0.7.1 (2021/08/03)": [[311, "release-notes-v0-7-1-2021-08-03"]], "Release notes v0.8.0 (2022/01/31)": [[312, "release-notes-v0-8-0-2022-01-31"]], "Release notes v0.9.0 (2023/04/15)": [[313, "release-notes-v0-9-0-2023-04-15"]], "Contributing": [[315, "contributing"]], "Types of Contributions": [[315, "types-of-contributions"]], "Report Bugs": [[315, "report-bugs"]], "Fix Bugs": [[315, "fix-bugs"]], "Implement Features": [[315, "implement-features"]], "Write Documentation": [[315, "write-documentation"]], "Submit Feedback": [[315, "submit-feedback"]], "Get Started!": [[315, "get-started"]], "Pull Request Guidelines": [[315, "pull-request-guidelines"]], "Publishing Releases": [[315, "publishing-releases"]], "Checklist before Releasing": [[315, "checklist-before-releasing"]], "Doing the release": [[315, "doing-the-release"]], "Other stuff that needs doing for the release": [[315, "other-stuff-that-needs-doing-for-the-release"]]}, "indexentries": {"disable_warnings() (in module fury)": [[273, "fury.disable_warnings"]], "enable_warnings() (in module fury)": [[273, "fury.enable_warnings"]], "fury": [[273, "module-fury"]], "get_info() (in module fury)": [[273, "fury.get_info"]], "module": [[273, "module-fury"], [274, "module-fury.actor"], [275, "module-fury.actors"], [275, "module-fury.actors.odf_slicer"], [275, "module-fury.actors.peak"], [275, "module-fury.actors.tensor"], [276, "module-fury.animation"], [276, "module-fury.animation.animation"], [276, "module-fury.animation.helpers"], [276, "module-fury.animation.interpolator"], [276, "module-fury.animation.timeline"], [277, "module-fury.colormap"], [278, "module-fury.convert"], [279, "module-fury.data"], [279, "module-fury.data.fetcher"], [280, "module-fury.decorators"], [281, "module-fury.deprecator"], [282, "module-fury.gltf"], [283, "module-fury.io"], [284, "module-fury.layout"], [285, "module-fury.lib"], [286, "module-fury.material"], [287, "module-fury.molecular"], [288, "module-fury.pick"], [289, "module-fury.pkg_info"], [290, "module-fury.primitive"], [291, "module-fury.shaders"], [291, "module-fury.shaders.base"], [292, "module-fury.stream"], [292, "module-fury.stream.client"], [292, "module-fury.stream.constants"], [292, "module-fury.stream.server"], [292, "module-fury.stream.server.async_app"], [292, "module-fury.stream.server.main"], [292, "module-fury.stream.tools"], [292, "module-fury.stream.widget"], [293, "module-fury.transform"], [294, "module-fury.ui"], [294, "module-fury.ui.containers"], [294, "module-fury.ui.core"], [294, "module-fury.ui.elements"], [294, "module-fury.ui.helpers"], [295, "module-fury.utils"], [296, "module-fury.window"]], "addposition() (fury.actor.container method)": [[274, "fury.actor.Container.AddPosition"]], "container (class in fury.actor)": [[274, "fury.actor.Container"]], "getbounds() (fury.actor.container method)": [[274, "fury.actor.Container.GetBounds"]], "getcenter() (fury.actor.container method)": [[274, "fury.actor.Container.GetCenter"]], "getlength() (fury.actor.container method)": [[274, "fury.actor.Container.GetLength"]], "getposition() (fury.actor.container method)": [[274, "fury.actor.Container.GetPosition"]], "getvisibility() (fury.actor.container method)": [[274, "fury.actor.Container.GetVisibility"]], "newinstance() (fury.actor.container method)": [[274, "fury.actor.Container.NewInstance"]], "setposition() (fury.actor.container method)": [[274, "fury.actor.Container.SetPosition"]], "setvisibility() (fury.actor.container method)": [[274, "fury.actor.Container.SetVisibility"]], "shallowcopy() (fury.actor.container method)": [[274, "fury.actor.Container.ShallowCopy"]], "__init__() (fury.actor.container method)": [[274, "fury.actor.Container.__init__"]], "add() (fury.actor.container method)": [[274, "fury.actor.Container.add"]], "add_to_scene() (fury.actor.container method)": [[274, "fury.actor.Container.add_to_scene"]], "anchor (fury.actor.container attribute)": [[274, "fury.actor.Container.anchor"]], "arrow() (in module fury.actor)": [[274, "fury.actor.arrow"]], "axes() (in module fury.actor)": [[274, "fury.actor.axes"]], "billboard() (in module fury.actor)": [[274, "fury.actor.billboard"]], "box() (in module fury.actor)": [[274, "fury.actor.box"]], "clear() (fury.actor.container method)": [[274, "fury.actor.Container.clear"]], "cone() (in module fury.actor)": [[274, "fury.actor.cone"]], "contour_from_label() (in module fury.actor)": [[274, "fury.actor.contour_from_label"]], "contour_from_roi() (in module fury.actor)": [[274, "fury.actor.contour_from_roi"]], "cube() (in module fury.actor)": [[274, "fury.actor.cube"]], "cylinder() (in module fury.actor)": [[274, "fury.actor.cylinder"]], "disk() (in module fury.actor)": [[274, "fury.actor.disk"]], "dot() (in module fury.actor)": [[274, "fury.actor.dot"]], "dots() (in module fury.actor)": [[274, "fury.actor.dots"]], "ellipsoid() (in module fury.actor)": [[274, "fury.actor.ellipsoid"]], "figure() (in module fury.actor)": [[274, "fury.actor.figure"]], "frustum() (in module fury.actor)": [[274, "fury.actor.frustum"]], "fury.actor": [[274, "module-fury.actor"]], "grid() (in module fury.actor)": [[274, "fury.actor.grid"]], "items (fury.actor.container property)": [[274, "fury.actor.Container.items"]], "label() (in module fury.actor)": [[274, "fury.actor.label"]], "line() (in module fury.actor)": [[274, "fury.actor.line"]], "markers() (in module fury.actor)": [[274, "fury.actor.markers"]], "octagonalprism() (in module fury.actor)": [[274, "fury.actor.octagonalprism"]], "odf_slicer() (in module fury.actor)": [[274, "fury.actor.odf_slicer"]], "padding (fury.actor.container attribute)": [[274, "fury.actor.Container.padding"]], "peak() (in module fury.actor)": [[274, "fury.actor.peak"]], "peak_slicer() (in module fury.actor)": [[274, "fury.actor.peak_slicer"]], "pentagonalprism() (in module fury.actor)": [[274, "fury.actor.pentagonalprism"]], "point() (in module fury.actor)": [[274, "fury.actor.point"]], "rectangle() (in module fury.actor)": [[274, "fury.actor.rectangle"]], "remove_from_scene() (fury.actor.container method)": [[274, "fury.actor.Container.remove_from_scene"]], "rhombicuboctahedron() (in module fury.actor)": [[274, "fury.actor.rhombicuboctahedron"]], "scalar_bar() (in module fury.actor)": [[274, "fury.actor.scalar_bar"]], "sdf() (in module fury.actor)": [[274, "fury.actor.sdf"]], "slicer() (in module fury.actor)": [[274, "fury.actor.slicer"]], "sphere() (in module fury.actor)": [[274, "fury.actor.sphere"]], "square() (in module fury.actor)": [[274, "fury.actor.square"]], "streamtube() (in module fury.actor)": [[274, "fury.actor.streamtube"]], "superquadric() (in module fury.actor)": [[274, "fury.actor.superquadric"]], "surface() (in module fury.actor)": [[274, "fury.actor.surface"]], "tensor_slicer() (in module fury.actor)": [[274, "fury.actor.tensor_slicer"]], "text_3d() (in module fury.actor)": [[274, "fury.actor.text_3d"]], "texture() (in module fury.actor)": [[274, "fury.actor.texture"]], "texture_2d() (in module fury.actor)": [[274, "fury.actor.texture_2d"]], "texture_on_sphere() (in module fury.actor)": [[274, "fury.actor.texture_on_sphere"]], "texture_update() (in module fury.actor)": [[274, "fury.actor.texture_update"]], "triangularprism() (in module fury.actor)": [[274, "fury.actor.triangularprism"]], "uncertainty_cone() (in module fury.actor)": [[274, "fury.actor.uncertainty_cone"]], "update() (fury.actor.container method)": [[274, "fury.actor.Container.update"]], "vector_text() (in module fury.actor)": [[274, "fury.actor.vector_text"]], "odfsliceractor (class in fury.actors.odf_slicer)": [[275, "fury.actors.odf_slicer.OdfSlicerActor"]], "peakactor (class in fury.actors.peak)": [[275, "fury.actors.peak.PeakActor"]], "__init__() (fury.actors.odf_slicer.odfsliceractor method)": [[275, "fury.actors.odf_slicer.OdfSlicerActor.__init__"]], "__init__() (fury.actors.peak.peakactor method)": [[275, "fury.actors.peak.PeakActor.__init__"]], "cross_section (fury.actors.peak.peakactor property)": [[275, "fury.actors.peak.PeakActor.cross_section"]], "display() (fury.actors.odf_slicer.odfsliceractor method)": [[275, "fury.actors.odf_slicer.OdfSlicerActor.display"]], "display_cross_section() (fury.actors.peak.peakactor method)": [[275, "fury.actors.peak.PeakActor.display_cross_section"]], "display_extent() (fury.actors.odf_slicer.odfsliceractor method)": [[275, "fury.actors.odf_slicer.OdfSlicerActor.display_extent"]], "display_extent() (fury.actors.peak.peakactor method)": [[275, "fury.actors.peak.PeakActor.display_extent"]], "double_cone() (in module fury.actors.tensor)": [[275, "fury.actors.tensor.double_cone"]], "fury.actors": [[275, "module-fury.actors"]], "fury.actors.odf_slicer": [[275, "module-fury.actors.odf_slicer"]], "fury.actors.peak": [[275, "module-fury.actors.peak"]], "fury.actors.tensor": [[275, "module-fury.actors.tensor"]], "global_opacity (fury.actors.peak.peakactor property)": [[275, "fury.actors.peak.PeakActor.global_opacity"]], "high_ranges (fury.actors.peak.peakactor property)": [[275, "fury.actors.peak.PeakActor.high_ranges"]], "is_range (fury.actors.peak.peakactor property)": [[275, "fury.actors.peak.PeakActor.is_range"]], "linewidth (fury.actors.peak.peakactor property)": [[275, "fury.actors.peak.PeakActor.linewidth"]], "low_ranges (fury.actors.peak.peakactor property)": [[275, "fury.actors.peak.PeakActor.low_ranges"]], "main_dir_uncertainty() (in module fury.actors.tensor)": [[275, "fury.actors.tensor.main_dir_uncertainty"]], "max_centers (fury.actors.peak.peakactor property)": [[275, "fury.actors.peak.PeakActor.max_centers"]], "min_centers (fury.actors.peak.peakactor property)": [[275, "fury.actors.peak.PeakActor.min_centers"]], "set_opacity() (fury.actors.odf_slicer.odfsliceractor method)": [[275, "fury.actors.odf_slicer.OdfSlicerActor.set_opacity"]], "slice_along_axis() (fury.actors.odf_slicer.odfsliceractor method)": [[275, "fury.actors.odf_slicer.OdfSlicerActor.slice_along_axis"]], "tensor_ellipsoid() (in module fury.actors.tensor)": [[275, "fury.actors.tensor.tensor_ellipsoid"]], "update_sphere() (fury.actors.odf_slicer.odfsliceractor method)": [[275, "fury.actors.odf_slicer.OdfSlicerActor.update_sphere"]], "animation (class in fury.animation.animation)": [[276, "fury.animation.animation.Animation"]], "cameraanimation (class in fury.animation.animation)": [[276, "fury.animation.animation.CameraAnimation"]], "timeline (class in fury.animation.timeline)": [[276, "fury.animation.timeline.Timeline"]], "__init__() (fury.animation.animation.animation method)": [[276, "fury.animation.animation.Animation.__init__"]], "__init__() (fury.animation.animation.cameraanimation method)": [[276, "fury.animation.animation.CameraAnimation.__init__"]], "__init__() (fury.animation.timeline.timeline method)": [[276, "fury.animation.timeline.Timeline.__init__"]], "actors (fury.animation.animation.animation attribute)": [[276, "fury.animation.animation.Animation.actors"]], "actors (fury.animation.animation.animation property)": [[276, "id0"]], "add() (fury.animation.animation.animation method)": [[276, "fury.animation.animation.Animation.add"]], "add_actor() (fury.animation.animation.animation method)": [[276, "fury.animation.animation.Animation.add_actor"]], "add_animation() (fury.animation.timeline.timeline method)": [[276, "fury.animation.timeline.Timeline.add_animation"]], "add_child_animation() (fury.animation.animation.animation method)": [[276, "fury.animation.animation.Animation.add_child_animation"]], "add_static_actor() (fury.animation.animation.animation method)": [[276, "fury.animation.animation.Animation.add_static_actor"]], "add_to_scene() (fury.animation.animation.animation method)": [[276, "fury.animation.animation.Animation.add_to_scene"]], "add_to_scene() (fury.animation.timeline.timeline method)": [[276, "fury.animation.timeline.Timeline.add_to_scene"]], "add_to_scene_at() (fury.animation.animation.animation method)": [[276, "fury.animation.animation.Animation.add_to_scene_at"]], "add_update_callback() (fury.animation.animation.animation method)": [[276, "fury.animation.animation.Animation.add_update_callback"]], "animations (fury.animation.timeline.timeline attribute)": [[276, "fury.animation.timeline.Timeline.animations"]], "animations (fury.animation.timeline.timeline property)": [[276, "id4"]], "camera (fury.animation.animation.cameraanimation attribute)": [[276, "fury.animation.animation.CameraAnimation.camera"]], "camera (fury.animation.animation.cameraanimation property)": [[276, "id3"]], "child_animations (fury.animation.animation.animation property)": [[276, "fury.animation.animation.Animation.child_animations"]], "color_interpolator() (in module fury.animation.interpolator)": [[276, "fury.animation.interpolator.color_interpolator"]], "cubic_bezier_interpolator() (in module fury.animation.interpolator)": [[276, "fury.animation.interpolator.cubic_bezier_interpolator"]], "cubic_spline_interpolator() (in module fury.animation.interpolator)": [[276, "fury.animation.interpolator.cubic_spline_interpolator"]], "current_timestamp (fury.animation.animation.animation property)": [[276, "fury.animation.animation.Animation.current_timestamp"]], "current_timestamp (fury.animation.timeline.timeline property)": [[276, "fury.animation.timeline.Timeline.current_timestamp"]], "duration (fury.animation.animation.animation property)": [[276, "fury.animation.animation.Animation.duration"]], "duration (fury.animation.timeline.timeline property)": [[276, "fury.animation.timeline.Timeline.duration"]], "euclidean_distances() (in module fury.animation.helpers)": [[276, "fury.animation.helpers.euclidean_distances"]], "fury.animation": [[276, "module-fury.animation"]], "fury.animation.animation": [[276, "module-fury.animation.animation"]], "fury.animation.helpers": [[276, "module-fury.animation.helpers"]], "fury.animation.interpolator": [[276, "module-fury.animation.interpolator"]], "fury.animation.timeline": [[276, "module-fury.animation.timeline"]], "get_color() (fury.animation.animation.animation method)": [[276, "fury.animation.animation.Animation.get_color"]], "get_current_value() (fury.animation.animation.animation method)": [[276, "fury.animation.animation.Animation.get_current_value"]], "get_focal() (fury.animation.animation.cameraanimation method)": [[276, "fury.animation.animation.CameraAnimation.get_focal"]], "get_keyframes() (fury.animation.animation.animation method)": [[276, "fury.animation.animation.Animation.get_keyframes"]], "get_next_timestamp() (in module fury.animation.helpers)": [[276, "fury.animation.helpers.get_next_timestamp"]], "get_opacity() (fury.animation.animation.animation method)": [[276, "fury.animation.animation.Animation.get_opacity"]], "get_position() (fury.animation.animation.animation method)": [[276, "fury.animation.animation.Animation.get_position"]], "get_previous_timestamp() (in module fury.animation.helpers)": [[276, "fury.animation.helpers.get_previous_timestamp"]], "get_rotation() (fury.animation.animation.animation method)": [[276, "fury.animation.animation.Animation.get_rotation"]], "get_scale() (fury.animation.animation.animation method)": [[276, "fury.animation.animation.Animation.get_scale"]], "get_time_tau() (in module fury.animation.helpers)": [[276, "fury.animation.helpers.get_time_tau"]], "get_timestamps_from_keyframes() (in module fury.animation.helpers)": [[276, "fury.animation.helpers.get_timestamps_from_keyframes"]], "get_value() (fury.animation.animation.animation method)": [[276, "fury.animation.animation.Animation.get_value"]], "get_values_from_keyframes() (in module fury.animation.helpers)": [[276, "fury.animation.helpers.get_values_from_keyframes"]], "get_view_up() (fury.animation.animation.cameraanimation method)": [[276, "fury.animation.animation.CameraAnimation.get_view_up"]], "has_playback_panel (fury.animation.timeline.timeline property)": [[276, "fury.animation.timeline.Timeline.has_playback_panel"]], "hsv_color_interpolator() (in module fury.animation.interpolator)": [[276, "fury.animation.interpolator.hsv_color_interpolator"]], "is_inside_scene_at() (fury.animation.animation.animation method)": [[276, "fury.animation.animation.Animation.is_inside_scene_at"]], "is_interpolatable() (fury.animation.animation.animation method)": [[276, "fury.animation.animation.Animation.is_interpolatable"]], "lab_color_interpolator() (in module fury.animation.interpolator)": [[276, "fury.animation.interpolator.lab_color_interpolator"]], "length (fury.animation.animation.animation attribute)": [[276, "fury.animation.animation.Animation.length"]], "length (fury.animation.animation.cameraanimation attribute)": [[276, "fury.animation.animation.CameraAnimation.length"]], "length (fury.animation.timeline.timeline attribute)": [[276, "fury.animation.timeline.Timeline.length"]], "lerp() (in module fury.animation.helpers)": [[276, "fury.animation.helpers.lerp"]], "linear_interpolator() (in module fury.animation.interpolator)": [[276, "fury.animation.interpolator.linear_interpolator"]], "loop (fury.animation.animation.animation attribute)": [[276, "fury.animation.animation.Animation.loop"]], "loop (fury.animation.animation.animation property)": [[276, "id2"]], "loop (fury.animation.animation.cameraanimation attribute)": [[276, "fury.animation.animation.CameraAnimation.loop"]], "loop (fury.animation.timeline.timeline attribute)": [[276, "fury.animation.timeline.Timeline.loop"]], "loop (fury.animation.timeline.timeline property)": [[276, "id5"]], "motion_path_res (fury.animation.animation.animation attribute)": [[276, "fury.animation.animation.Animation.motion_path_res"]], "motion_path_res (fury.animation.animation.cameraanimation attribute)": [[276, "fury.animation.animation.CameraAnimation.motion_path_res"]], "parent_animation (fury.animation.animation.animation property)": [[276, "fury.animation.animation.Animation.parent_animation"]], "pause() (fury.animation.timeline.timeline method)": [[276, "fury.animation.timeline.Timeline.pause"]], "paused (fury.animation.timeline.timeline property)": [[276, "fury.animation.timeline.Timeline.paused"]], "play() (fury.animation.timeline.timeline method)": [[276, "fury.animation.timeline.Timeline.play"]], "playback_panel (fury.animation.timeline.timeline attribute)": [[276, "fury.animation.timeline.Timeline.playback_panel"]], "playing (fury.animation.timeline.timeline property)": [[276, "fury.animation.timeline.Timeline.playing"]], "record() (fury.animation.timeline.timeline method)": [[276, "fury.animation.timeline.Timeline.record"]], "remove_actor() (fury.animation.animation.animation method)": [[276, "fury.animation.animation.Animation.remove_actor"]], "remove_actors() (fury.animation.animation.animation method)": [[276, "fury.animation.animation.Animation.remove_actors"]], "remove_animations() (fury.animation.animation.animation method)": [[276, "fury.animation.animation.Animation.remove_animations"]], "remove_from_scene() (fury.animation.animation.animation method)": [[276, "fury.animation.animation.Animation.remove_from_scene"]], "remove_from_scene() (fury.animation.timeline.timeline method)": [[276, "fury.animation.timeline.Timeline.remove_from_scene"]], "remove_from_scene_at() (fury.animation.animation.animation method)": [[276, "fury.animation.animation.Animation.remove_from_scene_at"]], "restart() (fury.animation.timeline.timeline method)": [[276, "fury.animation.timeline.Timeline.restart"]], "seek() (fury.animation.timeline.timeline method)": [[276, "fury.animation.timeline.Timeline.seek"]], "seek_percent() (fury.animation.timeline.timeline method)": [[276, "fury.animation.timeline.Timeline.seek_percent"]], "set_color() (fury.animation.animation.animation method)": [[276, "fury.animation.animation.Animation.set_color"]], "set_color_interpolator() (fury.animation.animation.animation method)": [[276, "fury.animation.animation.Animation.set_color_interpolator"]], "set_color_keyframes() (fury.animation.animation.animation method)": [[276, "fury.animation.animation.Animation.set_color_keyframes"]], "set_focal() (fury.animation.animation.cameraanimation method)": [[276, "fury.animation.animation.CameraAnimation.set_focal"]], "set_focal_interpolator() (fury.animation.animation.cameraanimation method)": [[276, "fury.animation.animation.CameraAnimation.set_focal_interpolator"]], "set_focal_keyframes() (fury.animation.animation.cameraanimation method)": [[276, "fury.animation.animation.CameraAnimation.set_focal_keyframes"]], "set_interpolator() (fury.animation.animation.animation method)": [[276, "fury.animation.animation.Animation.set_interpolator"]], "set_keyframe() (fury.animation.animation.animation method)": [[276, "fury.animation.animation.Animation.set_keyframe"]], "set_keyframes() (fury.animation.animation.animation method)": [[276, "fury.animation.animation.Animation.set_keyframes"]], "set_opacity() (fury.animation.animation.animation method)": [[276, "fury.animation.animation.Animation.set_opacity"]], "set_opacity_interpolator() (fury.animation.animation.animation method)": [[276, "fury.animation.animation.Animation.set_opacity_interpolator"]], "set_opacity_keyframes() (fury.animation.animation.animation method)": [[276, "fury.animation.animation.Animation.set_opacity_keyframes"]], "set_position() (fury.animation.animation.animation method)": [[276, "fury.animation.animation.Animation.set_position"]], "set_position_interpolator() (fury.animation.animation.animation method)": [[276, "fury.animation.animation.Animation.set_position_interpolator"]], "set_position_keyframes() (fury.animation.animation.animation method)": [[276, "fury.animation.animation.Animation.set_position_keyframes"]], "set_rotation() (fury.animation.animation.animation method)": [[276, "fury.animation.animation.Animation.set_rotation"]], "set_rotation_as_vector() (fury.animation.animation.animation method)": [[276, "fury.animation.animation.Animation.set_rotation_as_vector"]], "set_rotation_interpolator() (fury.animation.animation.animation method)": [[276, "fury.animation.animation.Animation.set_rotation_interpolator"]], "set_scale() (fury.animation.animation.animation method)": [[276, "fury.animation.animation.Animation.set_scale"]], "set_scale_interpolator() (fury.animation.animation.animation method)": [[276, "fury.animation.animation.Animation.set_scale_interpolator"]], "set_scale_keyframes() (fury.animation.animation.animation method)": [[276, "fury.animation.animation.Animation.set_scale_keyframes"]], "set_view_up() (fury.animation.animation.cameraanimation method)": [[276, "fury.animation.animation.CameraAnimation.set_view_up"]], "set_view_up_interpolator() (fury.animation.animation.cameraanimation method)": [[276, "fury.animation.animation.CameraAnimation.set_view_up_interpolator"]], "set_view_up_keyframes() (fury.animation.animation.cameraanimation method)": [[276, "fury.animation.animation.CameraAnimation.set_view_up_keyframes"]], "slerp() (in module fury.animation.interpolator)": [[276, "fury.animation.interpolator.slerp"]], "speed (fury.animation.timeline.timeline property)": [[276, "fury.animation.timeline.Timeline.speed"]], "spline_interpolator() (in module fury.animation.interpolator)": [[276, "fury.animation.interpolator.spline_interpolator"]], "static_actors (fury.animation.animation.animation property)": [[276, "fury.animation.animation.Animation.static_actors"]], "step_interpolator() (in module fury.animation.interpolator)": [[276, "fury.animation.interpolator.step_interpolator"]], "stop() (fury.animation.timeline.timeline method)": [[276, "fury.animation.timeline.Timeline.stop"]], "stopped (fury.animation.timeline.timeline property)": [[276, "fury.animation.timeline.Timeline.stopped"]], "tan_cubic_spline_interpolator() (in module fury.animation.interpolator)": [[276, "fury.animation.interpolator.tan_cubic_spline_interpolator"]], "timeline (fury.animation.animation.animation property)": [[276, "fury.animation.animation.Animation.timeline"]], "update() (fury.animation.timeline.timeline method)": [[276, "fury.animation.timeline.Timeline.update"]], "update_animation() (fury.animation.animation.animation method)": [[276, "fury.animation.animation.Animation.update_animation"]], "update_animation() (fury.animation.animation.cameraanimation method)": [[276, "fury.animation.animation.CameraAnimation.update_animation"]], "update_duration() (fury.animation.animation.animation method)": [[276, "fury.animation.animation.Animation.update_duration"]], "update_duration() (fury.animation.timeline.timeline method)": [[276, "fury.animation.timeline.Timeline.update_duration"]], "update_motion_path() (fury.animation.animation.animation method)": [[276, "fury.animation.animation.Animation.update_motion_path"]], "xyz_color_interpolator() (in module fury.animation.interpolator)": [[276, "fury.animation.interpolator.xyz_color_interpolator"]], "t (in module fury.colormap)": [[277, "fury.colormap.T"], [277, "id0"]], "base (in module fury.colormap)": [[277, "fury.colormap.base"], [277, "id15"]], "boys2rgb() (in module fury.colormap)": [[277, "fury.colormap.boys2rgb"]], "cc() (in module fury.colormap)": [[277, "fury.colormap.cc"]], "colormap_lookup_table() (in module fury.colormap)": [[277, "fury.colormap.colormap_lookup_table"]], "create_colormap() (in module fury.colormap)": [[277, "fury.colormap.create_colormap"]], "ctypes (in module fury.colormap)": [[277, "fury.colormap.ctypes"], [277, "id14"]], "data (in module fury.colormap)": [[277, "fury.colormap.data"], [277, "id2"]], "distinguishable_colormap() (in module fury.colormap)": [[277, "fury.colormap.distinguishable_colormap"]], "dtype (in module fury.colormap)": [[277, "fury.colormap.dtype"], [277, "id3"]], "flags (in module fury.colormap)": [[277, "fury.colormap.flags"], [277, "id4"]], "flat (in module fury.colormap)": [[277, "fury.colormap.flat"], [277, "id5"]], "fury.colormap": [[277, "module-fury.colormap"]], "get_cmap() (in module fury.colormap)": [[277, "fury.colormap.get_cmap"]], "get_xyz_coords() (in module fury.colormap)": [[277, "fury.colormap.get_xyz_coords"]], "hex_to_rgb() (in module fury.colormap)": [[277, "fury.colormap.hex_to_rgb"]], "hsv2rgb() (in module fury.colormap)": [[277, "fury.colormap.hsv2rgb"]], "imag (in module fury.colormap)": [[277, "fury.colormap.imag"], [277, "id6"]], "itemsize (in module fury.colormap)": [[277, "fury.colormap.itemsize"], [277, "id9"]], "lab2rgb() (in module fury.colormap)": [[277, "fury.colormap.lab2rgb"]], "lab2xyz() (in module fury.colormap)": [[277, "fury.colormap.lab2xyz"]], "line_colors() (in module fury.colormap)": [[277, "fury.colormap.line_colors"]], "nbytes (in module fury.colormap)": [[277, "fury.colormap.nbytes"], [277, "id10"]], "ndim (in module fury.colormap)": [[277, "fury.colormap.ndim"], [277, "id11"]], "orient2rgb() (in module fury.colormap)": [[277, "fury.colormap.orient2rgb"]], "real (in module fury.colormap)": [[277, "fury.colormap.real"], [277, "id7"]], "rgb2hsv() (in module fury.colormap)": [[277, "fury.colormap.rgb2hsv"]], "rgb2lab() (in module fury.colormap)": [[277, "fury.colormap.rgb2lab"]], "rgb2xyz() (in module fury.colormap)": [[277, "fury.colormap.rgb2xyz"]], "rgb_from_xyz() (in module fury.colormap)": [[277, "fury.colormap.rgb_from_xyz"]], "shape (in module fury.colormap)": [[277, "fury.colormap.shape"], [277, "id12"]], "size (in module fury.colormap)": [[277, "fury.colormap.size"], [277, "id8"]], "ss() (in module fury.colormap)": [[277, "fury.colormap.ss"]], "strides (in module fury.colormap)": [[277, "fury.colormap.strides"], [277, "id13"]], "xyz2lab() (in module fury.colormap)": [[277, "fury.colormap.xyz2lab"]], "xyz2rgb() (in module fury.colormap)": [[277, "fury.colormap.xyz2rgb"]], "xyz_from_rgb() (in module fury.colormap)": [[277, "fury.colormap.xyz_from_rgb"]], "fury.convert": [[278, "module-fury.convert"]], "matplotlib_figure_to_numpy() (in module fury.convert)": [[278, "fury.convert.matplotlib_figure_to_numpy"]], "data_dir() (in module fury.data)": [[279, "fury.data.DATA_DIR"]], "check_sha() (in module fury.data.fetcher)": [[279, "fury.data.fetcher.check_sha"]], "copyfileobj_withprogress() (in module fury.data.fetcher)": [[279, "fury.data.fetcher.copyfileobj_withprogress"]], "fetch_data() (in module fury.data.fetcher)": [[279, "fury.data.fetcher.fetch_data"]], "fetch_gltf() (in module fury.data.fetcher)": [[279, "fury.data.fetcher.fetch_gltf"]], "fetch_viz_cubemaps() (in module fury.data.fetcher)": [[279, "fury.data.fetcher.fetch_viz_cubemaps"]], "fetch_viz_dmri() (in module fury.data.fetcher)": [[279, "fury.data.fetcher.fetch_viz_dmri"]], "fetch_viz_icons() (in module fury.data.fetcher)": [[279, "fury.data.fetcher.fetch_viz_icons"]], "fetch_viz_models() (in module fury.data.fetcher)": [[279, "fury.data.fetcher.fetch_viz_models"]], "fetch_viz_new_icons() (in module fury.data.fetcher)": [[279, "fury.data.fetcher.fetch_viz_new_icons"]], "fetch_viz_textures() (in module fury.data.fetcher)": [[279, "fury.data.fetcher.fetch_viz_textures"]], "fetch_viz_wiki_nw() (in module fury.data.fetcher)": [[279, "fury.data.fetcher.fetch_viz_wiki_nw"]], "fury.data": [[279, "module-fury.data"]], "fury.data.fetcher": [[279, "module-fury.data.fetcher"]], "list_gltf_sample_models() (in module fury.data.fetcher)": [[279, "fury.data.fetcher.list_gltf_sample_models"]], "read_viz_cubemap() (in module fury.data.fetcher)": [[279, "fury.data.fetcher.read_viz_cubemap"]], "read_viz_dmri() (in module fury.data.fetcher)": [[279, "fury.data.fetcher.read_viz_dmri"]], "read_viz_gltf() (in module fury.data.fetcher)": [[279, "fury.data.fetcher.read_viz_gltf"]], "read_viz_icons() (in module fury.data.fetcher)": [[279, "fury.data.fetcher.read_viz_icons"]], "read_viz_models() (in module fury.data.fetcher)": [[279, "fury.data.fetcher.read_viz_models"]], "read_viz_textures() (in module fury.data.fetcher)": [[279, "fury.data.fetcher.read_viz_textures"]], "update_progressbar() (in module fury.data.fetcher)": [[279, "fury.data.fetcher.update_progressbar"]], "skip_re() (in module fury.decorators)": [[280, "fury.decorators.SKIP_RE"]], "doctest_skip_parser() (in module fury.decorators)": [[280, "fury.decorators.doctest_skip_parser"]], "fury.decorators": [[280, "module-fury.decorators"]], "argsdeprecationwarning (class in fury.deprecator)": [[281, "fury.deprecator.ArgsDeprecationWarning"]], "expireddeprecationerror (class in fury.deprecator)": [[281, "fury.deprecator.ExpiredDeprecationError"]], "_leading_white() (in module fury.deprecator)": [[281, "fury.deprecator._LEADING_WHITE"]], "__init__() (fury.deprecator.argsdeprecationwarning method)": [[281, "fury.deprecator.ArgsDeprecationWarning.__init__"]], "__init__() (fury.deprecator.expireddeprecationerror method)": [[281, "fury.deprecator.ExpiredDeprecationError.__init__"]], "cmp_pkg_version() (in module fury.deprecator)": [[281, "fury.deprecator.cmp_pkg_version"]], "deprecate_with_version() (in module fury.deprecator)": [[281, "fury.deprecator.deprecate_with_version"]], "deprecated_params() (in module fury.deprecator)": [[281, "fury.deprecator.deprecated_params"]], "fury.deprecator": [[281, "module-fury.deprecator"]], "is_bad_version() (in module fury.deprecator)": [[281, "fury.deprecator.is_bad_version"]], "__init__() (fury.gltf.gltf method)": [[282, "fury.gltf.glTF.__init__"]], "actors() (fury.gltf.gltf method)": [[282, "fury.gltf.glTF.actors"]], "apply_morph_vertices() (fury.gltf.gltf method)": [[282, "fury.gltf.glTF.apply_morph_vertices"]], "apply_skin_matrix() (fury.gltf.gltf method)": [[282, "fury.gltf.glTF.apply_skin_matrix"]], "export_scene() (in module fury.gltf)": [[282, "fury.gltf.export_scene"]], "fury.gltf": [[282, "module-fury.gltf"]], "generate_tmatrix() (fury.gltf.gltf method)": [[282, "fury.gltf.glTF.generate_tmatrix"]], "get_acc_data() (fury.gltf.gltf method)": [[282, "fury.gltf.glTF.get_acc_data"]], "get_animations() (fury.gltf.gltf method)": [[282, "fury.gltf.glTF.get_animations"]], "get_buff_array() (fury.gltf.gltf method)": [[282, "fury.gltf.glTF.get_buff_array"]], "get_joint_actors() (fury.gltf.gltf method)": [[282, "fury.gltf.glTF.get_joint_actors"]], "get_materials() (fury.gltf.gltf method)": [[282, "fury.gltf.glTF.get_materials"]], "get_matrix_from_sampler() (fury.gltf.gltf method)": [[282, "fury.gltf.glTF.get_matrix_from_sampler"]], "get_morph_data() (fury.gltf.gltf method)": [[282, "fury.gltf.glTF.get_morph_data"]], "get_prim() (in module fury.gltf)": [[282, "fury.gltf.get_prim"]], "get_sampler_data() (fury.gltf.gltf method)": [[282, "fury.gltf.glTF.get_sampler_data"]], "get_skin_data() (fury.gltf.gltf method)": [[282, "fury.gltf.glTF.get_skin_data"]], "get_texture() (fury.gltf.gltf method)": [[282, "fury.gltf.glTF.get_texture"]], "gltf (class in fury.gltf)": [[282, "fury.gltf.glTF"]], "initialize_skin() (fury.gltf.gltf method)": [[282, "fury.gltf.glTF.initialize_skin"]], "inspect_scene() (fury.gltf.gltf method)": [[282, "fury.gltf.glTF.inspect_scene"]], "load_camera() (fury.gltf.gltf method)": [[282, "fury.gltf.glTF.load_camera"]], "load_mesh() (fury.gltf.gltf method)": [[282, "fury.gltf.glTF.load_mesh"]], "main_animation() (fury.gltf.gltf method)": [[282, "fury.gltf.glTF.main_animation"]], "morph_animation() (fury.gltf.gltf method)": [[282, "fury.gltf.glTF.morph_animation"]], "skin_animation() (fury.gltf.gltf method)": [[282, "fury.gltf.glTF.skin_animation"]], "transverse_animations() (fury.gltf.gltf method)": [[282, "fury.gltf.glTF.transverse_animations"]], "transverse_bones() (fury.gltf.gltf method)": [[282, "fury.gltf.glTF.transverse_bones"]], "transverse_channels() (fury.gltf.gltf method)": [[282, "fury.gltf.glTF.transverse_channels"]], "transverse_node() (fury.gltf.gltf method)": [[282, "fury.gltf.glTF.transverse_node"]], "update_morph() (fury.gltf.gltf method)": [[282, "fury.gltf.glTF.update_morph"]], "update_skin() (fury.gltf.gltf method)": [[282, "fury.gltf.glTF.update_skin"]], "write_accessor() (in module fury.gltf)": [[282, "fury.gltf.write_accessor"]], "write_buffer() (in module fury.gltf)": [[282, "fury.gltf.write_buffer"]], "write_bufferview() (in module fury.gltf)": [[282, "fury.gltf.write_bufferview"]], "write_camera() (in module fury.gltf)": [[282, "fury.gltf.write_camera"]], "write_material() (in module fury.gltf)": [[282, "fury.gltf.write_material"]], "write_mesh() (in module fury.gltf)": [[282, "fury.gltf.write_mesh"]], "write_node() (in module fury.gltf)": [[282, "fury.gltf.write_node"]], "write_scene() (in module fury.gltf)": [[282, "fury.gltf.write_scene"]], "fury.io": [[283, "module-fury.io"]], "load_cubemap_texture() (in module fury.io)": [[283, "fury.io.load_cubemap_texture"]], "load_image() (in module fury.io)": [[283, "fury.io.load_image"]], "load_polydata() (in module fury.io)": [[283, "fury.io.load_polydata"]], "load_sprite_sheet() (in module fury.io)": [[283, "fury.io.load_sprite_sheet"]], "load_text() (in module fury.io)": [[283, "fury.io.load_text"]], "save_image() (in module fury.io)": [[283, "fury.io.save_image"]], "save_polydata() (in module fury.io)": [[283, "fury.io.save_polydata"]], "gridlayout (class in fury.layout)": [[284, "fury.layout.GridLayout"]], "horizontallayout (class in fury.layout)": [[284, "fury.layout.HorizontalLayout"]], "layout (class in fury.layout)": [[284, "fury.layout.Layout"]], "verticallayout (class in fury.layout)": [[284, "fury.layout.VerticalLayout"]], "xlayout (class in fury.layout)": [[284, "fury.layout.XLayout"]], "ylayout (class in fury.layout)": [[284, "fury.layout.YLayout"]], "zlayout (class in fury.layout)": [[284, "fury.layout.ZLayout"]], "__init__() (fury.layout.gridlayout method)": [[284, "fury.layout.GridLayout.__init__"]], "__init__() (fury.layout.horizontallayout method)": [[284, "fury.layout.HorizontalLayout.__init__"]], "__init__() (fury.layout.layout method)": [[284, "fury.layout.Layout.__init__"]], "__init__() (fury.layout.verticallayout method)": [[284, "fury.layout.VerticalLayout.__init__"]], "__init__() (fury.layout.xlayout method)": [[284, "fury.layout.XLayout.__init__"]], "__init__() (fury.layout.ylayout method)": [[284, "fury.layout.YLayout.__init__"]], "__init__() (fury.layout.zlayout method)": [[284, "fury.layout.ZLayout.__init__"]], "apply() (fury.layout.layout method)": [[284, "fury.layout.Layout.apply"]], "apply() (fury.layout.xlayout method)": [[284, "fury.layout.XLayout.apply"]], "apply() (fury.layout.ylayout method)": [[284, "fury.layout.YLayout.apply"]], "apply() (fury.layout.zlayout method)": [[284, "fury.layout.ZLayout.apply"]], "compute_positions() (fury.layout.gridlayout method)": [[284, "fury.layout.GridLayout.compute_positions"]], "compute_positions() (fury.layout.horizontallayout method)": [[284, "fury.layout.HorizontalLayout.compute_positions"]], "compute_positions() (fury.layout.layout method)": [[284, "fury.layout.Layout.compute_positions"]], "compute_positions() (fury.layout.verticallayout method)": [[284, "fury.layout.VerticalLayout.compute_positions"]], "compute_positions() (fury.layout.xlayout method)": [[284, "fury.layout.XLayout.compute_positions"]], "compute_positions() (fury.layout.ylayout method)": [[284, "fury.layout.YLayout.compute_positions"]], "compute_positions() (fury.layout.zlayout method)": [[284, "fury.layout.ZLayout.compute_positions"]], "compute_sizes() (fury.layout.gridlayout method)": [[284, "fury.layout.GridLayout.compute_sizes"]], "fury.layout": [[284, "module-fury.layout"]], "get_cells_shape() (fury.layout.gridlayout method)": [[284, "fury.layout.GridLayout.get_cells_shape"]], "get_cells_shape() (fury.layout.xlayout method)": [[284, "fury.layout.XLayout.get_cells_shape"]], "get_cells_shape() (fury.layout.ylayout method)": [[284, "fury.layout.YLayout.get_cells_shape"]], "get_cells_shape() (fury.layout.zlayout method)": [[284, "fury.layout.ZLayout.get_cells_shape"]], "actor (in module fury.lib)": [[285, "fury.lib.Actor"]], "actor2d (in module fury.lib)": [[285, "fury.lib.Actor2D"]], "algorithmoutput (in module fury.lib)": [[285, "fury.lib.AlgorithmOutput"]], "arrowsource (in module fury.lib)": [[285, "fury.lib.ArrowSource"]], "assembly (in module fury.lib)": [[285, "fury.lib.Assembly"]], "bmpreader (in module fury.lib)": [[285, "fury.lib.BMPReader"]], "bmpwriter (in module fury.lib)": [[285, "fury.lib.BMPWriter"]], "butterflysubdivisionfilter (in module fury.lib)": [[285, "fury.lib.ButterflySubdivisionFilter"]], "camera (in module fury.lib)": [[285, "fury.lib.Camera"]], "cellarray (in module fury.lib)": [[285, "fury.lib.CellArray"]], "cellpicker (in module fury.lib)": [[285, "fury.lib.CellPicker"]], "cleanpolydata (in module fury.lib)": [[285, "fury.lib.CleanPolyData"]], "command (in module fury.lib)": [[285, "fury.lib.Command"]], "conesource (in module fury.lib)": [[285, "fury.lib.ConeSource"]], "contourfilter (in module fury.lib)": [[285, "fury.lib.ContourFilter"]], "cylindersource (in module fury.lib)": [[285, "fury.lib.CylinderSource"]], "dataobject (in module fury.lib)": [[285, "fury.lib.DataObject"], [285, "id0"]], "datasetattributes (in module fury.lib)": [[285, "fury.lib.DataSetAttributes"]], "datasetmapper (in module fury.lib)": [[285, "fury.lib.DataSetMapper"]], "disksource (in module fury.lib)": [[285, "fury.lib.DiskSource"]], "doublearray (in module fury.lib)": [[285, "fury.lib.DoubleArray"]], "floatarray (in module fury.lib)": [[285, "fury.lib.FloatArray"]], "follower (in module fury.lib)": [[285, "fury.lib.Follower"]], "glyph3d (in module fury.lib)": [[285, "fury.lib.Glyph3D"]], "hardwareselector (in module fury.lib)": [[285, "fury.lib.HardwareSelector"]], "idtypearray (in module fury.lib)": [[285, "fury.lib.IdTypeArray"]], "imageactor (in module fury.lib)": [[285, "fury.lib.ImageActor"]], "imagedata (in module fury.lib)": [[285, "fury.lib.ImageData"]], "imageflip (in module fury.lib)": [[285, "fury.lib.ImageFlip"]], "imagemaptocolors (in module fury.lib)": [[285, "fury.lib.ImageMapToColors"]], "imagereader2factory (in module fury.lib)": [[285, "fury.lib.ImageReader2Factory"]], "imagereslice (in module fury.lib)": [[285, "fury.lib.ImageReslice"]], "interactoreventrecorder (in module fury.lib)": [[285, "fury.lib.InteractorEventRecorder"]], "interactorstyle (in module fury.lib)": [[285, "fury.lib.InteractorStyle"]], "interactorstyleimage (in module fury.lib)": [[285, "fury.lib.InteractorStyleImage"]], "interactorstyletrackballactor (in module fury.lib)": [[285, "fury.lib.InteractorStyleTrackballActor"]], "interactorstyletrackballcamera (in module fury.lib)": [[285, "fury.lib.InteractorStyleTrackballCamera"]], "interactorstyleuser (in module fury.lib)": [[285, "fury.lib.InteractorStyleUser"]], "jpegreader (in module fury.lib)": [[285, "fury.lib.JPEGReader"]], "jpegwriter (in module fury.lib)": [[285, "fury.lib.JPEGWriter"]], "lodactor (in module fury.lib)": [[285, "fury.lib.LODActor"]], "linearextrusionfilter (in module fury.lib)": [[285, "fury.lib.LinearExtrusionFilter"]], "lookuptable (in module fury.lib)": [[285, "fury.lib.LookupTable"]], "loopsubdivisionfilter (in module fury.lib)": [[285, "fury.lib.LoopSubdivisionFilter"]], "mniobjectreader (in module fury.lib)": [[285, "fury.lib.MNIObjectReader"]], "mniobjectwriter (in module fury.lib)": [[285, "fury.lib.MNIObjectWriter"]], "matrix3x3 (in module fury.lib)": [[285, "fury.lib.Matrix3x3"]], "matrix4x4 (in module fury.lib)": [[285, "fury.lib.Matrix4x4"]], "molecule (in module fury.lib)": [[285, "fury.lib.Molecule"]], "objreader (in module fury.lib)": [[285, "fury.lib.OBJReader"]], "openglmoleculemapper (in module fury.lib)": [[285, "fury.lib.OpenGLMoleculeMapper"]], "openglrenderer (in module fury.lib)": [[285, "fury.lib.OpenGLRenderer"]], "outlinefilter (in module fury.lib)": [[285, "fury.lib.OutlineFilter"]], "plyreader (in module fury.lib)": [[285, "fury.lib.PLYReader"]], "plywriter (in module fury.lib)": [[285, "fury.lib.PLYWriter"]], "pngreader (in module fury.lib)": [[285, "fury.lib.PNGReader"]], "pngwriter (in module fury.lib)": [[285, "fury.lib.PNGWriter"]], "periodictable (in module fury.lib)": [[285, "fury.lib.PeriodicTable"]], "pointpicker (in module fury.lib)": [[285, "fury.lib.PointPicker"]], "points (in module fury.lib)": [[285, "fury.lib.Points"]], "polydata (in module fury.lib)": [[285, "fury.lib.PolyData"]], "polydatamapper (in module fury.lib)": [[285, "fury.lib.PolyDataMapper"]], "polydatamapper2d (in module fury.lib)": [[285, "fury.lib.PolyDataMapper2D"]], "polydatanormals (in module fury.lib)": [[285, "fury.lib.PolyDataNormals"]], "polydatareader (in module fury.lib)": [[285, "fury.lib.PolyDataReader"]], "polydatawriter (in module fury.lib)": [[285, "fury.lib.PolyDataWriter"]], "polyvertex (in module fury.lib)": [[285, "fury.lib.PolyVertex"]], "polygon (in module fury.lib)": [[285, "fury.lib.Polygon"]], "proppicker (in module fury.lib)": [[285, "fury.lib.PropPicker"]], "property2d (in module fury.lib)": [[285, "fury.lib.Property2D"]], "proteinribbonfilter (in module fury.lib)": [[285, "fury.lib.ProteinRibbonFilter"]], "regularpolygonsource (in module fury.lib)": [[285, "fury.lib.RegularPolygonSource"]], "renderlargeimage (in module fury.lib)": [[285, "fury.lib.RenderLargeImage"]], "renderwindow (in module fury.lib)": [[285, "fury.lib.RenderWindow"]], "renderwindowinteractor (in module fury.lib)": [[285, "fury.lib.RenderWindowInteractor"]], "renderer (in module fury.lib)": [[285, "fury.lib.Renderer"]], "stlreader (in module fury.lib)": [[285, "fury.lib.STLReader"]], "stlwriter (in module fury.lib)": [[285, "fury.lib.STLWriter"]], "scalarbaractor (in module fury.lib)": [[285, "fury.lib.ScalarBarActor"]], "shader (in module fury.lib)": [[285, "fury.lib.Shader"]], "simplebondperceiver (in module fury.lib)": [[285, "fury.lib.SimpleBondPerceiver"]], "skybox (in module fury.lib)": [[285, "fury.lib.Skybox"]], "spheresource (in module fury.lib)": [[285, "fury.lib.SphereSource"]], "splinefilter (in module fury.lib)": [[285, "fury.lib.SplineFilter"]], "stringarray (in module fury.lib)": [[285, "fury.lib.StringArray"]], "tiffreader (in module fury.lib)": [[285, "fury.lib.TIFFReader"]], "tiffwriter (in module fury.lib)": [[285, "fury.lib.TIFFWriter"]], "textactor (in module fury.lib)": [[285, "fury.lib.TextActor"]], "textactor3d (in module fury.lib)": [[285, "fury.lib.TextActor3D"]], "texture (in module fury.lib)": [[285, "fury.lib.Texture"]], "texturemaptoplane (in module fury.lib)": [[285, "fury.lib.TextureMapToPlane"]], "texturedactor2d (in module fury.lib)": [[285, "fury.lib.TexturedActor2D"]], "texturedspheresource (in module fury.lib)": [[285, "fury.lib.TexturedSphereSource"]], "transform (in module fury.lib)": [[285, "fury.lib.Transform"]], "transformpolydatafilter (in module fury.lib)": [[285, "fury.lib.TransformPolyDataFilter"]], "trianglefilter (in module fury.lib)": [[285, "fury.lib.TriangleFilter"]], "tubefilter (in module fury.lib)": [[285, "fury.lib.TubeFilter"]], "unsignedchararray (in module fury.lib)": [[285, "fury.lib.UnsignedCharArray"]], "unstructuredgrid (in module fury.lib)": [[285, "fury.lib.UnstructuredGrid"]], "vtk_version() (in module fury.lib)": [[285, "fury.lib.VTK_VERSION"]], "vectortext (in module fury.lib)": [[285, "fury.lib.VectorText"]], "volume (in module fury.lib)": [[285, "fury.lib.Volume"]], "windowtoimagefilter (in module fury.lib)": [[285, "fury.lib.WindowToImageFilter"]], "worldpointpicker (in module fury.lib)": [[285, "fury.lib.WorldPointPicker"]], "xmlpolydatareader (in module fury.lib)": [[285, "fury.lib.XMLPolyDataReader"]], "xmlpolydatawriter (in module fury.lib)": [[285, "fury.lib.XMLPolyDataWriter"]], "fury.lib": [[285, "module-fury.lib"]], "fury.material": [[286, "module-fury.material"]], "manifest_pbr() (in module fury.material)": [[286, "fury.material.manifest_pbr"]], "manifest_principled() (in module fury.material)": [[286, "fury.material.manifest_principled"]], "manifest_standard() (in module fury.material)": [[286, "fury.material.manifest_standard"]], "molecule (class in fury.molecular)": [[287, "fury.molecular.Molecule"]], "ptable (class in fury.molecular)": [[287, "fury.molecular.PTable"]], "__init__() (fury.molecular.molecule method)": [[287, "fury.molecular.Molecule.__init__"]], "__init__() (fury.molecular.ptable method)": [[287, "fury.molecular.PTable.__init__"]], "add_atom() (in module fury.molecular)": [[287, "fury.molecular.add_atom"]], "add_bond() (in module fury.molecular)": [[287, "fury.molecular.add_bond"]], "atom_color() (fury.molecular.ptable method)": [[287, "fury.molecular.PTable.atom_color"]], "atomic_number() (fury.molecular.ptable method)": [[287, "fury.molecular.PTable.atomic_number"]], "atomic_radius() (fury.molecular.ptable method)": [[287, "fury.molecular.PTable.atomic_radius"]], "atomic_symbol() (fury.molecular.ptable method)": [[287, "fury.molecular.PTable.atomic_symbol"]], "ball_stick() (in module fury.molecular)": [[287, "fury.molecular.ball_stick"]], "bounding_box() (in module fury.molecular)": [[287, "fury.molecular.bounding_box"]], "compute_bonding() (in module fury.molecular)": [[287, "fury.molecular.compute_bonding"]], "deep_copy_molecule() (in module fury.molecular)": [[287, "fury.molecular.deep_copy_molecule"]], "element_name() (fury.molecular.ptable method)": [[287, "fury.molecular.PTable.element_name"]], "fury.molecular": [[287, "module-fury.molecular"]], "get_all_atomic_numbers() (in module fury.molecular)": [[287, "fury.molecular.get_all_atomic_numbers"]], "get_all_atomic_positions() (in module fury.molecular)": [[287, "fury.molecular.get_all_atomic_positions"]], "get_all_bond_orders() (in module fury.molecular)": [[287, "fury.molecular.get_all_bond_orders"]], "get_atomic_number() (in module fury.molecular)": [[287, "fury.molecular.get_atomic_number"]], "get_atomic_position() (in module fury.molecular)": [[287, "fury.molecular.get_atomic_position"]], "get_bond_order() (in module fury.molecular)": [[287, "fury.molecular.get_bond_order"]], "ribbon() (in module fury.molecular)": [[287, "fury.molecular.ribbon"]], "set_atomic_number() (in module fury.molecular)": [[287, "fury.molecular.set_atomic_number"]], "set_atomic_position() (in module fury.molecular)": [[287, "fury.molecular.set_atomic_position"]], "set_bond_order() (in module fury.molecular)": [[287, "fury.molecular.set_bond_order"]], "sphere_cpk() (in module fury.molecular)": [[287, "fury.molecular.sphere_cpk"]], "stick() (in module fury.molecular)": [[287, "fury.molecular.stick"]], "total_num_atoms (fury.molecular.molecule property)": [[287, "fury.molecular.Molecule.total_num_atoms"]], "total_num_bonds (fury.molecular.molecule property)": [[287, "fury.molecular.Molecule.total_num_bonds"]], "pickingmanager (class in fury.pick)": [[288, "fury.pick.PickingManager"]], "selectionmanager (class in fury.pick)": [[288, "fury.pick.SelectionManager"]], "__init__() (fury.pick.pickingmanager method)": [[288, "fury.pick.PickingManager.__init__"]], "__init__() (fury.pick.selectionmanager method)": [[288, "fury.pick.SelectionManager.__init__"]], "event_position() (fury.pick.pickingmanager method)": [[288, "fury.pick.PickingManager.event_position"]], "event_position() (fury.pick.selectionmanager method)": [[288, "fury.pick.SelectionManager.event_position"]], "fury.pick": [[288, "module-fury.pick"]], "pick() (fury.pick.pickingmanager method)": [[288, "fury.pick.PickingManager.pick"]], "pick() (fury.pick.selectionmanager method)": [[288, "fury.pick.SelectionManager.pick"], [288, "id0"]], "pickable_off() (fury.pick.pickingmanager method)": [[288, "fury.pick.PickingManager.pickable_off"]], "pickable_on() (fury.pick.pickingmanager method)": [[288, "fury.pick.PickingManager.pickable_on"]], "select() (fury.pick.selectionmanager method)": [[288, "fury.pick.SelectionManager.select"], [288, "id1"]], "selectable_off() (fury.pick.selectionmanager method)": [[288, "fury.pick.SelectionManager.selectable_off"]], "selectable_on() (fury.pick.selectionmanager method)": [[288, "fury.pick.SelectionManager.selectable_on"]], "update_selection_type() (fury.pick.selectionmanager method)": [[288, "fury.pick.SelectionManager.update_selection_type"]], "fury.pkg_info": [[289, "module-fury.pkg_info"]], "pkg_commit_hash() (in module fury.pkg_info)": [[289, "fury.pkg_info.pkg_commit_hash"]], "faces_from_sphere_vertices() (in module fury.primitive)": [[290, "fury.primitive.faces_from_sphere_vertices"]], "fury.primitive": [[290, "module-fury.primitive"]], "prim_arrow() (in module fury.primitive)": [[290, "fury.primitive.prim_arrow"]], "prim_box() (in module fury.primitive)": [[290, "fury.primitive.prim_box"]], "prim_cone() (in module fury.primitive)": [[290, "fury.primitive.prim_cone"]], "prim_cylinder() (in module fury.primitive)": [[290, "fury.primitive.prim_cylinder"]], "prim_frustum() (in module fury.primitive)": [[290, "fury.primitive.prim_frustum"]], "prim_icosahedron() (in module fury.primitive)": [[290, "fury.primitive.prim_icosahedron"]], "prim_octagonalprism() (in module fury.primitive)": [[290, "fury.primitive.prim_octagonalprism"]], "prim_pentagonalprism() (in module fury.primitive)": [[290, "fury.primitive.prim_pentagonalprism"]], "prim_rhombicuboctahedron() (in module fury.primitive)": [[290, "fury.primitive.prim_rhombicuboctahedron"]], "prim_sphere() (in module fury.primitive)": [[290, "fury.primitive.prim_sphere"]], "prim_square() (in module fury.primitive)": [[290, "fury.primitive.prim_square"]], "prim_star() (in module fury.primitive)": [[290, "fury.primitive.prim_star"]], "prim_superquadric() (in module fury.primitive)": [[290, "fury.primitive.prim_superquadric"]], "prim_tetrahedron() (in module fury.primitive)": [[290, "fury.primitive.prim_tetrahedron"]], "prim_triangularprism() (in module fury.primitive)": [[290, "fury.primitive.prim_triangularprism"]], "repeat_primitive() (in module fury.primitive)": [[290, "fury.primitive.repeat_primitive"]], "repeat_primitive_function() (in module fury.primitive)": [[290, "fury.primitive.repeat_primitive_function"]], "shaders_dir() (in module fury.shaders.base)": [[291, "fury.shaders.base.SHADERS_DIR"]], "add_shader_callback() (in module fury.shaders.base)": [[291, "fury.shaders.base.add_shader_callback"]], "attribute_to_actor() (in module fury.shaders.base)": [[291, "fury.shaders.base.attribute_to_actor"]], "compose_shader() (in module fury.shaders.base)": [[291, "fury.shaders.base.compose_shader"]], "fury.shaders": [[291, "module-fury.shaders"]], "fury.shaders.base": [[291, "module-fury.shaders.base"]], "import_fury_shader() (in module fury.shaders.base)": [[291, "fury.shaders.base.import_fury_shader"]], "load() (in module fury.shaders.base)": [[291, "fury.shaders.base.load"]], "load_shader() (in module fury.shaders.base)": [[291, "fury.shaders.base.load_shader"]], "replace_shader_in_actor() (in module fury.shaders.base)": [[291, "fury.shaders.base.replace_shader_in_actor"]], "shader_apply_effects() (in module fury.shaders.base)": [[291, "fury.shaders.base.shader_apply_effects"]], "shader_to_actor() (in module fury.shaders.base)": [[291, "fury.shaders.base.shader_to_actor"]], "arraycircularqueue (class in fury.stream.tools)": [[292, "fury.stream.tools.ArrayCircularQueue"]], "furystreamclient (class in fury.stream.client)": [[292, "fury.stream.client.FuryStreamClient"]], "furystreaminteraction (class in fury.stream.client)": [[292, "fury.stream.client.FuryStreamInteraction"]], "genericcircularqueue (class in fury.stream.tools)": [[292, "fury.stream.tools.GenericCircularQueue"]], "genericimagebuffermanager (class in fury.stream.tools)": [[292, "fury.stream.tools.GenericImageBufferManager"]], "genericmultidimensionalbuffer (class in fury.stream.tools)": [[292, "fury.stream.tools.GenericMultiDimensionalBuffer"]], "intervaltimer (class in fury.stream.tools)": [[292, "fury.stream.tools.IntervalTimer"]], "intervaltimerthreading (class in fury.stream.tools)": [[292, "fury.stream.tools.IntervalTimerThreading"]], "rtcserver (class in fury.stream.server.main)": [[292, "fury.stream.server.main.RTCServer"]], "rawarrayimagebuffermanager (class in fury.stream.tools)": [[292, "fury.stream.tools.RawArrayImageBufferManager"]], "rawarraymultidimensionalbuffer (class in fury.stream.tools)": [[292, "fury.stream.tools.RawArrayMultiDimensionalBuffer"]], "sharedmemcircularqueue (class in fury.stream.tools)": [[292, "fury.stream.tools.SharedMemCircularQueue"]], "sharedmemimagebuffermanager (class in fury.stream.tools)": [[292, "fury.stream.tools.SharedMemImageBufferManager"]], "sharedmemmultidimensionalbuffer (class in fury.stream.tools)": [[292, "fury.stream.tools.SharedMemMultiDimensionalBuffer"]], "widget (class in fury.stream.widget)": [[292, "fury.stream.widget.Widget"]], "_cqueue() (in module fury.stream.constants)": [[292, "fury.stream.constants._CQUEUE"]], "_cqueue_event_ids() (in module fury.stream.constants)": [[292, "fury.stream.constants._CQUEUE_EVENT_IDs"]], "_cqueue_index_info() (in module fury.stream.constants)": [[292, "fury.stream.constants._CQUEUE_INDEX_INFO"]], "__init__() (fury.stream.client.furystreamclient method)": [[292, "fury.stream.client.FuryStreamClient.__init__"]], "__init__() (fury.stream.client.furystreaminteraction method)": [[292, "fury.stream.client.FuryStreamInteraction.__init__"]], "__init__() (fury.stream.server.main.rtcserver method)": [[292, "fury.stream.server.main.RTCServer.__init__"]], "__init__() (fury.stream.tools.arraycircularqueue method)": [[292, "fury.stream.tools.ArrayCircularQueue.__init__"]], "__init__() (fury.stream.tools.genericcircularqueue method)": [[292, "fury.stream.tools.GenericCircularQueue.__init__"]], "__init__() (fury.stream.tools.genericimagebuffermanager method)": [[292, "fury.stream.tools.GenericImageBufferManager.__init__"]], "__init__() (fury.stream.tools.genericmultidimensionalbuffer method)": [[292, "fury.stream.tools.GenericMultiDimensionalBuffer.__init__"]], "__init__() (fury.stream.tools.intervaltimer method)": [[292, "fury.stream.tools.IntervalTimer.__init__"]], "__init__() (fury.stream.tools.intervaltimerthreading method)": [[292, "fury.stream.tools.IntervalTimerThreading.__init__"]], "__init__() (fury.stream.tools.rawarrayimagebuffermanager method)": [[292, "fury.stream.tools.RawArrayImageBufferManager.__init__"]], "__init__() (fury.stream.tools.rawarraymultidimensionalbuffer method)": [[292, "fury.stream.tools.RawArrayMultiDimensionalBuffer.__init__"]], "__init__() (fury.stream.tools.sharedmemcircularqueue method)": [[292, "fury.stream.tools.SharedMemCircularQueue.__init__"]], "__init__() (fury.stream.tools.sharedmemimagebuffermanager method)": [[292, "fury.stream.tools.SharedMemImageBufferManager.__init__"]], "__init__() (fury.stream.tools.sharedmemmultidimensionalbuffer method)": [[292, "fury.stream.tools.SharedMemMultiDimensionalBuffer.__init__"]], "__init__() (fury.stream.widget.widget method)": [[292, "fury.stream.widget.Widget.__init__"]], "async_get_jpeg() (fury.stream.tools.genericimagebuffermanager method)": [[292, "fury.stream.tools.GenericImageBufferManager.async_get_jpeg"]], "buffer (fury.stream.tools.genericmultidimensionalbuffer property)": [[292, "fury.stream.tools.GenericMultiDimensionalBuffer.buffer"]], "buffer_index (fury.stream.tools.genericimagebuffermanager property)": [[292, "fury.stream.tools.GenericImageBufferManager.buffer_index"]], "callback_stream_client() (in module fury.stream.client)": [[292, "fury.stream.client.callback_stream_client"]], "check_port_is_available() (in module fury.stream.widget)": [[292, "fury.stream.widget.check_port_is_available"]], "cleanup() (fury.stream.client.furystreamclient method)": [[292, "fury.stream.client.FuryStreamClient.cleanup"]], "cleanup() (fury.stream.client.furystreaminteraction method)": [[292, "fury.stream.client.FuryStreamInteraction.cleanup"]], "cleanup() (fury.stream.tools.arraycircularqueue method)": [[292, "fury.stream.tools.ArrayCircularQueue.cleanup"]], "cleanup() (fury.stream.tools.genericcircularqueue method)": [[292, "fury.stream.tools.GenericCircularQueue.cleanup"]], "cleanup() (fury.stream.tools.genericimagebuffermanager method)": [[292, "fury.stream.tools.GenericImageBufferManager.cleanup"]], "cleanup() (fury.stream.tools.genericmultidimensionalbuffer method)": [[292, "fury.stream.tools.GenericMultiDimensionalBuffer.cleanup"]], "cleanup() (fury.stream.tools.rawarrayimagebuffermanager method)": [[292, "fury.stream.tools.RawArrayImageBufferManager.cleanup"]], "cleanup() (fury.stream.tools.rawarraymultidimensionalbuffer method)": [[292, "fury.stream.tools.RawArrayMultiDimensionalBuffer.cleanup"]], "cleanup() (fury.stream.tools.sharedmemcircularqueue method)": [[292, "fury.stream.tools.SharedMemCircularQueue.cleanup"]], "cleanup() (fury.stream.tools.sharedmemimagebuffermanager method)": [[292, "fury.stream.tools.SharedMemImageBufferManager.cleanup"]], "cleanup() (fury.stream.tools.sharedmemmultidimensionalbuffer method)": [[292, "fury.stream.tools.SharedMemMultiDimensionalBuffer.cleanup"]], "cleanup() (fury.stream.widget.widget method)": [[292, "fury.stream.widget.Widget.cleanup"]], "command_string (fury.stream.widget.widget property)": [[292, "fury.stream.widget.Widget.command_string"]], "create_mem_resource() (fury.stream.tools.arraycircularqueue method)": [[292, "fury.stream.tools.ArrayCircularQueue.create_mem_resource"]], "create_mem_resource() (fury.stream.tools.genericcircularqueue method)": [[292, "fury.stream.tools.GenericCircularQueue.create_mem_resource"]], "create_mem_resource() (fury.stream.tools.genericimagebuffermanager method)": [[292, "fury.stream.tools.GenericImageBufferManager.create_mem_resource"]], "create_mem_resource() (fury.stream.tools.genericmultidimensionalbuffer method)": [[292, "fury.stream.tools.GenericMultiDimensionalBuffer.create_mem_resource"]], "create_mem_resource() (fury.stream.tools.rawarrayimagebuffermanager method)": [[292, "fury.stream.tools.RawArrayImageBufferManager.create_mem_resource"]], "create_mem_resource() (fury.stream.tools.rawarraymultidimensionalbuffer method)": [[292, "fury.stream.tools.RawArrayMultiDimensionalBuffer.create_mem_resource"]], "create_mem_resource() (fury.stream.tools.sharedmemcircularqueue method)": [[292, "fury.stream.tools.SharedMemCircularQueue.create_mem_resource"]], "create_mem_resource() (fury.stream.tools.sharedmemimagebuffermanager method)": [[292, "fury.stream.tools.SharedMemImageBufferManager.create_mem_resource"]], "create_mem_resource() (fury.stream.tools.sharedmemmultidimensionalbuffer method)": [[292, "fury.stream.tools.SharedMemMultiDimensionalBuffer.create_mem_resource"]], "dequeue() (fury.stream.tools.arraycircularqueue method)": [[292, "fury.stream.tools.ArrayCircularQueue.dequeue"]], "dequeue() (fury.stream.tools.genericcircularqueue method)": [[292, "fury.stream.tools.GenericCircularQueue.dequeue"]], "dequeue() (fury.stream.tools.sharedmemcircularqueue method)": [[292, "fury.stream.tools.SharedMemCircularQueue.dequeue"]], "display() (fury.stream.widget.widget method)": [[292, "fury.stream.widget.Widget.display"]], "enqueue() (fury.stream.tools.arraycircularqueue method)": [[292, "fury.stream.tools.ArrayCircularQueue.enqueue"]], "enqueue() (fury.stream.tools.genericcircularqueue method)": [[292, "fury.stream.tools.GenericCircularQueue.enqueue"]], "enqueue() (fury.stream.tools.sharedmemcircularqueue method)": [[292, "fury.stream.tools.SharedMemCircularQueue.enqueue"]], "fury.stream": [[292, "module-fury.stream"]], "fury.stream.client": [[292, "module-fury.stream.client"]], "fury.stream.constants": [[292, "module-fury.stream.constants"]], "fury.stream.server": [[292, "module-fury.stream.server"]], "fury.stream.server.async_app": [[292, "module-fury.stream.server.async_app"]], "fury.stream.server.main": [[292, "module-fury.stream.server.main"]], "fury.stream.tools": [[292, "module-fury.stream.tools"]], "fury.stream.widget": [[292, "module-fury.stream.widget"]], "get_app() (in module fury.stream.server.async_app)": [[292, "fury.stream.server.async_app.get_app"]], "get_current_frame() (fury.stream.tools.genericimagebuffermanager method)": [[292, "fury.stream.tools.GenericImageBufferManager.get_current_frame"]], "get_jpeg() (fury.stream.tools.genericimagebuffermanager method)": [[292, "fury.stream.tools.GenericImageBufferManager.get_jpeg"]], "get_start_end() (fury.stream.tools.genericmultidimensionalbuffer method)": [[292, "fury.stream.tools.GenericMultiDimensionalBuffer.get_start_end"]], "head (fury.stream.tools.genericcircularqueue property)": [[292, "fury.stream.tools.GenericCircularQueue.head"]], "interaction_callback() (in module fury.stream.client)": [[292, "fury.stream.client.interaction_callback"]], "is_unlocked() (fury.stream.tools.sharedmemcircularqueue method)": [[292, "fury.stream.tools.SharedMemCircularQueue.is_unlocked"]], "load_mem_resource() (fury.stream.tools.arraycircularqueue method)": [[292, "fury.stream.tools.ArrayCircularQueue.load_mem_resource"]], "load_mem_resource() (fury.stream.tools.genericcircularqueue method)": [[292, "fury.stream.tools.GenericCircularQueue.load_mem_resource"]], "load_mem_resource() (fury.stream.tools.genericimagebuffermanager method)": [[292, "fury.stream.tools.GenericImageBufferManager.load_mem_resource"]], "load_mem_resource() (fury.stream.tools.genericmultidimensionalbuffer method)": [[292, "fury.stream.tools.GenericMultiDimensionalBuffer.load_mem_resource"]], "load_mem_resource() (fury.stream.tools.rawarrayimagebuffermanager method)": [[292, "fury.stream.tools.RawArrayImageBufferManager.load_mem_resource"]], "load_mem_resource() (fury.stream.tools.rawarraymultidimensionalbuffer method)": [[292, "fury.stream.tools.RawArrayMultiDimensionalBuffer.load_mem_resource"]], "load_mem_resource() (fury.stream.tools.sharedmemcircularqueue method)": [[292, "fury.stream.tools.SharedMemCircularQueue.load_mem_resource"]], "load_mem_resource() (fury.stream.tools.sharedmemimagebuffermanager method)": [[292, "fury.stream.tools.SharedMemImageBufferManager.load_mem_resource"]], "load_mem_resource() (fury.stream.tools.sharedmemmultidimensionalbuffer method)": [[292, "fury.stream.tools.SharedMemMultiDimensionalBuffer.load_mem_resource"]], "lock() (fury.stream.tools.sharedmemcircularqueue method)": [[292, "fury.stream.tools.SharedMemCircularQueue.lock"]], "next_buffer_index (fury.stream.tools.genericimagebuffermanager property)": [[292, "fury.stream.tools.GenericImageBufferManager.next_buffer_index"]], "pcs() (in module fury.stream.server.async_app)": [[292, "fury.stream.server.async_app.pcs"]], "recv() (fury.stream.server.main.rtcserver method)": [[292, "fury.stream.server.main.RTCServer.recv"]], "release() (fury.stream.server.main.rtcserver method)": [[292, "fury.stream.server.main.RTCServer.release"]], "remove_shm_from_resource_tracker() (in module fury.stream.tools)": [[292, "fury.stream.tools.remove_shm_from_resource_tracker"]], "return_iframe() (fury.stream.widget.widget method)": [[292, "fury.stream.widget.Widget.return_iframe"]], "run_command() (fury.stream.widget.widget method)": [[292, "fury.stream.widget.Widget.run_command"]], "set_head_tail() (fury.stream.tools.genericcircularqueue method)": [[292, "fury.stream.tools.GenericCircularQueue.set_head_tail"]], "set_mouse() (in module fury.stream.server.async_app)": [[292, "fury.stream.server.async_app.set_mouse"]], "set_mouse_click() (in module fury.stream.server.async_app)": [[292, "fury.stream.server.async_app.set_mouse_click"]], "set_weel() (in module fury.stream.server.async_app)": [[292, "fury.stream.server.async_app.set_weel"]], "start() (fury.stream.client.furystreamclient method)": [[292, "fury.stream.client.FuryStreamClient.start"]], "start() (fury.stream.client.furystreaminteraction method)": [[292, "fury.stream.client.FuryStreamInteraction.start"]], "start() (fury.stream.tools.intervaltimer method)": [[292, "fury.stream.tools.IntervalTimer.start"]], "start() (fury.stream.tools.intervaltimerthreading method)": [[292, "fury.stream.tools.IntervalTimerThreading.start"]], "start() (fury.stream.widget.widget method)": [[292, "fury.stream.widget.Widget.start"]], "stop() (fury.stream.client.furystreamclient method)": [[292, "fury.stream.client.FuryStreamClient.stop"]], "stop() (fury.stream.client.furystreaminteraction method)": [[292, "fury.stream.client.FuryStreamInteraction.stop"]], "stop() (fury.stream.tools.intervaltimer method)": [[292, "fury.stream.tools.IntervalTimer.stop"]], "stop() (fury.stream.tools.intervaltimerthreading method)": [[292, "fury.stream.tools.IntervalTimerThreading.stop"]], "stop() (fury.stream.widget.widget method)": [[292, "fury.stream.widget.Widget.stop"]], "tail (fury.stream.tools.genericcircularqueue property)": [[292, "fury.stream.tools.GenericCircularQueue.tail"]], "unlock() (fury.stream.tools.sharedmemcircularqueue method)": [[292, "fury.stream.tools.SharedMemCircularQueue.unlock"]], "url (fury.stream.widget.widget property)": [[292, "fury.stream.widget.Widget.url"]], "web_server() (in module fury.stream.server.main)": [[292, "fury.stream.server.main.web_server"]], "web_server_raw_array() (in module fury.stream.server.main)": [[292, "fury.stream.server.main.web_server_raw_array"]], "write_into() (fury.stream.tools.genericimagebuffermanager method)": [[292, "fury.stream.tools.GenericImageBufferManager.write_into"]], "_tuple2axes() (in module fury.transform)": [[293, "fury.transform._TUPLE2AXES"]], "apply_transformation() (in module fury.transform)": [[293, "fury.transform.apply_transformation"]], "cart2sphere() (in module fury.transform)": [[293, "fury.transform.cart2sphere"]], "euler_matrix() (in module fury.transform)": [[293, "fury.transform.euler_matrix"]], "fury.transform": [[293, "module-fury.transform"]], "rotate() (in module fury.transform)": [[293, "fury.transform.rotate"]], "scale() (in module fury.transform)": [[293, "fury.transform.scale"]], "sphere2cart() (in module fury.transform)": [[293, "fury.transform.sphere2cart"]], "transform_from_matrix() (in module fury.transform)": [[293, "fury.transform.transform_from_matrix"]], "translate() (in module fury.transform)": [[293, "fury.transform.translate"]], "anticlockwise_rotation_x (fury.ui.containers.gridui attribute)": [[294, "fury.ui.containers.GridUI.ANTICLOCKWISE_ROTATION_X"]], "anticlockwise_rotation_y (fury.ui.containers.gridui attribute)": [[294, "fury.ui.containers.GridUI.ANTICLOCKWISE_ROTATION_Y"]], "button2d (class in fury.ui.core)": [[294, "fury.ui.core.Button2D"]], "clockwise_rotation_x (fury.ui.containers.gridui attribute)": [[294, "fury.ui.containers.GridUI.CLOCKWISE_ROTATION_X"]], "clockwise_rotation_y (fury.ui.containers.gridui attribute)": [[294, "fury.ui.containers.GridUI.CLOCKWISE_ROTATION_Y"]], "card2d (class in fury.ui.elements)": [[294, "fury.ui.elements.Card2D"]], "checkbox (class in fury.ui.elements)": [[294, "fury.ui.elements.Checkbox"]], "combobox2d (class in fury.ui.elements)": [[294, "fury.ui.elements.ComboBox2D"]], "disk2d (class in fury.ui.core)": [[294, "fury.ui.core.Disk2D"]], "drawpanel (class in fury.ui.elements)": [[294, "fury.ui.elements.DrawPanel"]], "drawshape (class in fury.ui.elements)": [[294, "fury.ui.elements.DrawShape"]], "filemenu2d (class in fury.ui.elements)": [[294, "fury.ui.elements.FileMenu2D"]], "gridui (class in fury.ui.containers)": [[294, "fury.ui.containers.GridUI"]], "imagecontainer2d (class in fury.ui.containers)": [[294, "fury.ui.containers.ImageContainer2D"]], "linedoubleslider2d (class in fury.ui.elements)": [[294, "fury.ui.elements.LineDoubleSlider2D"]], "lineslider2d (class in fury.ui.elements)": [[294, "fury.ui.elements.LineSlider2D"]], "listbox2d (class in fury.ui.elements)": [[294, "fury.ui.elements.ListBox2D"]], "listboxitem2d (class in fury.ui.elements)": [[294, "fury.ui.elements.ListBoxItem2D"]], "option (class in fury.ui.elements)": [[294, "fury.ui.elements.Option"]], "panel2d (class in fury.ui.containers)": [[294, "fury.ui.containers.Panel2D"]], "playbackpanel (class in fury.ui.elements)": [[294, "fury.ui.elements.PlaybackPanel"]], "radiobutton (class in fury.ui.elements)": [[294, "fury.ui.elements.RadioButton"]], "rangeslider (class in fury.ui.elements)": [[294, "fury.ui.elements.RangeSlider"]], "rectangle2d (class in fury.ui.core)": [[294, "fury.ui.core.Rectangle2D"]], "ringslider2d (class in fury.ui.elements)": [[294, "fury.ui.elements.RingSlider2D"]], "spinbox (class in fury.ui.elements)": [[294, "fury.ui.elements.SpinBox"]], "tabpanel2d (class in fury.ui.containers)": [[294, "fury.ui.containers.TabPanel2D"]], "tabui (class in fury.ui.containers)": [[294, "fury.ui.containers.TabUI"]], "textblock2d (class in fury.ui.core)": [[294, "fury.ui.core.TextBlock2D"]], "textbox2d (class in fury.ui.elements)": [[294, "fury.ui.elements.TextBox2D"]], "ui (class in fury.ui.core)": [[294, "fury.ui.core.UI"]], "__init__() (fury.ui.containers.gridui method)": [[294, "fury.ui.containers.GridUI.__init__"]], "__init__() (fury.ui.containers.imagecontainer2d method)": [[294, "fury.ui.containers.ImageContainer2D.__init__"]], "__init__() (fury.ui.containers.panel2d method)": [[294, "fury.ui.containers.Panel2D.__init__"]], "__init__() (fury.ui.containers.tabpanel2d method)": [[294, "fury.ui.containers.TabPanel2D.__init__"]], "__init__() (fury.ui.containers.tabui method)": [[294, "fury.ui.containers.TabUI.__init__"]], "__init__() (fury.ui.core.button2d method)": [[294, "fury.ui.core.Button2D.__init__"]], "__init__() (fury.ui.core.disk2d method)": [[294, "fury.ui.core.Disk2D.__init__"]], "__init__() (fury.ui.core.rectangle2d method)": [[294, "fury.ui.core.Rectangle2D.__init__"]], "__init__() (fury.ui.core.textblock2d method)": [[294, "fury.ui.core.TextBlock2D.__init__"]], "__init__() (fury.ui.core.ui method)": [[294, "fury.ui.core.UI.__init__"]], "__init__() (fury.ui.elements.card2d method)": [[294, "fury.ui.elements.Card2D.__init__"]], "__init__() (fury.ui.elements.checkbox method)": [[294, "fury.ui.elements.Checkbox.__init__"]], "__init__() (fury.ui.elements.combobox2d method)": [[294, "fury.ui.elements.ComboBox2D.__init__"]], "__init__() (fury.ui.elements.drawpanel method)": [[294, "fury.ui.elements.DrawPanel.__init__"]], "__init__() (fury.ui.elements.drawshape method)": [[294, "fury.ui.elements.DrawShape.__init__"]], "__init__() (fury.ui.elements.filemenu2d method)": [[294, "fury.ui.elements.FileMenu2D.__init__"]], "__init__() (fury.ui.elements.linedoubleslider2d method)": [[294, "fury.ui.elements.LineDoubleSlider2D.__init__"]], "__init__() (fury.ui.elements.lineslider2d method)": [[294, "fury.ui.elements.LineSlider2D.__init__"]], "__init__() (fury.ui.elements.listbox2d method)": [[294, "fury.ui.elements.ListBox2D.__init__"]], "__init__() (fury.ui.elements.listboxitem2d method)": [[294, "fury.ui.elements.ListBoxItem2D.__init__"]], "__init__() (fury.ui.elements.option method)": [[294, "fury.ui.elements.Option.__init__"]], "__init__() (fury.ui.elements.playbackpanel method)": [[294, "fury.ui.elements.PlaybackPanel.__init__"]], "__init__() (fury.ui.elements.radiobutton method)": [[294, "fury.ui.elements.RadioButton.__init__"]], "__init__() (fury.ui.elements.rangeslider method)": [[294, "fury.ui.elements.RangeSlider.__init__"]], "__init__() (fury.ui.elements.ringslider2d method)": [[294, "fury.ui.elements.RingSlider2D.__init__"]], "__init__() (fury.ui.elements.spinbox method)": [[294, "fury.ui.elements.SpinBox.__init__"]], "__init__() (fury.ui.elements.textbox2d method)": [[294, "fury.ui.elements.TextBox2D.__init__"]], "active_color (fury.ui.elements.linedoubleslider2d attribute)": [[294, "fury.ui.elements.LineDoubleSlider2D.active_color"]], "active_color (fury.ui.elements.lineslider2d attribute)": [[294, "fury.ui.elements.LineSlider2D.active_color"]], "active_color (fury.ui.elements.ringslider2d attribute)": [[294, "fury.ui.elements.RingSlider2D.active_color"]], "actor (fury.ui.core.textblock2d attribute)": [[294, "fury.ui.core.TextBlock2D.actor"]], "actor (fury.ui.elements.textbox2d attribute)": [[294, "fury.ui.elements.TextBox2D.actor"]], "actors (fury.ui.core.ui property)": [[294, "fury.ui.core.UI.actors"]], "add_callback() (fury.ui.core.ui method)": [[294, "fury.ui.core.UI.add_callback"]], "add_character() (fury.ui.elements.textbox2d method)": [[294, "fury.ui.elements.TextBox2D.add_character"]], "add_element() (fury.ui.containers.panel2d method)": [[294, "fury.ui.containers.Panel2D.add_element"]], "add_element() (fury.ui.containers.tabpanel2d method)": [[294, "fury.ui.containers.TabPanel2D.add_element"]], "add_element() (fury.ui.containers.tabui method)": [[294, "fury.ui.containers.TabUI.add_element"]], "add_to_scene() (fury.ui.core.ui method)": [[294, "fury.ui.core.UI.add_to_scene"]], "alignment (fury.ui.containers.panel2d attribute)": [[294, "fury.ui.containers.Panel2D.alignment"]], "angle (fury.ui.elements.ringslider2d property)": [[294, "fury.ui.elements.RingSlider2D.angle"]], "append_item() (fury.ui.elements.combobox2d method)": [[294, "fury.ui.elements.ComboBox2D.append_item"]], "auto_font_scale (fury.ui.core.textblock2d attribute)": [[294, "fury.ui.core.TextBlock2D.auto_font_scale"]], "auto_font_scale (fury.ui.core.textblock2d property)": [[294, "id4"]], "background_color (fury.ui.core.textblock2d property)": [[294, "fury.ui.core.TextBlock2D.background_color"]], "bg_color (fury.ui.core.textblock2d attribute)": [[294, "fury.ui.core.TextBlock2D.bg_color"]], "body (fury.ui.elements.card2d property)": [[294, "fury.ui.elements.Card2D.body"]], "body_box (fury.ui.elements.card2d attribute)": [[294, "fury.ui.elements.Card2D.body_box"]], "bold (fury.ui.core.textblock2d attribute)": [[294, "fury.ui.core.TextBlock2D.bold"]], "bold (fury.ui.core.textblock2d property)": [[294, "id5"]], "border_color (fury.ui.containers.panel2d property)": [[294, "fury.ui.containers.Panel2D.border_color"]], "border_width (fury.ui.containers.panel2d property)": [[294, "fury.ui.containers.Panel2D.border_width"]], "bottom_disk_ratio (fury.ui.elements.linedoubleslider2d property)": [[294, "fury.ui.elements.LineDoubleSlider2D.bottom_disk_ratio"]], "bottom_disk_value (fury.ui.elements.linedoubleslider2d property)": [[294, "fury.ui.elements.LineDoubleSlider2D.bottom_disk_value"]], "bottom_y_position (fury.ui.elements.linedoubleslider2d property)": [[294, "fury.ui.elements.LineDoubleSlider2D.bottom_y_position"]], "bottom_y_position (fury.ui.elements.lineslider2d property)": [[294, "fury.ui.elements.LineSlider2D.bottom_y_position"]], "cal_bounding_box() (fury.ui.elements.drawshape method)": [[294, "fury.ui.elements.DrawShape.cal_bounding_box"]], "cal_bounding_box_2d() (in module fury.ui.helpers)": [[294, "fury.ui.helpers.cal_bounding_box_2d"]], "cal_min_boundary_distance() (fury.ui.elements.drawpanel method)": [[294, "fury.ui.elements.DrawPanel.cal_min_boundary_distance"]], "cal_size_from_message() (fury.ui.core.textblock2d method)": [[294, "fury.ui.core.TextBlock2D.cal_size_from_message"]], "caret_pos (fury.ui.elements.textbox2d attribute)": [[294, "fury.ui.elements.TextBox2D.caret_pos"]], "center (fury.ui.core.ui attribute)": [[294, "fury.ui.core.UI.center"]], "center (fury.ui.core.ui property)": [[294, "id0"]], "center (fury.ui.elements.drawshape property)": [[294, "fury.ui.elements.DrawShape.center"]], "check_overflow() (in module fury.ui.helpers)": [[294, "fury.ui.helpers.check_overflow"]], "clamp_mouse_position() (fury.ui.elements.drawpanel method)": [[294, "fury.ui.elements.DrawPanel.clamp_mouse_position"]], "clamp_position() (fury.ui.elements.drawshape method)": [[294, "fury.ui.elements.DrawShape.clamp_position"]], "clear_selection() (fury.ui.elements.listbox2d method)": [[294, "fury.ui.elements.ListBox2D.clear_selection"]], "clip_overflow() (in module fury.ui.helpers)": [[294, "fury.ui.helpers.clip_overflow"]], "collapse_tab_ui() (fury.ui.containers.tabui method)": [[294, "fury.ui.containers.TabUI.collapse_tab_ui"]], "color (fury.ui.containers.panel2d property)": [[294, "fury.ui.containers.Panel2D.color"]], "color (fury.ui.containers.tabpanel2d property)": [[294, "fury.ui.containers.TabPanel2D.color"]], "color (fury.ui.core.button2d property)": [[294, "fury.ui.core.Button2D.color"]], "color (fury.ui.core.disk2d property)": [[294, "fury.ui.core.Disk2D.color"]], "color (fury.ui.core.rectangle2d property)": [[294, "fury.ui.core.Rectangle2D.color"]], "color (fury.ui.core.textblock2d attribute)": [[294, "fury.ui.core.TextBlock2D.color"]], "color (fury.ui.core.textblock2d property)": [[294, "id6"]], "color (fury.ui.elements.card2d property)": [[294, "fury.ui.elements.Card2D.color"]], "content_panel (fury.ui.containers.tabpanel2d attribute)": [[294, "fury.ui.containers.TabPanel2D.content_panel"]], "coord_to_ratio() (fury.ui.elements.linedoubleslider2d method)": [[294, "fury.ui.elements.LineDoubleSlider2D.coord_to_ratio"]], "current_mode (fury.ui.elements.drawpanel property)": [[294, "fury.ui.elements.DrawPanel.current_mode"]], "current_time (fury.ui.elements.playbackpanel property)": [[294, "fury.ui.elements.PlaybackPanel.current_time"]], "current_time_str (fury.ui.elements.playbackpanel property)": [[294, "fury.ui.elements.PlaybackPanel.current_time_str"]], "decrement() (fury.ui.elements.spinbox method)": [[294, "fury.ui.elements.SpinBox.decrement"]], "decrement_callback() (fury.ui.elements.spinbox method)": [[294, "fury.ui.elements.SpinBox.decrement_callback"]], "default_color (fury.ui.elements.linedoubleslider2d attribute)": [[294, "fury.ui.elements.LineDoubleSlider2D.default_color"]], "default_color (fury.ui.elements.lineslider2d attribute)": [[294, "fury.ui.elements.LineSlider2D.default_color"]], "default_color (fury.ui.elements.ringslider2d attribute)": [[294, "fury.ui.elements.RingSlider2D.default_color"]], "deselect() (fury.ui.elements.listboxitem2d method)": [[294, "fury.ui.elements.ListBoxItem2D.deselect"]], "deselect() (fury.ui.elements.option method)": [[294, "fury.ui.elements.Option.deselect"]], "directory_click_callback() (fury.ui.elements.filemenu2d method)": [[294, "fury.ui.elements.FileMenu2D.directory_click_callback"]], "down_button_callback() (fury.ui.elements.listbox2d method)": [[294, "fury.ui.elements.ListBox2D.down_button_callback"]], "draw_shape() (fury.ui.elements.drawpanel method)": [[294, "fury.ui.elements.DrawPanel.draw_shape"]], "drop_down_button (fury.ui.elements.combobox2d attribute)": [[294, "fury.ui.elements.ComboBox2D.drop_down_button"]], "drop_down_menu (fury.ui.elements.combobox2d attribute)": [[294, "fury.ui.elements.ComboBox2D.drop_down_menu"]], "dynamic_bbox (fury.ui.core.textblock2d attribute)": [[294, "fury.ui.core.TextBlock2D.dynamic_bbox"]], "dynamic_bbox (fury.ui.core.textblock2d property)": [[294, "id7"]], "edit_mode() (fury.ui.elements.textbox2d method)": [[294, "fury.ui.elements.TextBox2D.edit_mode"]], "element (fury.ui.elements.listboxitem2d property)": [[294, "fury.ui.elements.ListBoxItem2D.element"]], "extensions (fury.ui.elements.filemenu2d attribute)": [[294, "fury.ui.elements.FileMenu2D.extensions"]], "final_time (fury.ui.elements.playbackpanel property)": [[294, "fury.ui.elements.PlaybackPanel.final_time"]], "font_family (fury.ui.core.textblock2d attribute)": [[294, "fury.ui.core.TextBlock2D.font_family"]], "font_family (fury.ui.core.textblock2d property)": [[294, "id8"]], "font_size (fury.ui.core.textblock2d attribute)": [[294, "fury.ui.core.TextBlock2D.font_size"]], "font_size (fury.ui.core.textblock2d property)": [[294, "id9"]], "font_size (fury.ui.elements.checkbox property)": [[294, "fury.ui.elements.Checkbox.font_size"]], "font_size (fury.ui.elements.option attribute)": [[294, "fury.ui.elements.Option.font_size"]], "format_text() (fury.ui.elements.linedoubleslider2d method)": [[294, "fury.ui.elements.LineDoubleSlider2D.format_text"]], "format_text() (fury.ui.elements.lineslider2d method)": [[294, "fury.ui.elements.LineSlider2D.format_text"]], "format_text() (fury.ui.elements.ringslider2d method)": [[294, "fury.ui.elements.RingSlider2D.format_text"]], "fury.ui": [[294, "module-fury.ui"]], "fury.ui.containers": [[294, "module-fury.ui.containers"]], "fury.ui.core": [[294, "module-fury.ui.core"]], "fury.ui.elements": [[294, "module-fury.ui.elements"]], "fury.ui.helpers": [[294, "module-fury.ui.helpers"]], "get_all_file_names() (fury.ui.elements.filemenu2d method)": [[294, "fury.ui.elements.FileMenu2D.get_all_file_names"]], "get_directory_names() (fury.ui.elements.filemenu2d method)": [[294, "fury.ui.elements.FileMenu2D.get_directory_names"]], "get_file_names() (fury.ui.elements.filemenu2d method)": [[294, "fury.ui.elements.FileMenu2D.get_file_names"]], "handle (fury.ui.elements.lineslider2d attribute)": [[294, "fury.ui.elements.LineSlider2D.handle"]], "handle (fury.ui.elements.ringslider2d attribute)": [[294, "fury.ui.elements.RingSlider2D.handle"]], "handle_character() (fury.ui.elements.textbox2d method)": [[294, "fury.ui.elements.TextBox2D.handle_character"]], "handle_events() (fury.ui.core.ui method)": [[294, "fury.ui.core.UI.handle_events"]], "handle_mouse_click() (fury.ui.elements.drawpanel method)": [[294, "fury.ui.elements.DrawPanel.handle_mouse_click"]], "handle_mouse_drag() (fury.ui.elements.drawpanel method)": [[294, "fury.ui.elements.DrawPanel.handle_mouse_drag"]], "handle_move_callback() (fury.ui.elements.linedoubleslider2d method)": [[294, "fury.ui.elements.LineDoubleSlider2D.handle_move_callback"]], "handle_move_callback() (fury.ui.elements.lineslider2d method)": [[294, "fury.ui.elements.LineSlider2D.handle_move_callback"]], "handle_move_callback() (fury.ui.elements.ringslider2d method)": [[294, "fury.ui.elements.RingSlider2D.handle_move_callback"]], "handle_release_callback() (fury.ui.elements.linedoubleslider2d method)": [[294, "fury.ui.elements.LineDoubleSlider2D.handle_release_callback"]], "handle_release_callback() (fury.ui.elements.lineslider2d method)": [[294, "fury.ui.elements.LineSlider2D.handle_release_callback"]], "handle_release_callback() (fury.ui.elements.ringslider2d method)": [[294, "fury.ui.elements.RingSlider2D.handle_release_callback"]], "handles (fury.ui.elements.linedoubleslider2d attribute)": [[294, "fury.ui.elements.LineDoubleSlider2D.handles"]], "height (fury.ui.core.rectangle2d property)": [[294, "fury.ui.core.Rectangle2D.height"]], "height (fury.ui.elements.textbox2d attribute)": [[294, "fury.ui.elements.TextBox2D.height"]], "hide() (fury.ui.elements.playbackpanel method)": [[294, "fury.ui.elements.PlaybackPanel.hide"]], "image (fury.ui.elements.card2d attribute)": [[294, "fury.ui.elements.Card2D.image"]], "img (fury.ui.containers.imagecontainer2d attribute)": [[294, "fury.ui.containers.ImageContainer2D.img"]], "increment() (fury.ui.elements.spinbox method)": [[294, "fury.ui.elements.SpinBox.increment"]], "increment_callback() (fury.ui.elements.spinbox method)": [[294, "fury.ui.elements.SpinBox.increment_callback"]], "init (fury.ui.elements.textbox2d attribute)": [[294, "fury.ui.elements.TextBox2D.init"]], "inner_radius (fury.ui.core.disk2d property)": [[294, "fury.ui.core.Disk2D.inner_radius"]], "is_selected (fury.ui.elements.drawshape property)": [[294, "fury.ui.elements.DrawShape.is_selected"]], "italic (fury.ui.core.textblock2d attribute)": [[294, "fury.ui.core.TextBlock2D.italic"]], "italic (fury.ui.core.textblock2d property)": [[294, "id10"]], "justification (fury.ui.core.textblock2d attribute)": [[294, "fury.ui.core.TextBlock2D.justification"]], "justification (fury.ui.core.textblock2d property)": [[294, "id11"]], "key_press() (fury.ui.elements.textbox2d method)": [[294, "fury.ui.elements.TextBox2D.key_press"]], "key_press_callback() (fury.ui.containers.gridui method)": [[294, "fury.ui.containers.GridUI.key_press_callback"]], "key_press_callback() (fury.ui.core.ui static method)": [[294, "fury.ui.core.UI.key_press_callback"]], "label (fury.ui.elements.option attribute)": [[294, "fury.ui.elements.Option.label"]], "labels (fury.ui.elements.checkbox attribute)": [[294, "fury.ui.elements.Checkbox.labels"]], "labels (fury.ui.elements.radiobutton attribute)": [[294, "fury.ui.elements.RadioButton.labels"]], "left_button_click_callback() (fury.ui.core.ui static method)": [[294, "fury.ui.core.UI.left_button_click_callback"]], "left_button_clicked() (fury.ui.elements.listboxitem2d method)": [[294, "fury.ui.elements.ListBoxItem2D.left_button_clicked"]], "left_button_dragged() (fury.ui.containers.panel2d method)": [[294, "fury.ui.containers.Panel2D.left_button_dragged"]], "left_button_dragged() (fury.ui.containers.tabui method)": [[294, "fury.ui.containers.TabUI.left_button_dragged"]], "left_button_dragged() (fury.ui.elements.card2d method)": [[294, "fury.ui.elements.Card2D.left_button_dragged"]], "left_button_dragged() (fury.ui.elements.combobox2d method)": [[294, "fury.ui.elements.ComboBox2D.left_button_dragged"]], "left_button_dragged() (fury.ui.elements.drawpanel method)": [[294, "fury.ui.elements.DrawPanel.left_button_dragged"]], "left_button_dragged() (fury.ui.elements.drawshape method)": [[294, "fury.ui.elements.DrawShape.left_button_dragged"]], "left_button_press() (fury.ui.elements.textbox2d method)": [[294, "fury.ui.elements.TextBox2D.left_button_press"]], "left_button_pressed() (fury.ui.containers.panel2d method)": [[294, "fury.ui.containers.Panel2D.left_button_pressed"]], "left_button_pressed() (fury.ui.containers.tabui method)": [[294, "fury.ui.containers.TabUI.left_button_pressed"]], "left_button_pressed() (fury.ui.elements.card2d method)": [[294, "fury.ui.elements.Card2D.left_button_pressed"]], "left_button_pressed() (fury.ui.elements.combobox2d method)": [[294, "fury.ui.elements.ComboBox2D.left_button_pressed"]], "left_button_pressed() (fury.ui.elements.drawpanel method)": [[294, "fury.ui.elements.DrawPanel.left_button_pressed"]], "left_button_pressed() (fury.ui.elements.drawshape method)": [[294, "fury.ui.elements.DrawShape.left_button_pressed"]], "left_button_release_callback() (fury.ui.core.ui static method)": [[294, "fury.ui.core.UI.left_button_release_callback"]], "left_button_released() (fury.ui.elements.drawshape method)": [[294, "fury.ui.elements.DrawShape.left_button_released"]], "left_click_callback() (fury.ui.containers.gridui static method)": [[294, "fury.ui.containers.GridUI.left_click_callback"]], "left_click_callback2() (fury.ui.containers.gridui static method)": [[294, "fury.ui.containers.GridUI.left_click_callback2"]], "left_disk_ratio (fury.ui.elements.linedoubleslider2d property)": [[294, "fury.ui.elements.LineDoubleSlider2D.left_disk_ratio"]], "left_disk_value (fury.ui.elements.linedoubleslider2d property)": [[294, "fury.ui.elements.LineDoubleSlider2D.left_disk_value"]], "left_move_left() (fury.ui.elements.textbox2d method)": [[294, "fury.ui.elements.TextBox2D.left_move_left"]], "left_move_right() (fury.ui.elements.textbox2d method)": [[294, "fury.ui.elements.TextBox2D.left_move_right"]], "left_release_callback() (fury.ui.containers.gridui static method)": [[294, "fury.ui.containers.GridUI.left_release_callback"]], "left_release_callback2() (fury.ui.containers.gridui static method)": [[294, "fury.ui.containers.GridUI.left_release_callback2"]], "left_x_position (fury.ui.elements.linedoubleslider2d property)": [[294, "fury.ui.elements.LineDoubleSlider2D.left_x_position"]], "left_x_position (fury.ui.elements.lineslider2d property)": [[294, "fury.ui.elements.LineSlider2D.left_x_position"]], "length (fury.ui.elements.linedoubleslider2d attribute)": [[294, "fury.ui.elements.LineDoubleSlider2D.length"]], "length (fury.ui.elements.lineslider2d attribute)": [[294, "fury.ui.elements.LineSlider2D.length"]], "line_width (fury.ui.elements.linedoubleslider2d attribute)": [[294, "fury.ui.elements.LineDoubleSlider2D.line_width"]], "line_width (fury.ui.elements.lineslider2d attribute)": [[294, "fury.ui.elements.LineSlider2D.line_width"]], "listbox (fury.ui.elements.filemenu2d attribute)": [[294, "fury.ui.elements.FileMenu2D.listbox"]], "loop() (fury.ui.elements.playbackpanel method)": [[294, "fury.ui.elements.PlaybackPanel.loop"]], "menu_toggle_callback() (fury.ui.elements.combobox2d method)": [[294, "fury.ui.elements.ComboBox2D.menu_toggle_callback"]], "message (fury.ui.core.textblock2d attribute)": [[294, "fury.ui.core.TextBlock2D.message"]], "message (fury.ui.core.textblock2d property)": [[294, "id12"]], "mid_track_radius (fury.ui.elements.ringslider2d attribute)": [[294, "fury.ui.elements.RingSlider2D.mid_track_radius"]], "mid_track_radius (fury.ui.elements.ringslider2d property)": [[294, "id15"]], "middle_button_click_callback() (fury.ui.core.ui static method)": [[294, "fury.ui.core.UI.middle_button_click_callback"]], "middle_button_release_callback() (fury.ui.core.ui static method)": [[294, "fury.ui.core.UI.middle_button_release_callback"]], "mouse_move_callback() (fury.ui.containers.gridui static method)": [[294, "fury.ui.containers.GridUI.mouse_move_callback"]], "mouse_move_callback() (fury.ui.core.ui static method)": [[294, "fury.ui.core.UI.mouse_move_callback"]], "mouse_move_callback2() (fury.ui.containers.gridui static method)": [[294, "fury.ui.containers.GridUI.mouse_move_callback2"]], "move_caret_left() (fury.ui.elements.textbox2d method)": [[294, "fury.ui.elements.TextBox2D.move_caret_left"]], "move_caret_right() (fury.ui.elements.textbox2d method)": [[294, "fury.ui.elements.TextBox2D.move_caret_right"]], "move_handle() (fury.ui.elements.ringslider2d method)": [[294, "fury.ui.elements.RingSlider2D.move_handle"]], "move_left() (fury.ui.elements.textbox2d method)": [[294, "fury.ui.elements.TextBox2D.move_left"]], "move_right() (fury.ui.elements.textbox2d method)": [[294, "fury.ui.elements.TextBox2D.move_right"]], "next_icon() (fury.ui.core.button2d method)": [[294, "fury.ui.core.Button2D.next_icon"]], "next_icon_id() (fury.ui.core.button2d method)": [[294, "fury.ui.core.Button2D.next_icon_id"]], "on_change (fury.ui.elements.listbox2d attribute)": [[294, "fury.ui.elements.ListBox2D.on_change"]], "on_key_press (fury.ui.core.ui attribute)": [[294, "fury.ui.core.UI.on_key_press"]], "on_left_mouse_button_clicked (fury.ui.core.ui attribute)": [[294, "fury.ui.core.UI.on_left_mouse_button_clicked"]], "on_left_mouse_button_dragged (fury.ui.core.ui attribute)": [[294, "fury.ui.core.UI.on_left_mouse_button_dragged"]], "on_left_mouse_button_pressed (fury.ui.core.ui attribute)": [[294, "fury.ui.core.UI.on_left_mouse_button_pressed"]], "on_left_mouse_button_released (fury.ui.core.ui attribute)": [[294, "fury.ui.core.UI.on_left_mouse_button_released"]], "on_left_mouse_double_clicked (fury.ui.core.ui attribute)": [[294, "fury.ui.core.UI.on_left_mouse_double_clicked"]], "on_middle_mouse_button_clicked (fury.ui.core.ui attribute)": [[294, "fury.ui.core.UI.on_middle_mouse_button_clicked"]], "on_middle_mouse_button_dragged (fury.ui.core.ui attribute)": [[294, "fury.ui.core.UI.on_middle_mouse_button_dragged"]], "on_middle_mouse_button_pressed (fury.ui.core.ui attribute)": [[294, "fury.ui.core.UI.on_middle_mouse_button_pressed"]], "on_middle_mouse_button_released (fury.ui.core.ui attribute)": [[294, "fury.ui.core.UI.on_middle_mouse_button_released"]], "on_middle_mouse_double_clicked (fury.ui.core.ui attribute)": [[294, "fury.ui.core.UI.on_middle_mouse_double_clicked"]], "on_right_mouse_button_clicked (fury.ui.core.ui attribute)": [[294, "fury.ui.core.UI.on_right_mouse_button_clicked"]], "on_right_mouse_button_dragged (fury.ui.core.ui attribute)": [[294, "fury.ui.core.UI.on_right_mouse_button_dragged"]], "on_right_mouse_button_pressed (fury.ui.core.ui attribute)": [[294, "fury.ui.core.UI.on_right_mouse_button_pressed"]], "on_right_mouse_button_released (fury.ui.core.ui attribute)": [[294, "fury.ui.core.UI.on_right_mouse_button_released"]], "on_right_mouse_double_clicked (fury.ui.core.ui attribute)": [[294, "fury.ui.core.UI.on_right_mouse_double_clicked"]], "opacity (fury.ui.containers.panel2d property)": [[294, "fury.ui.containers.Panel2D.opacity"]], "opacity (fury.ui.core.disk2d property)": [[294, "fury.ui.core.Disk2D.opacity"]], "opacity (fury.ui.core.rectangle2d property)": [[294, "fury.ui.core.Rectangle2D.opacity"]], "options (fury.ui.elements.checkbox attribute)": [[294, "fury.ui.elements.Checkbox.options"]], "options (fury.ui.elements.radiobutton attribute)": [[294, "fury.ui.elements.RadioButton.options"]], "outer_radius (fury.ui.core.disk2d property)": [[294, "fury.ui.core.Disk2D.outer_radius"]], "padding (fury.ui.elements.checkbox attribute)": [[294, "fury.ui.elements.Checkbox.padding"]], "padding (fury.ui.elements.checkbox property)": [[294, "id17"]], "padding (fury.ui.elements.radiobutton attribute)": [[294, "fury.ui.elements.RadioButton.padding"]], "pause() (fury.ui.elements.playbackpanel method)": [[294, "fury.ui.elements.PlaybackPanel.pause"]], "play() (fury.ui.elements.playbackpanel method)": [[294, "fury.ui.elements.PlaybackPanel.play"]], "play_once() (fury.ui.elements.playbackpanel method)": [[294, "fury.ui.elements.PlaybackPanel.play_once"]], "position (fury.ui.core.textblock2d attribute)": [[294, "fury.ui.core.TextBlock2D.position"]], "position (fury.ui.core.ui attribute)": [[294, "fury.ui.core.UI.position"]], "position (fury.ui.core.ui property)": [[294, "id2"]], "previous_value (fury.ui.elements.ringslider2d attribute)": [[294, "fury.ui.elements.RingSlider2D.previous_value"]], "previous_value (fury.ui.elements.ringslider2d property)": [[294, "id16"]], "range_slider (fury.ui.elements.rangeslider attribute)": [[294, "fury.ui.elements.RangeSlider.range_slider"]], "range_slider_center (fury.ui.elements.rangeslider attribute)": [[294, "fury.ui.elements.RangeSlider.range_slider_center"]], "range_slider_handle_move_callback() (fury.ui.elements.rangeslider method)": [[294, "fury.ui.elements.RangeSlider.range_slider_handle_move_callback"]], "ratio (fury.ui.elements.lineslider2d property)": [[294, "fury.ui.elements.LineSlider2D.ratio"]], "ratio (fury.ui.elements.ringslider2d property)": [[294, "fury.ui.elements.RingSlider2D.ratio"]], "ratio_to_coord() (fury.ui.elements.linedoubleslider2d method)": [[294, "fury.ui.elements.LineDoubleSlider2D.ratio_to_coord"]], "ratio_to_value() (fury.ui.elements.linedoubleslider2d method)": [[294, "fury.ui.elements.LineDoubleSlider2D.ratio_to_value"]], "re_align() (fury.ui.containers.panel2d method)": [[294, "fury.ui.containers.Panel2D.re_align"]], "remove() (fury.ui.elements.drawshape method)": [[294, "fury.ui.elements.DrawShape.remove"]], "remove_character() (fury.ui.elements.textbox2d method)": [[294, "fury.ui.elements.TextBox2D.remove_character"]], "remove_element() (fury.ui.containers.panel2d method)": [[294, "fury.ui.containers.Panel2D.remove_element"]], "remove_element() (fury.ui.containers.tabpanel2d method)": [[294, "fury.ui.containers.TabPanel2D.remove_element"]], "remove_element() (fury.ui.containers.tabui method)": [[294, "fury.ui.containers.TabUI.remove_element"]], "render_text() (fury.ui.elements.textbox2d method)": [[294, "fury.ui.elements.TextBox2D.render_text"]], "resize() (fury.ui.containers.gridui method)": [[294, "fury.ui.containers.GridUI.resize"]], "resize() (fury.ui.containers.imagecontainer2d method)": [[294, "fury.ui.containers.ImageContainer2D.resize"]], "resize() (fury.ui.containers.panel2d method)": [[294, "fury.ui.containers.Panel2D.resize"]], "resize() (fury.ui.containers.tabpanel2d method)": [[294, "fury.ui.containers.TabPanel2D.resize"]], "resize() (fury.ui.core.button2d method)": [[294, "fury.ui.core.Button2D.resize"]], "resize() (fury.ui.core.rectangle2d method)": [[294, "fury.ui.core.Rectangle2D.resize"]], "resize() (fury.ui.core.textblock2d method)": [[294, "fury.ui.core.TextBlock2D.resize"]], "resize() (fury.ui.elements.card2d method)": [[294, "fury.ui.elements.Card2D.resize"]], "resize() (fury.ui.elements.combobox2d method)": [[294, "fury.ui.elements.ComboBox2D.resize"]], "resize() (fury.ui.elements.drawpanel method)": [[294, "fury.ui.elements.DrawPanel.resize"]], "resize() (fury.ui.elements.drawshape method)": [[294, "fury.ui.elements.DrawShape.resize"]], "resize() (fury.ui.elements.filemenu2d method)": [[294, "fury.ui.elements.FileMenu2D.resize"]], "resize() (fury.ui.elements.listbox2d method)": [[294, "fury.ui.elements.ListBox2D.resize"]], "resize() (fury.ui.elements.listboxitem2d method)": [[294, "fury.ui.elements.ListBoxItem2D.resize"]], "resize() (fury.ui.elements.spinbox method)": [[294, "fury.ui.elements.SpinBox.resize"]], "resize_shape() (fury.ui.elements.drawpanel method)": [[294, "fury.ui.elements.DrawPanel.resize_shape"]], "right_button_click_callback() (fury.ui.core.ui static method)": [[294, "fury.ui.core.UI.right_button_click_callback"]], "right_button_release_callback() (fury.ui.core.ui static method)": [[294, "fury.ui.core.UI.right_button_release_callback"]], "right_disk_ratio (fury.ui.elements.linedoubleslider2d property)": [[294, "fury.ui.elements.LineDoubleSlider2D.right_disk_ratio"]], "right_disk_value (fury.ui.elements.linedoubleslider2d property)": [[294, "fury.ui.elements.LineDoubleSlider2D.right_disk_value"]], "right_move_left() (fury.ui.elements.textbox2d method)": [[294, "fury.ui.elements.TextBox2D.right_move_left"]], "right_move_right() (fury.ui.elements.textbox2d method)": [[294, "fury.ui.elements.TextBox2D.right_move_right"]], "right_x_position (fury.ui.elements.linedoubleslider2d property)": [[294, "fury.ui.elements.LineDoubleSlider2D.right_x_position"]], "right_x_position (fury.ui.elements.lineslider2d property)": [[294, "fury.ui.elements.LineSlider2D.right_x_position"]], "rotate() (fury.ui.elements.drawshape method)": [[294, "fury.ui.elements.DrawShape.rotate"]], "rotate_2d() (in module fury.ui.helpers)": [[294, "fury.ui.helpers.rotate_2d"]], "scale() (fury.ui.containers.imagecontainer2d method)": [[294, "fury.ui.containers.ImageContainer2D.scale"]], "scale() (fury.ui.core.button2d method)": [[294, "fury.ui.core.Button2D.scale"]], "scroll_callback() (fury.ui.elements.filemenu2d method)": [[294, "fury.ui.elements.FileMenu2D.scroll_callback"]], "scroll_click_callback() (fury.ui.elements.listbox2d method)": [[294, "fury.ui.elements.ListBox2D.scroll_click_callback"]], "scroll_drag_callback() (fury.ui.elements.listbox2d method)": [[294, "fury.ui.elements.ListBox2D.scroll_drag_callback"]], "scroll_release_callback() (fury.ui.elements.listbox2d method)": [[294, "fury.ui.elements.ListBox2D.scroll_release_callback"]], "select() (fury.ui.elements.listbox2d method)": [[294, "fury.ui.elements.ListBox2D.select"]], "select() (fury.ui.elements.listboxitem2d method)": [[294, "fury.ui.elements.ListBoxItem2D.select"]], "select() (fury.ui.elements.option method)": [[294, "fury.ui.elements.Option.select"]], "select_option_callback() (fury.ui.elements.combobox2d method)": [[294, "fury.ui.elements.ComboBox2D.select_option_callback"]], "select_tab_callback() (fury.ui.containers.tabui method)": [[294, "fury.ui.containers.TabUI.select_tab_callback"]], "selected_text (fury.ui.elements.combobox2d property)": [[294, "fury.ui.elements.ComboBox2D.selected_text"]], "selected_text_index (fury.ui.elements.combobox2d property)": [[294, "fury.ui.elements.ComboBox2D.selected_text_index"]], "selection_box (fury.ui.elements.combobox2d attribute)": [[294, "fury.ui.elements.ComboBox2D.selection_box"]], "selection_change() (fury.ui.elements.drawshape method)": [[294, "fury.ui.elements.DrawShape.selection_change"]], "set_icon() (fury.ui.core.button2d method)": [[294, "fury.ui.core.Button2D.set_icon"]], "set_icon_by_name() (fury.ui.core.button2d method)": [[294, "fury.ui.core.Button2D.set_icon_by_name"]], "set_img() (fury.ui.containers.imagecontainer2d method)": [[294, "fury.ui.containers.ImageContainer2D.set_img"]], "set_message() (fury.ui.elements.textbox2d method)": [[294, "fury.ui.elements.TextBox2D.set_message"]], "set_position() (fury.ui.elements.linedoubleslider2d method)": [[294, "fury.ui.elements.LineDoubleSlider2D.set_position"]], "set_position() (fury.ui.elements.lineslider2d method)": [[294, "fury.ui.elements.LineSlider2D.set_position"]], "set_slot_colors() (fury.ui.elements.filemenu2d method)": [[294, "fury.ui.elements.FileMenu2D.set_slot_colors"]], "set_visibility() (fury.ui.containers.panel2d method)": [[294, "fury.ui.containers.Panel2D.set_visibility"]], "set_visibility() (fury.ui.core.ui method)": [[294, "fury.ui.core.UI.set_visibility"]], "set_visibility() (fury.ui.elements.combobox2d method)": [[294, "fury.ui.elements.ComboBox2D.set_visibility"]], "shadow (fury.ui.core.textblock2d attribute)": [[294, "fury.ui.core.TextBlock2D.shadow"]], "shadow (fury.ui.core.textblock2d property)": [[294, "id13"]], "shape (fury.ui.elements.linedoubleslider2d attribute)": [[294, "fury.ui.elements.LineDoubleSlider2D.shape"]], "shape (fury.ui.elements.lineslider2d attribute)": [[294, "fury.ui.elements.LineSlider2D.shape"]], "show() (fury.ui.elements.playbackpanel method)": [[294, "fury.ui.elements.PlaybackPanel.show"]], "show_rotation_slider() (fury.ui.elements.drawpanel method)": [[294, "fury.ui.elements.DrawPanel.show_rotation_slider"]], "showable_text() (fury.ui.elements.textbox2d method)": [[294, "fury.ui.elements.TextBox2D.showable_text"]], "size (fury.ui.containers.imagecontainer2d attribute)": [[294, "fury.ui.containers.ImageContainer2D.size"]], "size (fury.ui.core.textblock2d attribute)": [[294, "fury.ui.core.TextBlock2D.size"]], "size (fury.ui.core.ui attribute)": [[294, "fury.ui.core.UI.size"]], "size (fury.ui.core.ui property)": [[294, "id3"]], "speed (fury.ui.elements.playbackpanel property)": [[294, "fury.ui.elements.PlaybackPanel.speed"]], "stop() (fury.ui.elements.playbackpanel method)": [[294, "fury.ui.elements.PlaybackPanel.stop"]], "tabs (fury.ui.containers.tabui attribute)": [[294, "fury.ui.containers.TabUI.tabs"]], "text (fury.ui.elements.linedoubleslider2d attribute)": [[294, "fury.ui.elements.LineDoubleSlider2D.text"]], "text (fury.ui.elements.lineslider2d attribute)": [[294, "fury.ui.elements.LineSlider2D.text"]], "text (fury.ui.elements.ringslider2d attribute)": [[294, "fury.ui.elements.RingSlider2D.text"]], "text (fury.ui.elements.textbox2d attribute)": [[294, "fury.ui.elements.TextBox2D.text"]], "text_block (fury.ui.containers.tabpanel2d attribute)": [[294, "fury.ui.containers.TabPanel2D.text_block"]], "textbox_update_value() (fury.ui.elements.spinbox method)": [[294, "fury.ui.elements.SpinBox.textbox_update_value"]], "title (fury.ui.containers.tabpanel2d property)": [[294, "fury.ui.containers.TabPanel2D.title"]], "title (fury.ui.elements.card2d property)": [[294, "fury.ui.elements.Card2D.title"]], "title_bold (fury.ui.containers.tabpanel2d property)": [[294, "fury.ui.containers.TabPanel2D.title_bold"]], "title_box (fury.ui.elements.card2d attribute)": [[294, "fury.ui.elements.Card2D.title_box"]], "title_color (fury.ui.containers.tabpanel2d property)": [[294, "fury.ui.containers.TabPanel2D.title_color"]], "title_font_size (fury.ui.containers.tabpanel2d property)": [[294, "fury.ui.containers.TabPanel2D.title_font_size"]], "title_italic (fury.ui.containers.tabpanel2d property)": [[294, "fury.ui.containers.TabPanel2D.title_italic"]], "toggle() (fury.ui.elements.option method)": [[294, "fury.ui.elements.Option.toggle"]], "top_disk_ratio (fury.ui.elements.linedoubleslider2d property)": [[294, "fury.ui.elements.LineDoubleSlider2D.top_disk_ratio"]], "top_disk_value (fury.ui.elements.linedoubleslider2d property)": [[294, "fury.ui.elements.LineDoubleSlider2D.top_disk_value"]], "top_y_position (fury.ui.elements.linedoubleslider2d property)": [[294, "fury.ui.elements.LineDoubleSlider2D.top_y_position"]], "top_y_position (fury.ui.elements.lineslider2d property)": [[294, "fury.ui.elements.LineSlider2D.top_y_position"]], "track (fury.ui.elements.linedoubleslider2d attribute)": [[294, "fury.ui.elements.LineDoubleSlider2D.track"]], "track (fury.ui.elements.lineslider2d attribute)": [[294, "fury.ui.elements.LineSlider2D.track"]], "track (fury.ui.elements.ringslider2d attribute)": [[294, "fury.ui.elements.RingSlider2D.track"]], "track_click_callback() (fury.ui.elements.lineslider2d method)": [[294, "fury.ui.elements.LineSlider2D.track_click_callback"]], "track_click_callback() (fury.ui.elements.ringslider2d method)": [[294, "fury.ui.elements.RingSlider2D.track_click_callback"]], "up_button_callback() (fury.ui.elements.listbox2d method)": [[294, "fury.ui.elements.ListBox2D.up_button_callback"]], "update() (fury.ui.elements.linedoubleslider2d method)": [[294, "fury.ui.elements.LineDoubleSlider2D.update"]], "update() (fury.ui.elements.lineslider2d method)": [[294, "fury.ui.elements.LineSlider2D.update"]], "update() (fury.ui.elements.listbox2d method)": [[294, "fury.ui.elements.ListBox2D.update"]], "update() (fury.ui.elements.ringslider2d method)": [[294, "fury.ui.elements.RingSlider2D.update"]], "update_alignment() (fury.ui.core.textblock2d method)": [[294, "fury.ui.core.TextBlock2D.update_alignment"]], "update_border_coords() (fury.ui.containers.panel2d method)": [[294, "fury.ui.containers.Panel2D.update_border_coords"]], "update_bounding_box() (fury.ui.core.textblock2d method)": [[294, "fury.ui.core.TextBlock2D.update_bounding_box"]], "update_button_icons() (fury.ui.elements.drawpanel method)": [[294, "fury.ui.elements.DrawPanel.update_button_icons"]], "update_element() (fury.ui.containers.panel2d method)": [[294, "fury.ui.containers.Panel2D.update_element"]], "update_element() (fury.ui.containers.tabpanel2d method)": [[294, "fury.ui.containers.TabPanel2D.update_element"]], "update_element() (fury.ui.containers.tabui method)": [[294, "fury.ui.containers.TabUI.update_element"]], "update_scrollbar() (fury.ui.elements.listbox2d method)": [[294, "fury.ui.elements.ListBox2D.update_scrollbar"]], "update_shape_position() (fury.ui.elements.drawshape method)": [[294, "fury.ui.elements.DrawShape.update_shape_position"]], "update_shape_selection() (fury.ui.elements.drawpanel method)": [[294, "fury.ui.elements.DrawPanel.update_shape_selection"]], "update_tabs() (fury.ui.containers.tabui method)": [[294, "fury.ui.containers.TabUI.update_tabs"]], "validate_value() (fury.ui.elements.spinbox method)": [[294, "fury.ui.elements.SpinBox.validate_value"]], "value (fury.ui.elements.lineslider2d property)": [[294, "fury.ui.elements.LineSlider2D.value"]], "value (fury.ui.elements.ringslider2d property)": [[294, "fury.ui.elements.RingSlider2D.value"]], "value (fury.ui.elements.spinbox property)": [[294, "fury.ui.elements.SpinBox.value"]], "value_slider (fury.ui.elements.rangeslider attribute)": [[294, "fury.ui.elements.RangeSlider.value_slider"]], "value_slider_center (fury.ui.elements.rangeslider attribute)": [[294, "fury.ui.elements.RangeSlider.value_slider_center"]], "value_to_ratio() (fury.ui.elements.linedoubleslider2d method)": [[294, "fury.ui.elements.LineDoubleSlider2D.value_to_ratio"]], "vertical_justification (fury.ui.core.textblock2d attribute)": [[294, "fury.ui.core.TextBlock2D.vertical_justification"]], "vertical_justification (fury.ui.core.textblock2d property)": [[294, "id14"]], "width (fury.ui.core.rectangle2d property)": [[294, "fury.ui.core.Rectangle2D.width"]], "width (fury.ui.elements.playbackpanel property)": [[294, "fury.ui.elements.PlaybackPanel.width"]], "width (fury.ui.elements.textbox2d attribute)": [[294, "fury.ui.elements.TextBox2D.width"]], "width_set_text() (fury.ui.elements.textbox2d method)": [[294, "fury.ui.elements.TextBox2D.width_set_text"]], "window_left (fury.ui.elements.textbox2d attribute)": [[294, "fury.ui.elements.TextBox2D.window_left"]], "window_right (fury.ui.elements.textbox2d attribute)": [[294, "fury.ui.elements.TextBox2D.window_right"]], "wrap_overflow() (in module fury.ui.helpers)": [[294, "fury.ui.helpers.wrap_overflow"]], "add_polydata_numeric_field() (in module fury.utils)": [[295, "fury.utils.add_polydata_numeric_field"]], "apply_affine() (in module fury.utils)": [[295, "fury.utils.apply_affine"]], "apply_affine_to_actor() (in module fury.utils)": [[295, "fury.utils.apply_affine_to_actor"]], "array_from_actor() (in module fury.utils)": [[295, "fury.utils.array_from_actor"]], "asbytes() (in module fury.utils)": [[295, "fury.utils.asbytes"]], "change_vertices_order() (in module fury.utils)": [[295, "fury.utils.change_vertices_order"]], "color_check() (in module fury.utils)": [[295, "fury.utils.color_check"]], "colors_from_actor() (in module fury.utils)": [[295, "fury.utils.colors_from_actor"]], "compute_bounds() (in module fury.utils)": [[295, "fury.utils.compute_bounds"]], "fix_winding_order() (in module fury.utils)": [[295, "fury.utils.fix_winding_order"]], "fury.utils": [[295, "module-fury.utils"]], "get_actor_from_polydata() (in module fury.utils)": [[295, "fury.utils.get_actor_from_polydata"]], "get_actor_from_polymapper() (in module fury.utils)": [[295, "fury.utils.get_actor_from_polymapper"]], "get_actor_from_primitive() (in module fury.utils)": [[295, "fury.utils.get_actor_from_primitive"]], "get_bounding_box_sizes() (in module fury.utils)": [[295, "fury.utils.get_bounding_box_sizes"]], "get_bounds() (in module fury.utils)": [[295, "fury.utils.get_bounds"]], "get_grid_cells_position() (in module fury.utils)": [[295, "fury.utils.get_grid_cells_position"]], "get_polydata_colors() (in module fury.utils)": [[295, "fury.utils.get_polydata_colors"]], "get_polydata_field() (in module fury.utils)": [[295, "fury.utils.get_polydata_field"]], "get_polydata_lines() (in module fury.utils)": [[295, "fury.utils.get_polydata_lines"]], "get_polydata_normals() (in module fury.utils)": [[295, "fury.utils.get_polydata_normals"]], "get_polydata_primitives_count() (in module fury.utils)": [[295, "fury.utils.get_polydata_primitives_count"]], "get_polydata_tangents() (in module fury.utils)": [[295, "fury.utils.get_polydata_tangents"]], "get_polydata_tcoord() (in module fury.utils)": [[295, "fury.utils.get_polydata_tcoord"]], "get_polydata_triangles() (in module fury.utils)": [[295, "fury.utils.get_polydata_triangles"]], "get_polydata_vertices() (in module fury.utils)": [[295, "fury.utils.get_polydata_vertices"]], "get_polymapper_from_polydata() (in module fury.utils)": [[295, "fury.utils.get_polymapper_from_polydata"]], "is_ui() (in module fury.utils)": [[295, "fury.utils.is_ui"]], "lines_to_vtk_polydata() (in module fury.utils)": [[295, "fury.utils.lines_to_vtk_polydata"]], "map_coordinates_3d_4d() (in module fury.utils)": [[295, "fury.utils.map_coordinates_3d_4d"]], "normalize_v3() (in module fury.utils)": [[295, "fury.utils.normalize_v3"]], "normals_from_actor() (in module fury.utils)": [[295, "fury.utils.normals_from_actor"]], "normals_from_v_f() (in module fury.utils)": [[295, "fury.utils.normals_from_v_f"]], "normals_to_actor() (in module fury.utils)": [[295, "fury.utils.normals_to_actor"]], "numpy_to_vtk_cells() (in module fury.utils)": [[295, "fury.utils.numpy_to_vtk_cells"]], "numpy_to_vtk_colors() (in module fury.utils)": [[295, "fury.utils.numpy_to_vtk_colors"]], "numpy_to_vtk_image_data() (in module fury.utils)": [[295, "fury.utils.numpy_to_vtk_image_data"]], "numpy_to_vtk_matrix() (in module fury.utils)": [[295, "fury.utils.numpy_to_vtk_matrix"]], "numpy_to_vtk_points() (in module fury.utils)": [[295, "fury.utils.numpy_to_vtk_points"]], "primitives_count_from_actor() (in module fury.utils)": [[295, "fury.utils.primitives_count_from_actor"]], "primitives_count_to_actor() (in module fury.utils)": [[295, "fury.utils.primitives_count_to_actor"]], "remove_observer_from_actor() (in module fury.utils)": [[295, "fury.utils.remove_observer_from_actor"]], "repeat_sources() (in module fury.utils)": [[295, "fury.utils.repeat_sources"]], "represent_actor_as_wireframe() (in module fury.utils)": [[295, "fury.utils.represent_actor_as_wireframe"]], "rgb_to_vtk() (in module fury.utils)": [[295, "fury.utils.rgb_to_vtk"]], "rotate() (in module fury.utils)": [[295, "fury.utils.rotate"]], "set_actor_origin() (in module fury.utils)": [[295, "fury.utils.set_actor_origin"]], "set_input() (in module fury.utils)": [[295, "fury.utils.set_input"]], "set_polydata_colors() (in module fury.utils)": [[295, "fury.utils.set_polydata_colors"]], "set_polydata_normals() (in module fury.utils)": [[295, "fury.utils.set_polydata_normals"]], "set_polydata_primitives_count() (in module fury.utils)": [[295, "fury.utils.set_polydata_primitives_count"]], "set_polydata_tangents() (in module fury.utils)": [[295, "fury.utils.set_polydata_tangents"]], "set_polydata_tcoords() (in module fury.utils)": [[295, "fury.utils.set_polydata_tcoords"]], "set_polydata_triangles() (in module fury.utils)": [[295, "fury.utils.set_polydata_triangles"]], "set_polydata_vertices() (in module fury.utils)": [[295, "fury.utils.set_polydata_vertices"]], "shallow_copy() (in module fury.utils)": [[295, "fury.utils.shallow_copy"]], "tangents_from_actor() (in module fury.utils)": [[295, "fury.utils.tangents_from_actor"]], "tangents_from_direction_of_anisotropy() (in module fury.utils)": [[295, "fury.utils.tangents_from_direction_of_anisotropy"]], "tangents_to_actor() (in module fury.utils)": [[295, "fury.utils.tangents_to_actor"]], "triangle_order() (in module fury.utils)": [[295, "fury.utils.triangle_order"]], "update_actor() (in module fury.utils)": [[295, "fury.utils.update_actor"]], "update_polydata_normals() (in module fury.utils)": [[295, "fury.utils.update_polydata_normals"]], "update_surface_actor_colors() (in module fury.utils)": [[295, "fury.utils.update_surface_actor_colors"]], "vertices_from_actor() (in module fury.utils)": [[295, "fury.utils.vertices_from_actor"]], "vtk_matrix_to_numpy() (in module fury.utils)": [[295, "fury.utils.vtk_matrix_to_numpy"]], "scene (class in fury.window)": [[296, "fury.window.Scene"]], "showmanager (class in fury.window)": [[296, "fury.window.ShowManager"]], "__init__() (fury.window.scene method)": [[296, "fury.window.Scene.__init__"]], "__init__() (fury.window.showmanager method)": [[296, "fury.window.ShowManager.__init__"]], "add() (fury.window.scene method)": [[296, "fury.window.Scene.add"]], "add_animation() (fury.window.showmanager method)": [[296, "fury.window.ShowManager.add_animation"]], "add_iren_callback() (fury.window.showmanager method)": [[296, "fury.window.ShowManager.add_iren_callback"]], "add_timer_callback() (fury.window.showmanager method)": [[296, "fury.window.ShowManager.add_timer_callback"]], "add_window_callback() (fury.window.showmanager method)": [[296, "fury.window.ShowManager.add_window_callback"]], "analyze_scene() (in module fury.window)": [[296, "fury.window.analyze_scene"]], "analyze_snapshot() (in module fury.window)": [[296, "fury.window.analyze_snapshot"]], "animations (fury.window.showmanager property)": [[296, "fury.window.ShowManager.animations"]], "antialiasing() (in module fury.window)": [[296, "fury.window.antialiasing"]], "azimuth() (fury.window.scene method)": [[296, "fury.window.Scene.azimuth"]], "background() (fury.window.scene method)": [[296, "fury.window.Scene.background"]], "camera() (fury.window.scene method)": [[296, "fury.window.Scene.camera"]], "camera_direction() (fury.window.scene method)": [[296, "fury.window.Scene.camera_direction"]], "camera_info() (fury.window.scene method)": [[296, "fury.window.Scene.camera_info"]], "clear() (fury.window.scene method)": [[296, "fury.window.Scene.clear"]], "destroy_timer() (fury.window.showmanager method)": [[296, "fury.window.ShowManager.destroy_timer"]], "destroy_timers() (fury.window.showmanager method)": [[296, "fury.window.ShowManager.destroy_timers"]], "dolly() (fury.window.scene method)": [[296, "fury.window.Scene.dolly"]], "elevation() (fury.window.scene method)": [[296, "fury.window.Scene.elevation"]], "enable_stereo() (in module fury.window)": [[296, "fury.window.enable_stereo"]], "exit() (fury.window.showmanager method)": [[296, "fury.window.ShowManager.exit"]], "frame_rate (fury.window.showmanager property)": [[296, "fury.window.ShowManager.frame_rate"]], "fury.window": [[296, "module-fury.window"]], "fxaa_off() (fury.window.scene method)": [[296, "fury.window.Scene.fxaa_off"]], "fxaa_on() (fury.window.scene method)": [[296, "fury.window.Scene.fxaa_on"]], "get_camera() (fury.window.scene method)": [[296, "fury.window.Scene.get_camera"]], "gl_disable_blend() (in module fury.window)": [[296, "fury.window.gl_disable_blend"]], "gl_disable_depth() (in module fury.window)": [[296, "fury.window.gl_disable_depth"]], "gl_enable_blend() (in module fury.window)": [[296, "fury.window.gl_enable_blend"]], "gl_enable_depth() (in module fury.window)": [[296, "fury.window.gl_enable_depth"]], "gl_get_current_state() (in module fury.window)": [[296, "fury.window.gl_get_current_state"]], "gl_reset_blend() (in module fury.window)": [[296, "fury.window.gl_reset_blend"]], "gl_set_additive_blending() (in module fury.window)": [[296, "fury.window.gl_set_additive_blending"]], "gl_set_additive_blending_white_background() (in module fury.window)": [[296, "fury.window.gl_set_additive_blending_white_background"]], "gl_set_multiplicative_blending() (in module fury.window)": [[296, "fury.window.gl_set_multiplicative_blending"]], "gl_set_normal_blending() (in module fury.window)": [[296, "fury.window.gl_set_normal_blending"]], "gl_set_subtractive_blending() (in module fury.window)": [[296, "fury.window.gl_set_subtractive_blending"]], "initialize() (fury.window.showmanager method)": [[296, "fury.window.ShowManager.initialize"]], "iren (fury.window.showmanager attribute)": [[296, "fury.window.ShowManager.iren"]], "is_done() (fury.window.showmanager method)": [[296, "fury.window.ShowManager.is_done"]], "last_render_time (fury.window.scene property)": [[296, "fury.window.Scene.last_render_time"]], "lock() (fury.window.showmanager method)": [[296, "fury.window.ShowManager.lock"]], "lock_current() (fury.window.showmanager method)": [[296, "fury.window.ShowManager.lock_current"]], "pitch() (fury.window.scene method)": [[296, "fury.window.Scene.pitch"]], "play_events() (fury.window.showmanager method)": [[296, "fury.window.ShowManager.play_events"]], "play_events_from_file() (fury.window.showmanager method)": [[296, "fury.window.ShowManager.play_events_from_file"]], "projection() (fury.window.scene method)": [[296, "fury.window.Scene.projection"]], "record() (in module fury.window)": [[296, "fury.window.record"]], "record_events() (fury.window.showmanager method)": [[296, "fury.window.ShowManager.record_events"]], "record_events_to_file() (fury.window.showmanager method)": [[296, "fury.window.ShowManager.record_events_to_file"]], "release_context() (in module fury.window)": [[296, "fury.window.release_context"]], "release_current() (fury.window.showmanager method)": [[296, "fury.window.ShowManager.release_current"]], "release_lock() (fury.window.showmanager method)": [[296, "fury.window.ShowManager.release_lock"]], "remove_animation() (fury.window.showmanager method)": [[296, "fury.window.ShowManager.remove_animation"]], "render() (fury.window.showmanager method)": [[296, "fury.window.ShowManager.render"]], "reset_camera() (fury.window.scene method)": [[296, "fury.window.Scene.reset_camera"]], "reset_camera_tight() (fury.window.scene method)": [[296, "fury.window.Scene.reset_camera_tight"]], "reset_clipping_range() (fury.window.scene method)": [[296, "fury.window.Scene.reset_clipping_range"]], "rm() (fury.window.scene method)": [[296, "fury.window.Scene.rm"]], "rm_all() (fury.window.scene method)": [[296, "fury.window.Scene.rm_all"]], "roll() (fury.window.scene method)": [[296, "fury.window.Scene.roll"]], "save_screenshot() (fury.window.showmanager method)": [[296, "fury.window.ShowManager.save_screenshot"]], "scene (fury.window.showmanager attribute)": [[296, "fury.window.ShowManager.scene"]], "set_camera() (fury.window.scene method)": [[296, "fury.window.Scene.set_camera"]], "show() (in module fury.window)": [[296, "fury.window.show"]], "size() (fury.window.scene method)": [[296, "fury.window.Scene.size"]], "skybox() (fury.window.scene method)": [[296, "fury.window.Scene.skybox"]], "snapshot() (in module fury.window)": [[296, "fury.window.snapshot"]], "start() (fury.window.showmanager method)": [[296, "fury.window.ShowManager.start"]], "style (fury.window.showmanager attribute)": [[296, "fury.window.ShowManager.style"]], "timelines (fury.window.showmanager property)": [[296, "fury.window.ShowManager.timelines"]], "wait() (fury.window.showmanager method)": [[296, "fury.window.ShowManager.wait"]], "window (fury.window.showmanager attribute)": [[296, "fury.window.ShowManager.window"]], "yaw() (fury.window.scene method)": [[296, "fury.window.Scene.yaw"]], "zoom() (fury.window.scene method)": [[296, "fury.window.Scene.zoom"]]}}) \ No newline at end of file diff --git a/v0.10.x/sg_execution_times.html b/v0.10.x/sg_execution_times.html new file mode 100644 index 000000000..97ce4b3a2 --- /dev/null +++ b/v0.10.x/sg_execution_times.html @@ -0,0 +1,796 @@ + + + + + + + + Computation times — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Computation times#

+

00:00.591 total execution time for 76 files from all galleries:

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Example

Time

Mem (MB)

Chain Simulation (../examples_revamped/17_pybullet/viz_chain.py)

00:00.591

0.0

Fury Arrow Actor (../examples_revamped/01_introductory/viz_arrow.py)

00:00.000

0.0

Fury Cone Actor (../examples_revamped/01_introductory/viz_cone.py)

00:00.000

0.0

Texture Sphere Animation (../examples_revamped/01_introductory/viz_earth_animation.py)

00:00.000

0.0

Earth Coordinate Conversion (../examples_revamped/01_introductory/viz_earth_coordinates.py)

00:00.000

0.0

Visualizing a glTF file (../examples_revamped/01_introductory/viz_gltf.py)

00:00.000

0.0

Visualizing a glTF file (../examples_revamped/01_introductory/viz_gltf_animated.py)

00:00.000

0.0

Exporting scene as a glTF file (../examples_revamped/01_introductory/viz_gltf_export.py)

00:00.000

0.0

Morphing Animation in a glTF (../examples_revamped/01_introductory/viz_morphing.py)

00:00.000

0.0

Multithreading Example (../examples_revamped/01_introductory/viz_multithread.py)

00:00.000

0.0

Simple picking (../examples_revamped/01_introductory/viz_picking.py)

00:00.000

0.0

Selecting multiple objects (../examples_revamped/01_introductory/viz_selection.py)

00:00.000

0.0

Skeletal Animation in a glTF file (../examples_revamped/01_introductory/viz_skinning.py)

00:00.000

0.0

Simple volume slicing (../examples_revamped/01_introductory/viz_slice.py)

00:00.000

0.0

Solar System Animation (../examples_revamped/01_introductory/viz_solar_system.py)

00:00.000

0.0

FURY sphere Actor (../examples_revamped/01_introductory/viz_sphere.py)

00:00.000

0.0

Spiky Sphere (../examples_revamped/01_introductory/viz_spiky.py)

00:00.000

0.0

Visualize surfaces (../examples_revamped/01_introductory/viz_surfaces.py)

00:00.000

0.0

Sphere Texture (../examples_revamped/01_introductory/viz_texture.py)

00:00.000

0.0

Using a timer (../examples_revamped/01_introductory/viz_timers.py)

00:00.000

0.0

Collisions of particles in a box (../examples_revamped/04_demos/collision-particles.py)

00:00.000

0.0

Advanced interactive visualization (../examples_revamped/04_demos/viz_advanced.py)

00:00.000

0.0

Animated 2D functions (../examples_revamped/04_demos/viz_animated_surfaces.py)

00:00.000

0.0

Brownian motion (../examples_revamped/04_demos/viz_brownian_motion.py)

00:00.000

0.0

Visualize bundles and metrics on bundles (../examples_revamped/04_demos/viz_bundles.py)

00:00.000

0.0

Display Tensor Ellipsoids for DTI using tensor_slicer vs ellipsoid actor (../examples_revamped/04_demos/viz_dt_ellipsoids.py)

00:00.000

0.0

Electromagnetic Wave Propagation Animation (../examples_revamped/04_demos/viz_emwave_animation.py)

00:00.000

0.0

Brain Fiber ODF Visualisation (../examples_revamped/04_demos/viz_fiber_odf.py)

00:00.000

0.0

Fine-tuning the OpenGL state using shader callbacks (../examples_revamped/04_demos/viz_fine_tuning_gl_context.py)

00:00.000

0.0

Fractals (../examples_revamped/04_demos/viz_fractals.py)

00:00.000

0.0

Motion of a charged particle in a combined magnetic and electric field (../examples_revamped/04_demos/viz_helical_motion.py)

00:00.000

0.0

Fury Markers (../examples_revamped/04_demos/viz_markers.py)

00:00.000

0.0

Visualize Interdisciplinary map of the journals network (../examples_revamped/04_demos/viz_network.py)

00:00.000

0.0

Visualize Networks (Animated version) (../examples_revamped/04_demos/viz_network_animated.py)

00:00.000

0.0

Interactive PBR demo (../examples_revamped/04_demos/viz_pbr_interactive.py)

00:00.000

0.0

Play a video in the 3D world (../examples_revamped/04_demos/viz_play_video.py)

00:00.000

0.0

Visualization of ROI Surface Rendered with Streamlines (../examples_revamped/04_demos/viz_roi_contour.py)

00:00.000

0.0

Tesseract (Hypercube) (../examples_revamped/04_demos/viz_tesseract.py)

00:00.000

0.0

Buttons & Text (../examples_revamped/07_ui/viz_buttons.py)

00:00.000

0.0

Card (../examples_revamped/07_ui/viz_card.py)

00:00.000

0.0

Card (../examples_revamped/07_ui/viz_card_sprite_sheet.py)

00:00.000

0.0

Figure and Color Control using Check boxes and Radio Buttons (../examples_revamped/07_ui/viz_check_boxes.py)

00:00.000

0.0

ComboBox (../examples_revamped/07_ui/viz_combobox.py)

00:00.000

0.0

DrawPanel (../examples_revamped/07_ui/viz_drawpanel.py)

00:00.000

0.0

Using Layouts with different UI elements (../examples_revamped/07_ui/viz_layout.py)

00:00.000

0.0

Sphere Color Control using Radio Buttons (../examples_revamped/07_ui/viz_radio_buttons.py)

00:00.000

0.0

Simple Shapes (../examples_revamped/07_ui/viz_shapes.py)

00:00.000

0.0

SpinBox UI (../examples_revamped/07_ui/viz_spinbox.py)

00:00.000

0.0

Tab UI (../examples_revamped/07_ui/viz_tab.py)

00:00.000

0.0

User Interfaces (../examples_revamped/07_ui/viz_ui.py)

00:00.000

0.0

ListBox (../examples_revamped/07_ui/viz_ui_listbox.py)

00:00.000

0.0

Cube & Slider Control (../examples_revamped/07_ui/viz_ui_slider.py)

00:00.000

0.0

Bezier Interpolator (../examples_revamped/10_animation/viz_bezier_interpolator.py)

00:00.000

0.0

Keyframe animation: Camera and opacity (../examples_revamped/10_animation/viz_camera.py)

00:00.000

0.0

Keyframe Color Interpolators (../examples_revamped/10_animation/viz_color_interpolators.py)

00:00.000

0.0

Making a custom interpolator (../examples_revamped/10_animation/viz_custom_interpolator.py)

00:00.000

0.0

Keyframe hierarchical Animation (../examples_revamped/10_animation/viz_hierarchical_animation.py)

00:00.000

0.0

Keyframe animation (../examples_revamped/10_animation/viz_interpolators.py)

00:00.000

0.0

Keyframe animation introduction (../examples_revamped/10_animation/viz_introduction.py)

00:00.000

0.0

Arm Robot Animation (../examples_revamped/10_animation/viz_robot_arm_animation.py)

00:00.000

0.0

Keyframes Spline Interpolator (../examples_revamped/10_animation/viz_spline_interpolator.py)

00:00.000

0.0

Timeline and setting keyframes (../examples_revamped/10_animation/viz_timeline.py)

00:00.000

0.0

Keyframe animation (../examples_revamped/10_animation/viz_using_time_equations.py)

00:00.000

0.0

SDF Impostors on Billboards (../examples_revamped/13_shaders/viz_billboard_sdf_spheres.py)

00:00.000

0.0

Physically-Based Rendering (PBR) on spheres (../examples_revamped/13_shaders/viz_pbr_spheres.py)

00:00.000

0.0

Principled BRDF shader on spheres (../examples_revamped/13_shaders/viz_principled_spheres.py)

00:00.000

0.0

Make a Cylinder using polygons vs SDF (../examples_revamped/13_shaders/viz_sdf_cylinder.py)

00:00.000

0.0

Visualize SDF Actor (../examples_revamped/13_shaders/viz_sdfactor.py)

00:00.000

0.0

Varying Color (../examples_revamped/13_shaders/viz_shader.py)

00:00.000

0.0

Ball Collision Simulation (../examples_revamped/17_pybullet/viz_ball_collide.py)

00:00.000

0.0

Brick Wall Simulation (../examples_revamped/17_pybullet/viz_brick_wall.py)

00:00.000

0.0

Domino Physics Simulation (../examples_revamped/17_pybullet/viz_domino.py)

00:00.000

0.0

Wrecking Ball Simulation (../examples_revamped/17_pybullet/viz_wrecking_ball.py)

00:00.000

0.0

Streaming FURY with user interaction (../examples_revamped/20_stream/viz_interaction.py)

00:00.000

0.0

Streaming FURY with WebRTC/MJPEG (../examples_revamped/20_stream/viz_no_interaction.py)

00:00.000

0.0

Streaming FURY with WebRTC/MJPEG using the Widget Object (../examples_revamped/20_stream/viz_widget.py)

00:00.000

0.0

+
+
+ +
+ + +
+ +
+ + + +
+ +
+
+
+ +
+ + + +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/symlink/contributing.html b/v0.10.x/symlink/contributing.html new file mode 100644 index 000000000..60e4c1ac1 --- /dev/null +++ b/v0.10.x/symlink/contributing.html @@ -0,0 +1,822 @@ + + + + + + + + Contributing — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

Contributing#

+

Contributions are welcome, and they are greatly appreciated! Every +little bit helps, and credit will always be given.

+

You can contribute in many ways:

+
+

Types of Contributions#

+
+

Report Bugs#

+

Report bugs at fury-gl/fury#issues.

+

If you are reporting a bug, please include:

+
    +
  • Any details about your local setup that might be helpful in troubleshooting.

  • +
  • Detailed steps to reproduce the bug.

  • +
+
+
+

Fix Bugs#

+

Look through the GitHub issues for bugs. Anything tagged with “bug” +is open to whoever wants to implement it.

+
+
+

Implement Features#

+

Look through the GitHub issues for features. Anything tagged with “feature” +is open to whoever wants to implement it.

+
+
+

Write Documentation#

+

FURY could always use more documentation, whether +as part of the official FURY docs, in docstrings, +or even on the web in blog posts, articles, and such. +FURY uses Sphinx. +Please follow the numpy coding style and PEP8 +for docstring documentation.

+
+
+

Submit Feedback#

+

The best way to send feedback is to file an issue at fury-gl/fury#issues.

+

If you are proposing a feature:

+
    +
  • Explain in detail how it would work.

  • +
  • Keep the scope as narrow as possible, to make it easier to implement.

  • +
  • Remember that this is a volunteer-driven project, and that contributions +are welcome :)

  • +
+
+
+
+

Get Started!#

+

Ready to contribute? Here’s how to set up FURY for local development.

+
    +
  1. Fork the FURY repo on GitHub.

  2. +
  3. Clone your fork locally:

    +
    $ git clone https://github.com/your_name_here/fury.git
    +
    +
    +
  4. +
  5. Add a tracking branch which can always have the last version of FURY:

    +
    $ git remote add fury-gl https://github.com/fury-gl/fury.git
    +$ git fetch fury-gl
    +$ git branch fury-gl-master --track fury-gl/master
    +$ git checkout fury-gl-master
    +$ git pull
    +
    +
    +
  6. +
  7. Create a branch from the last dev version of your tracking branch for local development:

    +
    $ git checkout -b name-of-your-bugfix-or-feature
    +
    +
    +
  8. +
  9. Install it locally:

    +
    $ pip install --user -e .
    +
    +
    +
  10. +
  11. Now you can make your changes locally:

    +
    $ git add .
    +$ git commit -m "Your detailed description of your changes."
    +$ git push origin name-of-your-bugfix-or-feature
    +
    +
    +
  12. +
  13. Install the required packages for running the unittests:

    +
    $ pip install -r requirements/optional.txt
    +$ pip install -r requirements/test.txt
    +
    +
    +
  14. +
  15. When you’re done making changes, check that your changes pass flake8 and pytest:

    +
    $ flake8 fury
    +$ pytest -svv fury
    +
    +
    +

    To get flake8 and pytest, just pip install them into your virtualenv.

    +
  16. +
  17. Submit a pull request through the GitHub website.

  18. +
+
+
+

Pull Request Guidelines#

+

Before you submit a pull request, check that it meets these guidelines:

+
    +
  1. The pull request should include tests.

  2. +
  3. If the pull request adds functionality, the docs should be updated. Put +your new functionality into a function with a docstring, and add the +feature to the list in README.md.

  4. +
  5. The pull request should work for Python 3.6, 3.7, 3.8, 3.9 and for PyPy. Check +fury-gl/fury +and make sure that the tests pass for all supported Python versions.

  6. +
+
+
+

Publishing Releases#

+
+

Checklist before Releasing#

+
    +
  • Review the open list of FURY issues. Check whether there are +outstanding issues that can be closed, and whether there are any issues that +should delay the release. Label them !

  • +
  • Check whether there are no build failing on Travis.

  • +
  • Review and update the release notes. Get a partial list of contributors with something like:

    +
    git shortlog -nse v0.1.0..
    +
    +
    +

    where v0.1.0 was the last release tag name.

    +

    Then manually go over git shortlog v0.1.0.. to make sure the release notes +are as complete as possible and that every contributor was recognized.

    +
  • +
  • Use the opportunity to update the .mailmap file if there are any duplicate +authors listed from git shortlog -ns.

  • +
  • Add any new authors to the AUTHORS file.

  • +
  • Check the copyright years in LICENSE

  • +
  • Generate release notes. Go to docs/source/ext and run github_tools.py script the following way:

    +
    $ python github_tools.py --tag=v0.1.0 --save --version=0.2.0
    +
    +
    +

    This command will generate a new file named release0.2.0.rst in release_notes folder.

    +
  • +
  • Check the examples and tutorial - we really need an automated check here.

  • +
  • Make sure all tests pass on your local machine (from the <fury root> directory):

    +
    cd ..
    +pytest -s --verbose --doctest-modules fury
    +cd fury # back to the root directory
    +
    +
    +
  • +
  • Check the documentation doctests:

    +
    cd docs
    +make -C . html
    +cd ..
    +
    +
    +
  • +
  • The release should now be ready.

  • +
+
+
+

Doing the release#

+
    +
  • Update release-history.rst in the documentation if you have not done so already. +You may also highlight any additions, improvements, and bug fixes.

  • +
  • Type git status and check that you are on the master branch with no uncommitted code.

  • +
  • Now it’s time for the source release. Mark the release with an empty commit, just to leave a marker. +It makes it easier to find the release when skimming through the git history:

    +
    git commit --allow-empty -m "REL: vX.Y.Z"
    +
    +
    +
  • +
  • Tag the commit:

    +
    git tag -am 'Second public release' vX.Y.Z  # Don't forget the leading v
    +
    +
    +

    This will create a tag named vX.Y.Z. The -a flag (strongly recommended) opens up a text editor where +you should enter a brief description of the release.

    +
  • +
  • Verify that the __version__ attribute is correctly updated:

    +
    import fury
    +fury.__version__  # should be 'X.Y.Z'
    +
    +
    +

    Incidentally, once you resume development and add the first commit after this tag, __version__ will take +on a value like X.Y.Z+1.g58ad5f7, where +1 means “1 commit past version X.Y.Z” and 58ad5f7 is the +first 7 characters of the hash of the current commit. The letter g stands for “git”. This is all managed +automatically by versioneer and in accordance with the specification in PEP 440.

    +
  • +
  • Push the new commit and the tag to master:

    +
    git push origin master
    +git push origin vX.Y.Z
    +
    +
    +
  • +
  • Register for a PyPI account and Install twine, a tool for uploading packages to PyPI:

    +
    python3 -m pip install --upgrade twine
    +
    +
    +
  • +
  • Remove any extraneous files:

    +
    git clean -dfx
    +
    +
    +

    If you happen to have any important files in your project directory that are not committed to git, +move them first; this will delete them!

    +
  • +
  • Publish a release on PyPI:

    +
    python setup.py sdist
    +python setup.py bdist_wheel
    +twine upload dist/*
    +
    +
    +
  • +
  • Check how everything looks on pypi - the description, the packages. If +necessary delete the release and try again if it doesn’t look right.

  • +
  • Set up maintenance / development branches

    +

    If this is this is a full release you need to set up two branches, one for +further substantial development (often called ‘trunk’) and another for +maintenance releases.

    +
      +
    • Branch to maintenance:

      +
      git co -b maint/X.Y.Z
      +
      +
      +

      Push with something like git push upstream-rw maint/0.6.x --set-upstream

      +
    • +
    • Start next development series:

      +
      git co main-master
      +
      +
      +

      Next merge the maintenance branch with the “ours” strategy. This just labels +the maintenance branch info.py edits as seen but discarded, so we can +merge from maintenance in future without getting spurious merge conflicts:

      +
      git merge -s ours maint/0.6.x
      +
      +
      +

      Push with something like git push upstream-rw main-master:master

      +
    • +
    +

    If this is just a maintenance release from maint/0.6.x or similar, just +tag and set the version number to - say - 0.6.2.dev.

    +
  • +
  • Push the tag with git push upstream-rw 0.6.0

  • +
+
+

Other stuff that needs doing for the release#

+
    +
  • Checkout the tagged release, build the html docs and upload them to +the github pages website:

    +
    make upload
    +
    +
    +
  • +
  • Announce to the mailing lists. With fear and trembling.

  • +
+
+
+
+
+ +
+ + +
+ +
+ + + + + +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/symlink/license.html b/v0.10.x/symlink/license.html new file mode 100644 index 000000000..df5ae2744 --- /dev/null +++ b/v0.10.x/symlink/license.html @@ -0,0 +1,507 @@ + + + + + + + + License — FURY 0.10.0 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+
+ + + + + +
+
+ +
+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ + +
+ +
+

License#

+

Copyright (c) 2024, FURY - Free Unified Rendering in Python. All rights reserved.

+

Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met:

+
    +
  • Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer.

  • +
  • Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution.

  • +
  • Neither the name of the FURY - Free Unified Rendering in Python +nor the names of its contributors may be used to endorse or promote +products derived from this software without specific prior written permission.

  • +
+

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+
+ +
+ + +
+ +
+ + + + + +
+ + + +
+ +
+ + +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v0.10.x/video.html b/v0.10.x/video.html new file mode 100644 index 000000000..fc95a5b8f --- /dev/null +++ b/v0.10.x/video.html @@ -0,0 +1,163 @@ + + + + + + + + + FURY + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ + Remove to Display +
+

Video Landing Page

+

Full Screen Video Background

+ Start Here +
+ +
+ +

Hypertext Markup Language (HTML) is the standard markup language for creating web pages and web applications. With Cascading Style Sheets (CSS) and JavaScript, it forms a triad of cornerstone technologies for the World Wide Web.[3] Web browsers receive HTML documents from a web server or from local storage and render them into multimedia web pages. HTML describes the structure of a web page semantically and originally included cues for the appearance of the document.

+ + + + + + + + + + + \ No newline at end of file